Every commit touching user-visible frontend source rewrote the single
frontend-modern/browser-verification.json, so any two open frontend pull
requests conflicted as soon as either merged. A merge could not repair
the loser: concluding it staged main's frontend files as if the author
had changed them, and the guard then demanded a receipt for files the
author never ran. The only honest recovery was a rebuild on the new main
and a fresh browser pass, as #2415 -> #2418 -> #2433 showed on 2-3
October.
Each commit now adds its own receipt under
frontend-modern/browser-verification/, named by the fingerprint of the
content it verified. Receipts are only ever added, so git merges them
unaided. The guard keeps every binding it had: the commit's own parent,
the exact changed paths and their content digests, a desktop and a
narrow viewport, non-empty routes, states and interactions, and the
range check that each changed file's final content matches a receipt
from a non-merge commit in the range.
Concluding a merge no longer counts content a merged parent already
carries as the commit's own change. Merged content that neither parent
holds is flagged and still needs a follow-up receipt in range mode, and
a merge commit may not record one.
The shared file is retired: no commit may write it again. A commit that
modified it while its own parent still carried it stays valid evidence
in range mode, so a pull request that still rewrites it is repaired by
merging main and taking main's copy rather than by a rebuild. The file
is deleted in a change of its own, because deleting it here would
conflict with every pull request that still rewrites it.
--write-template writes the skeleton at the path the staged content
requires. --prune deletes receipts already on main. A change that
records a receipt may not delete one: git pairs the two as a rename,
which conflicts with any other change deleting the same receipt.
A committed release with an unchanged operator-owned containment failure cannot converge through unattended retries. Classify that evidence without weakening the block, and rearm only when the relevant private inputs or public controls change.
Change-source: pulse-maintainer
Docs under frontend-modern/public/docs are byte-for-byte copies of repo
docs, but the only guard was a CI vitest the git hooks never run. On
2026-09-01 two commits (f4886c2dfb, f313882a7b) each edited a mirrored
doc without its copy, passed the hooks, and broke main's Frontend job.
Add scripts/check_docs_mirror.py with an index-blob --staged mode wired
into the pre-commit hook: a commit that stages either side of an
out-of-sync pair (or an orphan shipped copy) fails with the exact sync
command, while pre-existing drift from other commits only warns. The
worktree mode runs as a named step in the public-docs workflow, with
unit tests in scripts/tests picked up by the existing runner. The
docsLinks vitest stays as the CI backstop.
Build-time generation of public/docs was considered and rejected: the
shipped set is a curated subset (61 of 421 docs), so generation still
needs a hand-maintained manifest while adding build, dev-server, and
test-order coupling.
GOTOOLCHAIN=auto never downgrades, so once the system Go moved to
go1.27.0 the go command wrote version-4 export data that golangci-lint
v1.64.8 (built with go1.26, older vendored x/tools) cannot decode.
Every Go commit then failed with "export data version 4 is greater
than maximum supported version 2" and a cascade of bogus "type X has
no field" typecheck errors. Rebuilding the linter with go1.27 does not
help; its vendored x/tools is still too old for the new export data.
Derive GOTOOLCHAIN from the root go.mod (toolchain directive, falling
back to the go directive, else auto) and export it for both the root
and nested-module lint invocations, so lint always runs under the
toolchain the module actually ships with. The single root pin also
covers nested modules, whose go directives must stay at or below it.
GOLANGCI_LINT_GOTOOLCHAIN overrides the derivation.
Three commits failed today on timeouts that had nothing to do with their
diffs. golangci-lint hit its 5m default while loading packages, and
TestStatusJSONLaneEvidenceReferencesAreStructured hit Go's 10m default after
9m11s with its goroutine parked in a syscall. Both ran at load average 185,
with four pre-commit hooks and two dozen eslint and vitest processes from
other agent sessions competing for the same box. Each failure cost a full
re-run to diagnose, and the same commits passed unchanged once the machine
went quiet.
The repoctl guardrail tests are I/O bound rather than CPU bound: they os.Stat
every evidence path status.json references, across repos, so they degrade
badly under contention while doing nothing wrong. golangci-lint already
exposed GOLANGCI_LINT_TIMEOUT; the go test line had no -timeout at all and
silently inherited the 10m default.
This raises the ceilings to 20m and 30m and adds PULSE_HOOK_GO_TEST_TIMEOUT
for the latter. No check is skipped and no rule is relaxed: on an idle
machine these stages finish in seconds to minutes and the change is inert.
The cost is that a genuinely hung test now takes longer to surface, which is
the better trade against false failures that read as real ones.
New scripts/release_control/format_staged_frontend.py mirrors the staged
Go formatter: formats staged frontend-modern/src {ts,tsx,css,json} blobs
through prettier --stdin-filepath, writes results back to the index
directly (no broad restaging), syncs the worktree only when it matches
the previously staged content, and iterates to a fixed point to absorb
prettier's occasional non-idempotence. Skips gracefully when prettier is
not installed (fresh clones, linked worktrees without node_modules).
Wired into .husky/pre-commit after the Go formatter, with unit tests in
the governance battery, a README note, and a .gitignore allowlist entry.
With the one-time sweep in the previous commits, prettier drift can no
longer re-accumulate and make format stays clean on a clean tree.
Canonical Governance failed on nearly every push today (6 of the last 8
commits) because the local pre-commit hook and the CI workflow disagreed
about the canonical completion guard in two ways.
Frontend-only commits skipped the guard entirely: the hook gated ALL
governance checks behind governance-path detection as a perf
optimization, but subsystem contracts name canonical frontend files, so
those commits landed locally and failed the same guard in CI. The hook
now always runs the (cheap) completion guard; only the multi-minute Go
test and audit battery stays path-gated.
Contract-neutral bypasses did not travel: PULSE_ALLOW_CONTRACT_NEUTRAL_COMMIT
authorized the commit in the local shell and vanished, so CI re-ran the
guard without it and went red. A new prepare-commit-msg hook records the
reason as a Contract-Neutral trailer in the commit message, and the
workflow now evaluates the guard per commit (each commit's file list
against its own parent), honoring the trailer exactly as the commit-time
hook honored the env var. Per-commit evaluation also stops a compliant
commit from being blamed for range-mates.
The new hook is registered as a worktree-sensitive governance file in
governance_stage_guard.py with a matching unit test assert.
golangci-lint was invoked from the repo root for every staged Go
package, so files in nested modules like
tests/integration/mock-github-server failed typechecking with 'main
module does not contain package' and could never be committed. Group
staged package dirs by their nearest enclosing go.mod and lint nested
modules from their own root.
The husky pre-commit hook unconditionally ran the full release-control
governance audit chain (`governance_stage_guard.py`, `control_plane_audit.py`,
`status_audit.py`, `registry_audit.py`, `contract_audit.py`, the
`go test ./internal/repoctl` package test, the readiness assertion guard,
and 15 Python helper unit tests) on every single commit, regardless of
what was actually staged. For a one-file frontend TS change, that meant
~15-20 minutes of audits the change couldn't possibly affect.
That cost is amplified by Pulse being driven by multiple agent harnesses
in parallel (Codex lanes, Claude Code interactive sessions, Anti-Gravity).
Each agent's commit serialized behind the same unrelated suite, even
when none of their staged files touched governance.
The hook already had `staged_files_match` and was using it to gate the
golangci-lint and `npm run lint` blocks. Apply the same pattern to the
governance block: run it only when the staged set actually touches
governance-relevant paths (docs/release-control/, scripts/release_control/,
internal/repoctl/, any .go file, go.{mod,sum,work,work.sum}, VERSION,
or the husky hooks themselves so hook changes still validate).
Frontend-only commits now finish in roughly the time the sensitivity
check, gitleaks scan, and `npm run lint` need (tens of seconds), rather
than tens of minutes. Governance-touching commits are unaffected; the
full audit chain still runs whenever any path in the gating regex is
staged.
Smoke-tested the regex against 13 representative paths (frontend TS,
README, internal docs JSON, release_control py, repoctl go, generic go,
go.mod/go.sum, VERSION, .husky/pre-commit, .husky/pre-push). All
classifications matched the intended skip/run behavior. Bash syntax of
the modified hook validated with `bash -n`.
The previous hook scoped lint to staged packages but still surfaced
all pre-existing violations in those packages on every commit, which
turned long-standing technical debt (errcheck on test mock helpers,
dupl warnings on poll providers) into a per-commit blocker.
Add --new-from-rev=HEAD so golangci-lint only reports issues
introduced by the staged diff. Pre-existing violations on untouched
lines are filtered out; new violations on changed lines still fail
the commit. Override with GOLANGCI_LINT_NEW_FROM_REV (set to "" to
lint the whole package, or to a base revision such as HEAD~5 to
broaden the comparison window).
Whole-repo golangci-lint run ./... was OOMing the host (an in-flight
process held 18 GB resident under sustained load) and the macOS
runtime kept SIGTERM-ing it before completion, blocking commits.
Replace ./... with packages derived from staged Go files (falling
back to ./... when none) and add a 5 minute deadline overridable via
GOLANGCI_LINT_TIMEOUT. Behavior on substantial Go changes still hits
the same lint coverage; trivial-touch commits no longer scan the
whole tree.
Add three layers of secret leak prevention:
1. .gitleaks.toml — config extending the default ruleset (~150 rules for
AWS, GCP, Stripe, OpenAI, private keys, JWTs, etc.) with allowlists
tuned to suppress false positives from test fixtures and docs.
2. .husky/pre-commit — enhanced with gitleaks protect --staged (graceful
skip if not installed), sensitive file type blocking (.pem, .key, .enc,
id_rsa, etc.), and broadened fallback patterns covering AWS, OpenAI,
GCP, and private key headers alongside existing Stripe checks.
3. .github/workflows/build-and-test.yml — new secret-scan CI job using
gitleaks-action that runs in parallel with build on every push/PR,
serving as the last gate if someone bypasses local hooks.
- Add persistent volume mounts for Go/npm caches (faster rebuilds)
- Add shell config with helpful aliases and custom prompt
- Add comprehensive devcontainer documentation
- Add pre-commit hooks for Go formatting and linting
- Use go-version-file in CI workflows instead of hardcoded versions
- Simplify docker compose commands with --wait flag
- Add gitignore entries for devcontainer auth files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>