Elnor Repo Reader

DOC16_R5_4.md

Current Specs/DOC16/DOC16_R5_4.md

Short text page ee4765e17bbe. Generated 2026-06-09T01:23:58.539Z from commit dbaa25962edc11ab30e8d4ca1715f9ae5bf77331. Worktree: clean.

Open readable HTML page · Open raw txt · Open path URL

ELNOR REPO READER TEXT MIRROR
Original path: Current Specs/DOC16/DOC16_R5_4.md
Source repo: /Users/OpenClaw1/Elnor/Elnor Specs
Git branch: main
Git commit: dbaa25962edc11ab30e8d4ca1715f9ae5bf77331
Generated: 2026-06-09T01:23:58.539Z

---

# DOC16 — Deferred Additions (R5.4)

**Revision Lineage (must persist in all later versions):**
- Based on `DOC16_Deferred_Additions_R4.md`
- Incorporates `DOC16_Memory_Context_Code_Awareness_Delegation_Patch_R2.md`
- Incorporates `DOC16_Patch_R2_Doc_by_Doc_Amendment_Map_R1.md`
- Supersedes `DOC16_Deferred_Additions_R5_1_COMPLETE.md`
- Incorporates `DOC16_Deferred_Additions_R5_12_COMPLETE.md` (substantive additions reconciled into this cleaned version)
- Earlier source files already subsumed by R4 remain subsumed here, including:
  - `DOC16_DEFERRED_ADDITIONS_PUNCH_LIST_R3.md`
  - `DOC16_Punch_List_Additions_CIL_Session.md`
  - `DOC16_DEFERRED_ADDITIONS_PUNCH_LIST_R3_1_Knowledge_Topology_Alignment.md`
  - `DOC16_Punch_List_Additions_CIL_Session_R1_1_Graph_Topology_Alignment.md`

**Current Operative Revision:** R5.3  
**Consolidation/Cleanup Note:** R5.3 keeps the cleaned structure from R5.2, preserves the full R4-chain substance, the full Patch R2, and the full Doc-by-Doc Amendment Map R1, and also incorporates the additional preserved amendment wave from R5.12 for interactive chat / forum / panel latency, streaming, and composer responsiveness.  
**Interpretation Rule:**
1. This is a planning / preservation / amendment-home-base document, not a final owner spec.
2. The R4 chain remains the inherited baseline, but only its latest operative sections are carried forward here.
3. The Patch R2 brief adds the unified new architecture package.
4. The Doc-by-Doc Amendment Map provides the most detailed owner-allocation and drafting guidance where overlap exists.
5. If two later sections overlap, the later more specific section governs.

---

## Part I — Core Deferred Architecture (latest operative content from the R4 chain)

## Purpose

DOC16 is a **running punch list** for side additions, future integrations, and deferred-but-important work that is **not the primary focus of the current drafting cycle**, but should **not be lost**.

This document is meant to:

- preserve important ideas that emerged during spec, audit, and implementation review,
- distinguish **what should be added later** from what must be handled immediately,
- give enough detail that later drafting or implementation does not have to rediscover the problem,
- provide exact placement and coding guidance for future incorporation into the canonical specs,
- reduce repeated red-teaming churn by maintaining a stable “other things still to do” list.

## How to use this document

Each entry in DOC16 should include:

1. **Problem statement** — what is missing, broken, or weak today.
2. **Why it matters** — what failure mode or value justifies the work.
3. **Relevant OpenClaw / system capability** — what native capability or external change makes this possible or necessary.
4. **Recommended architecture decision** — what we should do, and what we should not do.
5. **Required spec changes** — exactly which documents should be amended and how.
6. **Required code changes** — exact services, schemas, routes, stores, jobs, or UI needed.
7. **Risks and mitigations** — what could go wrong if implemented badly.
8. **Suggested implementation sequence** — safest order for doing the work later.
9. **Acceptance criteria** — how we know it is done correctly.

## Status key

- **Deferred** — important, but not part of the current active spec pass
- **Planned** — should be incorporated in a later drafting wave
- **Ready for spec** — enough clarity exists to amend the canonical specs
- **Ready for code** — specs are sufficient and build work can begin
- **Done** — fully incorporated into canonical specs and/or code

---

---

# Entry 16.1 — Semantic Search / Local Embeddings for ELNOR Memory (QMD)

**Status:** Deferred → Planned  
**Priority:** High  
**Primary owners:** DOC1 / canonical memory spec / DOC15 / Q memory surfaces  
**Secondary owners:** DOC10, Running Brief, DOC11 (clarifying note only), DOC13 (optional future perf/usage fields)

---

## 16.1.1 Problem statement

ELNOR’s EC-managed memory retrieval is currently **keyword-heavy** and therefore misses many conceptually relevant memories when the query vocabulary differs from the stored vocabulary.

Examples:

- Stored memory: `user prefers concise bullets`
- Later query: `How should I format responses?`
- Keyword-only retrieval may miss it even though it is conceptually relevant.

Another example:

- Stored memory: `client prefers settlement over litigation`
- Later query: `What’s the dispute resolution approach?`
- Keyword-only retrieval may miss it even though it is semantically related.

As ELNOR_MEMORY grows, this problem gets worse:

- relevant memories become harder to retrieve unless wording is consistent,
- warm-path retrieval quality decays,
- useful corrections / preferences / project memories become buried,
- users lose trust because the system “should have known that already.”

The current system already includes:

- QMD Deep Search in Q,
- warm-path memory retrieval in EC,
- a `qmd_available` signal / mode labeling,
- a memory index,
- and an aspirational “semantic” story,

but the current EC ranking path still behaves effectively as **keyword / metadata retrieval**, not true semantic retrieval.

---

## 16.1.2 Important architectural clarification

There are now **two different memory-search worlds**, and they must not be conflated:

### A. OpenClaw native memory search

OpenClaw now supports:

- vector memory search over `MEMORY.md` and `memory/*.md`,
- `memorySearch.provider = "ollama"` for local/self-hosted embeddings,
- hybrid retrieval (BM25 + vector),
- experimental `memory.backend = "qmd"`,
- CLI-level memory search tooling,
- local embedding / sqlite-vec acceleration patterns.

This is **real native OpenClaw memory functionality**.

### B. ELNOR EC-managed memory search

ELNOR’s memory search is separate and currently runs over EC-owned memory artifacts such as:

- `ELNOR_MEMORY/system/memory_index.json`,
- structured memory metadata,
- standing orders,
- corrections,
- warm-path memory retrieval,
- future CIL/MemoryService ownership.

This is **not the same system** as OpenClaw native memory search, even if the conceptual techniques are similar.

### Required conclusion

We should **not** simply “route ELNOR memory search through OpenClaw” without a deliberate bridge design.

We should instead:

- keep **EC** as owner of ELNOR memory retrieval,
- borrow the right **semantic retrieval architecture** from OpenClaw’s direction,
- keep the corpora and ownership models distinct,
- avoid duplicate or conflicting memory layers,
- and prevent duplicate memory injection between OpenClaw-native memory and ELNOR memory.

---

## 16.1.3 Why this matters

### User-facing value

Semantic retrieval improves:

- recall of user preferences,
- recall of prior decisions,
- recall of legal/strategic/project reasoning stored under different vocabulary,
- continuity in long-running projects,
- quality of warm-path memory selection,
- utility of the QMD Deep Search UI.

### System value

A hybrid retrieval layer allows:

- better scaling as memory grows,
- better retrieval under local/self-hosted model configurations,
- less reliance on exact word overlap,
- more future alignment with CIL MemoryService and more modular memory infrastructure.

### Why it is not just “nice to have”

If this is not improved, the memory system will increasingly look broken **even when the right memory exists**.

That is one of the worst possible failure modes:
- the system has the information,
- but retrieval quality is too weak to find it,
- so the user experiences the system as forgetful anyway.

---

## 16.1.4 Relevant OpenClaw capability

OpenClaw now documents and supports native semantic memory search behavior for its own memory corpus, including:

- vector search over memory markdown,
- Ollama embedding provider support,
- hybrid retrieval,
- optional QMD backend,
- CLI access to memory search/index/status,
- local-first embedding patterns.

This is significant because it means:

- semantic retrieval is no longer speculative,
- local embeddings are now an accepted OpenClaw-native pattern,
- local/self-hosted semantic recall is realistic,
- and ELNOR can align to this direction without inventing an alien architecture.

### Important boundary

OpenClaw native memory search does **not automatically upgrade** EC-owned ELNOR memory retrieval.

The fact that OpenClaw can do it natively means:
- the technique is validated,
- the local-first pattern is valid,
- but EC still needs its own retrieval provider layer if it is to search the ELNOR corpus semantically.

---

## 16.1.5 Recommended architecture decision

## Decision

Add a **Semantic Retrieval Provider Layer** to EC-owned memory retrieval.

### Keep

- EC remains the owner of ELNOR memory retrieval.
- Q remains the owner of the QMD search UI.
- OpenClaw remains the owner of its native memory system.
- Warm-path retrieval remains bounded and token-aware.
- Hybrid retrieval (keyword + semantic + metadata/trust) becomes the target state.

### Do not do

- Do **not** casually shell out to OpenClaw CLI/Gateway for ELNOR memory retrieval as a shortcut.
- Do **not** collapse ELNOR memory and OpenClaw memory into one undifferentiated system.
- Do **not** make semantic retrieval the immediate default for every hot path without latency/budget safeguards.
- Do **not** inline large embedding vectors into the main human-readable memory index long-term.
- Do **not** let semantic retrieval become an excuse to inject more memories into prompts.

### High-level architecture

```text
EC Memory Search Service
  ├─ keyword / metadata retrieval
  ├─ semantic retrieval provider
  │    ├─ Ollama embeddings (preferred local option)
  │    ├─ future remote providers
  │    └─ disabled/fallback mode
  ├─ hybrid score combiner
  ├─ embedding index store
  ├─ search/debug status
  └─ warm-path bounded retrieval
```

---

## 16.1.6 Required spec changes

## A. DOC1 / Memory Resilience / canonical memory spec

### Add: Semantic Retrieval Provider section

Add a section defining:

- `retrieval_mode`: `keyword_only | hybrid | semantic_only | disabled`
- `semantic_provider_kind`: `none | ollama | local | openai | gemini | voyage | mistral | qmd_sidecar`
- `semantic_provider_status`: `healthy | degraded | unavailable | stale | unknown`
- `embedding_model`
- `embedding_dimensions`
- `embedding_created_at`
- `embedding_index_version`
- `embedding_corpus_version`

### Add: Search result schema

Define a retrieval result shape containing at minimum:

- `memory_id`
- `final_score`
- `keyword_score`
- `semantic_score`
- `metadata_score`
- `reason_codes[]`
- `retrieval_mode`
- `provider_kind`
- `embedding_model`
- `search_corpus`
- `confidence`

### Add: Hybrid scoring guidance

Specify that hybrid retrieval should combine:

- keyword/text match
- semantic similarity
- metadata/trust weighting
- project/topic relevance
- recency
- optional diversity/reranking

Do **not** hard-lock exact blend weights permanently in the canonical spec, but specify:

- required components,
- safe defaults,
- tunability,
- and how score breakdowns are exposed for debugging.

### Add: Embedding storage guidance

Do **not** require embedding vectors to live inline in the primary memory index.

Preferred direction:
- separate embedding index store
- separate refresh lifecycle
- separate versioning

### Add: Backfill and re-embedding rules

Specify:
- background backfill
- incremental embedding generation on new/updated memory
- stale embedding detection when embedding model changes
- index refresh on memory delete/update

### Add: Warm-path constraints

Specify:
- semantic retrieval may contribute to warm-path selection,
- but warm-path remains latency- and token-budgeted,
- and must degrade cleanly to keyword-only or cached results.

### Add: Degrade/fallback behavior

If semantic retrieval is unavailable:
- no hard failure,
- degrade to keyword-only,
- expose degraded status visibly.

---

## B. Canonical QMD / Q memory search spec

### Add: Naming clarification

The spec must explicitly distinguish:

- **ELNOR QMD Dashboard** (Q UI/search surface)
- **EC Memory Search Service** (ELNOR retrieval engine)
- **OpenClaw QMD backend** (native OpenClaw experimental backend)

Without this clarification, future spec/code work will drift badly.

### Add: Search mode visibility

Q should be able to show:
- `keyword_only`
- `hybrid`
- `semantic_only`
- `degraded_to_keyword`
- `disabled`

### Add: Search debug / breakdown UI

At least in advanced/debug mode, Q should be able to display:
- keyword score
- semantic score
- final score
- provider/model used
- embedding index freshness
- degraded state/warning

### Add: Reindex/backfill controls

At least in an advanced/admin/debug mode, provide:
- reindex embeddings
- refresh provider status
- show last error
- show stale embeddings count

---

## C. DOC15 / CIL / MemoryService

### Add: MemorySearchService ownership

DOC15 should eventually own a reusable service for:

- retrieval provider selection
- embedding generation
- vector storage/indexing
- hybrid score composition
- search health/degrade logic
- query-time capability/status
- debug introspection

### Add: Extractable service pattern

Any near-term EC implementation should be designed so later extraction into CIL is straightforward.

This means the spec should say:
- do not hard-couple semantic retrieval to a monolithic EC route handler,
- keep provider/adaptor logic separable,
- keep score-composition logic separable,
- keep embedding-index lifecycle separable.

---

## D. Q dashboard spec / search surfaces

### Add: Search mode indicator

Deep Search should show the current retrieval mode.

### Add: Score breakdown panel

At least in debug/advanced mode, the UI should show score breakdowns.

### Add: Search provider health

Display:
- semantic provider status
- embedding model
- last refresh
- degraded reason if any

### Add: Result explanation

If useful, allow a simple “why did this match?” explanation based on reason codes.

---

## E. DOC10 / Running Brief

### Add a small seam note only

DOC10 / Running Brief should acknowledge that:
- warm-path memory retrieval may use hybrid search,
- but retrieval remains bounded,
- and the selected retrieval mode/provider may appear in the context manifest/debug data.

This should be a **small note**, not a major rewrite.

---

## F. DOC11

### Add only a clarifying note

DOC11 should clarify that:
- OpenClaw native semantic memory search and EC-owned ELNOR memory retrieval are separate systems,
- DOC11 does not currently assume a native Gateway RPC seam for EC/QMD semantic search,
- runtime truth for EC-owned semantic search remains a separate memory-service concern.

This should stay small.

---

## G. DOC13 (optional later enhancement)

### Add perf/usage fields if useful

If desired later, DOC13 may add support for tracking:
- embedding query latency
- embedding provider usage/cost if any
- local semantic-search health

This is optional and should not block the core retrieval architecture.

---

## 16.1.7 Required code changes

## A. EC / Memory Search Service

### New helpers/services

Add:

#### `embedText(text, options)`
Responsible for:
- calling the configured embedding provider,
- timing out safely,
- returning embedding vector + provider/model metadata,
- degrading to `null`/unavailable cleanly.

#### `computeCosineSimilarity(vecA, vecB)`
Responsible for:
- deterministic semantic similarity math,
- returning normalized semantic similarity,
- no network dependency.

#### `MemorySearchService`
Owns:
- query embedding generation,
- embedding retrieval for stored memories,
- hybrid scoring,
- provider health,
- fallback/degrade logic,
- result shaping,
- warm-path constraints.

### New stores

Add a separate embedding index store.

Preferred options:
- simple phase 1: separate JSON/JSONL keyed by `memory_id`
- better long-term: SQLite/vec-backed index

### Required behavior

- embed new/updated memory in background
- support backfill/reindex jobs
- track embedding model/version per memory
- re-embed when embedding model changes
- degrade safely when provider unavailable
- avoid hot-path full-corpus embedding work

## B. Contracts package

Add schemas for:
- `SemanticRetrievalProviderStatus`
- `MemorySearchMode`
- `MemorySearchResultBreakdown`
- `EmbeddingIndexEntry`
- `SemanticRetrievalReasonCode`
- `MemorySearchHealthStatus`

## C. Q frontend

Add support for:
- mode indicator
- provider/model/health visibility
- optional score breakdown debug panel
- optional reindex/refresh controls
- degraded-to-keyword warnings

## D. Migration/backfill code

Add:
- background backfill worker
- stale embedding detector
- reindex trigger
- safe one-time migration path for existing memories

---

## 16.1.8 Risks and mitigations

## Risk 1 — Semantic over-recall

**Problem:** conceptually related but irrelevant memories surface.

**Mitigation:**
- hybrid scoring rather than semantic-only,
- metadata/trust gating,
- project/topic filters,
- max result cap,
- reason-code debugging.

## Risk 2 — Latency blowout

**Problem:** embedding requests on the hot path slow ordinary chat.

**Mitigation:**
- background embedding generation,
- query embedding cache,
- timeout + degrade,
- guarded warm-path participation only.

## Risk 3 — Duplicate memory injection

**Problem:** OpenClaw-native memory and EC memory both contribute semantically similar content.

**Mitigation:**
- keep corpus ownership distinct,
- record source corpus in manifests,
- avoid mirroring identical content into both memory systems where possible.

## Risk 4 — Spec confusion around “QMD”

**Problem:** OpenClaw QMD backend vs ELNOR QMD Dashboard naming collision.

**Mitigation:**
- explicitly namespace the terms in specs now.

## Risk 5 — Embedding staleness

**Problem:** provider/model changes make old vectors less reliable.

**Mitigation:**
- store embedding model/version,
- mark stale embeddings,
- support re-embedding.

## Risk 6 — Prompt sludge by success

**Problem:** retrieval improves so much that more memories get injected, recreating context sludge.

**Mitigation:**
- retrieval quality can improve,
- prompt injection discipline must stay strict,
- warm-path budgets remain bounded,
- search success must not equal injection entitlement.

---

## 16.1.9 Suggested implementation sequence

### Phase 1 — Manual / Deep Search only

Implement:
- semantic provider abstraction
- embedding generation
- embedding index
- hybrid search in QMD Deep Search
- debug/status UI
- no warm-path use yet

### Phase 2 — Explicit memory workflows

Use hybrid retrieval for:
- explicit memory questions
- memory review/debug workflows
- admin/search tooling

### Phase 3 — Guarded warm-path integration

Allow hybrid retrieval to participate in warm-path selection only when:
- latency budget permits,
- provider health is good,
- caches are warm enough,
- result caps and token budgets are respected.

This phased approach reduces risk and makes debugging much easier.

---

## 16.1.10 Acceptance criteria

This punch-list item should be considered fully addressed only when:

1. EC-owned memory retrieval can operate in `keyword_only` and `hybrid` modes.
2. Local embeddings via Ollama (or another approved provider) can be used by EC’s memory retrieval layer.
3. Search results expose score breakdowns and provider/mode truth.
4. Warm-path retrieval can degrade cleanly to keyword-only without failure.
5. Existing memories can be backfilled/reindexed without blocking the hot path.
6. The canonical memory/QMD specs distinguish clearly between:
   - OpenClaw native memory search,
   - OpenClaw QMD backend,
   - ELNOR QMD Dashboard,
   - EC Memory Search Service.
7. Semantic retrieval improves recall without turning warm-path injection into a new source of prompt sludge.
8. The implementation path remains compatible with DOC15 / MemoryService extraction later.

---

## 16.1.11 Recommended decision for now

**Do not implement this directly in the middle of DOC11 work.**

Instead:
- preserve it here in DOC16,
- revisit it during the memory/QMD/CIL drafting wave,
- and treat it as a high-value deferred addition that has enough architectural clarity to be specced later without rediscovering the problem.

---



---

# Entry 16.2 — OpenClaw Release-Alignment Additions for DOC12 (Rooms / Panels / Forums / Channel Projection)

**Status:** Deferred → Ready for spec  
**Priority:** High  
**Primary owners:** DOC12 / Q room-panel-forum surfaces / channel projection logic  
**Secondary owners:** DOC11 (runtime-truth seam), DOC10 (trace/telemetry linkage), DOC4 (OpenClaw bridge), Running Brief, future automation/channel docs

---

## 16.2.1 Problem statement

DOC12 has been evolving quickly around:

- multi-agent rooms,
- guided panels,
- forums,
- channel projection,
- participant configuration,
- attachment-aware discussion,
- and participant/runtime status display.

At the same time, recent OpenClaw releases have added or improved several native behaviors that are highly relevant to DOC12, especially:

- **Telegram per-topic `agentId` routing** for forum groups and DM topics,
- **ACP durable Discord channel / Telegram topic bindings**,
- **routing/session duplicate suppression**,
- **legacy route inheritance fixes**,
- **session agent discovery improvements**,
- **channel/media local-root propagation**,
- **subagent attachment hardening**,
- **media-result blocking to prevent base64 prompt bloat**,
- **session-scoped heartbeat / automation behavior**,
- and richer external-channel/session continuity handling.

If DOC12 does not explicitly account for these capabilities, two bad outcomes become likely:

1. DOC12 will describe room/forum/channel behavior in a way that is **too generic** and fails to match actual OpenClaw routing/session reality.
2. Future implementation will flatten thread/topic/participant/channel truth into a simpler but wrong model, producing:
   - fake participant/session continuity,
   - duplicate routing,
   - weak attachment/media behavior,
   - or room/channel projections that do not behave like real OpenClaw channels.

This is not a “rewrite DOC12 because OpenClaw changed” issue. It is a **targeted alignment issue**.

---

## 16.2.2 Why it matters

### A. Multi-agent truth depends on real routing truth

DOC12 wants rooms, forums, and panels to support:

- multiple configured agents,
- participant-specific runtime state,
- room-specific context buckets,
- per-participant model/runtime truth,
- future channel projection,
- and eventually rich red-team and coordination flows.

That only works if participant/session/channel routing is modeled honestly.

### B. External channel projection is not generic chat mirroring

OpenClaw is getting more precise about:

- topic/thread routing,
- durable bindings,
- session inheritance,
- and route-duplication suppression.

So DOC12 should not hand-wave “Discord/Telegram projection” as one generic chat transport. It should treat topic/thread-aware channels as first-class routed surfaces.

### C. Attachment/media handling is now important to room/panel/forum design

OpenClaw changes around:

- media roots,
- `sessions_spawn` attachment behavior,
- media invoke blocking,
- and transport safety

mean that DOC12 should treat attachments and shared artifacts as real room/panel/forum concerns, not just ordinary chat baggage.

### D. Automation/session targeting matters later

Because newer OpenClaw releases push heartbeat and some wake semantics more explicitly into agent/session-scoped behavior, future DOC12 interactions with scheduled rooms, panel rounds, and room-linked automation should not assume a single global wake model.

---

## 16.2.3 Relevant OpenClaw capability / release alignment

Recent OpenClaw releases added or improved several capabilities that are relevant to DOC12:

1. **Telegram/topic agent routing** — per-topic `agentId` overrides for forum groups and DM topics, with isolated sessions.
2. **ACP persistent channel bindings** — durable Discord channel / Telegram topic binding storage, routing resolution, and management support.
3. **Routing/session duplicate suppression** — fixes to delivery-context inheritance, channel-paired merges, reply-surface targeting, and external/main-session continuity.
4. **Gateway/session agent discovery** — disk-scanned agent IDs remain visible in gateway session aggregation/listings even when `agents.list` is configured.
5. **Extensions/media local-root propagation** — outbound adapters consistently honor configured local media roots for attachments.
6. **Sessions/subagent attachments hardening** — schema/runtime hardening around attachment byte handling and file-size enforcement.
7. **Nodes/media blocking for prompt hygiene** — agent-context media-returning node invocations are blocked to avoid base64 prompt bloat while HTTP tool-context media remains allowed.
8. **Heartbeat legacy-path migration / session scoping** — heartbeat configuration and related wake semantics are becoming more agent/session-scoped.

These changes do not automatically rewrite DOC12. But they strongly indicate how DOC12 should model:

- channel/topic/thread identity,
- participant/session truth,
- attachment/media handling,
- and future scheduling/channel interactions.

---

## 16.2.4 Recommended architecture decision

## Decision

Treat these release-note items as **DOC12 alignment requirements**, not as standalone features bolted on later.

### Keep

- Q rooms/panels/forums remain the canonical rich orchestration surfaces.
- DOC11 remains the runtime/session/control seam.
- OpenClaw remains the native routing/channel/runtime engine.
- External channels remain projections/adapters with channel-specific constraints.

### Add

DOC12 should explicitly model:

- topic/thread-aware channel projection,
- participant/session/channel binding truth,
- durable external binding references,
- attachment/media-aware room/panel/forum flows,
- participant-level runtime/config display,
- and clear distinctions between room-local truth and external-channel truth.

### Do not do

- Do **not** model all external channels as one generic “message surface.”
- Do **not** assume one room = one session = one channel thread.
- Do **not** let channel projection erase participant/runtime distinctions.
- Do **not** assume attachments/media behave uniformly across all projected channels.
- Do **not** let room/panel/forum behavior depend on stale route inheritance or implicit default-session fallback.

---

## 16.2.5 Required spec changes

## A. DOC12 — Rooms / Panels / Forums / Channel Projection

### Add: Channel Binding and Projection section

Add a section defining:

- `channel_binding_kind`: `discord_channel | discord_thread | telegram_topic | telegram_dm_topic | slack_channel | slack_dm | webchat | q_room_only | unknown`
- `binding_persistence`: `ephemeral | durable`
- `binding_owner`: `room | panel | forum | participant | acp_delegate | system`
- `binding_resolution_source`: `q_config | doc12_store | gateway_runtime | acp_binding_store | unknown`
- `binding_health_state`: `healthy | stale | orphaned | mismatched | unknown`

### Add: Participant-to-channel routing truth

For each participant/projected surface, DOC12 should support:

- `participant_id`
- `room_id / panel_id / forum_id`
- `external_binding_ref?`
- `channel_binding_kind?`
- `topic_or_thread_id?`
- `routing_scope`: `room_local | topic_scoped | thread_scoped | dm_scoped | mixed`
- `binding_state`
- `binding_last_verified_at?`
- `binding_issue_codes[]`

### Add: Durable binding references

DOC12 should explicitly support a durable binding reference model so rooms/panels/forums can map to ACP/Discord/Telegram bindings that survive restarts and are not recomputed from vibes.

### Add: Projection-capability matrix

Add a DOC12 matrix for each projected channel type showing support for:

- multi-participant display
- thread/topic isolation
- attachments
- media previews
- streaming
- reaction/typing status
- room moderator controls
- participant roster visibility
- reply targeting
- shared artifact posting
- phase-aware or round-aware presentation

### Add: Room/panel/forum attachment scopes

Define:

- `turn_attachment`
- `room_shared_artifact`
- `panel_shared_artifact`
- `forum_attached_reference`
- `bucket_backed_reference`

and explicitly connect them to DOC11 capability-check and transport-mode truth.

### Add: Media handling rules for projected surfaces

DOC12 should not assume that any channel that accepts text also accepts media equivalently.

Add per-surface rules for:

- local media roots
- external media refs
- media fallbacks
- metadata-only fallback rendering
- channel-specific degradation behavior

### Add: Participant drawer / roster alignment with routing truth

The participant roster / drawer should be able to show:

- external binding kind
- topic/thread scope
- durable binding status
- routing mismatch warnings
- projection capability limitations

### Add: Duplicate-route suppression awareness

DOC12 should include a rule that external projection logic must respect runtime route dedupe / reply-surface truth and must not synthesize duplicate sends just because a room has multiple possible channel bindings.

### Add: ACP delegate distinction

If ACP workers or channel delegates participate in room/panel/forum projection, DOC12 must treat them as delegated participants with channel-binding truth, not as normal room agents with ordinary Gateway session assumptions.

### Add: Scheduling/heartbeat awareness note

Add a note that future scheduled room rounds, panel automation, or forum nudges must respect session-scoped heartbeat/automation semantics rather than assuming a single global wake model.

---

## B. DOC11 cross-amendment note

DOC12 changes above require DOC11 to remain the owner of:

- participant runtime truth,
- session binding truth,
- capability checks,
- attachment transport truth,
- and execution-watermark truth.

DOC12 should reference, not re-own, those contracts.

---

## C. DOC10 / integration ledger note

Add cross-ledger items ensuring that:

- room/panel/forum channel projections are traced as real routed operations,
- room-turn dispatch does not lose participant/channel binding truth,
- and mismatch/fallback/channel-binding errors surface in route traces and diagnostics.

---

## D. Running Brief note

Add a short Running Brief note reminding that:

- channel projection is capability-specific,
- thread/topic-aware routing should be preserved,
- and room/panel/forum projected attachments/media must respect DOC11 transport truth.

---

## 16.2.6 Required code changes

## A. Q frontend / room-panel-forum UI

Add or strengthen:

- channel binding display in room/panel/forum headers or drawers
- participant routing/binding indicators
- durable binding warnings
- projection-capability display (at least in advanced/debug settings)
- attachment scope selection UI for shared artifacts vs per-turn attachments
- media degradation notices where relevant

## B. EC / orchestration layer

Add or strengthen:

