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