Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,43 @@ Reverse-chronological, newest on top; prepend-only. Promote to `## YYYY-MM` sect

---

### 2026-07-27 · [ad hoc] New `SESSION_RUNNER.md` Learning #13 — a forward-looking claim has to be computed, not re-read

- **Change:** one row appended to the `starter-kit/SESSION_RUNNER.md` Learnings table (table was
**1–12**; appended, never renumbered — the diff on that file is a single added line with no
deletions, so rows 1–12 are byte-unchanged). That file is `bin/_manifest.py`-**distributed**, so
adopters receive the row via `bin/sync`. *A forward-looking claim cannot be checked by re-reading
a file — it has to be computed.*
- **Why the existing rows did not cover it.** Learning #6 and FM #11 cover claims written *from
memory*, and both prescribe the same repair: go re-read the file that confirms the claim. #7, #10
and #12 cover cross-references that go stale in the *corpus*. Neither reaches the other half of a
handoff — its predictions. A prediction describes a state that does not exist yet, so no file
confirms it; the only honest check is to derive it from current state, or to say plainly that it
is a guess.
- **The motivating case is in this repository's own history, and it refutes the tempting
diagnosis.** The S3 receipt's `next_steps` tells the next session to *"expect one CHANGELOG union
conflict, resolve newest-on-top."* The sync merge that followed met **seven** conflicting files.
But the prediction had not gone stale — it was never true. Two commands show why:
`git log -S 'expect one CHANGELOG union conflict' -- HANDOFFS.md` locates the sentence first
entering the tree in `bec4095`, and `git show --stat bec4095` shows that same commit changing
seven files. Every fact needed to get the prediction right was already in the author's own working
tree at the moment it was typed. (The seven-conflict outcome was measured against the contributing
fork's `main` at `ae6050d`, which is not reachable from this repository, so it is corroboration
here — the two commands above carry the argument on their own.)
- **Why it earns a row rather than a gotcha:** a wrong prediction is worse than none, because it
licenses the successor to resolve *quickly* rather than *carefully* — and a merge resolved on the
belief that "only the ledger differs" discards work silently, with no failing check to catch it.
The countermeasure is mechanical and non-mutating: `git merge-tree --write-tree --name-only`
computes the conflicting paths without touching a working tree.
- **Cross-reference sweep (Learnings #7/#10).** `git grep -nE 'table (was|is|now) ?1[–-][0-9]+'`
returns two live sites outside this entry — the v3.4 narration in this ledger and the matching
v3.4 bullet in `CLAUDE.md` §Versioning — both dated release narration this repo leaves verbatim by
design (the v2.7.1 precedent). The Learnings caption states no size. Nothing else needed updating.
- **Commit/PR:** [PR #63](https://github.com/KJ5HST/methodology/pull/63)
- **Session:** docs-only follow-on to the v3.6 ship · **Verified:** `bin/tests.sh` 84/84 ·
`bin/check-links` OK (82 links / 21 files) · Learnings table parses as contiguous rows 1–13, every
row 4-column, rows 1–12 byte-unchanged · brand-neutrality grep empty.

### 2026-07-26 · [ad hoc] Dashboard signal-integrity campaign lands upstream — the scanner's signals now mean what they say (v3.6)
- **Change:** the portfolio health scanner's signals are reconciled with what they actually measure,
closing upstream issues [#59](https://github.com/KJ5HST/methodology/issues/59),
Expand Down
1 change: 1 addition & 0 deletions starter-kit/SESSION_RUNNER.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ These are documented tendencies. The agent must actively guard against them.
| 10 | **A review pass scoped to the diff has a blind spot: what the change made stale *outside* it.** Learning #7 (cross-reference completeness) and Learning #8 (close-out-gate propagation) are authoring-time self-checks — they catch drift the *author* introduces. But an adversarial review or audit is pointed at the diff by default, so "what did this change make stale elsewhere in the corpus?" is nobody's job. The v3.3 close-out-receipt work (#52/#53) shipped a clean 6-lens adversarial review, yet left `HOW_TO_USE.md`, the `README.md` repo tree, and three tutorials describing close-out *without* the new receipt — none were in the diff, so no diff-scoped lens looked at them. A human had to ask "has documentation been fully updated?" (fixed in #54). | Upstream issue #55 (completeness-critic proposal), motivated by the v3.3 doc-completeness gap fixed in PR #54 | Promote Learning #7/#8 from an authoring self-check to a review-time lens: when a change adds, renames, or removes a concept, artifact, file, step, or numbered-set member, grep the *whole corpus* (not just the diff) for file/artifact enumerations, worked examples/tutorials, indexes/cross-references, and count/size claims ("N failure modes", "the six requirements") that now lag. See `workstreams/AUDIT_WORKSTREAM.md`'s Verification Checklist for the operative step. |
| 11 | **Heterogeneous capability tiers within one slice are a division of labor, not a new gate.** Splitting a pre-declared vertical slice's layers across agents of different capability tiers — with the strongest tier reviewing every lighter-tier layer's output before that layer's checkpoint commit lands — satisfies the existing per-boundary verification gates (c)/(d); it does not add a fifth gate or substitute for the build/test matrix. The risk is a plausible-sounding misreading: treating cross-tier review as proof a layer is correct on its own, or batching review to the end of the slice instead of per boundary — either one reopens failure mode #26 (mega-session masquerading as a vertical slice) wearing a division-of-labor costume. | The close-out-receipt slice's own hybrid capability-tier build (`HANDOFFS.md` session S1; concrete agent/model names live in `RECOMMENDED_SKILLS.md`), formalized as the §Vertical Slice Sessions "capability-tiered review" addition (BL-7) | When a slice's layers will be built or reviewed by agents of different capability tiers: state the tier assignment in the gate (a) contract, delegate a layer only where an objective gate (test suite, exhaustive grep, mechanical spec) proves its correctness, and confirm review happens per boundary before each checkpoint commit — never as one pass at the end. |
| 12 | **When an invariant is mechanical, encode it as a test — a review-time grep is a human step that silently stops happening.** Learnings #7 and #10 catch stale cross-references by *grepping at review time*, and that is the right tool for a relation between prose and meaning. But where the invariant is a relation between two **enumerable sets**, the grep is a weak substitute for an assertion: it depends on someone remembering, and its absence leaves no evidence. The motivating case: `HANDOFFS.md` joined the distributed corpus in v3.3 and was never added to the health scanner's methodology checklist, so the checklist silently stopped describing the corpus it scores — and the gap survived *two* releases of exactly the greps #7 and #10 prescribe. Stated as a property of two lists ("every distributed adopter-root destination is either on the checklist or explicitly exempt with a stated reason"), it is a few lines of test code — plus a second test that guards the guard, asserting every exemption names a real distributed file and states a reason, so a stale exemption cannot quietly hollow the invariant out. Once written, the whole class is closed: the next distributed artifact fails the suite instead of going uncounted. **The precondition is non-negotiable — drive the new assertion RED against unpatched code and watch it fail before trusting it.** A mechanized invariant that was never seen to fail is the same trap one level up, and this campaign hit it twice: an absence-check filtering a *dict* by `"Large files" in r` tested keys and passed vacuously, and a fixture whose render toolchain short-circuited the counts under test was structurally incapable of failing while looking like coverage. Pair every absence assertion with a presence control, and ask what a fixture makes *unreachable*, not only what it asserts. | Dashboard signal-integrity campaign (S9–S16) — the manifest-vs-checklist guard prototyped in S9 and shipped in Layer 1; the two vacuous tests caught in Layer 7 | When a change adds a member to an enumerable distributed set (a shipped file, a checklist item, a numbered set), or when you are about to rely on #7/#10 to keep two lists in step: ask whether the invariant is a relation between two sets you can enumerate in code. If it is, write the assertion — then drive it RED before trusting it. Keep the grep for what cannot be enumerated. |
| 13 | **A forward-looking claim cannot be checked by re-reading a file — it has to be computed.** Learning #6 and FM #11 catch claims written *from memory*, and both prescribe the same repair: re-read the file that confirms it. #7, #10 and #12 catch cross-references that go stale *in the corpus*. Neither reaches a handoff's predictions. "Expect one merge conflict", "these are the files you will touch", "this should be quick" describe a state that does not exist yet, so no file confirms them; the only honest check is to derive the answer, or to say plainly that it is a guess. The case in the Source column did not go stale — that is the tempting diagnosis and the wrong one; it was never true. A wrong prediction is worse than none: it licenses the successor to resolve *quickly* rather than *carefully*, and a merge resolved on the belief that "only the ledger differs" discards work silently, with no failing check to catch it. | This repo's v3.6 release cycle — a receipt predicted one conflicting file and the merge met seven; the sentence was written in a commit that had itself changed all seven | When you *write* a claim about a state that does not exist yet — a merge outcome, the files the next session will touch, an effort estimate — derive it or label it a guess. For a merge the derivation is exact and touches no working tree: `git merge-tree --write-tree --name-only <ours> <theirs>` lists the conflicting paths between the tree id on line 1 and the trailing `CONFLICT` block. When you *inherit* a prediction, re-derive it before acting. |

---

Expand Down