- stores for external binding refs
- participant/channel binding reconciliation
- durable binding refresh and stale detection
- route dedupe awareness in projected deliveries
- issue logging for routing mismatch, orphaned thread/topic bindings, and media capability mismatch

## C. OpenClaw bridge / adapter layer

Add or strengthen:

- channel/topic/thread-aware binding resolution
- ACP durable binding consumption
- participant-bound projection routing
- channel capability discovery or static capability mapping where runtime discovery is unavailable
- local media root propagation where applicable

## D. Telemetry / diagnostics

Add or strengthen:

- route trace fields for external binding kind, topic/thread scope, and projection degradation
- participant/channel binding mismatch logs
- room/panel/forum projection capability mismatch logs

---

## 16.2.7 Risks and mitigations

### Risk 1 — DOC12 over-models every channel

**Mitigation:** Keep Q room/panel/forum as canonical rich surfaces. Treat channel projections as capability-limited adapters.

### Risk 2 — Duplicate replies / duplicate routing

**Mitigation:** Respect runtime route inheritance and duplicate-suppression truth. Add explicit dedupe rules and binding precedence.

### Risk 3 — Attachment/media chaos

**Mitigation:** Keep DOC11 as owner of transport/capability truth. DOC12 only defines projection and scope behavior.

### Risk 4 — Topic/thread truth gets flattened away in UI

**Mitigation:** Add explicit binding-kind and scope fields to participant drawer/roster and room projection settings.

### Risk 5 — Future scheduling conflicts with session-scoped automation

**Mitigation:** Add a DOC12 note and future automation-spec note that room/panel/forum scheduled behavior must align with agent/session-scoped heartbeat/cron semantics.

---

## 16.2.8 Suggested implementation sequence

### Phase 1 — Spec alignment only

- Amend DOC12 to add binding/projection truth, projection-capability matrix, and attachment/media scope distinctions.
- Add minimal DOC10 / Running Brief cross-notes.

### Phase 2 — Read-models and diagnostics

- Add external binding refs, participant/channel binding stores, and routing mismatch diagnostics.
- Add drawer/roster/header displays.

### Phase 3 — Safer projection behavior

- Implement duplicate-route suppression awareness.
- Implement projection-capability-aware attachment/media handling.
- Implement durable binding reconciliation.

### Phase 4 — Advanced channel features

- Round/phase-aware projection improvements
- richer moderator/projection controls
- scheduled room/panel/forum integration with session-scoped automation

---

## 16.2.9 Acceptance criteria

This punch-list item should be considered fully addressed only when:

1. DOC12 distinguishes clearly between:
   - room-local truth,
   - participant runtime truth,
   - external channel binding truth,
   - and projected channel capability limits.
2. Topic/thread-aware routing is represented explicitly in DOC12 where relevant.
3. Durable ACP/channel/topic bindings are modeled rather than hand-waved.
4. Room/panel/forum attachment/media handling is explicitly scoped and tied to DOC11 capability/transport truth.
5. Duplicate-route suppression and stale binding/orphan handling are accounted for.
6. Participant drawer/roster/status surfaces can display routing/binding truth where useful.
7. Future scheduling/heartbeat integration is not based on a vague global wake model.
8. The spec remains OpenClaw-preserving and does not flatten channel/runtime truth into a fake generic chat model.

---

## 16.2.10 Recommended decision for now

**Do not patch DOC12 blindly in the middle of unrelated drafting work.**

Instead:
- preserve this entry in DOC16,
- use it as the alignment checklist the next time DOC12 is revised,
- and treat it as the canonical “OpenClaw release alignment for DOC12” punch-list item.

This keeps the release-note implications from getting lost without forcing constant churn in the canonical docs.

## R3 consolidation note

R3 consolidates:

- the existing R2 entries for semantic retrieval and DOC12 OpenClaw release-alignment,
- the separate DOC16 additions generated during the DOC15/CIL review session,
- the new Litigation Rooms / Matter Workbench / linked-room constellation proposal,
- and related DocIndex, advisor-routing, UI, storage, telemetry, and approval-gate additions.

Where earlier addenda overlapped, R3 preserves the intent and merges them into a single owner-aware punch list rather than keeping parallel notes that would drift.


# Entry 16.3 — Advisor Dispatch, DocIndex Surfacing, and CIL / Review Advisory Integration

**Status:** Deferred → Ready for spec  
**Priority:** High  
**Primary owners:** DOC10 / DOC15 / ELNOR Core canonical spec / DOC4 agent registry / Q advisory surfaces  
**Secondary owners:** DOC12, DOC14, DOC7, DOC11, Running Brief

---

## 16.3.1 Problem statement

Multiple Q surfaces now need explanatory or advisory help:

- suggestion cards,
- knowledge-node browser rows,
- nightly “what changed” cards,
- context inspector entries,
- inline pills,
- task/panel setup screens,
- cost and health surfaces,
- and review / red-team dashboards.

If each surface invents its own “ask why?” behavior, several failure modes follow:

1. **Context pollution** — the active working agent gets interrupted with unrelated architecture, learning, or cost questions.
2. **Duplication** — each surface implements a different advisory flow, payload format, and routing rule.
3. **Weak explanations** — the advisor receives a vague question without the IDs, signals, nodes, or records that the question is actually about.
4. **DocIndex underuse** — system files and spec documents are not consistently registered, so agents cannot resolve them cleanly by alias.
5. **Manual setup burden** — advisor and systems agents still depend on ad hoc context assembly rather than declaring what documents they require.
6. **Review friction** — red-team and review questions require finding ledgers, prompts, and outcome records, but there is no standard advisory pattern for them.

This results in slow, noisy, high-cost advisory behavior exactly where the dashboard should feel crisp and explainable.

---

## 16.3.2 Why this matters

### A. Explanatory UI is only useful if it is deep-linked

A “Why?” button that launches a chat without telling the advisor which node, suggestion, or plan it refers to is theatrical nonsense. The advisor should receive a typed payload pointing directly at the relevant records.

### B. Advisory questions should not hijack the main working agent

Elnor Prime or the active room participant should not have to absorb CIL state, spec documents, or cost tables just because the user clicked a dashboard help affordance.

### C. DocIndex is more valuable if it works both proactively and on demand

DocIndex should not only resolve files during manual setup. It should also:

- surface relevant documents proactively from learned patterns,
- resolve advisor dependencies at spawn,
- and act as a lightweight hot-path tool for agents that need a chunk or skeleton mid-run.

### D. Review and learning workflows need advisor support too

Users will ask questions like:

- “Why did this suggestion appear?”
- “What changed in confidence?”
- “Which findings mattered most?”
- “What documents does the system usually load for this kind of review?”

Those questions deserve a systematic answer path.

---

## 16.3.3 Relevant capability / architectural context

Several existing directions make this addition practical and appropriate:

1. DOC15 already treats CIL state and knowledge-node explanations as first-class UI concerns.
2. DOC10 already owns system-agent routing and is the right place to define advisory dispatch.
3. DOC12 already includes review rooms, context inspectors, pinned references, and room-linked workflows.
4. ELNOR already has a DocIndex direction and document alias resolution patterns.
5. The system is increasingly document-centric, which makes declarative document dependencies more attractive than manual context wrangling.

---

## 16.3.4 Recommended architecture decision

## Decision

Add a unified **Advisor Dispatch + Document Dependency + Deep-Link Payload** pattern.

### Keep

- DOC10 as the owner of advisor dispatch and systems-agent routing.
- DOC15 as the owner of CIL semantics, state files, and learning explanations.
- DOC4 / agent registry as the owner of advisor agent definitions.
- DocIndex / EC as the owner of document registration, resolution, and surfacing.
- Advisors as lightweight, bounded, mostly one-thread helper agents rather than long-lived parallel runtimes.

### Add

- a low-cost `advisor_dispatcher` agent,
- specialized advisors (`cil_advisor`, `review_advisor`, `spec_advisor`, `task_advisor`, `cost_advisor`),
- a typed `CILQueryContextPayload` and a general advisory routing payload pattern,
- declarative `document_dependencies` in agent definitions,
- proactive DocIndex surfacing for learned document sets,
- DocIndex tool access for all agents,
- consistent +ask/+advise routing from all Q surfaces,
- and a rule that spec/system questions route through advisors rather than the active worker by default.

### Do not do

- Do **not** send all +ask/+advise traffic to Elnor Prime.
- Do **not** make each surface invent its own advisory logic.
- Do **not** let advisors rummage broadly when the UI already knows the relevant IDs.
- Do **not** require human users to hand-select every supporting document for every advisor spawn.
- Do **not** make advisory threads persist forever; they should be thread-scoped, not immortal.

---

## 16.3.5 Required spec changes

## A. DOC10 — Unified Engagement Orchestration

### Add: Dispatcher + sub-advisor architecture

Define a lightweight dispatcher pattern for all Q `+ask` / `+advise` flows.

#### New roles

```ts
const AdvisorRoleTypeSchema = z.enum([
  "advisor_dispatcher",
  "cil_advisor",
  "review_advisor",
  "spec_advisor",
  "task_advisor",
  "cost_advisor"
]);
```

#### Dispatcher routing config

```ts
const AdvisorDispatchRouteSchema = z.object({
  match_kind: z.enum([
    "cil",
    "review",
    "spec",
    "task",
    "cost",
    "general"
  ]),
  target_role: AdvisorRoleTypeSchema,
  default_model_tier: z.enum(["local_low", "flash", "mid", "custom"]),
  allow_clarifying_question: z.boolean().default(true)
});
```

Default routing table:

- learning / memory / confidence / knowledge-node questions → `cil_advisor`
- review / red-team / finding / model-comparison questions → `review_advisor`
- architecture / spec questions → `spec_advisor`
- task setup / workflow configuration questions → `task_advisor`
- budget / token / cost questions → `cost_advisor`
- unclear advisory questions → dispatcher may ask one clarifying question

### Add: advisory thread persistence rule

DOC10 should define:

> Advisor agents persist for the duration of one advisory conversation thread. A new `+ask` press starts a new thread. Follow-up questions within that thread reuse the running advisor instance.

### Add: +ask/+advise routing rule

All +ask/+advise buttons across Q surfaces route to the dispatcher, not directly to the main working agent.

### Add: agent document dependency declarations

Allow system agents and advisor agents to declare document dependencies in their definitions.

```ts
const AgentDocumentDependencySchema = z.object({
  alias: z.string(),
  required: z.boolean().default(false),
  priority: z.enum(["critical", "useful", "background"]).default("useful"),
  preferred_materialization: z.enum([
    "full_if_possible",
    "always_full",
    "skeleton_ok",
    "summary_ok",
    "chunk_on_demand"
  ]).default("skeleton_ok"),
  notes: z.string().optional()
});
```

### Add: spawn-time dependency resolution note

At agent spawn, EC resolves dependencies through DocIndex, estimates budget, and chooses full/skeleton/summary/chunk_map materialization according to policy.

---

## B. DOC15 — CIL / Context & Intent Layer

### Add: brief advisor integration section

DOC15 should note:

- CIL surfaces expose +ask/+advise entry points.
- These route via DOC10 dispatcher to a `cil_advisor`.
- CIL state files must be DocIndex-indexed with standard aliases.
- `knowledge_nodes.jsonl` should include `display_summary` so advisors can explain nodes in plain English without bespoke transformation logic.

### Add: CIL Query Context Payload

```ts
export const CILQueryContextPayloadSchema = z.object({
  source_surface: z.enum([
    "suggestion_card",
    "knowledge_node_browser",
    "nightly_card",
    "context_inspector",
    "inline_pill",
    "cil_health_tab",
    "general_ask"
  ]),
  source_id: z.string().optional(),
  referenced_node_ids: z.array(z.string()).default([]),
  referenced_signal_ids: z.array(z.string()).default([]),
  referenced_dispatch_id: z.string().optional(),
  referenced_profile_id: z.string().optional(),
  snapshot: z.object({
    confidence: z.number().optional(),
    confidence_tier: z.string().optional(),
    evidence_grade: z.string().optional(),
    display_summary: z.string().optional(),
  }).optional(),
  user_question: z.string().optional(),
  asked_at: z.string().datetime(),
});
```

### Add: payload handling rule

If IDs are present, the advisor must use those IDs first rather than broad-searching the corpus.

### Add: per-surface payload requirements

At minimum, Q should populate the payload like this:

| Surface | `source_id` | Key references | Typical use |
|---|---|---|---|
| Suggestion card `Why?` | ResolvedOperation id | `referenced_node_ids`, `referenced_dispatch_id`, `referenced_profile_id` | “Why is this being recommended?” |
| Knowledge Node Browser `Explain` | node id | `referenced_node_ids`, `referenced_signal_ids` | “What is this node and why does it exist?” |
| Nightly card `Tell me more` | nightly entry id | changed node ids + before/after confidence in snapshot | “What changed and why?” |
| Context Inspector `Explain this plan` | ContextPlan id | injected node ids, dropped node ids, dispatch id | “Why were these items injected or dropped?” |
| Inline pill click | dispatch id or pill id | injected node ids | “What learned knowledge was used here?” |
| CIL Health tab | metric / card id | metric-specific refs | “Why is this metric changing?” |
| General chat `+ask` | optional | no ids required | broad system / architecture help |

### Add: dispatcher payload pass-through rule

The dispatcher receives the advisory payload and passes it through unchanged to the target advisor. It may use `source_surface` and the existence of specific IDs to help classify the request, but it must not strip or rewrite the payload before handoff.

### Add: DocIndex registration of CIL state files

On CIL initialization, register:

- `ELNOR_MEMORY/system/cil/knowledge_nodes.jsonl`
- `ELNOR_MEMORY/system/cil/signal_spool.jsonl`
- `ELNOR_MEMORY/system/cil/config.json`
- `ELNOR_MEMORY/system/cil/profiles/`
- `ELNOR_MEMORY/system/cil/nightly/`

with human-meaningful aliases.

### Add: document access patterns as passive signals

When DocIndex resolves a document access, emit passive signal:

```ts
const DocumentAccessedSignalPayloadSchema = z.object({
  doc_id: z.string(),
  alias_used: z.string().optional(),
  context_facts: z.record(z.string(), z.any()).default({}),
  source_surface: z.string().optional(),
  room_id: z.string().optional(),
  workspace_id: z.string().optional(),
  matter_id: z.string().optional()
});
```

Nightly learning may promote co-access patterns into `context_packaging_hint` or `workspace_default` nodes.

---

## C. ELNOR Core canonical spec / DocIndex

### Add: proactive document surfacing

DocIndex should not be purely reactive. When CIL has matching document-packaging hints, ContextPlanner may request suggested documents for surfacing.

### Add: DocIndex tool access for agents

All agents should be able to call:

```ts
interface DocIndexTool {
  resolve(alias: string): Promise<{ doc_id: string; title: string; aliases: string[] } | null>;
  get_chunk(doc_id: string, chunk_key: string): Promise<{ text: string; metadata: Record<string, any> }>;
  get_skeleton(doc_id: string): Promise<{ outline: string; chunk_map: string[] }>;
}
```

### Add: spec-document indexing rule

All ELNOR spec documents (DOC1–DOC16, build manifests, integration contracts, addenda) should be registered in DocIndex with useful aliases.

### Add: compression override guidance

- never compress authority memory,
- never compress active review target / pinned review doc,
- compress required room documents last,
- compress workspace standing document set last,
- everything else follows normal CRS ordering.

---

## D. DOC7 — Context Buckets & Files

### Add: DocIndex-aware budget allocation guidance

Budget manager should consider:

1. pin / required status,
2. recent access count,
3. whether the doc is referenced by active CIL nodes,
4. token cost,
5. room / task criticality.

### Add: document priority hints

```ts
const DocumentPriorityHintSchema = z.object({
  doc_id: z.string(),
  priority: z.enum(["critical", "useful", "background"]),
  reason: z.string()
});
```

ContextPlanner may provide these to Budget Manager.

---

## E. DOC12 — Inter-Agent Communication and Multi-Agent Rooms

DOC12 should receive the following **minimal** additions here, with the more complete room-document / linked-room model defined in Entry 16.4.

### Add: active review target auto-pinning

- the room’s current review target is auto-pinned,
- the current-round submission becomes the next round’s pinned target,
- previous-round targets may compress but remain chunk-accessible.

### Add: room document context requirement note

Rooms may declare `required_documents`; these are always available, compress last, and later map into the richer `RoomDocumentBinding` model in Entry 16.4.

---

## F. DOC14 — CANDOR / Red-Team Review

### Add: review advisor note

DOC14 should acknowledge a `review_advisor` path via dispatcher for questions like:

- “Which findings were most impactful?”
- “Which model found the most novel issues?”
- “What is the current state of the P0 findings?”

### Add: red-team document pinning rules

- review target is always pinned,
- current prompt pinned for current round,
- current-round responses pinned until user review,
- companion docs summary-first,
- finding ledger summary-first, full on demand.

---

## G. DOC4 / Agent Registry

Add starter advisor definitions and fields for document dependencies.

Suggested starter roles:

- `advisor_dispatcher`
- `cil_advisor`
- `review_advisor`
- `spec_advisor`
- `task_advisor`
- `cost_advisor`

Agent definitions should support:

```ts
const AgentDefinitionExtensionSchema = z.object({
  role_type: AdvisorRoleTypeSchema.optional(),
  document_dependencies: z.array(AgentDocumentDependencySchema).default([]),
  conversation_lifetime: z.enum([
    "one_shot",
    "thread_scoped",
    "long_running"
  ]).default("one_shot")
});
```

### Suggested starter advisor definitions

#### `cil_advisor`

- role: explain learned patterns, confidence, recommendation provenance, and state-file-backed CIL behavior in plain English
- default dependencies:
  - `ELNOR_MEMORY/system/cil/knowledge_nodes.jsonl` (skeleton OK)
  - `ELNOR_MEMORY/system/cil/config.json` (always full)
  - current workspace standing orders (always full)
  - DOC15 spec summary or chunks on demand
- behavioral rule: distinguish observed patterns from proven rules; never oversell low-confidence learning

#### `advisor_dispatcher`

- role: classify advisory intent and route to the appropriate advisor
- default model tier: lowest practical cost tier
- behavioral rule: one clarifying question max when routing is unclear; do not answer substantive questions directly

#### `review_advisor`

- default dependencies:
  - current review target (full if pinned)
  - finding ledger (skeleton + chunks)
  - review outcomes
  - DOC14 summary/chunks on demand

#### `spec_advisor`

- default dependencies:
  - ELNOR spec registry via DocIndex aliases
  - skeleton-first, chunk-on-demand loading pattern
- behavioral rule: resolve the relevant spec before answering technical/ownership questions

### Optional SOUL / config guidance

The canonical docs do not need full prose SOUL files, but DOC4 should preserve the starter behavior above as editable template guidance so the first-boot advisor pack works without manual wiring.

---

## H. Integration contract additions

Add the following integration-contract items:

| # | Source | Target | Capture Point | Priority |
|---|---|---|---|---|
| 31 | EC Core (DocIndex) | DOC15 (CIL) | DocIndex access events → CIL passive behavioral signal for document usage patterns | Important |
| 32 | DOC15 (CIL) | EC Core (DocIndex) | CIL state files registered in DocIndex with aliases on CIL init | Immediate |
| 33 | DOC10 | DOC15 (CIL) | `+ask/+advise` routing for CIL surfaces → CIL advisor via dispatcher | Immediate |
| 34 | DOC10 | EC Core (DocIndex) | Agent document dependency declarations → DocIndex auto-resolution at spawn | Important |
| 35 | DOC15 (CIL) | DOC10 | CIL suggestion cards include document recommendations → DocIndex resolution for loading | Important |

---

## I. Cross-cutting note

This entry assumes a rebuild-friendly architecture. The routing config, agent definitions, DocIndex alias registrations, and advisory payload types should be treated as setup-time system configuration, not as special-case hand-coded exceptions.

---

## 16.3.6 Required code changes

## A. Dispatcher routing service

Add a Q/EC advisory entrypoint:

```text
POST /api/advisors/dispatch
```

Request:

```ts
const AdvisorDispatchRequestSchema = z.object({
  user_question: z.string().optional(),
  source_surface: z.string(),
  payload_kind: z.enum(["cil_query_context", "review_context", "general"]).default("general"),
  payload: z.record(z.string(), z.any()).optional(),
  current_thread_id: z.string().optional(),
  workspace_id: z.string().optional(),
  room_id: z.string().optional(),
  matter_id: z.string().optional()
});
```

Behavior:

1. Q surface packages payload.
2. Q backend proxies to EC advisory dispatcher command.
3. Dispatcher chooses target advisor.
4. EC spawns/reuses thread-scoped advisor.
5. Advisor receives the payload as first structured context object.

## B. Frontend `buildQueryContext()` helpers

Every CIL-visible UI element must implement a client-side helper that builds the advisory payload from local props/state.

Examples:

- suggestion card → operation id + node ids + snapshot
- knowledge-node row → node id + evidence refs
- nightly card → changed node ids + before/after confidence
- context inspector → injected/dropped ids + plan id
- inline pill → dispatch id + injected node ids

## C. Agent spawn dependency resolver

Implement spawn-time dependency loading:

```ts
async function resolveAgentDocumentDependencies(
  deps: AgentDocumentDependency[],
  budget: ContextBudget
): Promise<ResolvedDocumentMaterialization[]> {
  const resolved = [];
  for (const dep of deps) {
    const match = await docIndex.resolve(dep.alias);
    if (!match) continue;
    resolved.push(await materializeDocForBudget(match.doc_id, dep, budget));
  }
  return resolved;
}
```

## D. DocIndex alias registration + spec indexing

On initialization, ensure:

- CIL state files are registered.
- ELNOR spec documents are registered.
- aliases include formal name, short name, topical aliases, and common user phrasing.

## E. Proactive surfacing path

ContextPlanner path:

```text
ContextPlanner
  -> query CIL for matching workspace / task / matter document hints
  -> receive doc_ids + reason strings
  -> request DocIndex metadata
  -> Budget Manager allocates summary/full/skeleton budget
  -> included docs appear in context manifest
```

## F. Review advisor helper paths

Add lightweight query helpers so review advisors can read:

- finding ledger summaries,
- review outcome summaries by model,
- current review target,
- current round prompt,
- pending P0 findings.

---

## 16.3.7 Risks and mitigations

### Risk 1 — Advisory sprawl

**Mitigation:** one dispatcher, one routing table, one payload system.

### Risk 2 — Main agent still gets polluted

**Mitigation:** all dashboard advisory entrypoints route through dispatcher unless user explicitly asks the active worker.

### Risk 3 — Advisors receive vague requests

**Mitigation:** require payload builders on source surfaces; use IDs first.

### Risk 4 — DocIndex alias drift

**Mitigation:** central alias registration and periodic alias validation.

### Risk 5 — Dependency declarations blow the token budget

**Mitigation:** budget-aware materialization with skeleton/summary/chunk_on_demand fallback.

### Risk 6 — Review advisor becomes a back door for unsupported state mutation

**Mitigation:** advisors are read-mostly helpers; mutation still goes through explicit commands and UI surfaces.

---

## 16.3.8 Suggested implementation sequence

### Phase 1 — Dispatcher + payload contracts

- define dispatcher routes,
- define `CILQueryContextPayload`,
- add +ask/+advise routing to dispatcher,
- wire a minimal `cil_advisor` and `review_advisor`.

### Phase 2 — DocIndex registration + dependency resolution

- register CIL files and spec documents,
- add agent document dependency declarations,
- add spawn-time resolution.

### Phase 3 — Proactive surfacing + room review helpers

- add document access passive signals,
- nightly co-access learning,
- proactive doc surfacing,
- review advisor access to finding/outcome summaries.

### Phase 4 — polish

- thread reuse,
- debug views,
- surface-specific quality improvements.

---

## 16.3.9 Acceptance criteria

This entry is addressed only when:

1. All dashboard +ask/+advise actions route through a dispatcher.
2. CIL surfaces send typed query-context payloads with IDs.
3. Advisors can resolve CIL files and ELNOR specs through DocIndex aliases.
4. Agent definitions can declare document dependencies.
5. Dependency resolution is budget-aware and visible in manifests.
6. Review advisors can answer finding / model / round-status questions without hijacking the active worker.
7. Active review-target pinning and required-room-doc support exist at least in minimal form, with richer room contracts handled by Entry 16.4.

---

## 16.3.10 Recommended decision for now

Do not leave the CIL/session additions as a detached appendix. Consolidate them into the canonical DOC16 running punch list and treat advisor dispatch + DocIndex surfacing as a real cross-doc planning item for the next orchestration / learning / dashboard revision wave.


# Entry 16.4 — Litigation Rooms / Matter Workbench / Linked Room Constellations

**Status:** Ready for spec  
**Priority:** High  
**Primary owners:** DOC12 / DOC6 / ELNOR Core + DocIndex / DOC11 / DOC4  
**Secondary owners:** DOC14, DOC15, DOC10, DOC3, DOC7, DOC8, DOC13

---

## 16.4.1 Problem statement

ELNOR now has the pieces for serious multi-agent work — rooms, panels, forums, runtime truth, red-team overlays, document indexing, and linked workflows — but it still lacks a cohesive model for **matter-centric, lawyer-supervised, linked-room work**.

Current gaps:

1. **No first-class matter workflow shell** tying together a courtroom-style room, prep rooms, research rooms, and red-team child rooms.
2. **Subrooms exist but are too weakly specified** for structured work-product exchange, actor reuse, side confidentiality, and approval-gated progression.
3. **DocIndex is good as a canonical document substrate but not yet a matter/work-product coordination layer.**
4. **The same logical actor cannot cleanly appear across multiple rooms** without people being tempted to reuse transcripts or blur session boundaries.
5. **Human-approval checkpoints are still underpowered** relative to the required “do not proceed until I approve” workflow.
6. **Participant trace visibility is not strong enough** for high-oversight professional work.
7. **Panels and rooms overlap heavily** but the `room_backed_panel` bridge is not yet strong enough for a courtroom / matter workbench flow.
8. **There is no canonical room-side contract for transfer packets, room document bindings, logical actor bindings, or linked-room graph navigation.**

The result is that ELNOR can simulate pieces of the workflow but cannot yet support a real multi-room litigation-style process without implementers making up a lot of critical glue.

---

## 16.4.2 Why this matters

### A. This is a credible flagship vertical

Litigation-style work is an extreme stress test for:

- document handling,
- side separation,
- approval gates,
- participant truth,
- linked-room workflows,
- and review/red-team reuse.

If ELNOR can do this honestly, it can do many other professional multi-agent workflows too.

### B. The right solution is generic-underneath

The system should not become “a legal runtime.” It should gain a stronger generic linked-room / matter-workbench architecture, then ship a first-party litigation pack on top.

### C. Oversight must be structural, not prompt theater

For serious professional use, the user must be able to see:

- what context each participant saw,
- what documents they used,
- what runtime/model actually executed,
- what subagents/tools/documents were involved,
- what work product moved between rooms,
- and where the workflow is blocked awaiting approval.

### D. Reusing the existing room + red-team stack is better than inventing a parallel review engine

Brief review and rebuttal can run as linked child rooms using the existing red-team substrate rather than a brand-new room species.

---

## 16.4.3 Recommended architecture decision

## Decision

Build a **Litigation Workbench** as a first-party pack on top of the existing architecture:

- **Matter Panel** (`room_backed_panel`) for governance, phase state, approval queue, timeline, exports
- **Courtroom Room** for live plaintiff / defense / judge / human interaction
- **Prep Rooms** for side drafting and strategy
- **Research Rooms** or bounded native delegation for authority gathering
- **Red-Team Child Rooms** targeting selected drafts
- **Optional Judge Chambers Room** for deliberation or bench memo workflow
- **DocIndex-backed matter document storage** with room-local bindings, not a second legal database
- **Approval checkpoints** as structural blockers
- **Logical actor bindings** so the same role can appear across rooms without shared transcripts
- **Bounded delegation trace summaries** for visibility without pretending EC owns every native loop detail

### Keep

- EC as sole durable writer.
- DOC12 as owner of rooms, linked-room execution, room presets, output contracts, room-level telemetry.
- DOC6 as owner of panels and matter workflow state.
- DOC11 as owner of runtime truth, context truth, and capability-check truth.
- DOC4 as owner of built-in agent templates.
- DOC14 as owner of red-team policy, not litigation workflow generally.
- DocIndex as the canonical document substrate.

### Do not do

- Do **not** build a second litigation-specific document database.
- Do **not** build a special legal runtime.
- Do **not** copy transcripts or document bodies between rooms as the durable transfer mechanism.
- Do **not** reuse visible-participant sessions across rooms.
- Do **not** make approval a soft prompt instruction; make it a structural block.
- Do **not** claim complete subagent visibility if only summary-level trace is available.

---

## 16.4.4 Required spec changes

## A. DOC12 — Inter-Agent Communication and Multi-Agent Rooms

