carlos / platform Public

plan9 SQL seal tests: read the whole goroutine dump, not its first MiB

waitPlan9SealQueued and the handle-registration wait looked for the queued
goroutine in runtime.Stack(buf, true) with a fixed 1 MiB buffer.
runtime.Stack stops at the buffer's end, and a full run of the console
package has thousands of goroutines. A goroutine past that point was never
seen, and the wait timed out after 10 s. CI on Go 1.26.10 hit it twice. The
diagnostic run (54f217fe) showed the dump at exactly 1048576 of 1048576
bytes with 3344 goroutines. Both waits now use plan9GoroutineStacks, which
doubles the buffer until the dump fits. This replaces the diagnostic, which
the revert in this commit removes.
Human

Prompt

Can we make sure we're on the latest version of go  to deal with https://emudhra.we-have-a-problem.com ?

From this commit's own message. The prompt ledger has no entries for it — which is what a squashed, rebased or amended commit looks like, and what every commit looks like in a repo without a ledger.

Summary

Adds plan9GoroutineStacks (a growing buffer) and uses it in both stack-scanning waits in plan9_sql_seal_test.go. Test-only.
Agent notes
Reproduced locally with 4000 parked goroutines and the target started last: the 1 MiB buffer filled and missed it, and the helper found it. Why 1.26.10 tips it over and 1.26.5 doesn't is not established: the dump sits right at the limit, and goroutine order and stack depth vary between toolchains. internal/host/startup_largebox_linux_test.go:1709 has the same pattern with 8 MiB; not touched here.
claude agent, operated by paul@keymail.dev 7f5d3c2b8a3f1794a448c6f4177169021f05fad2 parent 54f217f
1 file changed, +18 −8
  • internal/console/plan9_sql_seal_test.go +18 −8

CI passed — run details

CI log
=== gate ===
cd launchctx && go vet ./... && go test ./... -count=1
ok  	amadan.net/carlos/platform.git/launchctx	0.014s
?   	amadan.net/carlos/platform.git/launchctx/controlname	[no test files]
?   	amadan.net/carlos/platform.git/launchctx/wireid	[no test files]
go vet ./...
gofmt -l .: clean
go test ./... -count=1 -timeout 30m
ok  	github.com/carlosframework/platform	336.797s
?   	github.com/carlosframework/platform/cmd/changelog	[no test files]
ok  	github.com/carlosframework/platform/cmd/console	3.135s
ok  	github.com/carlosframework/platform/cmd/moveprobe	92.548s
ok  	github.com/carlosframework/platform/cmd/zddprobe	0.738s
ok  	github.com/carlosframework/platform/internal/activator	250.356s
ok  	github.com/carlosframework/platform/internal/agentsock	0.018s
ok  	github.com/carlosframework/platform/internal/alerting	0.004s
ok  	github.com/carlosframework/platform/internal/analytics	0.036s
ok  	github.com/carlosframework/platform/internal/appconfig	2.677s
ok  	github.com/carlosframework/platform/internal/apperr	0.099s
ok  	github.com/carlosframework/platform/internal/applog	0.169s
ok  	github.com/carlosframework/platform/internal/awsinv	0.011s
ok  	github.com/carlosframework/platform/internal/boxchoice	0.007s
ok  	github.com/carlosframework/platform/internal/boxid	0.736s
?   	github.com/carlosframework/platform/internal/boxid/boxidtest	[no test files]
?   	github.com/carlosframework/platform/internal/boxid/internal/signtest	[no test files]
ok  	github.com/carlosframework/platform/internal/boxvolumes	0.009s
ok  	github.com/carlosframework/platform/internal/caps	0.014s
ok  	github.com/carlosframework/platform/internal/certwarm	0.003s
ok  	github.com/carlosframework/platform/internal/cgroup	0.741s
ok  	github.com/carlosframework/platform/internal/changelog	0.456s
ok  	github.com/carlosframework/platform/internal/claimactivation	1.020s
ok  	github.com/carlosframework/platform/internal/clamd	0.059s
?   	github.com/carlosframework/platform/internal/cliflag	[no test files]
ok  	github.com/carlosframework/platform/internal/console	419.306s
?   	github.com/carlosframework/platform/internal/controlname	[no test files]
?   	github.com/carlosframework/platform/internal/controlsock	[no test files]
ok  	github.com/carlosframework/platform/internal/dbdoor	6.630s
ok  	github.com/carlosframework/platform/internal/dbdoor/dbdoortest	0.017s
ok  	github.com/carlosframework/platform/internal/dbverify	0.006s
ok  	github.com/carlosframework/platform/internal/dnsrec	0.006s
ok  	github.com/carlosframework/platform/internal/docsite	0.011s
ok  	github.com/carlosframework/platform/internal/domains	3.181s
ok  	github.com/carlosframework/platform/internal/doorkey	0.019s
ok  	github.com/carlosframework/platform/internal/economics	0.014s
ok  	github.com/carlosframework/platform/internal/edge	46.199s
?   	github.com/carlosframework/platform/internal/edgeproof	[no test files]
ok  	github.com/carlosframework/platform/internal/edgesfile	0.012s
ok  	github.com/carlosframework/platform/internal/fleetapi	0.246s
ok  	github.com/carlosframework/platform/internal/gate	2.282s
ok  	github.com/carlosframework/platform/internal/genselect	0.048s
ok  	github.com/carlosframework/platform/internal/geo	0.022s
ok  	github.com/carlosframework/platform/internal/geoip	0.056s
ok  	github.com/carlosframework/platform/internal/historyreadback	0.669s
ok  	github.com/carlosframework/platform/internal/host	194.891s
ok  	github.com/carlosframework/platform/internal/hostactors	6.698s
ok  	github.com/carlosframework/platform/internal/hostactors/awsmembership	0.013s
ok  	github.com/carlosframework/platform/internal/hostbox	3.606s
ok  	github.com/carlosframework/platform/internal/hostclaim	0.984s
ok  	github.com/carlosframework/platform/internal/hostenv	0.016s
ok  	github.com/carlosframework/platform/internal/hostevidence	0.007s
ok  	github.com/carlosframework/platform/internal/hostexec	7.239s
ok  	github.com/carlosframework/platform/internal/hostfence	0.088s
ok  	github.com/carlosframework/platform/internal/hostfiles	10.738s
ok  	github.com/carlosframework/platform/internal/hostfloor	0.039s
ok  	github.com/carlosframework/platform/internal/hostguard	1.161s
ok  	github.com/carlosframework/platform/internal/hostops	2.589s
?   	github.com/carlosframework/platform/internal/hostops/fencerelease	[no test files]
ok  	github.com/carlosframework/platform/internal/hostops/internal/fencerelease	0.004s
ok  	github.com/carlosframework/platform/internal/hostquarantine	0.003s
ok  	github.com/carlosframework/platform/internal/hostrelocate	0.756s
ok  	github.com/carlosframework/platform/internal/hostresolve	0.282s
ok  	github.com/carlosframework/platform/internal/hostwrite	0.009s
ok  	github.com/carlosframework/platform/internal/infraview	0.009s
ok  	github.com/carlosframework/platform/internal/instancectl	5.325s
ok  	github.com/carlosframework/platform/internal/instanceexec	2.782s
ok  	github.com/carlosframework/platform/internal/instancefs	0.008s
ok  	github.com/carlosframework/platform/internal/instancekey	0.013s
ok  	github.com/carlosframework/platform/internal/instanceupdates	0.012s
ok  	github.com/carlosframework/platform/internal/layout	2.290s
ok  	github.com/carlosframework/platform/internal/lbhealth	0.003s
ok  	github.com/carlosframework/platform/internal/lease	10.069s
ok  	github.com/carlosframework/platform/internal/lease/leasetest	0.645s
ok  	github.com/carlosframework/platform/internal/ledger	0.330s
ok  	github.com/carlosframework/platform/internal/mail	0.305s
ok  	github.com/carlosframework/platform/internal/maintenance	0.113s
ok  	github.com/carlosframework/platform/internal/maintenanceexec	5.804s
ok  	github.com/carlosframework/platform/internal/maintenanceguard	0.122s
ok  	github.com/carlosframework/platform/internal/metrics	0.006s
ok  	github.com/carlosframework/platform/internal/moves	22.474s
ok  	github.com/carlosframework/platform/internal/moves/archive	1.579s
ok  	github.com/carlosframework/platform/internal/objstore	0.227s
ok  	github.com/carlosframework/platform/internal/ops	0.239s
ok  	github.com/carlosframework/platform/internal/park	0.393s
ok  	github.com/carlosframework/platform/internal/privatefile	0.004s
ok  	github.com/carlosframework/platform/internal/provision	22.597s
ok  	github.com/carlosframework/platform/internal/publicrelease	0.009s
?   	github.com/carlosframework/platform/internal/regionname	[no test files]
ok  	github.com/carlosframework/platform/internal/registry	6.288s
ok  	github.com/carlosframework/platform/internal/relay	7.231s
ok  	github.com/carlosframework/platform/internal/release	26.796s
ok  	github.com/carlosframework/platform/internal/rollout	4.423s
ok  	github.com/carlosframework/platform/internal/rolloutwords	0.005s
ok  	github.com/carlosframework/platform/internal/rootaws	0.009s
ok  	github.com/carlosframework/platform/internal/rootparticipation	0.066s
ok  	github.com/carlosframework/platform/internal/rootstate	0.031s
ok  	github.com/carlosframework/platform/internal/runs	0.557s
ok  	github.com/carlosframework/platform/internal/s3compat	0.005s
ok  	github.com/carlosframework/platform/internal/safefile	0.006s
ok  	github.com/carlosframework/platform/internal/schedule	2.914s
ok  	github.com/carlosframework/platform/internal/seeds	0.012s
ok  	github.com/carlosframework/platform/internal/sim/hostlife	17.127s
ok  	github.com/carlosframework/platform/internal/sim/litestreamfacts	4.070s
ok  	github.com/carlosframework/platform/internal/status	0.099s
ok  	github.com/carlosframework/platform/internal/steering	0.011s
ok  	github.com/carlosframework/platform/internal/stopevidence	0.258s
ok  	github.com/carlosframework/platform/internal/svcrole	0.002s
ok  	github.com/carlosframework/platform/internal/telemetry	0.005s
ok  	github.com/carlosframework/platform/internal/termfence	0.006s
ok  	github.com/carlosframework/platform/internal/tunnelclient	0.004s
ok  	github.com/carlosframework/platform/internal/unixdial	0.005s
ok  	github.com/carlosframework/platform/internal/updatewords	0.008s
ok  	github.com/carlosframework/platform/internal/usage	0.006s
ok  	github.com/carlosframework/platform/internal/version	0.002s
ok  	github.com/carlosframework/platform/internal/vet	1.849s
=== cross ===
--- shard 0 of 5 ---
cross-compiling darwin/arm64
--- shard 1 of 5 ---
cross-compiling darwin/amd64
--- shard 2 of 5 ---
cross-compiling linux/arm64
linux/arm64 carlos binary: 49938594 bytes (ceiling 52000000)
--- shard 3 of 5 ---
cross-compiling windows/amd64
--- shard 4 of 5 ---
cross-compiling windows/arm64
=== minio-contract ===
minio contract: arm64, minio RELEASE.2025-09-07T16-13-09Z, mc RELEASE.2025-08-13T08-35-41Z
  minio: downloading https://github.com/minio/minio/releases/download/RELEASE.2025-09-07T16-13-09Z/minio.linux-arm64.RELEASE.2025-09-07T16-13-09Z
  minio: downloaded, digest verified
  mc: downloading https://github.com/minio/mc/releases/download/RELEASE.2025-08-13T08-35-41Z/mc.linux-arm64.RELEASE.2025-08-13T08-35-41Z
  mc: downloaded, digest verified
  minio healthy on 127.0.0.1:20999
