Skip to content

feat(automation): proposal queue + approval gate (Arc D phase 2)#44

Merged
saagpatel merged 1 commit into
mainfrom
arc-d2-proposal-queue
Jun 6, 2026
Merged

feat(automation): proposal queue + approval gate (Arc D phase 2)#44
saagpatel merged 1 commit into
mainfrom
arc-d2-proposal-queue

Conversation

@saagpatel

Copy link
Copy Markdown
Owner

Arc D — Phase 2 of 3: durable proposal queue + real approval gate

Second rung. Adds the durable intent queue and the real enforcement gate that the phase-3 executor will sit behind. Still no execution here.

Design

  • Proposals record intent (action type + target + description) + status — no precomputed payload. The executor (phase 3) derives fresh content at apply time, so nothing goes stale between proposal and execution.
  • Lifecycle: pending → approved → executed, or pending → rejected.

Surface (src/automation_proposals.py)

  • build_automation_proposals(candidates, *, action_type, created_at, existing) — id-deduplicated merge. Operator decisions are sticky: re-proposing never resets an existing approval and never resurrects a rejection.
  • approve_proposal / reject_proposal — guarded PENDING-only transitions; raise ProposalNotFoundError (unknown id) / ProposalApprovalError (wrong source status).
  • executable_proposals / require_approvedthe hard gate: only APPROVED proposals are ever executable, exact status match. Code-review confirmed no non-approved status can slip through.
  • load_proposals / save_proposals — JSON persistence; missing file → []; malformed / invalid-status / missing-field / non-dict entries → ValueError.

Tests / gates

  • 25 tests (tests/test_automation_proposals.py): id stability, sticky merge, no-resurrect, every transition guard, gate filtering, persistence round-trip + all malformed-input paths.
  • Full suite 2363 passed. ruff check . clean.
  • /code-review applied: fixed reject_proposal corrupting approved_at (added rejected_at field); hardened from_dict/load_proposals to honor the malformed→ValueError contract.

Next — phase 3: the gated executor (catalog-seed apply + auto-PR with dry-run default / never-main / skip-dirty / re-check-eligibility rails) plus the complete propose → approve → execute CLI workflow.

Add src/automation_proposals.py: the durable intent queue and real approval
gate for bounded automation. A proposal records intent (action type + target +
description) and a status; it carries no precomputed payload so the executor
(phase 3) derives fresh content at apply time.

- AutomationProposal (frozen) with pending/approved/rejected/executed lifecycle.
- build_automation_proposals merges candidate proposals into an existing queue,
  id-deduplicated; operator approvals and rejections are sticky (never reset by
  re-proposing, and rejected proposals are not resurrected).
- approve_proposal / reject_proposal: guarded PENDING-only transitions that
  raise on unknown id (ProposalNotFoundError) or wrong source status
  (ProposalApprovalError).
- executable_proposals / require_approved: the hard enforcement gate — only
  APPROVED proposals are ever executable (exact status match).
- load_proposals / save_proposals: JSON persistence; missing file -> [],
  malformed/invalid-status/missing-field/non-dict entries -> ValueError.

25 tests. /code-review applied: fixed reject_proposal writing into approved_at
(added rejected_at field) and hardened from_dict/load to honor the documented
malformed->ValueError contract. Full suite green, ruff clean.
@saagpatel
saagpatel merged commit 0d63dd7 into main Jun 6, 2026
2 checks passed
@saagpatel
saagpatel deleted the arc-d2-proposal-queue branch June 6, 2026 09:25

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a5794c8c0d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

)
return cls(
proposal_id=str(data["proposal_id"]),
action_type=str(data["action_type"]),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject unknown persisted action types

When a proposal file contains an approved entry whose action_type is not one of the two supported actions, from_dict accepts it and the execution gate later filters only on status, so hand-edited or stale JSON can bypass the action whitelist that generation enforces. Validate the loaded action_type here (for example via _require_action_type) so only supported actions can become executable.

Useful? React with 👍 / 👎.

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