Q&A and Accumulated Knowledge Persist to NCL, Not Browser Storage
Accepted
Context
The initial Q&A bookmarks feature stored entries in browser localStorage keyed by project. This is convenient but violates the dag-formalized axiom: knowledge that lives only in a browser session is invisible to agents, not git-versioned, not queryable via MCP, and is lost on browser data reset. The same problem applies to quick actions and any other accumulated operational knowledge. The system accumulates knowledge during development sessions (AI interactions, architectural reviews, debugging) that should be first-class artifacts — not ephemeral browser state.
Decision
All Q&A entries persist to `reflection/qa.ncl` — a typed NCL record file governed by `reflection/schemas/qa.ncl`. Mutations happen via `crates/ontoref-daemon/src/ui/qa_ncl.rs` (line-level surgery, same pattern as backlog_ncl.rs). Four MCP tools expose the store to AI agents: `ontoref_qa_list` (read, with filter), `ontoref_qa_add` (append), `ontoref_qa_delete` (remove block), `ontoref_qa_update` (field mutation). HTTP endpoints `/qa-json` (GET), `/qa/add`, `/qa/delete`, `/qa/update` (POST) serve the UI. The UI renders server-side entries via Tera template injection (SERVER_ENTRIES JSON blob), eliminating the need for a separate fetch on load. The same principle is applied to quick actions: they are declared in `.ontoref/config.ncl` (quick_actions array) and new modes are created as `reflection/modes/<id>.ncl` files via `ontoref_action_add`.
Constraints
- Hard All mutations to reflection/qa.ncl must go through crates/ontoref-daemon/src/ui/qa_ncl.rs — no direct file writes from other call sites
- Hard reflection/qa.ncl must conform to the QaStore contract from reflection/schemas/qa.ncl — nickel typecheck must pass
- Hard MCP tools ontoref_qa_list and ontoref_qa_add must never trigger sync apply steps or modify .ontology/ files
Alternatives considered
- Keep localStorage as the storage backend, add optional sync to NCL on explicit user action — rejected: Two sources of truth creates sync complexity and divergence. AI agents would still not see localStorage entries. The sync step would be frequently skipped. NCL as primary is simpler.
- Store Q&A in SurrealDB via stratum-db (existing optional dependency) — rejected: Requires the db feature and a running SurrealDB instance. NCL files are always present, git-versioned, and work without any database. The protocol-not-runtime axiom argues for file-first. SurrealDB can be added as a secondary index later if full-text search is needed.
- Full AST parse of qa.ncl via nickel-lang-core for mutations — rejected: nickel-lang-core has an unstable Rust API. The file structure is predictable enough for line-level surgery. backlog_ncl.rs has been operating safely with this pattern. Adding a hard dependency on nickel-lang-core for a file that is always written by the daemon is unnecessary complexity.