Seeds the entity graph from existing project state, memories, and
vault docs across p04-gigabit (11 entities), p05-interferometer (10),
and p06-polisher (14). Covers systems, subsystems, components,
materials, decisions, requirements, constraints, vendors, and
parameters with structural and intent relationships.
Example: GET /entities/{M1 Mirror Assembly id} returns the full
context — 4 subsystems it contains, 2 requirements it's constrained
by, and the parent project — traversable in one API call.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
189 lines
8.7 KiB
Python
189 lines
8.7 KiB
Python
"""Bootstrap engineering entities from existing project knowledge.
|
|
|
|
One-shot script that seeds the entity/relationship graph from what
|
|
AtoCore already knows via memories, project state, and vault docs.
|
|
Safe to re-run — uses name+project dedup.
|
|
|
|
Usage:
|
|
|
|
python3 scripts/bootstrap_entities.py --base-url http://localhost:8100
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import urllib.request
|
|
|
|
DEFAULT_BASE_URL = os.environ.get("ATOCORE_BASE_URL", "http://dalidou:8100")
|
|
|
|
|
|
def post(base_url, path, body):
|
|
data = json.dumps(body).encode("utf-8")
|
|
req = urllib.request.Request(
|
|
f"{base_url}{path}", method="POST",
|
|
headers={"Content-Type": "application/json"}, data=data,
|
|
)
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=10) as resp:
|
|
return json.loads(resp.read().decode("utf-8"))
|
|
except Exception as e:
|
|
return {"error": str(e)}
|
|
|
|
|
|
def entity(base_url, etype, name, project="", desc="", props=None):
|
|
result = post(base_url, "/entities", {
|
|
"entity_type": etype, "name": name, "project": project,
|
|
"description": desc, "properties": props or {},
|
|
})
|
|
eid = result.get("id", "")
|
|
status = "+" if eid else "skip"
|
|
print(f" {status} [{etype}] {name}")
|
|
return eid
|
|
|
|
|
|
def rel(base_url, src, tgt, rtype):
|
|
if not src or not tgt:
|
|
return
|
|
result = post(base_url, "/relationships", {
|
|
"source_entity_id": src, "target_entity_id": tgt,
|
|
"relationship_type": rtype,
|
|
})
|
|
print(f" -> {rtype}")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--base-url", default=DEFAULT_BASE_URL)
|
|
args = parser.parse_args()
|
|
b = args.base_url
|
|
|
|
print("=== P04 GigaBIT M1 ===")
|
|
p04 = entity(b, "project", "GigaBIT M1", "p04-gigabit",
|
|
"1.2m primary mirror for stratospheric balloon telescope")
|
|
|
|
p04_m1 = entity(b, "system", "M1 Mirror Assembly", "p04-gigabit",
|
|
"Primary mirror blank + support system + reference frame")
|
|
rel(b, p04, p04_m1, "contains")
|
|
|
|
p04_vs = entity(b, "subsystem", "Vertical Support", "p04-gigabit",
|
|
"18-point whiffletree axial support from below")
|
|
p04_ls = entity(b, "subsystem", "Lateral Support", "p04-gigabit",
|
|
"Circumferential constraint system with GF-PTFE pads")
|
|
p04_rf = entity(b, "subsystem", "Reference Frame", "p04-gigabit",
|
|
"Structural mounting interface between mirror and OTA")
|
|
p04_blank = entity(b, "component", "M1 Blank", "p04-gigabit",
|
|
"1.2m Zerodur aspheric blank from Schott",
|
|
{"material": "Zerodur", "diameter_m": 1.2, "focal_ratio": "F/1.2"})
|
|
rel(b, p04_m1, p04_vs, "contains")
|
|
rel(b, p04_m1, p04_ls, "contains")
|
|
rel(b, p04_m1, p04_rf, "contains")
|
|
rel(b, p04_m1, p04_blank, "contains")
|
|
|
|
p04_zerodur = entity(b, "material", "Zerodur", "p04-gigabit",
|
|
"Glass-ceramic with near-zero CTE for mirror blanks")
|
|
p04_ptfe = entity(b, "material", "GF-PTFE", "p04-gigabit",
|
|
"Glass-filled PTFE for thermal stability on lateral pads")
|
|
rel(b, p04_blank, p04_zerodur, "uses_material")
|
|
rel(b, p04_ls, p04_ptfe, "uses_material")
|
|
|
|
p04_optb = entity(b, "decision", "Option B Conical Back", "p04-gigabit",
|
|
"Selected mirror architecture: conical-back lightweighting")
|
|
rel(b, p04_optb, p04_blank, "affected_by_decision")
|
|
|
|
p04_wfe = entity(b, "requirement", "WFE < 15nm RMS filtered", "p04-gigabit",
|
|
"Filtered mechanical wavefront error below 15 nm across 20-60 deg elevation")
|
|
p04_mass = entity(b, "requirement", "Mass < 103.5 kg", "p04-gigabit",
|
|
"Total mirror assembly mass constraint")
|
|
rel(b, p04_m1, p04_wfe, "constrained_by")
|
|
rel(b, p04_m1, p04_mass, "constrained_by")
|
|
|
|
print("\n=== P05 Interferometer ===")
|
|
p05 = entity(b, "project", "Interferometer System", "p05-interferometer",
|
|
"Metrology system for GigaBIT M1 figuring")
|
|
|
|
p05_rig = entity(b, "system", "Test Rig", "p05-interferometer",
|
|
"Folded-beam interferometric test setup for M1 measurement")
|
|
rel(b, p05, p05_rig, "contains")
|
|
|
|
p05_ifm = entity(b, "component", "Interferometer", "p05-interferometer",
|
|
"Fixed horizontal Twyman-Green dynamic interferometer")
|
|
p05_fold = entity(b, "component", "Fold Mirror", "p05-interferometer",
|
|
"45-degree beam redirect, <= lambda/20 surface quality")
|
|
p05_cgh = entity(b, "component", "CGH Null Corrector", "p05-interferometer",
|
|
"6-inch transmission CGH for F/1.2 asphere null test",
|
|
{"diameter": "6 inch", "substrate": "fused silica", "error_budget_nm": 5.5})
|
|
p05_tilt = entity(b, "subsystem", "Tilting Platform", "p05-interferometer",
|
|
"Mirror tilting platform, co-tilts with interferometer")
|
|
rel(b, p05_rig, p05_ifm, "contains")
|
|
rel(b, p05_rig, p05_fold, "contains")
|
|
rel(b, p05_rig, p05_cgh, "contains")
|
|
rel(b, p05_rig, p05_tilt, "contains")
|
|
rel(b, p05_ifm, p05_fold, "interfaces_with")
|
|
rel(b, p05_cgh, p05_tilt, "interfaces_with")
|
|
|
|
p05_vendor_dec = entity(b, "decision", "Vendor Path: Twyman-Green preferred", "p05-interferometer",
|
|
"4D technical lead but cost-challenged; Zygo Verifire SV at 55K is value path")
|
|
p05_vendor_zygo = entity(b, "vendor", "Zygo / AMETEK", "p05-interferometer",
|
|
"Certified used Verifire SV, 55K, Nabeel Sufi contact")
|
|
p05_vendor_4d = entity(b, "vendor", "4D Technology", "p05-interferometer",
|
|
"PC6110/PC4030, above budget but strongest technical option")
|
|
p05_vendor_aom = entity(b, "vendor", "AOM (CGH)", "p05-interferometer",
|
|
"CGH design and fabrication, 28-30K package")
|
|
rel(b, p05_vendor_dec, p05_ifm, "affected_by_decision")
|
|
|
|
print("\n=== P06 Polisher ===")
|
|
p06 = entity(b, "project", "Polisher System", "p06-polisher",
|
|
"Machine overhaul + software suite for optical polishing")
|
|
|
|
p06_machine = entity(b, "system", "Polisher Machine", "p06-polisher",
|
|
"Swing-arm polishing machine with force modulation")
|
|
p06_sw = entity(b, "system", "Software Suite", "p06-polisher",
|
|
"Three-layer software: polisher-sim, polisher-post, polisher-control")
|
|
rel(b, p06, p06_machine, "contains")
|
|
rel(b, p06, p06_sw, "contains")
|
|
|
|
p06_sim = entity(b, "subsystem", "polisher-sim", "p06-polisher",
|
|
"Digital twin: surface assimilation, removal simulation, planning")
|
|
p06_post = entity(b, "subsystem", "polisher-post", "p06-polisher",
|
|
"Bridge: validation, translation, packaging for machine")
|
|
p06_ctrl = entity(b, "subsystem", "polisher-control", "p06-polisher",
|
|
"Executor: state machine, interlocks, telemetry, run logs")
|
|
rel(b, p06_sw, p06_sim, "contains")
|
|
rel(b, p06_sw, p06_post, "contains")
|
|
rel(b, p06_sw, p06_ctrl, "contains")
|
|
rel(b, p06_sim, p06_post, "interfaces_with")
|
|
rel(b, p06_post, p06_ctrl, "interfaces_with")
|
|
|
|
p06_fc = entity(b, "subsystem", "Force Control", "p06-polisher",
|
|
"Frame-grounded counterweight actuator with cable tension modulation",
|
|
{"actuator_capacity_N": "150-200", "compliance_spring_Nmm": "3-5"})
|
|
p06_zaxis = entity(b, "component", "Z-Axis", "p06-polisher",
|
|
"Binary engage/retract mechanism, not continuous position")
|
|
p06_cam = entity(b, "component", "Cam Mechanism", "p06-polisher",
|
|
"Mechanically set by operator, read by encoders, not actuated")
|
|
rel(b, p06_machine, p06_fc, "contains")
|
|
rel(b, p06_machine, p06_zaxis, "contains")
|
|
rel(b, p06_machine, p06_cam, "contains")
|
|
|
|
p06_fw = entity(b, "decision", "Firmware Interface Contract", "p06-polisher",
|
|
"controller-job.v1 in, run-log.v1 + telemetry out — invariant")
|
|
p06_offline = entity(b, "decision", "Offline-First Design", "p06-polisher",
|
|
"Machine works fully offline; network is for remote access only")
|
|
p06_usb = entity(b, "decision", "USB SSD Storage", "p06-polisher",
|
|
"USB SSD mandatory on RPi, not SD card")
|
|
|
|
p06_contracts = entity(b, "constraint", "Shared Contracts", "p06-polisher",
|
|
"Stable IDs, explicit versions, hashable artifacts, planned-vs-executed separation")
|
|
rel(b, p06_sw, p06_contracts, "constrained_by")
|
|
|
|
p06_preston = entity(b, "parameter", "Preston Coefficient kp", "p06-polisher",
|
|
"Calibrated from before/after surface measurements, multi-run inverse-variance weighting")
|
|
|
|
print(f"\nDone.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|