Store the completion claim and close an issue from a verified outcome when policy permits #150

Closed AtlantisPleb opened this 5d ago

Evidence

Shipped in the release at 05ac698, promoted 2026-08-26.

Outcome

A completion claim becomes a durable record keyed to the issue, the attempt, and the exact revision, graded by the accepted-outcome contract, and a repository may opt in to closing an issue from an accepted result. An unverified claim leaves the issue open with a typed reason.

This is stage 6 of #10 and the whole of Track E's E7. The design is docs/2026-08-23-issue-work-receipt-linkage-design.md, section 5.

Current behavior

Three mechanisms meet here and none of them connects to the others.

OpenAgents.AcceptedOutcome.evaluate/1 (lib/openagents/accepted_outcome.ex:104) grades a claim map and returns {:accepted, ...}, {:not_accepted, type, reasons}, or {:not_applicable, exemption}. It is a pure function. Nothing stores a claim, and nothing stores a result, so no surface can answer which evidence qualified an issue and no policy can key on it. Its only caller in lib/ is continual learning.

compensation_outcome_decisions — the record PROMISE-001 gates LIVE promises on — is keyed on tool_step_id (lib/openagents/compensation/outcome_decision.ex:11), one immutable module outcome inside one conversation. It cannot be reached from an issue.

#130 closes an issue from a Closes #N trailer when a commit lands on the default branch, attributed to the pusher. That is a human assertion, authenticated and bound to a merge, and it is the right default for most work.

Work

  • Store the claim, keyed on {issue, attempt, revision}, so the evaluation is reproducible and the issue can name which receipt satisfied which acceptance criterion.
  • Grade it with AcceptedOutcome.evaluate/1 and record the typed result. Do not reimplement the contract; AcceptedOutcome.validate/1 already refuses a contract that drifts from the code.
  • Fill the five required attempt fields from records that exist: forge_assignments carries the issue, the repository, the requesting principal, and the terminal revision, and stage 1's work_job_id reaches the budget snapshot on the work job.
  • Make verified closing an explicit, per-repository, opt-in policy. Never reopen from this path: an unverified claim leaves the issue open with an incomplete, unauthorized, or failed result.
  • Leave #130 untouched. Trailer-driven closing is a person's assertion and stays attributed to that person. If both paths fire, record both and close once.
  • Publish only the bounded projection AcceptedOutcome.public_projection/1 already produces: result state, typed reasons, criterion names, and public receipt references.

Acceptance criteria

  • A claim that satisfies the contract closes the issue on a repository that opted in, and the issue records the evidence used.
  • A claim missing an issue section, an attempt field, a verifier, a falsifier, or a criterion's evidence leaves the issue open with the exact typed reason.
  • A result carrying any of the five named false-green classes is failed even when the verifier reported green.
  • Human-only work and repositories with agents disabled evaluate to not_applicable and are unaffected.
  • A public projection never carries a prompt, a log, a private repository name, or a private receipt reference.
  • Closing through this path clears the derived blocked flag on dependents exactly as a manual close does, per #100.

Verification

Context tests for the claim lifecycle and every typed non-accepted result, policy tests for the opt-in and the human-only exemption, authority tests for private evidence, and an interaction test with #130's trailer close; mix precommit.

Dependencies

Stage 6 of #10, and it should be last. Needs stage 4 (#148) for the evidence edges and coordinates with #130. INVARIANTS.md, OUTCOME-001 and PROMISE-001. Track E, E7.

  1. AtlantisPleb opened this issue 5d ago
  2. AtlantisPleb closed this as completed in bd7939c 4d ago
Sign in with GitHub to comment on this issue.