Orchestrata Ultimate › Plans › evidence › w8-context-layer-inventory
W8.1 Ground-Truth Inventory — Context Semantic Layer (2026-07-06)
Source: plans/evidence/w8-context-layer-inventory.md at 8a2cb42ad · last changed 2026-07-27 · first committed 2026-07-06 · 101 lines.
Prose pending.
Plan text
W8.1 Ground-Truth Inventory — Context Semantic Layer (2026-07-06)
Evidence pack for the W8.2 design. Produced read-only while W4.4 (injector merge) was IN FLIGHT — context_injector.py findings marked pre-merge must be re-verified after W4.4 lands.
1. KG schema-as-built — SIX independent, uncoordinated writers
| Writer | File | Labels | Merge key(s) | Rels |
|---|---|---|---|---|
| AST->KG bridge | knowledge_graph/sync.py:32-889 (Neo4jSyncer, via scripts/sync_ast_to_neo4j.py) | Project, Package, Module, Class, Function, Method, Parameter, Requirement, Test | id (all; hardcoded constraint list sync.py:69-81) |
DEFINES (sync.py:538), INHERITS_FROM, IMPORTS, CALLS, TESTED_BY (sync.py:808), HAS_METHOD |
| Spike writer | knowledge_graph/synchronizer.py:280,369 (FileSynchronizer) | File (path key), Class/Function |
path/id |
DEFINES (File->sym), HAS_METHOD, CALLS, INHERITS, IMPORTS |
| Pipeline runtime | kernel/pipeline_kg.py:140,208,240,312,318 | Volk, Artifact, Intent, PipelineRun, Decision, Requirement | Volk=alias; Requirement=req_id (DIVERGES from sync.py id) |
GENERATED_BY, EXECUTED_BY, TRIGGERED, MADE, JUSTIFIED_BY, APPLIES_TO |
| Session KG sync | session/kg_sync/_stage_code.py:281-378 + _stage_specs_traces.py:114-297 | Class/Function (methods collapsed into :Function w/ class_id), Spec, Requirement, RequirementItem | Class/Fn id = {relpath}::{Name} (DIVERGES from sync.py qualified-name ids) |
HAS_CLASS/HAS_FUNCTION (3rd rel for what sync.py calls DEFINES), TRACES_TO (->RequirementItem!), IMPLEMENTS |
| kg_design spike | knowledge_graph/kg_design.py:142,493,506,561 | CodeClass (distinct from Class!) | {name, project} composite | TRACES_TO (CodeClass->Requirement direct) |
| Misc audit/session | kernel/audit/writers.py:295, gateway/audit.py:40, memory/cold_store.py:92, orchestrator/fact_neo4j.py:70, orchestrator/neo4j_audit.py:346, session/kg_sync/_stage_session.py:44,86, harness/history.py:165 | Session, Project, Volk | Session: session_id x4 vs id vs seq (3 keys!); Project: id vs slug; Volk: alias vs volk_id vs name (3 keys!) |
— |
Constraint split-brain: 3 non-overlapping "schemas": sync.py:69-81 hardcoded (13 labels, some never written); schema.py:113-139 LABEL_* (21 labels; get_all_ddl() at :175 has ZERO callers); types_enums.py:24-58 NodeType/RelationshipType StrEnums (12 types, missing Task/Method/Volk/Intent/Decision/PipelineRun). No single command creates a consistent schema.
2. Injection surfaces
- ContextInjector (knowledge_graph/context_injector.py) — ONLY wired surface; invoked from kernel/pipeline_kg.py:63-66; INJECT_SUBJECTS (:23-32) = implement/fix_issues/review_and_test/design_review/scope_review/ux_design. Queries are :File-rooted (:377,422,447) — matches FileSynchronizer's shape, NOT sync.py's Module-rooted shape => a KG populated only via scripts/sync_ast_to_neo4j.py is INVISIBLE to ContextInjector.
- LABEL-MISMATCH BUGS (silent empty sections, not errors): queries [:TRACES] vs actual DEFINES_REQUIREMENT; [:TESTS] vs actual TESTED_BY (sync.py:808); TRACES_TO->Requirement vs actual TRACES_TO->RequirementItem (_stage_specs_traces.py:283).
- Task-type layer (TaskType BUILD/REFACTOR/DEBUG/DOCUMENT/TEST/REVIEW + inject_for_task): merged per D9 (W4.4); tests exist (tests/knowledge_graph/test_context_injector_task_types.py, 545 lines) but inject_for_task has ZERO call sites in src/ — wiring is W8.5's job.
- SIZE CONTROL VERDICT: PARTIAL/DECORATIVE. MAX_ENTITIES=50 + MAX_CONTEXT_CHARS=8000 (:34-35) DECLARED BUT NEVER REFERENCED; real caps = scattered hardcoded Cypher LIMITs (5/50/20/10) + to_prompt(max_context_tokens=4000) char-estimate truncation (:64,:90). No k-hop bound, no per-node-type budget, no pre-injection token count. SPEC-009's <100ms NFR is NOT test-gated for the injection path.
3. Reusable assets
- domaingen IR (models.py:34-87): DomainModel/Module/Entity/Field/Relationship pure dataclasses; parse_ontology (reader.py:178, rdflib OWL/TTL); render_ontology (ttl.py:99); generate_code (generator.py:105, topo-sorted).
- openspec/ (SPEC-104): parse_spec (parse.py:79), detect_spec_folder (detect.py:42) — ZERO consumers, unused island; live spec parsing = session/spec_parser.py (parse_all_specs <- _stage_specs_traces.py:45,52). DECISION NEEDED: adopt or keep island.
- Token counters (memory/token_counter.py): WordTokenCounter:15, TiktokenCounter:44 (real tiktoken w/ fallback), get_token_counter(provider):84; .count(text)->int, .truncate(text,max)->str — reusable for pack budgeting.
- Memory recall: MemoryEngine.search (memory_engine.py:207) cosine over <=1000 hot-store candidates; EMBEDDINGS ARE A P1 STUB (embedding.py:16-38, hash-projected TF-IDF; sentence-transformers deferred P2) => ranking must lean on graph-structural signals, not vector similarity.
- AST serialization (plans/ast-ultimate.json, 10.4MB): 618 modules / 1144 classes / 926 functions / 4632 methods; classes carry raw @traces decorator strings; NO complexity field, NO requirements field => sync.py:449-451 _sync_requirements is DEAD CODE (always empty); real Requirement nodes come from core/tracing/scanner.py collect_traces() via _stage_specs_traces.py:225.
- Claude-side brief surface: scripts/gen_codebase_map.py + inject-codebase-map.sh hook (two-tier, static, not task-aware) — the integration point for scripts/context_pack.py (W8.4).
4. Gaps the design must fill (ranked)
- NO CANONICAL CODE-GRAPH WRITER — labels/ids/rels diverge across 5-6 writers; a selector query gets 0/1/3 disjoint nodes depending on which writer last ran. Canonicalize (one writer/id scheme) BEFORE building the selector, or every query needs coalesce-style multi-key matching (context_injector.py:679,698 already does this defensively).
- Requirement/Spec pipeline split + partially dead (AST-bridge no-op vs session/kg_sync live path) — ONE extraction path needed.
- inject_for_task unwired (0 call sites) — W8.5.
- No real token/size budget enforcement (constants dead; no k-hop bound).
- No semantic ranking signal (embedding stub) — use graph-structural ranking.
- No editable-pack format exists — VolkContext.to_dict()/to_markdown() is the closest precedent but is a fixed render.
- openspec island decision.
5. Risks
- MERGE-KEY DIVERGENCE (Session x3 keys, Volk x3, Project x2, Requirement x2) = HIGHEST severity: selectors silently see partial graphs — exactly the degraded-context failure Wave 8 exists to fix.
- Enum/constant split-brain: 3 sources of truth for labels/rels, none authoritative.
- context_injector.py observed changing 528->1172->528 lines mid-audit (W4.4 in flight) — re-verify final state before W8.2 design.
- Injector label mismatches under-deliver context TODAY (silent empty sections) — worth fixing regardless of the new design.
Not covered
kg_design.py full read; _stage_folders/_stage_docs bodies; Neo4j runtime verification (all static Cypher analysis); domaingen/constraints.py + stardog.py bodies; orchestrator audit writers beyond merge-key grep; false-confidence-test pass on tests/knowledge_graph/* (recommend separate audit before W8.3/W8.4).