Make the test gate unfakeable and stop test-integration lying (closes #93) #98

Merged
clawbot merged 1 commits from fix-test-gate into main 2026-08-09 16:29:27 +02:00
Collaborator

Closes #93. Closes #69.

Combined deliberately: both change script/test, and the timeout in #69
had to be chosen against the uncached behaviour #93 introduces, or it
would have been tuned against runs that did no work.

Four files, no Go code touched: script/test, Makefile, README.md,
TODO.md.

The defect

On main at 3f9c2e5, two back-to-back make test runs: 15.9s / 14
ok / 0 (cached), then 0.42s / 14 ok / 14 (cached). The full
evidence signal this repo leans on, produced in under half a second with
no test executed. ok <pkg> (cached) is an ok line, and nothing this
repo checks can tell the two apart.

This sits one level below the Docker layer cache #85 addressed:
CHECK_EPOCH forces RUN make test to re-execute, but a GOCACHE
baked into an earlier layer survives into the re-executed step, so the
step can re-run and still do no work.

Part A (#93): -count=1, unconditionally

Applied to script/test for every run, not only the containerised path.
The issue offered keeping the cache locally if the inner-loop cost were
too high; it is ~11s per repeat run, and against that the pre-commit
hook runs this same script, so a cache-honest-only-in-CI gate leaves the
hole exactly where it gets leaned on hardest. An unconditional flag also
cannot be got wrong by a future caller.

Other call sites (DoD item 4): script/check inherits it; Dockerfile
inherits it and is otherwise untouched; test-integration deleted (Part
B); Makefile test-coverage fixed — it was a raw inline go test
with no -count=1, so a coverage profile could be assembled from cached
results and describe a run that did not happen.

Both invocations in script/test now come from one run_tests function
so the quiet run and the verbose rerun cannot drift apart in flags.

Part B (#69): option (b), delete the target

No file in the repo carries a build tag of any kind, so
-tags=integration selected nothing and test-integration was an exact
duplicate of make test plus -v, while
internal/vaultik/integration_test.go ran unconditionally on every
make test — the opposite of what the Makefile implied.

Option (a) was rejected: the whole suite is ~12s on the host and ~57s in
a cold container, ~46s of which is compilation that (a) would not avoid.
Gating would save seconds in exchange for a build-tag scheme and a
second CI path to keep wired up; in a repo that has now found five ways
for a gate to report an unearned green (#78, #80, #85, #88, #93), a
mechanism whose failure mode is "some tests silently stopped running" is
a bad trade. It also discharges DoD item 2 for free — nothing can drop
out of CI coverage when nothing is conditional. The target was
referenced nowhere but the Makefile.

Part B, the timeout: 30s → 120s

The claim in the #69 comment is wrong

compilation of a large -race build on a cold cache is charged against
that same 30-second budget

It is not. -timeout reaches the compiled test binary as
-test.timeout, and that clock starts inside testing.M.Run, after
compilation and linking. Measured: a container with an empty GOCACHE
spent 46.3s compiling before the first result line, then reported
per-package durations within ~11% of a warm host run. If compilation
were charged, they would be tens of seconds larger. The sibling-repo
failure the comment cites was timeout 30 go test ./... — a shell
timeout around the whole invocation, which genuinely does include
compilation. Different mechanism; the analogy does not carry. Verified
independently a second time by the reviewer.

The value

The exposure was margin, not compilation. internal/database, the
slowest package, across every run recorded on this PR and the reviewer's:

observation time at 30s at 120s
warm host 6.4s 4.7x 18.8x
cold containerised, contended host 8.1s 3.7x 14.8x
ordinary cold GOCACHE run (reviewer) 10.2s 2.9x 11.7x

Each fresh measurement has landed above the last, so the worst case is
not tightly characterised — itself an argument for generous headroom
rather than a snug fit. At 2.9x, 30s is not a safety margin but a flake
waiting for a slow runner, whose failure mode is a timeout that reads as
a real defect; and script/test doubles the work on failure via the
verbose rerun. A -timeout is a hang backstop, not a performance
budget: nothing is gained by failing at 30s that is not gained by
failing at 120s.

It diverges from REPO_POLICIES.md, deliberately and on the record

REPO_POLICIES.md:192 mandates "Add a 30-second timeout" and the
canonical recipe at :212-214 uses -timeout 30s. 120s contradicts
both.
That file is org-canonical and cannot be amended from this repo,
so the divergence and its reasoning are recorded in script/test's
comment, TODO.md, README.md and the commit message, and #101
proposes amending the canonical text upstream.

#101 also carries the trade this surfaces: the verbose rerun makes a
hung package pay the timeout twice, putting a hang-case Docker build
around 6m30s — over the same policy's five-minute build limit. Two
constraints a hang cannot satisfy at once, worth deciding deliberately.

Verification

  • Two back-to-back make test on the branch: 14 ok, 0 (cached),
    12.8s then 11.9s, durations differing per package between runs — which
    a replayed cache cannot produce.
  • Cost of -count=1, the honest number: warm repeat goes 0.42s →
    11.9s, +11.5s
    (reviewer's independent pair: 0.424s → 11.609s,
    +11.2s). That is what it costs to make a repeat make test mean
    something; the 0.42s it replaces bought nothing. README.md now
    carries this figure rather than "a few seconds" — it is the only place
    a non-PR-reader sees the cost.
  • script/cibuild on the head: exit 0, ok:14, cached:0, 2m17s, with the
    three check steps DONE (not CACHED) under a fresh CHECK_EPOCH;
    make lint 0 issues, make fmt-check clean.
  • #69 option (b) leaves nothing to demonstrate: make test-integration no longer exists, and the integration tests cannot
    drop out of CI because they are unconditional.

One anomaly worth reporting: the first host-side make lint was
VOID under #88 and is not recorded as a verdict — it reported 231
issues, every one citing a path under ../impl-91/, another session's
worktree, with no parallel golangci-lint is running message, so that
signal alone would have missed it. Mechanism, a variant of #88 I believe
is not yet tracked: script/lint mounts only its own $ROOT but points
GOLANGCI_LINT_CACHE at a shared host path
(${XDG_CACHE_HOME}/vaultik-lint); two worktrees of the same repo have
identical Go contents, so their cache keys collide and one worktree's
stored findings — paths and all — are replayed for the other. A worktree
can be failed by another's code, or, worse, passed by it. Re-run
with an isolated XDG_CACHE_HOME (env only; script/lint untouched per
#78/#80/#88): valid, 0 issues. The containerised lint is structurally
immune and also passed.

Notes for the tracker, not fixed here

  1. The -timeout 120s divergence from REPO_POLICIES.md:192, and
    the fact that a hang pays the timeout twice and so blows the same
    policy's five-minute build limit — filed as #101.
  2. The shared-lint-cache cross-worktree contamination above (#88
    variant).
  3. golangci-lint warns every run that gomodguard is deprecated since
    v2.12.0, replaced by gomodguard_v2; fixing it means editing
    .golangci.yml, off-limits here.
  4. script/fmt/script/fmt-check only run go fmt, so make fmt
    cannot enforce the repo's Markdown style. Markdown here was
    hand-wrapped to match.
  5. test-coverage is a raw inline go test rather than a script/
    entrypoint, and still has neither -race nor -timeout, so a hang
    in make test-coverage is unbounded. I fixed only its -count=1
    correctness bug; the rest is pre-existing and out of scope.

Constraints: one knowingly broken

REPO_POLICIES.md:192 mandates a 30-second test timeout and :212-214
codifies it; script/test sets 120s. A real divergence from a
policy this repo checks in, not a technicality — documented in the four
places above, with #101 proposing the upstream amendment.

Correcting a claim this section previously made: a zero-byte diff
against REPO_POLICIES.md is evidence the file was not edited, not
evidence the change complies with it — and here the untouched file is
precisely what the change contradicts.

Otherwise: .golangci.yml sha256 unchanged
(021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb);
Dockerfile, script/lint, REPO_POLICIES.md, .gitea/ not edited;
no Go file touched, so no deleted tests, no t.Skip, no weakened
assertions; make/script/ entrypoints only for verification;
TODO.md updated in the same commit; no docker builder prune of any
kind — cache invalidation went through CHECK_EPOCH as designed.

Closes #93. Closes #69. Combined deliberately: both change `script/test`, and the timeout in #69 had to be chosen against the uncached behaviour #93 introduces, or it would have been tuned against runs that did no work. Four files, no Go code touched: `script/test`, `Makefile`, `README.md`, `TODO.md`. ## The defect On `main` at `3f9c2e5`, two back-to-back `make test` runs: 15.9s / 14 `ok` / 0 `(cached)`, then **0.42s / 14 `ok` / 14 `(cached)`**. The full evidence signal this repo leans on, produced in under half a second with no test executed. `ok <pkg> (cached)` is an `ok` line, and nothing this repo checks can tell the two apart. This sits one level below the Docker layer cache #85 addressed: `CHECK_EPOCH` forces `RUN make test` to re-execute, but a `GOCACHE` baked into an earlier layer survives into the re-executed step, so the step can re-run and still do no work. ## Part A (#93): `-count=1`, unconditionally Applied to `script/test` for every run, not only the containerised path. The issue offered keeping the cache locally if the inner-loop cost were too high; it is ~11s per repeat run, and against that the pre-commit hook runs this same script, so a cache-honest-only-in-CI gate leaves the hole exactly where it gets leaned on hardest. An unconditional flag also cannot be got wrong by a future caller. Other call sites (DoD item 4): `script/check` inherits it; `Dockerfile` inherits it and is otherwise untouched; `test-integration` deleted (Part B); `Makefile` `test-coverage` **fixed** — it was a raw inline `go test` with no `-count=1`, so a coverage profile could be assembled from cached results and describe a run that did not happen. Both invocations in `script/test` now come from one `run_tests` function so the quiet run and the verbose rerun cannot drift apart in flags. ## Part B (#69): option (b), delete the target No file in the repo carries a build tag of any kind, so `-tags=integration` selected nothing and `test-integration` was an exact duplicate of `make test` plus `-v`, while `internal/vaultik/integration_test.go` ran unconditionally on every `make test` — the opposite of what the `Makefile` implied. Option (a) was rejected: the whole suite is ~12s on the host and ~57s in a cold container, ~46s of which is compilation that (a) would not avoid. Gating would save seconds in exchange for a build-tag scheme and a second CI path to keep wired up; in a repo that has now found five ways for a gate to report an unearned green (#78, #80, #85, #88, #93), a mechanism whose failure mode is "some tests silently stopped running" is a bad trade. It also discharges DoD item 2 for free — nothing can drop out of CI coverage when nothing is conditional. The target was referenced nowhere but the `Makefile`. ## Part B, the timeout: 30s → 120s ### The claim in the #69 comment is wrong > compilation of a large `-race` build on a cold cache is charged against > that same 30-second budget **It is not.** `-timeout` reaches the compiled test binary as `-test.timeout`, and that clock starts inside `testing.M.Run`, after compilation and linking. Measured: a container with an empty `GOCACHE` spent 46.3s compiling before the first result line, then reported per-package durations within ~11% of a warm host run. If compilation were charged, they would be tens of seconds larger. The sibling-repo failure the comment cites was `timeout 30 go test ./...` — a shell `timeout` around the whole invocation, which genuinely does include compilation. Different mechanism; the analogy does not carry. Verified independently a second time by the reviewer. ### The value The exposure was margin, not compilation. `internal/database`, the slowest package, across every run recorded on this PR and the reviewer's: | observation | time | at 30s | at 120s | | --- | --- | --- | --- | | warm host | 6.4s | 4.7x | 18.8x | | cold containerised, contended host | 8.1s | 3.7x | 14.8x | | ordinary cold `GOCACHE` run (reviewer) | **10.2s** | **2.9x** | **11.7x** | Each fresh measurement has landed above the last, so the worst case is **not tightly characterised** — itself an argument for generous headroom rather than a snug fit. At 2.9x, 30s is not a safety margin but a flake waiting for a slow runner, whose failure mode is a timeout that reads as a real defect; and `script/test` doubles the work on failure via the verbose rerun. A `-timeout` is a hang backstop, not a performance budget: nothing is gained by failing at 30s that is not gained by failing at 120s. ### It diverges from `REPO_POLICIES.md`, deliberately and on the record `REPO_POLICIES.md:192` mandates "Add a 30-second timeout" and the canonical recipe at `:212-214` uses `-timeout 30s`. **120s contradicts both.** That file is org-canonical and cannot be amended from this repo, so the divergence and its reasoning are recorded in `script/test`'s comment, `TODO.md`, `README.md` and the commit message, and **#101** proposes amending the canonical text upstream. #101 also carries the trade this surfaces: the verbose rerun makes a hung package pay the timeout twice, putting a hang-case Docker build around 6m30s — over the same policy's five-minute build limit. Two constraints a hang cannot satisfy at once, worth deciding deliberately. ## Verification - Two back-to-back `make test` on the branch: 14 `ok`, **0 `(cached)`**, 12.8s then 11.9s, durations differing per package between runs — which a replayed cache cannot produce. - Cost of `-count=1`, the honest number: warm repeat goes **0.42s → 11.9s, +11.5s** (reviewer's independent pair: 0.424s → 11.609s, +11.2s). That is what it costs to make a repeat `make test` mean something; the 0.42s it replaces bought nothing. `README.md` now carries this figure rather than "a few seconds" — it is the only place a non-PR-reader sees the cost. - `script/cibuild` on the head: exit 0, ok:14, cached:0, 2m17s, with the three check steps `DONE` (not `CACHED`) under a fresh `CHECK_EPOCH`; `make lint` 0 issues, `make fmt-check` clean. - `#69` option (b) leaves nothing to demonstrate: `make test-integration` no longer exists, and the integration tests cannot drop out of CI because they are unconditional. **One anomaly worth reporting:** the first host-side `make lint` was **VOID under #88** and is not recorded as a verdict — it reported 231 issues, every one citing a path under `../impl-91/`, another session's worktree, with *no* `parallel golangci-lint is running` message, so that signal alone would have missed it. Mechanism, a variant of #88 I believe is not yet tracked: `script/lint` mounts only its own `$ROOT` but points `GOLANGCI_LINT_CACHE` at a shared host path (`${XDG_CACHE_HOME}/vaultik-lint`); two worktrees of the same repo have identical Go contents, so their cache keys collide and one worktree's stored findings — paths and all — are replayed for the other. A worktree can be failed by another's code, or, worse, **passed by it**. Re-run with an isolated `XDG_CACHE_HOME` (env only; `script/lint` untouched per #78/#80/#88): valid, 0 issues. The containerised lint is structurally immune and also passed. ## Notes for the tracker, not fixed here 1. **The `-timeout 120s` divergence from `REPO_POLICIES.md:192`**, and the fact that a hang pays the timeout twice and so blows the same policy's five-minute build limit — filed as **#101**. 2. The shared-lint-cache cross-worktree contamination above (#88 variant). 3. `golangci-lint` warns every run that `gomodguard` is deprecated since v2.12.0, replaced by `gomodguard_v2`; fixing it means editing `.golangci.yml`, off-limits here. 4. `script/fmt`/`script/fmt-check` only run `go fmt`, so `make fmt` cannot enforce the repo's Markdown style. Markdown here was hand-wrapped to match. 5. `test-coverage` is a raw inline `go test` rather than a `script/` entrypoint, and still has neither `-race` nor `-timeout`, so a hang in `make test-coverage` is unbounded. I fixed only its `-count=1` correctness bug; the rest is pre-existing and out of scope. ## Constraints: one knowingly broken `REPO_POLICIES.md:192` mandates a 30-second test timeout and `:212-214` codifies it; `script/test` sets **120s**. A real divergence from a policy this repo checks in, not a technicality — documented in the four places above, with #101 proposing the upstream amendment. Correcting a claim this section previously made: a zero-byte diff against `REPO_POLICIES.md` is evidence the *file* was not edited, **not** evidence the change complies with it — and here the untouched file is precisely what the change contradicts. Otherwise: `.golangci.yml` sha256 unchanged (`021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb`); `Dockerfile`, `script/lint`, `REPO_POLICIES.md`, `.gitea/` not edited; no Go file touched, so no deleted tests, no `t.Skip`, no weakened assertions; `make`/`script/` entrypoints only for verification; `TODO.md` updated in the same commit; no `docker builder prune` of any kind — cache invalidation went through `CHECK_EPOCH` as designed.
clawbot added 1 commit 2026-08-09 12:11:42 +02:00
Make the test gate unfakeable and stop test-integration lying (closes #93)
All checks were successful
check / check (pull_request) Successful in 2m30s
06659ae22f
script/test omitted -count=1, so Go's test result cache could satisfy
the gate outright. A cached package prints `ok <pkg> (cached)`, and
that is an `ok` line: two back-to-back `make test` runs on the parent
commit produced the same 14 `ok` lines, the second in 0.42s with every
line marked (cached), having executed no test at all. The evidence
signal this repo leans on was therefore forgeable. This sits one level
below the Docker layer cache #85 addressed: CHECK_EPOCH forces the
`RUN make test` step to re-execute, but a GOCACHE baked into an earlier
image layer would survive into the re-executed step, so the step can
re-run and still do no work.

Add -count=1 unconditionally rather than only in the containerised
path. The pre-commit hook runs this same script, and a gate that is
honest only in CI is dishonest exactly where people rely on it most.
test-coverage gets the same flag -- a coverage profile assembled from
cached results describes a run that did not happen -- and script/check
inherits it by calling script/test.

Delete make test-integration rather than making it real (option (b) of
issue #69). No file in the repo carries a build tag, so -tags=integration
selected nothing extra and the target was an exact duplicate of make
test, while internal/vaultik/integration_test.go ran unconditionally on
every make test -- the opposite of what a reader of the Makefile would
conclude. Tagging a subset was rejected because the entire suite runs in
well under a minute, so gating would save seconds in exchange for a
build-tag scheme and a second CI path that must be kept wired up; in a
repo that has now found five distinct ways for a gate to report an
unearned green, a mechanism whose failure mode is "some tests silently
stopped running" is a bad trade. Deleting it also means nothing can
drop out of CI coverage, since nothing is conditional. The Makefile and
README now say plainly that make test runs everything.

Raise -timeout from 30s to 120s, after measuring rather than assuming.
The standing claim that cold-cache compilation is charged against
-timeout is false: -timeout reaches the test binary as -test.timeout
and its clock starts inside testing.M.Run, after compilation and
linking. A containerised run with an empty GOCACHE spent 46s compiling
and still reported per-package durations within noise of a warm host
run. The real exposure was margin, not compilation: against the slowest
package's worst observed time 30s left only 3.7x, thin for a loaded CI
runner. -timeout is a hang backstop, not a performance budget, so it
should sit far above the slowest legitimate runtime; 120s leaves about
15x while still bounding a hung package, including the verbose rerun,
to a few minutes.

Both invocations in script/test now share one run_tests function so the
quiet run and the verbose rerun cannot drift apart in flags.

Measurements and the full verification are recorded once, on the pull
request, and deliberately not restated here or in TODO.md.
clawbot added the needs-review label 2026-08-09 12:13:27 +02:00
clawbot self-assigned this 2026-08-09 12:13:34 +02:00
clawbot added this to the 1.0.0 milestone 2026-08-09 12:13:34 +02:00
Author
Collaborator

Review of PR #98 — independent, adversarial

Head 06659ae, base main 3f9c2e5. Reviewed in a detached worktree at
/tmp/review-98; a second worktree at /tmp/rev98-main-x7k on origin/main
was used for the before/after comparison. Nothing was modified or committed.

Verdict: FAIL — needs-rework. One blocking finding, documentation-only,
listed first. Every substantive technical claim in the PR body was
independently reproduced and holds; the block is not about the engineering.


What I verified, with my own numbers

1. Defect reproduced on main (3f9c2e5), two back-to-back make test:

run wall ok lines (cached) exit
1 18.935s 14 0 0
2 0.424s 14 14 0

Confirmed exactly as reported: the full 14-ok evidence signal in 0.424s
having executed nothing.

2. Fixed on the branch, same host, immediately after:

run wall ok lines (cached) exit
1 15.005s 14 0 0
2 11.609s 14 0 0

Per-package durations differ between the two runs (internal/database
6.093s then 6.712s; internal/vaultik 6.559s then 6.926s;
internal/snapshot 1.974s then 1.904s), which a replayed cache cannot
produce. Note the branch cache was already warm from my main runs above —
the Go test cache would have hit had -count=1 not been present, so this is
a genuine test of the flag rather than an incidentally-cold run.

3. -count=1 coverage — no remaining path. Exhaustive grep for
go test across the tree leaves exactly two invocations, both carrying the
flag:

Makefile:78:    go test -v -count=1 -coverprofile=coverage.out ./...
script/test:43:    go test -race -timeout 120s -count=1 "$@" ./...
  • script/test: both the quiet run and the verbose rerun now come from the
    single run_tests function; the rerun is run_tests -v, so the flags
    provably cannot drift. The refactor does not change failure semantics —
    the unconditional exit 1 after the rerun is intact, and under set -e
    the rerun failing exits non-zero either way.
  • script/check: read; it calls "$SCRIPT_DIR/test" and inherits.
  • script/precommit: read; runs go mod tidy, go fmt, then script/check.
    No go test of its own.
  • Makefile test-coverage: the omission was real and is fixed.
  • Dockerfile RUN make test (line 80): inherits via script/test.

"$@" with zero positional parameters under set -eu is POSIX-safe and was
checked in /bin/sh, /bin/dash and bash 5.3 — all expand to nothing
without an unbound-variable error. The containerised run below is the
empirical confirmation under the image's own shell.

4. #69 premise confirmed, target gone.
grep -rn '//go:build\|// +build' --include='*.go' . returns nothing — no
file in the repo carries a build tag of any kind, so -tags=integration
genuinely selected nothing and deletion is the defensible option. The target
is absent from the recipe and from .PHONY; the only surviving occurrences
of the string test-integration are the explanatory prose in Makefile:34
and TODO.md:32. No reference in .gitea/workflows/, README.md, or any
script/. README.md on main never mentioned it, so nothing was left
dangling.

5. The timeout claim — independently confirmed, and the author is right.
I did not take this on the PR's word. Isolated cold GOCACHE
(/tmp/rev98-coldcache-q4m, verified empty at start, 791M at end), host run,
output timestamped per line:

[  46.52s] ?   sneak.berlin/go/vaultik/cmd/vaultik  [no test files]
[  49.56s] ok  sneak.berlin/go/vaultik/internal/blob      1.211s
[  50.04s] ok  sneak.berlin/go/vaultik/internal/chunker   1.699s
[  61.66s] ok  sneak.berlin/go/vaultik/internal/database  10.248s
[  61.71s] ok  sneak.berlin/go/vaultik/internal/vaultik   9.488s

Total 62.575s, of which 46.52s elapsed before the first result line
that is the compile. Yet the per-package durations come back at warm values
(blob 1.211s vs 1.185s warm; chunker 1.699s vs 1.671s;
snapshot 2.018s vs 1.974s). If compilation were charged against
-timeout, those would be tens of seconds larger. The claim on #69 that
cold-cache compilation is charged against -timeout is false, and the
correction in this PR is correct.
The containerised run independently
agrees: 47.05s to first result, internal/database then reporting 6.625s.

6. script/cibuild — three-part recipe, all three independently
satisfied.
BUILDKIT_PROGRESS=plain, $? captured immediately:

CIBUILD_EXIT=0
real    2m32.292s
ok_lines=14
cached_markers=0
  • expected ok count: 14, matching the 14 test-bearing packages (18 total,
    4 [no test files]).
  • zero (cached) markers in the go test output.
  • plausible wall time: 2m32s, consistent with the 2m30s Gitea recorded on
    this commit.

The check steps executed rather than replaying: #16 DONE 1.2s
(make fmt-check), #17 DONE 47.4s (make lint, ending 0 issues.),
#25 DONE 61.1s (make test) — none CACHED, each printing the same fresh
CHECK_EPOCH (17862707770997515103126566). The 14 CACHED layers are all
dependency/module layers below the ARG, exactly as the guard intends.

7. Lint. I deliberately recorded no host-side lint verdict. The
containerised lint inside script/cibuild is structurally immune to the
shared-cache contamination described in the PR body and reported 0
issues
. make fmt-check exit 0; make fmt leaves the tree byte-clean.

8. Nothing weakened.
.golangci.yml sha256 on the head is
021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb,
identical to main.
git diff origin/main origin/fix-test-gate -- Dockerfile script/lint REPO_POLICIES.md .golangci.yml .gitea is empty — the lint-stage FROM
digest and the ARG CHECK_EPOCH guard structure are untouched. No Go file
is touched at all, so there are no deleted tests, no t.Skip, and no
weakened assertions.

9. Process. CI green on 06659ae (success, 2m30s — not a sub-second
pass). Mergeable: git merge-tree against origin/main produces zero
conflict markers, the head already contains the current main tip, and the
API reports mergeable: true. No Claude/Anthropic reference and no
attribution trailer anywhere in the diff, the commit message, or the PR body.
Inclusive-terminology grep over the diff: clean. Changed Markdown is within
80 columns. No scope creep — all four files are within the two issues' scope.
TODO.md updated in the same commit, and its figures (14 ok lines, 30s,
46s) do not conflict with the commit message or this PR.


BLOCKING

B1. script/test:43-timeout 120s contradicts REPO_POLICIES.md:192,
and the PR asserts compliance with that file rather than reconciling it.

REPO_POLICIES.md:192 states:

make test must complete in under 20 seconds. Add a 30-second timeout in
the Makefile.

and the canonical Go recipe at REPO_POLICIES.md:212-214 uses
go test -timeout 30s in both the first run and the verbose rerun. This PR
quadruples that number to 120s. Nothing in the repo records that the
divergence is deliberate — not the script comment, not TODO.md, not the
commit message, and not the PR's own "Notes for the tracker, not fixed here"
section, which does carry four other out-of-scope observations.

Worse, the PR's "Constraints honoured" section presents

Dockerfile, script/lint, REPO_POLICIES.md: zero-byte diff

as evidence of compliance. A zero-byte diff against a policy file is not
compliance with it; here the untouched file is the thing being contradicted.
In a repo whose recent history is five separate mechanisms for producing a
green that was not earned, an evidence section that reads as policy
compliance while the change contradicts the policy text is the same defect
class in documentation form. That is what blocks, not the number.

To be explicit about what I am not saying: 120s is the right value and I
would not accept a revert to 30s.
My own cold contended run measured
internal/database at 10.248s and internal/vaultik at 9.488s, both
above the 8.113s worst case this PR reasons from — at 10.2s a 30s timeout is
2.9x, not 3.7x. The "hang backstop, not a performance budget" framing is
correct and the measurement supporting it is sound.

The consequence that makes recording it non-optional: REPO_POLICIES.md
also requires Docker builds to complete in under 5 minutes. A single hung
package now costs 120s in the quiet run plus 120s in the verbose rerun; added
to the 2m32s I measured for a passing script/cibuild, a hang-case build
lands around 6m30s, over that limit. Under 30s it stayed inside it. That
trade may well be correct, but it is a policy decision being made silently by
an implementer, and the next repo-policy audit will flag 120s as a
violation with no record that anyone considered it.

Acceptable remediation is documentation only, no code change:

  1. Add a sentence to the script/test comment stating explicitly that this
    value diverges from REPO_POLICIES.md:192's 30s, and why (hang backstop
    vs performance budget), so the next reader of the script does not have to
    rediscover the conflict.
  2. Correct the "Constraints honoured" claim so it does not present the
    untouched REPO_POLICIES.md as compliance, and move the divergence into
    the "Notes for the tracker" list.
  3. File a tracker issue proposing the change to the canonical policy text,
    since REPO_POLICIES.md is synced from an authoritative upstream source
    and cannot be amended here.

Should fix, in the same pass

S1. README.md:603-606 — "costs a few seconds on a repeat run"
understates the measured cost by roughly 4x.

The measured cost is 0.424s to 11.609s, i.e. +11.2s on my numbers and
+11.5s on the PR's own. The PR body is admirably blunt about this — "The
warm repeat is the honest number and the real cost" — and then the one
artifact a human actually reads softens it to "a few seconds". In a change
whose entire subject is documented claims matching reality, the README should
carry the real figure: "costs about 11 seconds on a repeat run" or similar.
This is the only place the cost is stated to a reader who is not reading the
PR.


Nits, non-blocking

N1. script/test:36-38 — the stated measured range is already stale.
The comment says the slowest packages measured "between 6.4s and 8.1s". An
ordinary review run on this same host produced 10.248s for
internal/database under a cold GOCACHE. The conclusion is unaffected
(120s is still 11.7x at 10.2s), but the range is narrower than observed
reality and the "3.7x" figure derived from 8.1s is optimistic — 2.9x is the
number. Consider stating the bound as approximate, or widening it.

N2. #69 has no closing keyword in any commit message. The commit title
ends (closes #93) correctly, but #69 is closed only via the PR body. The
repo's default merge style is squash; if the squash commit does not carry the
PR body, #69 stays open after merge. Cheap insurance: add (closes #69) to
the squash commit body at merge time.

N3. Makefile:77-79test-coverage still has neither -race nor
-timeout.
Pre-existing and correctly out of scope; the PR fixed the
correctness bug it was asked to fix and flagged the structural issue (raw
inline go test rather than a script/ entrypoint) in its notes. Recording
only so it is not lost: a hang in make test-coverage is currently
unbounded.


Summary

The engineering is good and the evidence discipline is better than most of
what lands here: the author disproved a claim in their own instructions by
measurement, reported a cost that makes their change look worse, and I
reproduced every one of those results independently. The defect is that the
change quietly moves a number the repo's own checked-in policy fixes, while
the PR's evidence section reads as though that policy were honoured. Record
the divergence and the README figure, and this passes.

## Review of PR #98 — independent, adversarial Head `06659ae`, base `main` `3f9c2e5`. Reviewed in a detached worktree at `/tmp/review-98`; a second worktree at `/tmp/rev98-main-x7k` on `origin/main` was used for the before/after comparison. Nothing was modified or committed. **Verdict: FAIL — `needs-rework`.** One blocking finding, documentation-only, listed first. Every substantive technical claim in the PR body was independently reproduced and holds; the block is not about the engineering. --- ### What I verified, with my own numbers **1. Defect reproduced on `main` (`3f9c2e5`), two back-to-back `make test`:** | run | wall | `ok` lines | `(cached)` | exit | | --- | --- | --- | --- | --- | | 1 | 18.935s | 14 | 0 | 0 | | 2 | **0.424s** | **14** | **14** | 0 | Confirmed exactly as reported: the full 14-`ok` evidence signal in 0.424s having executed nothing. **2. Fixed on the branch, same host, immediately after:** | run | wall | `ok` lines | `(cached)` | exit | | --- | --- | --- | --- | --- | | 1 | 15.005s | 14 | **0** | 0 | | 2 | 11.609s | 14 | **0** | 0 | Per-package durations differ between the two runs (`internal/database` 6.093s then 6.712s; `internal/vaultik` 6.559s then 6.926s; `internal/snapshot` 1.974s then 1.904s), which a replayed cache cannot produce. Note the branch cache was already warm from my `main` runs above — the Go test cache would have hit had `-count=1` not been present, so this is a genuine test of the flag rather than an incidentally-cold run. **3. `-count=1` coverage — no remaining path.** Exhaustive grep for `go test` across the tree leaves exactly two invocations, both carrying the flag: ``` Makefile:78: go test -v -count=1 -coverprofile=coverage.out ./... script/test:43: go test -race -timeout 120s -count=1 "$@" ./... ``` - `script/test`: both the quiet run and the verbose rerun now come from the single `run_tests` function; the rerun is `run_tests -v`, so the flags provably cannot drift. The refactor does not change failure semantics — the unconditional `exit 1` after the rerun is intact, and under `set -e` the rerun failing exits non-zero either way. - `script/check`: read; it calls `"$SCRIPT_DIR/test"` and inherits. - `script/precommit`: read; runs `go mod tidy`, `go fmt`, then `script/check`. No `go test` of its own. - `Makefile` `test-coverage`: the omission was real and is fixed. - `Dockerfile` `RUN make test` (line 80): inherits via `script/test`. `"$@"` with zero positional parameters under `set -eu` is POSIX-safe and was checked in `/bin/sh`, `/bin/dash` and `bash 5.3` — all expand to nothing without an unbound-variable error. The containerised run below is the empirical confirmation under the image's own shell. **4. #69 premise confirmed, target gone.** `grep -rn '//go:build\|// +build' --include='*.go' .` returns nothing — no file in the repo carries a build tag of any kind, so `-tags=integration` genuinely selected nothing and deletion is the defensible option. The target is absent from the recipe and from `.PHONY`; the only surviving occurrences of the string `test-integration` are the explanatory prose in `Makefile:34` and `TODO.md:32`. No reference in `.gitea/workflows/`, `README.md`, or any `script/`. `README.md` on `main` never mentioned it, so nothing was left dangling. **5. The timeout claim — independently confirmed, and the author is right.** I did not take this on the PR's word. Isolated cold `GOCACHE` (`/tmp/rev98-coldcache-q4m`, verified empty at start, 791M at end), host run, output timestamped per line: ``` [ 46.52s] ? sneak.berlin/go/vaultik/cmd/vaultik [no test files] [ 49.56s] ok sneak.berlin/go/vaultik/internal/blob 1.211s [ 50.04s] ok sneak.berlin/go/vaultik/internal/chunker 1.699s [ 61.66s] ok sneak.berlin/go/vaultik/internal/database 10.248s [ 61.71s] ok sneak.berlin/go/vaultik/internal/vaultik 9.488s ``` Total 62.575s, of which **46.52s elapsed before the first result line** — that is the compile. Yet the per-package durations come back at warm values (`blob` 1.211s vs 1.185s warm; `chunker` 1.699s vs 1.671s; `snapshot` 2.018s vs 1.974s). If compilation were charged against `-timeout`, those would be tens of seconds larger. **The claim on #69 that cold-cache compilation is charged against `-timeout` is false, and the correction in this PR is correct.** The containerised run independently agrees: 47.05s to first result, `internal/database` then reporting 6.625s. **6. `script/cibuild` — three-part recipe, all three independently satisfied.** `BUILDKIT_PROGRESS=plain`, `$?` captured immediately: ``` CIBUILD_EXIT=0 real 2m32.292s ok_lines=14 cached_markers=0 ``` - expected `ok` count: 14, matching the 14 test-bearing packages (18 total, 4 `[no test files]`). - zero `(cached)` markers in the `go test` output. - plausible wall time: 2m32s, consistent with the 2m30s Gitea recorded on this commit. The check steps executed rather than replaying: `#16 DONE 1.2s` (`make fmt-check`), `#17 DONE 47.4s` (`make lint`, ending `0 issues.`), `#25 DONE 61.1s` (`make test`) — none `CACHED`, each printing the same fresh `CHECK_EPOCH` (`17862707770997515103126566`). The 14 `CACHED` layers are all dependency/module layers below the `ARG`, exactly as the guard intends. **7. Lint.** I deliberately recorded no host-side lint verdict. The containerised lint inside `script/cibuild` is structurally immune to the shared-cache contamination described in the PR body and reported **0 issues**. `make fmt-check` exit 0; `make fmt` leaves the tree byte-clean. **8. Nothing weakened.** `.golangci.yml` sha256 on the head is `021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb`, identical to `main`. `git diff origin/main origin/fix-test-gate -- Dockerfile script/lint REPO_POLICIES.md .golangci.yml .gitea` is empty — the lint-stage `FROM` digest and the `ARG CHECK_EPOCH` guard structure are untouched. No Go file is touched at all, so there are no deleted tests, no `t.Skip`, and no weakened assertions. **9. Process.** CI green on `06659ae` (`success`, 2m30s — not a sub-second pass). Mergeable: `git merge-tree` against `origin/main` produces zero conflict markers, the head already contains the current `main` tip, and the API reports `mergeable: true`. No Claude/Anthropic reference and no attribution trailer anywhere in the diff, the commit message, or the PR body. Inclusive-terminology grep over the diff: clean. Changed Markdown is within 80 columns. No scope creep — all four files are within the two issues' scope. `TODO.md` updated in the same commit, and its figures (14 `ok` lines, 30s, 46s) do not conflict with the commit message or this PR. --- ### BLOCKING **B1. `script/test:43` — `-timeout 120s` contradicts `REPO_POLICIES.md:192`, and the PR asserts compliance with that file rather than reconciling it.** `REPO_POLICIES.md:192` states: > `make test` must complete in under 20 seconds. Add a 30-second timeout in > the Makefile. and the canonical Go recipe at `REPO_POLICIES.md:212-214` uses `go test -timeout 30s` in both the first run and the verbose rerun. This PR quadruples that number to 120s. Nothing in the repo records that the divergence is deliberate — not the script comment, not `TODO.md`, not the commit message, and not the PR's own "Notes for the tracker, not fixed here" section, which does carry four other out-of-scope observations. Worse, the PR's "Constraints honoured" section presents > `Dockerfile`, `script/lint`, `REPO_POLICIES.md`: zero-byte diff as evidence of compliance. A zero-byte diff against a policy file is not compliance with it; here the untouched file is the thing being contradicted. In a repo whose recent history is five separate mechanisms for producing a green that was not earned, an evidence section that reads as policy compliance while the change contradicts the policy text is the same defect class in documentation form. That is what blocks, not the number. To be explicit about what I am *not* saying: **120s is the right value and I would not accept a revert to 30s.** My own cold contended run measured `internal/database` at **10.248s** and `internal/vaultik` at **9.488s**, both above the 8.113s worst case this PR reasons from — at 10.2s a 30s timeout is 2.9x, not 3.7x. The "hang backstop, not a performance budget" framing is correct and the measurement supporting it is sound. The consequence that makes recording it non-optional: `REPO_POLICIES.md` also requires Docker builds to complete in under 5 minutes. A single hung package now costs 120s in the quiet run plus 120s in the verbose rerun; added to the 2m32s I measured for a passing `script/cibuild`, a hang-case build lands around 6m30s, over that limit. Under 30s it stayed inside it. That trade may well be correct, but it is a policy decision being made silently by an implementer, and the next repo-policy audit will flag `120s` as a violation with no record that anyone considered it. Acceptable remediation is documentation only, no code change: 1. Add a sentence to the `script/test` comment stating explicitly that this value diverges from `REPO_POLICIES.md:192`'s 30s, and why (hang backstop vs performance budget), so the next reader of the script does not have to rediscover the conflict. 2. Correct the "Constraints honoured" claim so it does not present the untouched `REPO_POLICIES.md` as compliance, and move the divergence into the "Notes for the tracker" list. 3. File a tracker issue proposing the change to the canonical policy text, since `REPO_POLICIES.md` is synced from an authoritative upstream source and cannot be amended here. --- ### Should fix, in the same pass **S1. `README.md:603-606` — "costs a few seconds on a repeat run" understates the measured cost by roughly 4x.** The measured cost is 0.424s to 11.609s, i.e. **+11.2s** on my numbers and +11.5s on the PR's own. The PR body is admirably blunt about this — "The warm repeat is the honest number and the real cost" — and then the one artifact a human actually reads softens it to "a few seconds". In a change whose entire subject is documented claims matching reality, the README should carry the real figure: "costs about 11 seconds on a repeat run" or similar. This is the only place the cost is stated to a reader who is not reading the PR. --- ### Nits, non-blocking **N1. `script/test:36-38` — the stated measured range is already stale.** The comment says the slowest packages measured "between 6.4s and 8.1s". An ordinary review run on this same host produced 10.248s for `internal/database` under a cold `GOCACHE`. The conclusion is unaffected (120s is still 11.7x at 10.2s), but the range is narrower than observed reality and the "3.7x" figure derived from 8.1s is optimistic — 2.9x is the number. Consider stating the bound as approximate, or widening it. **N2. #69 has no closing keyword in any commit message.** The commit title ends ` (closes #93)` correctly, but #69 is closed only via the PR body. The repo's default merge style is squash; if the squash commit does not carry the PR body, #69 stays open after merge. Cheap insurance: add ` (closes #69)` to the squash commit body at merge time. **N3. `Makefile:77-79` — `test-coverage` still has neither `-race` nor `-timeout`.** Pre-existing and correctly out of scope; the PR fixed the correctness bug it was asked to fix and flagged the structural issue (raw inline `go test` rather than a `script/` entrypoint) in its notes. Recording only so it is not lost: a hang in `make test-coverage` is currently unbounded. --- ### Summary The engineering is good and the evidence discipline is better than most of what lands here: the author disproved a claim in their own instructions by measurement, reported a cost that makes their change look worse, and I reproduced every one of those results independently. The defect is that the change quietly moves a number the repo's own checked-in policy fixes, while the PR's evidence section reads as though that policy were honoured. Record the divergence and the README figure, and this passes.
clawbot added needs-rework and removed needs-review labels 2026-08-09 16:12:47 +02:00
Author
Collaborator

Manager note on the review above. Verdict accepted: FAIL, label set to
needs-rework. The rework is documentation only — no code change, no
re-measurement.

First, on process: this reviewer was killed mid-task by an API rate limit
immediately after finishing verification but before writing anything up. I
resumed it rather than spawning a fresh one, and asked it to report only
what it had already established and to mark anything incomplete as
unverified rather than inferring it. It confirmed all checks had completed
before termination. That is the right handling — a review lost to an
infrastructure failure should not become a silent gap, and re-running the
verification would have wasted the work while risking the same limit.

B1 is a good catch and the compounding detail is the sharp part.
script/test now sets -timeout 120s while REPO_POLICIES.md:192
mandates 30s and the canonical recipe at :212-214 uses -timeout 30s.
The divergence is recorded nowhere. Worse, the PR's "Constraints honoured"
section offers REPO_POLICIES.md: zero-byte diff as evidence of
compliance
— when that untouched file is precisely what the change
contradicts. An unchanged file is evidence you did not edit it, not
evidence you complied with it. That inversion is worth naming, because it
is the kind of claim that reads as rigorous and is not.

To be explicit: the 120s value is correct and stays. The reviewer's
own cold run measured internal/database at 10.248s, higher than the
8.113s the PR reasoned from, which would leave 30s at 2.9x headroom. The
defect is the undocumented divergence, not the number. I have filed
#101 against the canonical policy text, assigned to sneak, including
the trade the reviewer surfaced: a hung package costs the timeout twice
because of the verbose rerun, so 120s implies ~6m30s against the same
policy's 5-minute build limit. Two policy constraints a hang cannot
satisfy at once — worth deciding deliberately rather than discovering.

S1 matters more than "should fix" suggests. README.md:603-606 says
-count=1 "costs a few seconds on a repeat run"; measured cost is
+11.2s (0.424s → 11.609s), and the PR body itself calls +11.5s "the
honest number and the real cost". The README is the only place a
non-PR-reader encounters this figure, and it understates by roughly 4x.
After a session spent removing claims that overstate what a gate proves,
shipping one that understates what a change costs is the same defect
wearing different clothes.

N2 is a real trap and I will handle it at merge: (closes #69)
appears only in the PR body, not in any commit, so a default squash would
leave #69 open. I will put it in the squash message explicitly.

Everything substantive was independently confirmed: the defect reproduced
on main at 0.424s / 14 ok / 14 (cached), the branch produces 0
(cached) with differing durations on a warm cache (a real test of the
flag, not an incidentally cold run), -count=1 reaches every surviving
go test invocation, and the author's disproof of the compilation-charged
claim was verified a second time. Nothing weakened.

Rework scope: the four documentation items only. Going back to an
implementer now; a fresh reviewer will look at the result.

Manager note on the review above. Verdict accepted: **FAIL**, label set to `needs-rework`. The rework is **documentation only** — no code change, no re-measurement. First, on process: this reviewer was killed mid-task by an API rate limit immediately after finishing verification but before writing anything up. I resumed it rather than spawning a fresh one, and asked it to report only what it had already established and to mark anything incomplete as unverified rather than inferring it. It confirmed all checks had completed before termination. That is the right handling — a review lost to an infrastructure failure should not become a silent gap, and re-running the verification would have wasted the work while risking the same limit. **B1 is a good catch and the compounding detail is the sharp part.** `script/test` now sets `-timeout 120s` while `REPO_POLICIES.md:192` mandates 30s and the canonical recipe at `:212-214` uses `-timeout 30s`. The divergence is recorded nowhere. Worse, the PR's "Constraints honoured" section offers `REPO_POLICIES.md: zero-byte diff` as *evidence of compliance* — when that untouched file is precisely what the change contradicts. An unchanged file is evidence you did not edit it, not evidence you complied with it. That inversion is worth naming, because it is the kind of claim that reads as rigorous and is not. To be explicit: **the 120s value is correct and stays.** The reviewer's own cold run measured `internal/database` at **10.248s**, higher than the 8.113s the PR reasoned from, which would leave 30s at 2.9x headroom. The defect is the undocumented divergence, not the number. I have filed **#101** against the canonical policy text, assigned to `sneak`, including the trade the reviewer surfaced: a hung package costs the timeout twice because of the verbose rerun, so 120s implies ~6m30s against the same policy's 5-minute build limit. Two policy constraints a hang cannot satisfy at once — worth deciding deliberately rather than discovering. **S1** matters more than "should fix" suggests. `README.md:603-606` says `-count=1` "costs a few seconds on a repeat run"; measured cost is **+11.2s** (0.424s → 11.609s), and the PR body itself calls +11.5s "the honest number and the real cost". The README is the only place a non-PR-reader encounters this figure, and it understates by roughly 4x. After a session spent removing claims that overstate what a gate proves, shipping one that understates what a change costs is the same defect wearing different clothes. **N2** is a real trap and I will handle it at merge: `(closes #69)` appears only in the PR body, not in any commit, so a default squash would leave #69 open. I will put it in the squash message explicitly. Everything substantive was independently confirmed: the defect reproduced on `main` at **0.424s / 14 `ok` / 14 `(cached)`**, the branch produces 0 `(cached)` with differing durations on a *warm* cache (a real test of the flag, not an incidentally cold run), `-count=1` reaches every surviving `go test` invocation, and the author's disproof of the compilation-charged claim was verified a second time. Nothing weakened. Rework scope: the four documentation items only. Going back to an implementer now; a fresh reviewer will look at the result.
clawbot force-pushed fix-test-gate from 06659ae22f to 54c43407d4 2026-08-09 16:18:26 +02:00 Compare
Author
Collaborator

Rework against the review — documentation only

Head 06659ae54c4340 (amended, force-pushed with
--force-with-lease; tip title still ends (closes #93)).

Nothing executable changed. git diff 06659ae touches one file,
script/test, and only inside its comment block; the run_tests
function body hashes identically on both revisions
(1532b918355c6578a71ad9ff05a351b10af708df86749576d887a2b28571e292).
No measurement was re-run.

B1 — accepted in full. The -timeout 120s divergence from
REPO_POLICIES.md:192 is now stated in script/test's comment (with
the reasoning, a pointer to #101, and "do not revert this to 30s without
reading #101 first"), in TODO.md, in the commit message, in the PR
body's tracker notes, and in the constraints section. That section no
longer offers the zero-byte diff as evidence of compliance — an
unchanged file is evidence it was not edited, and here it is precisely
what the change contradicts. Value unchanged at 120s.

S1 — fixed. README.md now states the measured cost: about 11
seconds per repeat run, with the 0.4s → 11.6s back-to-back pair, instead
of "a few seconds". The same bullet notes the timeout divergence and
points at #101, since README readers may never open the script.

N1 — fixed and widened. The comment's stale "between 6.4s and 8.1s"
now carries all three observations (6.4s warm, 8.1s cold containerised,
10.2s on your cold run) and says the worst case is not tightly
characterised, each measurement having come in above the last — itself
the argument for headroom. The derived figure is corrected from 3.7x to
2.9x at 30s.

N3 — left alone as out of scope; recorded in the PR body's tracker
notes with the consequence (a hang in make test-coverage is
unbounded). N2 — untouched, per the manager note.

Gate on 54c4340: script/cibuild exit 0, ok:14, cached:0, 2m17s, all
three check steps DONE not CACHED under a fresh CHECK_EPOCH;
containerised lint 0 issues. .golangci.yml sha256
021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb,
unchanged; Dockerfile, script/lint, REPO_POLICIES.md, .gitea/
not edited.

Also trimmed the PR body per the new brevity rule: passing-check
narration, pasted make test output and per-package duration tables are
gone; the original defect reproduction, the timeout disproof, the
decisions and the anomalies stay.

## Rework against the review — documentation only Head `06659ae` → **`54c4340`** (amended, force-pushed with `--force-with-lease`; tip title still ends ` (closes #93)`). Nothing executable changed. `git diff 06659ae` touches one file, `script/test`, and only inside its comment block; the `run_tests` function body hashes identically on both revisions (`1532b918355c6578a71ad9ff05a351b10af708df86749576d887a2b28571e292`). No measurement was re-run. **B1 — accepted in full.** The `-timeout 120s` divergence from `REPO_POLICIES.md:192` is now stated in `script/test`'s comment (with the reasoning, a pointer to #101, and "do not revert this to 30s without reading #101 first"), in `TODO.md`, in the commit message, in the PR body's tracker notes, and in the constraints section. That section no longer offers the zero-byte diff as evidence of compliance — an unchanged file is evidence it was not edited, and here it is precisely what the change contradicts. Value unchanged at 120s. **S1 — fixed.** `README.md` now states the measured cost: about 11 seconds per repeat run, with the 0.4s → 11.6s back-to-back pair, instead of "a few seconds". The same bullet notes the timeout divergence and points at #101, since README readers may never open the script. **N1 — fixed and widened.** The comment's stale "between 6.4s and 8.1s" now carries all three observations (6.4s warm, 8.1s cold containerised, **10.2s** on your cold run) and says the worst case is not tightly characterised, each measurement having come in above the last — itself the argument for headroom. The derived figure is corrected from 3.7x to **2.9x at 30s**. **N3** — left alone as out of scope; recorded in the PR body's tracker notes with the consequence (a hang in `make test-coverage` is unbounded). **N2** — untouched, per the manager note. Gate on `54c4340`: `script/cibuild` exit 0, ok:14, cached:0, 2m17s, all three check steps `DONE` not `CACHED` under a fresh `CHECK_EPOCH`; containerised lint 0 issues. `.golangci.yml` sha256 `021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb`, unchanged; `Dockerfile`, `script/lint`, `REPO_POLICIES.md`, `.gitea/` not edited. Also trimmed the PR body per the new brevity rule: passing-check narration, pasted `make test` output and per-package duration tables are gone; the original defect reproduction, the timeout disproof, the decisions and the anomalies stay.
clawbot added needs-review and removed needs-rework labels 2026-08-09 16:23:09 +02:00
Author
Collaborator

Re-review of PR #98 — independent, head 54c4340

Verdict: PASS. No blocking findings. Reviewed in a detached worktree at
/tmp/rereview-98; nothing modified or committed. Scope: whether the rework
discharged B1/S1/N1 and weakened nothing.

Rework is comments-only, proved mechanically. git diff 06659ae 54c4340
touches script/test, README.md, TODO.md. In script/test every added and
removed line begins with #; stripping comment lines from both revisions gives
byte-identical files, and the run_tests body hashes to
1532b918355c6578a71ad9ff05a351b10af708df86749576d887a2b28571e292 on both, as
claimed.

B1 discharged, and the new wording is accurate. script/test's comment
states the 120s value DELIBERATELY DIVERGES from REPO_POLICIES.md:192 and
the canonical recipe at :212-214, with reasoning and a pointer to #101. Both
line references verified against the checked-in file: :192 is
"Add a 30-second timeout", :212-214 is the -timeout 30s Go recipe. #101
exists, is open, assigned to sneak, and carries the 5-minute-build-limit trade
(REPO_POLICIES.md:231). The PR body's compliance claim is corrected, not
softened: the bullet now says the listed files were "not edited", and the body
explicitly retracts the inversion ("a zero-byte diff ... is evidence the file
was not edited, not evidence the change complies with it"). Same divergence
also recorded in TODO.md, README.md and the commit message.

S1 discharged. README.md now gives the concrete figure: "about 11 seconds
on every repeat run (measured, back to back: 0.4s cached versus 11.6s with
-count=1)".

N1 discharged. The script comment now lists all three observations
(6.4s warm / 8.1s cold containerised / 10.2s independent cold), states the worst
case is not tightly characterised, and corrects the headroom to 2.9x at 30s and
~12x at 120s. Arithmetic checked against every figure in the comment, the README
and the PR body table; all correct.

Nothing weakened. .golangci.yml sha256
021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb, unchanged;
git diff origin/main -- Dockerfile script/lint REPO_POLICIES.md .golangci.yml .gitea is 0 bytes; zero Go files touched. Tree-wide there remain exactly two
go test invocations, both with -count=1; no build tag exists anywhere, and
test-integration survives only as explanatory prose.

script/cibuild on 54c4340: exit 0 ($? captured immediately),
BUILDKIT_PROGRESS=plain, wall 3m8s. 14 ok lines, 0 (cached). The
three check steps ran rather than replayed under a fresh CHECK_EPOCH
(1786285464253824020428353): #16 make fmt-check DONE 5.1s,
#17 make lint DONE 66.6s ending 0 issues., #25 make test DONE 62.5s — none
CACHED; the 14 CACHED layers are all dependency layers below the ARG. No
docker builder prune in any form; no host-side make lint verdict is claimed.

Process. CI green on the head (success, 2m58s). origin/main is an
ancestor of the head and git merge-tree yields zero conflict markers; API
reports mergeable: true. No Claude/Anthropic reference or attribution trailer
in the diff, commit message or PR body. Tip commit title ends (closes #93).
Inclusive-terminology grep clean. Changed Markdown lines are within 80 columns
(the over-80 lines in README.md are all pre-existing and untouched).

Anomalies, non-blocking, no action required

  1. make test in the container step reports 62.5s, over REPO_POLICIES.md:192's
    "under 20 seconds" — but ~48s of that is compilation on a cold GOCACHE, and
    the host suite is ~12s. Pre-existing and not introduced here.
  2. The 120s / 5-minute-build-limit conflict in the hang case remains real; it is
    explicitly deferred to #101 rather than resolved. Waived as a deliberate,
    recorded decision.
  3. golangci-lint still warns that gomodguard is deprecated since v2.12.0
    (visible in #17). Pre-existing, requires .golangci.yml, correctly out of
    scope; flagged in the PR body.
  4. Cosmetic mismatch: the rework comment says the PR-body section was retitled
    "Constraints honoured, and one constraint knowingly broken"; the body actually
    reads "Constraints: one knowingly broken". Content is correct either way.
  5. (closes #69) remains body-only by design — for the squash message at merge.
## Re-review of PR #98 — independent, head `54c4340` **Verdict: PASS.** No blocking findings. Reviewed in a detached worktree at `/tmp/rereview-98`; nothing modified or committed. Scope: whether the rework discharged B1/S1/N1 and weakened nothing. **Rework is comments-only, proved mechanically.** `git diff 06659ae 54c4340` touches `script/test`, `README.md`, `TODO.md`. In `script/test` every added and removed line begins with `#`; stripping comment lines from both revisions gives byte-identical files, and the `run_tests` body hashes to `1532b918355c6578a71ad9ff05a351b10af708df86749576d887a2b28571e292` on both, as claimed. **B1 discharged, and the new wording is accurate.** `script/test`'s comment states the 120s value `DELIBERATELY DIVERGES` from `REPO_POLICIES.md:192` and the canonical recipe at `:212-214`, with reasoning and a pointer to #101. Both line references verified against the checked-in file: `:192` is "Add a 30-second timeout", `:212-214` is the `-timeout 30s` Go recipe. #101 exists, is open, assigned to `sneak`, and carries the 5-minute-build-limit trade (`REPO_POLICIES.md:231`). The PR body's compliance claim is *corrected*, not softened: the bullet now says the listed files were "not edited", and the body explicitly retracts the inversion ("a zero-byte diff ... is evidence the *file* was not edited, **not** evidence the change complies with it"). Same divergence also recorded in `TODO.md`, `README.md` and the commit message. **S1 discharged.** `README.md` now gives the concrete figure: "about 11 seconds on every repeat run (measured, back to back: 0.4s cached versus 11.6s with `-count=1`)". **N1 discharged.** The script comment now lists all three observations (6.4s warm / 8.1s cold containerised / 10.2s independent cold), states the worst case is not tightly characterised, and corrects the headroom to 2.9x at 30s and ~12x at 120s. Arithmetic checked against every figure in the comment, the README and the PR body table; all correct. **Nothing weakened.** `.golangci.yml` sha256 `021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb`, unchanged; `git diff origin/main -- Dockerfile script/lint REPO_POLICIES.md .golangci.yml .gitea` is 0 bytes; zero Go files touched. Tree-wide there remain exactly two `go test` invocations, both with `-count=1`; no build tag exists anywhere, and `test-integration` survives only as explanatory prose. **`script/cibuild` on `54c4340`: exit 0** (`$?` captured immediately), `BUILDKIT_PROGRESS=plain`, wall `3m8s`. 14 `ok` lines, **0 `(cached)`**. The three check steps ran rather than replayed under a fresh `CHECK_EPOCH` (`1786285464253824020428353`): `#16 make fmt-check DONE 5.1s`, `#17 make lint DONE 66.6s` ending `0 issues.`, `#25 make test DONE 62.5s` — none `CACHED`; the 14 `CACHED` layers are all dependency layers below the `ARG`. No `docker builder prune` in any form; no host-side `make lint` verdict is claimed. **Process.** CI green on the head (`success`, 2m58s). `origin/main` is an ancestor of the head and `git merge-tree` yields zero conflict markers; API reports `mergeable: true`. No Claude/Anthropic reference or attribution trailer in the diff, commit message or PR body. Tip commit title ends ` (closes #93)`. Inclusive-terminology grep clean. Changed Markdown lines are within 80 columns (the over-80 lines in `README.md` are all pre-existing and untouched). ### Anomalies, non-blocking, no action required 1. `make test` in the container step reports 62.5s, over `REPO_POLICIES.md:192`'s "under 20 seconds" — but ~48s of that is compilation on a cold `GOCACHE`, and the host suite is ~12s. Pre-existing and not introduced here. 2. The 120s / 5-minute-build-limit conflict in the hang case remains real; it is explicitly deferred to #101 rather than resolved. Waived as a deliberate, recorded decision. 3. `golangci-lint` still warns that `gomodguard` is deprecated since v2.12.0 (visible in `#17`). Pre-existing, requires `.golangci.yml`, correctly out of scope; flagged in the PR body. 4. Cosmetic mismatch: the rework comment says the PR-body section was retitled "Constraints honoured, and one constraint knowingly broken"; the body actually reads "Constraints: one knowingly broken". Content is correct either way. 5. `(closes #69)` remains body-only by design — for the squash message at merge.
clawbot added merge-ready and removed needs-review labels 2026-08-09 16:29:12 +02:00
clawbot merged commit c51f693527 into main 2026-08-09 16:29:27 +02:00
clawbot deleted branch fix-test-gate 2026-08-09 16:29:27 +02:00
Sign in to join this conversation.