Skip to content

release: 0.17.0 — Markers that were trusted to be numbers - #328

Merged
fdaviddpt merged 1 commit into
mainfrom
release/0.17.0
Aug 8, 2026
Merged

release: 0.17.0 — Markers that were trusted to be numbers#328
fdaviddpt merged 1 commit into
mainfrom
release/0.17.0

Conversation

@fdaviddpt

Copy link
Copy Markdown
Contributor

Manifest 0.16.0 → 0.17.0 and the CHANGELOG section for the release. No code.

Ships #322 (the two cooldown markers save-session.sh fed to $(( )), reported and fixed by @jmossie82) and #320 (the auth-marker scan's blind spot).

The intro states plainly what this release does not fix: #326 (the guards check syntax, not range — a future-dated marker sticks the throttle on, and the rewrite is unreachable on that path) and #327 (10# landed in save-session.sh only). Both predate this release, both are fails-to-preserve, neither blocks it — but the previous CHANGELOG wording asserted a self-heal property that is only true for the syntax-error case, so that claim is now scoped rather than left to mislead whoever reads it next.

Release-gate audit of v0.16.0..main: no destroys, no discloses. Findings filed as #326/#327.

Local suite not run — this is a manifest field and markdown, and there is no version-drift test in this repo (swept: .claude-plugin/plugin.json is the only file carrying the version). CI is the authority.

@fdaviddpt
fdaviddpt merged commit eeb7a62 into main Aug 8, 2026
12 checks passed
fdaviddpt added a commit that referenced this pull request Aug 8, 2026
…e sweep (#336)

* fix(#326,#332): bound the marker's range, not just its syntax — and let a check do the sweep

#326 — the four cooldown guards validate SYNTAX and not RANGE. A digits-only
marker ahead of now is accepted, makes ELAPSED negative, and a negative ELAPSED
is -lt any cooldown, so the gate takes its `exit 0` — which sits ABOVE the line
that rewrites the marker. The self-heal the last three releases rest on is
unreachable on exactly the path that needs it: no save, no compression, no git
backup, permanently and mutely, until the wall clock catches up.

Three states, not two. Out of range now PROCEEDS, resets the marker at the point
of rejection where the reset is reachable, and says so once in hook-errors.log
via a new report_error() in log.sh. A silent clamp would trade a mute stuck
throttle for a mute wrong value.

post-tool-hook.sh is deliberately asymmetrical: it declines the cooldown it
cannot substantiate and does nothing else — no rewrite (the marker is
save-session.sh's), no diagnostic (one per tool call), no added spawn or read
(#299/#330).

The source comment at save-session.sh:155 asserted the opposite and is corrected
here. That comment, not the CHANGELOG, is why the issue was reopened: PR #328
closed it by referencing it.

#332 — twelve remaining sites read a case-guarded value into $(( )) with no 10#,
not the seven the issue lists. The five extra were found by
tests/test_arith_base_lint_332.py, which sweeps scripts/ and hooks.d/ for the
shape mechanically and is the part that prevents a sixth issue. ShellCheck does
not flag it (koalaman/shellcheck#2679). No shared helper: a helper a new author
does not know about cannot stop them writing the sixteenth site.

tests/test_ndc_day_boundary.py was suppressing NDC by writing a marker 34,000
years in the future — #326's defect used as an off switch. Switched to
_suppress_ndc, the brake the product documents (#159).

Targeted RED verified before the fix at all four sites; full suite 1545 passed,
43 skipped. Windows unverified — CI is the authority.

Co-Authored-By: Max <noreply>

* review(#336): a fifth site the issue never named, and a lint that would have cried wolf

Findings from the /code-review pass on PR #336, fixed in the same run.

FIFTH SITE (#326). hooks.d/before_session_start/50-git-restore.sh reads
`started=` through the same digits-only case. A value ahead of now makes _age
negative, so _fetch_health answers "in-flight" — the one state meaning "wait,
something is already running" — about nothing, and _spawn_fetch takes its early
return so the only writers of the record never run. Same geometry as the four
sites #326 enumerates, and not on its list.

The harm is worse than a wrong label: the caller then prints "already up to
date with origin/main" off refs no fetch refreshed, which is exactly what
_fetch_health's own header forbids. Now answers "abandoned" and spawns a real
fetch that rewrites the record. _fetch_health stays pure — its stdout is the
verdict, read through $( ) — so the diagnostic goes in _spawn_fetch.

LINT COULD NOT BE TRUSTED AS A GATE (#332). `case "$1" in` captures the guarded
name as the bare string "1", and the matcher did not require the $ sigil, so
every `$(( x + 1 ))` in a file guarding a positional parameter was a finding.
lib-lock.sh guards two, so the next ordinary arithmetic there would have failed
CI for no reason. Numeric names now require the sigil.

ITS OWN FIXTURE WAS NOT THE SHAPE IT CLAIMED. `''` inside a single-quoted Python
literal closes it and opens another, so the planted guard had silently become
`case "$LAST" in |*[!0-9]*)`. A self-test whose fixture is not what it plants
still goes green, and green here is supposed to mean "looked, found none".
Pinned by a test.

STALE LINE-NUMBER CITATIONS. Six comments this PR added cited line numbers;
three were already wrong at commit time. All replaced with construct names. A
PR that exists because a comment outlived the truth should not add more.

Targeted RED verified before each fix — including catching that the first draft
of the restore tests passed vacuously, because a doubled backslash put a literal
\\n in the state file and the digits-only guard rejected it for the wrong
reason. Full suite 1551 passed, 43 skipped. Windows unverified.

Co-Authored-By: Max <noreply>
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.

The cooldown guards validate syntax but not range: a digits-only marker ahead of now sticks the throttle ON permanently, with no diagnostic

1 participant