Skip to content

feat: retire stale absence claims — anchoring, contradiction rule, revisit: dates - #9

Merged
aoc81 merged 2 commits into
mainfrom
feat/revisit-and-contradictions
Sep 30, 2026
Merged

aoc81 merged 2 commits into
mainfrom
feat/revisit-and-contradictions

Conversation

@aoc81

@aoc81 aoc81 commented Sep 30, 2026

Copy link
Copy Markdown
Owner

Summary

A learning like "No database backup exists; the owner accepted the risk for now" goes stale the day someone adds the backup. On 0.5.2, nothing reliably retired it:

Moment Result on 0.5.2 (files: [])
Session adds a nightly backup (prompt) old entry surfaces ✅
Editing docker-compose.yml nothing
/lore:lint, --report, /lore:sweep nothing (no anchor to check)
Later: "do we have a backup?" stale entry served as current ❌
Agent writes a new "nightly backup" entry both surface, both current ❌

1. Anchoring and contradictions (8d41dcc)

  • The skill now asks for an absence claim's files: to point at where the change would land (a directory or glob). The same simulation with files: [docker-compose.yml, scripts/] surfaces the entry at edit time and gets flagged by drift triage after the commit.
  • When a new learning contradicts an entry listed by the overlap check, the old entry is set to status: superseded with a banner pointing to the new one. This rule is in the skill and also in the overlap check's own output, because that output is what the agent is reading at that moment.

2. revisit: YYYY-MM-DD (7c2d2cf) — the date a decision taken "for now" must be re-decided. From that date, for live entries:

  • Recall marks the entry ! revisit due since <date>.
  • /lore:lint --report lists it, so /lore:sweep picks it up.
  • /lore:stats counts it.
  • An unreadable revisit: value is reported by the default lint.

Bumping verified: on or after the date clears it, the same way verified: clears drift. Retired entries are ignored.

Test plan

  • New tests cover the revisit logic, the recall flag (live entries only, plus a hook-level case), the report and stats output, the value check, the README example and the overlap-check rule. All fail on main.
  • python -m unittest discover -s tests: 211 passed, 1 skipped. claude plugin validate .: passed.
  • Re-ran the backup scenario end to end: the flag shows in recall, the entry is listed in --report, and the contradiction rule appears in the overlap check.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DMXx6BJswH6xiwdqrwQnEf


Generated by Claude Code

A learning that states an absence -- "no database backup exists; the owner
accepted the risk for now" -- goes stale the day someone adds the backup, and
lore had no path that reliably retired it. Simulated on 0.5.2:

    entry written with files: []      (nothing to point at: the thing is absent)
    session adds a nightly backup     prompt recall shows the old entry
    edit docker-compose.yml           edit-time recall: nothing
    /lore:lint, --report, /lore:sweep nothing -- no anchor to check
    later: "do we have a backup?"     the stale entry, served as current
    new "nightly backup" entry added  both surface, both `current`

Two places decide the outcome, and both now say so:

- Authoring: an absence claim points `files:` at where the change would land
  (a directory or glob). The same simulation with
  `files: [docker-compose.yml, scripts/]` surfaces the entry at edit time to
  whoever adds the backup, and drift triage flags it after the commit.
- Capture: when the overlap check lists an entry that the new learning
  contradicts, the old one is set to `status: superseded` with a banner to the
  new authority instead of staying live beside it. This is in the skill and,
  because that is the moment the agent is looking at the old entry, in the
  overlap check's own output (which only spoke of near-duplicates).

Tests: the overlap check's output names the contradiction rule (fails before).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DMXx6BJswH6xiwdqrwQnEf
"No database backup exists; the owner accepted the risk for now" is true the
day it is written and carries its own expiry -- but lore had no way to hold
that "for now". The only time-based signal is the generic age flag, which
starts after `staleAfterMonths` (default 6) whatever the decision said.

`revisit: YYYY-MM-DD` records the date a temporary decision or accepted risk
must be re-decided. From that date, for live entries:

- recall (prompt and edit time) marks the entry `! revisit due since <date>`,
  so a stale "no backup" is no longer served as plain current guidance;
- `/lore:lint --report` -- the worklist /lore:sweep reads -- lists it in a
  "Revisit due" section, whether or not its code moved (silent when nothing
  is due; most stores will never use the field);
- `/lore:stats` counts it; the default lint mode reports an unreadable value,
  since a revisit date nobody can parse is a reminder that never fires.

Re-verifying the claim on or after the date (bumping `verified:`) clears it,
the same way `verified:` clears drift triage; if the decision is still
temporary, the sweep sets a new `revisit:`. Retired entries are ignored.

Documented in the skill (frontmatter, authoring, "when the code changes
later"), the README format example and authoring notes, the entry template,
and the lint/stats/sweep commands.

Tests: due/not-due/re-verified/malformed dates, iter_entries, the recall flag
(live only) and a hook-level case, the report section and the stats count,
the value check, and the README example parsing its new field. All fail
without the change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DMXx6BJswH6xiwdqrwQnEf
@aoc81
aoc81 merged commit 694922f into main Sep 30, 2026
6 checks passed
@aoc81 aoc81 mentioned this pull request Sep 30, 2026
2 of 3 tasks
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