DOC12 is the core owner for linked-room constellations, room document bindings, logical actors, transfer packets, approval checkpoints, and room-side UI/state/telemetry.

### A1. Add concepts to DOC12

Add these concepts to DOC12 definitions:

- **Linked Room**
- **Linked Room Group**
- **Logical Actor**
- **Room Document Binding**
- **Transfer Packet**
- **Approval Checkpoint**
- **Delegation Trace Summary**

### A2. Add global and per-room storage

```ts
const ROOMS_ROOT = "ELNOR_MEMORY/system/rooms";

const LINKED_ROOM_EDGES_JSONL_PATH = `${ROOMS_ROOT}/linked_room_edges.jsonl`;
const LOGICAL_ACTOR_BINDINGS_JSONL_PATH = `${ROOMS_ROOT}/logical_actor_bindings.jsonl`;
const ROOM_TRANSFER_PACKETS_JSONL_PATH = `${ROOMS_ROOT}/room_transfer_packets.jsonl`;

const ROOM_LINKED_ROOMS_CURRENT_PATH = (room_id: string) =>
  `${roomDir(room_id)}/linked_rooms_current.json`;

const ROOM_LOGICAL_ACTORS_CURRENT_PATH = (room_id: string) =>
  `${roomDir(room_id)}/logical_actors_current.json`;

const ROOM_DOCUMENT_BINDINGS_CURRENT_PATH = (room_id: string) =>
  `${roomDir(room_id)}/document_bindings_current.json`;

const ROOM_DOCUMENT_BINDING_EVENTS_JSONL_PATH = (room_id: string) =>
  `${roomDir(room_id)}/document_binding_events.jsonl`;

const ROOM_TRANSFER_INBOX_CURRENT_PATH = (room_id: string) =>
  `${roomDir(room_id)}/transfer_inbox_current.json`;

const ROOM_TRANSFER_OUTBOX_CURRENT_PATH = (room_id: string) =>
  `${roomDir(room_id)}/transfer_outbox_current.json`;

const ROOM_APPROVAL_CHECKPOINTS_CURRENT_PATH = (room_id: string) =>
  `${roomDir(room_id)}/approval_checkpoints_current.json`;

const ROOM_APPROVAL_EVENTS_JSONL_PATH = (room_id: string) =>
  `${roomDir(room_id)}/approval_events.jsonl`;

const ROOM_DELEGATION_TRACE_INDEX_JSONL_PATH = (room_id: string) =>
  `${roomDir(room_id)}/delegation_trace_index.jsonl`;
```

### A3. Add schemas

#### LinkedRoomEdgeSchema

```ts
const LinkedRoomEdgeSchema = z.object({
  edge_id: z.string(),
  linked_room_group_id: z.string().optional(),
  from_room_id: z.string(),
  to_room_id: z.string(),
  edge_kind: z.enum([
    "parent_child",
    "sibling",
    "prep_for",
    "research_supports",
    "redteam_of",
    "reports_to",
    "deliberates_for"
  ]),
  status: z.enum(["active", "paused", "closed"]).default("active"),
  visibility_policy: z.enum([
    "none",
    "moderator_only",
    "human_only",
    "selected_participants",
    "panel_visible"
  ]).default("human_only"),
  allowed_transfer_kinds: z.array(z.enum([
    "draft_output_ref",
    "document_ref_bundle",
    "research_packet",
    "finding_subset",
    "instruction_bundle",
    "decision_basis_ref",
    "approval_return_with_edits"
  ])).default([]),
  selected_participant_ids: z.array(z.string()).optional(),
  created_by: z.object({
    actor_type: z.enum(["user", "participant", "system"]),
    actor_id: z.string().optional()
  }),
  created_at: z.string(),
  notes: z.string().optional()
});
```

#### LogicalActorBindingSchema

```ts
const LogicalActorBindingSchema = z.object({
  logical_actor_id: z.string(),
  logical_role_key: z.string(),
  agent_profile_id: z.string(),
  display_name: z.string(),
  matter_id: z.string().optional(),
  room_id: z.string(),
  participant_id: z.string(),
  session_scope: z.enum([
    "surface_bound_fresh",
    "surface_bound_persistent",
    "single_turn_ephemeral"
  ]),
  memory_sharing_policy: z.enum([
    "none",
    "explicit_transfer_only"
  ]).default("explicit_transfer_only"),
  created_at: z.string(),
  created_by: z.object({
    actor_type: z.enum(["user", "system"]),
    actor_id: z.string().optional()
  })
});
```

#### RoomDocumentBindingSchema

```ts
const RoomDocumentBindingSchema = z.object({
  binding_id: z.string(),
  room_id: z.string(),
  doc_id: z.string(),
  alias_used: z.string().optional(),
  doc_role: z.enum([
    "review_target",
    "authority",
    "evidence",
    "research_memo",
    "instructions",
    "draft_output",
    "prior_round_output",
    "decision",
    "background",
    "custom"
  ]),
  custom_role_label: z.string().optional(),
  visibility_scope: z.enum([
    "all_active_participants",
    "moderator_only",
    "human_only",
    "selected_participants",
    "role_scoped"
  ]),
  selected_participant_ids: z.array(z.string()).optional(),
  selected_role_keys: z.array(z.string()).optional(),
  phase_scope: z.array(z.string()).optional(),
  pin_state: z.enum([
    "unpinned",
    "pinned_reference",
    "pinned_active"
  ]).default("unpinned"),
  load_preference: z.enum([
    "skeleton_default",
    "summary_default",
    "full_if_budget",
    "always_full",
    "chunk_on_demand"
  ]).default("full_if_budget"),
  compression_policy: z.enum([
    "allow_docindex",
    "never_compress_active",
    "summary_only_when_needed"
  ]).default("allow_docindex"),
  required_for_output: z.boolean().default(false),
  version_group_id: z.string().optional(),
  supersedes_doc_id: z.string().optional(),
  source_transfer_packet_id: z.string().optional(),
  added_by: z.object({
    actor_type: z.enum(["user", "participant", "system"]),
    actor_id: z.string().optional()
  }),
  added_at: z.string(),
  notes: z.string().optional()
});
```

#### TransferContentRefSchema and RoomTransferPacketSchema

```ts
const TransferContentRefSchema = z.object({
  ref_kind: z.enum([
    "doc_id",
    "room_output_ref",
    "finding_id",
    "finding_set_ref",
    "decision_basis_ref",
    "instruction_text",
    "message_ref"
  ]),
  ref_id: z.string(),
  label: z.string().optional(),
  content_hash: z.string().optional(),
  suggested_doc_role: z.string().optional(),
  include_as_doc_binding: z.boolean().default(false)
});

const RoomTransferPacketSchema = z.object({
  packet_id: z.string(),
  linked_room_group_id: z.string().optional(),
  matter_id: z.string().optional(),
  from_surface_kind: z.enum(["room", "panel", "forum"]),
  from_surface_id: z.string(),
  to_surface_kind: z.enum(["room", "panel", "forum"]),
  to_surface_id: z.string(),
  transfer_kind: z.enum([
    "draft_output_ref",
    "document_ref_bundle",
    "research_packet",
    "finding_subset",
    "instruction_bundle",
    "decision_basis_ref",
    "approval_return_with_edits"
  ]),
  status: z.enum([
    "created",
    "available",
    "imported",
    "rejected",
    "superseded"
  ]).default("created"),
  origin_room_turn_id: z.string().optional(),
  origin_output_slot: z.string().optional(),
  content_refs: z.array(TransferContentRefSchema),
  summary_text: z.string().optional(),
  decision_basis_ref: z.string().optional(),
  approved_by_human: z.boolean().default(false),
  approval_checkpoint_id: z.string().optional(),
  confidentiality: z.enum([
    "normal",
    "side_confidential",
    "judge_only",
    "human_only"
  ]).default("normal"),
  import_policy: z.enum([
    "manual_import",
    "auto_bind_documents",
    "auto_attach_summary",
    "auto_queue_instruction"
  ]).default("manual_import"),
  created_by: z.object({
    actor_type: z.enum(["user", "participant", "system"]),
    actor_id: z.string().optional()
  }),
  created_at: z.string(),
  imported_by: z.object({
    actor_type: z.enum(["user", "participant", "system"]),
    actor_id: z.string().optional()
  }).optional(),
  imported_at: z.string().optional()
});
```

#### ApprovalCheckpointSchema

```ts
const ApprovalCheckpointSchema = z.object({
  checkpoint_id: z.string(),
  room_id: z.string(),
  matter_id: z.string().optional(),
  label: z.string(),
  checkpoint_kind: z.enum([
    "pre_phase_transition",
    "pre_export",
    "pre_transfer_dispatch",
    "pre_close",
    "custom"
  ]),
  required_before: z.enum([
    "advance_phase",
    "export_output",
    "dispatch_linked_room",
    "post_to_panel",
    "close_room"
  ]),
  blocking_scope: z.enum([
    "room",
    "linked_edge",
    "panel_stage"
  ]).default("room"),
  status: z.enum([
    "pending",
    "approved",
    "rejected",
    "returned_with_edits",
    "expired"
  ]).default("pending"),
  target_refs: z.array(z.object({
    ref_kind: z.enum(["doc_id", "room_output_ref", "transfer_packet_id", "finding_set_ref"]),
    ref_id: z.string()
  })),
  diff_ref: z.string().optional(),
  instruction_to_human: z.string().optional(),
  requested_by: z.object({
    actor_type: z.enum(["user", "participant", "system"]),
    actor_id: z.string().optional()
  }),
  requested_at: z.string(),
  resume_mode: z.enum(["manual_only", "auto_after_approval"]).default("manual_only"),
  resolved_by: z.object({
    actor_type: z.enum(["user", "participant", "system"]),
    actor_id: z.string().optional()
  }).optional(),
  resolved_at: z.string().optional(),
  human_response_text: z.string().optional()
});
```

#### ParticipantDelegationTraceSummarySchema

```ts
const ParticipantDelegationTraceSummarySchema = z.object({
  trace_id: z.string(),
  room_id: z.string(),
  room_turn_id: z.string(),
  participant_id: z.string(),
  trace_capture_state: z.enum([
    "off",
    "summary",
    "partial",
    "debug",
    "unsupported"
  ]),
  subagent_count: z.number().int().nonnegative(),
  subagent_role_refs: z.array(z.string()).default([]),
  tool_action_refs: z.array(z.string()).default([]),
  doc_access_refs: z.array(z.string()).default([]),
  artifact_refs: z.array(z.string()).default([]),
  external_capability_refs: z.array(z.string()).default([]),
  error_refs: z.array(z.string()).default([]),
  summary: z.string().optional(),
  native_capture_limitations: z.array(z.string()).default([]),
  captured_at: z.string()
});
```

### A4. Add commands and route contracts

```ts
type RoomCommandType =
  | "room_create_linked"
  | "room_attach_link"
  | "room_bind_document"
  | "room_update_document_binding"
  | "room_unbind_document"
  | "room_create_transfer_packet"
  | "room_import_transfer_packet"
  | "room_request_approval"
  | "room_approve_checkpoint"
  | "room_reject_checkpoint"
  | "room_return_with_edits"
  | "room_register_logical_actor"
  | "room_set_trace_mode"
  | "room_judge_finding";
```

Suggested request schemas:

```ts
const RoomBindDocumentRequestSchema = z.object({
  room_id: z.string(),
  doc_id: z.string(),
  alias_used: z.string().optional(),
  doc_role: RoomDocumentBindingSchema.shape.doc_role,
  custom_role_label: z.string().optional(),
  visibility_scope: RoomDocumentBindingSchema.shape.visibility_scope,
  selected_participant_ids: z.array(z.string()).optional(),
  selected_role_keys: z.array(z.string()).optional(),
  phase_scope: z.array(z.string()).optional(),
  pin_state: RoomDocumentBindingSchema.shape.pin_state.optional(),
  load_preference: RoomDocumentBindingSchema.shape.load_preference.optional(),
  compression_policy: RoomDocumentBindingSchema.shape.compression_policy.optional(),
  required_for_output: z.boolean().optional(),
  version_group_id: z.string().optional(),
  supersedes_doc_id: z.string().optional(),
  notes: z.string().optional()
});

const RoomCreateTransferPacketRequestSchema = z.object({
  from_room_id: z.string(),
  to_surface_kind: z.enum(["room", "panel", "forum"]),
  to_surface_id: z.string(),
  transfer_kind: RoomTransferPacketSchema.shape.transfer_kind,
  content_refs: z.array(TransferContentRefSchema),
  summary_text: z.string().optional(),
  decision_basis_ref: z.string().optional(),
  confidentiality: RoomTransferPacketSchema.shape.confidentiality.optional(),
  import_policy: RoomTransferPacketSchema.shape.import_policy.optional(),
  approved_by_human: z.boolean().optional(),
  approval_checkpoint_id: z.string().optional()
});

const RoomApproveCheckpointRequestSchema = z.object({
  room_id: z.string(),
  checkpoint_id: z.string(),
  human_response_text: z.string().optional(),
  resume_mode: z.enum(["manual_only", "auto_after_approval"]).optional()
});

const RoomRegisterLogicalActorRequestSchema = z.object({
  room_id: z.string(),
  participant_id: z.string(),
  logical_actor_id: z.string(),
  logical_role_key: z.string(),
  agent_profile_id: z.string(),
  display_name: z.string(),
  memory_sharing_policy: z.enum(["none", "explicit_transfer_only"]).optional()
});
```

Suggested Q backend routes:

```text
POST   /api/rooms/:roomId/linked-rooms
POST   /api/rooms/:roomId/links
GET    /api/rooms/:roomId/links

POST   /api/rooms/:roomId/document-bindings
PATCH  /api/rooms/:roomId/document-bindings/:bindingId
DELETE /api/rooms/:roomId/document-bindings/:bindingId
GET    /api/rooms/:roomId/document-bindings

POST   /api/rooms/:roomId/transfer-packets
POST   /api/rooms/:roomId/transfer-packets/:packetId/import
GET    /api/rooms/:roomId/transfer-packets
GET    /api/rooms/:roomId/transfer-packets/inbox
GET    /api/rooms/:roomId/transfer-packets/outbox

POST   /api/rooms/:roomId/approval-checkpoints
POST   /api/rooms/:roomId/approval-checkpoints/:checkpointId/approve
POST   /api/rooms/:roomId/approval-checkpoints/:checkpointId/reject
POST   /api/rooms/:roomId/approval-checkpoints/:checkpointId/return-with-edits
GET    /api/rooms/:roomId/approval-checkpoints

POST   /api/rooms/:roomId/logical-actors
GET    /api/rooms/:roomId/logical-actors

GET    /api/rooms/:roomId/participants/:participantId/delegation-trace
POST   /api/rooms/:roomId/participants/:participantId/trace-mode

POST   /api/rooms/:roomId/findings/:findingId/judgments
```

### A5. Add bootstrap packet extensions

```ts
type RoomBootstrapPacketExtension = {
  logical_actor_id?: string;
  document_binding_refs: Array<{
    binding_id: string;
    doc_id: string;
    doc_role: string;
    materialization_mode: "full" | "summary" | "skeleton" | "chunk_map";
    reason_included: string;
  }>;
  active_review_target_ref?: {
    binding_id: string;
    doc_id: string;
  };
  imported_transfer_packet_refs: string[];
  pending_approval_checkpoint_ref?: string;
  linked_room_refs?: Array<{
    room_id: string;
    edge_kind: string;
    visibility: string;
  }>;
};
```

Assembly rules:

- filter bindings by participant visibility and phase scope,
- promote `pinned_active` docs to highest inclusion priority,
- never leak side-confidential docs across visibility scopes,
- record included/dropped bindings in the DOC11 context manifest,
- preserve active-review-target auto-pinning from Entry 16.3 and expand it here.

### A6. Add built-in room presets

Add built-in presets under the DOC12 preset path:

```text
litigation_courtroom_room
litigation_plaintiff_prep_room
litigation_defense_prep_room
litigation_research_room
litigation_brief_redteam_room
litigation_judge_chambers_room
```

Example starter courtroom preset:

```json
{
  "preset_id": "litigation_courtroom_room",
  "title_template": "Courtroom Room",
  "room_mode": "plan_driven",
  "director_mode_default": true,
  "output_contract_template": "document_draft",
  "participant_slots": [
    { "role_slot": "plaintiff_counsel", "required": true },
    { "role_slot": "defense_counsel", "required": true },
    { "role_slot": "judge", "required": true },
    { "role_slot": "human", "required": true }
  ],
  "round_plan": {
    "phases": [
      { "id": "opening_setup", "label": "Setup", "participants": ["human"], "requires_approval": false },
      { "id": "defense_motion", "label": "Defense Motion", "participants": ["defense_counsel"], "requires_approval": true },
      { "id": "plaintiff_opposition", "label": "Plaintiff Opposition", "participants": ["plaintiff_counsel"], "requires_approval": true },
      { "id": "defense_reply", "label": "Defense Reply", "participants": ["defense_counsel"], "requires_approval": true },
      { "id": "judge_review", "label": "Judge Review", "participants": ["judge"], "requires_approval": true },
      { "id": "final_export", "label": "Export", "participants": ["human"], "requires_approval": true }
    ]
  },
  "linked_room_templates": [
    "plaintiff_brief_redteam",
    "defense_brief_redteam",
    "research_support"
  ]
}
```

### A7. Add UI surfaces to DOC12

#### Room Launch Wizard

Tabs:

1. Preset
2. Roster
3. Documents
4. Workflow
5. Advanced

#### Role Roster Builder

Per slot:

- role label
- agent profile selector
- display name
- reuse logical actor toggle
- allow native subagents
- allow research tools
- default linked room templates
- needs approval before export
- trace visibility

#### Document Shelf

Document card fields:

- title / alias
- `doc_role`
- visibility chip
- phase scope chip
- pin chip
- materialization chip
- version chain / supersedes badge
- source packet badge

Actions:

- bind document
- rebind role
- pin/unpin
- change visibility
- send to linked room
- open in DocIndex

#### Linked Room Navigator

Graph/list of linked rooms with:

- room title
- preset/type
- phase/status
- pending approvals
- unread transfer packets
- runtime truth chip
- child red-team badge
- logical actor overlap badge

#### Transfer Packet Tray

Inbox / Outbox cards showing:

- packet type
- source / destination
- summary
- content refs
- approval status
- confidentiality
- import actions

#### Approval Banner

Persistent blocking banner with actions:

- open diff
- approve & continue
- return with edits
- reject / hold

#### Participant Drawer tabs

- Runtime Truth
- Context Seen
- Documents Used
- Delegation Trace
- Usage / Cost
- Controls

#### Draft / red-team launch affordance

Any room output contract that produces a `document_draft` should expose a `Red-team this draft` action with target selection and import-back strategy.

### A8. Add telemetry

```text
room.link.created
room.link.updated
room.document.bound
room.document.unbound
room.document.pin_changed
room.document.visibility_changed
room.transfer.created
room.transfer.available
room.transfer.imported
room.transfer.rejected
room.approval.requested
room.approval.granted
room.approval.rejected
room.approval.returned_with_edits
room.blocked.awaiting_human
room.logical_actor.bound
room.trace.summary_available
room.trace.capture_degraded
room.finding.judged
```

Every event should include `room_id`, `route_trace_id`, `operation_id`, and when available `room_turn_id`, `participant_id`, `matter_id`, `linked_room_group_id`.

### A9. Add acceptance tests to DOC12 appendix

At minimum:

1. create room-backed litigation room from preset,
2. logical actor reused across two rooms without transcript reuse,
3. document binding persists and appears via SSE,
4. phase-scoped visibility works,
5. side-confidential docs do not leak,
6. active review target remains pinned under compression,
7. transfer packet stores refs rather than full transcript duplication,
8. approval checkpoint blocks scheduler,
9. approval resumes scheduler,
10. return-with-edits keeps room blocked and stores response,
11. child red-team room launches from a draft,
12. red-team findings import back via packet,
13. delegation trace summary renders honestly as summary/partial/unsupported,
14. no direct Q durable writes bypass EC.

---

## B. DOC6 — Matter Panel / Litigation Workbench / Room-Backed Panel Bridge

DOC6 owns panel artifacts and should add a first-class room-backed matter-workbench preset.

### B1. Add panel preset

```text
panel_preset_id: "litigation_matter_workbench"
panel_execution_mode: "room_backed"
```

### B2. Add MatterPanelStateSchema

```ts
const MatterPanelStateSchema = z.object({
  matter_id: z.string(),
  matter_type: z.literal("litigation"),
  title: z.string(),
  panel_execution_mode: z.literal("room_backed"),
  backing_room_id: z.string(),
  linked_room_ids: z.array(z.string()).default([]),
  phase: z.enum([
    "intake",
    "drafting",
    "research",
    "redteam",
    "approval",
    "ready_for_export",
    "closed"
  ]),
  filing_timeline: z.array(z.object({
    stage_id: z.string(),
    label: z.string(),
    due_at: z.string().optional(),
    linked_output_ref: z.string().optional(),
    status: z.enum(["not_started", "in_progress", "awaiting_approval", "complete"])
  })).default([]),
  approval_queue_ref: z.string(),
  filings_index_ref: z.string(),
  transfer_inbox_ref: z.string(),
  document_query: z.object({
    matter_id: z.string(),
    domain_tags: z.array(z.string()).default([])
  }),
  created_at: z.string(),
  updated_at: z.string()
});
```

### B3. Add Matter Workbench UI

Tabs:

- Overview
- Rooms
- Documents
- Drafts & Orders
- Findings
- Approvals
- Telemetry

### B4. Add panel routes

```text
POST /api/panels/create-room-backed
GET  /api/panels/:panelId/rooms
GET  /api/panels/:panelId/documents
GET  /api/panels/:panelId/transfer-inbox
POST /api/panels/:panelId/transfer-packets/:packetId/import
POST /api/panels/:panelId/launch-linked-room
```

### B5. Add create-room-backed-matter contract

```ts
const CreateRoomBackedMatterRequestSchema = z.object({
  panel_preset_id: z.literal("litigation_matter_workbench"),
  room_preset_id: z.string(),
  title: z.string(),
  initial_participants: z.array(z.object({
    role_slot: z.string(),
    agent_profile_id: z.string(),
    display_name: z.string(),
    logical_actor_id: z.string().optional()
  })),
  initial_document_bindings: z.array(z.any()).default([]),
  initial_linked_room_templates: z.array(z.string()).default([]),
  initial_approval_checkpoints: z.array(z.object({
    label: z.string(),
    required_before: z.string()
  })).default([])
});
```

Creation flow:

1. DOC6 creates panel.
2. DOC12 creates backing room.
3. DOC6 stores `backing_room_id`.
4. DOC12 binds docs and logical actors.
5. DOC6 tracks linked rooms, approvals, and matter timeline.
6. DOC10 correlates the route trace across the multi-step create flow.

---

## C. ELNOR Core / DocIndex — matter-aware metadata and coordination

### C1. Keep one canonical document substrate

Do **not** create a second litigation-only store. Extend DocIndex metadata and use room-local bindings + transfer packets for coordination.

### C2. Add metadata extensions

```ts
const DocIndexMetadataExtensionSchema = z.object({
  matter_id: z.string().optional(),
  work_product_class: z.enum([
    "source",
    "authority",
    "evidence",
    "research_note",
    "draft",
    "final_output",
    "decision",
    "instruction",
    "other"
  ]).default("other"),
  domain_tags: z.array(z.string()).default([]),
  workflow_stage: z.string().optional(),
  version_group_id: z.string().optional(),
  supersedes_doc_id: z.string().optional(),
  derived_from_doc_ids: z.array(z.string()).default([]),
  source_room_id: z.string().optional(),
  source_room_turn_id: z.string().optional(),
  source_panel_id: z.string().optional(),
  source_transfer_packet_id: z.string().optional(),
  author_actor_id: z.string().optional(),
  producer_role_key: z.string().optional(),
  access_scope: z.enum([
    "workspace",
    "matter",
    "room_scoped",
    "private"
  ]).default("workspace"),
  approval_status: z.enum([
    "draft",
    "awaiting_human",
    "approved",
    "rejected",
    "superseded",
    "archived"
  ]).default("draft"),
  citation_manifest_ref: z.string().optional()
});
```

### C3. Ship a built-in legal tag taxonomy (extensible strings)

```ts
const BUILTIN_LEGAL_DOMAIN_TAGS = [
  "complaint",
  "answer",
  "motion",
  "motion_to_dismiss",
  "opposition",
  "reply",
  "order",
  "bench_memo",
  "research_memo",
  "authority",
  "case_law",
  "statute",
  "rule",
  "evidence",
  "exhibit",
  "declaration",
  "facts",
  "procedural_history"
];
```

### C4. Add registration / update APIs

```ts
const RegisterDocumentRequestSchema = z.object({
  title: z.string(),
  aliases: z.array(z.string()).default([]),
  file_path: z.string().optional(),
  inline_content: z.string().optional(),
  mime_type: z.string(),
  metadata_extension: DocIndexMetadataExtensionSchema.optional()
});

const UpdateDocumentMetadataRequestSchema = z.object({
  doc_id: z.string(),
  metadata_patch: DocIndexMetadataExtensionSchema.partial()
});
```

Routes:

```text
POST  /api/docindex/documents/register
PATCH /api/docindex/documents/:docId/metadata
GET   /api/docindex/documents/:docId
GET   /api/docindex/search?matterId=...&tag=...&workProductClass=...
```

### C5. Define exact usage model

#### On upload or save-as-document

- Q registers document in DocIndex.
- EC returns stable `doc_id`.
- Any room or panel refers to that `doc_id`.

#### On room binding

- DOC12 stores `RoomDocumentBinding` only.
- No durable document body copy in room storage.

#### On bootstrap assembly

- DOC12 resolves visible bindings.
- DocIndex chooses materialization mode according to load policy and budget.
- DOC11 records included/dropped docs in context manifest.

#### On actual access

- DocIndex emits `document_accessed`.
- DOC15/CIL learns co-access patterns.

#### On cross-room transfer

- transfer packet carries refs to `doc_id` or `room_output_ref`.
- if work product only exists as room output, register it in DocIndex before transfer.
- target room import creates new bindings to the same canonical `doc_id`.

#### On versioning

- each revised brief/order gets a new `doc_id`,
- shared `version_group_id`,
- `supersedes_doc_id` tracks lineage.

### C6. Suggested helper for room outputs

```ts
async function registerGeneratedRoomOutputAsDocument(opts: {
  room_id: string;
  room_turn_id?: string;
  matter_id?: string;
  title: string;
  markdown: string;
  work_product_class: "draft" | "final_output" | "decision";
  domain_tags?: string[];
  version_group_id?: string;
  supersedes_doc_id?: string;
  producer_role_key?: string;
}) {
  return docIndex.register({
    title: opts.title,
    aliases: [opts.title],
    inline_content: opts.markdown,
    mime_type: "text/markdown",
    metadata_extension: {
      matter_id: opts.matter_id,
      work_product_class: opts.work_product_class,
      domain_tags: opts.domain_tags ?? [],
      version_group_id: opts.version_group_id,
      supersedes_doc_id: opts.supersedes_doc_id,
      source_room_id: opts.room_id,
      source_room_turn_id: opts.room_turn_id,
      producer_role_key: opts.producer_role_key,
      approval_status: "draft"
    }
  });
}
```

---

## D. DOC11 — runtime truth, context truth, delegation-trace seam

### D1. Extend participant drawer data contract

```ts
type ParticipantRuntimeDrawerExtended = ParticipantRuntimeDrawerViewModel & {
  document_usage_refs?: string[];
  delegation_trace_latest_ref?: string;
  logical_actor_id?: string;
  room_config_options_ref?: string;
  trace_capture_state?: "off" | "summary" | "partial" | "debug" | "unsupported";
};
```

### D2. Extend context inspector

Add fields for:

- document bindings considered,
- document bindings included,
- document bindings dropped,
- imported transfer packet refs,
- active review target ref,
- pin-state reasons,
- phase-scope filter reasons.

### D3. Add bounded trace seam to room-turn dispatch

```ts
const GatewayRoomTurnDispatchRequestExtension = z.object({
  trace_mode: z.enum(["off", "summary", "debug"]).default("summary")
});

const GatewayRoomTurnResultExtension = z.object({
  trace_capture_state: z.enum([
    "off",
    "summary",
    "partial",
    "debug",
    "unsupported"
  ]).optional(),
  delegation_trace_summary: z.object({
    subagent_count: z.number().int().nonnegative(),
    tool_action_refs: z.array(z.string()),
    doc_access_refs: z.array(z.string()),
    artifact_refs: z.array(z.string()),
    summary: z.string().optional(),
    native_capture_limitations: z.array(z.string()).default([])
  }).optional()
});
```

### D4. Add room/page truth chip requirements

Each room and matter panel should show:

- verified active participants,
- degraded/mismatch count,
- pending approval count,
- blocked state.

---

## E. DOC4 — built-in legal starter agents and variants

DOC4 should ship editable starter templates, not immutable special cases.

