Orchestrata Ultimate / Specs / 107-context-injection-improvements

107-context-injection-improvements: Context-Injection Improvements

The existing context assembler (src/orchestrata_ultimate/context/assembler.py) has the right layered shape, but several layers are either empty in production or under-used:

At a glance

Item Value
Spec directory specs/107-context-injection-improvements/
Status line in the spec not stated
Requirement IDs defined 73
With a @traces citation in src/ 13 (17.8%)
With a @traces citation in tests/ 1 (1.4%)
Tracked files 2
RTM page 107-context-injection-improvements

Reading this spec

This spec improves how context reaches agents through the existing layered context assembler. The assembler has the right shape, but several layers are empty or under-used in production: session and goal context is implemented but never fed because production callers pass no context data, the plan layer is budgeted but never populated, memory recall loads an unbounded number of entries and scores them in Python, the semantic graph and the serialized AST are rich sources that are not injected automatically, context use per layer is not logged so tuning is blind, and the artifact store is in-memory only with no digest pagination.

Four ruling constraints apply. Selection is never LLM-driven; ranking and filtering stay deterministic, matching SPEC-106 FR-003. The UnifiedContextAssembler.assemble() signature is unchanged, and new layers are optional parts. Every new source has a no-op fallback when its backend (Neo4j, Memgraph, Redis or Prolog) is unavailable. Tests use real backends, without mocks, on production context paths.

The fourteen functional requirements (FR-001 to FR-014) are: session and plan context, bounded memory recall (for example a max_age_seconds pre-filter before similarity scoring), a semantic-graph context layer, an AST-derived context layer (a budgeted summary of the most relevant complex or called symbols), context telemetry, an artifact store refactor (digests ranked by recency and relevance, top-N within budget), on-demand context tools, context pack caching, expanded graph-context sections (requirements and decisions found through TRACES_TO and APPLIES_TO), runtime signal ingestion, a validator feedback loop, and snapshot and knowledge-base freshness (the ast-sync step runs incrementally, cutting a no-change run from 60.7 s to 8.3 s). The last two requirements concern delivery: claude/ in the repository is the source of truth and ~/.claude is a deployment of it, the deployed virtual environment is verified free-threaded with no reference to the source checkout, and shipping is mechanical. The 73 requirement IDs are numbered REQ-107-NNN.

The code touches many places, so each module holds only a few citations: context tools (6 requirements), the AST context, plan context and semantic context providers, the usage log, the artifact store and the context injector. The requirements traceability matrix lists each ID. The spec states no status line and tracks 2 files. Measured coverage is 13 of 73 requirements cited by at least one @traces in src/ (17.8%), spread over 9 modules; the module citing the most of them is orchestrata_ultimate/tools/context_tools (6 requirements). In tests/, 1 requirement is cited by a test-side @traces. 60 requirements have no citing symbol; the behaviour may still exist in code that was never annotated.

Requirements

Checkbox is the state recorded in the requirements checklist; Traced by is the count of src/ symbols whose @traces names the ID.

ID Done Requirement Traced by
REQ-107-001 yes Production PipelineRunner and gateway paths load ContextData from the active SessionController and pass it to UnifiedContextAssembler.assemble() none
REQ-107-002 yes mission_context.render_mission_context() is rendered into the mission layer when context_data is supplied none
REQ-107-003 yes A plan_context provider renders recent pipeline outcomes / next planned stages into the existing plan budget 3
REQ-107-004 yes An observed test proves the mission layer is non-empty when a session has active goals none
REQ-107-060 yes PlanParser parses plans/execution-plan.md into structured (step_num, title, goal, actions, verify, expected) tuples 8
REQ-107-061 yes Goal persists a current_step index; the session controller provides advance_goal_step and set_goal_step none
REQ-107-062 yes plan_context provider uses current_step to render the current step in full plus next steps and recent done summaries none
REQ-107-005 yes MemoryEngine.search accepts a max_entries pre-filter before similarity scoring none
REQ-107-006 yes MemoryEngine.search accepts a max_age_seconds pre-filter before similarity scoring none
REQ-107-007 yes Default filters (max_entries=50, max_age_seconds=3600) keep memory recall bounded in UnifiedContextAssembler none
REQ-107-008 yes An observed test proves recall returns at most max_entries results none
REQ-107-009 yes SemanticGraphContextProvider queries Memgraph for chunks relevant to a query string none
REQ-107-010 yes The provider contributes a semantic part to ContextAssembly for subjects implement, fix_issues, and review_and_test none
REQ-107-011 yes When Memgraph is unavailable the provider returns an empty string without raising none
REQ-107-012 yes An observed test proves semantic context is injected for implement subject none
REQ-107-013 yes AST complexity, branch, and call-graph signals are queryable from Neo4j or the AST snapshot none
REQ-107-014 yes An ast_context provider returns a budgeted summary of the most relevant complex/called symbols 1
REQ-107-015 yes When the AST/KG source is unavailable the provider returns an empty string without raising 4
REQ-107-016 yes An observed test proves ast_context is non-empty for a task targeting a known module none
REQ-107-020 yes Every UnifiedContextAssembler.assemble() call logs ContextUsage.to_dict() at INFO 1
REQ-107-021 yes scripts/context_usage_report.py exists and can aggregate per-layer token spend from logs or a session record 1
REQ-107-022 yes The report script can aggregate per-volk and per-subject token spend none
REQ-107-030 yes ArtifactStore accepts an optional output_dir and persists each artifact to a JSONL file none
REQ-107-031 yes ArtifactStore replays the JSONL file into the in-memory index on construction none
REQ-107-032 yes render_artifact_digest ranks artifacts by recency/relevance and renders only top-N within budget 1
REQ-107-033 yes PipelineArtifact carries optional spec and reqs fields none
REQ-107-034 yes ArtifactStore.by_requirement(req_id) returns artifacts whose reqs include that id none
REQ-107-035 yes An observed test proves artifacts survive an ArtifactStore reconstruct cycle none
REQ-107-050 yes get_code tool returns content or signature for a canonical code entity id 4
REQ-107-051 yes get_tests tool returns covering tests for a canonical code entity 4
REQ-107-052 yes get_requirements tool returns traced requirements for a canonical code entity 5
REQ-107-053 yes search_code tool returns semantic-search context for a natural-language query 2
REQ-107-054 yes Tools degrade gracefully when Neo4j or Memgraph is unavailable 11
REQ-107-055 yes Tools are registered as SPEC-062 native tools and exposed to Architect, CodeDirector, QA, and Documentor 1
REQ-107-056 yes Observed tests prove each tool against real Neo4j/Memgraph none
REQ-107-070 yes UnifiedContextAssembler caches rendered ContextPack output by (snapshot_id, volk_alias, subject) for the lifetime of a pipeline run none
REQ-107-071 yes An observed test proves the cache returns identical context parts for repeated calls with the same key none
REQ-107-080 yes GraphContext populates a recent_changes section from explicit Change nodes, NEXT_VERSION chains, or file timestamp properties none
REQ-107-081 yes GraphContext populates a similar_patterns section with files sharing base classes or protocols with target files none
REQ-107-082 yes GraphContext populates a semantic_files section via the Memgraph semantic-search bridge none
REQ-107-083 yes GraphContext populates requirements and decisions sections by traversing TRACES_TO and APPLIES_TO relationships none
REQ-107-084 yes Requirement closure walks REQUIRES edges up to a bounded depth and returns shortest-hop records none
REQ-107-090 yes Runtime signals (Message, ToolCall, Decision, GatewayEvent) are persisted to Neo4j with deterministic ids none
REQ-107-091 yes Runtime signals link to mentioned File/Class/Function nodes via MENTIONS edges none
REQ-107-092 yes Kernel pipeline dispatch, orchestrator runner, and BaseAgent wire the RuntimeSignalWriter none
REQ-107-100 yes GraphContextValidator validates LLM responses against core entities cited in graph_context none
REQ-107-101 yes ValidatorLoop retries LLM calls with expanded context when validation fails none
REQ-107-102 yes ContextExpansion controls extra_hops, include_tested_by, include_requirement_closure, and limit_multiplier none
REQ-107-110 yes ast-sync passes --incremental, warm-starting from the snapshot on disk and re-parsing only changed files (60.7s → 8.3s on a no-change run; 2819 modules before and after) none
REQ-107-111 yes ast-sync --snapshot-only runs steps 1/1b and stops, skipping the frozen-monorepo serialization and deep comparison none
REQ-107-112 yes main() parses the argv it is given; argv=None inheriting sys.argv aborts an in-process caller under pytest with SystemExit(2) none
REQ-107-113 yes Freshness is evaluated at the point of USE and scoped to the files the task touches, not across the whole tree none
REQ-107-114 yes A consumer that cannot reach the KB distinguishes "queried, answer is nothing" from "could not query" none
REQ-107-115 yes Blast radius resolves impact targets from the module's parsed AST, not module-api (__all__ is declared by only 136 of 2816 modules — 4.8%) none
REQ-107-116 yes Every bound on an answer (fan-out, parse caps, project scoping) is stated in the output none
REQ-107-117 yes code_intel.py impact accepts many qnames in one invocation, and the six-symbol fan-out cap is removed rather than documented (it left 456 of 2485 symbols — 18% — unqueried) none
REQ-107-120 yes claude/ in this repo is the source of truth; ~/.claude is a deployment of it and nothing is authored in the deployed tree none
REQ-107-121 yes The deployment copies files — no symlink from ~/.claude into a checkout none
REQ-107-122 yes The deployment owns a uv venv on python3.14t, and ~/.claude/.envrc auto-activates it under direnv none
REQ-107-123 yes The installer rewrites settings.json hook commands to the venv's absolute interpreter, because Claude Code spawns hooks from the project's cwd where direnv never applies none
REQ-107-124 yes The installer records the source commit and refuses success unless every deployed file is byte-identical to that commit's blob none
REQ-107-125 yes The drift comparison survives SIGPIPE and trailing-newline stripping — both previously made it report nothing, which reads as a pass none
REQ-107-126 yes Deployed files are enumerated, never selected by filename heuristic (--exclude='test_*.py' once deleted 8 live files including a registered hook) none
REQ-107-127 yes A verification that matched zero files fails (CHECKED -gt 0 asserted explicitly) none
REQ-107-128 yes The deployed venv is verified free-threaded, and no deployed file references the source checkout none
REQ-107-130 yes ship runs verify → push → deploy → verify-the-deployment in one sequence none
REQ-107-131 yes ship is reachable by name on PATH, and the installer verifies that by name rather than by path none
REQ-107-132 yes Each project states its own gate in ship; an unknown project fails rather than shipping unverified none
REQ-107-133 yes The dirty-tree check excludes tooling-rewritten paths, narrowly — sibling hand-written pages in the same directory still block none
REQ-107-134 yes A Stop hook refuses to end a turn while a watched repo holds local-only commits none
REQ-107-135 yes That hook stays quiet while a ship for the repo is already running, detecting it by whole-argv-element equality against the resolved executable (pgrep -f "bin/ship" substring-matched its own poller and returned true unconditionally) none
REQ-107-136 yes In-flight detection is by process, not lockfile — a lockfile outliving a SIGKILL would suppress the guard permanently none
REQ-107-137 yes --no-verify states that it skips only this script's gate, and warns that an installed pre-push hook still runs none

