Documentation Verification¶
Every page below was checked against the EIDOS source code at commit 19d408be on 2026-08-25. Divergences are marked at the top of each page. The KM sources are unchanged — these marks live only in this reference site.
29 pages audited — 9 verified · 15 minor · 5 diverging · 53 findings.
| Page | Status | Findings | Notes |
|---|---|---|---|
| Documents Engine | Diverges | 6 | All six first-pass findings survived adversarial re-verification against the code on disk: the blocklist section describes read-time filtering that GET /node/{id}/documents and the admin browse endpoint genuinely do not perform (confirmed no is_blocked call in either read path), and five canonical_operations signatures in the KM YAML are confirmed stale/wrong against the actual documents_engine.py/documents_import.py functions — status remains diverges on the blocklist behavioural gap alone (kind=behaviour, severity=high), independently reinforced by two medium-severity api-signature contradictions. |
| Domain Registry | Diverges | 5 | Diverges confirmed: the doc's 'Backend proxy routing' section describes a get_domain_base_uri(domain_key) function implemented in tools/backend/domain_catalog.py that does not exist anywhere in the codebase (grep confirms zero matches outside the docs themselves) — the real backend-side resolver is an unrelated _SECONDARY_DOMAINS dict built in backend/server.py from backend/domains.json, and the cited file path tools/backend/domain_catalog.py doesn't exist (only tools/backend/domains.json and access_rules.db are there; the real module is tools/bootstrap/domain_catalog.py). Secondary, lower-severity issues survive too: a fictional initApp() frontend entry point (real one is init(), line 3003) plus stale line numbers for loadRegistry/getBaseURI/resolveBaseForURI/baseToDomain; a misnamed mutation-gate function (doc says _mutationBase, code has _mutationApiBase at line 5490 — but its described validate-and-return-null behaviour is otherwise accurate); and the 'Adding a New Domain' port/prefix checklist omitting the existing document domain (port 8097, prefix @). |
| Eidos Loader | Diverges | 2 | Both first-pass findings survive adversarial verification: the KM YAML's canonical_operations names three functions (load_graph, invalidate_cache, get_cached_graph) that exist nowhere in the codebase — confirmed by direct grep of backend/ — while the real canonical entry points load_instance (line 549) and refresh_instance (line 558) are correctly documented elsewhere on the same page; sources.files also points at a nonexistent backend/eidos_loader.py rather than the real backend/persistence/eidos_loader.py. |
| Frontend Crud | Diverges | 3 | Adversarial re-check confirms all three first-pass findings against the code on disk: HeaderAddInfoBtn is genuinely gone (deleted in ec5b324c, locked in by tests/test_frontend_node_header_declutter.py), EngAddPropForm is a fictional name for the real AddPropForm component, and every one of the doc's precise app.js/detail-panel.js line citations is stale by 130-3100 lines — the HeaderAddInfoBtn removal is a genuine high-severity behavioural contradiction, so the page keeps its "diverges" verdict. |
| Rulebook Engine | Diverges | 3 | All three first-pass findings survive adversarial verification with exact file:line confirmation: canonical_operations names three functions (apply_property_inheritance/apply_relation_inheritance/apply_property_propagation) that exist nowhere in backend/domain/rulebook_engine.py (whose real methods are cascading_properties, is_relation_inheritable, get_relation_rule, relation_inheritance_overridable, intra_propagation_rules, inter_propagation_rules); the doc's RuleCatalog.add()/remove()/serialize_catalog_for_audit()-as-instance-method claims are false against rule_catalog.py's actual surface (from_rulebook, rules, get, referencing_objects, with add/delete done via free functions add_movement_rule/delete_movement_rule in rulebook_store.py, and serialize_catalog_for_audit being a module-level function); and the doc's three per-category admin PUT routes do not exist in admin_rulebook_router.py, whose actual routes are generic movement-rule CRUD plus separate propagation-rules and rule-catalog families. Each is a genuine API-kind, high-severity contradiction that would mislead a reader into calling nonexistent functions/routes. |
| Cache Coherence | Minor divergences | 1 | The cache-coherence.md page's behavioural claims are highly accurate: get_effective_graph()/_load()'s cache-then-invalidate strategy, the four-stage lifecycle, DomainStore.invalidate()/_clear_caches(), bump_version_counter()/read_version_counter(), the cross-process integer sentinel in mutations/_cache_version, the write_lock() asyncio+fcntl double-lock, and the merge_overlay/failure-mode discussion all match backend/persistence/mutation_store.py and backend/persistence/eidos_loader.py line-for-line (including specific cited line numbers such as write_lock at line 149 and bump_version_counter at line 97). The one divergence is a stale file path in the KM entity's sources.files list itself. |
| Composite View Assembly | Minor divergences | 2 | The four-stage merge_overlay algorithm (tombstone-filter-first, then relation tombstones, node tombstones, overlay merge) is accurately described and matches backend/domain/graph_merge.py line-for-line for Steps 1-4d. Two divergences: the sources.files path is wrong, and Step 4e (append overlay relations) omits a tombstone-endpoint filter added to the code after the doc's verified_at_commit. |
| Cross Domain Resolution | Minor divergences | 3 | The core routing mechanism (resolveApiBase/_sigil/sourceDomainKeyForBase in frontend/plugins/domain-routing.js, and apiFetch/getBaseURI/baseToDomain/loadRegistry in frontend/app.js) is described accurately and the quoted code excerpts match the code verbatim. However the domain inventory is stale (a 6th domain, 'document', now exists and is omitted) and essentially every cited app.js line number is wrong, pointing to unrelated code — the file has grown substantially since the doc's verified_at_commit. |
| Domain | Minor divergences | 1 | The domain.md doc is exceptionally precise about schema, file paths, function names, and even quotes several code blocks verbatim and correctly (e.g. domain-routing.js sourceDomainKeyForBase, eidos_loader.py domain-root detection, server.py apiFetch, config/domains.yaml field list). One divergence found: the self-proxy guard section misattributes the guard to the wrong function and misquotes the HTTP status code it raises. |
| Domain Routing Key Invariant | Minor divergences | 8 | The core guarantee, enforcement mechanism (apiFetch's branch/throw logic, baseToDomain, the DomainRouting resolver functions, and the domains.json baseURI/publicURI split) all match the code exactly in behaviour and identifier names. However, every specific line-number citation in the compiled doc page is stale — the actual locations in frontend/app.js have shifted by roughly 700-870 lines since the doc was last verified (verified_at_commit d50caf31), and the KM YAML's sources.files lists only a reference doc (docs/architecture/cross-domain-base-resolution.md), omitting the actual code files (frontend/app.js, frontend/plugins/domain-routing.js) that the compiled page's claims depend on. |
| Effective Graph | Minor divergences | 2 | Code claims are largely accurate and verified with high precision — merge_overlay's exact line-134 citation for nodes.update(overlay["nodes"]), the tombstone/node-tombstone filtering snippets, the _cache dict keys/lifecycle (invalidate/_clear_caches/_bump_cache_version/patch_remove_relation), and get_effective_graph() all match backend/persistence/eidos_loader.py, backend/domain/graph_merge.py, and backend/persistence/mutation_store.py exactly. Two minor divergences found. |
| Export Engine | Minor divergences | 2 | The compiled doc page (docs/manual/dev/export-engine.md) is exhaustively accurate against the code — all ~35 canonical_operations symbols (frontend plugin functions, EidosExportRegistry, backend routes, export_service functions) were confirmed present with matching names/signatures/behavior across frontend/plugins/*.js, frontend/app.js, backend/server.py, backend/persistence/export_service.py, backend/api/mutations_io_router.py, backend/api/api_reports_router.py, and backend/routes/project_io.py. Two minor divergences found. |
| Graph Merge | Minor divergences | 2 | The compiled doc page is unusually precise: merge_overlay's signature, the four-phase algorithm order, the exact line numbers for the function definition (line 30) and the Phase-4 guard (line 126), the _strip_prefix/_build_ref helpers and their worked examples, and the eidos_loader._load() call site (verified lines 361-382 match verbatim, including the ImportError guard and BL-FE-080 ordering rationale) all match backend/domain/graph_merge.py and backend/persistence/eidos_loader.py exactly as they exist on disk. Two divergences survive: the KM entity YAML's sources.files cites a nonexistent path for the module itself, and the 'Relation merge' prose omits a real protective filter the code applies to overlay relations. |
| Import Pipeline | Minor divergences | 1 | The described parse/normalize/evaluate/commit/cache-invalidation behaviour, function signatures (parse_excel, normalize_paths, fuse_anchor_first_segment, _excel_evaluate_commands, relation_import_idem_key), error codes (NODE_LABEL_DUPLICATE, PARENT_NOT_RESOLVED, ALREADY_COMMITTED), idempotency-key format, and write-atomic/cache-invalidation mechanics all match the code exactly. The one material gap is stale file attribution: the doc and the KM entity's sources.files repeatedly claim the two endpoints and the _excel_evaluate_commands/_excel_parse_and_setup helpers are 'defined in backend/server.py', but they were extracted into backend/api/mutations_excel_router.py on 2026-07-02 (after this doc's verified_at_commit of 2026-06-22). server.py now only includes the router and re-exports the two helper names for backward compatibility; it no longer contains their definitions. |
| Mutation Pipeline | Minor divergences | 1 | The core claims check out against the actual implementation: preview issues a server-side previewId via mutation_store.write_preview and commit consumes it single-use via consume_preview (returning 400 PREVIEW_REQUIRED on reuse); derive_entity_uuid (UUID v5) is called inside mutation_engine.build_preview during the preview pass, guaranteeing preview-UUID == commit-UUID; mutation_store.write_atomic does temp-file write → fsync → os.replace; cache invalidation bumps a monotonic sentinel counter that eidos_loader picks up to re-run domain.graph_merge.merge_overlay. The one divergence is the doc's generic route notation, which doesn't reflect the real, non-parametrized endpoint set. |
| Mutation Store | Minor divergences | 2 | All documented canonical operations exist with matching signatures and behaviour in backend/persistence/mutation_store.py (write_atomic, load_overlay, invalidate, write_tombstone, write_node_tombstone, load_ownership, write_ownership, cleanup_stale_previews, get_effective_graph all verified against DomainStore methods and module-level wrappers). Directory layout, field-name mapping table, write_lock(), ensure_dirs() subdirectory list, and cross-process cache-version mechanism all match the code exactly. Two minor omissions found. |
| Overlay Wins On Conflict | Minor divergences | 2 | The invariant, its enforcement point (merge_overlay in backend/domain/graph_merge.py), the Step 4a/4b node-merge logic, the tombstone-ordering fix, and the BL-FE-037 regression test all match the code precisely, including exact line 134 for nodes.update(overlay["nodes"]) and near-verbatim code quotes for the Step-1 tombstone pre-filter. The one divergence is in the KM YAML itself: sources.files cites a nonexistent path for the enforcement file. |
| Preview Before Commit | Minor divergences | 1 | The invariant's guarantee, enforcement mechanism, and single-use semantics are accurately described and verified against backend/persistence/mutation_store.py (write_preview, consume_preview), backend/domain/mutation_engine.py (build_preview, derive_entity_uuid, _canonicalize), backend/api/mutations_router.py (commit endpoint PREVIEW_REQUIRED gate ordering), and frontend/app.js:9042 (I-2 Confirm-button disable logic matches exactly). One minor factual inaccuracy found regarding where cleanup_stale_previews is invoked at startup. |
| Reports Engine | Minor divergences | 1 | All canonical_operations, function signatures, file paths, error classes, route paths, and integration behaviour (StreamingResponse, dependency check, split Mermaid/SVG/PDF pipeline) match backend/reports/*.py and backend/api/api_reports_router.py exactly. One small internal inconsistency found in the compiled doc's own prose. |
| Search Engine | Minor divergences | 5 | The described flow (Ctrl+K dialog, DOMAIN_REGISTRY fan-out via Promise.allSettled with a shared AbortController, dedup by id+domainBase, GET /search dispatching to _search_v2_impl behind GLOBAL_SEARCH_V2, Wave A/B semantics, IAM filtering, _gs_assign_group bucket routing, and the _domainBase/_domainLabel/_domainIcon/_domainColor result fields) is all accurate and verified in code. However several canonical_operations entries reference symbols/signatures that do not literally exist as named, and the doc page's parameter table for GET /search omits a real, functional query parameter. |
| Agents Engine | Verified | — | Every canonical operation, signature, agent-class step sequence, status/HTTP-code table, and layer claim in the doc matches backend/agents/{init,base,create_node_agent,create_relation_agent,update_node_agent}.py and the POST /command handler in backend/server.py (lines 3675-3723) exactly. AgentResult fields, check_idempotency/command_hash behaviour, per-agent execute() flows (idempotency check -> validate -> derive uuid/find subtree root -> lock -> write overlay + idempotency record -> invalidate -> audit -> return), the 200/201/422/409/400 status table, and the mutation_engine bridge functions (validate_add_node, validate_create_relation, validate_update_node, derive_entity_uuid, find_subtree_root, build_overlay_node, build_overlay_relation, build_overlay_update_node) all check out against the code on disk. |
| Atomic Write | Verified | — | Every code-checkable claim matches the code exactly. The quoted write_atomic implementation (temp file via tempfile.mkstemp, fsync, os.replace, cleanup-on-exception) is byte-for-byte identical to backend/persistence/mutation_store.py:224-238. _acquire_file_lock/_release_file_lock (lines 73-94), the per-loop _loop_write_lock/_write_loop_locks dict (lines 136-145), write_ownership's lock-then-write_atomic pattern (lines 494-515), the CCR Rule 5 module-header annotation, and the load_overlay exception-swallowing comment (line 335, verbatim 'silence: malformed overlay file; skip entry') are all confirmed present and behaving as described. No divergence found. |
| Canonical Deep Link | Verified | — | All code-checkable claims match current code: canonicalNodeShareUrl/copyShareLink (frontend/app.js:4481-4497) build the link from the UUID extracted via uriToId (app.js:6326-6329) + BASE_URL, never the raw @id; notifications.py:66-67 builds {base}/node/{uuid} from req.node_id; export_service.canonical_web_uris (export_service.py:62-77) stamps the primary origin on every hasDomain edge regardless of per-domain publicURI, exactly as described; resolveDomainBaseForNode/nodeToTreeIndex (app.js:2768-2777) and the non_local_node/proxyRoutes 404 fallback in loadNodeDetail (app.js:4846-4864, 6352-6365) are present and match the described consumer-side resolution. |
| Deterministic Uuid | Verified | — | The KM entity's sources.files lists only two reference markdown docs (no code files), but the compiled doc page makes extensive, precisely verifiable code claims about backend/domain/mutation_engine.py and backend/infra/key_derivation.py — all confirmed accurate: _canonicalize (mutation_engine.py:52-64, exact _TRANSIENT_FIELDS set and four-key envelope), derive_entity_uuid (mutation_engine.py:67-72, exact uuid.uuid5(NAMESPACE_EIDOS, ...) call), payload_hash (mutation_engine.py:75-78), the build_preview call site cited as 'line 257' matches exactly (node_uuid = derive_entity_uuid(cmd, parent_context=parent_id)), NAMESPACE_EIDOS/NAMESPACE_SEEDED_RELATION/NAMESPACE_BOOTSTRAP constants and ownership comments (key_derivation.py:24-36) match verbatim, and the CreateRelation/parent_context=None claim is confirmed by derive_overlay_relation_uuid (key_derivation.py:47-64), which builds a (sourceId, targetId, relationType) cmd and delegates to mutation_engine.derive_entity_uuid with no parent_context, making it truly 'the single point of UUID derivation for all overlay nodes and overlay relations' as claimed. |
| Excel Importer | Verified | — | Every canonical operation, signature, status value, error path, and behavioral claim in the doc page matches backend/api/excel_importer.py exactly as it exists on disk (parse_excel, normalize_paths, parse_relation_rows/resolve_relation_rows, parse_property_rows/resolve_property_rows, parse_product_node_rows, fuse_anchor_first_segment, relation_import_idem_key, _load_workbook_guarded all verified line-for-line, including exact error message strings and status-value sets). |
| Iam Engine | Verified | — | Re-verified 2026-09-02 after hardening 0.2 (#520) + 0.9 (#531): ALL relation write-paths are node-scoped gated — preview/commit + delete + heal-uuid via _iam_reject_if_locked on the source node, and document-attach via _gate_item_write. The KM source documents the two-helper model (mutations router vs Excel-import) incl. both 403 bodies. No remaining gaps in relation write authorization; IamGuard unification is trin 3.2. |
| Mutation Engine | Verified | — | Every code-checkable claim in the YAML and compiled doc matches backend/domain/mutation_engine.py as it exists on disk: all listed canonical_operations (derive_entity_uuid, validate_add_node, build_preview, build_preview_update_node, build_preview_relation, build_overlay_node, build_overlay_relation) plus the additional documented functions (payload_hash, validate_update_node, validate_create_relation, build_overlay_update_node, resolve_owner, find_subtree_root) exist with the exact signatures, error codes, validation-stage ordering, and overlay-document field sets described. The 'does not write to disk' / pure-function boundary claim holds — no filesystem or network calls appear in the module. NAMESPACE_EIDOS, _TRANSIENT_FIELDS, and the required-field constants match verbatim. infra/key_derivation.py confirms NAMESPACE_EIDOS and derive_overlay_relation_uuid exist as referenced, and docs/architecture/key-derivation-audit-2026-05-13.md (the second sources.files entry) exists on disk. |
| Overlay | Verified | — | The overlay.md page's claims about the JSON-LD overlay layer, its on-disk layout, the write_atomic/load_overlay/write_tombstone/write_node_tombstone functions, the _normalize_node field mapping, and the merge_overlay tombstone-ordering logic (including the specific line-134 nodes.update(overlay['nodes']) citation) all match backend/persistence/mutation_store.py and backend/domain/graph_merge.py exactly as they exist on disk. Function signatures, line-number citations (write_atomic 224-238, invalidate mechanics, DomainStore fields), directory names (nodes/, relations/, tombstones/, node_tombstones/), and both stated invariants (overlay-wins-on-conflict, atomic-write) are all borne out by the code. The sources.files directory entry backend/mutations/nodes/ is currently empty on this checkout (no nodes have been created yet) but is a valid runtime path created by DomainStore.ensure_dirs(), not a code-path divergence. |
| Relation Catalog | Verified | — | Every canonical operation in the YAML (frontend: loadRelationCatalog, getApplicablePredicates, getAssociationPredicates, isTargetCompatible, getPredicateById, resolveTargetDomainForPredicate, isCableNode; backend: get_all, get, filter_for_source_type, validate_relation, validate_relation_domains, is_hierarchy, is_available_for_association, get_association_predicates, get_default_association_predicate, get_allow_unresolved, get_cardinality, invalidate_cache) matches an identically-named, identically-signatured function in frontend/relation-catalog.js and backend/domain/relation_catalog.py respectively. The compiled doc's detailed claims — validation stage order and error codes (HIERARCHY_VIA_RELATION_ENDPOINT, UNRESOLVED_NOT_ALLOWED, CATALOG_VIOLATION, DOMAIN_NOT_ALLOWED_FOR_PREDICATE) in mutation_engine.validate_create_relation, the lazy from domain import relation_catalog import there, the module-level import and GET /relation-catalog endpoint plus get_cardinality() use during inheritance resolution in server.py, and the isCableNode cable-code-prefix logic — all verified against the current code. |