### E1. Built-in starter profiles

```text
builtin/plaintiff_counsel
builtin/defense_counsel
builtin/research_associate
builtin/judge_doctrinal
builtin/judge_pragmatic
builtin/brief_redteam_critic
builtin/citation_checker
```

### E2. Extend agent profile fields

```ts
const AgentProfileExtensionSchema = z.object({
  starter_pack_id: z.string().optional(),
  variant_of_agent_id: z.string().optional(),
  room_role_defaults: z.array(z.string()).default([]),
  allowed_room_preset_ids: z.array(z.string()).default([]),
  preferred_trace_mode: z.enum(["off", "summary", "debug"]).optional(),
  document_dependency_templates: z.array(z.object({
    alias: z.string(),
    required: z.boolean().default(false),
    load_preference: z.enum(["full", "summary", "skeleton", "chunk_on_demand"])
  })).default([]),
  capability_expectations: z.array(z.string()).default([]),
  logical_role_keys: z.array(z.string()).default([])
});
```

### E3. Variant system

Starter agents should be cloneable into user-defined subpresets such as aggressive / conservative / technical / strict-evidence variants.

---

## F. DOC14 — red-team integration for litigation workflows

### F1. Add precise review-target binding ref

```ts
const ReviewTargetBindingRefSchema = z.object({
  room_id: z.string(),
  binding_id: z.string(),
  doc_id: z.string(),
  version_group_id: z.string().optional()
});
```

### F2. Add child red-team launch policy

```ts
const ChildRedTeamLaunchPolicySchema = z.object({
  allow_child_redteam_launch: z.boolean().default(true),
  default_import_back_strategy: z.enum([
    "finding_subset",
    "finding_subset_plus_summary",
    "full_redteam_output_ref"
  ]).default("finding_subset"),
  require_human_approval_before_launch: z.boolean().default(false)
});
```

### F3. Canonicalize finding judgment route

DOC14 should explicitly depend on `room_judge_finding` as the canonical judgment path for `FindingJudgmentSchema` persistence and status mutation.

### F4. Add import/export packet compatibility

DOC14 outputs should be easily wrapped into transfer packets containing:

- finding subset refs,
- summary text,
- decision basis refs,
- proposed-fix doc refs.

---

## G. DOC15 — CIL integration for matter defaults and document usage

### G1. Extend document access context facts

```ts
type LitigationContextFactsExtension = {
  matter_id?: string;
  room_id?: string;
  logical_role_key?: string;
  doc_role?: string;
  workflow_stage?: string;
  linked_room_group_id?: string;
};
```

### G2. Add passive signals

```text
signal_type: "transfer_packet_imported"
signal_type: "approval_checkpoint_resolved"
signal_type: "room_document_bound"
```

Default weight should remain observational until promoted by later learning policy.

### G3. Add suggestion-card patterns

Examples:

- “Load your standard documents for this matter stage?”
- “Launch a brief red-team room for this draft?”
- “Prepare a bench memo packet for this judge profile?”

---

## H. DOC10 — orchestration authority matrix and matter endpoints

### H1. Add command types to authority matrix

Add:

- `room_create_linked`
- `room_attach_link`
- `room_bind_document`
- `room_update_document_binding`
- `room_unbind_document`
- `room_create_transfer_packet`
- `room_import_transfer_packet`
- `room_request_approval`
- `room_approve_checkpoint`
- `room_reject_checkpoint`
- `room_return_with_edits`
- `room_register_logical_actor`
- `room_set_trace_mode`
- `room_judge_finding`
- `panel_create_room_backed_matter`
- `panel_import_transfer_packet`
- `panel_launch_linked_room`

### H2. Add read-model endpoints

```text
GET /api/matters/:matterId/overview
GET /api/matters/:matterId/rooms
GET /api/matters/:matterId/documents
GET /api/matters/:matterId/approvals
GET /api/matters/:matterId/telemetry
```

### H3. Route-trace correlation rule

Every linked-room / transfer / approval operation should carry:

- `route_trace_id`
- `operation_id`
- `origin_surface_kind`
- `origin_surface_id`
- `matter_id` when present

---

## I. DOC3 — legal research capability contracts

DOC3 should define provider-agnostic research capabilities rather than hard-coding one vendor name into the core capability id.

### I1. Capability family

```text
legal_research.search
legal_research.get_authority
legal_research.download_authority
legal_research.extract_citations
legal_research.summarize_authority
legal_research.verify_citation
```

### I2. Suggested schemas

```ts
const LegalResearchSearchRequestSchema = z.object({
  query: z.string(),
  jurisdiction: z.string().optional(),
  court_level: z.string().optional(),
  date_range: z.object({
    start: z.string().optional(),
    end: z.string().optional()
  }).optional(),
  result_limit: z.number().int().min(1).max(50).default(10)
});

const LegalResearchSearchResultSchema = z.object({
  provider_result_id: z.string(),
  title: z.string(),
  citation: z.string().optional(),
  court: z.string().optional(),
  decision_date: z.string().optional(),
  snippet: z.string().optional(),
  download_supported: z.boolean().default(false)
});

const LegalResearchGetAuthorityRequestSchema = z.object({
  provider_result_id: z.string()
});

const LegalResearchAuthorityArtifactSchema = z.object({
  authority_id: z.string(),
  title: z.string(),
  citation: z.string().optional(),
  full_text_ref: z.string().optional(),
  summary_text: z.string().optional(),
  extracted_holdings: z.array(z.string()).default([]),
  jurisdiction: z.string().optional(),
  court: z.string().optional()
});
```

### I3. Save behavior

When retained, downloaded authorities and research memos should be registered in DocIndex with `matter_id` and appropriate `work_product_class`.

---

## J. DOC8 — learning signals for workflow outcomes

### J1. Add workflow outcome signal

```ts
const LitigationWorkflowOutcomeSignalSchema = z.object({
  matter_id: z.string(),
  linked_room_group_id: z.string().optional(),
  source_room_id: z.string(),
  workflow_stage: z.string(),
  output_doc_id: z.string().optional(),
  approval_outcome: z.enum([
    "approved",
    "returned_with_edits",
    "rejected"
  ]).optional(),
  synthetic_judge_outcome: z.enum([
    "plaintiff_favored",
    "defense_favored",
    "mixed",
    "undecided"
  ]).optional(),
  human_usefulness_rating: z.number().min(1).max(5).optional(),
  supervision_cost: z.object({
    checkpoint_count: z.number().int(),
    return_with_edits_count: z.number().int(),
    manual_override_count: z.number().int()
  })
});
```

### J2. Weighting rule

Synthetic judge results are useful but lower-weight than human approval/rejection or real downstream outcomes.

---

## K. DOC13 — cost aggregation and reserve budgeting

### K1. Add matter-level cost aggregate

```ts
const MatterCostAggregateSchema = z.object({
  matter_id: z.string(),
  total_tokens: z.number(),
  total_cost_usd: z.number().optional(),
  room_breakdown: z.array(z.object({
    room_id: z.string(),
    tokens: z.number(),
    cost_usd: z.number().optional()
  })),
  participant_breakdown: z.array(z.object({
    logical_actor_id: z.string().optional(),
    participant_id: z.string(),
    tokens: z.number(),
    cost_usd: z.number().optional()
  }))
});
```

### K2. Add minimum viable completion reserve

Child red-team rooms and matter workflows with synthesis/export phases should reserve enough budget to finish with a coherent export rather than dying mid-critique.

---

## L. DOC7 — bucket/materialization compatibility

Allow `TransferPacketRef` and `RoomDocumentBindingRef` as valid context/materialization sources. Preserve confidentiality and do not create second durable copies when a packet merely references a document.

---

## 16.4.5 Required code changes

## A. Room command handlers

### A1. Document binding flow

```ts
async function applyRoomBindDocument(cmd: RoomCommandEnvelope<RoomBindDocumentRequest>) {
  const p = RoomBindDocumentRequestSchema.parse(cmd.payload);
  await assertRoomExists(p.room_id);
  await assertDocExistsInDocIndex(p.doc_id);

  const binding = RoomDocumentBindingSchema.parse({
    binding_id: crypto.randomUUID(),
    room_id: p.room_id,
    doc_id: p.doc_id,
    alias_used: p.alias_used,
    doc_role: p.doc_role,
    custom_role_label: p.custom_role_label,
    visibility_scope: p.visibility_scope,
    selected_participant_ids: p.selected_participant_ids,
    selected_role_keys: p.selected_role_keys,
    phase_scope: p.phase_scope,
    pin_state: p.pin_state ?? "unpinned",
    load_preference: p.load_preference ?? "full_if_budget",
    compression_policy: p.compression_policy ?? "allow_docindex",
    required_for_output: p.required_for_output ?? false,
    version_group_id: p.version_group_id,
    supersedes_doc_id: p.supersedes_doc_id,
    added_by: cmd.actor,
    added_at: cmd.issued_at,
    notes: p.notes
  });

  await appendJsonl(ROOM_DOCUMENT_BINDING_EVENTS_JSONL_PATH(p.room_id), {
    event_type: "room_document_bound",
    binding
  });

  const current = await loadJson(ROOM_DOCUMENT_BINDINGS_CURRENT_PATH(p.room_id), { bindings: [] });
  current.bindings.push(binding);
  await atomicWriteJson(ROOM_DOCUMENT_BINDINGS_CURRENT_PATH(p.room_id), current);

  await emitRoomEvent(p.room_id, "room.document.bound", {
    room_id: p.room_id,
    binding_id: binding.binding_id,
    doc_id: binding.doc_id,
    doc_role: binding.doc_role
  });

  return { status: "ok", binding_id: binding.binding_id };
}
```

### A2. Transfer packet flow

```ts
async function applyRoomCreateTransferPacket(
  cmd: RoomCommandEnvelope<RoomCreateTransferPacketRequest>
) {
  const p = RoomCreateTransferPacketRequestSchema.parse(cmd.payload);

  await assertRoomExists(p.from_room_id);
  await assertSurfaceExists(p.to_surface_kind, p.to_surface_id);
  for (const ref of p.content_refs) await assertTransferRefExists(ref);

  const packet = RoomTransferPacketSchema.parse({
    packet_id: crypto.randomUUID(),
    from_surface_kind: "room",
    from_surface_id: p.from_room_id,
    to_surface_kind: p.to_surface_kind,
    to_surface_id: p.to_surface_id,
    transfer_kind: p.transfer_kind,
    status: "available",
    content_refs: p.content_refs,
    summary_text: p.summary_text,
    decision_basis_ref: p.decision_basis_ref,
    approved_by_human: p.approved_by_human ?? false,
    approval_checkpoint_id: p.approval_checkpoint_id,
    created_by: cmd.actor,
    created_at: cmd.issued_at,
    confidentiality: p.confidentiality ?? "normal",
    import_policy: p.import_policy ?? "manual_import"
  });

  await appendJsonl(ROOM_TRANSFER_PACKETS_JSONL_PATH, packet);
  await addPacketToOutbox(packet.from_surface_id, packet);
  await addPacketToInbox(packet.to_surface_kind, packet.to_surface_id, packet);

  await emitRoomEvent(p.from_room_id, "room.transfer.created", {
    packet_id: packet.packet_id,
    transfer_kind: packet.transfer_kind,
    to_surface_kind: packet.to_surface_kind,
    to_surface_id: packet.to_surface_id
  });

  return { status: "ok", packet_id: packet.packet_id };
}
```

### A3. Approval checkpoint flow

```ts
async function requestApprovalCheckpoint(roomId: string, checkpoint: ApprovalCheckpoint) {
  await appendJsonl(ROOM_APPROVAL_EVENTS_JSONL_PATH(roomId), {
    event_type: "approval_requested",
    checkpoint
  });

  const current = await loadJson(ROOM_APPROVAL_CHECKPOINTS_CURRENT_PATH(roomId), { items: [] });
  current.items = upsertById(current.items, checkpoint, "checkpoint_id");
  await atomicWriteJson(ROOM_APPROVAL_CHECKPOINTS_CURRENT_PATH(roomId), current);

  await patchRoomState(roomId, {
    block_state: "awaiting_human_approval",
    blocking_checkpoint_id: checkpoint.checkpoint_id
  });

  await emitRoomEvent(roomId, "room.approval.requested", {
    checkpoint_id: checkpoint.checkpoint_id,
    required_before: checkpoint.required_before
  });
}
```

Scheduler guard:

```ts
if (room.block_state === "awaiting_human_approval") {
  doNotScheduleAnyFurtherTurns(room.room_id);
  return;
}
```

### A4. Approval resolution flow

```ts
async function applyRoomApproveCheckpoint(
  cmd: RoomCommandEnvelope<RoomApproveCheckpointRequest>
) {
  const p = RoomApproveCheckpointRequestSchema.parse(cmd.payload);

  const current = await loadJson(ROOM_APPROVAL_CHECKPOINTS_CURRENT_PATH(p.room_id));
  const checkpoint = findRequiredCheckpoint(current, p.checkpoint_id);

  checkpoint.status = "approved";
  checkpoint.resolved_by = cmd.actor;
  checkpoint.resolved_at = cmd.issued_at;
  checkpoint.human_response_text = p.human_response_text;

  await atomicWriteJson(ROOM_APPROVAL_CHECKPOINTS_CURRENT_PATH(p.room_id), current);
  await appendJsonl(ROOM_APPROVAL_EVENTS_JSONL_PATH(p.room_id), {
    event_type: "approval_resolved",
    checkpoint_id: p.checkpoint_id,
    status: "approved",
    resolved_by: cmd.actor
  });

  await patchRoomState(p.room_id, {
    block_state: "none",
    blocking_checkpoint_id: null
  });

  await emitRoomEvent(p.room_id, "room.approval.granted", {
    checkpoint_id: p.checkpoint_id
  });

  if ((p.resume_mode ?? checkpoint.resume_mode) === "auto_after_approval") {
    await enqueueRoomSchedulerWake(p.room_id);
  }

  return { status: "ok" };
}
```

## B. Q frontend implementation tasks

1. Build the Room Launch Wizard.
2. Build the Role Roster Builder.
3. Build the Document Shelf.
4. Build the Linked Room Navigator.
5. Build the Transfer Packet Tray.
6. Build the Approval Banner and Approval Queue surfaces.
7. Extend participant drawers with Documents Used and Delegation Trace tabs.
8. Add “Red-team this draft” affordance on eligible room outputs.
9. Add room-backed matter-workbench pages and tabs.

## C. Bootstrap and context assembly code

At room-turn bootstrap:

1. load room document bindings,
2. filter by visibility + phase scope,
3. materialize through DocIndex according to load policy,
4. pin active review target,
5. include transfer packet summaries and imported instructions where relevant,
6. record all of this in the context manifest.

## D. Panel bridge code

Add code that maps:

- panel stage ↔ room phase,
- room output refs ↔ panel filing timeline,
- approval checkpoints ↔ panel approval queue,
- transfer inbox/outbox ↔ room/panel surfaces.

---

## 16.4.6 End-to-end reference flow

### Example: matter creation → draft → approval → red-team → order

1. User creates a new Litigation Workbench matter.
2. DOC6 creates the panel and DOC12 creates the backing courtroom room.
3. DOC12 registers logical actors and initial document bindings.
4. A side room produces a draft brief and saves it as a DocIndex document.
5. An approval checkpoint blocks progression until the human approves or returns edits.
6. A red-team child room launches against that draft via a transfer packet.
7. Findings or critique packets import back into the source room or matter panel.
8. A judge or chambers room drafts an order.
9. The order is registered in DocIndex with lineage metadata and appears in the matter timeline.

Reference flow:

```text
Q Frontend
  -> Q Backend proxy
  -> EC command envelope
  -> DOC12 / DOC6 / DocIndex durable write
  -> telemetry + SSE
  -> room / panel UI refresh
```

## 16.4.7 Risks and mitigations

### Risk 1 — architecture drifts into a legal-only special case

**Mitigation:** keep the core generic and ship litigation as a first-party pack.

### Risk 2 — rooms and panels duplicate each other

**Mitigation:** panel owns governance / room owns live execution; strengthen the bridge instead of flattening them together.

### Risk 3 — document chaos and duplicate storage

**Mitigation:** one DocIndex substrate, room-local bindings only, transfer packets store refs not bodies.

### Risk 4 — side-confidential leakage

**Mitigation:** explicit visibility scopes, phase filters, confidentiality on transfer packets, context manifest auditing.

### Risk 5 — fake trace visibility

**Mitigation:** bounded summary contracts with `partial` / `unsupported` states instead of bluffing completeness.

### Risk 6 — approval gates become UI cosmetics

**Mitigation:** room scheduler must actually block on checkpoint state.

### Risk 7 — “same actor across rooms” tempts transcript/session reuse

**Mitigation:** logical actor binding must never imply shared room transcript state.

---

## 16.4.8 Suggested implementation sequence

### Phase 1 — owner contracts and storage

- DOC12 linked-room / binding / transfer / approval schemas
- DocIndex metadata extensions
- DOC6 matter panel preset and state
- DOC10 authority matrix updates

### Phase 2 — minimum viable workflow

- room launch wizard
- logical actor binding
- document shelf
- approval checkpoints
- transfer packets
- room-backed matter panel

### Phase 3 — review and trace polish

- child red-team launch
- delegation trace summaries
- participant drawer enhancements
- matter telemetry and cost aggregates

### Phase 4 — legal research + learning polish

- DOC3 research capability integration
- DOC15 matter doc-set suggestions
- DOC8 workflow-outcome learning

---

## 16.4.9 Acceptance criteria

This entry is addressed only when:

1. A user can create a room-backed litigation matter with a courtroom room and linked prep/research/red-team rooms.
2. The same logical actor can appear across multiple rooms without transcript/session reuse.
3. Documents are stored canonically in DocIndex and coordinated via room bindings, not duplicated into a second database.
4. Transfer packets move refs/provenance between rooms and panels.
5. Approval checkpoints structurally block room progression until human approval.
6. The UI exposes roster, document, trace, transfer, and approval state clearly.
7. Red-team child rooms can be launched from draft outputs and their results can import back cleanly.
8. Runtime truth, context truth, and trace-capture limitations remain honest.
9. Every user control maps to EC command → durable write → telemetry → visible read-model.

---

## 16.4.10 Recommended decision for now

Treat this as a major planned addition and use it as the canonical planning entry for the next DOC12 / DOC6 / DOC11 / DOC4 revision wave. The goal is not to make ELNOR “about litigators”; the goal is to harden linked-room, document-centric, approval-gated multi-agent workflows in a way that supports litigation as a first-party pack and improves the broader architecture at the same time.


# Entry 16.5 — Knowledge Topology / Graph Read-Model for Documents, Claims, Matters, and Learned Context

## 16.5.1 Problem statement

ELNOR already has several **graph-like** pieces, but they are distributed and not yet preserved as one coherent architecture:

- DOC1 already owns a canonical **memory relationship index** for memory-to-memory edges.
- ELNOR Core already owns document indexing, DOCMETA discovery, and hybrid retrieval surfaces.
- DOC15 already learns from document access and recommends `workspace_default` document sets.
- DOC18 already defines a semantic retrieval sidecar for selected corpora.
- DOC10 already supports bounded reference-first context and controlled neighbor expansion.

What is missing is a preserved architecture for a broader **knowledge topology / graph read-model** that can improve:

- retrieval reranking,
- relation-aware explanation,
- contradiction / supersession handling,
- support-pack assembly,
- workspace / matter document suggestions,
- and later legal/domain navigation.

Without that preserved architecture, the same idea will keep resurfacing as disconnected feature requests: “related documents,” “why did this match?,” “show what superseded this,” “group documents by issue,” “learn support packs,” and “track matter/workflow context.”

## 16.5.2 Why this matters

### A. Retrieval quality improves when the system can navigate relationships, not just words

Semantic retrieval is helpful, but retrieval gets markedly better when the system can also use **typed relations** such as:

- same matter,
- same issue,
- supersedes,
- contradicts,
- used with,
- support-pack member,
- successful in context.

That is how ELNOR avoids both:

- lexical misses (“wrong words, right idea”), and
- prompt sludge (“too many vaguely relevant results, no topology”).

### B. Explanation surfaces need relation truth

If ELNOR suggests a document, suppresses an older memory, or recommends a support pack, the user should be able to ask **why** and get a truthful answer such as:

- “this document is in the same matter and was co-used in similar motion types,”
- “this memory was deprioritized because a later correction superseded it,”
- “these documents were grouped because they repeatedly traveled together in successful reviews.”

That kind of explanation depends on relation-aware read models, not only vector similarity or keyword scores.

### C. This is a good bridge between generic retrieval and legal/domain work

A light topology layer gives ELNOR a clean way to represent:

- matters,
- cases,
- motion types,
- document roles,
- issues/doctrines/claims,
- workflow stages,
- and learned behavior patterns

without turning the entire platform into a legal-only special case.

### D. This should be derived, not a second truth store

The right answer is **not** a giant parallel database that silently becomes “the real truth.”

The right answer is a **derived read-model** built from existing durable artifacts so it can improve retrieval and explanation while canonical ownership stays where it already belongs.

## 16.5.3 Relevant current architecture

This entry assumes the following owner split stays intact:

- **DOC1** keeps ownership of the current memory relationship index.
- **ELNOR Core / DocIndex** are the most likely eventual owners of the broader document/claim/matter/workflow topology read-model.
- **DOC18** keeps ownership of the LlamaIndex semantic corpus sidecar.
- **DOC3** keeps ownership of route/provider doctrine.
- **DOC15** consumes topology outputs for ranking, packaging, suggestions, and advisor explanations.
- **DOC10** keeps orchestration discipline, bounded context assembly, and user-visible receipts/explanations.

## 16.5.4 Recommended architecture decision

## Decision

Preserve a **Knowledge Topology / Graph Read-Model** as a planned architecture addition.

### Keep

- DOC1 memory relationship index as the canonical current relationship system for memory edges.
- DOC18 as an optional semantic retrieval sidecar for selected corpora.
- DOC10’s bounded, reference-first, one-context-authority discipline.
- DOC15 as a **consumer** of graph/topology outputs, not the universal owner.

### Add

- a broader **derived** topology read-model over documents, claims, matters, workflow nodes, and learned context;
- bounded neighbor traversal and relation-aware explanation seams;
- graph-aware document priority hints and support-pack groupings;
- contradiction/supersession freshness and health semantics;
- topology-backed recommendation inputs for CIL/advisors/Q surfaces.

### Do not do

- Do **not** replace canonical files with graph nodes as truth.
- Do **not** make DOC18 or LlamaIndex the owner of graph truth.
- Do **not** force DOC1 to own every document/matter/claim relationship immediately.
- Do **not** commit to a graph database before the read-model and owner split are proven.
- Do **not** turn this into an “Obsidian clone” product rewrite.

## 16.5.5 Proposed node and edge families

### A. Recommended starting node families

#### Scope / operational nodes
- `workspace`
- `matter`
- `case`
- `operation` / `dispatch`
- `panel_run`
- `room_run`
- `review_target`

#### Document nodes
- `document`
- `document_version`
- `document_chunk` (read-model only)
- `transcript` / `recording_artifact`

#### Memory / learning nodes
- `authority_memory`
- `heuristic_knowledge_node`
- `preference_hint`
- `document_recommendation_node`
- `support_pack` / `workspace_default_set`

#### Legal/domain nodes
- `motion_type`
- `document_role`
- `issue` / `doctrine` / `claim`
- `cause_of_action`
- `procedural_posture`
- `workflow_stage`
- `evidence_domain`
- later if useful: `jurisdiction`, `court`

#### Entity / concept nodes
- `person` / `organization` / `counterparty`
- `topic` / `concept`

### B. Recommended starting edge families

- `belongs_to_workspace`
- `belongs_to_matter`
- `belongs_to_case`
- `references`
- `derived_from`
- `supports`
- `contradicts`
- `supersedes`
- `same_issue_as`
- `used_with`
- `successful_in_context`
- `applies_to_motion_type`
- `classified_as`
- `generated_in_run`
- `approved_in`
- `rejected_in`

### C. Dynamic behavior rule

Safe to create automatically:

- deterministic document/workspace/matter/version nodes,
- operation/panel/room references,
- straightforward `belongs_to_*` edges,
- co-access / used-with edges,
- support-pack membership candidates.

Usually should be proposal-/confidence-gated:

- `contradicts`,
- `supersedes`,
- ambiguous legal categorization,
- issue/claim extraction when the source is uncertain.

Authority nodes remain protected and may not be silently rewritten by graph maintenance.

## 16.5.6 Suggested schemas (planning-grade)

```ts
export const TopologyNodeKindSchema = z.enum([
  "workspace",
  "matter",
  "case",
  "operation",
  "panel_run",
  "room_run",
  "review_target",
  "document",
  "document_version",
  "document_chunk",
  "transcript",
  "recording_artifact",
  "authority_memory",
  "heuristic_knowledge_node",
  "preference_hint",
  "document_recommendation_node",
  "support_pack",
  "workspace_default_set",
  "motion_type",
  "document_role",
  "issue",
  "doctrine",
  "claim",
  "cause_of_action",
  "procedural_posture",
  "workflow_stage",
  "evidence_domain",
  "topic",
  "concept",
  "person",
  "organization",
  "counterparty",
]);

export const TopologyEdgeKindSchema = z.enum([
  "belongs_to_workspace",
  "belongs_to_matter",
  "belongs_to_case",
  "references",
  "derived_from",
  "supports",
  "contradicts",
  "supersedes",
  "same_issue_as",
  "used_with",
  "successful_in_context",
  "applies_to_motion_type",
  "classified_as",
  "generated_in_run",
  "approved_in",
  "rejected_in",
]);

export const TopologyNodeSchema = z.object({
  node_id: z.string().uuid(),
  node_kind: TopologyNodeKindSchema,
  canonical_ref: z.string(),
  title: z.string().max(240),
  scope: z.object({
    workspace_id: z.string().optional(),
    matter_id: z.string().optional(),
    case_id: z.string().optional(),
  }).default({}),
  metadata: z.record(z.unknown()).default({}),
  provenance: z.object({
    source_system: z.string(),
    source_ref: z.string(),
    derived: z.boolean().default(false),
  }),
  created_at: z.string().datetime(),
  updated_at: z.string().datetime(),
});

export const TopologyEdgeSchema = z.object({
  edge_id: z.string().uuid(),
  src_id: z.string().uuid(),
  tgt_id: z.string().uuid(),
  edge_kind: TopologyEdgeKindSchema,
  strength: z.number().min(0).max(1).default(0.5),
  freshness_state: z.enum(["fresh", "aging", "stale", "degraded"]).default("fresh"),
  confidence: z.number().min(0).max(1).optional(),
  provenance: z.object({
    source_system: z.string(),
    source_ref: z.string(),
    generation_mode: z.enum(["deterministic", "learned", "proposed"]),
  }),
  metadata: z.record(z.unknown()).default({}),
  created_at: z.string().datetime(),
  updated_at: z.string().datetime(),
});
```

## 16.5.7 Required spec changes

## A. DOC10 Orchestration Integration Ledger

Add suite-wide XDI rows for:

- retrieval-lane ownership,
- provider truth,
- retrieval receipt surfaces,
- graph-aware advisory seams,
- topology build/health jobs,
- and docs-consistency coverage.

## B. DOC15 — CIL / MemorySearchService / ContextPlanner

Add:

- topology-backed ranking inputs,
- relation-aware advisor explanation hooks,
- graph-aware document priority/support-pack hints,
- bounded relationship-index consumption rules,
- and retrieval-receipt/provider-truth display fields for CIL surfaces.

## C. DOC18 — LlamaIndex Retrieval Sidecar

Clarify:

- that DOC18 stays a semantic-corpus lane only,
- how corpus/provider truth enters receipts,
- how staleness/degraded state is surfaced,
- and how topology uses sidecar results without letting the sidecar become graph truth.

## D. DOC3 — routing/provider doctrine

Add / confirm:

- unified provider/lane naming,
- route scoring reason codes that distinguish semantic corpus vs canonical memory,
- and route receipts that can be shown in Q / advisor surfaces.

## E. DOC7 — Context Buckets & Files

Add:

- graph-aware `document_priority_hints`,
- support-pack group hints,
- and bounded neighbor/document expansion compatibility with CRS/materialization budgets.

## F. ELNOR Core / DocIndex

Add:

- topology snapshot/build jobs,
- aliases / stable IDs,
- bounded neighbor lookup APIs,
- freshness/health exports,
- and support-pack/materialization handoff seams.

## G. DOC1 (optional cross-amendment note)

Only if helpful, add a small clarifying note that:

- DOC1 continues to own the memory relationship index,
- and broader document/matter/claim topology will sit beside it rather than silently replacing it.

## 16.5.8 Required code changes

## A. Topology build and refresh jobs

Add read-model builders that:

- ingest canonical refs from DocIndex / Core / checkpoints / memory records,
- derive node/edge snapshots,
- assign freshness states,
- and publish health metrics.

## B. Query / traversal helpers

