DOC1_Memory Resilience Rebuild_R1.md
Current Specs/DOC1/DOC1_Memory Resilience Rebuild_R1.md
# DOC1 [Rebuild] R1 — Memory Resilience
**Status:** consolidated rebuild working version
**Type:** single-document consolidation for rebuild-from-scratch work
**Lineage persistence rule:** Keep this **Revision Lineage** block at the top of all later Rebuild versions.
## Revision Lineage (must persist in all later Rebuild versions)
This document is the consolidated successor to the following prior operative sources:
1. **ELNOR Suite — Memory + Self-Learning Addendum v1.11.3-FINAL** (`DOC1_MEMORY_RESILIENCE_v1_11_3_FINAL_REF_PACK_SEED_TOGGLE.md`)
2. **DOC1 — Memory Resilience v1.11.3.1 — Relationship Index and Topology Bridge** (`DOC1_MEMORY_RESILIENCE_v1_11_3_1_Relationship_Index_and_Topology_Bridge.md`)
## Reading Rule
This rebuild document is intended to be the **single file** you read for the DOC1 rebuild baseline. It consolidates the prior v1.11.3 memory-resilience spec with the v1.11.3.1 relationship-index/topology amendment so the operative DOC1 spec no longer depends on a separate `.1` side document.
---
Generated: 2026-02-23
Base: DOC1_MEMORY_RESILIENCE_v1_11_3_FINAL.md (pinned below)
## Spec pinning (non-negotiable)
**This addendum + these canonical specs are the authoritative inputs for implementation.**
- DOC1_MEMORY_RESILIENCE_v1_11_3_FINAL.md
03f1c5ce75292e58019421763812dfd1f6fdd5942b202a3f07a8768063de2496
- ELNOR_CORE_SPEC_v1_11_2_CANONICAL.md
a1a23894dae7bbe93af868d02204896d887b2c2d1afd7b63a66a1c4468c81571
- Q_DASHBOARD_SPEC_v1_11_2_CANONICAL.md
f24788fbade9788a30df7e1d5546d14ac65e9464abd8cef84a9e4b4112405fa3
---
## 0) Non‑negotiable constraints (repeat to prevent drift)
### C0.1 Local-first and auditable
All durable artifacts live under `ELNOR_MEMORY/` as real files. Every durable write is logged.
### C0.2 Single-writer
EC is the only process that writes durable state. Q never writes durable state directly.
### C0.3 Approval-gated permanence
Anything that becomes durable "standing knowledge" (standing orders, global rules, promotions, rulebook entries, process templates) must go through **candidate → pending → explicit approval**, and must pass the **Memory Firewall** (write-time gate).
### C0.4 Taint-aware by default
Untrusted content is never injected into prompts by default and cannot be promoted without explicit review.
### C0.5 No bloat / no hot-path LLM
Hot-path logic is deterministic and bounded. QMD queries are warm-path only, timeout-protected, and token-capped.
### C0.6 Archive-not-delete [ADDED]
Pruning NEVER deletes memories. All pruning moves to `system/task_archive/memories/`. Permanent deletion only via explicit user action with confirmation in Q. This is non-negotiable for litigation use — archived case materials must remain recoverable for statute of limitations periods and potential appeals.
---
## 0A) Relationship Index + Topology Bridge Rules [ADDED in Rebuild R1]
### 0A.1 DOC1 remains the owner of the memory relationship index
DOC1 owns the canonical **memory relationship index** and its write/query semantics.
That means DOC1 owns:
- memory-edge durability rules,
- provenance and contradiction semantics for memory lifecycle,
- memory-side project/capsule linkage,
- one-hop memory relation traversal,
- relation-health/current-view exports for memory consumers.
DOC1 does **not** become the owner of the broader document/claim/matter/workflow graph.
### 0A.2 At least one side of a DOC1 relation must be memory-centric
A DOC1 relationship edge must have at least one side that is memory-lifecycle centric:
- memory,
- authority record,
- capsule,
- gap event,
- generalized memory candidate.
If neither side is memory-centric, the edge belongs to the broader ELNOR Core topology/read-model, not DOC1.
### 0A.3 Bounded traversal only
DOC1 may expose only bounded, one-hop traversal to consumers.
Defaults:
- depth: **1 only**
- max results per query: **20**
- relation types filterable
- minimum strength filterable
- scope filterable when scope metadata exists
### 0A.4 Relationship edges are not authority memory by themselves
A relation edge may explain provenance, contradiction, reinforcement, or project linkage.
It is **not** automatically an authority memory item.
If a contradiction edge points at a correction or standing order, the authority still comes from the correction/standing-order artifact itself, not from the edge.
---
## 1) Canonical paths and invariants (do not improvise)
> **IMPORTANT:** Use the canonical paths already established by v1.11.2 contradiction resolution. If your current code uses older paths, implement the migrations described here and then stop using the legacy paths.
### 1.1 Canonical paths referenced by this addendum
- Command queue: `ELNOR_MEMORY/system/queue/commands.jsonl`
- Command results: `ELNOR_MEMORY/system/queue/command_results.jsonl`
- Event bus: `ELNOR_MEMORY/system/events/live.jsonl`
- OpenClaw gateway config: `ELNOR_MEMORY/system/openclaw/gateway.json`
- Remote tokens: `ELNOR_MEMORY/system/remote/tokens.json`
- STOP request: `ELNOR_MEMORY/system/stop_request.json`
- Learning signals: `ELNOR_MEMORY/system/learning/signals.jsonl`
### 1.2 New paths introduced by this addendum
- Flush artifacts:
- `ELNOR_MEMORY/system/flush/YYYY-MM-DD_flush.md`
- `ELNOR_MEMORY/system/flush/YYYY-MM-DD_flush.json`
- `ELNOR_MEMORY/system/flush/flush_index.jsonl`
- CRS capsule ledger:
- `ELNOR_MEMORY/system/crs_capsules/<run_id>_capsule.json`
- Memory gap ledger:
- `ELNOR_MEMORY/system/learning/memory_gaps.jsonl`
- Deferred learning queue (battery-aware):
- `ELNOR_MEMORY/system/learning/deferred_queue.jsonl`
- Memory conflicts queue:
- `ELNOR_MEMORY/system/conflicts/pending.jsonl`
- Relationship index:
- `ELNOR_MEMORY/system/memory_relations.jsonl`
- `ELNOR_MEMORY/system/memory_relations_current.json`
- `ELNOR_MEMORY/system/memory_relations_health.json`
- `ELNOR_MEMORY/system/memory_relations_audit.jsonl`
- Running brief: [ADDED]
- `ELNOR_MEMORY/system/runs/<run_id>/running_brief.json`
- Handoff artifacts: [ADDED]
- `ELNOR_MEMORY/system/handoffs/<run_id>_<ts>.md`
- Autopilot reports: [ADDED]
- `ELNOR_MEMORY/system/learning/autopilot/<date>.json`
---
## 2) Data model upgrades (must implement first)
### 2.1 Memory types: add `mistake` as a first-class memory type
**Do not implement MISTAKES as a parallel memory system.** `mistake` must be included in the same memory infrastructure as other memories:
- lifecycle tracking
- usage_stats + calibrated_confidence
- relationship index (provenance and clustering)
- QMD indexing and retrieval filters
- Memory Firewall gate (promotion/generalization)
If you currently store mistakes as a sidecar file, keep an optional derived view (see §6), but canonical storage is the core memory store.
**Mistake-specific fields (extend base schema):** [ADDED]
```json
{
"type": "mistake",
"category": "legal|tool|tone|cost|security|formatting|research|procedural",
"severity": "high|medium|low",
"trigger_pattern": "service of process, personal jurisdiction, long-arm statute",
"fix_action": "Check local rules for service requirements before drafting jurisdiction arguments",
"source_signal_ids": ["SIG-089", "SIG-092"],
"verified_by_user": false
}
```
**Mistake creation sources:** [ADDED]
- User corrections revealing a procedural failure (not just factual correction)
- Agent self-review tagged `#mistake`
- Reflection failures logged by chain executor (§8)
- Manual creation via Q or chat: "Elnor, remember this as a mistake: ..."
- Gap learning loop (§10): when a gap reveals systematic failure pattern
**Mistake injection rules:** [ADDED]
- Max **2 mistakes** injected per turn
- Only inject when `trigger_pattern` matches current conversation topic (tag match OR QMD similarity > 0.8)
- Never inject `taint_status: untrusted` mistakes
- Injection format: concise, action-oriented (content + fix_action only)
- Dedicated slot in injection order: after corrections, before domain profile (Position 5 in §5.6)
### 2.2 Add usage_stats and calibrated confidence to *every* memory record
Add the following to your base memory schema (where you store memory metadata):
```json
{
"usage_stats": {
"inject_count": 0,
"inject_proceed_count": 0,
"inject_correct_count": 0,
"last_injected_at": null,
"calibrated_confidence": null
}
}
```
**Deterministic update rule (no LLM):**
- On each injection of memory M: `inject_count += 1`, set `last_injected_at`.
- Define correction window: next **2** user turns (configurable).
- If a correction signal occurs with weight ≥ 0.5 and is attributable to the same run/topic: `inject_correct_count += 1`
else `inject_proceed_count += 1`.
**Bayesian confidence (must):**
Use Beta prior α=2, β=2:
`calibrated_confidence = (α + inject_proceed_count) / (α + β + inject_count)`
**Where calibrated_confidence is consumed:** [ADDED]
| Consumer | How |
|----------|-----|
| Context Assembler (§5) | Tiebreaker when injection budget is tight — higher calibrated_confidence wins |
| Consolidation job | Targets low calibrated_confidence memories for review queue |
| Maturity transitions (§3) | `reinforced` requires calibrated_confidence ≥ 0.85 for 5+ inject cycles |
| Learning Dashboard (Q) | Displays as "reliability" percentage per memory |
| Pruning (§3.3) | Low calibrated_confidence + old + low inject_count = first to prune |
### 2.3 Add maturity_state and maturity audit trail to memory records
Add:
```json
{
"maturity_state": "observation|candidate|staged|active|reinforced|established|standing_knowledge|decayed|archived",
"maturity_changed_at": "ISO-8601",
"maturity_history": [
{ "from": "candidate", "to": "active", "at": "ISO-8601", "trigger": "auto_promote_trusted_high_confidence" }
]
}
```
The `maturity_history` array is append-only and provides full audit trail for provenance queries in Q Memory Browser. [ADDED]
### 2.4 Add recency metadata to memory records [ADDED]
These fields support the Freshness + Personal State Addendum but must be present in the base schema now:
```json
{
"recency_type": "static|time_bound|verified_as_of",
"last_verified_at": null,
"verification_ttl_days": null
}
```
Auto-classification at extraction time:
- Dates of past events, user preferences, corrections → `static`
- Deadlines, statute/rule citations, court schedules → `time_bound` (TTL: 90 days)
- Contact info, office holders → `time_bound` (TTL: 30 days)
- Filing fees, software info → `time_bound` (TTL: 14–30 days)
When a `time_bound` memory passes TTL, it's flagged as stale. Stale memories still inject but with `[STALE]` marker. The Freshness Addendum's Recency Router uses stale status as a search trigger.
---
## 3) Memory Maturity Lifecycle (A6 "teeth": explicit triggers)
### 3.1 Lifecycle transitions (normative)
Implement these transition rules exactly; do not invent new ones without adding them to specs.
**observation → candidate**
- when created via extraction/reflection/teach action (default path)
**candidate → staged**
- after schema validation + taint assignment
- enters pending inbox if type is rule/process/template/rulebook entry OR taint != trusted
**staged → active**
- requires explicit approval if:
- taint != trusted OR
- type is rule/standing_order/process/template/rulebook entry OR
- firewall detected any conflict (must be resolved first)
- may auto-activate if:
- type is low-risk preference AND user-directive AND taint=trusted AND no conflicts
**active → reinforced**
- requires all:
- calibrated_confidence ≥ 0.85
- inject_count ≥ 5
- inject_correct_count / inject_count ≤ 0.10
**reinforced → established**
- requires all:
- inject_count ≥ 10
- calibrated_confidence ≥ 0.90
- zero corrections in last 90 days (or last K=10 uses)
- used across ≥ 2 distinct sessions OR ≥ 14 days
**established → standing_knowledge**
- requires explicit user approval for:
- any legal rules, deadlines, procedural rules, standing orders
- may auto-promote for non-legal preference categories only if enabled by setting (default OFF)
**active → decayed**
- if no use for type TTL (see §3.3 for per-type defaults)
**decayed → archived**
- if decayed for 30d with no re-use
**archived → active**
- manual restore only (from Q)
### 3.2 Automatic vs approval-gated transitions
- Upward beyond `active` is automatic based on metrics *except* `standing_knowledge` which requires approval for legal categories.
- Downward transitions are automatic.
- `staged → active` is approval-gated for sensitive types and any taint/conflict conditions.
- Any transition can be overridden by user action in Q Memory Browser. [ADDED]
- All transitions logged to `memory_audit.jsonl` with trigger event, source state, target state, and triggering metric values. [ADDED]
- A user edit or explicitly user-created memory always enters at `active` maturity (user-authored = trusted). [ADDED]
### 3.3 Per-type TTL defaults for decay [ADDED]
| Memory Type | Decay TTL (no use) | Archive After Decay | Notes |
|-------------|-------------------|---------------------|-------|
| Standing orders / legal rules / corrections / never rules | **Never decay** | N/A — stale flag only | Safety-critical |
| Mistakes | **Never decay** | N/A — stale flag only | High learning value |
| Project memories linked to active capsules | **Never decay** | N/A — protected by relationship index | Capsule-aware protection |
| Project memories linked to archived capsules | Decay after 180d unused | Archive after capsule closure + 3 years | Litigation retention (SoL, appeals) |
| Domain knowledge | Decay after 365d unused | Archive 30d after decay | Slow decay |
| Preferences | Decay after 180d unused | Archive 30d after decay | Medium retention |
| Patterns | Existing §3.5 decay rules | Per existing spec | Already specified |
| Ephemeral / low-confidence facts | Decay after 30–90d unused | Archive 30d after decay | Quick cleanup |
| Vocabulary | Decay after 180d unused | Archive 30d after decay | Medium retention |
### 3.4 Pruning priority order [ADDED]
When the consolidation job runs, target memories in this order:
1. Low `calibrated_confidence` + old + low `inject_count` → first to archive
2. `maturity_state: decayed` for > 30 days → archive
3. Past type-specific TTL (§3.3) → archive
4. Low-confidence patterns past existing §3.5 decay threshold → archive
### 3.5 Pruning preview [ADDED]
Before weekly consolidation executes pruning, surface candidates in Q Unified Inbox with:
- **Keep Forever** — marks as protected
- **Keep for This Project** — links to active capsule via relationship index, protecting from future pruning
- **Archive** — confirm archival
User has 48 hours to review before auto-archive executes. Urgent pruning (file system pressure) can execute immediately with Q notification.
---
## 4) Relationship Index (v1.11.3.1 tightened)
### 4.1 Required schema (append-only JSONL; one edge per line)
Path: `ELNOR_MEMORY/system/memory_relations.jsonl`
```ts
// packages/contracts/src/memory/relations.ts
import { z } from "zod";
export const MemoryRelationRefKindSchema = z.enum([
"memory",
"capsule",
"gap_event",
"authority_record",
"generalization_candidate",
]);
export const MemoryRelationRefSchema = z.object({
kind: MemoryRelationRefKindSchema,
id: z.string().max(200),
});
export const MemoryRelationTypeSchema = z.enum([
"belongs_to_project",
"supersedes",
"derived_from",
"contradicts",
"reinforces",
"triggered_by_gap",
"corrects",
"generalized_into",
]);
export const MemoryRelationEdgeSchema = z.object({
relation_id: z.string().uuid(),
src_ref: MemoryRelationRefSchema,
rel_type: MemoryRelationTypeSchema,
dst_ref: MemoryRelationRefSchema,
created_at: z.string(),
updated_at: z.string().optional(),
strength: z.number().min(0).max(1).default(0.5),
scope: z.object({
workspace_id: z.string().max(160).optional(),
capsule_id: z.string().max(160).optional(),
operation_family: z.string().max(120).optional(),
}).default({}),
provenance: z.object({
source_kind: z.string().max(120),
source_id: z.string().max(200),
}).optional(),
notes: z.string().max(500).optional(),
});
```
#### Backward compatibility rule
Legacy records using:
- `src_id`,
- `dst_id`,
- `ts`,
- `weight`
must still be readable. On read/rebuild they normalize to:
- `src_ref = { kind: "memory", id: src_id }`
- `dst_ref = { kind: "memory", id: dst_id }`
- `created_at = ts`
- `strength = weight`
This prevents breaking existing data while fixing the current schema/prose mismatch.
### 4.2 Usage rules (must)
- **Provenance** is represented by `derived_from`, `supersedes`, `corrects`, and `generalized_into`.
- **Conflicts** are represented by `contradicts` and must create/attach a conflict record (see §8).
- **Project scoping** uses `belongs_to_project`, typically linking a memory ref to a capsule ref.
- **Retrieval boost** may use `reinforces` and `belongs_to_project`.
- **Gap learning** uses `triggered_by_gap` links from created memory items back to the gap event.
- **Generalization lineage** uses `generalized_into` and `derived_from`.
### 4.3 Context Assembler integration (tightened)
**Capsule one-hop traversal:** When loading a capsule, DOC1 may query all memory edges where:
- `rel_type == belongs_to_project`
- either `src_ref` or `dst_ref` is the target capsule ref
- the opposite side is a memory ref
This fixes the prior ambiguity where prose expected capsule links but the schema looked memory-only.
**Retrieval boost:** When scoring memory results, boost memories that have relation edges to memories already selected in the injection set.
**Pruning protection:** Memories with `belongs_to_project` relations to active, non-archived capsules remain protected from pruning regardless of TTL or maturity decay.
### 4.4 Generalization provenance (tightened)
When the generalization engine (§12) creates a generalized memory from 3+ source memories:
- write `derived_from` edges linking the new memory to each source memory,
- write `generalized_into` edges from each source memory to the new generalized memory,
- source memories may still carry the convenience field `generalized_into`,
- the durable provenance chain remains the relationship index.
### 4.5 Current-view and health artifacts
Add the following derived artifacts:
```text
ELNOR_MEMORY/system/
├── memory_relations.jsonl # append-only canonical relation log
├── memory_relations_current.json # atomic normalized current view
├── memory_relations_health.json # atomic health/degraded state
└── memory_relations_audit.jsonl # optional append-only maintenance/audit log
```
`memory_relations_current.json` must contain a normalized, query-ready view:
```ts
export const MemoryRelationsCurrentViewSchema = z.object({
updated_at: z.string(),
relation_count: z.number().int().min(0),
relations: z.array(MemoryRelationEdgeSchema),
});
export const MemoryRelationsHealthSchema = z.object({
updated_at: z.string(),
freshness_state: z.enum(["fresh", "stale", "degraded", "missing"]),
relation_count: z.number().int().min(0),
last_error: z.string().max(240).optional(),
degraded_reason_codes: z.array(z.string().max(120)).default([]),
});
```
### 4.6 Bounded read/query seam
DOC1 must expose a stable one-hop query seam for consumers such as ELNOR Core, DOC10, and DOC15.
```ts
export const MemoryRelationQuerySchema = z.object({
seed_refs: z.array(MemoryRelationRefSchema).min(1).max(5),
rel_types: z.array(MemoryRelationTypeSchema).max(8).optional(),
min_strength: z.number().min(0).max(1).default(0.0),
scope_filter: z.object({
workspace_id: z.string().max(160).optional(),
capsule_id: z.string().max(160).optional(),
operation_family: z.string().max(120).optional(),
}).optional(),
limit: z.number().int().min(1).max(20).default(20),
});
export const MemoryRelationQueryResultSchema = z.object({
freshness_state: z.enum(["fresh", "stale", "degraded", "missing"]),
degraded_reason: z.string().max(240).optional(),
truncated: z.boolean().default(false),
relations: z.array(MemoryRelationEdgeSchema).default([]),
});
```
Implementation guidance:
```ts
// apps/ec-service/src/memory/relations/query-memory-relations.ts
export async function queryMemoryRelations(
input: z.infer<typeof MemoryRelationQuerySchema>
): Promise<z.infer<typeof MemoryRelationQueryResultSchema>>;
```
Query rules:
- one-hop only,
- relation-type filters are optional but recommended,
- results must be truncated rather than unbounded,
- if health is degraded, return degraded metadata instead of throwing where safe.
### 4.7 Core topology handoff rule
ELNOR Core’s broader topology/read-model may ingest DOC1 relation edges as one source input.
Handoff rule:
- DOC1 emits/query-serves canonical memory relation edges,
- ELNOR Core may derive broader read-model edges from them,
- ELNOR Core may not redefine DOC1 relation ownership,
- DOC1 does not become the owner of broader document/claim/workflow topology.
### 4.8 Contradiction and supersession semantics for consumers
Consumers may treat relation types as follows:
- `reinforces` → modest rank boost
- `belongs_to_project` → scope/continuity boost and pruning protection
- `derived_from` → provenance/explanation only
- `corrects` → provenance + correction lineage
- `supersedes` → older memory may be demoted or shown as archived lineage
- `contradicts` → comparison/explanation path; may trigger user-review surfacing
- `triggered_by_gap` → gap-learning provenance only
- `generalized_into` → lineage from specific memories to generalized pattern
These semantics are ranking/explanation helpers. They do not by themselves mutate authority.
### 4.9 UI implications
Q Memory Browser relation view should now show:
- relation type,
- source ref kind/id,
- destination ref kind/id,
- strength,
- capsule/project linkage when applicable,
- contradiction/supersession pills,
- lineage for generalized memories.
Loading states:
- **loading** — relation panel skeleton
- **empty** — “No related memory edges recorded”
- **degraded** — “Relation data unavailable; showing memory only”
- **populated** — one-hop relation list with filters
### 4.10 Code implementation guidance
```text
packages/contracts/src/memory/relations.ts
apps/ec-service/src/memory/relations/write-memory-relation.ts
apps/ec-service/src/memory/relations/normalize-legacy-relations.ts
apps/ec-service/src/memory/relations/query-memory-relations.ts
apps/ec-service/src/memory/relations/build-current-view.ts
apps/ec-service/src/memory/relations/health.ts
```
Suggested normalizer:
```ts
export function normalizeLegacyRelation(raw: any): z.infer<typeof MemoryRelationEdgeSchema> {
return {
relation_id: raw.relation_id ?? crypto.randomUUID(),
src_ref: raw.src_ref ?? { kind: "memory", id: raw.src_id },
rel_type: raw.rel_type,
dst_ref: raw.dst_ref ?? { kind: "memory", id: raw.dst_id },
created_at: raw.created_at ?? raw.ts,
updated_at: raw.updated_at,
strength: raw.strength ?? raw.weight ?? 0.5,
scope: raw.scope ?? {},
provenance: raw.provenance,
notes: raw.notes,
};
}
```
### 4.11 Failure behavior
| Failure | Behavior |
|--------|----------|
| malformed edge line | quarantine that line, continue loading others |
| legacy line missing `src_id` / `dst_id` | quarantine line, emit degraded health |
| current view build fails | keep last good current view, mark health degraded |
| query called while health degraded | return degraded result with last good relations where safe |
### 4.12 Explicit non-goals [ADDED in Rebuild R1]
This revision does **not**:
- create a universal graph database for ELNOR,
- move document/matter/workflow graph ownership into DOC1,
- allow relation inference to create standing orders automatically,
- authorize unbounded graph traversal,
- replace existing pruning/maturity/approval rules.
## 5) QMD Injection Hook (two-tier, timeout-protected, budgeted)
### 5.1 Hot-path injection (always, no QMD call, ≤250 tokens)
Inject (if present) in this order:
1) pinned Project Card (micro)
2) active Capsule Micro (micro)
3) last Handoff Brief OR Running Brief excerpt
### 5.2 Warm-path injection (QMD call only on triggers)
Triggers:
- new session/conversation
- project switch
- topic shift detector
- "remember/what did we decide" query class
- post-compaction boundary
- agent/model handoff
- panel round boundary (if panels are used)
Warm-path constraints:
- max 3 results
- max 400 tokens total
- hard timeout 150–300ms
- if timeout, skip and log `qmd_timeout` signal
Filters:
- exclude `taint_status=untrusted` unless user explicitly requests "include untrusted"
- prefer high-confidence, project-scoped, recently used, pinned
- dedupe across consecutive turns
### 5.3 Context budgeter (big pasted docs)
If user message tokens exceed threshold (default: **2,000 tokens**, configurable):
- reduce warm-path to 1 result or 0
- keep hot-path unchanged
- keep personal context injection (from Freshness Addendum) unchanged — it's small and always valuable [ADDED]
- reduce mistake injection to max 1 [ADDED]
### 5.4 Injection block format (stable)
```text
[Working Memory — Hot]
• …
[QMD: Relevant Memories — Warm]
• MEM-… (confidence: …; scope: …; last_used: …): …
```
### 5.5 Turn dedupe [ADDED]
Track `last_injected_memories[]` in session state (in-memory, not persisted). Don't re-inject the same memory on consecutive turns unless:
- The memory was explicitly referenced in the intervening user message
- A topic shift was detected
- A compaction boundary occurred
- A warm-path trigger fired (§5.2)
This prevents the same memory from consuming injection budget turn after turn when the conversation hasn't moved.
### 5.6 Full injection order (canonical, all positions) [ADDED]
This is the master injection order combining hot-path, warm-path, and reserved slots for companion addenda. Position 1 is injected first (top of context).
| Position | Component | Token Budget | Drop Policy | Source |
|----------|-----------|-------------|-------------|--------|
| 1 | **Recency Layer** — date, time, model cutoff, freshness policy | ~60 tokens | NEVER drop | Freshness Addendum |
| 2 | **Personal Context Card** — calendar, email, files, deadlines | ~150–250 tokens | NEVER drop | Freshness Addendum |
| 3 | **SOUL.md** — personality, communication style | Per config | NEVER drop | Existing spec |
| 4 | **Standing Orders + Corrections + Never Rules** | ~500 tokens | NEVER drop | Existing spec |
| 5 | **Active Mistakes** — max 2, topic-matched | ~100 tokens | Drop if budget critical | This addendum §2.1 |
| 6 | **Topic Capsule** — micro or standard tier | ~200–1,500 tokens | Downgrade to micro if tight | Existing spec |
| 7 | **Workspace Instructions** | ~200 tokens | Drop if budget critical | Existing spec |
| 8 | **Domain Profile** | ~300 tokens | Drop if budget critical | Existing spec |
| 9 | **QMD Warm Results** — max 3, ≤400 tokens, only on triggers | ~400 tokens | Skip entirely if budget tight | This addendum §5.2 |
| 10 | **Recent Memories / Entity-specific / Task Templates / Patterns** | Remaining budget | Trimmed first | Existing spec |
Total injection ceiling: **6,500 tokens** (unchanged from existing §4.5).
Positions 1–4 are **hot** (always loaded, no QMD, deterministic). Positions 5–9 are **warm** (conditional). Position 10 is the overflow bucket trimmed first under budget pressure.
---
## 6) Pre-Compaction Flush (flush as checkpoint + doc references)
### 6.1 Artifacts and budgets
Write:
- `system/flush/YYYY-MM-DD_flush.md` (human)
- `system/flush/YYYY-MM-DD_flush.json` (machine)
- append `system/flush/flush_index.jsonl` (one line per flush)
Default flush token budget: **1500 tokens** (project-configurable).
### 6.2 Flush contents (required)
- active Project Card
- top pinned memories (max 3)
- active capsule micros
- open loops + pending inbox summary
- running_brief snapshot [ADDED]
- active standing orders list [ADDED]
- active mistakes (topic-relevant) [ADDED]
- personal_context deadline snapshot (from Freshness Addendum, if available) [ADDED]
- referenced_documents[] (required):
- `path`, `hash`, `docmeta_summary`, `last_used_at`, `taint_status`, optional deep link
**Token budget overflow:** If contents exceed budget, truncate by same priority waterfall as Context Assembler §5.6: drop patterns first, then recent memories, then domain profile, then workspace instructions. Capsule micro, standing orders, corrections, and running brief are never dropped from flush. [ADDED]
### 6.3 Flush preview + manual trigger
- Add EC command: `flush_now` and `flush_preview_generate`
- Q must implement "Flush Preview" editor:
- view/edit flush content
- token count vs budget display [ADDED]
- confirm → EC writes artifacts
### 6.4 Post-compaction injector integration [ADDED]
When the existing §17.3.3 Post-Compaction Injector fires:
1. Check for a flush artifact for the current conversation.
2. If one exists and is **< 30 minutes old**, inject it as the primary recovery payload. This is faster and more coherent than assembling from scratch.
3. If no fresh flush exists, fall back to existing §17.3.3 assembly method.
This is a critical bridge — the flush and the post-compaction injector must know about each other.
### 6.5 Session-start flush injection (toggleable) [ADDED]
**Intent:** Reduce “cold start” amnesia when starting a new chat/thread or returning after an idle gap. This reuses the existing **flush** artifacts as the session-start context seed; it does **not** rename or replace flush artifacts.
**Trigger (session boundary):**
- A new conversation/thread begins, **OR**
- `last_message_at` is older than `session_start_flush_idle_minutes` (default **30 minutes**, configurable).
**Behavior:**
1. On session boundary, EC checks for the **latest flush** artifact (from `system/flush/flush_index.jsonl`).
2. If a flush exists and is within `session_start_flush_max_age_minutes` (default **1440 minutes / 24 hours**), EC injects that flush **once** as a structured “Session Start Context” block for the first assistant turn after the boundary.
3. EC also emits a visible, collapsible **system message** in Q chat labeled **[Session Start Context]** containing the same structured block (truncated to the flush token budget rules in §6.2).
4. The injected block is **not repeated** on subsequent turns until the next session boundary.
5. If no eligible flush exists, EC does **not** generate a new flush automatically; it falls back to normal Context Assembler behavior.
**Injection rules:**
- Uses the same token budget and truncation waterfall as the flush (§6.1–§6.2).
- Must respect taint: for untrusted channels, apply the same redaction rules used by Memory Firewall (e.g., redact local paths; include hashes + docmeta summaries instead).
- No extra QMD calls are required to generate the seed. If warm-path QMD results already exist for the session, they may be referenced by handle, but EC must not trigger new QMD searches solely to decorate the seed.
**User control (must be a button, not only settings):**
- Q must provide a one-click toggle button labeled **“Session Start Context”** (On/Off) in the chat UI (visible within the active chat view). Toggling Off disables §6.5 injection and hides the system message for future session boundaries.
- Q must also surface the same toggle in Settings (§13.6).
- Toggle changes are durable (single-writer): Q submits an append-only command; EC updates the canonical toggle state (see §13.6).
**Defaults:**
- `session_start_flush_injection_enabled`: **ON**
- `session_start_flush_idle_minutes`: **30**
- `session_start_flush_max_age_minutes`: **1440**
---
## 7) CRS Capsule Ledger + rehydration gating
### 7.1 Capsule artifact
On any CRS compression or multi-session decomposition write:
- `system/crs_capsules/<run_id>_capsule.json`
Contains:
- dropped/summarized items with `recoverable: true/false` flags [ADDED]
- pointers to originals (session hourly summaries, workflow manifests) [ADDED]
- rehydrate plan (auto-approved vs requires-approval lists) [ADDED]
- before/after token counts [ADDED]
- reason codes
### 7.2 Rehydrate rules
- Auto-rehydrate only trusted, low-cost chunks.
- Approval required for mixed/untrusted or high-cost rehydrate.
- Q must show capsule timeline + "Rehydrate" action with estimated token cost. [ADDED]
- Command: `rehydrate_from_crs_capsule {ledger_id}` [ADDED]
---
## 8) Memory Firewall (write-time gate + conflict queue UI)
### 8.1 Gate pipeline (required)
Before any durable write into memory/rules/processes:
1) schema validate — reject malformed entries, verify all required fields per §2 [ADDED]
2) taint check — untrusted → route to `staged`; mixed → write with `conflict_flag: true` [ADDED]
3) dedup check — >80% content similarity with existing memory of same type/scope → merge candidate, route to consolidation queue, don't create duplicate [ADDED]
4) contradiction check (firewall proper)
5) budget check — if active memories of this type exceed type budget (soft limits: 100 corrections, 50 standing orders, 500 facts), flag but allow [ADDED]
6) staging/approval
7) write + audit + relationship index update [ADDED]
### 8.2 Conflict types (required)
- hard negation (Always X vs Never X) → **block write**, create conflict entry, surface in Unified Inbox
- scope conflict (global vs project exception) → write with `conflict_flag: true`, surface as "review suggested"
- temporal conflict (superseded vs current) → write succeeds, old memory gets `superseded_by` field and maturity → `archived`, create `supersedes` relation [ADDED]
- confidence conflict (high confidence contradicted by low confidence) → **reject low-confidence write**, log `confidence_conflict_rejected` [ADDED]
### 8.3 Conflict queue
Write to:
- `system/conflicts/pending.jsonl`
Each conflict entry must include:
- conflict_id
- detected_at [ADDED]
- involved memory ids (memory_a_id, memory_b_id) [ADDED]
- both memories' content summaries (for Q display without additional lookups) [ADDED]
- scope_a, scope_b (to distinguish global vs project-scoped conflicts) [ADDED]
- rel_type=contradicts edges written to relations index
- recommended resolution options (scope, supersede, exception)
- resolution status: null until resolved [ADDED]
- resolved_at, resolved_by: populated on resolution [ADDED]
Q must surface conflicts in the Unified Inbox and require user resolution.
---
## 9) Citations-in-memory (verifiability) + "View Source"
### 9.1 Citations schema (required for legal-rule memories)
Any memory that asserts a legal rule, deadline, procedural rule, or factual claim must include:
```json
{
"citations": [
{
"path": "...",
"hash": "...",
"page_or_bates": "optional",
"excerpt_pointer": "optional",
"captured_at": "ISO-8601",
"url": null,
"source_tier": null
}
]
}
```
When citation includes a URL (from web search grounding via Freshness Addendum), `source_tier` is populated (1–4). [ADDED]
### 9.2 UI requirement
Q must show "View source" / "Open referenced doc" actions for any memory with citations.
### 9.3 Weekly link check [ADDED]
Consolidation job extension: HEAD request for all URLs in memory citations. Dead links flagged in Q Memory Browser with broken-link indicator. User can update URL, remove citation, or ignore.
---
## 10) Gap Detector + "Teach Elnor" closed loop
### 10.1 Gap logging
When user indicates expectation of memory (remember queries) and QMD returns 0 results or times out:
- append to `system/learning/memory_gaps.jsonl` with:
- gap_id [ADDED]
- query text, project context (capsule_context), empty vs timeout, ts
- expected_type (inferred: fact, date, rule, preference) [ADDED]
- expected_domain (inferred from capsule or topic) [ADDED]
- recovery_action (user_taught, user_dismissed, unresolved) [ADDED]
- taught_memory_id (if user teaches, link to created memory) [ADDED]
### 10.2 Learning signal weight [ADDED]
Generate learning signal (weight: **0.9**, type: `memory_gap`). This is the highest-weight passive signal because a memory gap forces the user to re-teach — EC's most expensive failure mode.
### 10.3 Gap-to-memory linking [ADDED]
If the user teaches the missing info, the new memory gets:
- `triggered_by_gap` relation in relationship index pointing to the gap event
- `created_from_gap: "GAP-001"` metadata
- `maturity_state: active` (user-taught = trusted, skips staged)
### 10.4 Q UX
Show "Memory Gap Detected" card with:
- Teach Elnor → creates pending learning item linked to gap id, prefilled with type/scope/tags from gap context [ADDED]
- Deep search (trusted)
- Deep search incl untrusted (explicit toggle)
### 10.5 Gap-to-extraction improvement pipeline (weekly)
Weekly job:
- cluster gaps by memory type/topic/project
- if >3 gaps of same type in 30 days:
- create "Extraction Improvement Suggestion" pending item
- upon approval:
- update extraction template prompts to emphasize that type (e.g., deadline extraction)
Additional pattern detection: [ADDED]
- Same entity in 2+ gaps → suggest proactive capsule creation or capsule update
- Same domain in 3+ gaps → flag domain profile as underdeveloped
- Same capsule context in 3+ gaps → flag capsule as incomplete, suggest enrichment session
---
## 11) Battery-aware deferred learning queue (explicit, FIFO)
### 11.1 Queue file
- `system/learning/deferred_queue.jsonl`
Each item:
- id, ts, job_type, payload pointer, TTL (default 24h)
### 11.2 Processing
- On AC power return: process FIFO with budget caps.
- If TTL expires: process next heartbeat anyway (to avoid staleness).
### 11.3 What defers vs what doesn't [ADDED]
| Operation | Battery Behavior |
|-----------|-----------------|
| Signal capture, counter increments, file appends | Normal — cheap, always execute |
| Extraction, generalization, gap analysis (LLM calls) | Defer to AC |
| QMD warm-path triggers | Reduce to topic shift + explicit only |
| Weekly consolidation / nightly loop | Defer to AC |
| Link verification | Disabled |
---
## 12) Self-learning "Memory Performance Loop" (nightly bounded)
### 12.1 Schedule [ADDED]
Runs nightly (default: 02:00 local time). Battery-aware: if on battery at scheduled time, defer to deferred_queue (§11).
### 12.2 Operations in order [ADDED]
1. **Confidence calibration:** Recalculate `calibrated_confidence` for all memories with new usage data since last run.
2. **Maturity transitions:** Process all pending transitions per §3.1 rules.
3. **Generalization proposals:** Cluster mistakes and corrections by `trigger_pattern` / entity tags. If 3+ cluster on same topic → generate candidate (standing order or generalized memory). Candidate enters Write Gate (§8) at contradiction check. If no contradiction, written with `maturity_state: staged`, surfaces in Unified Inbox for approval. On approval: `derived_from` relations created, source memories get `generalized_into` field.
4. **Gap analysis:** Analyze `memory_gaps.jsonl` for patterns per §10.5.
5. **Pruning preview:** Identify candidates per §3.4 priority order, surface in Unified Inbox per §3.5.
6. **Maintenance suggestions:** Dead citations (§9.3 link check), orphaned relations, budget overflows.
7. **Stale knowledge list:** Identify time-bound memories past TTL for inclusion in Daily Brief (consumed by Freshness Addendum).
8. **Write Autopilot Report:** `system/learning/autopilot/<date>.json` — summary of all actions taken and proposals generated. Q shows as "Overnight Learning Report" card.
All permanent changes go through Unified Inbox approvals + firewall. The nightly loop PROPOSES — it never writes permanent changes unilaterally.
---
## 12A) Running Brief + Handoff Briefs [ADDED]
### 12A.1 Running Brief
Maintained passively throughout each run as a deterministic, incrementally-updated summary:
`ELNOR_MEMORY/system/runs/<run_id>/running_brief.json`
```json
{
"run_id": "run-2026-03-10-001",
"updated_at": "2026-03-10T22:14:00Z",
"brief": "Working on Henderson SoL analysis. Decided FRCP 15(c) relation-back approach. Brief v4 is current draft.",
"active_capsule": "capsule_henderson_v_pacific",
"active_files": ["~/OneDrive/Legal/Henderson/brief_v4.docx"],
"recent_decisions": ["Use FRCP 15(c) relation-back argument"],
"open_questions": ["Does equitable tolling apply to amended complaint?"],
"token_count": 95
}
```
Updated after each significant exchange (decisions, file references, status changes). Amortized cost: O(1) maintenance, not O(n) generation at handoff time.
### 12A.2 Handoff Briefs
On agent/model switch or CRS multi-session decomposition, snapshot running brief to:
`ELNOR_MEMORY/system/handoffs/<run_id>_<ts>.md`
Token budget: **250–500 tokens** (configurable per agent). Injected into receiving prompt as part of hot injection (Position 5.1 §5.1).
---
## 13) Q UI requirements (must implement)
### 13.1 Unified Inbox (single approval surface)
Inbox aggregates:
- pending rules
- pending learning items
- promotion candidates
- rulebook candidates
- gate approvals
- firewall conflicts
- extraction improvement suggestions
- pruning preview actions (Keep/Archive/Keep for Project) [ADDED]
- generalization candidates from nightly loop [ADDED]
- stale knowledge review items (from Freshness Addendum) [ADDED]
### 13.2 Memory Browser enhancements
- QMD Deep Search tab
- selection toolbar "Deep Search My Memories"
- result actions: promote / pin to capsule micro / add to capsule
- **Maturity filter:** filter memories by maturity_state [ADDED]
- **Calibration sort:** sort by calibrated_confidence (low first for review) [ADDED]
- **Relationship view:** for any memory, show one-hop relations (derived_from, corrects, belongs_to_project) [ADDED]
- **View Source:** click citations to open referenced document [ADDED]
### 13.3 Home cards
- QMD Health (coverage, refresh, latency, miss rate)
- Lessons This Week (top 3 mistakes with actions)
- Memory Health traffic-light:
- 🟢 **Healthy:** 0 gaps in 7 days, 0 pending conflicts, <5% stale, all connectors healthy [ADDED]
- 🟡 **Attention:** 1–3 gaps in 7 days, OR 1+ pending conflicts, OR >10% stale [ADDED]
- 🔴 **Action Required:** 3+ gaps in 7 days, OR unresolved hard contradictions, OR connectors down [ADDED]
### 13.4 Learning Dashboard [ADDED]
- **Maturity Distribution:** Bar chart of memories by maturity stage
- **Gap Trend:** Line chart of gaps per week (trending down = learning)
- **Generalization Activity:** Recent candidates with status
- **Confidence Calibration View:** Low-reliability memories for review
### 13.5 Flush and CRS views
- Flush Preview editor + history timeline [ADDED]
- CRS Capsule viewer + Rehydrate with token cost estimate [ADDED]
- **Session Start Context toggle button** (On/Off) must be visible in the active chat view UI, and must reflect the Settings toggle state (§13.6). [ADDED]
### 13.6 Settings toggles
- QMD injection: Auto/Always/Never
- Auto-flush before compaction: ON/OFF [ADDED]
- **Session Start Context:** ON/OFF (controls §6.5 injection) [ADDED]
- **Session Start idle minutes:** number (default 30) [ADDED]
- **Session Start max age minutes:** number (default 1440) [ADDED]
- Gap detector: ON/OFF [ADDED]
- Firewall: ON/OFF [ADDED]
- include untrusted in deep search (default OFF)
- advanced: flush/handoff token budgets
---
## 14) Acceptance tests (add to existing suite)
### 14.1 Core memory tests
| # | Test | Validates |
|---|------|-----------|
| 11 | Inject memory 5× without correction → maturity advances to `reinforced` | Maturity lifecycle (§3) |
| 12 | Inject memory, user corrects → `inject_correct_count` increments, `calibrated_confidence` decreases | Confidence calibration (§2.2) |
| 13 | 3+ clustered mistakes with similar trigger_pattern → generalization proposes standing order | Generalization (§12) |
| 14 | Load capsule → one-hop traversal pulls related memories via relationship index | Relationship index (§4.3) |
| 15 | QMD boost: memory with `reinforces` edge to already-loaded memory ranks higher | Relationship boost (§4.3) |
| 16 | Post-compaction injector uses flush artifact when < 30 min old | Flush integration (§6.4) |
| 17 | Deferred learning queue processes when AC power returns | Deferred queue (§11) |
| 18 | Gap analysis creates extraction improvement suggestion after 3+ same-type gaps in 30d | Gap learning (§10.5) |
| 19 | Session boundary injects latest eligible flush once | §6.5 injection, one-time behavior, visible system message |
| 20 | Toggle “Session Start Context” OFF disables injection | §6.5 toggle button + §13.6 settings persistence |
### 14.2 Write Gate tests [ADDED]
| # | Test | Validates |
|---|------|-----------|
| 19 | Extract memory contradicting existing correction → Write Gate blocks, creates conflict | Firewall (§8) |
| 20 | >80% content similarity with existing memory → dedup prevents duplicate | Dedup (§8.1) |
| 21 | High-confidence existing memory contradicted by low-confidence extraction → rejected | Confidence conflict (§8.2) |
| 22 | Temporal supersession → new memory written, old archived with `superseded_by` link | Temporal (§8.2) |
| 23 | Firewall conflict appears in Unified Inbox, user resolves → conflict cleared | Inbox integration (§13.1) |
### 14.3 Injection tests [ADDED]
| # | Test | Validates |
|---|------|-----------|
| 24 | User pastes 3,000-token brief → Context Budgeter reduces warm to 0–1 results | Budgeter (§5.3) |
| 25 | Same memory injected turn N; turn N+1 same topic → dedupe prevents re-injection | Turn dedupe (§5.5) |
| 26 | Mistake with matching trigger_pattern injected; non-matching mistake NOT injected | Mistake injection (§2.1) |
### 14.4 Additional verifications
- QMD injection respects caps + timeout + dedupe
- Flush includes referenced_documents with hashes
- Firewall conflicts appear in inbox
- Maturity_history array records all transitions
- Pruning preview surfaces in Unified Inbox with Keep/Archive actions
- Running brief updates incrementally after significant exchanges
- Archived memories are recoverable from Q Memory Browser
---
### 14.5 Relationship Index + Topology Bridge tests [ADDED in Rebuild R1]
| # | Test | Validates |
|---|------|-----------|
| 27 | A `belongs_to_project` edge with a capsule target is valid and queryable | Capsule target compatibility |
| 28 | Old `src_id` / `dst_id` records normalize to the new ref-based schema | Legacy relation migration |
| 29 | A high-degree memory cluster returns at most the configured limit and marks `truncated: true` when appropriate | Bounded traversal |
| 30 | A generalized memory shows `derived_from` and `generalized_into` provenance through the relationship index | Generalization lineage |
| 31 | If current-view rebuild fails, health reports degraded state and queries degrade honestly rather than silently returning empty results | Degraded health honesty |
| 32 | ELNOR Core can ingest DOC1 relation edges into the broader topology layer without replacing DOC1 as the owner of memory-edge truth | Core topology compatibility |
## 15) Codex execution instructions (to prevent drift)
### 15.1 Work plan (must follow)
1) Implement data model changes (§2) and migrations — add usage_stats, maturity_state, maturity_history, recency metadata, mistake fields to all memory records
2) Implement relationship index writer (§4)
3) Implement confidence calibration updates (§2.2) in Context Assembler injection pipeline
4) Implement maturity transitions (§3) with all per-type TTLs
5) Implement QMD injection hook (§5) including turn dedupe, budgeter, and full injection order
6) Implement flush artifacts + preview + post-compaction bridge (§6)
7) Implement CRS capsule ledger + rehydrate UI (§7)
8) Implement firewall with full gate pipeline including dedup + budget check (§8)
9) Implement gap detector + Teach loop + weekly extraction suggestions (§10)
10) Implement deferred queue + nightly loop with all 8 operations (§11–12)
11) Implement running brief + handoff briefs (§12A)
12) Implement Q UI additions (§13) including Learning Dashboard
13) Implement tests (§14) — all 32 tests
14) Produce a `PATCH_REPORT.md` with:
- file list changed
- how to run tests
- where new artifacts live
- how to verify each feature manually
### 15.2 "No drift" guardrails
- Do not invent new paths; use §1.
- Do not add external deps.
- Do not run Q as a writer; all writes via EC.
- Do not inject untrusted content by default.
- Do not exceed budgets.
- Do not delete memories — archive only (C0.6).
- Do not skip the Write Gate for any durable write.
- Positions 1–2 in injection order are reserved for the Freshness Addendum — do not fill them with memory content.
---
---
## 16) Repo implementation map (required for Codex; no new requirements)
**Purpose:** Map this addendum’s requirements onto the *known* monorepo structure so Codex does not invent paths. This section is implementation guidance only; it does not change normative behavior in §§0–15.
### 16.1 Known repo roots (do not invent new top-level folders)
- EC service: `apps/ec-service/src/`
- Q backend: `apps/q-backend/src/`
- Q frontend: `apps/q-frontend/src/`
- Contracts/schemas: `packages/contracts/src/`
- Tests: `tests/`
### 16.2 Contracts/schemas (packages/contracts/src)
Update/extend these existing files:
- `packages/contracts/src/schemas.ts` — extend the memory record schema with: `usage_stats`, `maturity_state`, `maturity_history`, `recency_type/last_verified_at/verification_ttl_days`, and add the `mistake` type fields (§2). Add schemas for new artifacts/records referenced by this addendum as needed (e.g., conflict record lines, gap records, deferred queue records).
- `packages/contracts/src/canonical.ts` — ensure canonical paths referenced in §1.1 are present and used by EC and Q.
- `packages/contracts/src/index.ts` — export any new schemas/types you add.
### 16.3 EC implementation (apps/ec-service/src)
Primary integration points:
- `apps/ec-service/src/server.ts`
- Add/extend command handlers and endpoints needed for: flush preview/generate, flush write, post-compaction integration hooks, conflict queue operations, gap ledger append, deferred queue enqueue/processing triggers, and any new UI-read endpoints required by §13.
- Ensure **all durable writes** required by this addendum occur here (single-writer).
- `apps/ec-service/src/fs-utils.ts`
- Add helper utilities needed for append-only JSONL writes, atomic json writes, and bounded reads used by dashboards (if not already present).
- `apps/ec-service/src/pending-index.ts`
- Extend to support the new pending item kinds required by §13.1 (conflicts, pruning preview, generalization candidates, extraction improvement suggestions), if pending index is the central inbox source in your build.
- `apps/ec-service/src/event-bus.ts`
- Emit compact events for major lifecycle actions (flush created, conflict detected/resolved, gap logged, nightly report available) to drive Q realtime status panels.
### 16.4 Q backend implementation (apps/q-backend/src)
Primary integration points:
- `apps/q-backend/src/server.ts`
- Add/extend routes that Q frontend needs to render the new memory UI surfaces (deep search, flush preview, capsule viewer, learning dashboard cards).
- Route all “write” operations to EC via `/api/commands` (do not write durable memory artifacts from Q backend).
- `apps/q-backend/src/event-streamer.ts`
- If used for realtime feeds, extend to stream memory-related events (conflict created, flush ready, nightly autopilot report) from EC to Q frontend.
### 16.5 Q frontend implementation (apps/q-frontend/src)
Use existing pages/components; add new components under existing folders only.
- Pages likely to extend:
- `apps/q-frontend/src/pages/MemoryPage.tsx` — Memory Browser enhancements (§13.2), deep search, maturity filters, relationship view, view source.
- `apps/q-frontend/src/pages/LearningPage.tsx` — Learning Dashboard (§13.4), gap trend, generalization candidates, calibration views.
- `apps/q-frontend/src/pages/InboxPage.tsx` and `apps/q-frontend/src/components/InboxList.tsx` — Unified Inbox aggregation (§13.1) and new pending item types.
- `apps/q-frontend/src/pages/HomePage.tsx` — home cards for health/lessons/traffic-light status (§13.3).
- Existing components to reuse/extend:
- `apps/q-frontend/src/components/TeachElnorModal.tsx` — Gap detector “Teach” flow (§10.4).
- `apps/q-frontend/src/components/LearningTimeline.tsx` — can be extended for nightly loop/autopilot report history.
- Add new UI components only under:
- `apps/q-frontend/src/components/` (e.g., FlushPreviewEditor, CapsuleViewer, ConflictResolutionCard) — names should stay aligned with existing terminology in this addendum.
### 16.6 Tests (tests/)
Add new tests under `tests/` (and subfolders) consistent with the existing vitest setup:
- Extend `tests/golden/elnor-golden.test.ts` if it is used as an integration harness.
- Add focused unit tests for deterministic logic (confidence calibration, maturity transitions, dedupe, TTL) and integration tests for command handling and artifact writes per §14.
**Important:** If Codex’s current build uses different file names internally, it must map these responsibilities to the *closest* existing modules without changing behavior, naming, or paths described under §1.
**End of addendum v1.11.3-FINAL.**