Skip to content

Fix macOS race in sync_render_test.go: wait for the run job before counting engine calls (main is red) #280

Closed

Description

@DanielNetzer

main is red on macOS: race in sync_render_test.go (blocks the v0.3.0 tag, 2026-10-27)

lab/internal/ui/sync_render_test.go (from #266) asserts the fake engine's call count right after POST /api/runs returns 202 Accepted. The engine call runs on the run job's goroutine, so on a slower runner the count is still 0.

Failures seen on macos-latest:

Fix (tests only, no product change):

  • After every accepted start in sync_render_test.go, wait for the run job with the existing waitJob(t, h, id) helper from gates_test.go, or an equivalent readiness signal from the fake drive, before reading d.calls().
  • Keep every refusal assertion exactly as strict: refused starts still assert 0 engine calls, with no wait needed, because a refusal never starts a job.
  • Do not add sleeps or wall-clock budgets.
  • Check the other *_test.go files in lab/internal/ui for the same pattern (call counts read right after a 202 from /api/runs or /api/loop/start) and fix them the same way.

Done when

  • go test -count=50 -run 'TestSyncRenderStartIntake' ./internal/ui/ passes.
  • The targeted check passes: go test -count=3 ./internal/ui/....

Review checklist (read before coding)

The adversarial review checks these every time. Recent slices failed review on all of them, so build them in from the start:

  • Bounds: sizes, counts, time and total work are bounded, and hitting a bound fails safe (incomplete or truncated, never silently accepted).
  • Filesystem safety: paths cannot traverse. Use Lstat and O_NOFOLLOW, and check symlinks and ownership. Watch for TOCTOU races on shared dirs (/tmp). Only ever delete Forgecell-owned, marked paths.
  • Untrusted input: issue text, repository files, model and tool output, and ledgers can be malformed, huge or hostile. Validate them, never interpolate them into HTML or a shell, and never let them trigger retries or approvals.
  • No local leaks: no absolute local paths, environment variables or credentials in output, logs, the UI or ledgers.
  • Contract changes: a changed adapter invocation bumps the protocol, and approved digests still bind exactly what was shown.
  • Tests: deterministic. Use no wall-clock budgets (use readiness markers or seams), write nothing into the user's real temp or home, and cover the failure path as well as the happy path.

Plan checks (for intake)

Check category must be one of regression, candidate or setup. Use targeted package tests only as plain go test commands (for example go test ./internal/<pkg>/...); the protected view adds -json itself when protected deltas are declared. The Formula baseline already runs the full suite once, so don't add another full go test ./... check, and don't repeat its go vet or gofmt checks. A plan may hold at most 16 checks in total, counting the 5 Formula baseline checks, so prefer one combined targeted command over one check per package.

  • Keep base tests compiling: the protected view runs the base _test.go files against your code. Never change the signature of an existing function, method or type that a base test file calls. Add a new function or field instead. A protected build failure can't be declared as an expected delta.
  • Keep base tests runnable: changed defaults or behaviour must not make a base test hang or panic. A package that aborts in the protected view hides every test after it, and nothing can be declared. Keep the old default when unconfigured and opt in to the new one.
  • Plan checks: the operator's visual or browser check is a manual step after delivery, never a plan check. Every check leaves reviewedAcceptance and independentProvenance empty.

Activity

  1. added this to the v1 milestone on Oct 27, 2026
  2. DanielNetzer commented on Oct 27, 2026

    @DanielNetzer
    OwnerAuthor

    Merged via #281.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions