Release 0.7.1 — the tier 0.7.0 announced, actually reachable - #486
Open
MongLong0214 wants to merge 13 commits into
Open
Release 0.7.1 — the tier 0.7.0 announced, actually reachable#486MongLong0214 wants to merge 13 commits into
MongLong0214 wants to merge 13 commits into
Conversation
0.7.0's headline change made `[directive]` reachable and it reached nobody. `commander` declares `--trusted-author` with a default of `[]`, so the flag arrives as an empty array rather than undefined when absent, `?? ` passes it through, and the fallback to the author `init` records is dead code. Every record on every install still graded `[claim]` -- the condition #415 was opened about, reintroduced one layer up by the fix for it. Resolution is on length now. An explicit flag is always non-empty and an absent one is always empty, whichever shape commander hands over, so the test matches what the caller meant rather than what the framework happened to supply. The tests that passed drove `buildInjection` with options assembled by hand and never crossed the command line, which is the only path the hook uses. The four new cases spawn the built CLI. They fail against the 0.7.0 build, which is the only property that makes them worth having. That file's header already carried the warning, one layer down: a unit test of `gradeRecord` would have passed throughout the period the original bug existed. The same sentence applied to `buildInjection` and I did not hear it. `package-lock.json` declared 0.1.0 while both manifests read 0.7.0, stale since the first release, and moves with them now. The CHANGELOG carries two corrections to 0.7.0's own review evidence: the promotion PR said 132 commits where the range holds 137, and seven install checks in RELEASE-GATE section 4 where it lists six. Both were mine. Limit: 0.7.0 stays published with its notes amended to name the defect at the top; retracting a tag people may already have installed trades a known-bad version for an unknown one Ruled-out: deleting the v0.7.0 tag and re-cutting it | rewriting a published ref breaks every clone that already fetched it, and the release notes can carry the truth without that Ruled-out: reading the flag with a nullish check and documenting the commander default | the documentation would sit in this file while the defect sits in every install, which is the arrangement that produced this Warn: any option declared with a non-nullish default has the same shape, and nothing checks for it -- this fix repairs one site, not the class Blast: system Undo: easy Certainty: firm Verified: the released 0.7.0 artefact renders `[claim]` for `inject --path` and `[directive]` only with an explicit flag, the patched build renders `[directive]` for the same plain invocation, and the four CLI-spawning cases pass alongside the six that already existed Provenance: authored Record-Id: r-rel071
The first fix repaired `inject` and its own Warn line said it repaired one site rather than the class. Sweeping the class found the second site immediately: `query.ts` resolved trusted authors with the same nullish check against the same commander default, so `commitlore context` reported `claim` for a record the hook rendered `directive`. The comment at that line already said the two routes must answer alike, or the grade means one thing on the hook and another on the terminal. That sentence was written before the fallback existed on either route, stayed true while neither had it, and became false the moment one did. A comment asserting a property is not the property, and nothing was checking. Two cases now compare the routes directly, configured and unconfigured, and they run the built CLI rather than the functions behind it -- the same reason the first four exist. Limit: the sweep covered `?? ` against an options field in src/commands, which is the shape that produced both defects; an option whose default is consumed some other way would not have shown up Ruled-out: threading a cwd parameter into queryOptions to match inject | this route resolves the repository it was invoked in and has no cwd of its own, so a parameter would exist only to look symmetrical with a function that needs one Ruled-out: deleting the comment now that a test enforces it | it explains why the routes must agree, which the test asserts but does not say Warn: both routes now read git config on every invocation, including the hook on the hot path of every edit -- one local config read, but it is new work in a place that is measured in milliseconds Blast: system Undo: easy Certainty: firm Verified: against the same repository the released artefact was reproduced in, `context` and `inject --path` both render directive with a configured author and both render claim without one; twelve cases pass in the trusted-author suite Provenance: authored Record-Id: r-queryroute
Release 0.7.1: the tier 0.7.0 announced was never reachable
CommitLore — record lintTrailers: clean — 13 commits in Active constraints for the paths this PR touchesLimits (185)
Ruled out (429)
Truncated: 405 lines omitted — the comment hit GitHub's 65000 character limit. Trailer violations fail this check. Active constraints are informational — they are what the repository already decided, not a verdict on this PR. |
The defect history of this command is a history of values held and not recorded. #49 had the redirected hook target in hand and printed it into prose. #128 and #149 failed a working hook by probing a synthesized path, which a row naming what was actually executed would have exposed on first read. #382 printed the stale pin inside its own ok line. #63 had the fetch exit code. #335 and #458 were verdicts built on counting a different convention's vocabulary. Every row now carries an evidence map beside its sentence: what was executed, what it returned, and the counts a conclusion rests on. A non-ok row must carry at least one key, so a claim with nothing behind it does not typecheck as a complete row. Process output is kept as a bounded excerpt rather than collapsed to present-or-empty, because hook-runtime and inject-runtime diagnose from stderr first lines -- the reference implementation sanitises there and this one reads there. Paths render home-relative so a pasted bug report does not carry someone's directory layout. The text report is byte-identical. The pinned snapshot is what says so. Limit: evidence answers what was observed, not whether the observation was the right one to make -- #335's wrong count would now be visible in a field rather than prevented Ruled-out: collapsing stdout and stderr to present or empty, as the reference does | it sanitises against paths and tokens it cannot inspect, while these checks diagnose from the first line and would lose the diagnosis Ruled-out: leaving evidence optional on non-ok rows | a conclusion without its observation is the shape every defect above shares, and optional means absent in the row nobody looked at Warn: the 200-character cap is a judgement with no measurement behind it, and a diagnostic whose useful part sits past it will be silently cut with only the paired truncated flag to say so Blast: local Undo: easy Certainty: firm Verified: thirteen of thirteen rows carry evidence with zero empty maps, no value contains an absolute home path, the excerpt cap and its paired truncated flag hold in both directions, and the text and check-order snapshots are unchanged across the change Provenance: authored Record-Id: r-evidence465
Make a doctor row carry the observation its verdict rests on
Section 8.2 promised zero writes. Writing section 11's read-only test strictly is what found the promise false: a plain run touches `index.db-shm`, and `--fix` creates that and `-wal`. Those are SQLite's bookkeeping for a WAL database, created by opening one at all, for readers as much as writers, and they hold no committed data. Two ways to close the gap. Making the run literally write-free means opening the index outside WAL for doctor, which trades a documentation problem for the concurrency one #420 was about. So the document moves instead, and states the invariant that carries the meaning: `index.db` is byte-identical after a plain run, including under failure, and nothing else in the repository changes but those two sidecars. The acceptance row moves with it. A table that still said "zero writes" while the test asserted something narrower would leave the next reader to discover which one to believe. Limit: the exception is named for SQLite specifically, so a future dependency that touches the filesystem on open would need its own line rather than being covered by this one Ruled-out: opening the index outside WAL so the promise becomes literally true | it reintroduces the concurrency failure #420 fixed, to make a sentence accurate Ruled-out: leaving §8.2 and scoping only the test | the document is what a reader checks the code against, and a test quietly narrower than the promise it implements is the arrangement this milestone exists to remove Warn: `--fix` creates the `-wal` file that a plain run does not, so the two paths differ in what they leave behind even though neither writes data Blast: local Undo: easy Certainty: firm Verified: the three read-only invariant cases pass against the amended wording, asserting `index.db` equality and a filtered inventory rather than an unqualified zero Provenance: authored Record-Id: r-prdwrites
Say what a read-only run actually does
The generated block declared M4 while the paragraph above it stated an M5 result. That gap was filed rather than closed during the release, because rewriting the declaration between a CI failure and a tag is the careless publication the declaration exists to prevent. There is no tag pending now. Repointing it found a second thing. The block reported 1,240 runs where the registered analysis reports 1,160, because the generator counted rows on disk and M5 has seven shards of which three are re-runs. A study that re-runs a shard has more rows than measurements, and a line reporting the file count invites a reader to take the larger number for the study's size. The fix is in the generator rather than in the number. It now counts distinct task-arm-seed cells the way bench/m5-analysis.ts does, and says both figures with the difference named, so the published line and the registered analysis cannot disagree without one of them changing. The status note carries what the M4 note carried: why three shards are re-runs, where the supersession rule lives, the excluded error row, the unequal truncation and which direction it pushes, and that every record rendered `[claim]` so this is not the `[directive]` path 0.7.1 made reachable. M1, M1-b, M2 and M4 stay unpooled for the reason the M4 note already gave. Limit: the seven shards are declared individually, so a shard added later is invisible to this block until someone lists it -- which is the property the declaration was built for and the cost that comes with it Ruled-out: globbing bench/results for m5-*.jsonl | the file next to them is a withdrawn design log, and a glob is how the wrong dataset gets published without anyone deciding to Ruled-out: reporting only the 1,160 and dropping the row count | the rows are on disk and a reader who counts them would find the block understating; naming both and the reason is what makes either checkable Warn: the generator's supersession key is task, condition and seed, which is M5's cell shape; a study whose cell is keyed differently would silently collapse rows that are not duplicates Blast: local Undo: easy Certainty: firm Verified: 1,240 rows across the seven declared shards resolve to 1,160 distinct cells with 80 superseded, matching the registered analysis exactly; the gate passes with no --write and all four READMEs regenerate identically Provenance: authored Record-Id: r-m5sources
Publish the study the README's claim actually rests on
One dead hook runtime produced four independent-looking findings, and a reader had no way to tell the cause from the consequences. A dependent whose failure only restates its dependency's now carries `blockedBy` naming the root, so a fix plan can name causes once instead of repeating a symptom per row. The rule the whole milestone rests on is that annotation is not suppression. A blocked row keeps its status, its detail and its own evidence, and still appears in the report. A suppressed row is how a diagnostic lies by not looking, which is the defect #458 was, and a collapse that hid rows would have reintroduced it while claiming to reduce noise. The constructor refuses to name an `ok` blocker rather than trusting callers to avoid it. A collapse that points at a healthy check is worse than no collapse: it tells a reader to fix something that is not broken, and nothing downstream can detect the mistake. Independence is preserved deliberately. A stale stub whose runtime is also dead keeps its own finding unannotated, because that failure survives fixing the runtime and a fix plan that dropped it would leave the user with a repaired dependency and an unrepaired stub. Limit: only two edges are declared -- inject-version on inject-runtime, and the §2.2 checks on the capture chain -- so a dependency nobody wrote down still surfaces as an independent finding Ruled-out: declaring commit-msg-hook on hook-runtime to complete the graph | that edge runs backwards against registry order, and a declared edge the emission order cannot satisfy is a lie in the structure the fix plan walks Ruled-out: omitting a blocked row from the report and keeping it only in the JSON | the text report is what a user reads, and a row missing from it is indistinguishable from a check that was never run Warn: `blockedBy` resolves chains to the root, so a two-link chain reports the far cause and the intermediate failure is visible only as its own row -- correct for a fix plan, and surprising if read as a parent pointer Blast: local Undo: easy Certainty: firm Verified: thirteen rows in and thirteen out with collapse active, no row omitted and no `blockedBy: null` in the serialized report; a blocked dependent keeps its detail and evidence, a chain resolves to its root, an independent failure stays unannotated, and naming an ok blocker throws Provenance: authored Record-Id: r-collapse466
Say which failure is the cause and which are its echoes
The gate asked whether the plugin entry point resolved, and it passed for two releases while resolving to the wrong thing. Found running it against a fresh v0.7.0 clone on a machine carrying a 0.6.0 install: the clone answered 0.7.0 and the entry point answered 0.6.0, both exiting zero. `commitlore-run.sh` tries `commitlore` on PATH before CLAUDE_PLUGIN_ROOT, and that order is deliberate -- the installer's wrapper execs node itself, so it works where this script would otherwise have to find node, and on the hook hot path a missing node means no context at all. The order stays. What changes is that the gate narrows PATH and compares the version, so it asks whether the right thing resolved rather than whether something did. Two cases pin both halves. The entry point reaches the plugin when nothing shadows it, and a commitlore on PATH wins when one does. The second is not a bug being enshrined: it is the documented order, asserted so that changing it becomes a decision someone makes rather than a side effect of an unrelated edit. This is the smallest of the three options #483 recorded, and the only one that does not touch the hot path. Making the mismatch loud at runtime would mean running --version twice on every edit; preferring CLAUDE_PLUGIN_ROOT would reopen ADR-0011's relationship with the installer, which is a decision rather than a patch. Limit: the gate now catches the mismatch at release time, and doctor's inject-version check catches it for a user, but nothing tells a user who has never run doctor Ruled-out: preferring CLAUDE_PLUGIN_ROOT over PATH | it reopens how ADR-0011's ship-dist-in-the-repo interacts with the installer's wrapper, and the node-resolution advantage that motivated the current order would need re-examining rather than reversing Ruled-out: comparing versions inside the run script | it sits on the hot path of every edit and would spend a second process launch there to report a condition doctor already reports Warn: the narrowed PATH in the gate includes the interpreter's directory, so a machine whose node lives beside a commitlore wrapper still shadows the plugin and the check will pass for the wrong reason Blast: local Undo: easy Certainty: firm Verified: with PATH narrowed the entry point answers the repository's own version, and with a stub commitlore ahead of it on PATH it answers the stub -- both asserted, so the documented precedence cannot change silently Provenance: authored Record-Id: r-plugres483
Ask the release gate which commitlore the plugin actually ran
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.
Promotion of
devintomainfor v0.7.1. Patch on the released 0.7.0.Why this exists
0.7.0 shipped with its headline change non-functional. The review verdict on that promotion was FAIL and named the defect; the promotion had already been merged and tagged before the verdict arrived. That sequencing failure is recorded in #484 and in the CHANGELOG, not only here.
The defect, and the one the sweep found
commanderdeclares--trusted-authorwith a default of[], sooptions.trustedAuthor ?? configuredTrustedAuthors(cwd)never fell through. Every record on every install still graded[claim]— the condition #415 was opened about, reintroduced one layer up by its own fix.The first commit's
Warn:said it repaired one site rather than the class. Sweeping the class foundquery.tsimmediately:commitlore contextreportedclaimfor a record the hook rendereddirective, while the comment at that line already asserted the two routes must answer alike. A comment asserting a property is not the property.Verified against the released artefact
Six new cases spawn the built CLI. They fail against the 0.7.0 build, which is the only property that makes them worth having — the tests that passed drove
buildInjectionwith hand-assembled options and never crossed the command line, which is the only path the hook uses.Also
package-lock.jsondeclared0.1.0while both manifests read0.7.0. Stale since the first release.RELEASE-GATE.md§4 lists six. Both were mine.Evidence at this exact head
Sequencing for the tag, corrected
The verdict's second blocker was that the tag publishes before the post-tag fresh-clone gates, making publication fail-open. This time the release notes are not attached and the release is not announced until
RELEASE-GATE.md§4 has run against a clone of the tag. The tag itself still auto-creates a release — that is the workflow, not a choice — so the gate runs immediately after the push and before any notes go on.0.7.0 is not retracted
Its notes carry the defect at the top with a reproduction and a pointer here. Deleting a published tag breaks every clone that already fetched it.
Stated costs
Both routes now read git config on every invocation, including the hook on the hot path of every edit. One local config read, but new work in a place measured in milliseconds — for #472's budget to bound.
The sweep covered
??against an options field insrc/commands, the shape that produced both defects. An option whose default is consumed some other way would not have shown up.