Add helpers such as:

- `getTopologyNode(nodeId)`
- `getTopologyNeighbors(nodeId, filters)`
- `getSupportPackMembers(packId)`
- `explainRelationPath(srcId, tgtId)`

These should stay read-only and bounded.

## C. Q / advisor / inspector surfaces

Add support for:

- relation pills,
- provider/lane receipt chips,
- stale/degraded warnings,
- and “why this matched / why this replaced that?” explanation blocks.

## 16.5.9 Risks and mitigations

### Risk 1 — the read-model silently becomes truth
Mitigation: keep canonical writes in existing owner docs; topology remains derived and rebuildable.

### Risk 2 — overconnected noise
Mitigation: bounded edge families, confidence/freshness, and reason-coded explanations.

### Risk 3 — stale or misleading relation paths
Mitigation: freshness state, degraded mode, and visible health exports.

### Risk 4 — prompt sludge by uncontrolled neighbor expansion
Mitigation: relation-aware expansion stays bounded and reference-first under DOC10/DOC7 budgets.

### Risk 5 — LlamaIndex drifts into “the memory system”
Mitigation: keep sidecar truth limited to semantic corpus retrieval and preserve separate canonical memory ownership.

### Risk 6 — domain taxonomy expands faster than owner docs
Mitigation: preserve flexible node metadata and add legal/domain classes incrementally, not as hard-coded giant taxonomies on day one.

## 16.5.10 Suggested implementation sequence

### Phase 1 — preservation and trackers
- update DOC10 ledger, DOC15 contract, and DOC16 entries;
- keep the architecture preserved before touching owner docs.

### Phase 2 — owner-doc clarification
- revise DOC18 and DOC3 for route/provider truth;
- define Core/DocIndex topology build and read seams.

### Phase 3 — bounded consumer adoption
- revise DOC15 and DOC7 to consume topology-backed ranking, support-pack hints, and explanation data.

### Phase 4 — domain/legal enrichment
- add matter/case/motion/document-role/workflow enrichment only after the generic substrate works.

## 16.5.11 Acceptance criteria

1. A related-document suggestion can explain whether it came from semantic corpus retrieval, canonical memory, or graph-neighbor expansion.
2. A stale/superseded item can be shown with a truthful explanation rather than just disappearing silently.
3. One-hop relation-aware expansion can be used without turning every query into an uncontrolled graph walk.
4. DOC1 memory relations continue to work without being replaced or broken.
5. DOC18 continues to function as a sidecar provider rather than a second truth system.
6. DOC15 can consume topology outputs for suggestions/advisors without becoming the owner of graph storage.

## 16.5.12 Recommended decision for now

Treat this as a **major preserved architecture addition** and use it as the canonical planning entry for the retrieval / graph / topology amendment wave.

The immediate goal is **not** to ship a giant graph product. The immediate goal is to preserve the owner split, the node/edge model, and the consumer seams so the next DOC18 / DOC3 / DOC10 / DOC7 / DOC15 revisions can absorb the right parts without cross-document drift.


# Entry 16.6 — Interactive Chat / Forum / Panel Latency, Streaming, and Composer Responsiveness

**Status:** Ready for spec  
**Priority:** High  
**Primary owners:** DOC11 / DOC10 / EC Core Rebuild / Q Dashboard Master UI Specification / DOC6  
**Secondary owners:** DOC13 (latency and abort telemetry visibility), DOC15 (explanation/debug surfaces only)

## 16.6.1 Problem statement

The current implementation preserved some useful low-latency patterns, but the overall interactive surface is still architecturally split between:

- **good perceived-latency tricks** that reduce waiting pain,
- and **unfinished transport/runtime truth work** that prevents truly smooth chat.

The result is a system where chat can feel acceptable in light usage, but the architecture still permits:

- blocking full-response fetches instead of true streaming,
- cosmetic stop/abort controls,
- expensive background hydration interfering with active composition,
- forum/panel post acceptance being coupled to follow-up orchestration work,
- and composer/input behavior that is not fit for long-form drafting.

The specific current failure modes that must be preserved and fixed in the rebuild are:

### A. Interactive chat is still final-only at the user-visible layer

The previous Q chat path used:

- immediate optimistic user append,
- immediate local `thinkingState`,
- bounded context assembly,
- Gateway session reuse,
- short retry / backoff / fallback logic,

but the assistant reply still arrived through a blocking `fetch()` response rather than a real token stream. That means:

- no real TTFT-visible incremental output,
- no truthful stream gap handling,
- no real abort UX,
- and no proper active-run read model.

### B. Forum/panel posting mixes “post accepted” with downstream orchestration

The current forum/panel post routes follow a fragile sequence:

1. persist the user post,
2. run orchestrator tick / follow-up work,
3. then return the HTTP response.

That means the user-visible acceptance path is blocked on secondary work that is not the same thing as “your post was saved.”

This is exactly the wrong contract for an interactive surface.

If the post is durably written but the downstream tick is slow or errors:

- the user sees delay,
- the post may eventually appear,
- the composer may not clear,
- the user may think the submit failed and retry,
- and duplicate or confusing states become likely.

### C. Composer behavior is under-specified and currently wrong for panel/forum use

The current panel/forum post boxes behave like single-line inputs rather than multiline drafting surfaces. Long text continues horizontally instead of wrapping. That is not only bad UX; it also pressures users into worse interaction patterns and makes quick drafting feel broken.

### D. Dashboard-wide polling/hydration can still compete with active interactive work

The current frontend already added some protection:

- defer heavy message hydration while typing,
- signature-based update suppression,
- `startTransition` for lower-priority state merges,
- preservation of local optimistic messages during backend reconciliation.

Those patterns worked and must not be lost. But they are not yet preserved as spec-owned build obligations, which means a rebuild could accidentally regress and reintroduce typing lag, transcript churn, and scroll jank.

## 16.6.2 Why this matters

This matters because interactive latency is not one bug. It is a chain of distinct user-facing failure modes:

- “I clicked send and nothing seemed to happen”
- “my text posted, but the box didn’t clear”
- “the transcript jumps while I’m typing”
- “the reply appears all at once after a long stall”
- “stop exists, but it doesn’t actually stop anything”
- “long conversations feel heavier and heavier”

These failures destroy operator trust faster than many deeper backend issues, because they happen in the main surface continuously.

For a rebuild, low-latency interactive behavior must be treated as a first-class architecture concern, not a cosmetic polish pass.

## 16.6.3 Relevant implementation lessons from the previous build

The previous build already demonstrated several patterns worth preserving:

### A. What worked

- optimistic local append for the user message,
- local message IDs and reconciliation against persisted IDs,
- immediate local pending/thinking state,
- deterministic bounded context assembly,
- parallel hot-path enrichment work,
- Gateway session reuse by conversation/model,
- transient retry and quota backoff before falling back,
- snapshot-signature suppression of unnecessary frontend state writes,
- hydration deferral while the user is actively typing,
- `startTransition` for lower-priority dashboard state updates.

### B. What did not work

- no true assistant token streaming,
- no dedicated stream reducer/read model,
- no truthful abort state machine,
- no separation between “accepted” and “completed” in some interactive post flows,
- no preserved multiline composer contract for forum/panel drafting,
- no spec-owned virtualization / bottom-stick / markdown-finalization rules.

### C. Required conclusion

The rebuild must preserve the successful low-latency patterns while replacing the unfinished transport and UI contracts with real, explicit ones.

## 16.6.4 Recommended architecture decision

## Decision

Add a preserved cross-doc **Interactive Low-Latency Surface Contract** covering:

- chat send,
- forum post,
- panel post,
- stream display,
- abort/stop,
- draft/composer behavior,
- and reconciliation between optimistic UI and durable/runtime truth.

### Keep

- optimistic local append for user-originated messages/posts,
- deterministic bounded context assembly,
- no hot-path LLM in EC context planning,
- session reuse and retry/backoff logic where appropriate,
- defer-heavy-hydration-while-typing behavior,
- signature-based state-write suppression,
- runtime-truth-first behavior for chat execution state.

### Add

- explicit `accepted` vs `completed` vs `failed` semantics for interactive mutations,
- true chat streaming with batched UI delta application,
- abort state read-models and visible abort lifecycle,
- async follow-up/orchestration work after post acceptance,
- autosizing multiline composers for chat/forum/panel,
- per-surface draft persistence,
- transcript virtualization / bounded DOM rules,
- markdown-finalization rules so streaming does not repeatedly reparse heavy formatting,
- bottom-stick and scroll-preservation rules,
- explicit latency metrics and budgets.

### Do not do

- Do **not** make interactive chat depend on a blocking full-response fetch as the normative path.
- Do **not** block forum/panel post acceptance on orchestrator ticks, extraction, moderation side work, or secondary automation.
- Do **not** use single-line `<input>` controls for forum/panel drafting surfaces.
- Do **not** let dashboard-wide snapshot hydration become the primary live chat transport.
- Do **not** parse/render full markdown on every streaming delta.
- Do **not** optimistically claim “stopped” before real abort truth arrives.

## 16.6.5 Required spec changes

## A. DOC11 — runtime transport, streaming, abort, latency truth

Add a dedicated subsection such as:

- `Interactive Low-Latency Transport and Streaming Truth`

That section should explicitly define:

1. `dispatch accepted` vs terminal completion semantics for interactive chat.
2. Streaming event family ownership:
   - `gateway.chat.accepted`
   - `gateway.chat.stream.delta`
   - `gateway.chat.completed`
   - `gateway.chat.failed`
   - `gateway.chat.aborted`
3. Required fields for latency measurement:
   - `accepted_at`
   - `first_token_at`
   - `completed_at`
   - `ttft_ms`
   - `latency_ms`
   - `stream_duration_ms`
4. Stream gap detection and recovery truth.
5. Abort/STOP state machine:
   - `abort_pending`
   - `abort_verified`
   - `abort_unknown`
   - `abort_failed`
   - optional `cleanup_pending`
6. Session reuse rules for interactive chat.
7. A rule that Q renders from read-model truth and stream state, not from decorative local assumptions.
8. A rule that streaming deltas may be batched for UI transport, but batching must never falsify order or terminal truth.

## B. DOC10 — accepted/completed orchestration semantics

Add a subsection such as:

- `Interactive Mutation Lifecycle: accepted != completed`

That section should define:

1. User-visible interactive mutations that require fast acceptance:
   - chat send
   - forum post
   - panel post
   - reply-in-place / comment-like post surfaces
2. Required lifecycle states:
   - `accepted`
   - `secondary_work_pending`
   - `completed`
   - `failed_after_accept`
3. The rule that secondary work must never redefine whether the initial user action was accepted.
4. The difference between:
   - durable write acceptance,
   - runtime execution acceptance,
   - downstream enrichment completion.
5. Required receipts for accepted mutations.

## C. EC Core Rebuild spec — hot path, caches, async work queue

Add a subsection such as:

- `Interactive Hot Path Budget and Async Follow-Up`

That section should define:

1. Hard hot-path rule: no hot-path LLM in context assembly.
2. Revision-keyed cacheability for:
   - session-start context
   - resolved prompt plan
   - bounded authority pack
   - bounded memory retrieval slices
3. Background-only follow-up queue for:
   - forum/panel orchestrator ticks
   - extraction
   - secondary telemetry enrichment
   - post-send analysis
4. Required timeout budgets for hot-path enrichment.
5. The rule that accepted user mutations may enqueue follow-up work, but may not wait on it unless the user-facing contract explicitly says so.

## D. DOC6 — forum and panel posting contracts

Add a subsection such as:

- `Interactive Posting Acceptance and Composer Contract`

That section should define:

1. `POST /forum/.../posts` and `POST /panel/.../posts` semantics:
   - durable post append first,
   - immediate accepted response,
   - async orchestrator tick afterward.
2. UI-visible states:
   - `posting`
   - `posted`
   - `posted_with_followup_warning`
   - `post_failed_before_accept`
3. Required per-post IDs and reconciliation behavior.
4. The rule that failure in downstream forum/panel automation must not cause the main post composer to behave as though the post itself failed.

## E. Q Dashboard Master UI Specification

Add a dedicated section such as:

- `Interactive Surface Performance and Composer Rules`

It should define:

1. Chat send optimistic append.
2. Assistant pending row behavior.
3. Stream reducer and delta batching cadence.
4. Local-only vs persisted message reconciliation.
5. Hydration suppression while typing / while stream active.
6. Autosizing multiline `textarea` requirement for:
   - chat composer
   - forum reply box
   - panel inject post box
7. Keyboard behavior:
   - `Enter` sends
   - `Shift+Enter` newline
   - IME-safe composition handling
8. Draft persistence by surface scope.
9. Scroll and transcript virtualization rules.
10. Markdown-finalization rule:
    - lightweight/plain render while streaming,
    - full markdown/code render after completion.

## F. DOC13 — latency/cost read visibility

Add a small clarifying note that interactive latency and abort/stream lifecycle metrics may be recorded beside usage/cost read models for operator visibility, but DOC13 does not become the transport owner.

## 16.6.6 Required code changes

## A. Q frontend / rebuild UI modules

Required modules:

- `chat-store`
- `chat-stream-store`
- `forum-post-store`
- `panel-post-store`
- `composer-draft-store`
- `transcript-virtualizer`

Required behavior:

1. User message/post appends locally immediately.
2. Composer clears on `accepted`, not on final downstream completion.
3. Each optimistic row carries:
   - `client_message_id` or `client_post_id`
   - `scope_kind`
   - `scope_id`
   - `status`
   - `accepted_at`
4. Backend-confirmed rows reconcile by durable ID.
5. Stream deltas append to a live assistant draft row via a reducer.
6. Heavy background hydration must be deferred while typing or streaming.
7. Transcript rerenders must be bounded:
   - virtualization for long lists,
   - signature checks before wholesale state replacement,
   - low-priority transitions for snapshot updates.

## B. Q backend / interactive transport routes

Required changes:

1. Chat dispatch route must separate:
   - transport acceptance,
   - stream forwarding,
   - terminal result reconciliation.
2. Add a dedicated stream bridge:
   - SSE or WebSocket, but one owner, not mixed ad hoc.
3. Add active run state projection:
   - per conversation/session
   - current stream mode
   - abort state
   - degraded reason if present
4. Forum/panel post routes must:
   - durably write the post,
   - return accepted payload immediately,
   - enqueue orchestrator tick asynchronously,
   - expose follow-up status separately if needed.

## C. EC Core / orchestration services

Required modules:

- `interactive-followup-queue`
- `context-plan-cache`
- `accepted-mutation-receipt` builder
- `post-accept follow-up worker`

Required behavior:

1. Context assembly remains deterministic and bounded.
2. Cached context components are keyed by revision, not guessed from timestamps alone.
3. Follow-up work is isolated from acceptance writes.
4. Failures after acceptance emit warnings/telemetry without invalidating the accepted user action.

## D. Runtime / DOC11 adapter side

Required modules:

- `stream-state-store`
- `abort-state-store`
- `gateway-event-normalizer`
- `latency-watermark projector`

Required behavior:

1. Maintain active stream state per run.
2. Maintain abort state per run/session/participant scope.
3. Expose ordered stream delta sequence.
4. Detect gaps and project degraded stream state.
5. Preserve TTFT and total latency measurements.

## 16.6.7 Risks and mitigations

### Risk 1 — optimistic duplicates

**Mitigation:** require client IDs and deterministic reconciliation keys.

### Risk 2 — accepted-but-followup-failed confusion

**Mitigation:** separate post acceptance state from follow-up status; show warning badges rather than reclassifying the post as unsent.

### Risk 3 — rendering churn during streaming

**Mitigation:** batch deltas, avoid markdown reparse on every token, and virtualize long transcripts.

### Risk 4 — scroll jump and reading disruption

**Mitigation:** sticky-bottom only when already near bottom; preserve manual scroll position otherwise.

### Risk 5 — typing lag returns in the rebuild

**Mitigation:** preserve defer-while-typing and low-priority background hydration rules as spec obligations, not incidental implementation choices.

### Risk 6 — abort becomes decorative again

**Mitigation:** explicit DOC11 abort lifecycle and required UI read-model states.

## 16.6.8 Suggested implementation sequence

### Phase 1 — contract preservation

- amend DOC11, DOC10, Core, DOC6, and Q UI spec
- lock accepted/completed terminology
- lock multiline composer requirements

### Phase 2 — chat hot path

- rebuild deterministic context hot path
- implement session reuse, acceptance receipts, and stream state stores
- add true stream transport and delta reducer

### Phase 3 — forum/panel posting

- split accepted post write from async orchestrator tick
- implement optimistic local post rows
- clear composers on accepted response

### Phase 4 — transcript polish

- virtualization
- markdown-finalization pass
- bottom-stick behavior
- draft persistence and restore

### Phase 5 — abort and degraded truth

- wire real abort controls
- add stream/abort gap handling
- surface degraded state honestly

## 16.6.9 Acceptance criteria

This entry is addressed only when:

1. Chat replies can stream incrementally with truthful ordered delta updates.
2. Stop/abort is real, visible, and stateful rather than cosmetic.
3. Forum/panel post acceptance is fast and is not blocked on downstream orchestrator work.
4. A post that is durably accepted always clears the composer and appears immediately, even if follow-up work later warns or degrades.
5. Chat, forum, and panel composers are multiline autosizing textareas with newline support.
6. Active typing does not trigger heavy transcript or dashboard churn.
7. Long transcripts remain smooth under sustained usage because virtualization and bounded hydration are implemented.
8. Runtime metrics can distinguish:
   - submit-to-accepted
   - accepted-to-first-token
   - accepted-to-completed
9. Every visible interactive state is backed by a real read model or real accepted mutation receipt.

## 16.6.10 Recommended decision for now

Treat this as a **high-priority preserved amendment wave** for the rebuild.

This is not “UI polish later.” It is the architecture needed so the main working surfaces:

- feel immediate,
- remain truthful,
- do not regress under longer transcripts,
- and do not repeat the current panel/forum acceptance bug where a post can succeed while the UI behaves as though it failed.

# Entry 16.7 — Connector Management, Account Authentication, and Reverse MCP (R5.4 — new)

**Status:** PROPOSED
**Source:** Skills & Connectors Page Spec V1, DOC20 §6.29
**Target docs:** DOC11 (gateway runtime), DOC24 (capability registry), DOC20 (UI surfaces)
**Priority:** Day-one scope for MCP connector management and account connections; Phase 2 for Custom Tool Builder

---

## 16.7.1 Scope

This entry governs the backend lifecycle for:
1. MCP connector management — add, remove, configure, health-monitor MCP servers
2. Account authentication and credential management — OAuth, API key, bearer token flows with multi-account support
3. Reverse MCP server configuration — expose Elnor as an MCP server for external LLMs
4. Custom Tool Builder (Phase 2) — define REST API endpoints as Elnor tools without writing MCP servers

---

## 16.7.2 MCP Connector Lifecycle

### Registration

When a user adds an MCP server via DOC20 §6.29.5 Tab 2:
1. EC receives the registration request with URL and optional auth
2. EC probes the URL for MCP server discovery (standard MCP protocol)
3. On successful discovery: EC registers the server in the DOC24 capability registry with all discovered tools
4. EC starts periodic health checks (configurable interval, default: 5 minutes)
5. EC emits `connector.mcp.registered { connector_id, server_url, tool_count }`

### Health monitoring

```ts
export const ConnectorHealthCheckSchema = z.object({
  connector_id: z.string().uuid(),
  check_type: z.enum(["periodic", "on_demand", "on_failure"]),
  result: z.enum(["healthy", "degraded", "failed"]),
  degraded_tools: z.array(z.string().max(80)).default([]),
  latency_ms: z.number().int().optional(),
  error_message: z.string().max(500).optional(),
  checked_at: z.string().datetime(),
});
```

Health check policy:
- Periodic: every 5 minutes (configurable via `connectors.health_check_interval_s` in openclaw.json)
- On failure: retry 3 times with exponential backoff (10s, 30s, 90s)
- After 3 consecutive failures: auto-disable connector, emit `connector.mcp.auto_disabled`
- User can re-enable manually via Tab 2

### Removal

1. EC deregisters all tools from DOC24 capability registry
2. EC removes health check schedule
3. EC emits `connector.mcp.removed { connector_id }`
4. DOC24 execution-strategy cache entries referencing these tools are invalidated

---

## 16.7.3 Account Authentication & Credential Management

### Supported auth methods

| Method | Flow | Credential storage |
|---|---|---|
| OAuth 2.0 | Browser popup → authorization code → token exchange | Encrypted via macOS Keychain |
| API Key | User provides key → stored in credential vault | Encrypted via macOS Keychain |
| Bearer Token | User provides token → stored in credential vault | Encrypted via macOS Keychain |

### Credential lifecycle

```ts
export const CredentialRecordSchema = z.object({
  credential_id: z.string().uuid(),
  connector_id: z.string().uuid(),
  auth_method: z.enum(["oauth2", "api_key", "bearer"]),
  access_token_encrypted: z.string().optional(),
  refresh_token_encrypted: z.string().optional(),
  token_expiry: z.string().datetime().optional(),
  api_key_encrypted: z.string().optional(),
  authenticated_identity: z.string().max(120).optional(),
  scopes_granted: z.array(z.string().max(80)).default([]),
  created_at: z.string().datetime(),
  last_refreshed: z.string().datetime().optional(),
  status: z.enum(["valid", "expired", "revoked", "error"]),
});
```

Token refresh policy:
- OAuth tokens: auto-refresh when within 5 minutes of expiry
- On refresh failure: mark `auth_expired`, surface on Tab 2, emit `connector.auth.expired`
- Credentials are encrypted at rest using the macOS Keychain (via DOC11 gateway)
- Credentials are NEVER logged, transmitted to external models, or included in DOC72 entity graph

### Multi-account

Each service can have multiple credential records. Each connector card manages its own auth independently. Disconnecting one account does not affect others for the same service.

### Relationship to Entry 16.7 M365 integration

The M365 integration (`elnor@schallfirm.com` agentic identity, Cloudflare Tunnel, tiered email processing) is a specific instance of this general connector management framework. The M365 connector would use OAuth 2.0 auth, register its tools (email, calendar, files, Teams) via MCP or direct API integration, and be managed through Tab 2. The Cloudflare Tunnel configuration and tiered email processing rules are M365-specific configuration that lives under the connector's config panel.

---

## 16.7.4 Reverse MCP Server

### Runtime ownership

DOC11 owns the reverse MCP server runtime (start/stop endpoint, authenticate inbound connections, route to EC). DOC16 owns the configuration and exposure scope.

### Exposure scope enforcement

When enabled:
1. DOC11 starts an MCP server endpoint (localhost or Tailscale-exposed)
2. DOC11 authenticates inbound connections via bearer token
3. Inbound tool calls are routed to EC for evaluation:
   - EC checks capability filter (is this capability exposed?)
   - EC checks knowledge scope (is requested knowledge within allowed scope?)
   - EC checks action permissions (is execute allowed, or read-only?)
   - If all checks pass: EC executes and returns result
   - If any check fails: EC returns `EXPOSURE_SCOPE_DENIED`
4. Every invocation is logged to the audit trail

### Scope rules

- `experimental_private` capabilities are NEVER exposed, even if the user tries to add them to the filter
- `firm_shared` knowledge scope requires explicit user confirmation with a warning about privilege implications
- `execute` permission requires explicit user confirmation with a warning about remote action risks
- Audit log entries are written to EC's event store, queryable from DOC20 §6.29.7 Tab 4

### Audit trail

```ts
export const RemoteMCPInvocationLogSchema = z.object({
  invocation_id: z.string().uuid(),
  caller_identity: z.string().max(120),
  capability_accessed: z.string().max(160),
  action_type: z.enum(["query", "execute"]),
  knowledge_returned: z.boolean(),
  knowledge_scope_used: z.enum(["personal_only", "firm_shared", "both"]),
  timestamp: z.string().datetime(),
  response_size_tokens: z.number().int().optional(),
});
```

---

## 16.7.5 Custom Tool Builder (Phase 2)

```ts
export const CustomToolDefinitionSchema = z.object({
  tool_id: z.string().uuid(),
  tool_name: z.string().max(80),
  semantic_description: z.string().max(500),
  endpoint: z.object({
    url: z.string().url(),
    method: z.enum(["GET", "POST", "PUT", "DELETE"]),
    auth: z.object({
      type: z.enum(["api_key", "bearer", "basic", "none"]),
      credentials_ref: z.string().uuid().optional(),
    }),
    headers: z.record(z.string(), z.string()).default({}),
  }),
  input_schema: z.record(z.string(), z.unknown()),
  output_parsing: z.object({
    extract_path: z.string().max(120),
    result_description: z.string().max(240),
  }),
  health_check: z.object({
    probe_endpoint: z.string().url().optional(),
    interval_seconds: z.number().int().default(300),
  }).optional(),
  created_at: z.string().datetime(),
  schema_version: z.literal(1),
});
```

EC registers the custom tool as an action in DOC24 capability registry. DOC24 routes to it like any other action. Tool appears on Tab 1 as `api_integration` type. This is the visual equivalent of creating a simple MCP tool without standing up a separate MCP server.

---

## 16.7.6 Cross-doc obligations

| Target | Obligation |
|---|---|
| DOC11 | Tool catalog route (`GET /api/gateway/tool-catalog`), skill/plugin management routes (install/update/uninstall/enable/disable), ClawHub search proxy, reverse MCP server runtime (start/stop/auth/route), credential storage via macOS Keychain |
| DOC24 | MCP server registration/deregistration in capability registry, custom tool registration, cache invalidation on connector add/remove |
| DOC3 | Tab 5 surface integration (existing routes), SKILL.md import trigger (§25.6), pending abilities query |
| DOC72 | Procedure graph queries for Tab 1, provenance data (trace nodes, session metadata), confidence history, usage timeline (ProcedureExecutionOutcomeEvent), linked entity traversal |
| DOC20 | Page registration (§6.18.2), Nav tab entry, badge system for update counts |

---

## 16.7.7 Migration path

This entry will eventually migrate to its permanent owner documents:
- MCP connector lifecycle → DOC24 (capability registry owner)
- Credential management → DOC11 (gateway owner)
- Reverse MCP server configuration → DOC11 (runtime) + DOC24 (scope enforcement)
- Custom Tool Builder → DOC24 (capability registration)
- M365-specific integration → remains as DOC16 entry or DOC11 subsection


# Future entries

Future deferred additions can be added below using the same structure:

- 16.8 — _reserved_
- 16.9 — _reserved_
- 16.10 — _reserved_


---

---

## Part II — Targeted CIL / Advisor / DocIndex / Review Additions (latest operative content from the R4 chain)

## How to Use This Document

Each item specifies: which spec to modify, what to add, and why. Items are grouped by target spec. When working on a spec revision, search this document for that spec's name to find all pending additions.

---

## 1. ADDITIONS TO DOC10 (Unified Engagement Orchestration)

### 1.1 Dispatcher + Sub-Advisor Agent Architecture

**What:** Define a lightweight dispatcher agent pattern for +ask/+advise routing. The dispatcher receives user requests from +ask and +advise buttons across all surfaces, classifies the intent, and routes to the appropriate sub-advisor agent.

**Design:**
- The dispatcher is an OpenClaw agent with a simple SOUL.md: "You receive user questions and route them to the right advisor. Classify the request and spawn the appropriate agent."
- The dispatcher maintains a routing table (stored as a JSON config or in its SOUL.md):
  - CIL/learning/memory questions → CIL Advisor agent
  - Cost questions → Cost Advisor agent
  - Spec/architecture questions → Spec Advisor agent  
  - Task/workflow questions → Task Advisor agent
  - Red-team/review questions → Review Advisor agent
- The dispatcher is a low-cost model (Flash-tier). Sub-advisors can be low-cost too — they're reading structured data and explaining it, not doing creative analysis.
- The dispatcher should be spawned on +ask/+advise button press, classify quickly, and hand off. It doesn't need to persist — it's a one-shot routing decision.

**Why:** Elnor Prime shouldn't be interrupted with system questions that require injecting unrelated context (CIL state, cost data, spec documents) into whatever it's currently working on. Dedicated advisors keep context clean and costs low.

**Integration:** All +ask and +advise buttons across the Q Dashboard route to the dispatcher. The dispatcher is a DOC10 systems agent with a registered role type.

### 1.2 Agent Document Dependency Declarations

**What:** Allow agents to declare document dependencies in their definitions. On spawn, EC resolves these via DocIndex, checks token budget, and loads full or skeleton as appropriate.

**Design:**
- Agent definition (SOUL.md or agent config) includes a `document_dependencies` section:
  ```
  Documents needed:
  - "DOC15 spec" (always full if possible)
  - "CIL knowledge nodes" (skeleton OK)
  - "Current workspace standing orders" (always full)
  ```
- On spawn, EC resolves each alias via DocIndex, estimates total token cost, and loads within the agent's context budget.
- If total exceeds budget, apply DocIndex compression (skeleton + chunk_map) starting with lowest-priority documents.
- Agent can request specific chunks mid-conversation via DocIndex tool.

