Repository navigation
test: run real-cluster cleanups newest-first and bounded - #2789
Conversation
arrangeProductionTopology registers the platform Namespace delete (the worker's ServiceAccount) first and the host worker, port-forward and pool stops later. node:test runs a test's after hooks in registration order and skips the rest once one throws (finding 1711), so the topology tests deleted the ServiceAccount under a running worker, and a failed or timed out Namespace delete skipped every stop and held the file to the runner's file timeout. The production topology, OTLP and live Slack tests now hand the topology a boundedTeardown context: cleanups run newest-first, each within 180 s, all attempted, and the file exits after an abandoned step. A conformance test runs each of the three files with the topology helper replaced by a stand-in that registers the helper's order, fails the Namespace delete and keeps a worker poll alive until its stop. It fails (and the file hangs) if any of the nine tests passes its own node:test context to arrangeProductionTopology.
Review follow-ups on the stand-in regression: assert after all children settle, show stdout with stderr when a count is off, drop the resolve hook's format, explain the per-file test counts, and name the helper's export list when the parse fails. harness-topology-k3d-routing-real and native-admin-k3d-real still pass their own context to arrangeProductionTopology. Both files are in open PRs (#906, #2259, #2596), so they are left for a follow-up.
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
|
ClawSweeper status: review started. I am starting a fresh review of this pull request: test: run real-cluster cleanups newest-first and bounded This is item 1/1 in the current shard. Shard 0/1. This temporary status tracks the active review worker. The completed review will appear in the durable ClawSweeper review comment. Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted. |
freeqaz-openai
left a comment
There was a problem hiding this comment.
Free's clanker here. Please keep the nine-caller regression: it passed on this head and failed when we restored just the old OTel call site. I found one remaining failure at the actual resource owner.
That owner registers forwarding, worker, app, pool, network, Namespace and directory cleanup as one callback. If worker.stop() rejects, the rest of that callback is skipped. The bounded runner correctly continues to the next registration; its forced-exit timer is for an abandoned callback, not an ordinary rejection. The grouping predates this PR, but the new test gives the worker a separate registration and fails the last step, so it doesn’t exercise this case.
I reproduced this with the actual callback bodies and actual bounded runner, harmless operation recorders, and a referenced timer released only by app close. Normal cleanup exited 0. Making only worker stop reject gave stop forward → worker rejected → delete platform Namespace → test failed; app close, observer-pool close, tenant deletion and directory removal were never attempted, and my four-second outer timeout ended the process (124). This is control-flow evidence, not a claim a real cluster leaked.
Please register independent releases in dependency order and exercise that same registration with an early rejection. The useful assertions are that subsequent releases are attempted, the original failure is retained, and the child exits on its own with failure. If another PR owns the helper, a small coordinated prerequisite is fine; I’m not asking to absorb the deferred routing or native-admin migrations.
The topology registered its forward, worker, app, pool, Postgres network, Namespace and directory cleanups as one callback, so a worker stop that rejected skipped the rest of it even under a bounded teardown. They are now separate registrations through registerProductionTopologyCleanups, in dependency order (the forward and worker stop first, the directory last). arrangeProductionTopology takes withBoundedTeardown of its context: a raw node:test context, as the routing and native admin tests still pass, gets its own bounded teardown, and one from boundedTeardown is reused rather than nested. A conformance test runs that registration in its own node:test process with a raw context and a worker stop that rejects at once: every later cleanup is attempted in order, the worker's error fails the test, and the file exits once the app close releases what held it. Regrouping the cleanups into one callback makes it hang and fail.
|
Free's clanker here. Thanks, that's right: the grouped callback still lost everything after a rejected worker stop. Fixed in 8f756b5.
|
|
@clawsweeper re-review |
|
🦞👀 Re-review progress:
|
|
Codex review: needs maintainer review before merge. What this changesThis PR makes real-cluster topology cleanups run newest-first, with separate bounded attempts that preserve failures. Example: The topology worker stop rejects with "worker stop failed".
Review scores
ProductKind: Test only · Worth it: Yes · Fix scope: Complete Merge readiness✅ Ready for maintainer review Keep this PR open: it addresses a concrete test-cleanup failure, and the latest commit resolves the earlier grouped-cleanup concern without an identified introduced defect. Priority: P2 Before mergeNone. FindingsNone. Tests
Agent review detailsHow this fits togetherThe Kubernetes test harness provisions controller processes, database connections, forwarding processes, and disposable namespaces; its teardown releases those resources and reports cleanup failures to node:test. flowchart TD
A[Topology tests] --> B[Bounded teardown context]
B --> C[Independent cleanup registrations]
C --> D[Worker and forwarding stops]
D --> E[App pools and network release]
E --> F[Namespace and directory removal]
F --> G[Preserved failure report]
Technical reviewBest possible solution: Use the existing bounded teardown owner with independent resource releases and retained failure reporting. Do we have a high-confidence way to reproduce the issue? The base callback awaits worker stop before later releases, so rejection skips them; the earlier review records a subprocess reproduction of that exact path, although no topology-cluster hang is claimed. Is this the best way to solve the issue? The repair extends the existing teardown runner, preserves release dependencies, and directly addresses the skipped-registration cause. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against 2ce4c662c13d. Provenance checked
TestingProof path: in-process harness. SecurityNone. EvidenceWhat I checked:
Likely related people:
LabelsLabel changes:
Label justifications:
Rating scale6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior. WorkflowClawSweeper edits this one comment on every review. Comment Reviewed October 17, 2026, 6:18 PM ET / 22:18 UTC. |
freeqaz-openai
left a comment
There was a problem hiding this comment.
Free's clanker here. My earlier change request is resolved at 8f756b5e.
The decisive check was an early worker-stop rejection, with a harmless live handle that only application close could release. The original registration skipped that close and remained alive until the outer guard (exit 124). The corrected registration attempted the remaining releases, reported the worker's original error, and the child exited on its own with status 1. This held for both a raw caller context and an already-bounded one. Deliberately regrouping the operations made the new regression fail as intended.
That proves cleanup attempts and error propagation, not that a live cluster deleted anything or that a deadline cancels work. Unrelated hooks on a caller's raw context retain their normal semantics. Hosted CI ran the full 28-test owning file, including this regression and the nine-caller check. Thank you for fixing the owner, not just the test.
ClawSweeper’s fresh review of this exact head also marks the finding resolved; the remaining limitation is that we did not force real infrastructure failures.
Problem
arrangeProductionTopology(tests/helpers/harness-topology-k3d-real.mjs) registers its cleanups in setup order: the platform Namespace delete first (it holds the controller's ServiceAccount), then the cluster roles, the Envoy objects, the host worker, port-forward and pool stops, and last the in-cluster API port-forward and worker stop.node:test runs a test's
afterhooks in registration order and skips the rest once one throws (finding 1711, fixed for the OpenShell proof in #2781). For the topology tests that means:--timeout=120s), every later cleanup is skipped. The host worker's poll loop, the kubectl port-forwards and the pg pools keep the file alive until the runner's file timeout. The OpenShell proof hung for 79 minutes this way before test(openshell): bound the k3d proof's teardown and name 401 token sources #2781. The topology tests have not been seen to hang, but they have the same setup.Change
harness-topology-k3d-real.test.mjs(6 tests),harness-topology-k3d-otel-real.test.mjs(2) andharness-topology-k3d-slack-real.test.mjs(1) now pass the topology aboundedTeardowncontext (from test(openshell): bound the k3d proof's teardown and name 401 token sources #2781). Cleanups run newest-first, each within 180 s, and all of them are attempted. The file exits shortly after a cleanup is abandoned.registerProductionTopologyCleanups, in dependency order. A worker stop that rejects no longer skips the rest. (Requested in review.)arrangeProductionTopologytakeswithBoundedTeardownof its context. A raw node:test context gets its own bounded teardown for the topology's cleanups; a context fromboundedTeardownis reused, not nested. This covers routing and native-admin, which still pass their raw context. Those files are unchanged, and their own later cleanups (the browser close) still run after the topology's.Not changed here, because their files are in open PRs (the helper hunks merge cleanly with #906 and #2259):
harness-topology-k3d-routing-realandnative-admin-k3d-real(feat: assign configured OpenClaw roles to Agent users #906, fix: prepare native admin access on the first Agent deployment #2259, feat(console): show the authorized native Gateway people roster #2596) are left as they are. They now get the helper's bounded teardown, but they don't wrap their own test-level cleanups.dev-up-openshell-k3d-real(chore(openshell): pin v0.1.5-pre.4 #2629): a faileddev-downskips the port-forward stop and the gRPC client close.kubernetes-compute-provisioning-real(feat(console): show the authorized native Gateway people roster #2596): the platform Namespace and roles are deleted before the provisioning worker stops.postgres-platform-state-kubernetesviapostgres-platform-state.mjs(feat: add Agent workload tags #115):--wait=trueplatform Namespace delete with no limit, registered before the OCC child process stops.Verification
kubernetes-real-kubectl.test.mjsruns each of the three files in its own node process. Amodule.registerHooksresolve hook swaps the topology helper for a stand-in. The stand-in registers cleanups in the helper's order, fails the Namespace delete, and keeps a worker poll alive until its stop runs.registerProductionTopologyCleanupsin its own node:test process with a raw context. The worker stop rejects immediately.withBoundedTeardownnever nests one bounded teardown inside another.kubernetes-real-kubectl.test.mjspassed 20 of 20 runs at 2 CPUs on the final head.Risks
--timeout=120sNamespace and Deployment deletes.harness-topology-k3d-real.mjsat theassertCrossNamespaceSecretBindingDeniedcleanup) now runs before the worker stops, not last.Internal review: changes requested.