Skip to content

Pin the capture-scope timeout floor, not just its wiring - #182

Merged
bogatyrjov1 merged 1 commit into
mainfrom
guard-the-timeout-floor
Aug 29, 2026
Merged

Pin the capture-scope timeout floor, not just its wiring#182
bogatyrjov1 merged 1 commit into
mainfrom
guard-the-timeout-floor

Conversation

@bogatyrjov1

Copy link
Copy Markdown
Contributor

A 40 ms fixture pins the bound at "above 40 ms", and 45 ms is a live defect

The test added in #181 proves the preflight waits for its own answer, by having the stub take a real 40 ms. That pins the wiring. It does not pin the magnitude, and a post-merge validator on the app side found the gap: CAPTURE_SCOPE_TIMEOUT_MS = 45 typechecks clean and leaves the whole cli suite green.

45 ms aborts every real preflight there has ever been. Measured server-side over 1,271 production requests to this endpoint:

ms
p50 472
p95 1,269
p99 1,682
max 8,419

Every abort fails open by design, so the symptom is silent: captures are sent without asking whether the repository was excluded, and from the outside that is indistinguishable from the server having said "capture".

This is the fixture-grid trap in general form — a fixture can only ever pin a boundary it happens to straddle. So the constant is now exported and pinned from outside, as a floor rather than an equality: raising it is free, lowering it below the line is the defect. Equality would fail on any deliberate retune and teach the next person to edit the test in the same commit, which is how a guard becomes a formality.

Bisected across the floor, every value typecheck-clean

CAPTURE_SCOPE_TIMEOUT_MS result
0 2 fail (floor + the behavioural test)
45 1 fail (floor) — the survivor this PR exists for
4999 1 fail (floor)
5000 11 pass / 0 fail — the documented boundary, exactly
10_000 (shipped) 11 pass / 0 fail

Full cli/src/*.test.ts: 954 pass / 0 fail. tsc -p cli/tsconfig.json: clean.

The behavioural test stays as it is. It proves the request actually waits; this one proves it waits long enough to matter. Neither is sufficient alone: the behavioural test misses 45, and the floor alone would pass on a bound that was never wired to the fetch at all.

Reasoning

written by the agent in-session via backthread/add-reasoning-to-prs

Decisions

  • The constant is now exported purely so a test can pin it from outside. A test that re-declares the expected value only compares the constant to itself, which is why the previous round left this gap.
  • The floor is 5,000 ms, chosen against measured p99 (~1,700 ms) with roughly 3x headroom, not against the shipped 10,000. That keeps the guard meaningful if someone retunes the bound downward for a real reason.

Trade-offs

  • The behavioural fixture stays at 40 ms rather than being raised above production p95. Raising it would pin the magnitude behaviourally but add well over a second to every suite run, and the exported floor gets the same property for free.

Limitations

  • The floor is a static number in a test, so it does not track production latency. If this endpoint ever gets materially slower, 5,000 ms could stop being generous and nothing here would say so. Check: re-measure p99 if the preflight starts timing out in the field.

The test added last round has the stub answer after a real 40 ms, which
proves the preflight waits for its own answer. It does not pin how long.
CAPTURE_SCOPE_TIMEOUT_MS = 45 typechecks clean and leaves the whole suite
green, and 45 ms aborts every real preflight there has ever been: measured
over 1,271 production requests, p50 is 472 ms, p95 1,269 ms, p99 1,682 ms
and max 8,419 ms. Every abort fails open, so the symptom is silence.

A fixture can only pin a boundary it happens to straddle, so the constant
is exported and pinned from outside instead, as a floor rather than an
equality. Raising the bound stays free; lowering it past the line is the
defect. An equality would fail on any deliberate retune and teach the next
person to edit the test in the same commit.

Bisected, every value typecheck-clean: 0 fails twice, 45 and 4999 fail the
floor, 5000 and 10_000 pass. Full suite 954 pass, 0 fail.
@bogatyrjov1
bogatyrjov1 merged commit e2fb00c into main Aug 29, 2026
7 checks passed
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.

2 participants