**Why:** Currently agents get whatever context you manually configure. This makes agents self-describing — they declare what they need and the system provides it efficiently. Users don't have to remember to upload documents or configure context for each agent spawn.

**Integration:** Requires DocIndex alias resolution at agent spawn time. EC's context assembly reads agent document dependencies and resolves them before the first turn.

### 1.3 +Ask/+Advise Button Routing

**What:** Define that all +ask and +advise buttons across Q Dashboard surfaces route to the dispatcher agent (§1.1 above), not to Elnor Prime. Every request includes a **CILQueryContextPayload** (defined in DOC15 §2.1A) when the button is on a CIL surface — this is the "ticket" that tells the advisor exactly what the user is asking about.

**Surfaces affected:**
- Panel setup: +advise for review configuration suggestions
- Task setup: +advise for task configuration suggestions  
- Knowledge Node Browser: "Why?" and "Explain" buttons → payload includes node_id, signal_ids
- Suggestion cards: "Why?" button → payload includes ResolvedOperation ID, node_ids
- Nightly "What Changed?" cards: "Tell me more" link → payload includes changed node_ids, before/after confidence
- Context Inspector: "Explain this plan" link → payload includes ContextPlan ID, injected/dropped node_ids
- Inline context pills: click → payload includes dispatch_id, injected node_ids
- CIL Health tab: any explanatory buttons → payload includes metric context
- Cost dashboard: cost-related questions
- General chat: +ask when the question is about system behavior (not the current work task) → payload is "general_ask" with no specific IDs

**Dispatcher payload handling:** The dispatcher receives the CILQueryContextPayload, uses `source_surface` to help classify the routing target, and passes the full payload through to the advisor agent. The dispatcher never strips or transforms the payload — the advisor needs all the IDs and snapshot data to go directly to the right records.

**Why:** Centralizes advisory routing through a single dispatcher rather than having each surface implement its own advisory logic. The payload system means advisors get deep-linked to the exact record the user is asking about — no hunting, no "what are you asking about?" interrogation.

### 1.4 Retrieval Receipt / Provider Truth for Advisory Surfaces

**What:** Any +ask/+advise / Why-path that depends on retrieval-backed context should carry or be able to resolve a **retrieval receipt** showing at minimum:

- `search_lane` (`exact_live`, `semantic_corpus`, `canonical_memory`, `native_runtime`)
- `provider_kind`
- `corpus_id` (if applicable)
- `route_reason`
- `freshness_state`
- `degraded_reason` (if any)

**Why:** Without this, CIL explanations collapse into “search found this” and the user cannot tell whether a recommendation came from live lookup, LlamaIndex sidecar retrieval, canonical memory retrieval, or OpenClaw native/runtime-local search.

**Integration:** DOC10 owns the dispatcher and advisory path; DOC18/DOC3/route traces supply the receipt fields; DOC15 consumes them for explanation.

---

## 2. ADDITIONS TO DOC15 (Cognitive Infrastructure Layer) — for R5

### 2.1 CIL Advisor Agent Integration (Brief Section)

**What:** A brief section (not a full agent architecture — that's DOC10's job) noting:
- CIL surfaces expose +ask/+advise entry points that route via DOC10 dispatch to a CIL-knowledgeable agent
- The CIL Advisor agent requires read access to `ELNOR_MEMORY/system/cil/` and should be spawned with CIL system context per its SOUL.md
- CIL state files must be DocIndex-indexed with standard aliases so the advisor (and any agent) can resolve them by name
- knowledge_nodes.jsonl includes `display_summary` fields (plain English, generated at promotion time) so any agent can read and explain nodes without complex data transformation

### 2.1A CIL Query Context Payload (Advisory Deep-Link System)

**What:** Every CIL surface element (+ask/+advise buttons on suggestion cards, Knowledge Node Browser rows, nightly cards, inline pills, Context Inspector entries) must package a **query context payload** when the user presses +ask or +advise. This payload is the "help desk ticket" — it tells the advisor exactly what the user is asking about so it can go directly to the right records.

**Why:** Without this, the advisor receives "user has a question" with no context. It would have to ask "what are you asking about?" or search broadly. With the payload, the advisor opens the right files, looks up the right records by ID, and answers immediately. This is the difference between a useful 2-second response and a frustrating 30-second interrogation.

**Schema:**
```typescript
export const CILQueryContextPayloadSchema = z.object({
  // Where the user clicked
  source_surface: z.enum([
    "suggestion_card",
    "knowledge_node_browser",
    "nightly_card",
    "context_inspector",
    "inline_pill",
    "cil_health_tab",
    "general_ask"        // +ask from chat, no specific surface
  ]),

  // Unique ID of the surface element (resolved_operation_id, node_id, 
  // nightly_card_entry_id, etc.)
  source_id: z.string().optional(),

  // Direct record references — the advisor uses these to look up 
  // specific entries in CIL state files
  referenced_node_ids: z.array(z.string()).default([]),
  referenced_signal_ids: z.array(z.string()).default([]),
  referenced_dispatch_id: z.string().optional(),
  referenced_profile_id: z.string().optional(),

  // Snapshot of key data at click time (so advisor has immediate 
  // context even before reading files)
  snapshot: z.object({
    confidence: z.number().optional(),
    confidence_tier: z.string().optional(),
    evidence_grade: z.string().optional(),
    display_summary: z.string().optional(),
  }).optional(),

  // The user's actual question (from text input or implied by button)
  user_question: z.string().optional(),

  // Timestamp
  asked_at: z.string().datetime(),
});
```

**How it flows:**
1. User sees suggestion card → clicks "Why?"
2. Q Dashboard packages CILQueryContextPayload with source_surface="suggestion_card", source_id=the ResolvedOperation ID, referenced_node_ids=the nodes that backed the suggestion, snapshot of confidence/tier/grade
3. Payload sent to dispatcher agent via DOC10 +ask routing
4. Dispatcher sees CIL-related content → routes to CIL Advisor with payload attached
5. CIL Advisor reads payload → opens knowledge_nodes.jsonl → looks up nodes by ID → reads their display_summaries, evidence_refs, confidence history → explains in plain English
6. If user asks follow-up ("what sessions caused this?") → advisor already has node_ids in context → looks up signal spool for signals referencing those nodes → traces to dispatch checkpoints → explains
7. If user asks architectural question ("how does promotion work?") → advisor resolves "DOC15" via DocIndex → loads §4.5 chunk → explains using spec text

**Per-surface payload examples:**

| Surface | source_id | Key references | Typical user question |
|---|---|---|---|
| Suggestion card "Why?" | ResolvedOperation ID | node_ids, dispatch_id, profile_id | "Why is this being recommended?" |
| Knowledge Node "Explain" | node_id | signal_ids from evidence_refs | "What is this node and why does it exist?" |
| Nightly card "Tell me more" | nightly_entry_id | node_ids that changed, before/after confidence | "What changed and why?" |
| Context Inspector "Why this plan?" | ContextPlan ID | node_ids injected, node_ids dropped, budget info | "Why were these nodes injected and those dropped?" |
| Inline pill click | dispatch_id | node_ids injected for this dispatch | "What learned knowledge was used here?" |
| CIL Health tab | metric_id | aggregate stats | "Why is signal volume dropping?" |

**DocIndex integration for deep reference resolution:**
When the advisor traces a reference beyond CIL state files — e.g., a signal came from a DOC8 friction event, or a node's promotion logic is defined in DOC15 §4.5, or a dispatch checkpoint references a DOC12 room — the advisor resolves those references via DocIndex. DocIndex returns the relevant spec section or file chunk. The advisor can then explain the full chain: "This node was promoted because 8 signals from your last 3 red-team reviews exceeded the confidence threshold defined in §4.5 of the learning spec. The signals came from findings you starred and a satisfied review outcome."

**What the Q Dashboard must do:**
Every CIL-visible UI component must implement a `buildQueryContext()` function that assembles the payload from the component's props/state. This is a frontend responsibility, not an EC or CIL responsibility. The payload is assembled client-side and sent with the +ask/+advise request.

**What the dispatcher must do (DOC10):**
Accept the CILQueryContextPayload as part of the routing request. Pass it through to the advisor agent as the first message or as context. Do not strip or transform it.

**What the advisor must do:**
Read the payload first. Use referenced IDs to look up specific records before attempting any broad search. If IDs are present, go directly to those records. If no IDs (general_ask), fall back to asking the user for clarification or searching CIL state broadly.

### 2.1B Query Context Payload Extensions for Topology-Backed Explanations

**What:** Extend the advisory payload with optional fields for topology-backed explanation and retrieval truth.

**Suggested additions:**
```typescript
export const CILQueryContextPayloadSchema = z.object({
  // existing fields...
  referenced_topology_node_ids: z.array(z.string()).default([]),
  referenced_topology_edge_ids: z.array(z.string()).default([]),
  retrieval_receipt_ref: z.string().optional(),
  support_pack_id: z.string().optional(),
});
```

**Why:** This lets the advisor answer questions like:
- “Why did you suggest these related documents?”
- “What replaced the older brief?”
- “Did this come from LlamaIndex or memory search?”
without broad searching or guesswork.

### 2.2 DocIndex Integration Points

**What:** Two specific integration points between CIL and DocIndex:

**Point 1: Document access patterns as CIL behavioral signals.**
- When DocIndex resolves a document access (triggers #1, #4, #6 from the DocIndex trigger table), EC emits a passive behavioral signal to the CIL signal spool: `signal_type: "document_accessed"`, with payload including `doc_id`, `alias_used`, `context_facts` (what task/workspace was active).
- The nightly job aggregates document co-access patterns and can promote them to `context_packaging_hint` knowledge nodes: "For securities complaint reviews, user typically accesses [complaint], [Section 11 standards], and [prior case file]."
- These nodes surface via suggestion cards: "You typically reference these documents for this type of review. Include them?"

**Point 2: CIL state files registered in DocIndex.**
- On CIL initialization, register the following files in DocIndex with aliases:
  - `ELNOR_MEMORY/system/cil/knowledge_nodes.jsonl` → aliases: ["CIL knowledge nodes", "knowledge nodes", "learned patterns"]
  - `ELNOR_MEMORY/system/cil/signal_spool.jsonl` → aliases: ["CIL signals", "learning signals"]
  - `ELNOR_MEMORY/system/cil/config.json` → aliases: ["CIL config", "learning config"]
  - `ELNOR_MEMORY/system/cil/profiles/` → aliases: ["CIL profiles", "learning profiles"]
  - `ELNOR_MEMORY/system/cil/nightly/` → aliases: ["CIL nightly logs", "nightly learning logs"]
- These registrations allow any agent to resolve "pull up the knowledge nodes" via standard DocIndex alias resolution.

### 2.3 Workspace Document Sets as CIL-Learned Defaults

**What:** CIL can learn and suggest default document sets per workspace based on observed access patterns.

**Design:**
- When the user consistently accesses the same documents within a workspace context, CIL promotes a `workspace_default` knowledge node with the document set.
- On workspace activation, the suggestion card can include: "Load your standard documents for this workspace?" with the learned set.
- User can accept (all documents loaded via DocIndex), edit (add/remove), or dismiss.
- The accepted set becomes a workspace pinned set — always available by summary, loaded in full when budget allows.

### 2.3A Graph-Aware Document Recommendations and Support Packs

**What:** Allow CIL to consume topology-backed signals when forming document recommendations.

**Design:**
- `workspace_default` remains valid, but CIL may also learn a **support-pack** pattern such as “for this motion type in this matter stage, these documents frequently travel together.”
- Suggestions remain bounded and reference-first. CIL should recommend the pack by summary + refs, not dump every document inline.
- Reason codes should be stored for explanation, e.g. `same_issue`, `same_matter`, `support_pack_member`, `supersedes_target`, `active_review_target_neighbor`.

### 2.3B Relation-Aware Advisor Explanations

**What:** Advisors should be able to explain when a suggestion is relation-backed rather than only similarity-backed.

**Examples:**
- “These documents were suggested because they were repeatedly co-used in similar reviews.”
- “This earlier memory was hidden because it was superseded by a later correction.”
- “This note was surfaced because it shares the same issue cluster as the active review target.”

### 2.3C Memory Relationship Index Consumption Boundary

**What:** CIL may consume the DOC1 relationship index for **bounded one-hop** relation-aware explanation and ranking, but CIL does not become the owner of the relationship graph.

**Rule:**
- one-hop expansion is acceptable;
- unbounded graph walks are not;
- authority nodes remain protected;
- contradiction/supersession explanations must preserve provenance.

### 2.4 Integration Contract Additions (for CIL ↔ DocIndex ↔ DOC10)

| # | Source | Target | Capture Point | Priority |
|---|---|---|---|---|
| 31 | EC Core (DocIndex) | DOC15 (CIL) | DocIndex access events → CIL passive behavioral signal for document usage patterns | Important |
| 32 | DOC15 (CIL) | EC Core (DocIndex) | CIL state files registered in DocIndex with aliases on CIL init | Immediate |
| 33 | DOC10 | DOC15 (CIL) | +ask/+advise routing for CIL surfaces → CIL advisor agent via dispatcher | Immediate |
| 34 | DOC10 | EC Core (DocIndex) | Agent document dependency declarations → DocIndex auto-resolution at spawn | Important |
| 35 | DOC15 (CIL) | DOC10 | CIL suggestion cards include document recommendations → DocIndex resolution for loading | Important |
| 41 | DOC18 / DOC3 / route layer | DOC15 (CIL) | retrieval receipt / provider truth for semantic-corpus-backed suggestions and explanations | Important |
| 42 | DOC1 | DOC15 (CIL) | bounded memory-relationship traversal seam for one-hop explanation/ranking | Important |
| 43 | ELNOR Core / DocIndex | DOC15 (CIL) | broader topology read-model availability by stable IDs / aliases / bounded neighbor query | Future |
| 44 | ELNOR Core / DocIndex + DOC1 | DOC15 (CIL) | contradiction / supersession edge exposure with strength, freshness, and provenance | Future |
| 45 | DOC7 + Core / DocIndex | DOC15 (CIL) | graph-aware document priority hints and support-pack grouping handoff | Important |
| 46 | ELNOR Core / DocIndex | DOC15 (CIL) | topology maintenance jobs and health/degraded export for honest explanation surfaces | Future |

---

## 3. ADDITIONS TO DOC12 (Inter-Agent Communication and Multi-Agent Rooms)

### 3.1 Active Review Target Auto-Pinning

**What:** In multi-round review rooms (red-team, document review, spec review), the current review target and current-round submissions must be auto-pinned as Task-level pinned references. Pinned references are never compressed by CRS Level 2.

**Design:**
- When a room is created with a review target, that document is auto-pinned.
- When a reviewer submits a revised document in round N, that submission becomes the new pinned target for round N+1.
- The previous round's submission is unpinned (can compress if needed, but remains accessible via DocIndex chunk_map).
- The moderator manages pin transitions between rounds.
- Pin state is stored in the room's runtime state, not in DocIndex itself.

**Why:** In a 20-turn red-team room reviewing a 2,000-line spec, context pressure will eventually trigger compression. If the spec being reviewed gets compressed to a skeleton, reviewers can't do deep analysis. Auto-pinning ensures the active target is always full-text.

**Rule:** "Active review target documents and current-round submissions are auto-pinned. Pinned documents are excluded from CRS Level 2 compression. Previous rounds' documents may compress but remain chunk-accessible."

### 3.2 Room Document Context Management

**What:** Rooms should declare document context requirements at creation time, similar to agent document dependencies (DOC10 §1.2 above).

**Design:**
- Room configuration includes a `required_documents` list (DocIndex aliases or doc_ids).
- Required documents are always available to room participants (full or skeleton depending on budget).
- The moderator can add/remove documents between rounds.
- When context pressure forces compression, required documents are compressed last (after conversation history, after non-required documents).

---

## 4. ADDITIONS TO DOC14 (CANDOR / Red-Team Review)

### 4.1 Red-Team Document Pinning Rules

**What:** Define specific pinning rules for red-team review workflows to prevent compression of active review materials.

**Rules:**
- The spec/document being red-teamed is ALWAYS pinned for all rounds. Never compressed.
- The current red-team prompt is pinned for the current round.
- Red-team responses from previous rounds: unpinned after the user has reviewed them. Can compress. But the CURRENT round's responses are pinned until reviewed.
- Companion documents (Addendum A, Build Manifest, Integration Contract) are loaded by summary unless the reviewer specifically needs them, in which case they're pinned for that round.
- Finding ledger: always available by summary. Full entries loaded on demand via DocIndex chunk_map.

**Why:** A red-team review of a 1,839-line spec with 5 model responses, each 10-30 pages, will absolutely hit context pressure. Without pinning rules, the system might compress the very spec being reviewed, making the review worthless.

### 4.2 Red-Team Advisor Agent

**What:** Note that the dispatcher (DOC10 §1.1) should include a Review Advisor sub-agent for red-team-specific questions.

**Capabilities:**
- "What findings have been most impactful across rounds?" → reads finding ledger
- "Which model found the most novel issues?" → reads review outcomes by model
- "What's the current state of the spec's P0 issues?" → reads spec + finding status
- "Compare the models' recommendations on signal weights" → reads multiple red-team responses

**Document dependencies:** Current review target (pinned), finding ledger, review outcomes, red-team prompt, model responses for current round.

---

## 5. ADDITIONS TO ELNOR CORE CANONICAL SPEC

### 5.1 DocIndex Proactive Document Surfacing

**What:** Extend DocIndex beyond reactive resolution to support proactive surfacing of relevant documents.

**Mechanism:**
- When CIL has `context_packaging_hint` knowledge nodes that reference DocIndex entries, those nodes trigger document surfacing during context assembly.
- Flow: ContextPlanner queries CIL for matching nodes → nodes include doc_ids → ContextPlanner requests DocIndex to surface those documents → Budget Manager allocates space → documents appear in agent context.
- The user doesn't trigger this — it happens automatically based on learned patterns.

### 5.2 DocIndex Agent Tool Access

**What:** DocIndex should be available as a tool to all agents, not just the EC context assembly pipeline.

**Mechanism:**
- Agents can call `docindex.resolve(alias)` to find a document by name.
- Agents can call `docindex.get_chunk(doc_id, chunk_key)` to retrieve a specific section.
- Agents can call `docindex.get_skeleton(doc_id)` to get the lossless skeleton.
- These are lightweight JSON lookups, zero LLM cost, available on the hot path.

**Why:** When an agent encounters a reference it can't resolve from current context (e.g., "as defined in DOC8 §4.6"), it can query DocIndex to pull in the relevant section without requiring a full context reload.

### 5.3 Compression Override Rules

**What:** Define categories of documents that should never be compressed or should be compressed last.

**Rules:**
- **Never compress:** Authority Memory items (standing orders, corrections, user profile). These are small and critical.
- **Never compress:** Active review target in any review room (auto-pinned per DOC12 §3.1).
- **Never compress:** Task pinned references (already in spec — trigger #7).
- **Compress last:** Required room documents (per DOC12 §3.2).
- **Compress last:** Current workspace's standing document set (per CIL workspace defaults).
- **Normal compression:** Everything else, per CRS Level 2 ladder.

### 5.4 Topology Snapshot Registration and Alias Exposure

**What:** If/when ELNOR Core / DocIndex exposes a broader topology read-model, register those snapshots and stable aliases so advisors can resolve them without bespoke file-path knowledge.

**Example aliases:**
- “knowledge topology”
- “document relations”
- “matter graph”
- “issue clusters”

### 5.5 Topology Health and Freshness Export

**What:** Any topology-backed explanation path should have access to health/freshness truth such as `healthy`, `stale`, `degraded`, and `building`.

**Why:** Advisors and Q surfaces should be able to say “topology data is stale” instead of pretending the relation view is current.

---

## 6. ADDITIONS TO DOC7 (Context Buckets & Files)

### 6.1 DocIndex-Aware Budget Allocation

**What:** The Budget Manager should use DocIndex metadata (estimated_tokens, last_accessed, access_count) to make smarter compression decisions.

**Design:**
- When CRS Level 2 fires and multiple documents need compression, prioritize compressing:
  1. Documents with lowest recent access count (least recently/frequently used)
  2. Documents not referenced by any active CIL knowledge node
  3. Documents with the highest token cost (biggest savings)
  4. Documents not pinned or required by the current task/room
- This is a priority ordering, not a hard rule. The Budget Manager works down the list until sufficient headroom is recovered.

### 6.2 CIL-Driven Document Budget Hints

**What:** CIL can provide hints to the Budget Manager about which documents are likely to be needed.

**Mechanism:**
- ContextPlanner includes a `document_priority_hints` field in the ContextPlan.
- Each hint is: `{ doc_id, priority: "critical" | "useful" | "background", reason: string }`.
- The Budget Manager uses these hints when deciding compression order.
- "Critical" documents are never compressed (equivalent to pinning).
- "Useful" documents are compressed last.
- "Background" documents compress normally.

### 6.3 Graph-Aware Document Priority Hints and Support Packs

**What:** Allow `document_priority_hints` to carry topology-backed reason codes and optional support-pack grouping metadata.

**Examples:**
- `same_issue`
- `same_matter`
- `support_pack_member`
- `supersedes_target`
- `active_review_target_neighbor`

**Why:** This lets DOC7 materialization stay bounded while still honoring the richer relation-aware recommendation logic coming from CIL/topology.

---

## 7. CIL ADVISOR AGENT DEFINITION (for ELNOR Agent Registry)

### 7.1 Agent: CIL Advisor

**Role:** `cil_advisor`
**Model:** Low-cost (Gemini Flash, Sonnet, or Ollama local)
**Spawn trigger:** Dispatcher routes CIL-related +ask/+advise requests
**Persistence:** One-shot (spawns, answers, terminates). No persistent state beyond what's in CIL files.

**SOUL.md outline:**
```
You are Elnor's learning and memory advisor. Your job is to explain 
what the system has learned, why it makes recommendations, and how 
confident it is in those recommendations.

FIRST: Read the CILQueryContextPayload attached to this request. 
It contains the exact IDs of what the user is asking about. Use 
those IDs to look up specific records in the CIL state files. 
Do NOT search broadly when you have specific IDs — go directly 
to the referenced records.

You have access to:
- ELNOR_MEMORY/system/cil/ (knowledge nodes, signals, profiles, config)
- The DOC15 spec summary (via DocIndex)
- The current workspace's standing orders
- All ELNOR spec documents (via DocIndex — resolve by alias, 
  load relevant chunks as needed)

When explaining learned patterns:
- Always use plain English, not technical jargon
- Always state the confidence level and what it means
- Always distinguish between "observed pattern" and "tested/proven"
- Never oversell what the system has learned
- If confidence is low, say so clearly: "This is an early guess based on 
  limited data"
- When tracing evidence, follow the chain: node → signals → dispatches 
  → sessions. Explain what happened in those sessions that led to this 
  recommendation.

When the user asks about system architecture or spec details:
- Resolve the relevant spec via DocIndex (e.g., "DOC15", "DOC8")
- Load the relevant section via chunk_map
- Explain using the spec text as your source

When the user asks to change something:
- You can help retire knowledge nodes
- You can explain how to adjust settings
- You can suggest what feedback would help the system learn faster
- You cannot directly modify CIL state — guide the user to the 
  Knowledge Node Browser or settings

When you don't know something:
- Say so. Don't guess about system internals.
- Suggest the user check the Context Inspector or Knowledge Node Browser.
```

**Document dependencies:** 
- `ELNOR_MEMORY/system/cil/knowledge_nodes.jsonl` (always, skeleton OK)
- `ELNOR_MEMORY/system/cil/config.json` (always, full — it's small)
- Current workspace standing orders (always, full)
- DOC15 spec summary (on demand via DocIndex if user asks architectural questions)

### 7.2 Agent: Dispatcher

**Role:** `advisor_dispatcher`
**Model:** Lowest-cost available (Flash-tier or local)
**Spawn trigger:** Any +ask or +advise button press across Q Dashboard
**Persistence:** One-shot. Classify intent → spawn appropriate advisor → terminate.

**SOUL.md outline:**
```
You are a routing agent. When you receive a user question, classify it 
and route to the appropriate advisor:

- Questions about learning, memory, knowledge nodes, recommendations, 
  confidence, "why did the system suggest X" → route to: cil_advisor
- Questions about cost, budget, spending, token usage → route to: cost_advisor
- Questions about specs, architecture, how the system works technically 
  → route to: spec_advisor
- Questions about task setup, workflow configuration → route to: task_advisor
- Questions about red-team reviews, findings, review quality 
  → route to: review_advisor

If unclear, ask one clarifying question. Do not attempt to answer 
the question yourself.
```

### 7.3 Agent: Review Advisor

**Role:** `review_advisor`
**Model:** Low-cost
**Spawn trigger:** Dispatcher routes review-related questions

**Document dependencies:**
- Current review target (via DocIndex, pinned — full text)
- Finding ledger (via DocIndex, skeleton + chunks)
- Review outcomes (via DocIndex)
- DOC14 summary (via DocIndex, on demand)

### 7.4 Agent: Spec Advisor

**Role:** `spec_advisor`  
**Model:** Mid-tier (needs comprehension ability for complex spec questions)
**Spawn trigger:** Dispatcher routes spec/architecture questions

**Document dependencies:**
- All ELNOR spec documents registered in DocIndex (loaded by skeleton, chunks on demand)
- This agent's power comes from DocIndex — it doesn't need to hold all 15+ specs in context. It resolves the relevant spec via alias, loads the skeleton, identifies the relevant section, pulls the chunk, and explains.

---

## 8. CROSS-CUTTING NOTES

### 8.1 DocIndex Should Index Spec Documents

All ELNOR spec documents (DOC1-DOC16, ELNOR Core, Build Manifest, Addendum A, Integration Contracts) should be registered in DocIndex with aliases. This enables any agent (including the Spec Advisor) to resolve "DOC15" or "the CIL spec" or "the red-team spec" to a file path, get a token estimate, and load full or skeleton as appropriate.

Aliases should include: formal name ("DOC15"), short name ("CIL spec"), topic name ("learning spec", "memory spec"), and any informal names Will uses.

### 8.2 Session Context vs. Persistent Context

Important distinction for all advisor agents: they don't maintain persistent memory across spawns. Each spawn is fresh — they read CIL state files, answer the question, and terminate. If the user has a multi-turn conversation with an advisor ("Why did confidence drop?" → "Which sessions caused that?" → "Can you show me the signals?"), the dispatcher should keep the same advisor instance alive for the duration of that conversation thread, not re-spawn on each turn.

DOC10 should define: "Advisor agents persist for the duration of a single advisory conversation thread. A new +ask press starts a new thread. Follow-up questions within the same thread reuse the running instance."

### 8.3 Rebuild Note

All of the above assumes a clean-room rebuild. The agent definitions, DocIndex registrations, and routing configurations are all setup-time configuration, not complex programming. In the existing codebase, some of these would require extraction work. In a rebuild, they're just part of the initial configuration.

### 8.4 Graph / Topology Is a Derived Read-Model

Do **not** let any advisor or CIL consumer treat the graph/topology layer as canonical truth. It is a derived read-model built from existing authoritative artifacts.

### 8.5 Retrieval Truth Must Stay Visible

If a recommendation or explanation depends on:
- LlamaIndex sidecar retrieval,
- canonical memory search,
- exact/live lookup, or
- topology neighbor expansion,

that path should remain visible through receipts/reason codes rather than being flattened into generic “search found this.”

---

*End of DOC16 additions from DOC15 R4 Red-Team Review Session.*
*These items should be incorporated into their respective spec documents during the next revision cycle.*

---

## Part III — Unified Patch Brief: Memory, Context, Code Awareness, Environment Registry, and Delegation

## 0) What this patch does

This patch brief consolidates the following idea families into one unified package:

1. **Conversation/session memory retrieval**
2. **Codebase awareness and repo navigation**
3. **Unified Environment + Source Registry**
4. **DOC5 evolution into Sources / Access / Permissions control**
5. **Hybrid semantic retrieval for canonical memory and session history**
6. **DocIndex auto-registration and session/document linkage**
7. **Thread synthesis and entity continuity**
8. **Memory feedback / self-learning improvements**
9. **Authority/memory injection governance**
10. **Subagent / helper / handoff behavior**
11. **Room charter / role card / task card split**
12. **Branch/task context guardrails**

The intent is **not** to create a parallel memory or graph system. The intent is to make the existing ELNOR system far better at:
- remembering what matters,
- finding the right past work,
- understanding the codebase,
- knowing what apps/roots/corpora/specs exist,
- using helpers intelligently,
- and staying on-task across long-running work.

---

## 1) Governing principles

### 1.1 One truth system, not two
These additions must extend the current ELNOR memory/context architecture. They must not create a second uncontrolled memory substrate.

### 1.2 Stable memory and retrievable history are different
The system must clearly distinguish:
- durable authority / standing guidance / corrections,
- learned heuristic memory,
- retrievable session history,
- and transient one-turn or one-session instructions.

### 1.3 Retrieval truth and topology truth are different
The system must distinguish:
- **how something was found** (provider, lane, corpus, degraded state),
- from **how it relates to other things** (same issue, same matter, supersedes, contradicts, support-pack membership).

### 1.4 Environment truth, runtime truth, and learned overlays are different
The system must distinguish:
- configured environment/source truth,
- runtime availability/health truth,
- and learned overlays such as file-pattern habits or preferred save roots.

### 1.5 Boundedness remains non-negotiable
More capable retrieval and helper use must not mean uncontrolled prompt stuffing or hidden context sprawl.

### 1.6 Helper delegation should improve answers, not fragment them
The default pattern should be:
- spawn helper(s),
- gather results,
- synthesize,
- respond once,
- keep helper traces available in a collapsed drawer.

### 1.7 Branch-local context should dominate generic recent context
If branch/task state exists, it must outrank unrelated recent memory during context assembly.

### 1.8 Permissions are operator truth
Elnor may request access changes, but may not silently grant itself new roots, new write access, new app launch rights, or cross-account privileges.

---

## 2) Final short instruction block for Elnor

This is the compact always-on instruction block.

> Use helper agents and handoffs whenever delegation is likely to produce a **faster, better, or more complete answer**, especially for parallel research, web/document/code search, verification, compare-and-synthesize work, or context-heavy subtasks. Prefer native OpenClaw helper/subagent mechanisms when available.  
>  
> By default, keep helper work out of the main answer stream: spawn helpers, wait for results, synthesize once, and return one final answer in the same user-visible turn. Helper activity may be logged to the research drawer automatically.  
>  
> Use a full visible research room only when the user asks to watch or collaborate, when the task is long-running, or when multi-agent discussion itself is valuable.  
>  
> Give helpers filtered task briefs, only the context they need, allowed tools, and a clear output format. Do not delegate trivial tasks, allow unrestricted recursive spawning, or let helper outputs directly create durable memory.

---

## 3) Runtime policy version (caps, budgets, receipts)

The short instruction above is not enough on its own. The runtime/orchestration layer should enforce the following default policy.

### 3.1 Delegation modes

```ts
export const DelegationModeSchema = z.enum([
  "silent_native_consult",
  "visible_research_room",
  "full_handoff_takeover",
]);
```

### 3.2 Default trigger guidance

Elnor should be encouraged to delegate when at least two are true:
- task has multiple separable subtasks
- work is read-heavy or search-heavy
- work is tool-specialized
- work is parallelizable
- work is likely to create context pressure if kept inline
- compare-and-synthesize or verification would improve quality

Elnor should usually avoid delegation when:
- task is trivial
- task is mostly conversational nuance
- helper would need nearly the entire parent context anyway
- mutation risk is high and direct control is better
- expected gain is lower than orchestration overhead

### 3.3 Helper count policy

```ts
export const DelegationLimitPolicySchema = z.object({
  default_helper_cap: z.number().int().min(1).max(8).default(4),
  soft_cap: z.number().int().min(1).max(8).default(4),
  hard_cap: z.number().int().min(1).max(16).default(8),
  allow_recursive_spawning: z.boolean().default(false),
});
```

### 3.4 Budget envelope

```ts
export const DelegationBudgetEnvelopeSchema = z.object({
  budget_id: z.string().uuid(),
  task_budget_usd_soft: z.number().nonnegative(),
  task_budget_usd_hard: z.number().nonnegative(),
  parent_reserve_usd: z.number().nonnegative(),
  per_helper_soft_cap_usd: z.number().nonnegative(),
  per_helper_hard_cap_usd: z.number().nonnegative(),
  max_parallel_helpers: z.number().int().positive().default(4),
  max_total_tool_calls: z.number().int().positive().default(40),
  max_wall_clock_ms: z.number().int().positive().default(180000),
  on_soft_cap: z.enum(["warn", "degrade", "stop"]).default("warn"),
  on_hard_cap: z.enum(["stop", "return_partial", "escalate_to_parent"]).default("return_partial"),
  on_timeout: z.enum(["stop", "return_partial", "retry_once"]).default("return_partial"),
});
```

### 3.5 Helper receipts

```ts
export const DelegationReceiptSchema = z.object({
  receipt_id: z.string().uuid(),
  parent_session_id: z.string(),
  branch_id: z.string().optional(),
  helper_session_id: z.string(),
  mode: DelegationModeSchema,
  task_id: z.string(),
  helper_role: z.string(),
  tools_used: z.array(z.string()).default([]),
  started_at: z.string().datetime(),
  completed_at: z.string().datetime().optional(),
  status: z.enum(["running", "completed", "timed_out", "failed", "stopped"]),
  cost_usd: z.number().nonnegative().optional(),
  token_usage: z.number().int().nonnegative().optional(),
  returned_summary_ref: z.string().optional(),
});
```

### 3.6 Barrier rule

When `mode = silent_native_consult`, the parent agent remains the active executor and waits at a helper barrier. The user receives one final synthesized response in the same visible turn.

### 3.7 Visibility default

- helper activity is captured by default
- research drawer exists by default
- drawer is collapsed by default
- main chat remains clean by default
- full visible room is a special mode, not the default

---

## 4) Coordination artifacts — room charter, role card, and task card

### 4.1 Use three levels, not one

The system should distinguish:

1. **Room Charter** — broad room goal, shared rules, success standard
2. **Role Card** — participant stance/specialization
3. **Task Card** — bounded delegated helper assignment

Task cards should mainly be used for:
- hidden helpers,
- bounded subtask delegation,
- verification/search/evidence pulls,
- and similar focused spawned work.

They should **not** become mandatory for every participant in every multi-agent room.

### 4.2 Room Charter schema

```ts
export const RoomCharterSchema = z.object({
  room_id: z.string(),
  room_type: z.string(),
  objective: z.string().max(500),
  success_standard: z.string().max(500),
  shared_rules: z.array(z.string()).default([]),
  current_phase: z.string().max(120).optional(),
  source_refs: z.array(z.string()).default([]),
});
```

### 4.3 Role Card schema

```ts
export const RoleCardSchema = z.object({
  participant_id: z.string(),
  role_name: z.string().max(160),
  specialization: z.string().max(240).optional(),
  stance: z.string().max(240).optional(),
  focus_areas: z.array(z.string()).default([]),
  avoid_areas: z.array(z.string()).default([]),
});
```

### 4.4 Task Card schema

```ts
export const SubagentTaskCardSchema = z.object({
  task_id: z.string().uuid(),
  parent_session_id: z.string(),
  branch_id: z.string().optional(),
  mode: DelegationModeSchema,
  purpose: z.string().max(240),
  subtask_prompt: z.string().max(4000),
  scope: z.record(z.string()).default({}),
  allowed_tools: z.array(z.string()).default([]),
  forbidden_tools: z.array(z.string()).default([]),
  context_refs: z.array(z.string()).default([]),
  document_refs: z.array(z.string()).default([]),
  success_condition: z.string().max(500),
  stop_condition: z.string().max(500).optional(),
  output_schema_name: z.string().max(160),
  mutation_policy: z.enum(["read_only", "proposal_only", "bounded_write"]).default("read_only"),
  can_spawn_helpers: z.boolean().default(false),
  visibility_mode: z.enum(["collapsed_trace", "live_open", "fully_hidden", "full_visible_room"]).default("collapsed_trace"),
  completion_barrier: z.enum(["parent_waits", "stream_then_parent_synthesizes"]).default("parent_waits"),
});
```

### 4.5 Helper output schema

```ts
export const SubagentReturnSchema = z.object({
  task_id: z.string().uuid(),
  summary: z.string().max(1200),
  findings: z.array(z.string()).default([]),
  evidence_refs: z.array(z.string()).default([]),
  uncertainties: z.array(z.string()).default([]),
  recommended_next_actions: z.array(z.string()).default([]),
});
```

### 4.6 Native OpenClaw behavior note

The policy must explicitly say:
- prefer native OpenClaw helper/subagent mechanisms when available
- do not simulate helpers in prose when native spawning exists
- do not interfere with native OpenClaw helper behavior except where explicit budget/safety/visibility rules apply

---

## 5) Codebase awareness and agent file access

### 5.1 Core additions

Add a lightweight codebase registry:

```ts
export const CodebaseConfigSchema = z.object({
  codebase_root: z.string(),
  primary_branch: z.string().default("main"),
  key_paths: z.record(z.string()).default({}),
  last_scanned_at: z.string().datetime().optional(),
  repo_hash: z.string().optional(),
});
```

Path:
- `ELNOR_MEMORY/system/codebase_config.json`

### 5.2 Shared code map

Generate:
- `ELNOR_MEMORY/system/code_map.md`

This is the shared structural map for all agents, not just repair agents.

### 5.3 Hot file awareness

Add:
- `ELNOR_MEMORY/system/hot_files_current.json`

This should capture recently touched / recently successful / frequently referenced files so “find and edit X” tasks become much more practical.

### 5.4 Rules

- agents do not need new file tools; OpenClaw already has them
- they need awareness of where the repo is and how it is organized
- code-aware tasks should receive `codebase_config.json` + `code_map.md` + optionally hot-file hints

### 5.5 DOC9 bridge

Existing repair knowledge should feed back into shared code awareness:
- repair fingerprints → file hints
- known fix locations → code map annotations
- static repair maps should no longer live as isolated repair-only truth

---

## 6) Unified Environment + Source Registry

### 6.1 Purpose

Elnor needs a single operational map of:
- what apps exist,
- what roots and sources exist,
- what codebases exist,
- what corpora exist,
- what specs are current,
- what is allowed,
- what is currently available,
- and what has been learned over time about where work lives.

This subsystem is not a replacement for DocIndex, memory, runtime truth, or capability manifests. It is a coordination layer across them.

### 6.2 Ownership split

- **ELNOR Core** owns the stable environment/source registry
- **DOC10** consumes it for awareness / “what can I do here?”
- **DOC11** overlays runtime truth
- **DOC3** still owns capability/app/skill manifests
- **DocIndex** still owns registered document objects and searchable artifacts
- **memory** only supplies learned overlays, not the base truth

### 6.3 Stable registry layer

```text
ELNOR_MEMORY/system/environment/
├── environment_registry.json
├── source_roots.json
├── app_registry.json
├── codebase_registry.json
├── corpus_registry.json
├── current_operative_spec_set.json
├── path_aliases.json
└── environment_policy.json
```

### 6.4 Runtime overlay layer

```text
ELNOR_MEMORY/system/environment_runtime/
├── apps_runtime_current.json
├── source_roots_runtime_current.json
├── corpora_runtime_current.json
├── codebases_runtime_current.json
└── environment_health.json
```

### 6.5 Learned overlay layer

```text
ELNOR_MEMORY/system/environment_learned/
├── file_patterns_current.json
├── path_aliases_learned.json
├── source_routing_hints_current.json
├── hot_files_current.json
├── support_pack_usage_current.json
└── environment_learned_audit.jsonl
```

### 6.6 App registry schema

```ts
export const AppRegistryEntrySchema = z.object({
  app_id: z.string(),
  display_name: z.string(),
  app_kind: z.enum(["editor", "office", "browser", "terminal", "viewer", "other"]),
  launch_method: z.string(),
  file_extensions: z.array(z.string()).default([]),
  preferred_for: z.array(z.string()).default([]),
  enabled: z.boolean().default(true),
});
```

### 6.7 Source root schema

```ts
export const SourceAccessModeSchema = z.enum([
  "direct",
  "mirror",
  "broker",
  "blocked",
]);

export const SourceRootSchema = z.object({
  root_id: z.string(),
  label: z.string(),
  path: z.string(),
  root_kind: z.enum([
    "work_docs",
    "matter_root",
    "case_root",
    "codebase_root",
    "spec_root",
    "template_root",
    "export_root",
    "recording_root",
    "sandbox_root",
    "other",
  ]),
  workspace_id: z.string().optional(),
  matter_id: z.string().optional(),
  project_id: z.string().optional(),
  know_exists: z.boolean().default(true),
  read_allowed: z.boolean().default(true),
  write_allowed: z.boolean().default(false),
  index_allowed: z.boolean().default(false),
  auto_register_docs: z.boolean().default(false),
  access_mode: SourceAccessModeSchema.default("direct"),
  include_globs: z.array(z.string()).default([]),
  exclude_globs: z.array(z.string()).default([]),
  sensitive: z.boolean().default(false),
});
```

### 6.8 Codebase registry schema

```ts
export const CodebaseRegistryEntrySchema = z.object({
  codebase_id: z.string(),
  label: z.string(),
  root_path: z.string(),
  active_branch: z.string().optional(),
  repo_hash: z.string().optional(),
  code_map_ref: z.string().optional(),
  hot_files_ref: z.string().optional(),
  languages: z.array(z.string()).default([]),
  build_commands: z.array(z.string()).default([]),
  test_commands: z.array(z.string()).default([]),
});
```

### 6.9 Corpus registry schema

```ts
export const CorpusRegistryEntrySchema = z.object({
  corpus_id: z.string(),
  label: z.string(),
  corpus_kind: z.enum([
    "spec_corpus",
    "matter_corpus",
    "brief_bank",
    "transcript_corpus",
    "code_corpus",
    "memory_corpus",
    "mixed",
  ]),
  provider_kind: z.string(),
  root_ids: z.array(z.string()).default([]),
  semantic_enabled: z.boolean().default(false),
  docindex_enabled: z.boolean().default(true),
  graph_enabled: z.boolean().default(false),
});
```

### 6.10 Current operative spec set schema

```ts
export const OperativeSpecEntrySchema = z.object({
  doc_id: z.string(),
  title: z.string(),
  status: z.enum([
    "current_operative",
    "active_companion",
    "support_non_owner",
    "future_planning",
    "historical",
  ]),
  path: z.string(),
  replaces: z.array(z.string()).default([]),
  must_read_with: z.array(z.string()).default([]),
});
```

### 6.11 What this tells Elnor

This registry tells Elnor:
- what apps are relevant and allowed
- what roots/sources exist
- what codebases are active
- what corpora exist and how they are served
- what specs are operative
- what is readable/writable/indexable
- and what has been learned over time about your environment

It should **not** try to mirror the entire machine.

---

## 7) DOC5 evolution — Sources, Access, Environment Setup, and Permissions

### 7.1 DOC5 becomes the onboarding + permissions UI/workflow

DOC5 should evolve from a OneDrive/mirror concept into a broader:

**Sources / Access / Environment Setup / Permissions** layer.

It should own:
- initial setup wizard
- root/app approval UI
- permission changes
- revoke/pause behavior
- auto-register policy
- account/provider binding
- source access audit
- environment snapshots

### 7.2 Same UI for setup and later changes

The same DOC5 surface should be used for:
- first-time setup,
- later permission changes,
- adding/removing roots,
- adding/removing apps,
- enabling/disabling indexing,
- switching direct/mirror/broker mode,
- and browsing/selecting files or folders manually.

Setup should be **pre-filled manual setup**, not a one-time-only wizard.

### 7.3 User experience model

The UI should let you:
- see suggestions,
- click to remove suggested items,
- browse and add your own folders/files/apps,
- classify them,
- and set permissions immediately.

Suggestions must not replace manual control.

### 7.4 Initial setup presets

Offer simple modes:
- Safe / Minimal
- Recommended / Practical
- Builder / Developer
- Broad Power User

These control defaults only. The user can always edit manually.

### 7.5 Permissions levels

Per source root:
- know exists
- read/search
- index / auto-register
- write / modify
- blocked

Per app:
- know exists
- can launch/use
- can act as default handler
- blocked

### 7.6 Security model

Elnor may:
- see what is already approved
- request access changes
- suggest new roots/apps
- suggest permission changes

Elnor may not:
- approve new access for itself
- elevate read to write
- enable sensitive roots
- enable new app launch permissions
- change cross-account trust settings

Sensitive changes should require explicit operator approval and, ideally, OS/admin authentication.

### 7.7 Direct, mirror, and broker modes

Use:
- `direct` for safe local roots already accessible to the Elnor account,
- `mirror` for curated read/search access across account boundaries,
- `broker` for privileged actions or roots where the operator account remains the real actor.

### 7.8 Two-account model support

The spec must explicitly support:
- a privileged main/operator account,
- a less-privileged Elnor/OpenClaw account,
- mirrored roots where useful,
- brokered actions where required,
- and approval/revocation workflows between them.

### 7.9 Ongoing maintenance

Over time the system should use:
1. quick startup health checks,
2. on-demand refresh when something is missing,
3. low-frequency background refresh,
4. suggestion-driven expansion when new likely-useful roots/apps are noticed.

It should not rescan the whole computer all the time.

---

## 8) Conversation/session memory retrieval

### 8.1 Three retrieval layers

1. **Recent Activity Brief** — ambient continuity, always available when relevant
2. **Matched session/thread summaries** — bounded retrieved context
3. **Recall tool** — deep retrieval only when needed

### 8.2 Core session insight schema

```ts
export const SessionInsightSchema = z.object({
  source_type: z.enum(["chat", "room", "panel", "task", "forum"]),
  source_id: z.string(),
  date: z.string().datetime(),
  auto_title: z.string().max(200),
  primary_topic: z.string().max(240).optional(),
  entities_mentioned: z.array(z.string()).default([]),
  key_facts_learned: z.array(z.string()).default([]),
  action_items: z.array(z.string()).default([]),
  unresolved_questions: z.array(z.string()).default([]),
  event_dates: z.array(z.string()).default([]),
  doc_index_refs: z.array(z.string()).default([]),
  related_session_ids: z.array(z.string()).default([]),
  continues_session_id: z.string().optional(),
  message_count: z.number().int().nonnegative().default(0),
});
```

### 8.3 Entity continuity

Add lightweight cross-session entity records for:
- cases,
- projects,
- repositories,
- documents,
- people,
- topics,
- specs,
- and recurring work artifacts.

### 8.4 Fact consolidation

Important repeated facts should be consolidated into normalized reusable memory artifacts rather than living only in session summaries.

### 8.5 Thread synthesis

When 3+ sessions clearly belong to the same matter/topic/entity, generate thread syntheses so the system can understand continuity across conversations.

### 8.6 Recall tool

Add an explicit recall tool for deep session retrieval. It should be bounded, reference-first, and explanation-friendly.

---

## 9) Hybrid semantic retrieval and bounded reranking

### 9.1 This goes into the specs

Hybrid semantic retrieval for sessions and canonical memory **should be part of the design**, not left as a maybe.

### 9.2 Retrieval model

Use a hybrid score composed from:
- lexical match
- semantic similarity
- metadata filters
- scope match
- authority/provenance
- recency/freshness
- explicit user selection
- topology/relationship signals when available

### 9.3 Bounded reranking

Retrieve a bounded candidate set first, then rerank only that set.

That means:
- better quality,
- no uncontrolled expansion,
- still compatible with context budgets.

### 9.4 What does not become core yet

Do **not** make aggressive self-tuning weight adjustment a core requirement yet. It may exist as a later adaptive layer, but not as a hard dependency of the main design.

---

## 10) DocIndex auto-registration and stable document identity

### 10.1 Auto-registration triggers

Any document that is:
- uploaded to a room,
- referenced in a chat,
- attached to a panel,
- produced by a task,
- or shared in a forum

should be checked for a stable DocIndex entry.

If absent, register it.

### 10.2 Single stable identity

Once a document enters the system, `doc_id` becomes the stable identity. Raw paths may still exist as logs, but should not remain the main retrieval identity.

### 10.3 Bidirectional linking

- session insight → `doc_index_refs`
- document entry → `session_refs`

This makes “pull up that document we used last week” actually work.

---

## 11) Memory feedback and self-learning

### 11.1 Keep observational feedback

Track whether injected memory/session/context was:
- selected,
- trimmed,
- skipped,
- deduped,
- or explicitly inspected.

### 11.2 Weak proxies stay weak

Do not over-trust naive “used vs ignored” inference based on simple overlap or lexical echo. These are weak observational signals.

### 11.3 Use feedback for

- dashboards,
- ranking hints,
- stale/review signals,
- later conservative tuning,
- support-pack review,
- and environment/source routing suggestions.

---

## 12) Authority / memory injection governance

### 12.1 Keep the separate categories

The system should clearly distinguish:
- durable authority memory
- heuristic learned memory
- retrievable history
- transient instructions

### 12.2 Add salience / cooling later if desired

If authority salience, injection cooling, and authority audit are later adopted, they should fit here as an extension — not as a separate memory stack.

---

## 13) Branch-local context guardrails

### 13.1 Add a branch-local task card

Every branch/thread should be able to carry:
- current objective
- current doc pack
- explicit exclusions
- current output type
- last user question
- open decisions

```ts
export const BranchTaskCardSchema = z.object({
  branch_id: z.string(),
  objective: z.string().max(500),
  doc_pack_refs: z.array(z.string()).default([]),
  exclusion_topics: z.array(z.string()).default([]),
  desired_output_type: z.string().max(160).optional(),
  last_user_question: z.string().max(4000).optional(),
  open_decisions: z.array(z.string()).default([]),
  updated_at: z.string().datetime(),
});
```

### 13.2 Add negative topic masks

The system should support branch-local exclusions like:
- ignore consolidation in this branch
- do not discuss versioning here
- this branch is only about memory additions

### 13.3 Add pre-response relevance validation

Before finalizing, compare the latest user question to the drafted answer and check for mismatch in entities/topics. If mismatch is high, force a re-check.

### 13.4 Branch-local context precedence

Branch-local context packs must outrank generic recent-history memory during context injection.

---

## 14) Cross-doc targets

This patch should eventually be merged into multiple owner docs.

### Primary owners
- **ELNOR Core** — session insight generation, entity store, environment/source registry, doc auto-registration, recall tool, codebase awareness
- **DOC5** — source access, permissions, onboarding/setup, manual browsing/selecting, revoke/pause, mirror/broker model
- **DOC10** — retrieval receipts, lane truth, orchestration behavior, helper barrier behavior, drawer surfaces, capability/source awareness
- **DOC15** — CIL consumption of session/thread/document memory, memory feedback, authority governance integration
- **DOC7** — code map / code-aware bucketing / doc hint consumption / support-pack materialization
- **DOC12** — visible research room behavior and room vs helper coordination model
- **DOC13** — helper/subagent budgeting and accounting
- **DOC14** — shared task-card extension for adversarial/red-team rooms when directed subtasks exist
- **DOC9** — shared codebase awareness bridge from repair knowledge

### Supporting architecture / preservation docs
- **DOC16** — preserve the architecture and patch package until merged
- **DOC18 / DOC3** — retrieval lane / provider truth alignment for semantic corpus retrieval

---

## 15) What goes in vs what stays out

### Goes in
- codebase awareness
- ambient session continuity
- session/thread retrieval
- hybrid semantic retrieval
- bounded reranking
- unified environment/source registry
- DOC5 permissions and access control expansion
- DocIndex auto-registration
- stable document identity
- thread synthesis
- helper/subagent delegation
- collapsed trace drawer
- room charter / role card / task card split
- branch-local task guardrails
- helper budget envelopes
- two-account mirror/broker model

### Does not go in as core mandatory behavior yet
- aggressive self-tuning ranking weights
- uncontrolled deep recall as default
- unbounded graph walks
- automatic durable-memory creation from helper outputs
- mandatory task cards for every room participant
- whole-machine unrestricted environment scanning

---

## 16) Final design position

The end-state this patch is aiming for is:

- Elnor remembers relevant prior work across chats, panels, rooms, and documents
- Elnor understands where the code lives and can act on it efficiently
- Elnor understands what apps/roots/corpora/specs are available and allowed
- semantic retrieval is built into the architecture rather than bolted on later
- documents gain stable identity and cross-session continuity
- memory stays bounded and inspectable
- Elnor uses helpers naturally when that will produce a faster, better, or more complete answer
- helper work is visible when you want it, but does not clutter the main chat
- branch-local task focus prevents unrelated recent topics from hijacking the answer
- access and permissions stay operator-controlled and auditable

This should be treated as one coherent patch family, not as a pile of separate experiments.

---

## Part IV — Detailed Doc-by-Doc Amendment Map

## 0) Executive summary

This amendment family adds five major capability clusters:

1. **Memory continuity**
   - conversation/session memory retrieval
   - entity continuity
   - fact consolidation
   - thread synthesis
   - branch-local context guardrails

2. **Codebase awareness**
   - codebase registry
   - shared code map
   - hot file awareness
   - spec/code awareness for Q/EC editing work

3. **Unified Environment + Source Registry**
   - apps
   - roots
   - corpora
   - codebases
   - current operative specs
   - runtime overlays
   - learned overlays

4. **DOC5 evolution**
   - one persistent Sources / Access / Environment Setup / Permissions surface
   - same UI for onboarding and later edits
   - direct / mirror / broker access modes
   - two-account model support

5. **Subagent / handoff behavior**
   - positive delegation instruction
   - helper barriers
   - collapsed research drawer
   - room charter / role card / task card split
   - DOC13 budget/accounting

The core principle is:

> **Extend the existing architecture. Do not create a second uncontrolled memory system, a second truth store, or a second runtime brain.**

---

## 1) Global owner split

### Primary owner docs
- **EC Core / Rebuild Core**  
  canonical environment/source registry, stable runtime coordination substrate, codebase/code-map persistence, source-root and corpus truth, current operative spec set
- **DOC1 [Rebuild]**  
  canonical memory lifecycle, authority/heuristic boundaries, memory relations, pruning/retention
- **DOC5 (evolved)**  
  user-facing setup, permissions, source/app approval, direct/mirror/broker controls
- **DOC10**  
  orchestration, capability awareness, retrieval receipts, collapsed research drawer behavior, one-turn helper barrier
- **DOC11**  
  OpenClaw runtime truth, native subagent behavior, runtime catalogs
- **DOC12**  
  room charters, participant role cards, visible research rooms, ghost/private consult rooms
- **DOC13**  
  helper/subagent budget envelopes and task-level cost controls
- **DOC15**  
  consumption of memory/context/code/environment outputs for CIL planning, suggestions, explanations, learning
- **DOC18**  
  sidecar semantic retrieval provider behavior for selected corpora
- **DOC3**  
  provider/capability routing, provider kinds, retrieval-lane truth, capability manifests

### Supporting / preservation docs
- **DOC16**  
  preserve future architecture and cross-wave additions until fully canonized
- **DOC7**  
  graph-aware document hints, support-pack and context-materialization consumption
- **DOC9**  
  code repair bridge into shared code awareness/hot files when relevant

---

## 2) Shared cross-doc primitives

These should be defined once in shared contracts and referenced/imported by owner docs rather than repeatedly redefined.

### 2.1 Delegation / helper schemas

```ts
export const DelegationModeSchema = z.enum([
  "silent_native_consult",
  "visible_research_room",
  "full_handoff_takeover",
]);

export const RoomCharterSchema = z.object({
  room_id: z.string(),
  room_type: z.string(),
  objective: z.string().max(500),
  success_standard: z.string().max(500),
  shared_rules: z.array(z.string()).default([]),
  current_phase: z.string().max(120).optional(),
  source_refs: z.array(z.string()).default([]),
});

export const RoleCardSchema = z.object({
  participant_id: z.string(),
  role_name: z.string().max(160),
  specialization: z.string().max(240).optional(),
  stance: z.string().max(240).optional(),
  focus_areas: z.array(z.string()).default([]),
  avoid_areas: z.array(z.string()).default([]),
});

export const SubagentTaskCardSchema = z.object({
  task_id: z.string().uuid(),
  parent_session_id: z.string(),
  branch_id: z.string().optional(),
  mode: DelegationModeSchema,
  purpose: z.string().max(240),
  subtask_prompt: z.string().max(4000),
  scope: z.record(z.string()).default({}),
  allowed_tools: z.array(z.string()).default([]),
  forbidden_tools: z.array(z.string()).default([]),
  context_refs: z.array(z.string()).default([]),
  document_refs: z.array(z.string()).default([]),
  success_condition: z.string().max(500),
  stop_condition: z.string().max(500).optional(),
  output_schema_name: z.string().max(160),
  mutation_policy: z.enum(["read_only", "proposal_only", "bounded_write"]).default("read_only"),
  can_spawn_helpers: z.boolean().default(false),
  visibility_mode: z.enum(["collapsed_trace", "live_open", "fully_hidden", "full_visible_room"]).default("collapsed_trace"),
  completion_barrier: z.enum(["parent_waits", "stream_then_parent_synthesizes"]).default("parent_waits"),
});

export const SubagentReturnSchema = z.object({
  task_id: z.string().uuid(),
  summary: z.string().max(1200),
  findings: z.array(z.string()).default([]),
  evidence_refs: z.array(z.string()).default([]),
  uncertainties: z.array(z.string()).default([]),
  recommended_next_actions: z.array(z.string()).default([]),
});

export const DelegationBudgetEnvelopeSchema = z.object({
  budget_id: z.string().uuid(),
  task_budget_usd_soft: z.number().nonnegative(),
  task_budget_usd_hard: z.number().nonnegative(),
  parent_reserve_usd: z.number().nonnegative(),
  per_helper_soft_cap_usd: z.number().nonnegative(),
  per_helper_hard_cap_usd: z.number().nonnegative(),
  max_parallel_helpers: z.number().int().positive().default(4),
  max_total_tool_calls: z.number().int().positive().default(40),
  max_wall_clock_ms: z.number().int().positive().default(180000),
  on_soft_cap: z.enum(["warn", "degrade", "stop"]).default("warn"),
  on_hard_cap: z.enum(["stop", "return_partial", "escalate_to_parent"]).default("return_partial"),
  on_timeout: z.enum(["stop", "return_partial", "retry_once"]).default("return_partial"),
});

export const DelegationReceiptSchema = z.object({
  receipt_id: z.string().uuid(),
  parent_session_id: z.string(),
  branch_id: z.string().optional(),
  helper_session_id: z.string(),
  mode: DelegationModeSchema,
  task_id: z.string(),
  helper_role: z.string(),
  tools_used: z.array(z.string()).default([]),
  started_at: z.string().datetime(),
  completed_at: z.string().datetime().optional(),
  status: z.enum(["running", "completed", "timed_out", "failed", "stopped"]),
  cost_usd: z.number().nonnegative().optional(),
  token_usage: z.number().int().nonnegative().optional(),
  returned_summary_ref: z.string().optional(),
});
```

### 2.2 Environment / source registry schemas

```ts
export const AppRegistryEntrySchema = z.object({
  app_id: z.string(),
  display_name: z.string(),
  app_kind: z.enum(["editor", "office", "browser", "terminal", "viewer", "other"]),
  launch_method: z.string(),
  file_extensions: z.array(z.string()).default([]),
  preferred_for: z.array(z.string()).default([]),
  enabled: z.boolean().default(true),
});

export const SourceRootSchema = z.object({
  root_id: z.string(),
  label: z.string(),
  path: z.string(),
  root_kind: z.enum([
    "work_docs",
    "matter_root",
    "case_root",
    "codebase_root",
    "spec_root",
    "template_root",
    "export_root",
    "recording_root",
    "sandbox_root",
    "other",
  ]),
  workspace_id: z.string().optional(),
  matter_id: z.string().optional(),
  project_id: z.string().optional(),
  read_allowed: z.boolean().default(true),
  write_allowed: z.boolean().default(false),
  index_allowed: z.boolean().default(false),
  auto_register_docs: z.boolean().default(false),
  access_mode: z.enum(["direct", "mirror", "broker", "blocked"]).default("direct"),
  include_globs: z.array(z.string()).default([]),
  exclude_globs: z.array(z.string()).default([]),
});

export const CodebaseRegistryEntrySchema = z.object({
  codebase_id: z.string(),
  label: z.string(),
  root_path: z.string(),
  active_branch: z.string().optional(),
  repo_hash: z.string().optional(),
  code_map_ref: z.string().optional(),
  hot_files_ref: z.string().optional(),
  languages: z.array(z.string()).default([]),
  build_commands: z.array(z.string()).default([]),
  test_commands: z.array(z.string()).default([]),
});

export const CorpusRegistryEntrySchema = z.object({
  corpus_id: z.string(),
  label: z.string(),
  corpus_kind: z.enum([
    "spec_corpus",
    "matter_corpus",
    "brief_bank",
    "transcript_corpus",
    "code_corpus",
    "memory_corpus",
    "mixed",
  ]),
  provider_kind: z.string(),
  root_ids: z.array(z.string()).default([]),
  semantic_enabled: z.boolean().default(false),
  docindex_enabled: z.boolean().default(true),
  graph_enabled: z.boolean().default(false),
});

export const OperativeSpecEntrySchema = z.object({
  doc_id: z.string(),
  title: z.string(),
  status: z.enum([
    "current_operative",
    "active_companion",
    "support_non_owner",
    "future_planning",
    "historical",
  ]),
  path: z.string(),
  replaces: z.array(z.string()).default([]),
  must_read_with: z.array(z.string()).default([]),
});
```

### 2.3 Session/history schemas

```ts
export const SessionInsightSchema = z.object({
  source_type: z.enum(["chat", "room", "panel", "task"]),
  source_id: z.string(),
  date: z.string().datetime(),
  auto_title: z.string().max(200),
  primary_topic: z.string().max(200),
  entities_mentioned: z.array(z.string()).default([]),
  key_facts_learned: z.array(z.string()).default([]),
  action_items: z.array(z.string()).default([]),
  unresolved_questions: z.array(z.string()).default([]),
  event_dates: z.array(z.string()).default([]),
  doc_index_refs: z.array(z.string()).default([]),
  related_session_ids: z.array(z.string()).default([]),
  continues_session_id: z.string().optional(),
  message_count: z.number().int().nonnegative().default(0),
});

export const ThreadSynthesisSchema = z.object({
  thread_id: z.string().uuid(),
  anchor_entities: z.array(z.string()).default([]),
  anchor_doc_refs: z.array(z.string()).default([]),
  summary: z.string().max(4000),
  source_session_ids: z.array(z.string()).default([]),
  open_questions: z.array(z.string()).default([]),
  current_status: z.string().max(200).optional(),
  updated_at: z.string().datetime(),
});
```

### 2.4 Retrieval receipt schemas

```ts
export const RetrievalProviderReceiptSchema = z.object({
  receipt_id: z.string().uuid(),
  provider_kind: z.string(),
  search_lane: z.enum([
    "exact_live_lookup",
    "semantic_corpus_retrieval",
    "canonical_memory_search",
    "native_runtime_local_search",
    "browser_fallback",
  ]),
  corpus_ids: z.array(z.string()).default([]),
  route_reason_codes: z.array(z.string()).default([]),
  freshness_state: z.enum(["live", "fresh", "stale", "degraded", "unknown"]).default("unknown"),
  degraded_reason: z.string().optional(),
  created_at: z.string().datetime(),
});
```

---

## 3) Cross-doc amendment matrix (high-level)

| Doc | Owner role | Primary additions | UI impact |
|---|---|---|---|
| DOC5 | setup / access / permissions | source/app approval, direct/mirror/broker, two-account model | major |
| EC Core / Rebuild Core | stable environment/source registry | registry storage, runtime overlay, codebase registry, corpora, operative specs | indirect |
| DOC1 / Rebuild | memory lifecycle + relation substrate | session insights, thread syntheses, fact consolidation hooks, branch-local overlays | indirect |
| DOC10 | orchestration and user-visible truth | capability/source awareness, retrieval receipts, research drawer, one-turn helper barrier | major |
| DOC11 | runtime truth / native subagent behavior | runtime catalogs, helper barrier truth, launch/read availability truth | low/moderate |
| DOC12 | rooms / visible collaboration | room charter, role card, visible research room / ghost room modes | moderate |
| DOC13 | cost governance | delegation budget envelopes, helper cost aggregation | low |
| DOC15 | CIL consumption | memory/context/code/environment consumption, explanation, support packs | moderate |
| DOC16 | architecture preservation | future topology / hybrid retrieval / environment registry preservation | low |
| DOC18 | semantic retrieval provider | corpus provider truth, receipts, sidecar metadata | low |
| DOC3 / DOC4 | capability/provider/tool routing | provider kinds, helper spawn wrappers, capability manifests | low/moderate |
| DOC7 | materialization / support-pack consumption | graph-aware hints, support packs, contradiction-aware packaging | moderate |
| DOC9 | code repair bridge | feed repair insights into shared code awareness/hot files | low |

---

## 4) Document-by-document amendment map

# 4A) DOC5 — Sources, Access, Environment Setup, and Permissions

## 4A.1 Owner decision
DOC5 should evolve from “account/file access build” into the durable owner of:
- onboarding
- manual source/app browsing and approval
- permission edits at any time
- direct / mirror / broker mode selection
- two-account coordination
- privileged approval/auth

## 4A.2 New top-level sections to add
- Purpose / non-goals
- Unified Environment + Source Registry integration
- Setup presets
- Suggested sources/apps vs manual browse
- App permissions
- Source root permissions
- Direct / mirror / broker modes
- Two-account model
- Security / authentication rules
- Background health refresh and access suggestions
- Admin / user / Elnor responsibility split

## 4A.3 Required UI surfaces

### A. Sources & Apps page
Must support:
- suggested roots/apps/codebases/spec roots
- manual browse/add/remove for folders/files
- permission toggles:
  - know exists
  - read/search
  - index
  - write
  - launch/use
  - blocked
- source classification:
  - work docs
  - matter root
  - case root
  - codebase root
  - spec root
  - export root
  - transcript root
  - other
- access mode:
  - direct
  - mirror
  - broker
  - blocked

### B. Setup wizard
Same UI as the steady-state page, just pre-populated with suggestions and presets.

### C. Approval surface
Must support:
- pending requests from Elnor
- approve/deny
- require password/admin auth for sensitive changes
- audit trail

### D. Health panel
Must show:
- root exists/missing
- app installed/unavailable
- mirror healthy/stale
- corpus indexed/degraded
- last refresh

## 4A.4 Required schemas

```ts
export const SourcePermissionLevelSchema = z.enum([
  "known",
  "read_search",
  "index",
  "write",
  "blocked",
]);

export const AppPermissionLevelSchema = z.enum([
  "known",
  "launch",
  "blocked",
]);

export const SourceAccessRequestSchema = z.object({
  request_id: z.string().uuid(),
  requested_by: z.enum(["user", "elnor", "system_suggestion"]),
  root_or_app_id: z.string(),
  request_kind: z.enum(["add_root", "change_permission", "enable_app", "change_access_mode"]),
  requested_state: z.record(z.any()),
  reason: z.string().max(500).optional(),
  created_at: z.string().datetime(),
  status: z.enum(["pending", "approved", "denied", "expired"]).default("pending"),
});
```

## 4A.5 Runtime rules
- Elnor may request access changes but may not approve them.
- Sensitive changes should require privileged confirmation.
- Initial setup and later edits use the same control surface.
- Suggestions never remove the ability for fully manual browse/add/remove.
- Direct/mirror/broker mode must be stored per source root.

## 4A.6 Cross-doc obligations
- writes approved registry entries into EC Core’s environment registry
- exposes approved roots to DocIndex auto-registration policy
- exposes app permissions to DOC10 capability awareness
- respects DOC11 runtime truth about whether an app is actually available now

## 4A.7 Acceptance tests
- user can browse and add a new root manually
- user can remove a suggested root before setup completes
- user can later revoke a root/app after initial setup
- Elnor can request but not self-approve a new root
- mirror vs broker behavior is visible and auditable
- two-account handoff still respects approved boundaries

---

# 4B) EC Core / Rebuild Core — Unified Environment + Source Registry

## 4B.1 Owner decision
Core owns the stable registry and runtime overlays. It does not own the permissions UI.

## 4B.2 New top-level sections to add
- Unified Environment + Source Registry
- Stable registry layer
- Runtime overlay layer
- Learned overlay layer
- Codebase registry
- Corpus registry
- Current operative spec set
- Refresh/health jobs
- Registry query APIs

## 4B.3 Required storage layout

```text
ELNOR_MEMORY/system/environment/
├── environment_registry.json
├── app_registry.json
├── source_roots.json
├── codebase_registry.json
├── corpus_registry.json
├── current_operative_spec_set.json
├── path_aliases.json
├── environment_policy.json
└── environment_audit.jsonl

ELNOR_MEMORY/system/environment_runtime/
├── apps_runtime_current.json
├── source_roots_runtime_current.json
├── corpora_runtime_current.json
├── codebases_runtime_current.json
└── environment_health.json

ELNOR_MEMORY/system/environment_learned/
├── file_patterns_current.json
├── path_aliases_learned.json
├── source_routing_hints_current.json
├── hot_files_current.json
└── support_pack_usage_current.json
```

## 4B.4 Required APIs / functions

```ts
async function getEnvironmentRegistry(): Promise<{
  apps: z.infer<typeof AppRegistryEntrySchema>[];
  roots: z.infer<typeof SourceRootSchema>[];
  codebases: z.infer<typeof CodebaseRegistryEntrySchema>[];
  corpora: z.infer<typeof CorpusRegistryEntrySchema>[];
  specs: z.infer<typeof OperativeSpecEntrySchema>[];
}>;

async function refreshEnvironmentRuntime(input?: {
  apps?: boolean;
  roots?: boolean;
  corpora?: boolean;
  codebases?: boolean;
}): Promise<void>;

async function getCurrentCodebase(codebaseId?: string): Promise<z.infer<typeof CodebaseRegistryEntrySchema> | null>;
async function getCurrentOperativeSpecSet(): Promise<z.infer<typeof OperativeSpecEntrySchema>[]>;
```

## 4B.5 Runtime rules
- no full-machine scan by default
- use curated roots/apps/codebases/specs as the base
- perform lightweight health checks on known entities
- allow targeted on-demand refresh
- learned overlays never replace configured truth

## 4B.6 Cross-doc obligations
- fed by DOC5 approvals
- consumed by DOC10 awareness layer
- consumed by DOC15 for context planning and code awareness
- consumed by DOC18/DOC3 for corpus binding and route scoring
- informs DocIndex auto-registration and corpus membership
- respects DOC11 runtime truth

## 4B.7 Acceptance tests
- registry survives restart
- runtime overlay can degrade without corrupting the stable registry
- codebase registry resolves active Q/EC repo correctly
- current operative spec set is queryable
- learned path aliases never overwrite configured roots

---

# 4C) DOC1 / Rebuild — Memory continuity substrate

## 4C.1 Owner decision
DOC1 owns the durable memory substrate and should absorb session/history continuity pieces, but not the environment registry.

## 4C.2 New sections to add
- Session insight records
- Entity continuity
- Fact consolidation
- Thread synthesis
- Session recall query interface
- Branch-local overlays / branch task cards
- Negative topic masks
- Relevance validation inputs

## 4C.3 Required schemas
Use:
- `SessionInsightSchema`
- `ThreadSynthesisSchema`

Add:

```ts
export const EntityContinuityRecordSchema = z.object({
  entity_id: z.string(),
  entity_kind: z.string(),
  aliases: z.array(z.string()).default([]),
  linked_session_ids: z.array(z.string()).default([]),
  linked_doc_ids: z.array(z.string()).default([]),
  latest_summary: z.string().max(2000).optional(),
  updated_at: z.string().datetime(),
});

export const FactConsolidationRecordSchema = z.object({
  fact_id: z.string().uuid(),
  entity_id: z.string().optional(),
  statement: z.string().max(2000),
  supporting_session_ids: z.array(z.string()).default([]),
  supporting_doc_ids: z.array(z.string()).default([]),
  status: z.enum(["candidate", "accepted", "contested", "superseded"]).default("candidate"),
  updated_at: z.string().datetime(),
});

export const BranchTaskCardSchema = z.object({
  branch_id: z.string(),
  objective: z.string().max(500),
  current_doc_pack: z.array(z.string()).default([]),
  exclusion_topics: z.array(z.string()).default([]),
  open_questions: z.array(z.string()).default([]),
  updated_at: z.string().datetime(),
});
```

## 4C.4 Retrieval rules
- Recent Activity Brief = lightweight current continuity
- matched session summaries = targeted retrieval layer
- recall tool = deeper explicit retrieval layer
- hybrid retrieval is allowed and should be built into the design, not left out
- bounded reranking applies to session-history candidates too

## 4C.5 Cross-doc obligations
- consumes doc IDs from DocIndex
- exposes session/thread/entity/fact refs to DOC15 and advisors
- should not create authority memory automatically
- should not take over current environment/source registry duties from Core

## 4C.6 Acceptance tests
- can retrieve relevant prior sessions for a continuing matter
- can build thread syntheses across related sessions
- can keep branch-local context separate from unrelated recent history
- can consolidate repeated facts without promoting them to authority automatically

---

# 4D) DOC10 — Orchestration, awareness, receipts, drawer behavior

## 4D.1 Owner decision
DOC10 owns the operator-facing truth of what Elnor can do *now*, what route/provider was used, and how helper activity is surfaced.

## 4D.2 New sections to add
- Unified capability + source awareness card
- Retrieval/provider receipts
- Research drawer behavior
- One-turn helper barrier
- Helper trace visibility
- Compare-route / why-this-route UI
- Branch-aware relevance checks

## 4D.3 Required UI surfaces

### Capability / source awareness card
Must show:
- apps known and available
- roots available
- active codebase
- active corpora
- degraded components

### Retrieval receipt card
Must show:
- provider
- search lane
- corpus ids
- freshness/degraded state
- route reason summary

### Research drawer
Must:
- exist by default
- be collapsed by default
- receive helper trace events automatically
- not clutter the main answer thread
- expand on demand

### Advanced explanation view
Must show:
- why this route
- why this memory/session/doc matched
- why something was skipped or trimmed
- what helper(s) were used

## 4D.4 Required endpoints / contracts

```ts
GET  /api/environment/current
GET  /api/retrieval/receipts/:receipt_id
GET  /api/delegation/receipts/:receipt_id
GET  /api/research-drawer/:parent_session_id
POST /api/research-drawer/:parent_session_id/toggle
```

Add:

```ts
export const ResearchDrawerEventSchema = z.object({
  event_id: z.string().uuid(),
  parent_session_id: z.string(),
  helper_session_id: z.string().optional(),
  event_kind: z.enum([
    "helper_started",
    "helper_progress",
    "helper_completed",
    "helper_failed",
    "synthesis_started",
    "synthesis_completed",
  ]),
  message: z.string().max(1200).optional(),
  created_at: z.string().datetime(),
});
```

## 4D.5 Runtime rules
- by default, helper work stays out of main chat and goes to the drawer
- parent waits and synthesizes once
- drawer visibility is a UI default, not mainly an agent choice
- full visible room is special-case mode
- capability awareness combines Core registry + DOC11 runtime truth + DOC3 capability truth

## 4D.6 Cross-doc obligations
- consume Core environment registry
- consume DOC11 runtime truth
- consume DOC18/DOC3 retrieval provider receipts
- consume DOC15 explanations as needed
- consume DOC13 budget states for helper tasks

## 4D.7 Acceptance tests
- one-turn hidden helper consult works
- drawer shows helper activity while main thread stays clean
- route receipt is visible for retrieval-backed answers
- compare-route panel does not lie about provider truth
- capability/source card updates when runtime overlay changes

---

# 4E) DOC11 — OpenClaw runtime truth and native helper behavior

## 4E.1 Owner decision
DOC11 owns what OpenClaw actually supports and what is available now.

## 4E.2 New sections to add
- native helper/subagent runtime truth
- parent/child binding and helper barriers
- runtime catalogs for apps/roots if available
- app launch truth
- helper completion / partial-return truth

## 4E.3 Required schemas

```ts
export const RuntimeCapabilityCatalogSchema = z.object({
  known_tools: z.array(z.string()).default([]),
  known_apps: z.array(z.string()).default([]),
  known_roots: z.array(z.string()).default([]),
  helper_modes_supported: z.array(DelegationModeSchema).default([]),
  updated_at: z.string().datetime(),
});
```

## 4E.4 Runtime rules
- prefer native OpenClaw subagent mechanisms when available
- parent may spawn helpers and wait at the barrier
- helper modes supported must be queryable
- runtime truth may say a configured app exists in the registry but is unavailable now

## 4E.5 Cross-doc obligations
- DOC10 capability/source awareness depends on this
- DOC5 approval does not override DOC11 runtime truth
- DOC12 visible-room behavior must not claim native helper behavior that runtime does not support

---

# 4F) DOC12 — Rooms, visible research rooms, charters, role cards

## 4F.1 Owner decision
DOC12 owns visible multi-agent collaboration surfaces, ghost/private consult rooms, room charters, and role-card behavior.

## 4F.2 New sections to add
- Room charter
- Role cards
- visible research room mode
- ghost/private research room mode
- task-card usage policy
- room trace streaming to Q

## 4F.3 Rules
- every room has a charter
- many participants may have role cards
- task cards are optional for open discussion rooms
- task cards are strongly recommended for directed subtask delegation and hidden helper consults
- visible research room can feed the same drawer/panel model if desired

## 4F.4 UI
- visible research room panel
- optional side drawer integration
- participant trace stream
- charter view
- role card display
- optional delegated task-card display

## 4F.5 Cross-doc obligations
- must integrate with DOC10 drawer/main-thread split
- may be used by DOC14
- helper budget still governed by DOC13
- helper spawn permissions still governed by DOC11 / runtime truth

---

# 4G) DOC13 — Cost and budget governance

## 4G.1 Owner decision
DOC13 owns budget/accounting for helper/subagent usage.

## 4G.2 New sections to add
- task-level helper budget envelopes
- parent reserve
- helper soft/hard caps
- timeout and partial-return policy
- aggregated helper cost reporting

## 4G.3 Required schemas
Use:
- `DelegationBudgetEnvelopeSchema`

Add:

```ts
export const DelegationBudgetStatusSchema = z.object({
  budget_id: z.string().uuid(),
  parent_spend_usd: z.number().nonnegative().default(0),
  helper_spend_usd: z.number().nonnegative().default(0),
  total_spend_usd: z.number().nonnegative().default(0),
  soft_cap_reached: z.boolean().default(false),
  hard_cap_reached: z.boolean().default(false),
  timed_out: z.boolean().default(false),
  updated_at: z.string().datetime(),
});
```

## 4G.4 Rules
- helpers draw from the parent envelope
- reserve must be preserved for synthesis
- parent can degrade helper count or breadth when budget is tight
- costs are attributed per helper and rolled up

## 4G.5 Cross-doc obligations
- DOC10 needs status for drawer/advanced views
- DOC11 helper runtime should receive budget constraints
- DOC15 learning should not mistake helper over-budget truncation for content irrelevance

---

# 4H) DOC15 — CIL consumption

## 4H.1 Owner decision
DOC15 consumes these systems for context planning, suggestions, explanations, and learning. It is not the owner of them.

## 4H.2 New sections to add
- environment/source registry consumption
- codebase awareness consumption
- session/thread/entity/fact retrieval consumption
- retrieval receipt consumption
- support-pack suggestions
- branch-local context guardrails
- helper explanation consumption

## 4H.3 New schemas

```ts
export const SupportPackSuggestionSchema = z.object({
  suggestion_id: z.string().uuid(),
  title: z.string().max(160),
  doc_refs: z.array(z.string()).default([]),
  reason_codes: z.array(z.string()).default([]),
  retrieval_receipts: z.array(RetrievalProviderReceiptSchema).default([]),
});

export const ContextExplanationSourceSchema = z.object({
  source_kind: z.enum(["authority", "heuristic", "session", "thread", "entity", "fact", "support_pack", "retrieval_receipt"]),
  source_id: z.string(),
  summary: z.string().max(240).optional(),
});
```

## 4H.4 Rules
- DOC15 may consume session/thread/entity/fact data for planning/explanation
- DOC15 may consume provider receipts for explanation
- DOC15 may use support packs as suggestions
- DOC15 must keep provider truth separate from relation truth
- DOC15 does not own app/root permissions
- DOC15 does not own codebase truth, only consumes it

## 4H.5 Cross-doc obligations
- needs Core environment registry
- needs DOC10 retrieval receipts
- needs DOC1 session/thread/fact continuity
- needs DOC7 materialized support packs
- needs DOC13 budget visibility where helper behavior affects context assembly or explanation

---

# 4I) DOC16 — architecture preservation and future canonization

## 4I.1 Owner decision
DOC16 preserves the architecture until it is fully folded into canonical owner docs.

## 4I.2 Required additions
- keep the unified patch themes together
- preserve future graph/topology and hybrid retrieval links
- preserve environment registry and DOC5 evolution concept
- preserve helper/task-card/room-charter architecture
- preserve branch-local guardrails

## 4I.3 Rule
DOC16 should never contradict the owner-doc split. It preserves future work; it does not replace owners.

---

# 4J) DOC18 — semantic retrieval provider

## 4J.1 Owner decision
DOC18 owns the semantic sidecar provider behavior.

## 4J.2 Additions
- corpus/provider truth for receipts
- routing metadata
- health/freshness fields
- environment-registry-aware corpus binding
- handoff of retrieval receipt data to DOC10 / DOC15

## 4J.3 Rule
DOC18 does not own canonical memory or the environment registry.

---

# 4K) DOC3 / DOC4 — provider/capability routing and helper wrappers

## 4K.1 Owner decision
DOC3 owns capability/provider kinds and routing doctrine. DOC4 owns OpenClaw bridge/runtime integration patterns.

## 4K.2 Additions
- `llamaindex_index` provider kind support
- capability awareness ties to environment registry
- helper wrapper skills if needed
- native helper preference notes
- receipt propagation requirements

## 4K.3 Rule
Do not put the main delegation policy only in one helper skill. Skills can execute the pattern, but the policy must live in the spec layer too.

---

# 4L) DOC7 — materialization and support-pack consumption

## 4L.1 Owner decision
DOC7 consumes graph-aware and support-pack-aware hints without becoming a general graph owner.

## 4L.2 Additions
- graph-aware `document_priority_hints`
- support-pack manifests
- contradiction/supersession-aware materialization
- active-review-target pinning
- provider receipt propagation into previews

## 4L.3 Rule
Graph or support-pack hints influence packaging; they do not automatically override budget or boundedness.

---

# 4M) DOC9 — repair/code feedback bridge

## 4M.1 Owner decision
DOC9 should feed shared code awareness rather than remain a repair-only island.

## 4M.2 Additions
- repair-derived hot file updates
- repair fingerprint → code map annotations
- successful fix path hints into `hot_files_current.json`

---

## 5) Cross-doc obligations by concept

### 5.1 Unified Environment + Source Registry
- Core stores it
- DOC5 edits/approves it
- DOC10 reads it
- DOC11 validates runtime availability against it
- DOC15 consumes it
- DocIndex uses it to decide what to auto-register/index

### 5.2 Session / thread memory continuity
- DOC1 stores continuity artifacts
- DOC15 consumes them
- DOC10 can expose them in inspectors/explanations
- DocIndex links documents into them

### 5.3 Helper/subagent delegation
- DOC11 owns runtime truth
- DOC12 owns visible room/charter behavior
- DOC13 owns budgets
- DOC10 owns receipts/drawer/main-thread behavior
- DOC15 consumes traces/explanations
- DOC3/DOC4 may define wrapper mechanisms

### 5.4 Codebase awareness
- Core stores registry + code maps + hot files
- DOC15 consumes for code-aware planning/explanations
- DOC10 exposes awareness state
- DOC9 feeds repairs back in

### 5.5 Retrieval receipts
- DOC18 / DOC3 / provider owners emit/provider-truth fields
- DOC10 displays them
- DOC15 explains them
- DOC7 can use them in previews/support packs

---

## 6) Minimal UI commitment map

These surfaces must exist after amendment, even if detailed visual polish comes later.

### DOC5
- Sources & Apps page
- Setup wizard
- Approval queue
- Health panel

### DOC10 / Q
- capability/source awareness card
- retrieval receipt card
- research drawer
- advanced explanation / compare route

### DOC12
- room charter view
- role card display
- visible research room or panel
- optional delegated task-card display

### DOC15
- inspector additions
- support-pack suggestion cards
- explanation source view
- branch-local task/exclusion display in debug/advanced views

---

## 7) What not to do

Do **not**:
- create a second memory system parallel to the existing one
- make the environment registry the same thing as DocIndex
- let memory override configured source/app truth
- make task cards mandatory for every room participant
- let helpers create durable memory directly
- hide provider truth behind “smart” but uninspectable behavior
- scan the entire computer continuously
- auto-grant new roots/apps without operator approval

---

## 8) Suggested amendment order (authoring order)

If you want to draft the actual amendments later, the safest order is:

1. DOC16 preservation update
2. DOC5 concept / permissions layer
3. Core environment/source registry
4. DOC10 awareness + receipts + drawer
5. DOC11 runtime truth updates
6. DOC12 room/charter/task-card updates
7. DOC13 budgets
8. DOC1 session/thread continuity
9. DOC15 consumption updates
10. DOC18 / DOC3 / DOC4 routing and provider ties
11. DOC7 support-pack/materialization
12. DOC9 repair bridge

This order minimizes ownership conflicts while keeping the UI and behavior aligned.

---

## 9) Final recommendation

This patch family is coherent enough that it should now be treated as a true cross-doc amendment wave rather than a loose set of ideas.

The next best step after this map is:
- either draft the actual amendments doc by doc,
- or choose a narrower subset (for example DOC5 + Core + DOC10 + DOC15) if you want to focus the first merge pass.

But this map is already specific enough that a coding/spec-writing agent should not need to guess what belongs where.

---

## Part V — Operational use note

Use this document as the single DOC16 planning/home-base document for:
- deferred additions
- future architecture preservation
- memory/context/code-awareness/environment-registry/delegation planning
- cross-doc amendment drafting

Historical source files may be archived once this R5.4 document is accepted as the operative DOC16 planning document.