Skip to content

feat: authoritative CHANGELOG.md action ledger — gate-on-write + reconcile-on-read (S2–S7) - #46

Merged
rmsharp merged 9 commits into
KJ5HST:mainfrom
rmsharp:feat/changelog-authoritative-ledger
Jul 8, 2026
Merged

rmsharp merged 9 commits into
KJ5HST:mainfrom
rmsharp:feat/changelog-authoritative-ledger

Conversation

@rmsharp

@rmsharp rmsharp commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

What & why

Makes CHANGELOG.md a dependable cross-source action ledger — the authoritative answer to "what was done here, ever?" across the three sources the operator named: backlog items, repository issues, and ad-hoc work. Originates from an operator request to depend on CHANGELOG.md as that summary. Ratified plan (fork-main-only): docs/planning/changelog-authoritative-ledger-gate-plan.md (1710e90), decisions D1–D7.

The central finding

A close-out write-gate alone is not dependable. An adversarial dependability pass returned is_dependable: false: eight high-severity escape paths let an action land in git history with no ledger entry (ghost/crashed session, out-of-band commit, in-progress hand-off, absent-CHANGELOG adopter, canonical repo has no runner to gate on, non-commit actions, multi-commit sessions, checklist self-exemption). Fix = two mechanisms, not one: gate-on-write (close-out) and reconcile-on-read (Phase 0 backfill). Reconcile is the keystone — it makes the ledger true when you read it.

Components (one session each — strict 1-and-done)

Dogfood

git config core.hooksPath .githooks is live in the canonical repo, and the commit that ships the hook was gated by the hook and passed because CHANGELOG.md was co-staged. The root CHANGELOG.md records this campaign as one [ad hoc] entry.

Verification

  • bin/tests.sh 51/51; dashboard 35 fixture assertions (S5); hook 14 behavior tests incl. live block on the real repo + --no-verify bypass + the grep -qxF regex-metachar regression (S7).
  • Every session ran an adversarial refute-default verification workflow. S7's raised 9 → 4 confirmed: hook regex-dot let-through (fixed, -qxF), BOOTSTRAP First-Session-Checklist ledger gap (fixed), --amend friction (documented), tutorial worked-transcript staleness (deferred — see below).
  • Reconcile frontier = HEAD (no self-inflicted false-positive); audit grep enumerates all 7 root-ledger entries one-tag-each; FM count = 27, "17 warning signs", "12 quality gates", "four session types" all unchanged.

Deliberately NOT in this PR

🤖 Generated with Claude Code

rmsharp and others added 8 commits July 7, 2026 13:19
…ledger gate (S2)

Component A of the authoritative-CHANGELOG campaign (ratified plan
docs/planning/changelog-authoritative-ledger-gate-plan.md, D1–D7): a
write-time hard gate that forces every session to record its actions in the
authoritative CHANGELOG.md ledger at close-out.

- New failure mode FM KJ5HST#27 "Unrecorded action" (APPENDED; FMs 1–26 unchanged,
  not renumbered) + a paired Degradation-Detection row.
