Skip to content

feat(knowledge): settle §6.2 — supersession computed, because newer-wins is false on the real library - #90

Open
guyettinger wants to merge 6 commits into
mainfrom
feat/knowledge-layer-seam
Open

feat(knowledge): settle §6.2 — supersession computed, because newer-wins is false on the real library#90
guyettinger wants to merge 6 commits into
mainfrom
feat/knowledge-layer-seam

Conversation

@guyettinger

Copy link
Copy Markdown
Owner

Settles docs/research/persistence-layers.md §6.2, the one question PR #89 deliberately left open: whether DeskRAG gets a persisted Knowledge layer with supersession chains that survive a re-index, or stays derived.

It stays derived, and the reason is a measurement rather than a preference.

The paper's rule is false on this library

Roynard's Knowledge is append-only and updated by supersession — newer claim wins, older marked superseded. Read off the real store (SQLite read-only, 12 recordings, 2026-08-17 → 2026-08-29):

event occurrences distinct payloads actual configurations
keymap_change 12 1 1
display_change 12 8 2

Seven of the eight display payloads are the same 1920×1080@2 primary carrying a different id every session (180, 185, 206, 219, 247, 296, 297) — macOS re-mints the identifier, so id is a decoy and geometry is what discriminates. The eighth is a genuine two-display setup.

Three consequences, and each one killed a design:

  1. A stored superseded_by keyed on the observed identifier would have minted 8 facts where there are 2 — the first table wrong on the first data it ever saw.
  2. The two real configurations do not supersede one another. A laptop is docked some days and not others; "newer wins" would delete a configuration that is still true.
  3. Deciding whether display 180 and display 185 are the same display is entity identity — which makes it a prerequisite of all three Knowledge candidates, not the second of three. That reordering is recorded, because it is the part a future session would otherwise re-derive.

keymap_change makes the opposite point just as sharply: one distinct payload across twelve recordings, so there is nothing to supersede at all.

The decision

Knowledge is DERIVED_LIBRARY_TABLES when it eventually has a table. The paper is append-only only because its system does not retain the evidence — an agent learns a fact from a conversation and the conversation is gone. CAPTURED_TABLES is exactly that retained evidence, and its defining property is that a re-index must never touch it. Re-derivability is free here, so the expensive side would have bought a property this store does not need at the price of the re-index invariant.

Supersession is computed; exclusivity is declared per fact TYPE. Every distinct value is kept with its sources, the type says whether its values can coexist, and current is answered per query and stored nowhere — the storage/query litmus from PR #89 applied to itself, since a stored edge is a storage-level commitment to a ranking.

What ships

src/knowledge/facts.ts — one leaf module, zero imports, no clock read. Ordering across recordings arrives injected as (sessionId) => number | undefined, on the EdgeRecency / RecencyOptions precedent, because t_mono restarts every session and session.started_at is joined at query time.

currentValue() ranks a value by its latest source, not its first, on the composite started_at + t_mono so two observations inside one recording still order. It refuses four ways, each an answer rather than an error:

  • a coexisting fact has no current value — the answer is the set;
  • a tie declines, on bindHabit's precedent;
  • a fact no recording can date says so, and undatable sources are counted beside a ranking that still stands — stabilityOf's undefined-vs-[] rule;
  • an empty fact answers instead of throwing.

Counts only, never a ratio — asserted in a test, not merely stated. A percentage here would be FrameResult.score under a new name.

It deliberately does not decide whether two values are the same value. Fed those eight display payloads it reports eight. That is the seam, not a defect: it makes the case legible as an identity problem instead of silently mis-keying it, which is precisely what a stored edge would have done while looking correct.

No table

No schema.ts edit, no sixth bucket, no stage, no UI, no MCP tool. This is cycle 0 — the invariant — following the src/trace/stability.ts pattern exactly, where the omission of storage is the design.

Testing

13 tests in test/knowledge.current.test.ts: the exclusive path (5) and every refusal (7), plus a barrel check. npm run typecheck, npm test (2379 passed / 16 skipped) and npm run build all pass — the build matters specifically here, since the app imports dist/ and a barrel export that does not survive it stays invisible until a later cycle needs it.

Docs

persistence.md's "The decision left open, on purpose" becomes "The decision, made 2026-09-04", carrying the measurement rather than the conclusion alone. §6.2 is marked settled, and CLAUDE.md gains the rule.

Two stale claims the settlement created were also corrected: CLAUDE.md's stability bullet still ended "that call is left open deliberately," and persistence.md's section intro named stability.ts as the only thing existing instead of a store. Both are paraphrases, so the planned grep would not have caught either.

Also re-verifies the preprint the whole line of work rests on: it was cited here from v1, arXiv now serves a v2 revised 2026-06-12, and every load-bearing figure is unchanged — including the keyword-router reversal (Δ = −0.125), which is the argument for deriving a tier rather than storing one, and the core threshold of three independent sessions, which is CORE_SESSIONS.

What would reopen this

A fact type whose evidence is genuinely not retained; a rebuild that cannot reproduce a fact in session order; or a measured need for a stored edge.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KNMAPpjspVHJU1kiuRpcba

guyettinger and others added 6 commits September 4, 2026 21:16
`docs/research/persistence-layers.md` §6.2 recorded one question as
deliberately open: whether a Knowledge layer is persisted append-only --
the first state in this store that is neither rebuildable nor authored --
or stays derived. The doc required that it be decided deliberately rather
than as a side effect of the first table. This is the decision, and no
table.

