fix(memory): make the Directory Inventory Status column enforceable - #1759
Open
anikinsasha wants to merge 1 commit into
Open
fix(memory): make the Directory Inventory Status column enforceable#1759anikinsasha wants to merge 1 commit into
anikinsasha wants to merge 1 commit into
Conversation
A fresh guided install warns 14 times on every SessionEnd, forever: the inventory marks 20 rows `active` while DeployCore scaffolds 6, and nothing in the release creates the other 14. Six of them are touched by no shipped code at all, so no amount of use can clear them. The Status column is the right axis and it is already there — it is just not enforced. Only the literal `active` produces drift, so every other value grants silence, and a value the row-wide regex cannot match (`dormant archive`) drops the row out of the parse entirely: absent from the missing check AND absent from the unknown-subsystem check, which turns into a spurious `unknown_on_disk` warning on any install that has the directory. - Cells are read positionally so a multi-word status is captured verbatim. - Recognised statuses are `active`, `on-demand`, `reserved`, `pending`; anything else is reported as unclassified, never exempted. - `pending` is new: absence keeps warning while a shipped reader still has no empty state. WISDOM/ and RELATIONSHIP/ are pending for that reason. - Governance rule: no row may be moved into silence while a shipped reader still consumes it, unless the same change gives that reader an empty state. - Rows re-derived against the shipped tree; writer cells that named components with no implementation in the payload corrected or dropped. - The `reserved` definition no longer cites release tooling that is not in the public payload, and moves out of the Class block: it is a Status. - The remedy text no longer proposes reclassifying the row to silence it. Fresh guided install: 14 permanent warnings -> 2, with no directory scaffolded to fake the checker quiet. An upgraded install that already has both trees on disk sees none. DeployCore is deliberately unchanged. 23 tests, bun test, green.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements #1757. Companion: #1758 (PR-A in the tables below).
Takes a fresh guided install from 14 permanent drift warnings to 2, and an
upgraded install that already has its trees on disk to zero — without scaffolding
a single directory to fake the checker quiet.
This is a re-cut, not a rebase. An earlier version of this change added a
separate
Provisioningcolumn. You solved the same problem this release byputting
on-demandinto the Status column, and I think that was the better call:one axis, no new cell for every future row. So this keeps your column and fixes
what is actually wrong with it, which is that it is not enforced.
What changes
LIFEOS/DOCUMENTATION/Memory/MemorySystem.mdreservedrestated self-containedly; governance rule; § Drift Detection prose; changelog entryhooks/handlers/MemoryDirIntegrity.tsskills/LifeOS/Tools/DeployCore.tsThe axis
active(guided setup creates it → absent afterwards is drift → warn) ·on-demand(created on first use → absence is normal → silent) ·reserved(nothing creates or reads it → silent, reason required) ·
pending(see below →warn). Anything else is reported. Silence is only ever granted by an explicit
recognised value, so a row added later without a status is loud rather than
quietly invisible.
The two failure modes this fixes
A typo is currently an exemption. Enforcement is
row.status === 'active'with no allow-list and no else branch, so every other value grants silence.
MemoryDirIntegrity.ts:57still declares the vocabulary as two values while thetable uses four, and the doc's own § Drift Detection prose (
MemorySystem.md:679)describes the same stale pair. Nothing can distinguish a deliberate exemption from
a misspelling.
A status with a space in it removes the row from the check entirely. The row
pattern at
:103anchors the status cell as[\w-]+, which cannot match a space,so the whole line fails to match and is never pushed into
rows. Running thatexact regex against the shipped section yields 27 rows out of 29;
RELATIONSHIP/(dormant archive) is one of the two it drops.That is not silencing in one direction — it is invisibility in both. A dropped row
is no longer checked for absence, and its directory on disk is no longer
recognised, so
:187-192reports it as an unknown subsystem. Every install thathas been running since v6 has
MEMORY/RELATIONSHIP/on disk; at this releasethose installs traded one warning for a different one telling them to add a row
that already exists.
Cells are now read positionally by splitting on
|, so a multi-word status iscaptured verbatim and judged afterwards. An unclassifiable row is reported as
itself rather than disappearing, and its directory stays recognised.
The trap this had to avoid
Reclassifying a row silences the checker, and
on-demandsilences as effectivelyas
reserved.WISDOM/andRELATIONSHIP/both have live readers inLoadContext.hook.ts(:429and:414), and neither reader renders anythingwhen its tree is empty (
learning-readback.ts:165,LoadContext.hook.ts:131both return null). For a fresh install the drift warning is the only signal that
the channel has no data.
So this PR ships a rule —
— and then obeys it: those two rows are
pending, which still warns. The changethat gives each reader an empty state is the change that reclassifies its row.
That is the 2 remaining warnings, and they are a dated debt rather than noise.
The rule is about readers, and the diagnostic the checker prints says the same
word. A writer with no reader produces nothing anyone is waiting for — which is
exactly the case for the rows this PR moves into silence, so a remedy text
saying "reader or writer" would have forbidden the repair this PR performs.
The old remedy text is also part of the problem and is replaced. It read "Either
create it or change the row's status to reserved/on-demand" — the checker
instructing the operator to silence it.
Corrections that go the other way
Two rows the writer cells made look like phantoms are not:
SECURITY/—EventLogger.hook.ts:336-356self-mkdirs and writesSECURITY/YYYY/MM/stop-failures-*.jsonl. The namedSecurityPipeline.hook.tsis what does not exist. Your own Hook Integration table already records the true
writer at
:640, one row above the false one at:642.SYSTEMUPDATES/—ActivityParser.ts:634-644self-mkdirs, andCreateUpdate.tsships publicly as of this release with
IntegrityMaintenance.ts:114pointing atit. That row is correct and is left alone.
Both are
on-demandwith corrected writers, not reserved. Getting these wrongwould have silenced two live subsystems.
Names with no implementation anywhere in the payload are removed from the writer
cells of
OBSERVABILITY/(TeammateIdle,observability-transport,HomeSensorDetector,Speedtest),TEAMS/andSKILLS/. A test pins that.The
reserveddefinition:307defined the status by citingShadowRelease.tsandFLAT_README_ROOTS—a file that has never existed in this repository and a constant declared nowhere —
describing stub READMEs shipping into a
MEMORY/tree the payload has not carriedsince the v6 format change. It is restated self-containedly and moved out of the
Class definitions block, where it did not belong:
reservedis a Status valueand never appears in the Class column. The companion private-references issue
covers the wider class and deliberately does not touch this file, so the rewrite
has one author.
Alternative available on one word
The v8.1 changelog block is your narrative of your own tree, and I have left it
alone entirely in this version. If you would rather it were corrected too — the
"grown organically since v7.x" sentence and the
FLAT_README_ROOTSscaffold claimat
:834are the two lines that read oddly in a public artifact — say so and Iwill add it. Nothing in the mechanism depends on it.
Shared files and rebase expectations
Measured by merging the branches against this base, not by reading the diffs.
hooks/handlers/MemoryDirIntegrity.tsLIFEOS/DOCUMENTATION/Memory/MemorySystem.mdRELATIONSHIP/row of the table this PR rewrites. Land B first and E becomes a one-cell change.Resolving the PR-A conflict. Two hunks, and neither is either/or. In the type
block, A adds the
DriftItemdocstring andkeyfield and this PR adds thestatus sets: keep both. In the handler, A keeps its findings inline while this PR
extracts them into a pure
computeDrift(): keepcomputeDrift(), and carry A'skeyfields into its pushes —unknown_on_disk:<dir>,missing_active:<NAME>,unrecognised_status:<NAME>,inventory_unparseable:<class>.Taking this PR's side verbatim drops every finding key, which is the identity A's
SessionStart readback compares to decide whether anything changed. Both suites
stay green either way — mine does not know about keys, A's tests the readback
rather than this handler — so a typechecker is what catches it, not
bun test.Co-requisite: PR-D. It is the change that gives
WISDOM/its visible emptystate, and its rebase onto this PR flips that one cell from
pendingtoon-demand. Landing B without D leaves the warning standing, which is correct butnoisy; landing D without B is fine.
Tests
hooks/handlers/MemoryDirIntegrity.test.ts— 27 cases,bun test, green.Including the shipped table itself: every row carries a recognised status, exactly
the six
DeployCoredirectories areactive, a fresh install after setupproduces exactly one finding per
pendingrow, and an upgraded install carryingboth pending directories produces none at all.
Four cases pin the two failure modes above directly — a status with a space is
read verbatim rather than dropped; an unrecognised status is reported even when
the directory exists; one row yields at most one finding; and a row the parse
could not classify keeps its directory recognised, so the
unknown_on_diskinversion cannot come back.
Nothing hard-codes which rows are
pending. The set is read off the table, andone assertion pins the table against the governance paragraph that explains it. A
pendingrow is a debt cleared by the release that gives its reader an emptystate, so the set shrinks by design: pinning the names would have made doing that
correctly break this suite while forgetting it cost nothing, which is the wrong
way round. PR-D's and PR-E's flips are the first two instances, and both bodies
say which sentence they touch. Additive and separable — this repository ships no
tests today.