Code that traces this spec

Module Symbols Requirements
orchestrata_ultimate/context/providers/ast_context 1 1
orchestrata_ultimate/context/providers/plan_context 1 1
orchestrata_ultimate/context/providers/semantic_context 1 1
orchestrata_ultimate/context/usage_log 2 2
orchestrata_ultimate/core/artifact_store 1 1
orchestrata_ultimate/knowledge_graph/context_injector 1 1
orchestrata_ultimate/knowledge_graph/semantic_bridge 2 1
orchestrata_ultimate/planning/plan_parser 8 2
orchestrata_ultimate/tools/context_tools 17 6

Checklists

checklists/requirements.md

The requirement list above comes from this file; 73 of 73 checkbox items are ticked.

Full spec text

Verbatim from specs/107-context-injection-improvements/spec.md; headings are pushed down two levels.

SPEC-107: Context-Injection Improvements

Version: 0.4.0 (draft)
Date: 2026-07-14
Status: Draft — Phase 2 context layers landed (semantic, AST, recent changes, similar patterns, requirement closure, runtime signals, validator loop); FR-012 snapshot/KB freshness added 2026-08-13; FR-013 (the machinery is a deployed artifact) and FR-014 (shipping is mechanical) added 2026-08-14
Depends on: SPEC-008 (knowledge graph), SPEC-009 (volk context injection), SPEC-106 (context semantic layer)

Problem

The existing context assembler (src/orchestrata_ultimate/context/assembler.py) has the right layered shape, but several layers are either empty in production or under-used:

Ruling constraints

  1. No LLM-driven selection. All context ranking and filtering remains deterministic, matching SPEC-106 FR-003.
  2. Backward-compatible assembler contract. UnifiedContextAssembler.assemble() keeps the same signature; new layers are optional parts.
  3. Degrade, don't crash. Every new source must have a no-op fallback when its backend (Neo4j, Memgraph, Redis, Prolog) is unavailable.
  4. Observed tests only. No mocks for production context paths; tests use real MemoryEngine/Neo4j/Memgraph where applicable.

FR-001: Session and plan context

FR-002: Bounded memory recall

FR-003: Semantic-graph context layer

FR-004: AST-derived context layer

FR-005: Context telemetry

FR-006: Artifact store refactor

FR-007: On-demand context tools

FR-008: Context pack caching

FR-009: Expanded graph-context sections

FR-010: Tier-H runtime signal ingestion

FR-011: Validator feedback loop

FR-012: Snapshot and KB freshness

The AST snapshot (plans/ast-ultimate.json) is the input every deterministic context layer is derived from: the Prolog code-intelligence KB is rebuilt from it, FR-004's AST layer reads it, and the gate fact base is extracted from it. A stale snapshot therefore does not weaken those layers, it makes them confidently wrong — the consumer has no way to tell an answer about deleted code from a current one.

FR-013: The injection machinery is a deployed artifact, not a home directory

Every layer above is delivered by hooks, tools and skills that Claude Code loads from ~/.claude. Until 2026-08-14 that directory was the only copy: unversioned, un-reviewed, and un-restorable, which made the injection layer the least governed code in the project while being the code that runs on every prompt.

FR-014: Shipping is mechanical

Context injection that exists only as a local commit changes nothing: worktrees branch off origin/master, so an unpushed commit leaves the next delegated task building on a base that does not contain it. This is the drift that left the claude/ dev folder 8831 lines behind the live config.