diff --git a/docs/roadmap/race.md b/docs/roadmap/race.md new file mode 100644 index 0000000..30d8a32 --- /dev/null +++ b/docs/roadmap/race.md @@ -0,0 +1,103 @@ +# Roadmap: synchronize delivery test fixtures + +Status: planned; implementation has not started. + +## Objective and evidence + +Make the delivery HTTP fixtures safe for concurrent access by test goroutines +and request handlers while preserving their existing behavioral assertions. +The [PromptKit bug report](promptkit-bug-report.md) supplies the original +diagnostics and consumer context. + +Upstream investigation reproduced +`TestReleaseKitSourceDeliveryWorkflowFromTaggedCheckout` under the race detector +with Go 1.26.8. The diagnostics identified `commit`, `remoteCommit`, and +`releaseCreates` accesses shared between the workflow test and HTTP handlers. +The workflow test and relevant unsynchronized accesses predate v0.4.0. +Subprocess completion supplies no synchronization for this shared Go state. + +The ordinary Woodpecker and multi-module workflow tests passed their focused +race-enabled runs during investigation. Source inspection nevertheless found +the same unsynchronized state pattern in their fixtures. A passing run alone +does not establish safe access under other scheduling. + +## Scope + +The correction belongs in test infrastructure: + +- The `deliveryServerState`, `newDeliveryServer`, and `writeDeliveryRelease` + helpers in [main_test.go](../../cmd/releasekit/main_test.go), including all + tests using that fixture. +- The [source-delivery workflow test](../../cmd/releasekit/releasekit_delivery_workflow_test.go) + and [ordinary Woodpecker workflow tests](../../cmd/releasekit/woodpecker_test.go). +- The `mappedDeliveryFixture`, `newMappedDeliveryFixture`, and their consumers + in [multi_module_woodpecker_test.go](../../cmd/releasekit/multi_module_woodpecker_test.go). + +Production behavior, public API contracts, and release requirements retain their +current definitions. Use the standard library and small fixture-local helpers, +following the [agent](../policy/agents.md) and +[testing](../policy/testing.md) policies. + +## Implementation + +1. **Synchronize the shared delivery fixture.** Give mutable fixture state a + `sync.Mutex`. Protect handler reads and writes, test-side configuration + changes, assertion reads, counters, page state, note content, and asset-map + operations with the same mutex. Initialize immutable configuration before + serving requests where practical; synchronize later initialization such as + the source commit assigned after profile creation. Review captured handler + values and response helpers as part of this boundary. + +2. **Update every shared-fixture consumer.** Use simple locked setters and + snapshot accessors for test configuration and assertions. Snapshot plain + values separately from the mutex, copying maps and mutable byte slices when + they will be inspected outside the lock. Include failure diagnostics that + format fixture state. Keep lock ownership clear in handler helpers and + release locks before executing CLI workflows or closing the server. + +3. **Apply the same discipline to the mapped fixture.** Protect its commit, + request and creation counters, page fields, uploads, and asset map, together + with all corresponding test accesses. Keep each fixture's synchronization + local and proportionate to its existing responsibilities. + +4. **Preserve behavioral coverage.** Retain rejection of mismatched hosted tags + before release creation, exact source-tag preservation, complete note bodies, + idempotent page and asset delivery, expected asset counts, mapped module + identity, retries using tagged configuration, and existing failure outcomes. + Use these workflows as the regression coverage for the reported race. Add + further coverage only for a concrete gap discovered during the correction. + +## Verification and completion + +With dependencies prepared, run the affected workflows from the repository root +using the local toolchain and offline module settings: + +```sh +GOTOOLCHAIN=local GOWORK=off GOPROXY=off GOSUMDB=off \ + go test -race -mod=readonly -count=1 ./cmd/releasekit \ + -run '^(TestReleaseKitSourceDeliveryWorkflowFromTaggedCheckout|TestWoodpeckerTagDeliveryTemplate|TestMultiModuleWoodpeckerDelivery)$' +``` + +Then run the full race-enabled suite once to verify the other shared-fixture +users and catch remaining cross-goroutine access: + +```sh +GOTOOLCHAIN=local GOWORK=off GOPROXY=off GOSUMDB=off \ + go test -race -mod=readonly -count=1 ./... +``` + +Review the fixture accesses as well as the test results: successful execution +complements the synchronization review. Keep local Git repositories, HTTP +servers, and synthetic module caches isolated as described in +[development](../development.md#testing-synthetic-modules). + +Completion means both fixtures and their consumers use synchronized state, +the existing assertions remain effective, and the focused and full race-enabled +suites pass. Record completion and verification here and update the bug report's +status with the remediation outcome. Commit the completed correction under the +repository's ordinary change workflow. + +This verification addresses the reported defect. Future release validation +continues to follow the [release procedure](../release.md). The correction is +suitable for a subsequent patch release; preparation and publication are separate +work under that procedure, preserving the published v0.4.0 contents.