Added `local` successfully.
Bucket created successfully `local/contract-bucket`.
Bucket created successfully `local/denied-bucket`.
Created policy `contract-only` successfully.
Added user `scopeduser` successfully.
Attached Policies: [contract-only]
To User: scopeduser
  buckets and scoped user ready
=== RUN   TestDeliveredContractMinio
=== RUN   TestDeliveredContractMinio/put
=== RUN   TestDeliveredContractMinio/get_round-trips_the_body
=== RUN   TestDeliveredContractMinio/list_shows_the_key
=== RUN   TestDeliveredContractMinio/head_and_list_agree_on_the_version
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_its_own_object
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/not_by_PutObjectTagging
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/and_not_by_x-amz-tagging_on_upload
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CreateMultipartUpload
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CopyObject_with_a_REPLACE_tagging_directive
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/but_multipart_itself_is_allowed
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_copy_itself_is_allowed
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/a_POST-policy_forged_tag_with_a_matching_version_is_still_not_a_verdict
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_an_ordinary_tagged-with-something-else_upload_is_allowed
=== RUN   TestDeliveredContractMinio/delete_removes_it
=== RUN   TestDeliveredContractMinio/cross-bucket_denial
--- PASS: TestDeliveredContractMinio (0.02s)
    --- PASS: TestDeliveredContractMinio/put (0.00s)
    --- PASS: TestDeliveredContractMinio/get_round-trips_the_body (0.00s)
    --- PASS: TestDeliveredContractMinio/list_shows_the_key (0.00s)
    --- PASS: TestDeliveredContractMinio/head_and_list_agree_on_the_version (0.00s)
    --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/not_by_PutObjectTagging (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/and_not_by_x-amz-tagging_on_upload (0.00s)
    --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route (0.01s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CreateMultipartUpload (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CopyObject_with_a_REPLACE_tagging_directive (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/but_multipart_itself_is_allowed (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_copy_itself_is_allowed (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/a_POST-policy_forged_tag_with_a_matching_version_is_still_not_a_verdict (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_an_ordinary_tagged-with-something-else_upload_is_allowed (0.00s)
    --- PASS: TestDeliveredContractMinio/delete_removes_it (0.00s)
    --- PASS: TestDeliveredContractMinio/cross-bucket_denial (0.00s)
PASS
ok  	github.com/carlosframework/platform/internal/objstore	0.025s
=== RUN   TestT4StorageProbeMinio
2026/10/20 17:15:48 moves: T4: STORE: list: operation error S3: ListObjectsV2, https response error StatusCode: 403, RequestID: 18E04C4DB415233D, HostID: 7c420053e0fbcd7f41653fdd92ffa2802c903d05303b1aa15adc2e8bb65d183f, api error SignatureDoesNotMatch: The request signature we calculated does not match the signature you provided. Check your key and signing method.
--- PASS: TestT4StorageProbeMinio (0.01s)
PASS
ok  	github.com/carlosframework/platform/internal/host	0.023s
minio contract: PASS
diff --git a/internal/console/plan9_sql_seal_test.go b/internal/console/plan9_sql_seal_test.go
index 86b3604c5..86c910f45 100644
--- a/internal/console/plan9_sql_seal_test.go
+++ b/internal/console/plan9_sql_seal_test.go
@@ -46,20 +46,32 @@ func plan9SealQueuedStmtQuery(st *sql.Stmt, out chan<- error) {
out <- err
}
+// plan9GoroutineStacks returns every goroutine's stack. runtime.Stack stops
+// at the end of the buffer it is given, and a full run of this package has
+// thousands of goroutines, so the buffer grows until the whole dump fits:
+// a goroutine past a fixed buffer's end would never be seen.
+func plan9GoroutineStacks() []string {
+ buf := make([]byte, 1<<20)
+ for {
+ n := runtime.Stack(buf, true)
+ if n < len(buf) {
+ return strings.Split(string(buf[:n]), "\n\n")
+ }
+ buf = make([]byte, 2*len(buf))
+ }
+}
+
// waitPlan9SealQueued returns once the goroutine running fn has finished
// (done has a value) or is parked on the database/sql driver-connection lock,
// which the batch commit holds.
func waitPlan9SealQueued(t *testing.T, fn string, done chan error) {
t.Helper()
deadline := time.Now().Add(10 * time.Second)
- buf := make([]byte, 1<<20)
- n := 0
for time.Now().Before(deadline) {
if len(done) > 0 {
return
}
- n = runtime.Stack(buf, true)
- for _, g := range strings.Split(string(buf[:n]), "\n\n") {
+ for _, g := range plan9GoroutineStacks() {
onDriver := strings.Contains(g, "database/sql.withLock(") || strings.Contains(g, "database/sql.resultFromStatement(") || strings.Contains(g, "database/sql.rowsiFromStatement(")
if strings.Contains(g, "console."+fn+"(") && onDriver && strings.Contains(g, "sync.(*Mutex).lockSlow(") {
return
@@ -67,7 +79,7 @@ func waitPlan9SealQueued(t *testing.T, fn string, done chan error) {
}
runtime.Gosched()
}
- t.Fatalf("%s neither finished nor queued on the driver connection (DIAGNOSTIC: last dump %d of %d bytes, %d goroutines)", fn, n, len(buf), runtime.NumGoroutine())
+ t.Fatalf("%s neither finished nor queued on the driver connection", fn)
}
// TestPlan9SQLBatchSealsRetainedWriteQueuedAcrossCommit checks the view fast
@@ -249,11 +261,9 @@ func TestPlan9SQLSealDuringHandleRegistration(t *testing.T) {
}
}()
deadline := time.Now().Add(10 * time.Second)
- buf := make([]byte, 1<<20)
waiting := false
for time.Now().Before(deadline) && !waiting {
- n := runtime.Stack(buf, true)
- for _, g := range strings.Split(string(buf[:n]), "\n\n") {
+ for _, g := range plan9GoroutineStacks() {
if strings.Contains(g, "console.(*claimBoundDB)."+method+"(") && strings.Contains(g, "sync.(*Mutex).lockSlow(") {
waiting = true
break