docs(arch): tool-handoff-boundaries + representation-authority
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.
This commit is contained in:
273
docs/architecture/representation-authority.md
Normal file
273
docs/architecture/representation-authority.md
Normal file
@@ -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 <external system>". 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
|
||||
339
docs/architecture/tool-handoff-boundaries.md
Normal file
339
docs/architecture/tool-handoff-boundaries.md
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user