Monetization core: shared billing (clients/ledger/holds/Stripe), factory intake (client repos + issue provisioning), eval farm intake/results, delivery receipts. Two front-ends, one billing core.
Go to file
Claude b46c356d64 fix(#29): head-integrity gates — recovery requires exact merged head; reject missing reviewed head (bounce-fix)
Governor review 10539 findings, finding by finding (issue-29 branch, PR #32 retained):

1. Recovery must never attribute a DIFFERENT head's merge to a reviewed-head plan.
   recover_incomplete() adopted any live record with merged is True for the PR
   number without comparing heads: if plan A was persisted and then head B was
   merged externally, the retry row for A would debit/label/close/comment as
   though reviewed head A had been delivered. Crash-window adoption now
   requires BOTH positive merged proof AND live head_sha == the persisted
   planned/reviewed head_sha. A merged DIFFERENT head fails closed with a
   structured HEAD_MISMATCH result (persisted attempt + result entry), and
   performs NO debit, NO label removal, NO issue close, NO success comment;
   the row is left unadopted. The same-head crash-window success case is
   preserved.

2. A candidate with no reviewed head_sha must never reach the merge client.
   Passing expected_head_sha=None to merge_pr would arm the production
   client's backward-compatible live-head fallback and could merge a head the
   policy never reviewed. _apply_policy() now rejects a missing/empty
   head_sha BEFORE the plan write (review_state.head_sha is NOT NULL, so the
   DB would reject it anyway — now with the correct semantic failure) and
   _safe_merge() independently refuses to call the client without a pinned
   reviewed head. Zero merge attempts and zero downstream side effects.

New regressions (tests/test_review_policy.py):
- test_recovery_merged_different_head_fails_closed — plan at sha-A, live
  merged at sha-B: HEAD_MISMATCH, zero side effects, merged_step unmarked.
- test_missing_reviewed_head_never_reaches_merge_client — candidate with no
  head_sha: structured failure, no merge_pr call, no debit/label/close/comment.

Preserved: reviewed-SHA merge pin, production normalized merged/state shape,
closed-unmerged negative gate (state==closed never counts), durable recovery
independent of the open-PR scan, checkpoint/idempotency coverage, and the
same-head crash-window adoption.

Evidence: python3 -m pytest -q -> 203 passed, 1 skipped (was 201 passed, 1
skipped; +2 new tests). git diff --check clean. Files: gitea_saas/review_policy.py,
tests/test_review_policy.py.
2026-08-29 03:20:53 -05:00
gitea_saas fix(#29): head-integrity gates — recovery requires exact merged head; reject missing reviewed head (bounce-fix) 2026-08-29 03:20:53 -05:00
tests fix(#29): head-integrity gates — recovery requires exact merged head; reject missing reviewed head (bounce-fix) 2026-08-29 03:20:53 -05:00
ARCHITECTURE.md gitea-saas-core#21: give gitea_saas/gitea_client.py a single owning issue (#4) 2026-08-25 10:32:42 -05:00
pyproject.toml gitea-saas-core#1: billing ledger core (clients/ledger/holds, idempotent, fail-closed) 2026-08-25 04:16:35 -05:00
README.md Initial commit 2026-08-25 11:01:12 +02:00
requirements.txt Merge remote-tracking branch 'origin/main' into issue-2 2026-08-25 06:29:19 -05:00

gitea-saas-core

Monetization core: shared billing (clients/ledger/holds/Stripe), factory intake (client repos + issue provisioning), eval farm intake/results, delivery receipts. Two front-ends, one billing core.