Skip to content

v4.12.0

Choose a tag to compare

@github-actions github-actions released this 19 Aug 10:23
· 117 commits to main since this release

Warning

ADVISORY (added 2026-08-20) — read before upgrading.
If audit/managed-content-manifest.json is missing from your install, do not run
hooks/local/upgrade.sh. It half-applies: new files arrive, the engine that calls them does not,
VERSION advances anyway, and the run writes upstream's manifest in as your base — after which
your stale files are reported as your own edits and the tree freezes.

If you have already run it from that state: do not re-run it, do not delete or
re-stamp the manifest, and do not bootstrap blindly — each recreates the same wrong base.
Preserve your *.pre-upgrade-* backups and wait for the recovery path.

Full guidance: https://github.com/fusebase-dev/fusebase-flow/blob/main/docs/ADVISORY-2026-08-20-missing-base-upgrade.md


v4.12.0 — the health check can see the enforcement layer

Full entry: CHANGELOG.md § [4.12.0]. This file records release evidence and the upgrade note.

Reported by the paperclip+hermes-v1 consumer, fifth in their escalation chain. Every claim in their
report survived an independent adversarial review before they filed it — including two of their own
companion claims that the review refuted.

Why this is a minor, not a patch

/fusebase-health gains a verdict it could not previously reach, and the manifest stampers can now
refuse to write. Both are new user-visible outcomes.

The defect

The settings arm keyed on exactly two facts: the count of expected event keys, and whether
hooks/handlers/stop.py appeared in the Stop chain. PreToolUse was never inspected. A tree where
the CLI regenerated .claude/settings.json and stripped everything was therefore indistinguishable
from a tree that never opted in, and both printed the same ✓.

The consumer observed both rows: the same line minutes after finding enforcement stripped, and again
after restoring it. Four such removals appear in their history.

Partial stripping was already caught — if stop.py survived but events were incomplete, the arm
recorded drift. The blind spot was specifically everything gone at once, which is what a wholesale
regeneration produces.

Why it matters beyond one consumer: /fusebase-health is the command an operator runs to answer
"did the update break anything?", and it answered yes-only-for-content — skills, agents, overlays —
while the runtime enforcement layer (FR-06/07/12) could be absent.

The fix

A dedicated, schema-validated intent marker — state/audit/flow-hook-wiring-intent.json — is written
only after a successful --wire-hooks, on a surface the CLI never rewrites. The arm then reads:

Marker Flow handler in the PreToolUse chain Verdict
valid, enabled present ✓ wired
valid, enabled absent DRIFT, exit 1
absent, or enabled: false either today's opt-in-default line, unchanged

Presence is not proof. The check matches the canonical handler (hooks/handlers/pre_tool_use.py)
inside the chain, not merely the "PreToolUse": key — a chain with the key and someone else's handler
is not Flow enforcement.

The drift carries its recovery, including --wire-hooks, because the default recovery explicitly
does not modify .claude/settings.json. Without that, detection would only relocate the operator's
forensics. Health remains read-only and never repairs.

Deliberate opt-out is first-class: --forget-hook-wiring records intent withdrawal, and the arm
goes quiet. A false alarm would be worse than the old silence, because it teaches operators to ignore
the alarm. Six states where the marker could lie — opt-out, settings replacement, an archived tree
carrying another checkout's marker, a malformed marker, missing settings, and a non-Flow handler — are
each handled and each tested.

Also — the stampers refuse to attest bytes that never ship

All three manifest stampers now emit a diagnostic, return non-zero, and leave the manifest
untouched
when a covered file holds CRLF under a resolved eol=lf. A warning that still writes a
knowingly non-canonical attestation is observability, not a guard.

This closes the proven CRLF subclass only. It does not settle
stamper-hashes-worktree-not-artifact — hashing committed bytes would fix artifact fidelity but
trade away local-tamper detection, and that trade stays open and undecided.

The consumer's forensics and this repo's own history converged on the same mechanism: five
occurrences here in three days, most recently a baseline file that hashed CRLF, shipped LF, and
reddened CI twice while looking clean locally, because the stamper and the verifier read the same
wrong bytes and agreed.

A guard that cannot load never fails a stamp. It degrades open and says so. The net is optional;
the manifest is not.

Also fixed

docs/release-notes/v4.7.0.md warned "use the 4.7.0 bootstrap-upgrade.sh, not the copy already
installed"
and then printed the installed path. The v4.6.1 copy has no base-synthesis step at all, so
which copy runs decides whether a base exists. The README and install docs print the same command and
were deliberately left alone — v4.11.0 made that command correct for them.

Release evidence

Item Value
Tag verification the v4.12.0 run is the authoritative gate; a local run is never release evidence
Pre-tag verification 6c4e1e5 green on both platforms, 1134/1134 on Windows
New phases hook-wiring-intent (23 rows), stamp-eol-guard (18 rows) — first full-tier run

Known residuals

  • Trees wired before this release carry no marker and stay silent until their next --wire-hooks. Marker-absence means "not known to have opted in", never "never opted in".
  • Manual cp .claude/settings.json.example wiring is a permanent false negative, unavoidable without a separate acknowledgement path.
  • Drift attribution in verify (the consumer's §3.2) is filed, not built: git-history attribution is unreliable on shallow and non-Git trees, where "no post-stamp commit" becomes false. It belongs behind an explicit flag.
  • upgrade.sh remains at its FR-25 baseline; the next change touching it must decompose it first.
  • The command gate still denies honest prose quoting a destructive pattern (K21/M8).