DOC2 ELNOR_FRESHNESS_MANAGER_ADDENDUM_v1_11_4 copy.md
Current Specs/DOC2/DOC2 ELNOR_FRESHNESS_MANAGER_ADDENDUM_v1_11_4 copy.md
ELNOR REPO READER TEXT MIRROR
Original path: Current Specs/DOC2/DOC2 ELNOR_FRESHNESS_MANAGER_ADDENDUM_v1_11_4 copy.md
Source repo: /Users/OpenClaw1/Elnor/Elnor Specs
Git branch: main
Git commit: dbaa25962edc11ab30e8d4ca1715f9ae5bf77331
Generated: 2026-06-09T01:23:58.539Z
---
# ELNOR Suite — Freshness Manager Addendum v1.11.4 (Patch-on-top)
Generated: 2026-02-23
Status: Normative patch addendum — implement on top of the running repo
## 0) Spec pinning (non-negotiable)
Canonical spec files used (SHA256):
- ELNOR_CORE_SPEC_v1_11_2_CANONICAL.md
a1a23894dae7bbe93af868d02204896d887b2c2d1afd7b63a66a1c4468c81571
- Q_DASHBOARD_SPEC_v1_11_2_CANONICAL.md
f24788fbade9788a30df7e1d5546d14ac65e9464abd8cef84a9e4b4112405fa3
- ELNOR_BUILD_PROMPT_v1_11_2_WITH_UI.md
23065621fb9d28dbfad80318cec0975ef9959419955e12b3f5d85b797364aef0
- Q_UI_DESIGN_SPEC_v1_11_2_UPDATED.md
1d86f08acbd7e40aeffbd98d15d9936d8f1942740043f7a3ada2de2df123b555
- q-mockup-v11.7m.jsx
508aaef7022a73d5a92beb83791196a38e512799f5dc06463e4c3d0397691e77
## 1) Non-negotiables (binding)
- EC is the sole durable writer. All durable changes occur via append-only commands that EC validates and applies.
- Q never writes durable state. Q submits commands and renders state, with a unified approvals inbox.
- No drift. Use canonical specs + patch addenda only. No redesign. No “helpful” renaming. No new terminology.
- Local-first. Remote access via Tailscale; read-only by default; token auth with rotation/revocation.
- Emergency stop via canonical STOP request file (no changes in this addendum).
- Spec pinning required at top of addendum + readiness report (this section).
## 2) Problem
LLMs can be stale. The system does not automatically web-search for time-sensitive information (news/prices/weather/sports/legal updates/local rules/deadlines), causing stale answers and dead links.
## 3) Goal (Freshness Manager)
Add a robust freshness subsystem aligned to single-writer + taint rules + UI anti-drift:
- Model Capability Registry: knowledge_cutoff_date + tool support flags.
- Always-on Recency Layer: inject “today’s date/timezone” + model cutoff + freshness policy (bounded).
- Deterministic Recency Router (pure function) classifies when search is required.
- EC-level Search Executor (provider pluggable), so freshness works even if model cannot tool-call.
- Verified Facts Cache with TTL + verified_as_of; facts stored as durable EC artifacts.
- Staleness metadata: last_verified_at on derived facts; stale badges; “Verify now”.
- Q UI: freshness pill / stale banner + “Update with latest search”; show evidence + verified-as-of.
- Learning loop (approval-gated): log stale corrections + outcomes; propose standing rules; never auto-promote low-trust sources.
## 4) Hard budgets (defaults unless canonical specs override)
- Max 2 search attempts per user query.
- Max 10s per attempt (hard timeout).
- Max 5 sources fetched per attempt.
- Freshness context injection cap: 800–1200 tokens (default cap = 1000).
- No raw pages in prompts. Inject only summaries + evidence handles.
- TTL defaults by category must be explicit and stored on each record.
## 5) Durable artifacts (EC-owned)
All durable artifacts are EC-owned and stored under ELNOR_MEMORY.
### 5.1 Locations (canonical paths)
Add new canonical paths in `packages/contracts/src/canonical.ts`:
- ELNOR_MEMORY/system/freshness/model_registry.json
- ELNOR_MEMORY/system/freshness/freshness_policy.json
- ELNOR_MEMORY/system/freshness/source_tiers.json
- ELNOR_MEMORY/system/freshness/search_runs.jsonl
- ELNOR_MEMORY/system/freshness/verified_facts.jsonl
- ELNOR_MEMORY/system/freshness/verified_facts_index.json
### 5.2 Records
#### SearchRunRecord (append-only JSONL)
Fields (minimum):
- id
- query, normalized_query
- router_decision (must_search / should_search / no_search)
- category
- retrieved_at, verified_as_of
- sources[]: url, title, tier, evidence_excerpt (capped), excerpt_hash
- result_summary (capped)
- ttl_days, expires_at
- status (ok/timeout/budget_exhausted/offline/error)
#### VerifiedFactRecord (append-only JSONL)
Fields (minimum):
- fact_id
- topic_key
- fact_text (short)
- fact_summary (short)
- verified_as_of
- sources[] with tier + capped snippet + snippet_hash
- ttl_days, expires_at
- confidence (high/medium/low)
- tags[]
- provenance (search_run_id, source_urls[])
- content_hash
#### Index (derived; EC only; atomic rewrite)
`verified_facts_index.json` maps:
- topic_key → latest_fact_id (prefer non-expired)
- fact_id → (optional) offsets/metadata (implementation choice)
## 6) Pure logic (Deterministic Recency Router + normalizer)
Implement in `packages/contracts/src/freshness.ts` (pure functions; testable; no I/O):
### 6.1 routeRecency(input) → { decision, category, reasons[] }
- MUST_SEARCH for:
- explicit recency terms: today / yesterday / tomorrow / latest / current / right now / this week / as of / recently / breaking / update
- inherently time-sensitive categories: news, sports schedules/scores, weather, prices/availability, current office-holders/leadership, software docs/version behavior, elections/voting procedures
- legal_mode + local rules / filing requirements / deadlines / court calendars / recent case law
- SHOULD_SEARCH for:
- “find/link/source” requests where user did not paste a URL
- ambiguous “recent” without explicit timeframe
- NO_SEARCH otherwise (default)
Router must be a pure function and MUST NOT use an LLM.
### 6.2 normalizeTopicKey(text) → topic_key
Deterministic normalizer:
- lowercase, strip punctuation
- drop stopwords
- expand common abbreviations (FRCP/CCP/CPLR, SDNY/CDCA, etc.) where safe
- sort tokens
- topic_key = sha256(tokens.join(" "))
### 6.3 TTL defaults by category (stored per record)
Defaults (policy-configurable):
- news: 1 day
- sports: 1 day
- weather: 1 day
- prices/availability: 3 days
- software docs: 21 days
- office holders/leadership: 30 days
- legal local rules/procedures: 90 days
- statutes (text): 180 days
- evergreen/historical: null (no expiry)
## 7) EC changes (apps/ec-service)
### 7.1 Modify existing files (real repo paths)
- apps/ec-service/src/index.ts
Ensure freshness directories/files exist on startup; load policy/registry/tiers.
- apps/ec-service/src/fs-utils.ts
Add helpers: sha256(str|bytes), readJsonOrDefault(path, default), readJsonlTail(path, maxLines)
- apps/ec-service/src/server.ts
Add:
- Command handlers (append-only + validated)
- Read-only API endpoints for policy/registry/facts/runs
- apps/ec-service/src/event-bus.ts
Emit events for freshness verify actions (optional; keep compact)
### 7.2 Add new files
- apps/ec-service/src/freshness-redact.ts
Deterministic redaction for outbound queries (strip tokens/api keys/local paths).
- apps/ec-service/src/freshness-executor.ts
Search provider interface + default provider implementation; hard budgets enforced.
- apps/ec-service/src/freshness-cache.ts
Cache read/write helpers for SearchRun + VerifiedFact + derived index maintenance.
### 7.3 EC commands (via /api/commands)
Add command_type handlers in EC server:
- freshness_set_policy
- freshness_set_model_registry
- freshness_set_source_tiers
- freshness_verify_now (query + model_id; optional force_search)
- freshness_verify_fact (topic_key + claim_text + model_id)
All durability happens in EC:
- append SearchRun / VerifiedFact JSONL
- atomically rewrite index json
- record command_results
### 7.4 EC read-only endpoints (for Q rendering)
Add read-only endpoints:
- GET /api/freshness/policy
- GET /api/freshness/model-registry
- GET /api/freshness/verified-facts?topic_key=...
- GET /api/freshness/search-runs?id=... (or list/limit)
## 8) Q backend changes (apps/q-backend)
Q backend must not write any freshness durable state.
### 8.1 Modify files
- apps/q-backend/src/server.ts
Integrate freshness orchestration into the chat flow:
- Always inject a tiny Temporal Context block.
- Call router (pure) and, when needed, request EC freshness verification.
- Inject only summary + evidence handles (no raw pages).
- Attach FreshnessMeta to response payload for UI.
### 8.2 Add file
- apps/q-backend/src/freshness.ts
Glue module that:
- calls routeRecency()
- calls EC commands/endpoints
- composes bounded freshness injection text
### 8.3 Verify Now endpoint
Add (or extend existing patterns) a route that triggers a forced verify:
- POST /api/freshness/verify-now { text, model_id, ... }
→ Q backend calls EC freshness_verify_now(force_search=true) and returns updated freshness evidence (and optionally triggers regenerate behavior per existing chat design).
## 9) Q frontend UI (apps/q-frontend)
### 9.1 Add components
- apps/q-frontend/src/components/FreshnessPill.tsx
- apps/q-frontend/src/components/StaleWarningBanner.tsx
- apps/q-frontend/src/components/FreshnessDetailsModal.tsx
### 9.2 Modify pages and API
- apps/q-frontend/src/api.ts
Add API calls for verify-now and evidence fetch.
- apps/q-frontend/src/pages/ChatsPage.tsx
Render pill per assistant message + stale banner when applicable.
- apps/q-frontend/src/pages/SettingsPage.tsx
Add “Knowledge Freshness” controls backed by EC commands:
- auto_search_enabled
- legal_research_mode
- injection_token_cap (bounded)
- provider selection (optional)
UI requirements:
- show verified-as-of date/time
- show “Verify now” for stale/unverified
- show evidence list (sources + capped snippets)
- do not redesign navigation or rename existing routes
## 10) Security & privacy
- Redact secrets/identifiers in outbound search queries (tokens, API keys, local paths).
- Prefer high-trust sources; allowlist/tier by category if possible.
- Never store secrets in caches.
- Never store raw HTML pages; store only capped excerpts + hashes + URLs/titles.
- No raw pages injected into prompts.
## 11) Acceptance tests (tests/)
Add tests under tests/ (vitest):
- tests/freshness/recency-router.test.ts
- tests/freshness/topic-key.test.ts
- tests/freshness/ttl.test.ts
- tests/freshness/cache.test.ts
- tests/freshness/redact.test.ts
- tests/freshness/executor.test.ts (mock fetch; enforce budgets)
Coverage must include:
- deterministic router classifications
- token/secret redaction
- TTL expiry behavior
- caching: hit vs miss
- hard caps: attempts, timeout, max sources
- injection size cap (approximate by bytes/chars)
## 12) Readiness report updates (BUILD_REPORT.md)
Append section “Freshness Manager v1.11.4” containing:
- the SHA256 pins (from §0)
- file inventory (modified/added)
- tests added + passing
- smoke checks:
1) “weather in Los Angeles today”
2) “latest Apple CEO” (time-sensitive office-holder)
3) evergreen question (no search)
4) force Verify Now on a stale answer