Orchestrata Ultimate › Plans › spec-audit › reverify-2026-10-18 › C-knowledge-memory
Cluster C — Knowledge, memory, context & compliance (reverify 2026-10-18)
Source: plans/spec-audit/reverify-2026-10-18/C-knowledge-memory.md at 8a2cb42ad · last changed 2026-10-18 · first committed 2026-10-18 · 279 lines.
Prose pending.
Plan text
Cluster C — Knowledge, memory, context & compliance (reverify 2026-10-18)
Read-only re-verification of SPEC-008, 009, 010, 019, 026 against CURRENT code
(branch components, 337 commits ahead of the 3-month-old audits). Evidence from
the AST toolkit only (symbols / refs / source); .py files never hand-read.
Builds on docs/spec-gap-register.md (2026-07-14), plans/spec-audit/C-knowledge-memory.md
(session 195), and 00-MASTER-PLAN.md §2. Main-session findings trusted (not
re-verified): SPEC-010 FR-008 migrate_to_cold wired via
gateway/handlers/session.py::_migrate_close_memories; SPEC-010 FR-001 IMemoryEngine
DI wired via gateway/server.py (DI singleton + handler wiring).
SPEC-008 Knowledge Graph — DONE (tree-sitter divergence resolved in-spec; only :Component live-population + orphaned ArchitectureWriter remain)
- Specifies: Neo4j KG as shared institutional memory — 13 node types, 19 relationship types, temporal props, context-injection Cypher, tree-sitter code parsing, file-watch sync, plus Phase-2 runtime-signal ingestion (FR-012) and validator feedback loop (FR-013).
- Verified:
- Schema (FR-001/002/003): ✅ all 13 original labels present in
canonical_schema.py(LABEL_PORTFOLIO/…/COMPONENT/VOLK/DECISION/ARTIFACT/FILE/CLASS/FUNCTION/PREDICATE/RULELABEL_COMPONENTin Tier C) —canonical_schema.pyis now the single DDL source (docstring:schema.pyLABEL_*+get_all_ddl()have zero callers). Provenance edges (REL_TRACES_TO,REL_HAS_SESSION,REL_HAS_AGENT, …) live alongside.
- Semantic layer (provenance writers): ✅
sync_intent_to_kg(kernel/pipeline_kg.py:523, usedkernel/pipeline.py:411+orchestrator/pipeline_runner.py:768),sync_artifacts_to_kg(pipeline_kg.py:396, usedpipeline_runner.py:769),sync_decisions_to_kg(pipeline_kg.py:590, usedpipeline_runner.py:776). All wired at runtime. - Context injection (FR-004/005 + FR-011): ✅
ContextInjector(context_injector.py:501, wiredcontext/assembler.py:84+kernel/pipeline_kg.py:174/191); expanded sections_query_recent_changes(:931),_query_similar_patterns(:1071),_query_semantic_context(:1256—(sym)-[:TRACES_TO]->(:RequirementItem)+(:Decision)-[:APPLIES_TO]->(x)). - Code parsing (FR-006/007): ✅ capability present (file/class/function/predicate extraction);
mechanism = stdlib
ast+ regex Prolog scanner, now recorded in-spec (spec.md FR-006/007 "Implementation note"). Divergence RESOLVED. - File watching (FR-008/009): ✅
FileWatcher(file_watcher.py:31,_watch_loop:108,_handle_delete:215);GraphSyncer(sync.py:58,full_sync:218,_sync_ast:259). - Runtime signals (FR-012): ✅
RuntimeSignalWriter(runtime_writer.py:42,write_message:73/write_gateway_event:169/write_decision:244/write_tool_call:301), wiredagents/volks/base.py:83/129+kernel/pipeline_kg.py:177/192. - Validator loop (FR-013): ✅
GraphContextValidator(graph_context_validator.py:87,validate:279) +ValidatorLoop(context_validator_loop.py:43), wiredagents/volks/base.py:290/293. :Component: ⚠️ still not populated by the live pipeline. A writer now exists —ArchitectureWriter(architecture_writer.py:390, usesLABEL_COMPONENTat 537/1399-1835) — butrefs ArchitectureWriter→ 0 IMP/0 USE insrc/(onlyscripts/sync_architecture_to_graph.py:96touches the label). So:Componentis writable only via an orphaned writer / a script, never by the pipeline/sync at runtime.
- Schema (FR-001/002/003): ✅ all 13 original labels present in
- Remaining work / plan:
- Scope: (a)
:Component— decide keep-or-drop. If keep, wireArchitectureWriterinto the pipeline (or move its MERGE intosync.py); if drop, remove label + orphaned writer. (b) Add the orphanedArchitectureWriterto the dead-code ledger if (a) chooses drop. - Target files:
knowledge_graph/architecture_writer.py(wire/delete),knowledge_graph/sync.py(alternative writer),canonical_schema.py(remove label if dropping). - Approach: no live consumer depends on
:Component; low value either way. Spec-hygiene + one keep/drop call. - Dependencies: none live (self-contained). Effort: S. Risk: low.
- Scope: (a)
- Evidence log:
symbols --pattern GraphSyncer|FileWatcher|ContextInjector|RuntimeSignalWriter|GraphContextValidator|ValidatorLoop→ all present (files above).refs RuntimeSignalWriter→agents/volks/base.py:83/129,kernel/pipeline_kg.py:177/192.refs ValidatorLoop→agents/volks/base.py:290/293.refs sync_intent_to_kg|sync_artifacts_to_kg|sync_decisions_to_kg→ wiredpipeline.py:411,pipeline_runner.py:768/769/776.refs ArchitectureWriter→ DEF only (0 production refs) = orphaned.refs LABEL_COMPONENT→architecture_writer.py+scripts/sync_architecture_to_graph.py:96only.
SPEC-009 Volk Context Injection — DONE (consolidated into SPEC-106/107; VolkContextInjector deleted, task-typed path now wired)
- Specifies:
VolkContextInjector.inject_for_task(volk_alias, task_type, task_params)with 6 task-typed KG queries (BUILD/REFACTOR/DEBUG/DOCUMENT/TEST/REVIEW) returningVolkContext(to_dict/to_markdown). Spec status line + consolidation note (2026-07-13) already record the merge intoContextInjector.inject_for_task+UnifiedContextAssembler. - Verified:
VolkContextInjector(FR-001 named class): ⚠️ deleted —symbols VolkContextInjector→ 0. The spec's own consolidation note covers this: the standalone class is superseded.- Task-typed API (FR-002): ✅
ContextInjector.inject_for_task(context_injector.py:1369) — deterministicRequestFrame→context_pack.select→packunder a token budget, adapts the pack back toVolkContext(Module/Class/Function→files, Spec→specs, Requirement→requirements), no LLM/embedding in selection. Six_inject_*_contexthandlers retained (unused, documented). TaskTypeenum (FR-002): ✅context_injector.py:87(BUILD/REFACTOR/DEBUG/DOCUMENT/TEST/REVIEW).- Wiring (FR-001/002 consumption): ✅
UnifiedContextAssembler(context/assembler.py:71,assemble:134) callsinjector.inject(..., task_type=..., task_params=...);ContextInjector.inject(context_injector.py:584) →inject_for_taskat:644whentask_typeis set. Production call site_assemble_context_for_subject(kernel/pipeline_kg.py:934-958) passestask_type=SUBJECT_TASK_TYPE.get(subject).SUBJECT_TASK_TYPEimported atkernel/pipeline_kg.py:35(module-level constant, not asymbols-indexed def) and read at:793/:958. - Output formats (FR-009/010): ✅
VolkContextdict/markdown produced byinject_for_task(rendered pack →context.summary;task_contextdict →payload["task_context"]).
- Remaining work / plan:
- Scope: spec-hygiene only — FR-001 still reads "SHALL provide
VolkContextInjector… importable fromorchestrata.knowledge.volk_context_injector", which is now false (class + module gone). Reword FR-001/FR-002 to state the consolidated delivery path. - Target files:
specs/009-volk-context-injection/spec.md(FR-001/002 text). - Approach: text-only; the consolidation note at the top already declares the supersession.
- Dependencies: none. Effort: S. Risk: low.
- Scope: spec-hygiene only — FR-001 still reads "SHALL provide
- Evidence log:
symbols VolkContextInjector→ 0 (deleted).symbols UnifiedContextAssembler→context/assembler.py:71.refs UnifiedContextAssembler→kernel/pipeline_kg.py:18 (IMP), 178/193/934 (USE).refs inject_for_task→ DEFcontext_injector.py:1369+ USEcontext_injector.py:644(called byinject).source kernel.pipeline_kggrepSUBJECT_TASK_TYPE→ import:35, reads:793/:958.
SPEC-010 Memory Engine — PARTIAL (DI + migrate_to_cold now done; PAM++ FR-013 is the one substantive gap left)
- Specifies: DI-registered
IMemoryEngine(ComponentType.MEMORY_ENGINE), dual Redis-hot/Neo4j-cold storage, embedding search, summarize/budget, hot→cold migration on session close, PAM++ governance- audit on every op.
- Verified:
- Interface + 8 ops (FR-002–005/016 + delete + migrate): ✅
MemoryEngineProtocol(core/protocols/memory.py:153— store:161, retrieve:177, search:191, summarize:217, update:228, delete:240, migrate_to_cold:245). Note: the abstract class is now a Protocol (IMemoryEngine→symbols0;core/interfaces/memory.py:17re-imports the Protocol). ConcreteMemoryEngine(memory/memory_engine.py:48) implements all eight (store:146, retrieve:191, search:209, summarize:264, update:282, delete:315, migrate_to_cold:326). - FR-001 DI: ✅ DONE (trusted) —
gateway/server.py:468 _register_memory_engineregisters the DI singleton + wires handlers (main-session verified; not re-verified here). - FR-008 hot→cold migration: ✅ DONE (trusted) —
refs migrate_to_cold→ USEgateway/handlers/session.py:381(the_migrate_close_memoriescall path). - FR-006/007 storage: ✅ hot
RedisMemoryStore(hot_store.py:49— store/retrieve/retrieve_by_scope/ retrieve_by_tag/embeddings/delete/delete_session); coldGraphMemoryStore(cold_store.py:55,store:150MERGEs(:Memory)+-[:BELONGS_TO]->(:Session)+-[:CREATED_BY]->(:Agent)+(:Project)hub edges). ⚠️store()writes hot only — cold write happens at migration (FR-002's "write cold asynchronously" is not per-store; consistent with the spec's own migration model). - FR-009/010 embedding+similarity: ✅ capability present but ⚠️ mechanism diverges —
EmbeddingService(embedding.py:16) uses a hash-based TF-IDF word-frequency vector (dim 384), not sentence-transformers all-MiniLM-L6-v2. Docstring is explicit: "sentence-transformers integration deferred to P2." Cosine similarity + threshold + limit implemented (embedding.py:64/77). - FR-005/012 summarize+budget: ✅
ContextCompressor(compressor.py:21, extractivesummarize:35); budget-aware kernel injection now delivered viarecall_sync/summarize_for_thread_sync(memory/memory_context.py:225/294) folded intoUnifiedContextAssembler.assemble(context/assembler.pymemory layer,recall_budget = layer_budget("memory") - 500). - FR-011 token counting: ⚠️
WordTokenCounter(token_counter.py:15) +TiktokenCounter(:42) present;AnthropicCounter→ 0 symbols. Engine hardcodesWordTokenCounter(memory_engine.py:89) — no provider-aware selection. - FR-014/015 classification + decay: ✅
MemoryClassificationenum (PRIVATE/SHARED/SYSTEM) +_apply_decay(memory_engine.py:345) with half-lives 24h/168h/720h (:38-42) — exact spec match. - FR-016/017 update + limits: ✅
update:282(recomputes embedding, bumpsupdated_at),MAX_CONTENT_LENGTH=32KB/MAX_TAG_COUNT=50(memory_engine.py:36-37), raisesValueError. - FR-013 PAM++ governance: ❌ still OPEN —
symbols can_store_memory|can_read_memory| can_share_memory|can_delete_memory→ 0 each. No ownership/permission query, no audit emission in any memory op (onlylogger.debug/error). - Recall wiring (US-001/003): ✅
register_memory(memory/memory_context.py:102) wiredagents/kernel_handler.py:249+kernel/pipeline.py:337+orchestrator/pipeline_runner.py:792;recall(:180) consumedagents/volks/base.py:241.
- Interface + 8 ops (FR-002–005/016 + delete + migrate): ✅
- Remaining work / plan:
- Scope: (1) FR-013 PAM++ — add
can_store/read/share/delete_memorypredicates to the governance Prolog base (on janus, not pyswip) and enforce + audit in every op (the one real remaining feature). (2) Minor: addAnthropicCounter+ provider-aware token-counter selection (FR-011); record the sentence-transformers→hash-embedding deferral as an in-spec divergence note (FR-009); decide whether store() should also write cold async (FR-002) vs the migration-only model. - Target files:
memory/memory_engine.py(PAM calls + audit),prolog/governance.pl(+ predicates),memory/token_counter.py(anthropic),specs/010-memory-engine/spec.md(divergence notes). - Approach: PAM predicates are the L item and couple to the governance engine (SPEC-060) + janus adapter; the engine is already DI-singleton (FR-001) so an enforcement wrapper can be layered in without a new lifecycle decision.
- Dependencies: PAM/governance (SPEC-060) + janus Prolog adapter for FR-013; provider manager (SPEC-011) for the token-counter selection. Effort: L (PAM) / S (the rest). Risk: med.
- Scope: (1) FR-013 PAM++ — add
- Evidence log:
symbols MemoryEngine|MemoryEngineProtocol|RedisMemoryStore|GraphMemoryStore|EmbeddingService|ContextCompressor|WordTokenCounter|TiktokenCounter→ all present.symbols IMemoryEngine|AnthropicCounter→ 0.symbols can_*_memory→ 0 each (FR-013 OPEN).refs migrate_to_cold→ USEgateway/handlers/session.py:381.refs register_memory→ kernel_handler/pipeline/pipeline_runner.source memory.memory_engine→ store writes_hot.storeonly;_apply_decay+ half-lives; limits 32KB/50 tags.source memory.embedding→ hash-based TF-IDF, "sentence-transformers deferred to P2".source memory.cold_store→(:Memory)-[:BELONGS_TO]->(:Session),-[:CREATED_BY]->(:Agent), Project hub.
SPEC-019 Intent Impact Analyzer — PARTIAL (classify+deps+plan wired; interface-verification & circular-dep still unwired/absent)
- Specifies:
ImpactAnalyzer→ classification + dependency impact + test discovery + interface verification (breaking-change detection) + parallel planning, wired as a pipeline step in the intent broker. - Verified:
- Classification (FR-001/002/003): ✅
IntentClassifier(orchestrator/impact/classifier.py:114,classify:143,_score_intent_types:165,_extract_entities:189,_extract_package:204,_extract_module:222). ⚠️ keyword/regex heuristic, not a ≥0.85-accuracy model (quality NFR, not structural). - Dependency analysis (FR-004/005/006): ✅
DependencyAnalyzer(orchestrator/impact/dependency_analyzer.py:19,find_affected_scope:55,_find_tests:183). Queries:Package/:Module— KG sync populates those labels (canonical_schema Tier A), so the coupling is real. - Parallel planning (FR-010/011/012/013): ✅
ParallelPlanner(orchestrator/impact/planner.py:33,create_plan:44,_build_branches:74, agent assignment_create_impl_tasks:136). - Orchestration + wiring (FR-014): ✅
IntentImpactAnalyzer(orchestrator/impact/analyzer.py:27,analyze:50) wiredorchestrator/intent_broker.py:72+intent_broker_factory.py:46+impact/cli.py:28. - GAP-1 interface verification (US-004, FR-007/008/009, ERR-007): ❌ still absent —
symbols InterfaceVerifier→ 0. The dataclasses exist (InterfaceContracttypes.py:122,BreakingChange:132,ImpactReport.interface_verification:247, default None) but have no producer:analyze()(analyzer.py:50-72) runs only classify →_find_impact_scope→create_plan, and never setsinterface_verification.find_interface(dependency_analyzer.py:203) is never called byanalyze()/_find_impact_scope. ERR-007 (block on breaking change) can never fire. - GAP-2 circular-dependency detection (FR-015, ERR-006): ❌ still unwired —
find_circular_deps(dependency_analyzer.py:241) exists but is not invoked byanalyze()/_find_impact_scope; cycles never surface inImpactReport.
- Classification (FR-001/002/003): ✅
- Remaining work / plan:
- Scope: (1) build
InterfaceVerifier(extract contract via the existingfind_interface, predictBreakingChanges, produceInterfaceVerification), wire intoanalyze()+ populateImpactReport.interface_verification, and enforce ERR-007 in the intent broker. (2) invokefind_circular_depsinside_find_impact_scopeand surface cycles (CRITICAL per ERR-006). (3) optional: the classifier accuracy target. - Target files: new
orchestrator/impact/interface_verifier.py;orchestrator/impact/analyzer.py(wire verifier + circular deps);orchestrator/intent_broker.py(ERR-007 gate). - Approach: types + KG extraction already exist — this is assembly + wiring, not greenfield. Breaking-change prediction from intent text is the hard part; scope a conservative heuristic first and flag the ≥95% accuracy target as aspirational.
- Dependencies: KG (SPEC-008) for interface/circular queries (labels populated). Independent of memory/DI/PAM. Effort: M. Risk: med (prediction accuracy).
- Minor:
@tracesonclassifier.py/analyzer.py/types.pyciteSPEC-100/placeholder reqs rather than SPEC-019 ids (traceability-hygiene, not functional).
- Scope: (1) build
- Evidence log:
symbols IntentClassifier|DependencyAnalyzer|ParallelPlanner|IntentImpactAnalyzer→ present;symbols InterfaceVerifier→ 0.refs IntentImpactAnalyzer→intent_broker.py:72,intent_broker_factory.py:46,impact/cli.py:28.source orchestrator.impact.analyzer→analyze()= classify → scope → plan only (no interface/circular step).source orchestrator.impact.dependency_analyzer→find_interface:203,find_circular_deps:241present but uncalled.source orchestrator.impact.types→interface_verification:247default None;InterfaceContract:122,BreakingChange:132.
SPEC-026 Compliance Volk (U:Cp) — DONE (minor signature/subject drift only)
- Specifies: deterministic
ComplianceVolk(U:Cp) running a 7-step pipeline after U:Qa: scan@traces→ load requirements from KG → generate RTM → sync code → check compliance → persist RTM (disk+KG) → report; graceful KG degradation; zero LLM. - Verified:
ComplianceVolk(FR-001): ✅agents/volks/compliance/volk.py:46(BaseAgent,alias="U:Cp",role="Compliance"), wiredkernel/pipeline.py:250(USE). ⚠️ subject string iscompliance_check(process:93), not the spec'scompliance(functional, one-line drift).- 7-step pipeline (FR-002/003): ✅
_run_pipeline:147calls in orderscan_traces(_pipeline.py:77),load_requirements(:116),generate_rtm(:177),sync_code(:219),check_compliance(:252),persist_rtm(:288),_calculate_results(volk.py:187). - Lazy KG init + graceful degradation (FR-033/034): ✅
_init_kg(volk.py:72,@tracesREQ-026-033/034) lazy-constructsKGDesignStore, non-fatal (setskg_store=Noneon failure). ⚠️ renamed from the spec'sget_kg_store(symbols get_kg_store→ 0). - Determinism (NFR-006): ✅ zero LLM calls in the compliance path.
- Report production (FR-029–032): ✅
_calculate_results(volk.py:187) +_build_report_artifact. - Status transition (FR-004): ⚠️
self.status = WorkStatus.IN_PROGRESS(volk.py:129); spec's IDLE→RUNNING→COMPLETED wording is stale vs the currentWorkStatusmodel.
- Remaining work / plan:
- Scope: none functional. Optional spec-hygiene: align FR-001 subject (
compliance_check), theget_kg_store→_init_kgrename,BaseVolk→BaseAgent, and the_calculate_resultslocation (method vs module function). Signature drift (load_requirements(kg_store, project_dir),generate_rtm(traces, requirements, task_summary), etc.) is functional, not a gap. - Target files:
specs/026-compliance/spec.md(API-contract + subject + terminology). - Approach: text-only. Effort: S. Risk: low.
- Scope: none functional. Optional spec-hygiene: align FR-001 subject (
- Evidence log:
symbols ComplianceVolk→volk.py:46;refs ComplianceVolk→kernel/pipeline.py:250.symbols scan_traces|load_requirements|generate_rtm|sync_code|check_compliance|persist_rtm→ all in_pipeline.py.source agents.volks.compliance.volk→process:93subject check,_init_kg:72,_run_pipeline:147.
Cluster summary table
| Spec | Class | Effort | Hard deps |
|---|---|---|---|
| SPEC-008 Knowledge Graph | DONE (minor :Component + orphaned writer) |
S | none live (self-contained) |
| SPEC-009 Volk Context Injection | DONE (consolidated → 106/107) | S (spec text) | none |
| SPEC-010 Memory Engine | PARTIAL (PAM++ FR-013 only) | L (PAM) · S (rest) | PAM/governance (060) + janus; token-counter → provider (011) |
| SPEC-019 Intent Impact Analyzer | PARTIAL | M | KG (008) [populated]; agents (U:Cd/Qa/Ar) |
| SPEC-026 Compliance Volk | DONE (drift only) | S (spec text) | — |
Real remaining work (this cluster)
- SPEC-010 FR-013 — the one substantive item: PAM++ memory predicates (
can_store/read/share/ delete_memory, all 0 symbols) + enforcement/audit in every op. Couples to SPEC-060 governance (janus, not pyswip). FR-001 DI and FR-008 migration are now DONE (trusted). - SPEC-019 — build+wire
InterfaceVerifier(FR-007/008/009) and wire the existingfind_circular_deps(FR-015); both confirmed still absent/unwired. - SPEC-008 / SPEC-009 / SPEC-026 — spec-hygiene only (no code work):
:Componentkeep/drop + orphanedArchitectureWriter; SPEC-009 FR-001 stale class reference; SPEC-026 subject/rename drift.
Cross-cluster dependencies noticed
- memory (010) ↔ governance/PAM (060) — FR-013 needs the Prolog governance base on janus + an enforcement wrapper; the engine is already DI-singleton (024 adopted via FR-001), so no new lifecycle decision remains.
- impact-analyzer (019) ↔ KG (008) — DependencyAnalyzer depends on
:Package/:Modulenodes (populated by sync); interface/circular queries ride the same schema. - context-injection (009) ↔ KG (008) ↔ SPEC-106/107 — the task-typed injector is consolidated onto
the SPEC-106 selector/packer (
context_pack); no further work here beyond the FR-001 text.