THE SOURCE IS RE-VERIFIED FIRST, because code had shipped on it. The
preprint was cited here from v1; arXiv now serves a v2 revised 2026-06-12,
and `06c5a57` shipped on v1's numbers in between. Every figure this repo
built on is unchanged in v2 -- the pilot table, the CI and McNemar p, and
the two that are load-bearing: the keyword-router reversal (delta -0.125),
which is the whole argument for deriving a tier rather than storing one,
and the three-session *core* threshold that is `CORE_SESSIONS`. A preprint
can be revised out from under a citation; this one was not.

MEASURED ON THE REAL LIBRARY, AND IT DECIDED BOTH HALVES. 12 recordings,
SQLite read-only: `keymap_change` is 12 occurrences and ONE distinct
payload, so nothing supersedes anything and the chain a naive design would
build is length 1. `display_change` is 12 occurrences and EIGHT distinct
payloads -- but only TWO configurations. Seven of the eight are the same
1920x1080@2 primary with a DIFFERENT `id` every session (180, 185, 206,
219, 247, 296, 297); the eighth is a real two-display setup. macOS re-mints
the identifier per session, so `id` is a decoy and geometry discriminates.

Three things follow. Keying supersession on the observed identifier would
have minted eight facts where there are two -- the first table wrong on the
first data it saw. The two real configurations do NOT supersede one another;
a laptop is docked some days and not others, so "newer wins" would delete a
configuration that is still true. And deciding whether display 180 and 185
are one display IS entity identity, which is therefore a PREREQUISITE of
every candidate rather than the second one: "is this the same display",
"is this the same document", "is this the same app version" are one question.

DECISION ONE -- `DERIVED_LIBRARY_TABLES`, not a sixth bucket. The paper is
append-only because its system does not retain the evidence; a conversation
is gone. `CAPTURED_TABLES` is exactly that retained evidence, and a re-index
must never touch it -- so re-derivability is free here and the paper's
reason does not transfer. A fact outliving the deletion of its evidence is
already precedented and needs no new rule: `removeSession` does not rebuild
the graph, `observations` survives while `sources` thins, and `stabilityOf`
already separates `undefined` from `[]`.

DECISION TWO -- exclusivity is per fact TYPE, and supersession is COMPUTED.
The paper's update mechanism and this repo's §7 decline of contradiction
resolution collide on the display data, and the paper's rule loses. Every
distinct value is kept with its sources; a type declares whether its values
can coexist; "current" is answered per query and stored nowhere. That is
the storage/query litmus applied to itself -- a stored `superseded_by` edge
is a storage-level commitment to a ranking.

The spec ships the contract only: `src/knowledge/` as a leaf, ordering
INJECTED because `tMono` restarts per session and `started_at` is joined at
query time, and a resolver that refuses three ways -- `coexisting` has no
current value, a tie declines on `bindHabit`'s precedent, and undatable
sources are disclosed. Counts only; a percentage would be `FrameResult.score`
renamed.

WHAT IT DELIBERATELY DOES NOT DO is decide whether two values are the same
value. Fed the real display data it reports eight, not two. That is the
seam: it makes the display case legible AS an identity problem instead of
silently mis-keying it, which is what a stored edge would have done while
looking correct.

Cycle 0 of four. No table, no bucket edit, no stage, no UI, no MCP tool.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KNMAPpjspVHJU1kiuRpcba
Four tasks, each with its own test cycle and commit: the contract and the
exclusive ranking, the three refusals, the barrel export, and the docs that
settle §6.2 where a future session will actually find them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KNMAPpjspVHJU1kiuRpcba
The Knowledge layer as typed semantics: a fact is a kind and its distinct
observed values, each carrying the recordings that saw it. Ordering across
recordings is INJECTED, because t_mono restarts every session and
session.started_at is joined at query time -- the same shape EdgeRecency
takes, and for the same reason. Nothing here reads a clock.

A value ranks by its LATEST source, not its first, and the composite is
started_at + t_mono so two observations inside one recording still order.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KNMAPpjspVHJU1kiuRpcba
… real data

A coexisting fact has NO current value and says so. Measured on the real
library: display_change is 12 occurrences and 8 distinct payloads but only
TWO configurations, and the two do not supersede one another -- a laptop is
docked some days and not others, so "newer wins" would delete a
configuration that is still true. The answer is the set.

A tie DECLINES, on bindHabit's precedent. A fact no recording can date says
that rather than guessing, and undatable sources are counted beside a
ranking that still stands -- stabilityOf's undefined-vs-[] rule.

Every path states a reason and returns counts. No fraction anywhere.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KNMAPpjspVHJU1kiuRpcba
Placed beside stabilityOf, which it is the companion of: both are the
paper's semantics as a pure function over evidence the store already holds,
and neither stores anything.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KNMAPpjspVHJU1kiuRpcba
persistence.md's "decision left open, on purpose" becomes the decision:
DERIVED_LIBRARY_TABLES when Knowledge has a table, supersession computed
rather than stored, exclusivity declared per fact type. The reasoning that
matters is the measurement, so it travels with the rule -- 8 display
payloads for 2 real configurations, because macOS re-mints the display id
every session.

That measurement also reordered the remaining cycles: entity identity is a
PREREQUISITE of every Knowledge candidate, not the second of three.

Also corrects two claims the settlement made stale: CLAUDE.md's stability
bullet still said the call was left open, and persistence.md's section
intro named stability.ts as the only thing that exists instead of a store.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KNMAPpjspVHJU1kiuRpcba
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant