From 368adf2ebca492d4f1f15eecb05effc781a70db6 Mon Sep 17 00:00:00 2001 From: Anto01 Date: Tue, 7 Apr 2026 06:50:56 -0400 Subject: [PATCH] docs(arch): tool-handoff-boundaries + representation-authority MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Session 3 of the four-session plan. Two more engineering planning docs that lock in the most contentious architectural decisions before V1 implementation begins. docs/architecture/tool-handoff-boundaries.md -------------------------------------------- Locks in the V1 read/write relationship with external tools: - AtoCore is a one-way mirror in V1. External tools push, AtoCore reads, AtoCore never writes back. - Per-tool stance table covering KB-CAD, KB-FEM, NX, PKM, Gitea repos, OpenClaw, AtoDrive, PLM/vendor systems - Two new ingest endpoints proposed for V1: POST /ingest/kb-cad/export and POST /ingest/kb-fem/export - Sketch JSON shapes for both exports (intentionally minimal, to be refined in dedicated schema docs during implementation) - Drift handling: KB-CAD changes a value -> creates an entity candidate -> existing active becomes a conflict member -> human resolves via the conflict model - Hard-line invariants V1 will not cross: no write to external tools, no live polling, no silent merging, no schema fan-out, no external-tool-specific logic in entity types - Why not bidirectional: schema drift, conflict semantics, trust hierarchy, velocity, reversibility - V2+ deferred items: selective write-back annotations, light polling, direct NX integration, cost/vendor/PLM connections - Open questions for the implementation sprint: schema location, who runs the exporter, full-vs-incremental, exporter auth docs/architecture/representation-authority.md --------------------------------------------- The canonical-home matrix that says where each kind of fact actually lives: - Six representation layers identified: PKM, KB project, Gitea repos, AtoCore memories, AtoCore entities, AtoCore project_state - The hard rule: every fact kind has exactly one canonical home; other layers may hold derived copies but never disagree - Comprehensive matrix covering 22 fact kinds (CAD geometry, CAD-side structure, FEM mesh, FEM results, code, repo docs, PKM prose, identity, preference, episodic, decision, requirement, constraint, validation claim, material, parameter, project status, ADRs, runbooks, backup metadata, interactions) - Cross-layer supremacy rule: project_state > tool-of-origin > entities > active memories > source chunks - Three worked examples showing how the rules apply: * "what material does the lateral support pad use?" (KB-CAD canonical, project_state override possible) * "did we decide to merge the bind mounts?" (Gitea + memory both canonical for different aspects) * "what's p05's current next focus?" (project_state always wins for current state queries) - Concrete consequences for V1 implementation: Material and Parameter are mostly KB-CAD shadows; Decisions / Requirements / Constraints / ValidationClaims are AtoCore-canonical; PKM is never authoritative; project_state is the override layer; the conflict model is the enforcement mechanism - Out of scope for V1: facts about other people, vendor/cost facts, time-bounded facts, cross-project shared facts - Open questions for V1: how the reviewer sees canonical home in the UI, whether entities need an explicit canonical_home field, how project_state overrides surface in query results This is pure doc work. No code, no schema, no behavior changes. After this commit the engineering planning sprint is 6 of 8 docs done — only human-mirror-rules and engineering-v1-acceptance remain. --- docs/architecture/representation-authority.md | 273 ++++++++++++++ docs/architecture/tool-handoff-boundaries.md | 339 ++++++++++++++++++ 2 files changed, 612 insertions(+) create mode 100644 docs/architecture/representation-authority.md create mode 100644 docs/architecture/tool-handoff-boundaries.md diff --git a/docs/architecture/representation-authority.md b/docs/architecture/representation-authority.md new file mode 100644 index 0000000..1ee8a4c --- /dev/null +++ b/docs/architecture/representation-authority.md @@ -0,0 +1,273 @@ +# Representation Authority (canonical home matrix) + +## Why this document exists + +The same fact about an engineering project can show up in many +places: a markdown note in the PKM, a structured field in KB-CAD, +a commit message in a Gitea repo, an active memory in AtoCore, an +entity in the engineering layer, a row in trusted project state. +**Without an explicit rule about which representation is +authoritative for which kind of fact, the system will accumulate +contradictions and the human will lose trust in all of them.** + +This document is the canonical-home matrix. Every kind of fact +that AtoCore handles has exactly one authoritative representation, +and every other place that holds a copy of that fact is, by +definition, a derived view that may be stale. + +## The representations in scope + +Six places where facts can live in this ecosystem: + +| Layer | What it is | Who edits it | How it's structured | +|---|---|---|---| +| **PKM** | Antoine's Obsidian-style markdown vault under `/srv/storage/atocore/sources/vault/` | Antoine, by hand | unstructured markdown with optional frontmatter | +| **KB project** | the engineering Knowledge Base (KB-CAD / KB-FEM repos and any companion docs) | Antoine, semi-structured | per-tool typed records | +| **Gitea repos** | source code repos under `dalidou:3000/Antoine/*` (Fullum-Interferometer, polisher-sim, ATOCore itself, ...) | Antoine via git commits | code, READMEs, repo-specific markdown | +| **AtoCore memories** | rows in the `memories` table | hand-authored or extracted from interactions | typed (identity / preference / project / episodic / knowledge / adaptation) | +| **AtoCore entities** | rows in the `entities` table (V1, not yet built) | imported from KB exports or extracted from interactions | typed entities + relationships per the V1 ontology | +| **AtoCore project state** | rows in the `project_state` table (Layer 3, trusted) | hand-curated only, never automatic | category + key + value | + +## The canonical home rule + +> For each kind of fact, exactly one of the six representations is +> the authoritative source. The other five may hold derived +> copies, but they are not allowed to disagree with the +> authoritative one. When they disagree, the disagreement is a +> conflict and surfaces via the conflict model. + +The matrix below assigns the authoritative representation per fact +kind. It is the practical answer to the question "where does this +fact actually live?" for daily decisions. + +## The canonical-home matrix + +| Fact kind | Canonical home | Why | How it gets into AtoCore | +|---|---|---|---| +| **CAD geometry** (the actual model) | NX (or successor CAD tool) | the only place that can render and validate it | not in AtoCore at all in V1 | +| **CAD-side structure** (subsystem tree, component list, materials, parameters) | KB-CAD | KB-CAD is the structured wrapper around NX | KB-CAD export → `/ingest/kb-cad/export` → entities | +| **FEM mesh & solver settings** | KB-FEM (wrapping the FEM tool) | only the solver representation can run | not in AtoCore at all in V1 | +| **FEM results & validation outcomes** | KB-FEM | KB-FEM owns the outcome records | KB-FEM export → `/ingest/kb-fem/export` → entities | +| **Source code** | Gitea repos | repos are version-controlled and reviewable | indirectly via repo markdown ingestion (Phase 1) | +| **Repo-level documentation** (READMEs, design docs in the repo) | Gitea repos | lives next to the code it documents | ingested as source chunks; never hand-edited in AtoCore | +| **Project-level prose notes** (decisions in long-form, journal-style entries, working notes) | PKM | the place Antoine actually writes when thinking | ingested as source chunks; the extractor proposes candidates from these for the review queue | +| **Identity** ("the user is a mechanical engineer running AtoCore") | AtoCore memories (`identity` type) | nowhere else holds personal identity | hand-authored via `POST /memory` or extracted from interactions | +| **Preference** ("prefers small reviewable diffs", "uses SI units") | AtoCore memories (`preference` type) | nowhere else holds personal preferences | hand-authored or extracted | +| **Episodic** ("on April 6 we debugged the EXDEV bug") | AtoCore memories (`episodic` type) | nowhere else has time-bound personal recall | extracted from captured interactions | +| **Decision** (a structured engineering decision) | AtoCore **entities** (Decision) once the engineering layer ships; AtoCore memories (`adaptation`) until then | needs structured supersession, audit trail, and link to affected components | extracted from PKM or interactions; promoted via review queue | +| **Requirement** | AtoCore **entities** (Requirement) | needs structured satisfaction tracking | extracted from PKM, KB-CAD, or interactions | +| **Constraint** | AtoCore **entities** (Constraint) | needs structured link to the entity it constrains | extracted from PKM, KB-CAD, or interactions | +| **Validation claim** | AtoCore **entities** (ValidationClaim) | needs structured link to supporting Result | extracted from KB-FEM exports or interactions | +| **Material** | KB-CAD if the material is on a real component; AtoCore entity (Material) if it's a project-wide material decision not yet attached to geometry | structured properties live in KB-CAD's material database | KB-CAD export, or hand-authored as a Material entity | +| **Parameter** | KB-CAD or KB-FEM depending on whether it's a geometry or solver parameter; AtoCore entity (Parameter) if it's a higher-level project parameter not in either tool | structured numeric values with units live in their tool of origin | KB export, or hand-authored | +| **Project status / current focus / next milestone** | AtoCore **project_state** (Layer 3) | the trust hierarchy says trusted state is the highest authority for "what is the current state of the project" | hand-curated via `POST /project/state` | +| **Architectural decision records (ADRs)** | depends on form: long-form ADR markdown lives in the repo; the structured fact about which ADR was selected lives in the AtoCore Decision entity | both representations are useful for different audiences | repo ingestion provides the prose; the entity is created by extraction or hand-authored | +| **Operational runbooks** | repo (next to the code they describe) | lives with the system it operates | not promoted into AtoCore entities — runbooks are reference material, not facts | +| **Backup metadata** (snapshot timestamps, integrity status) | the backup-metadata.json files under `/srv/storage/atocore/backups/` | each snapshot is its own self-describing record | not in AtoCore's database; queried via the `/admin/backup` endpoints | +| **Conversation history with AtoCore (interactions)** | AtoCore `interactions` table | nowhere else has the prompt + context pack + response triple | written by capture (Phase 9 Commit A) | + +## The supremacy rule for cross-layer facts + +When the same fact has copies in multiple representations and they +disagree, the trust hierarchy applies in this order: + +1. **AtoCore project_state** (Layer 3) is highest authority for any + "current state of the project" question. This is why it requires + manual curation and never gets touched by automatic processes. +2. **The tool-of-origin canonical home** is highest authority for + facts that are tool-managed: KB-CAD wins over AtoCore entities + for CAD-side structure facts; KB-FEM wins for FEM result facts. +3. **AtoCore entities** are highest authority for facts that are + AtoCore-managed: Decisions, Requirements, Constraints, + ValidationClaims (when the supporting Results are still loose). +4. **Active AtoCore memories** are highest authority for personal + facts (identity, preference, episodic). +5. **Source chunks (PKM, repos, ingested docs)** are lowest + authority — they are the raw substrate from which higher layers + are extracted, but they may be stale, contradictory among + themselves, or out of date. + +This is the same hierarchy enforced by `conflict-model.md`. This +document just makes it explicit per fact kind. + +## Examples + +### Example 1 — "what material does the lateral support pad use?" + +Possible representations: + +- KB-CAD has the field `component.lateral-support-pad.material = "GF-PTFE"` +- A PKM note from last month says "considering PEEK for the + lateral support, GF-PTFE was the previous choice" +- An AtoCore Material entity says `GF-PTFE` +- An AtoCore project_state entry says `p05 / decision / + lateral_support_material = GF-PTFE` + +Which one wins for the question "what's the current material"? + +- **project_state wins** if the query is "what is the current + trusted answer for p05's lateral support material" (Layer 3) +- **KB-CAD wins** if project_state has not been curated for this + field yet, because KB-CAD is the canonical home for CAD-side + structure +- **The Material entity** is a derived view from KB-CAD; if it + disagrees with KB-CAD, the entity is wrong and a conflict is + surfaced +- **The PKM note** is historical context, not authoritative for + "current" + +### Example 2 — "did we decide to merge the bind mounts?" + +Possible representations: + +- A working session interaction is captured in the `interactions` + table with the response containing `## Decision: merge the two + bind mounts into one` +- The Phase 9 Commit C extractor produced a candidate adaptation + memory from that decision +- A reviewer promoted the candidate to active +- The AtoCore source repo has the actual code change in commit + `d0ff8b5` and the docker-compose.yml is in its post-merge form + +Which one wins for "is this decision real and current"? + +- **The Gitea repo** wins for "is this decision implemented" — + the docker-compose.yml is the canonical home for the actual + bind mount configuration +- **The active adaptation memory** wins for "did we decide this" + — that's exactly what the Commit C lifecycle is for +- **The interaction record** is the audit trail — it's + authoritative for "when did this conversation happen and what + did the LLM say", but not for "is this decision current" +- **The source chunks** from PKM are not relevant here because no + PKM note about this decision exists yet (and that's fine — + decisions don't have to live in PKM if they live in the repo + and the AtoCore memory) + +### Example 3 — "what's p05's current next focus?" + +Possible representations: + +- The PKM has a `current-status.md` note updated last week +- AtoCore project_state has `p05 / status / next_focus = "wave 2 ingestion"` +- A captured interaction from yesterday discussed the next focus + at length + +Which one wins? + +- **project_state wins**, full stop. The trust hierarchy says + Layer 3 is canonical for current state. This is exactly the + reason project_state exists. +- The PKM note is historical context. +- The interaction is conversation history. +- If project_state and the PKM disagree, the human updates one or + the other to bring them in line — usually by re-curating + project_state if the conversation revealed a real change. + +## What this means for the engineering layer V1 implementation + +Several concrete consequences fall out of the matrix: + +1. **The Material and Parameter entity types are mostly KB-CAD + shadows in V1.** They exist in AtoCore so other entities + (Decisions, Requirements) can reference them with structured + links, but their authoritative values come from KB-CAD imports. + If KB-CAD doesn't know about a material, the AtoCore entity is + the canonical home only because nothing else is. +2. **Decisions / Requirements / Constraints / ValidationClaims + are AtoCore-canonical.** These don't have a natural home in + KB-CAD or KB-FEM. They live in AtoCore as first-class entities + with full lifecycle and supersession. +3. **The PKM is never authoritative.** It is the substrate for + extraction. The reviewer promotes things out of it; they don't + point at PKM notes as the "current truth". +4. **project_state is the override layer.** Whenever the human + wants to declare "the current truth is X regardless of what + the entities and memories and KB exports say", they curate + into project_state. Layer 3 is intentionally small and + intentionally manual. +5. **The conflict model is the enforcement mechanism.** When two + representations disagree on a fact whose canonical home rule + should pick a winner, the conflict surfaces via the + `/conflicts` endpoint and the reviewer resolves it. The + matrix in this document tells the reviewer who is supposed + to win in each scenario; they're not making the decision blind. + +## What the matrix does NOT define + +1. **Facts about people other than the user.** No "team member" + entity, no per-collaborator preferences. AtoCore is + single-user in V1. +2. **Facts about AtoCore itself as a project.** Those are project + memories and project_state entries under `project=atocore`, + same lifecycle as any other project's facts. +3. **Vendor / supplier / cost facts.** Out of V1 scope. +4. **Time-bounded facts** (a value that was true between two + dates and may not be true now). The current matrix treats all + active facts as currently-true and uses supersession to + represent change. Temporal facts are a V2 concern. +5. **Cross-project shared facts** (a Material that is reused across + p04, p05, and p06). Currently each project has its own copy. + Cross-project deduplication is also a V2 concern. + +## The "single canonical home" invariant in practice + +The hard rule that every fact has exactly one canonical home is +the load-bearing invariant of this matrix. To enforce it +operationally: + +- **Extraction never duplicates.** When the extractor scans an + interaction or a source chunk and proposes a candidate, the + candidate is dropped if it duplicates an already-active record + in the canonical home (the existing extractor implementation + already does this for memories; the entity extractor will + follow the same pattern). +- **Imports never duplicate.** When KB-CAD pushes the same + Component twice with the same value, the second push is + recognized as identical and updates the `last_imported_at` + timestamp without creating a new entity. +- **Imports surface drift as conflict.** When KB-CAD pushes the + same Component with a different value, that's a conflict per + the conflict model — never a silent overwrite. +- **Hand-curation into project_state always wins.** A + project_state entry can disagree with an entity or a KB + export; the project_state entry is correct by fiat (Layer 3 + trust), and the reviewer is responsible for bringing the lower + layers in line if appropriate. + +## Open questions for V1 implementation + +1. **How does the reviewer see the canonical home for a fact in + the UI?** Probably by including the fact's authoritative + layer in the entity / memory detail view: "this Material is + currently mirrored from KB-CAD; the canonical home is KB-CAD". +2. **Who owns running the KB-CAD / KB-FEM exporter?** The + `tool-handoff-boundaries.md` doc lists this as an open + question; same answer applies here. +3. **Do we need an explicit `canonical_home` field on entity + rows?** A field that records "this entity is canonical here" + vs "this entity is a mirror of ". Probably + yes; deferred to the entity schema spec. +4. **How are project_state overrides surfaced in the engineering + layer query results?** When a query (e.g. Q-001 "what does + this subsystem contain?") would return entity rows, the result + should also flag any project_state entries that contradict the + entities — letting the reviewer see the override at query + time, not just in the conflict queue. + +## TL;DR + +- Six representation layers: PKM, KB project, repos, AtoCore + memories, AtoCore entities, AtoCore project_state +- Every fact kind has exactly one canonical home +- The trust hierarchy resolves cross-layer conflicts: + project_state > tool-of-origin (KB-CAD/KB-FEM) > entities > + active memories > source chunks +- Decisions / Requirements / Constraints / ValidationClaims are + AtoCore-canonical (no other system has a natural home for them) +- Materials / Parameters / CAD-side structure are KB-CAD-canonical +- FEM results / validation outcomes are KB-FEM-canonical +- project_state is the human override layer, top of the + hierarchy, manually curated only +- Conflicts surface via `/conflicts` and the reviewer applies the + matrix to pick a winner diff --git a/docs/architecture/tool-handoff-boundaries.md b/docs/architecture/tool-handoff-boundaries.md new file mode 100644 index 0000000..43aefa9 --- /dev/null +++ b/docs/architecture/tool-handoff-boundaries.md @@ -0,0 +1,339 @@ +# Tool Hand-off Boundaries (KB-CAD / KB-FEM and friends) + +## Why this document exists + +The engineering layer V1 will accumulate typed entities about +projects, subsystems, components, materials, requirements, +constraints, decisions, parameters, analysis models, results, and +validation claims. Many of those concepts also live in real +external tools — CAD systems, FEM solvers, BOM managers, PLM +databases, vendor portals. + +The first big design decision before writing any entity-layer code +is: **what is AtoCore's read/write relationship with each of those +external tools?** + +The wrong answer in either direction is expensive: + +- Too read-only: AtoCore becomes a stale shadow of the tools and + loses the trust battle the moment a value drifts. +- Too bidirectional: AtoCore takes on responsibilities it can't + reliably honor (live sync, conflict resolution against external + schemas, write-back validation), and the project never ships. + +This document picks a position for V1. + +## The position + +> **AtoCore is a one-way mirror in V1.** External tools push +> structured exports into AtoCore. AtoCore never pushes back. + +That position has three corollaries: + +1. **External tools remain the source of truth for everything they + already manage.** A CAD model is canonical for geometry; a FEM + project is canonical for meshes and solver settings; KB-CAD is + canonical for whatever KB-CAD already calls canonical. +2. **AtoCore is the source of truth for the *AtoCore-shaped* + record** of those facts: the Decision that selected the geometry, + the Requirement the geometry satisfies, the ValidationClaim the + FEM result supports. AtoCore does not duplicate the external + tool's primary representation; it stores the structured *facts + about* it. +3. **The boundary is enforced by absence.** No write endpoint in + AtoCore ever generates a `.prt`, a `.fem`, an export to a PLM + schema, or a vendor purchase order. If we find ourselves wanting + to add such an endpoint in V1, we should stop and reconsider + the V1 scope. + +## Why one-way and not bidirectional + +Bidirectional sync between independent systems is one of the +hardest problems in engineering software. The honest reasons we +are not attempting it in V1: + +1. **Schema drift.** External tools evolve their schemas + independently. A bidirectional sync would have to track every + schema version of every external tool we touch. That is a + permanent maintenance tax. +2. **Conflict semantics.** When AtoCore and an external tool + disagree on the same field, "who wins" is a per-tool, per-field + decision. There is no general rule. Bidirectional sync would + require us to specify that decision exhaustively. +3. **Trust hierarchy.** AtoCore's whole point is the trust + hierarchy: trusted project state > entities > memories. If we + let entities push values back into the external tools, we + silently elevate AtoCore's confidence to "high enough to write + to a CAD model", which it almost never deserves. +4. **Velocity.** A bidirectional engineering layer is a + multi-year project. A one-way mirror is a months project. The + value-to-effort ratio favors one-way for V1 by an enormous + margin. +5. **Reversibility.** We can always add bidirectional sync later + on a per-tool basis once V1 has shown itself to be useful. We + cannot easily walk back a half-finished bidirectional sync that + has already corrupted data in someone's CAD model. + +## Per-tool stance for V1 + +| External tool | V1 stance | What AtoCore reads in | What AtoCore writes back | +|---|---|---|---| +| **KB-CAD** (Antoine's CAD knowledge base) | one-way mirror | structured exports of subsystems, components, materials, parameters via a documented JSON or CSV shape | nothing | +| **KB-FEM** (Antoine's FEM knowledge base) | one-way mirror | structured exports of analysis models, results, validation claims | nothing | +| **NX / Siemens NX** (the CAD tool itself) | not connected in V1 | nothing direct — only what KB-CAD exports about NX projects | nothing | +| **PKM (Obsidian / markdown vault)** | already connected via the ingestion pipeline (Phase 1) | full markdown/text corpus per the ingestion-waves doc | nothing | +| **Gitea repos** | already connected via the ingestion pipeline | repo markdown/text per project | nothing | +| **OpenClaw** (the LLM agent) | already connected via the read-only helper skill on the T420 | nothing — OpenClaw reads from AtoCore | nothing — OpenClaw does not write into AtoCore | +| **AtoDrive** (operational truth layer, future) | future: bidirectional with AtoDrive itself, but AtoDrive is internal to AtoCore so this isn't an external tool boundary | n/a in V1 | n/a in V1 | +| **PLM / vendor portals / cost systems** | not in V1 scope | nothing | nothing | + +## What "one-way mirror" actually looks like in code + +AtoCore exposes an ingestion endpoint per external tool that +accepts a structured export and turns it into entity candidates. +The endpoint is read-side from AtoCore's perspective (it reads +from a file or HTTP body), even though the external tool is the +one initiating the call. + +Proposed V1 ingestion endpoints: + +``` +POST /ingest/kb-cad/export body: KB-CAD export JSON +POST /ingest/kb-fem/export body: KB-FEM export JSON +``` + +Each endpoint: + +1. Validates the export against the documented schema +2. Maps each export record to an entity candidate (status="candidate") +3. Carries the export's source identifier into the candidate's + provenance fields (source_artifact_id, exporter_version, etc.) +4. Returns a summary: how many candidates were created, how many + were dropped as duplicates, how many failed schema validation +5. Does NOT auto-promote anything + +The KB-CAD and KB-FEM teams (which is to say, future-you) own the +exporter scripts that produce these JSON bodies. Those scripts +live in the KB-CAD / KB-FEM repos respectively, not in AtoCore. + +## The export schemas (sketch, not final) + +These are starting shapes, intentionally minimal. The schemas +will be refined in `kb-cad-export-schema.md` and +`kb-fem-export-schema.md` once the V1 ontology lands. + +### KB-CAD export shape (starting sketch) + +```json +{ + "exporter": "kb-cad", + "exporter_version": "1.0.0", + "exported_at": "2026-04-07T12:00:00Z", + "project": "p05-interferometer", + "subsystems": [ + { + "id": "subsystem.optical-frame", + "name": "Optical frame", + "parent": null, + "components": [ + { + "id": "component.lateral-support-pad", + "name": "Lateral support pad", + "material": "GF-PTFE", + "parameters": { + "thickness_mm": 3.0, + "preload_n": 12.0 + }, + "source_artifact": "kb-cad://p05/subsystems/optical-frame#lateral-support" + } + ] + } + ] +} +``` + +### KB-FEM export shape (starting sketch) + +```json +{ + "exporter": "kb-fem", + "exporter_version": "1.0.0", + "exported_at": "2026-04-07T12:00:00Z", + "project": "p05-interferometer", + "analysis_models": [ + { + "id": "model.optical-frame-modal", + "name": "Optical frame modal analysis v3", + "subsystem": "subsystem.optical-frame", + "results": [ + { + "id": "result.first-mode-frequency", + "name": "First-mode frequency", + "value": 187.4, + "unit": "Hz", + "supports_validation_claim": "claim.frame-rigidity-min-150hz", + "source_artifact": "kb-fem://p05/models/optical-frame-modal#first-mode" + } + ] + } + ] +} +``` + +These shapes will evolve. The point of including them now is to +make the one-way mirror concrete: it is a small, well-defined +JSON shape, not "AtoCore reaches into KB-CAD's database". + +## What AtoCore is allowed to do with the imported records + +After ingestion, the imported records become entity candidates +in AtoCore's own table. From that point forward they follow the +exact same lifecycle as any other candidate: + +- they sit at status="candidate" until a human reviews them +- the reviewer promotes them to status="active" or rejects them +- the active entities are queryable via the engineering query + catalog (Q-001 through Q-020) +- the active entities can be referenced from Decisions, Requirements, + ValidationClaims, etc. via the V1 relationship types + +The imported records are never automatically pushed into trusted +project state, never modified in place after import (they are +superseded by re-imports, not edited), and never written back to +the external tool. + +## What happens when KB-CAD changes a value AtoCore already has + +This is the canonical "drift" scenario. The flow: + +1. KB-CAD exports a fresh JSON. Component `component.lateral-support-pad` + now has `material: "PEEK"` instead of `material: "GF-PTFE"`. +2. AtoCore's ingestion endpoint sees the same `id` and a different + value. +3. The ingestion endpoint creates a new entity candidate with the + new value, **does NOT delete or modify the existing active + entity**, and creates a `conflicts` row linking the two members + (per the conflict model doc). +4. The reviewer sees an open conflict on the next visit to + `/conflicts`. +5. The reviewer either: + - **promotes the new value** (the active is superseded, the + candidate becomes the new active, the audit trail keeps both) + - **rejects the new value** (the candidate is invalidated, the + active stays — useful when the export was wrong) + - **dismisses the conflict** (declares them not actually about + the same thing, both stay active) + +The reviewer never touches KB-CAD from AtoCore. If the resolution +implies a change in KB-CAD itself, the reviewer makes that change +in KB-CAD, then re-exports. + +## What about NX directly? + +NX (Siemens NX) is the underlying CAD tool that KB-CAD wraps. +**NX is not connected to AtoCore in V1.** Any facts about NX +projects flow through KB-CAD as the structured intermediate. This +gives us: + +- **One schema to maintain.** AtoCore only has to understand the + KB-CAD export shape, not the NX API. +- **One ownership boundary.** KB-CAD owns the question of "what's + in NX". AtoCore owns the question of "what's in the typed + knowledge base". +- **Future flexibility.** When NX is replaced or upgraded, only + KB-CAD has to adapt; AtoCore doesn't notice. + +The same logic applies to FEM solvers (Nastran, Abaqus, ANSYS): +KB-FEM is the structured intermediate, AtoCore never talks to the +solver directly. + +## The hard-line invariants + +These are the things V1 will not do, regardless of how convenient +they might seem: + +1. **No write to external tools.** No POST/PUT/PATCH to any + external API, no file generation that gets written into a + CAD/FEM project tree, no email/chat sends. +2. **No live polling.** AtoCore does not poll KB-CAD or KB-FEM on + a schedule. Imports are explicit pushes from the external tool + into AtoCore's ingestion endpoint. +3. **No silent merging.** Every value drift surfaces as a + conflict for the reviewer (per the conflict model doc). +4. **No schema fan-out.** AtoCore does not store every field that + KB-CAD knows about. Only fields that map to one of the V1 + entity types make it into AtoCore. Everything else is dropped + at the import boundary. +5. **No external-tool-specific logic in entity types.** A + `Component` in AtoCore is the same shape regardless of whether + it came from KB-CAD, KB-FEM, the PKM, or a hand-curated + project state entry. The source is recorded in provenance, + not in the entity shape. + +## What this enables + +With the one-way mirror locked in, V1 implementation can focus on: + +- The entity table and its lifecycle +- The two `/ingest/kb-cad/export` and `/ingest/kb-fem/export` + endpoints with their JSON validators +- The candidate review queue extension (already designed in + `promotion-rules.md`) +- The conflict model (already designed in `conflict-model.md`) +- The query catalog implementation (already designed in + `engineering-query-catalog.md`) + +None of those are unbounded. Each is a finite, well-defined +implementation task. The one-way mirror is the choice that makes +V1 finishable. + +## What V2 might consider (deferred) + +After V1 has been live and demonstrably useful for a quarter or +two, the questions that become reasonable to revisit: + +1. **Selective write-back to KB-CAD for low-risk fields.** For + example, AtoCore could push back a "Decision id linked to this + component" annotation that KB-CAD then displays without it + being canonical there. Read-only annotations from AtoCore's + perspective, advisory metadata from KB-CAD's perspective. +2. **Live polling for very small payloads.** A daily poll of + "what subsystem ids exist in KB-CAD now" so AtoCore can flag + subsystems that disappeared from KB-CAD without an explicit + AtoCore invalidation. +3. **Direct NX integration** if the KB-CAD layer becomes a + bottleneck — but only if the friction is real, not theoretical. +4. **Cost / vendor / PLM connections** for projects where the + procurement cycle is part of the active engineering work. + +None of these are V1 work and they are listed only so the V1 +design intentionally leaves room for them later. + +## Open questions for the V1 implementation sprint + +1. **Where do the export schemas live?** Probably in + `docs/architecture/kb-cad-export-schema.md` and + `docs/architecture/kb-fem-export-schema.md`, drafted during + the implementation sprint. +2. **Who runs the exporter?** A scheduled job on the KB-CAD / + KB-FEM hosts, triggered by the human after a meaningful + change, or both? +3. **Is the export incremental or full?** Full is simpler but + more expensive. Incremental needs delta semantics. V1 starts + with full and revisits when full becomes too slow. +4. **How is the exporter authenticated to AtoCore?** Probably + the existing PAT model (one PAT per exporter, scoped to + `write:engineering-import` once that scope exists). Worth a + quick auth design pass before the endpoints exist. + +## TL;DR + +- AtoCore is a one-way mirror in V1: external tools push, + AtoCore reads, AtoCore never writes back +- Two import endpoints for V1: KB-CAD and KB-FEM, each with a + documented JSON export shape +- Drift surfaces as conflicts in the existing conflict model +- No NX, no FEM solvers, no PLM, no vendor portals, no + cost/BOM systems in V1 +- Bidirectional sync is reserved for V2+ on a per-tool basis, + only after V1 demonstrates value