Skip to content

Restore manual checks and make plan resume idempotent #385

Closed

Description

@datacas

Priority: P0. Effort: S–M. Currently blocked by this issue: #330 and its pull request #384 (REV-001 cannot be resolved through the runtime).

Problem and rationale. A cycle cannot resume a change request whose frozen verification plan holds a manual check. Two defects combine; observed on #330 / PR #384 (plan revision 2, readiness_unconfirmed).

  1. Manual checks can never be restored. authorized_bindings() (scripts/cycle_plan.py) accepts journal-proposed commands only if _is_verification_command allows them. A manual check such as manual:orca-live is not a runnable command and never passes, so restore_plan (scripts/cycle_history.py) raises HistoryError: stored check has no currently authorized command binding for the whole plan. Every resume then falls back to the unrestored plan, whose commands are sha256: fingerprints.
  2. The fallback is not idempotent. prepare_plan looks for a required check whose command equals the configured test command. Against fingerprints it finds none, so it derives configured-test-<digest> and extends the plan. That id was already added by the previous resume, with the fingerprint as its command, provenance: runtime and reason: runtime. The new spec carries the plain command, provenance: project and reason: configured test command, and VerificationPlan.extend rejects it with cannot rewrite frozen check identity. The run stops BLOCKED before any agent runs, and every later resume stops the same way.

The frozen-identity invariant is correct and must stay as it is. A reproduction against a snapshot of the persisted state is described in the evidence below.

Objective and scope. A change request with a manual check resumes any number of times without losing obligations or evidence.

Smallest proposed implementation scope.

  • authorized_bindings() also binds journal-proposed manual:* commands. A bound manual command grants no execution authority: _is_verification_command is not changed and still rejects it, and a manual check is never treated as verified because it was restored.
  • prepare_plan recognizes an existing configured check by its original command or by its canonical command digest (command_digest), and skips the extension when one is present. No frozen check is rewritten and no check is added twice.

Dependencies. None strict. Independent of #382 (host-attested evidence), which will build on manual checks being restorable. Unblocks #330 and PR #384.

Acceptance criteria.

  • A persisted plan containing a manual:* check restores without a HistoryError when its journal proposal exists.
  • Restoring a manual check neither marks it verified nor makes its command executable; _is_verification_command("manual:…") stays false.
  • Consecutive resumes of the same change request (at least three) succeed and yield the same set of check identities: no configured-test-<digest> duplicate appears and no frozen identity changes.
  • Historical results, frozen identities and required/criteria obligations are preserved across resumes.
  • A plan whose check command is genuinely unauthorized (not a manual check) still fails restore as before.
  • .code-cycle.yml and the command allowlist rules are unchanged.
  • docs/verification.md states that manual checks survive resume and that resume is idempotent.

Regression tests.

  • Reproduce the revision-2 collision: a plan with configured-test, agent-proposed checks, manual:orca-live and a previously added configured-test-<digest> entry whose command is a fingerprint; resume must not raise.
  • Three consecutive resumes of the same plan; identities and results are identical after each.
  • Manual check restored but unexecuted: stays unverified, never passes, cap() still lowers the conclusion.
  • Unauthorized non-manual command still raises HistoryError.
  • A sanitized fixture of the persisted PR feat(orca): share execution plans in supervised cycles (#330) #384 state (check ids, fingerprints, results, digest) restores without loss of obligations or evidence.

Verification before the real cycle resumes. The fix is first run against a copy of the persisted state of PR #384, to show that the plan that is already blocked recovers without losing obligations or evidence, before any real cycle is started on it.

Risks. Binding manual:* must not widen what a verifier is allowed to run: verify_pending passes pending commands as verify prefixes, so manual commands must stay excluded from that list or be proven inert. The change must not mask a genuinely unauthorized command.

Out of scope. Host-attested evidence (#382), changing the allowlist or .code-cycle.yml, relaxing extend's frozen-identity rule, any change to PR #384 or its worktree.

Evidence. On a snapshot of the telemetry database, restore_plan with the bindings authorized_bindings() builds raises HistoryError; adding manual:orca-live to the bindings restores the plan. The unrestored plan's extension step then fails with cannot rewrite frozen check identity, differing in command (fingerprint vs plain), provenance (runtime vs project) and reason.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P0Critical path of CCT 2.0bugSomething isn't working

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions