Skip to content

test(config): prove schemeless masking linearity deterministically - #981

Merged
acamarata merged 1 commit into
mainfrom
dw5-cli-7
Oct 27, 2026
Merged

acamarata merged 1 commit into
mainfrom
dw5-cli-7

Conversation

@acamarata

@acamarata acamarata commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Row id: LINEAR-TEST2

Problem

TestSchemelessLinear still fails on windows-2022 on main after #980 (run 40445087019), e.g. 4000 B took 0s/call, 40000 B took 2.0303ms/call: not linear. A wall-clock ratio cannot be made reliable on shared Windows runners (coarse timer, GC pauses, noisy neighbours).

Note: the test lives in internal/credmask (Schemeless, maskDSNUserinfo), not internal/config. MaskURLCredentials calls it. I ran both packages.

Change

  • internal/credmask/schemeless.go: a nil-in-production stepHook that receives the bytes read by each scan in maskDSNUserinfo (forward pass, colon-prefix LastIndexByte) and maskKeywordValues (per match). No behaviour change.
  • TestSchemelessLinear is now deterministic: for 13 adversarial shapes (@a(, :@a(, a:@, a:b@c(, x=y@a(, password=, password= x, letter runs, ::::, @@@@, one colon / :// / quote followed by @a() at 4 KB and 40 KB it requires steps < 15x, allocation count < 15x, allocated bytes < 25x (TotalAlloc deltas, min of 3). Allocation checks are skipped under -race (the race detector shadows allocations); the step check always runs.
  • TestSchemelessLinearWallClock is the coarse safety net: skipped on Windows and -short, best of 5, 40 KB vs 400 KB, ratio < 40 plus a 5 ms floor.

Measured growth for 10x input (current code, 4 KB to 40 KB)

  • steps: exactly 10.0x on every shape
  • allocation count: 9.7x to 9.9x
  • allocated bytes: 12.5x to 18.2x at this size, then flat per input byte (about 26 B/byte for a:b@c(, 46 to 55 B/byte for @a() from 256 KB to 4 MB. This is slice doubling and size classes, not super-linearity, hence the 25x bytes bound (a quadratic rebuild is 100x).
  • So the current implementation is linear; no implementation change was needed.

Mutation proof

Temporarily restored the pre-#979 maskDSNUserinfo (from c1d7e536^, with steps(2*len(token)) on its rescans): TestSchemelessLinear FAILED on 5 shapes (@a(: 5,326,668 vs 533,266,668 bytes read; x=y@a(, one colon then @a(, scheme then @a(, quote then @a(), and the wall-clock test failed too (@a( 40 KB 3.5 ms, 400 KB 239 ms). Reverted; the committed code is the linear one.

Commands run

  • go test -count=20 -run TestSchemelessLinear ./internal/credmask: ok (21.9 s; also runs the wall-clock test)
  • go test -count=1 ./internal/config ./internal/credmask: ok
  • go test -race -count=1 ./internal/credmask: ok
  • go test -count=1 -covermode=atomic ./internal/credmask: ok
  • GOOS=windows go vet ./internal/config ./internal/credmask: clean
  • GOOS=windows go test -c ./internal/credmask: compiles (the Windows test itself runs only in CI)
  • gofmt -l internal: clean

Untouched: cli#958. TestMaskURLCredentialsLinear in internal/config is also wall-clock but uses a 250 ms floor and was not in the failing log, so it is unchanged.

TestSchemelessLinear compared wall-clock times, which cannot be made
reliable on shared Windows runners (coarse timer, GC pauses, noisy
neighbours). Assert linearity on counted work instead: a test-only step
hook in the DSN and keyword scans, plus allocation counts and bytes, must
each grow under 15x (bytes 25x) for 10x input over 13 adversarial shapes.
Allocation checks are skipped under -race, which shadows allocations.
The wall-clock check stays as a coarse safety net, best of 5, 40x plus a
5 ms floor, and is skipped on Windows and under -short.
@acamarata
acamarata merged commit bcbec06 into main Oct 27, 2026
35 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.

1 participant