Skip to content

policy: unattended block + 4 Bucket-C gate routers (AB#3104, PR1 of 2) - #320

Closed
PolyphonyRequiem wants to merge 1 commit into
feature/3103-policy-path-env-overridefrom
feature/3104-unattended-policy-pr1
Closed

policy: unattended block + 4 Bucket-C gate routers (AB#3104, PR1 of 2)#320
PolyphonyRequiem wants to merge 1 commit into
feature/3103-policy-path-env-overridefrom
feature/3104-unattended-policy-pr1

Conversation

@PolyphonyRequiem

Copy link
Copy Markdown
Owner

Bucket-C policy controllability — schema + first 4 gates (AB#3104, PR1 of 2)

Stacked on #319. Targets feature/3103-policy-path-env-override. Will rebase to main once #319 merges.

What this PR ships

A new policy.unattended block that lets an operator opt deterministic, non-policy human_gate nodes into auto-routes, plus the upstream router scripts that wire the first four gates from the AB#3103 audit.

Schema (5 files)

File Change
src/Polyphony/Policy/PolicyConfig.cs New UnattendedPolicy { AcceptanceMode, ReviewWaitMode, CapMode } + three static class constants (UnattendedAcceptanceMode, UnattendedReviewWaitMode, UnattendedCapMode) mirroring the RootFallbackAutoDecide / RenegotiationAutoDecide precedent. New PolicyConfig.Unattended property.
src/Polyphony/Policy/PolicyLoader.cs ApplyBuiltInDefaults defaults all three modes to safe (manual / wait / manual). New ValidateUnattended rejects unknown enum values at parse time with a clear message.
src/Polyphony/Models/PolicyLoadResult.cs New PolicyUnattendedSnapshot record + PolicyLoadResult.Unattended property — exposes the resolved snapshot via polyphony policy load.
src/Polyphony/PolyphonyJsonContext.cs Registers PolicyUnattendedSnapshot for AOT serialization.
src/Polyphony/Commands/PolicyCommands.cs SnapshotUnattended helper + wires it into Load().

YAML examples (2 files)

File Change
.polyphony-config/policy.yaml New unattended: block with comments documenting each mode and which gates it controls.
.polyphony-config/policy-fasttrack.yaml unattended: { acceptance_mode: auto, review_wait_mode: skip, cap_mode: auto_proceed } so the canonical fast-track preset bypasses the wired gates. CAVEAT block updated to call out PR1 vs PR2 coverage.

Workflow wiring (3 files, 4 gates)

Each gate gets an upstream <gate>_policy_router script step that calls polyphony policy load and routes either to the bypass target (the route the operator's "happy" option would have selected) or falls through to the human gate. Pattern mirrors root-fallback-gate.yaml lines 88–101.

Workflow Gate Mode Auto-route target
apex-driver.yaml apex_completion_gate acceptance_mode=auto close_mark_satisfied
implement-merge-group.yaml user_acceptance acceptance_mode=auto pr_platform_router
plan-level.yaml pending_review_gate review_wait_mode=skip pr_poll_platform_router
plan-level.yaml stuck_review_gate review_wait_mode=skip stuck_review_reset

Reclassification note. The AB#3104 issue body had pending_review_gate in the acceptance bucket; on closer look both pending_review_gate and stuck_review_gate are pure "wait for someone else" gates with no semantic accept/reject decision, so both go under review_wait_mode. The issue's prose comment in policy.yaml is updated to reflect this.

Tests (1 file)

tests/Polyphony.Tests/Commands/PolicyCommandsTests.cs — five new Unattended tests:

  • Load_NoFile_AppliesUnattendedDefaults — defaults of manual / wait / manual.
  • Load_FileWithUnattended_PreservesAllModes (Theory ×4) — round-trips every mode combination.
  • Load_PartialUnattended_FillsMissingFromDefaults — partial override doesn't blow away unspecified modes.
  • Load_BadUnattendedMode_ReturnsConfigError (Theory ×3) — bad mode surfaces field name + bad token in the error envelope.
  • Load_Unattended_SnakeCaseFieldNames_PresentInRawJson — JSON serialization stays snake_case.

All 55 PolicyCommandsTests pass.

What this PR explicitly does NOT do

Wave 2 (AB#3104 follow-on PR) wires the remaining 18 Bucket-C gates from the audit:

  • Cap/recovery gates: revise_cap_gate, remediation_cap_gate, pr_fix_exhausted_gate, depth_exceeded_gate, closed_unmerged_gate, scope_violation_gate, stale_generation_gate, dependency_gate, conflict_resolution_gate, etc.
  • Other review-wait variants: ado_stuck_review_gate, ado_pr_pending_gate, ado_pr_changes_requested_gate.
  • Other happy-path variants: human_satisfaction_gate (apex-item-dispatch).

PR2 also adds harness scenarios that prove the bypass paths actually flow end-to-end. The schema + the four wired gates here are the smallest viable slice that lets the operator unblock an unattended research dogfood run on the happy path.

Verification

  • dotnet build src/Polyphony.SchemaExporter/Polyphony.SchemaExporter.csproj — green.
  • dotnet test --filter Unattended — 12 tests pass (5 new + 7 from policy: POLYPHONY_POLICY_PATH env override + policy-fasttrack example (AB#3103) #319 sharing PolicyFileFixture).
  • dotnet test (full suite) — 3349 / 3357 pass; the four intermittents (ProcessRunnerTests.RunAsync_TimeoutAfterEmittedOutput, ManifestCommandsTests.RecordRebase_HappyPath_AppendsAndReportsCount, PlanCommandsRebaseStaleDescendantTests.ParentPrFresh_ProceedsToRebase, PrCommandsMergePlanAdoTests.OpenPr_CompletesAndRecordsLedger) pass when re-run individually, so they are pre-existing flakes unrelated to this change.
  • conductor validate — green for apex-driver.yaml, implement-merge-group.yaml, plan-level.yaml.
  • tests/lint-jinja-resolver.ps1 — PASS, 0 errors, 31 (pre-existing) warnings.

Closes / refs

…s (AB#3104)

Adds the policy.unattended block (acceptance_mode/review_wait_mode/cap_mode)

promised by AB#3104, then fronts four deterministic human gates with upstream

policy-router scripts that bypass the gate when the operator opted in.

Schema additions:

  - PolicyConfig.Unattended (UnattendedPolicy { AcceptanceMode, ReviewWaitMode, CapMode })

  - UnattendedAcceptanceMode (manual|auto)

  - UnattendedReviewWaitMode (wait|skip)

  - UnattendedCapMode (manual|auto_proceed|auto_fail)

  - PolicyLoader.ApplyBuiltInDefaults defaults all three to safe (manual/wait/manual)

  - ValidateUnattended rejects unknown enum values at parse time

  - PolicyLoadResult.Unattended snapshot exposed via 'polyphony policy load'

Workflow wiring (4 of 22 Bucket-C gates — see AB#3104 for the catalogue):

  - apex_completion_gate (apex-driver.yaml) — acceptance_mode=auto bypasses to close_mark_satisfied

  - user_acceptance (implement-merge-group.yaml) — acceptance_mode=auto bypasses to pr_platform_router

  - pending_review_gate (plan-level.yaml) — review_wait_mode=skip bypasses to pr_poll_platform_router

  - stuck_review_gate (plan-level.yaml) — review_wait_mode=skip bypasses to stuck_review_reset

Each router mirrors the canonical pattern from root-fallback-gate.yaml (lines 88-101):

polyphony policy load -> route on output.unattended.<mode>.

policy-fasttrack.yaml gets unattended: { auto, skip, auto_proceed }; the canonical

policy.yaml ships with all-manual defaults plus a documentation block.

Tests: 5 new unit tests for the schema (defaults, full preserve, partial preserve,

all-bad-mode rejection, snake_case JSON serialization).

Remaining 18 Bucket-C gates filed for PR2 under AB#3104.

Refs: AB#3104, AB#3103

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@PolyphonyRequiem
PolyphonyRequiem deleted the branch feature/3103-policy-path-env-override May 12, 2026 04:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant