Skip to content

feat(memory): check: — a checkable fact says how to re-check itself, and add will not let it skip (DIVE-3885) - #757

Merged
5dive-bot merged 2 commits into
mainfrom
dive-3885-memory-check
Sep 1, 2026
Merged

feat(memory): check: — a checkable fact says how to re-check itself, and add will not let it skip (DIVE-3885)#757
5dive-bot merged 2 commits into
mainfrom
dive-3885-memory-check

Conversation

@5dive-bot

@5dive-bot 5dive-bot commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

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:

596  run:    <- session id, stamped AUTOMATICALLY by the consolidate pipeline
  5  task:
  3  sha:
  3  file:
  1  cmd:

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 and valid_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 as no_check:, so an unchecked fact is countable rather than merely absent. A stub reason is refused. memory consolidate passes 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=reference requires one of the two. That is the class of fact that rots. Every other type, and --store=wiki, is unchanged.
  • Two degeneracy guards — the load-bearing part. An enforcement is a field too, and the cheapest way to satisfy it is --check=true. So a check that cannot go red (true, :, exit 0, bare echo/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>&1 stays legal.
  • 5dive memory check [--write] [--slug=] [--timeout=] — dry-run by default; --write stamps check_status / checked_at / check_rc.
  • Recall demotes a stale atom 0.4× and flags ⚠ 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 --delete and nothing here removes or empties a file. And the distinction that makes it safe: a checker that could not run (timeout, command not found) is unknown, not stale — 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.sh55 assertions, PASS=55 FAIL=0, mostly negative controls: the refusal writes no file and no index line; every non-reference type is untouched; 8 degenerate checks refused; 7 non-read-only checks refused; unknownstale; 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:

  1. A live arm through the built binary caught the stale exit code being printed as "exited 1 without reporting a reason … this is a bug in the CLI" by the lib/output.sh backstop — which would have buried the digest a nightly pass exists to produce. Fixed with mark_reported.
  2. A fake HOME does not isolate --store=wiki (_memory_wiki_root falls 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_unit 46/46 (updated — its --type=reference fixtures now take the recorded opt-out), memory_consolidate_unit 71/71, memory_two_stage_recall_unit 33/33, heartbeat_memory_consolidate_unit 54/54, memory_doctor_unit, inherit_memory_unit green. shellcheck -S warning src/cmd_memory.sh surfaces only the three pre-existing warnings.

Not a provisioning-path change; scripts/inc/5dive-cli.sh and the agent-create path are untouched, so no smoke is owed. 5dive-cli is not auto-deploying (deliberate release-cut).

Knowledge compiled: community/wiki/a-field-the-pipeline-can-fill-converges-to-its-autostamp.md + index line.

Two limits, stated

  • The read-only guard is an author-facing degeneracy/foot-gun guard, not a sandbox. It refuses the shapes an author reaches for by reflex (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.
  • The pass is deliberately NOT wired into the heartbeat yet. The fleet currently holds ~0 authored checks, so a nightly cron would be burn over an empty set and would report an empty fleet as a healthy one. That is this row's own sequencing — enforce at write time first, harvest later. Scheduling it is a follow-up once check: has accrued, and it is a two-line addition to the heartbeat tick that already runs memory consolidate.

lodar and others added 2 commits September 1, 2026 17:04
…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
@5dive-bot
5dive-bot merged commit 6ab8b96 into main Sep 1, 2026
41 checks passed
@5dive-bot
5dive-bot deleted the dive-3885-memory-check branch September 1, 2026 19:58
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.

2 participants