feat(memory): check: — a checkable fact says how to re-check itself, and add will not let it skip (DIVE-3885) - #757
Merged
Merged
Conversation
…and add will not let it skip (DIVE-3885) Item 3 of the DIVE-3882 janitor plan needs a field whose exit code re-derives a fact. `--evidence` looked like the substrate (`cmd:` IS a check). The 2026-09-01 census over 2,651 atoms says it is not: 596 atoms carry evidence and 595 are the consolidate pipeline's `run:<session id>` autostamp. TWELVE hand-authored refs exist fleet-wide. Same shape in the lifecycle envelope — `confidence:` (pipeline- fillable) is heavily adopted, `valid_to:` is at zero on every seat. The rule: a memory field with no WRITE-TIME enforcement converges to whatever the autostamp fills in, however well documented. So this is a new authored field that `memory add` enforces where the fact is written. - --check='<cmd>' — read-only, its EXIT CODE re-derives the fact. - --no-check="<why>" — the RECORDED opt-out; the reason lands in frontmatter, so an unchecked fact is countable rather than absent. consolidate passes it, so the pipeline's gap is visible instead of becoming the silent norm. - --type=reference requires one of the two. Other types and the wiki: unchanged. - Two degeneracy guards, the load-bearing part: a check that cannot go red (true, :, bare echo) is refused, and a check that is not read-only (writes, sudo, rm, curl|sh, driving the board, redirect to a file) is refused — the pass runs these unattended. >/dev/null 2>&1 stays legal. - `5dive memory check [--write]` runs them; dry-run by default. Red = stale; a checker that could NOT RUN is `unknown`, never stale. - Nothing deletes. Recall demotes a stale atom 0.4x and flags `check red <date>`. tests/memory_check_field_unit.sh: 55 assertions, mostly negative controls, plus a live arm through the built binary — that arm caught the stale exit code being printed as "this is a bug in the CLI" by the lib/output.sh backstop. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Branch replayed onto current main so the PR head is graded against the tree that will land. Only CHANGELOG.md conflicted (two Unreleased entries added at the top); both are kept. # Conflicts: # CHANGELOG.md
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.
What this is
Item 3 of the DIVE-3882 memory-janitor plan — a
check:whose exit code re-derives a fact, plus a pass that flips it stale. DIVE-3885 exists because it looked buildable on the existing--evidence=<kind>:<ref>, and the measurement says it is not.Why not
evidence:Census of 2,651 atoms across 9 stores, 2026-09-01:
Twelve hand-authored evidence refs exist fleet-wide. The 22.5% adoption figure is arithmetically correct about the pipeline's autostamp, not about authorship. The lifecycle envelope shows the same split:
confidence:(pipeline-fillable) is heavily adopted;supersedes:≈ 0 andvalid_to:0 on every seat — both need an author to know something at write time.The rule this yields: a memory field with no write-time enforcement converges to whatever the autostamp fills in, however well documented.
What ships
memory add --check='<cmd>'— a read-only command whose exit code re-derives the fact.--no-check="<why>"— the opt-out, and it is recorded: the reason lands in frontmatter asno_check:, so an unchecked fact is countable rather than merely absent. A stub reason is refused.memory consolidatepasses it explicitly, so the pipeline's inability to author a check is a visible row in a census instead of silently becoming 99% of the field.--type=referencerequires one of the two. That is the class of fact that rots. Every other type, and--store=wiki, is unchanged.--check=true. So a check that cannot go red (true,:,exit 0, bareecho/printf/date) is refused, and a check that is not read-only (writes,sudo,rm,curl | sh, driving the board, a redirect to a file) is refused — the pass runs these unattended.>/dev/null 2>&1stays legal.5dive memory check [--write] [--slug=] [--timeout=]— dry-run by default;--writestampscheck_status/checked_at/check_rc.⚠ check red <date>. It is never hidden.The row's guardrail, kept mechanical
A red check means the fact is wrong OR the checker is. So the pass flips a flag and prints a digest. There is no
--deleteand nothing here removes or empties a file. And the distinction that makes it safe: a checker that could not run (timeout, command not found) isunknown, notstale— an instrument failure and a false fact are the same shape from the outside, and folding them together is how an automated janitor starts retiring true facts.How it was checked
tests/memory_check_field_unit.sh— 55 assertions, PASS=55 FAIL=0, mostly negative controls: the refusal writes no file and no index line; every non-referencetype is untouched; 8 degenerate checks refused; 7 non-read-only checks refused;unknown≠stale; every file survives the pass with its body verbatim; re-running replaces the stamp rather than duplicating it.Two defects were caught by arms that the sourced-function tests could not see, and both are now regression-covered:
lib/output.shbackstop — which would have buried the digest a nightly pass exists to produce. Fixed withmark_reported.HOMEdoes not isolate--store=wiki(_memory_wiki_rootfalls back to a hardcoded/home/claude/...), so the wiki arm wrote a fixture into the real shared wiki. Cleaned up, harness isolated, and the isolation is now itself asserted.Existing suites re-run green on the merged tree:
memory_evidence_dedup_unit46/46 (updated — its--type=referencefixtures now take the recorded opt-out),memory_consolidate_unit71/71,memory_two_stage_recall_unit33/33,heartbeat_memory_consolidate_unit54/54,memory_doctor_unit,inherit_memory_unitgreen.shellcheck -S warning src/cmd_memory.shsurfaces only the three pre-existing warnings.Not a provisioning-path change;
scripts/inc/5dive-cli.shand the agent-create path are untouched, so no smoke is owed.5dive-cliis not auto-deploying (deliberaterelease-cut).Knowledge compiled:
community/wiki/a-field-the-pipeline-can-fill-converges-to-its-autostamp.md+ index line.Two limits, stated
rm,sudo, a redirect to a file,curl | sh, driving the board). It does not contain a determined author —python3 -c '...'would get past it. That is the right threat model here: the person writing the check and the person running it are the same seat, and the guard exists so a check written in thirty seconds cannot quietly become a scheduled write.check:has accrued, and it is a two-line addition to the heartbeat tick that already runsmemory consolidate.