- New first bullet in SESSION_RUNNER §3F and a rewrite of
  ITERATIVE_METHODOLOGY Phase 6 step 8: append one dated, source-tagged entry
  per action ([issue #<N>] · [BL-<N>] · [ad hoc]) before commit; remove a
  completed BACKLOG.md item in the same commit; self-provision the ledger from
  the bootstrap seed if absent (D3) — the only opt-out is a CLAUDE.md-recorded
  "no CHANGELOG" decision.
- Keys on "authored/retained a commit OR took a non-commit action" (D2/D4),
  never "completed units only"; "too small to log" IS the failure mode, not an
  exception; anti-erosion clause ties it to FM KJ5HST#17.

Learning KJ5HST#7 count reconciliation (same commit): "26 → 27 failure modes" at 8
live sites + CLAUDE.md renumber clause (1–25 → 1–26); "16 → 17 warning signs"
in README. Dated history (§What's New, §Versioning, docs/planning) left verbatim.

Verified via a 6-lens adversarial workflow (append-only, count-completeness,
source-tag vocabulary, D2/D3/D4 compliance, cross-doc consistency, scope): 5
lenses clean, 1 confirmed defect (missed 16→17 warning-signs count) caught and
fixed. Dogfood root CHANGELOG (Component E) is deferred to S6 per plan order.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Component B of the authoritative-CHANGELOG campaign (ratified plan
docs/planning/changelog-authoritative-ledger-gate-plan.md, §3 Component B,
D2/D3/D4) — the dependability keystone. The central finding was that a
close-out write-gate ALONE is not dependable (is_dependable:false): a session
that crashes before Phase 3F, an out-of-band commit, or an in-progress hand-off
lands work in git with no ledger entry. Reconcile-on-read makes the ledger
self-healing so it is true WHEN READ, not merely "sessions were asked to log."

- SESSION_RUNNER Phase 0 step 6 now reconciles CHANGELOG.md against git log:
  frontier = `git log -1 --format=%H -- CHANGELOG.md`; gap = commits since with
  no entry; backfill each — during step 6, before the report and STOP — as its
  own `docs(changelog): backfill` commit. New ledger-reconcile note carries the
  mechanics; step 7 report surfaces the result.
- Phase 1B stub gains a `CHANGELOG: pending` crash breadcrumb; the git-log gap
  is the always-reliable backstop (covers the 3D->3F window the marker cannot).
- ITERATIVE_METHODOLOGY mirror: Pre-Flight step 4, purpose carve-out, gate,
  anti-pattern, Phase 1B step 1, Quality-Gate-1 question, Session Doc Template.
- CLAUDE.md:80 cross-ref corrected (Phase 0 "step 5"->"step 6", now also
  reconciles) — Learning KJ5HST#7: fix the cited destination of the changed step.

Decisions honored: D2 keys on any non-merge commit past the frontier (no
"completed unit" filter); D3 self-provisions if no committed ledger exists;
D4 keeps the honest division — reconcile backstops commit-bearing actions,
non-commit actions (releases/tags/PR/issue/access) remain the FM KJ5HST#27 write-gate's.
FM KJ5HST#17 anti-erosion clause: the backfill records history, is not the deliverable,
licenses no extra scope.

Verified via a 7-lens refute-default workflow. count-integrity and source-tag
greppability CLEAN; 11 defects found and fixed, chiefly two ship-blockers:
(1) an empty frontier (`CHANGELOG.md` never committed) collapsed `<frontier>..HEAD`
to an empty range and silently no-op'd escape #4 — fixed by making committed-ledger
existence the FIRST discriminator (reproduced across absent / uncommitted-seed /
normal / current cases); (2) the backfill-write timing straddled the STOP gate —
pinned to "during step 6, before the report and STOP." §5.2 reconciled: the
backfill entry leads with a source tag (default [ad hoc]) so the audit grep still
enumerates it, rather than the plan's un-greppable bracketed [backfilled] sketch.

No FM / numbered gate / Phase-0 step added: FM count stays 27, warning signs 17,
quality gates 12, Phase 0 = 8 steps, Pre-Flight = 7 steps — no count reconciliation
owed. Dogfood root CHANGELOG (Component E) is S6; dashboard freshness (C) is S5.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…(S4)

Component D of the authoritative-CHANGELOG campaign (ratified plan
docs/planning/changelog-authoritative-ledger-gate-plan.md, §3 Component D + D6):
the entry-format spec, the SESSION_NOTES division-of-labor, and the recompose of
the starter-kit CHANGELOG seed from Keep-a-Changelog/[Unreleased] to the action-log
shape. Both edited files are SEED disposition, so this reaches new adopters only;
enforcement for existing adopters already lives in the synced §3F / FM KJ5HST#27 /
Phase 0 text shipped by S2/S3.

- starter-kit/CHANGELOG.md recomposed: authoritative-action-ledger framing; the
  ratified entry format (### header line = required greppable unit, three detail
  bullets recommended — a true superset of S2/S3's shipped single-line form, not a
  contradiction); the one verbatim source-tag vocabulary [issue #<N>] · [BL-<N>] ·
  [ad hoc] (§5 must-fix #2), byte-identical to §3F/IM; the D2 keying rule (author or
  retain a commit OR take any non-commit action; NOT "completed units only"), an
  (in progress) marker for in-progress/reverted work (closes escape #3), and the sole
  empty-diff exemption; the CHANGELOG-vs-SESSION_NOTES division (transient handoff vs
  cumulative ledger, the commit SHA the only shared key, distill-not-copy); reverse-
  chron/prepend ordering with ## YYYY-MM time-grouping (not release-grouping).
- Signal-D freshness sentinel (D6): a single greppable METHODOLOGY-SEED-SENTINEL
  token whose documented contract — token present AND zero real-date ### headers =>
  fresh seed, suppress "never used" — is the anchor S5's dashboard will consume. The
  fresh seed carries zero real-date headers (the template uses a literal YYYY-MM-DD
  placeholder inside a fenced block), so it is correctly classified fresh, not stale.
- starter-kit/SESSION_NOTES.md gains the bidirectional counterpart pointer (transient
  here; cumulative in CHANGELOG; the SHA the shared key; distill-not-copy).

Decisions honored: D2 (keying + in-progress marker + empty-diff-only exemption);
D6 (recompose now, stays SEED in bin/_manifest.py, sentinel consistent). Out of scope
by plan order: Component C dashboard freshness is S5 (it consumes this sentinel);
Component E root CHANGELOG + boundary header is S6; D7 release pointer lands with E.
Loose "completed work history" captions in README/CLAUDE/BOOTSTRAP are left verbatim
(the S2/S3 caption convention) — a deliberate, recorded deferral.

Verified via a 6-lens refute-default workflow (vocabulary-verbatim, format-superset,
Signal-D invariant, D2-keying, count/cross-doc, scope): 0 ship-blockers, 0 should-fixes;
2 nits applied — deduplicated the sentinel token so a naive S5 token-grep can't match a
survivor line, and reworded the FM one-liner to mirror the mechanical keying. Deterministic
gates green: vocabulary byte-identical to §3F/IM, zero real-date headers, sentinel single-
occurrence, 51/51 bin/tests.sh.

No FM / numbered gate / Phase step added: FM count stays 27, quality gates 12 — no count
reconciliation owed. NEXT = S5 (Component C dashboard freshness).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stop rewarding mere presence of a CHANGELOG. A new evaluate_changelog_freshness()
grades whether the ledger still tracks the work, and feeds an advisory-only signal
(a RISK line + at most a 1-point documentation nudge — never a hard fail; the
authoritative gate lives in the session runner via FM KJ5HST#27 + Phase 0 reconcile).

- Signal C: >=10 non-merge commits since the ledger was last committed.
- Signal B: ledger frontier trails HEAD >21 days on an active repo.
- Signal D: never-used seed (sentinel present + zero real dated entries) on a repo
  with real history — keyed on token AND absence of `### YYYY-MM-DD`, never token alone.
- Signal F: done-marked BACKLOG.md items not migrated to the ledger.
- New-adopter grace (<10 commits) keeps a freshly bootstrapped seed silent.
- D3 absent-defect: absent CHANGELOG + real history is flagged only for adopters
  (SESSION_RUNNER.md present); non-adopters stay silent.

Doc sub-score: the old flat "+2 has_changelog" splits into +1 present / +1 fresh;
the 20-point cap is unchanged. Wired at the §5.5 anchor (after the metrics dict,
before scores). DASHBOARD_VERSION 2.6.1 -> 2.7.0. Both twins byte-identical.

Verified: 35 fixture assertions isolating each signal + grace + doc-split + D3 +
negative controls; 51/51 bin/tests.sh; live collect_all on this repo and a full
portfolio run rendering the risk line + version in terminal and HTML. Advisory —
no principle, phase, gate, workstream, or FM change; FM count stays 27.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…g boundary (S6)

Component E of the authoritative-CHANGELOG campaign (plan 1710e90, decisions
D5/D7). Creates this repo's own root CHANGELOG.md — the per-action operational
timeline, distinct from CLAUDE.md §Versioning's released-version narrative.

- Bounded backfill (D5): 7 entries covering everything v3.0-forward, newest on
  top, no hole at the recent edge, no full reconstruction. All three source
  tags demonstrated: [issue KJ5HST#43] (v3.0 MIT relicense), [BL-4] (backlog item),
  [ad hoc] (releases/PRs/grooming). Every SHA/date/tag verified against git.
- Self-logs this campaign with an (in progress) marker (D2 + FM KJ5HST#27 dogfood):
  the S6 commit records its own action.
- Release entries are one-line pointers into §Versioning, never re-narrations
  (D7 / cite-don't-restate); CLAUDE.md §Versioning gains the reverse boundary
  pointer so the two ledgers cannot diverge.
- Repo-scoped, not branch-scoped: fork-main-only backlog SHAs (ff5cee9,
  69dad12, 72dc914) honestly annotated (fork main), per D5's explicit inclusion.
- Upstream issue KJ5HST#43 cited as an absolute KJ5HST URL, never a bare #NN.

Not in the sync manifest (canonical-only file). Adversarial verification
(5 dimensions x refute) returned 0 confirmed defects; 51/51 bin/tests.sh.
Next: S7 (D1 pre-commit hook + step added to other session-type checklists).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ion-type + campaign checklist (S7, escape KJ5HST#8)

Closes escape KJ5HST#8 of the CHANGELOG-authoritative-ledger campaign: a
session-type checklist that summarizes close-out silently exempts any
gate it omits. Adds the CHANGELOG.md ledger step (Phase 3F, FM KJ5HST#27) to:
- SESSION_RUNNER Planning Session Checklist + vertical-slice revert close-out
- ITERATIVE_METHODOLOGY §Session Types: Review/Audit, Planning/Preparation, Debugging
- all six campaign per-execution + per-campaign (consolidation) checklists
- new Learning KJ5HST#8 codifying the rule (append-only; rows 1-7 unchanged)

Vocabulary byte-identical; FM count unchanged at 27. Checkpoint commit
(--no-verify): the campaign ledger entry lands with the close-out commit
so the reconcile frontier tracks HEAD.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…GELOG-ledger campaign (S7, D1)

Ships .githooks/pre-commit — the mechanical enforcement of FM KJ5HST#27 where a
repo has no root SESSION_RUNNER to run the close-out gate (escape #5): it
refuses a commit that changes tracked content unless CHANGELOG.md is
co-staged. Deliberately narrow and bypassable: skips merges/rebases and
absent-ledger repos, `git commit --no-verify` bypasses it, and Phase 0
reconcile-on-read (Component B) is the guarantee that backfills anything
past it. Match is fixed-string (grep -qxF), not a regex.

Docs: SAFEGUARDS Commit Discipline "Ledger Co-Staging Hook" subsection;
BOOTSTRAP Step 10 setup paragraph + scoped the stale "does not ship its
own hook script" line to blast-radius only; BOOTSTRAP First Session
Checklist step 7 gains the ledger step (escape KJ5HST#8, same class).

CHANGELOG.md: campaign S2-S7 marked complete. This commit is gated by the
hook it ships and passes (CHANGELOG co-staged) — the dogfood.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Designates the CHANGELOG-ledger campaign (S2-S7) as minor release v3.1
(first new failure mode since v2.7): CLAUDE.md §Versioning gains the
narrated v3.1 entry and current-version bump; README §What's New its
public restatement; root CHANGELOG.md a one-line pointer into §Versioning
(decision D7 triple-write). FM count 26 -> 27; 6 phases / 12 gates / four
session types / workstreams unchanged. Tag + GitHub Release cut at merge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@rmsharp

rmsharp commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

Holding this off upstream for now — the operator wants to validate the CHANGELOG-ledger campaign (S2–S7, incl. the pre-commit hook and reconcile-on-read) locally on the fork first. The branch feat/changelog-authoritative-ledger remains on the fork (rmsharp/methodology); this PR will be reopened once local validation is done. No content change — deferral only.

@rmsharp rmsharp closed this Jul 8, 2026
@rmsharp rmsharp reopened this Jul 8, 2026
@rmsharp
rmsharp merged commit 75a6853 into KJ5HST:main Jul 8, 2026
@rmsharp
rmsharp deleted the feat/changelog-authoritative-ledger branch July 8, 2026 03:42
rmsharp added a commit to rmsharp/methodology that referenced this pull request Jul 8, 2026
…se, fork sync (FM KJ5HST#27 close-out)

Append one dated [ad hoc] ledger entry with the completed-deploy anchors:
PR KJ5HST#46 merge 75a6853, annotated tag v3.1 + GitHub Release (Latest), fork main
synced 1adf6b3, tag mirrored, feature branch pruned. Dogfoods the .githooks
co-staging gate (CHANGELOG co-staged) and the FM KJ5HST#27 close-out rule.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
rmsharp added a commit to rmsharp/methodology that referenced this pull request Sep 5, 2026
…re 7/10

Predecessor S117 scored 8/10: exceptional gotchas that changed this session's
method, against a §6 that scopes every decision to the fork with no column
separating what ships, a D7 ground that is false, and an F4 generalisation
that over-reaches.

Self-score 7/10. Verification held -- the tombstone scheme, the row budget and
the precommit byte defect were each settled by running the code. Against that,
nine current-implementation limits were stated as structural ones and the
operator caught it, not me.

Learning KJ5HST#46 appended at 229 B, measured before writing against 245 B of
headroom. FRAMEWORK_LEARNINGS.md is now 73,712 / 73,728 -- 16 B left, and no
row of any size fits.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HRT4SwEjyyR23kNrwG6osj
rmsharp added a commit to rmsharp/methodology that referenced this pull request Sep 5, 2026
…, then compact

Phase 1B claim. Deliverable: Phase 2 of docs/planning/upstream-read-set-pr-plan.md
-- repair bin/check-learnings' row-budget scope, drive it RED against today's 20
violators, then compact all 20 over-budget rows of
starter-kit/FRAMEWORK_LEARNINGS.md to under the published 1,500 B budget.

THE OPERATOR ANSWERED S118'S GATING DECISION AT THIS CLAIM: compaction of existing
rows IS permitted, all 20, including KJ5HST#12 and KJ5HST#13. That answer is the operator's and
is recorded as its own CHANGELOG.md entry so a successor cannot read it as an
agent's recommendation. The rule it rules on -- "append only; do not edit existing
rows" -- names renumbering as its harm; compaction changes row content, not row
numbers. Explicitly NOT the answer: raising the ceiling a third time.

WHY PHASE 2 BEFORE PHASE 1, against the plan's own ordering. S118's next_steps (b):
compacting first means upstream receives a file already under the cap rather than
inheriting one 16,733 B over and needing a second change.

THE BLOCKER THIS CLEARS, re-measured at this claim: FRAMEWORK_LEARNINGS.md is
73,712 B against a 73,728 B ceiling -- 16 B of headroom, and the smallest row the
file has ever carried is 419 B. No learning row of any size fits.

THE GUARD THAT CANNOT FIRE, verified live: check-learnings exits 0 and prints
"0 unfrozen row(s), 0 over 1,500 B" with 20 violators present, because
check_row_budget scopes the budget to rows differing from git HEAD. It must be seen
to report 20 before anything is compacted.

RE-MEASURED, NOT QUOTED. The plan's 55,930 B target was computed against a 73,483 B
file; S118's Learning KJ5HST#46 added 229 B afterwards.

NOT IN SCOPE: Phase 1 (the port), Phase 3 (the gate), D1/D2/D3/D4/D6, BL-45's
remedy, issue KJ5HST#75's unsent PR, trimming either ledger, the upstream/main resync,
and any outward-facing action whatsoever.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019tacYU7wZPUd7cHfD2332P
rmsharp added a commit to rmsharp/methodology that referenced this pull request Sep 5, 2026
…nd the

ceiling is broken the other way

S121's deliverable. VERDICT: S120's "Phase 3C cannot be performed" is false as
written. The arithmetic is right and the denominator is wrong.

FOUR INDEPENDENT REFUTATIONS, each attacked by an agent told to break it.
1. METERED, the file is 19,617 tok = 78.5% of the 25,000-token cap. Six
   collinear probe points with ZERO residual on the three the model never saw;
   the concatenation seam MEASURED at exactly zero tokens, so f(1) is a
   measurement, not an extrapolation. Headroom 5,383 tokens.
2. 56,750 B is applied to this file by NO code path: methodology_trim.py
   answers [NO_CONFIG]/exit 3, both dashboard twins' read_cap_class() answer
   None, check-learnings has no whole-file arm. It is a detector FLOOR
   (2.27 B/tok, the conservative end of a measured band), not a budget.
3. Learning KJ5HST#34, in this very table, already moved the guard off the per-file
   axis at S97: read whole once, in part 243 times. The published budget is
   1,500 B PER ROW and all 46 rows comply.
4. No gate fires when a session appends nothing; BL-45 is the precedent, where
   S110-S114 ran through an identical declared deadlock and closed normally.

THE REAL DEFECT RUNS THE OTHER WAY, AND IT IS MEASURED, NOT MODELLED. 73,646 B
of this content -- 82 B UNDER the declared 73,728 B ceiling -- is refused at
25,486 tokens. BL-45 deliberately set that ceiling 2,023 B UNDER the then-cliff;
S119's compaction lowered density 3.0444 -> 2.8897 and inverted the margin. A
byte ceiling is tokens x density, and compaction is the operation that changes
density, so it rots silently. That is Learning KJ5HST#46's own mechanism, committed by
the framework's most recent remedy.

AND THE FINDING THAT ACTUALLY MATTERS: whenever headroom falls below ~1,500 B,
the row written EQUALS the headroom minus a few bytes (KJ5HST#34=604 at 604, KJ5HST#46=229
at 245). The file has saturated four times. The defect is not a blocked append,
it is a silent QUALITY TAX on the append.

SIX OF MY OWN NUMBERS WERE WRONG AND ARE CORRECTED IN PLACE, marked in the doc.
Two of them repeat, one level down, the exact error this document faults S120
for: I converted token headroom to bytes at the WHOLE-FILE density (2.8897) when
the headroom is consumed by ROWS, which meter 3.1974 B/token. Corrected capacity
is 11.5-16.5 rows, and the only safe unit is tokens (5,383). I also withdrew a
"the config refutes itself" division that compares two quantities the repo
explicitly declares non-comparable, and a fabricated quotation ("append a
Learning row") that I introduced into the record in claim commit 43387e1.

S120 WAS APPLYING ITS OWN RATIFIED PLAN'S STANDARD (:95, :106, :123). The defect
is in the plan. S120's SECOND reason -- byte-identity with the unpushed port
branch, blob b21854c identical on both -- is real, was never refuted, and is
answered as recommendation (4), a precondition rather than a remedy.

S119'S COMPACTION MUST NOT BE REVERTED: leg 1 (the row budget) independently
justifies every row, since only the 20-row option turns the checker green.
The operator's S119 decision table was scored on a column mis-scaled by ~19 KB;
the outcome is unchanged, but that is a finding he is entitled to be told.

NO REMEDY APPLIED. Present->Implement gate holds; recommendation sec 6 is an
answer proposed to open decisions D4/D5, not a correction an agent may apply.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NJo3fDBzjoYXwzhygVK1SM
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