Home / Projects / Orchestrata Ultimate / Decisions / ADR index / ADR-0086
ADR-0086: Claude sessions get a project-scoped SPEC-106 context pack at SessionStart
| field | value |
|---|---|
| Status | Proposed |
| Date | 2026-10-11 |
| Register | factory (docs/adr, 4-digit ids) |
| Source | docs/adr/0086-session-graph-context-injection.md — recorded on branch feat/session-ctx-inject at 030a4ff64, not yet on master |
| Wiki register entry | ADR-0086 (wiki status: Proposed) |
The record
Status: Proposed · Date: 2026-10-11
Context
Claude Code sessions start with flat dumps (session_resume_context.py prints the
whole task list — "156 pending work items … and 151 more"). The selective,
graph-backed injection the field calls context injection (inject only the slice
relevant to the current work) already exists in this repo for volks —
knowledge_graph/context_injector.py ContextInjector.inject_for_task over the
SPEC-106 pipeline analyze_request → select → pack → render — but nothing feeds it
to Claude sessions, and the earlier attempt (claude/hooks/context_graph, Ctx*
labels) has no writer, reads a Neo4j that no longer exists, and its only caller
(claude/hooks/session_context_hook.py) is registered nowhere live.
The SPEC-106 pipeline is also unusable at repo scale today. Measured 2026-10-11 on
the test fleet orchkg (10.53.2.10, 725,636 nodes):
| Defect | Measurement |
|---|---|
D-1 selector.select hop-0 / root match is (n:A OR n:B …) AND (n.id = rid OR n.alias = rid) — no index can serve it |
~5.7 s per id; a 3-entity request linked 90 ambiguous ids → ~8.5 min; scripts/context_pack.py did not finish in 120 s on any run. Per-label indexed MATCH (n:L {key: rid}) UNION form: 0.03 s for 5 ids; full 2-hop BUILD expansion 0.078 s |
D-2 frame._fetch_candidate_names downloads every linkable name per call |
14.6 s unscoped (Function 10.4 s / 160,840 rows); 8.4 s even project-scoped |
D-3 the shared orchkg holds one full code copy per worktree, id-prefixed <project>: |
Class nodes: wt-GD-CONVERSATION 6573, wt-GD-GATEWAY 6573, wt-AST-ROOTS 6568, orchestrata-ultimate 6286, orchestrata-ultimate-architecture 1668 …; n.project_id unpopulated → every name links ambiguously |
Design contract: plans/contracts/session-graph-context.{mmd,contract.json}
(validate_mermaid: valid classDiagram, 106 lines).
Decision (proposed)
- Fix D-1/D-2/D-3 inside SPEC-106 (indexed per-label root lookups; token-driven
indexed candidate lookup with
_foldre-check; project-scoped linking via an indexed id range>= "<p>:" AND < "<p>;"). - Add a SessionStart hook (
orchestrata_ultimate.context.session_graph_context, shim.claude/hooks/session-graph-context.sh, registered in.claude/settings.jsonand mirrored bygen_plugin.py) that builds the request from the session goal + current step, handoff alerts/files, branch, and files changed vsorigin/master, and emits a 1500-token pack viahookSpecificOutput.additionalContextunder a 5 s wall clock; every failure path prints one line and exits 0.
Four points need Mohamed's ruling:
- R1 — REQ-106-012 narrowing. Indexed lookup cannot serve full case/underscore
folding. Consequences: S1 a run-together lowercase token (
contextinjector) no longer linksContextInjector; S2 Modules link by full dotted name, not bare last segment. Recommendation: accept S1/S2 now; record the full-fold alternative (an indexedname_foldedproperty written at ingest) as a follow-up. RULED 2026-10-11 — option B (Mohamed: "b"): REQ-106-012 is NOT narrowed. Every writer of a linkable node (Module, Class, Function, Spec, Requirement, Volk) stores an indexed folded-name property (_foldof id, name, qualified_name and its last segment), and token linking matches_fold(token)against that index. S1 and S2 do not happen. The ingest change lands before the linking change; existing graphs are backfilled by the same writer path. - R2 — new requirement REQ-106-045: "Entity linking is scoped to the request's
project when one is known; other projects' nodes are not candidates."
Recommendation: mint it.
RULED 2026-10-11 — option A (Mohamed: "a"): REQ-106-045 minted (unchecked) in
specs/106-context-semantic-layer/checklists/requirements.mdunder FR-002; callers that pass no project keep cross-project linking. - R3 — un-ingested worktree. A fresh
wt-*has zero nodes. Fall back to the distribution projectorchestrata-ultimate(may lag the branch) with a visible reason line, or print only a one-line notice? Recommendation: fall back, with the reason line. RULED 2026-10-11 — option C (Mohamed: "no injest the project C"): when the session's project has no nodes, the hook ingests the project. No fallback to another project. The ingest reuses the existing path that already writes per-worktree<project>:code copies intoorchkg(no second ingester). Because a full ingest exceeds the 5 s session-start budget, the hook starts it detached and reports it in one line; the pack for that project is served once the ingest lands. The contract is amended to name that ingest seam and its completion signal. - R4 — the old hook. Retire
claude/hooks/session_context_hook.pyand re-trace REQ-020-030/031 to the new hook, or keep it and mint a new row? Recommendation: retire and re-trace (deleting the file needs Mohamed's permission).
Forks found while amending the contract for R1/R3 (2026-10-11, contract
specGap), open for Mohamed:
- F1 — ingest duration. Measured from
~/.local/state/ast-sync/*.log: ~900-module trees ingest in 38 s–1,498 s; ~3,400-module trees in 4,995 s–21,217 s (1.4–5.9 h). Under R3=C a fresh full-tree worktree therefore gets its first pack hours later. Accept, or first open a write-throughput item (D-8)? - F2 — orphan copies.
wt-FLOSS-CORPUS(4,708 code nodes) has no directory left, so no writer can backfill its fold properties. Garbage-collect project copies whose source root is gone, or leave them unlinkable? - F3 — R3 has no requirement row. Mint REQ-106-046 ("an un-ingested project is ingested, never substituted")?
- F4 — registration vs RUL-035. The contract registers the hook in the repo's
.claude/settings.json(thegen_plugininput); RUL-035 says hooks are registered at user level only. Register at user level instead?
Found and designed out (no ruling needed, fixed in the build): D-7 —
claude/hooks/ast_sync_hook.py falls back to <repo>/.env for the graph endpoint,
which names prod, so an edit in a shell without direnv can sync a worktree into prod
orchkg; the launcher resolves the endpoint from the process env, then
~/.config/ast-sync/env, nothing else.
Alternatives rejected
- Revive
context_graph(Ctx*) — no writer exists; it targets Neo4j; the session/code graph already holds the data SPEC-106 selects from. - Keep the flat dump — the problem this ADR exists to solve.
- Unscoped linking — measured 90-way ambiguity per 3 tokens on the shared graph.
- Cache the full name table on disk — still a 14.6 s cold fetch and a second source of truth that drifts from the graph.
Consequences
- Every Claude session in this repo receives a bounded, selective code/spec context block; session start never blocks (5 s + 7 s shell backstop) or fails.
- SPEC-106 consumers (volk
ContextInjector,scripts/context_pack.py) become usable at repo scale; REQ-106-044 (checked today, false at scale) is re-proved by scale tests against the sharedorchkg(read-only). - Follow-ups: D-4
scripts/graph_query.pyignoresORCHESTRATA_ENV_PROFILE; D-5 thecontext_graphtest leaks an orphanCtxTask; D-6 every checkout's.envsetsKG_ROUTING_URIto prod10.53.1.160:7691— only the shell export protects sessions;Ctx*package removal remains a separate decision.
Provenance
- Mohamed, 2026-10-11, on what replaces
context_graph: "research the word context injection … i mean in the web too", then "now you are getting it, start working". - R1 ruled 2026-10-11 by Mohamed: "b" (keep full fold semantics via an ingest-side indexed folded-name property).
- R2 ruled 2026-10-11 by Mohamed: "a" (mint REQ-106-045, project-scoped linking).
- R3 ruled 2026-10-11 by Mohamed: "no injest the project C" (an un-ingested project is ingested, not substituted).
- Measurements: this session's probes against the test fleet; contract by the
analyst agent,
plans/contracts/session-graph-context.contract.json.
Related ADRs
No other ADR is named in this record.
Rulings cited
- RUL-035: RUL-035 — Hooks live at the user level only and scope themselves to the project in cwd