diff --git a/docs/logs/engineering-log.md b/docs/logs/engineering-log.md index 43004b8f..d5611092 100644 --- a/docs/logs/engineering-log.md +++ b/docs/logs/engineering-log.md @@ -124,6 +124,20 @@ - Result: the focused test passed normal/race at `-count=100`, the complete harness package passed normal/race, and `./scripts/test-regression.sh` passed with 85.6% total coverage and zero uncovered functions. + +## 2026-07-30 (Swarm Activation Control Lifecycle Race — Issue #1046) + +- Symptom: hosted fast CI intermittently reported `agent_swarm` missing from an + unrestricted run immediately after test-local activation. +- Cause: the control reused an exhausted scripted provider, so terminal cleanup + could clear the activation before the fixture inspected definitions. +- Planned fix: use a dedicated provider that blocks until after the definition + assertion, then release it and wait for normal terminal cleanup. +- Verification contract: focused normal/race stress, harness normal/race, full + regression, and GitHub required checks. +- Result: the focused test passed normal/race at `-count=100`, the complete + harness package passed normal/race, and `./scripts/test-regression.sh` passed + with 85.6% total coverage and zero uncovered functions. ## 2026-07-30 (Worktree Containment CI Synchronization — Issue #1039) - Symptom: GitHub Actions fast run 30551198514 received diff --git a/docs/logs/long-term-thinking-log.md b/docs/logs/long-term-thinking-log.md index 1bae5705..c560cd4f 100644 --- a/docs/logs/long-term-thinking-log.md +++ b/docs/logs/long-term-thinking-log.md @@ -148,6 +148,19 @@ pinned states remain temporary exceptions, subscriber cancellation still triggers cleanup, and all focused through full gates are green. +## 2026-07-30 (Swarm Activation Control Lifecycle Race — Issue #1046) + +- Command intent: clear the hosted baseline flake blocking the cron/callback + merge chain. +- User intent: prove all accepted gates are green before merging to `main`. +- Success definition: the test deterministically exercises both a denied member + and a live unrestricted control, then cleans up normally. +- Guardrails: issue-first isolated worktree, test-only lifecycle control, no + production activation or Runner change. +- Outcome: the dedicated provider holds the actual control run live through + activation inspection, then releases it to normal completion; focused, + package, race, and coverage gates are green. + ## 2026-07-30 (Workflow Subscription Cancellation Test — Issue #1035) - Command intent: clear the race-gate blocker exposed while verifying the diff --git a/docs/plans/2026-07-30-issue-1046-swarm-activation-control-impact-map.md b/docs/plans/2026-07-30-issue-1046-swarm-activation-control-impact-map.md new file mode 100644 index 00000000..3baba671 --- /dev/null +++ b/docs/plans/2026-07-30-issue-1046-swarm-activation-control-impact-map.md @@ -0,0 +1,67 @@ +# Cross-Surface Impact Map: Issue #1046 Swarm Activation Control + +## Task + +- Task / issue: stabilize the unrestricted swarm activation control, #1046. +- Plan: `2026-07-30-issue-1046-swarm-activation-control-plan.md`. +- Owner: Codex. +- Status: implemented and fully verified locally; hosted checks pending. + +## Current Ownership, Callers, and Data Flow + +- Entry: `TestAgentSwarmDeniedForMemberRuns`. +- Production source of truth: `ActivationTracker` owns per-run activations; + terminal Runner paths call `Cleanup(runID)`. +- Test flow: the member run exhausts `capturingProvider.turns`; the following + unrestricted run can complete immediately, racing activation inspection. +- Search conclusion: adjacent swarm tests do not reuse an exhausted provider + for a live activation control. + +## Config, API, CLI, and Tools + +- Config/env/defaults: none. +- API/CLI/wire/tool behavior: unchanged. +- Tool contract: keep `agent_swarm` hidden for denied members and visible after + activation for unrestricted runs. + +## Persistence and Compatibility + +- State: test-local release channel only. +- Schemas/migrations/caches: none. +- Compatibility: no runtime change. + +## Lifecycle, Security, and Reliability + +- Concurrency: block the control provider until after definitions are read. +- Cleanup: release and wait for terminal status; Runner cleanup remains intact. +- Auth/privacy/secrets: none. + +## Product and Integration Surfaces + +- Harness production, API, TUI, web, macOS GUI, and providers: no code change. +- Automation: fast and race-enabled CI become repeatable. +- UX/accessibility: none. + +## Deployment and Operations + +- Deployment/migration/flags: none. +- Rollback: revert if the control no longer runs through normal Runner paths. +- Observability/operator docs: none. + +## Regression Tests + +- Red: hosted missing-definition failure after terminal cleanup. +- Green: focused normal/race `-count=100`. +- Controls: denied member remains hidden and uncallable; live unrestricted run + sees the activated definition; released control reaches terminal state. +- Full: harness normal/race and `./scripts/test-regression.sh`. + +## Documentation and Handoff + +- Update engineering log, long-term log, plan, impact map, and plans index. +- No public docs. + +## Warning Check + +- Every runtime/product surface is explicitly unaffected because the repair is + confined to the test provider lifecycle. diff --git a/docs/plans/2026-07-30-issue-1046-swarm-activation-control-plan.md b/docs/plans/2026-07-30-issue-1046-swarm-activation-control-plan.md new file mode 100644 index 00000000..2d917513 --- /dev/null +++ b/docs/plans/2026-07-30-issue-1046-swarm-activation-control-plan.md @@ -0,0 +1,60 @@ +# Plan: Keep the Swarm Activation Control Run Live + +## Context + +- Governing GitHub issue: #1046. +- Problem: `TestAgentSwarmDeniedForMemberRuns` reuses an exhausted scripted + provider for its unrestricted control. The control run can complete and clear + its activation between `Activate` and `filteredToolsForRun`. +- Red evidence: hosted fast CI failed at `runner_swarm_test.go:242` with + `agent_swarm missing from unrestricted run definitions after activation`. +- Constraint: preserve production activation cleanup and both sides of the + denied/unrestricted contract. + +## Scope + +- In scope: a dedicated, test-local blocking provider for the control run. +- Out of scope: production Runner lifecycle, activation tracking, agent swarm, + permissions, or deferred-tool filtering. + +## Documentation Contract + +- Feature status: test-only bug repair. +- Public docs affected: none. +- Evidence: engineering and long-term logs, plan, impact map, plans index. + +## Test Plan + +- Red: retain the exact hosted lifecycle-race failure as regression evidence. +- Green: focused normal and race tests at `-count=100`. +- Package: `internal/harness` normal and race. +- Full: `./scripts/test-regression.sh` and GitHub required checks. + +## Cross-Surface Impact Map + +- See `2026-07-30-issue-1046-swarm-activation-control-impact-map.md`. + +## Implementation Checklist + +- [x] Create contract-complete bug #1046. +- [x] Capture hosted failure and architecture search evidence. +- [x] Write plan and impact map before code. +- [x] Hold the unrestricted control run live through its assertion. +- [x] Run focused stress, package, and full local gates. +- [ ] Pass hosted required checks. +- [ ] Merge through a closing PR. + +## Verification + +- Focused normal and race tests passed at `-count=100`. +- The complete `internal/harness` package passed normal and race tests. +- `./scripts/test-regression.sh` passed normal, race, and the 85.6% coverage + gate with zero uncovered functions. + +## Risks and Mitigations + +- Risk: the control provider could leak when an assertion fails. +- Mitigation: register release and shutdown cleanup before starting the run. +- Risk: the control could stop proving a real unrestricted run. +- Mitigation: start a separate Runner normally, activate its actual run ID, and + assert through `filteredToolsForRun`. diff --git a/docs/plans/INDEX.md b/docs/plans/INDEX.md index a3c25ef3..d148a830 100644 --- a/docs/plans/INDEX.md +++ b/docs/plans/INDEX.md @@ -20,6 +20,8 @@ - `2026-07-30-issue-1042-default-registry-repeat-impact-map.md` — Cross-surface impact map for Issue #1042. - `2026-07-30-issue-1048-pinned-retention-quota-plan.md` — Issue #1048 planned exclusion of subscriber-pinned runs from the drainable terminal retention quota. - `2026-07-30-issue-1048-pinned-retention-quota-impact-map.md` — Cross-surface impact map for Issue #1048. +- `2026-07-30-issue-1046-swarm-activation-control-plan.md` — Issue #1046 planned live unrestricted control for the swarm activation regression. +- `2026-07-30-issue-1046-swarm-activation-control-impact-map.md` — Cross-surface impact map for Issue #1046. - `2026-07-30-issue-1035-workflow-subscription-cancel-plan.md` — Issue #1035 planned deterministic workflow subscription-cancellation regression repair. - `2026-07-30-issue-1035-workflow-subscription-cancel-impact-map.md` — Cross-surface impact map for Issue #1035. - `2026-07-30-issue-1026-feedback-direct-publish-plan.md` — Issue #1026 attached-image, publish-by-default GitHub feedback intake (implemented and verified; promotion pending). diff --git a/internal/harness/runner_swarm_test.go b/internal/harness/runner_swarm_test.go index 96e98993..832df056 100644 --- a/internal/harness/runner_swarm_test.go +++ b/internal/harness/runner_swarm_test.go @@ -227,13 +227,32 @@ func TestAgentSwarmDeniedForMemberRuns(t *testing.T) { } // Control: an unrestricted run sees the activated definition. - run2, err := runner.StartRun(RunRequest{Prompt: "parent"}) + releaseControl := make(chan struct{}) + var releaseControlOnce sync.Once + release := func() { + releaseControlOnce.Do(func() { close(releaseControl) }) + } + t.Cleanup(release) + controlProvider := &funcProvider{fn: func(ctx context.Context, _ CompletionRequest) (CompletionResult, error) { + select { + case <-releaseControl: + return CompletionResult{Content: "done"}, nil + case <-ctx.Done(): + return CompletionResult{}, ctx.Err() + } + }} + controlRunner := NewRunner(controlProvider, registry, RunnerConfig{ + DefaultModel: "test", + DefaultSystemPrompt: "sys", + Activations: activations, + }) + run2, err := controlRunner.StartRun(RunRequest{Prompt: "parent"}) if err != nil { t.Fatal(err) } activations.Activate(run2.ID, "agent_swarm") seen := false - for _, def := range runner.filteredToolsForRun(run2.ID) { + for _, def := range controlRunner.filteredToolsForRun(run2.ID) { if def.Name == "agent_swarm" { seen = true } @@ -241,7 +260,10 @@ func TestAgentSwarmDeniedForMemberRuns(t *testing.T) { if !seen { t.Fatal("agent_swarm missing from unrestricted run definitions after activation") } - waitForStatus(t, runner, run2.ID, RunStatusCompleted, RunStatusFailed) + release() + if got := waitForStatus(t, controlRunner, run2.ID, RunStatusCompleted, RunStatusFailed); got != RunStatusCompleted { + t.Fatalf("control run status = %q, want completed", got) + } } func TestAgentSwarmApprovalFlowSurfacesMutatingCall(t *testing.T) {