Skip to content

Approvals v2: the six product-proven ladder rules - #185

Merged
omercelikdev merged 1 commit into
mainfrom
approvals-v2
Aug 27, 2026
Merged

Approvals v2: the six product-proven ladder rules#185
omercelikdev merged 1 commit into
mainfrom
approvals-v2

Conversation

@omercelikdev

Copy link
Copy Markdown
Owner

What

Implements the accepted goldpath-approvals-v2 RFC: the six rules the api-portal product's approval engine proved live that the ladder engine lacked. All additive; the whole surface is still unshipped, so no shipped-API changes.

  • WithdrawWithdrawAsync(id, requestedBy): requester-only (NotRequester), pending-only, trailed; Withdrawn status is terminal.
  • Quorum rungsGoldpathApprovalRung.RequiredApprovals (default 1): each grant is a signature toward the rung; completion at quorum; the trail reads signed (n/m) then granted.
  • Distinct-eyes across the chain — one identity signs at most once per request, held across escalation even into a higher role (AlreadySigned). Quorum counts per rung; the bar spans the whole chain.
  • Mandatory rejection reason — a blank reason is refused (ReasonRequired); rejection stays terminal at any point, mid-quorum included.
  • Reject → resubmit chainResubmitAsync(rejectedId, requestedBy): fresh request linked by SupersedesId, both trails cross-referenced (resubmitted/superseded).
  • Store seamAddSignatureAsync/GetSignaturesAsync on IGoldpathApprovalStore, in-memory and EF (GoldpathApprovalSignatures table, indexed by request).

Contract note: decision verbs keep refusal-as-value; ResubmitAsync throws on misuse like the other creation verbs (RequestAsync, DelegateAsync).

Proof

  • 70 deterministic tests (20 existing + 50 new): the portal's seven multi-stage facts translated to rungs, withdraw/resubmit lifecycles, EF restart + round-trip, model-shape contract (table/column/index/conversion), composition seam (both AddGoldpathApprovals overloads + config binding), and the trail/refusal wording an auditor reads.
  • The package joins the mutation gate: stryker/Goldpath.Approvals.json, score 79.13% against break 70.
  • scripts/docs-freshness.sh green; dotnet format --verify-no-changes clean on the touched projects.

Ledgers (same PR as reality)

  • RFC flipped to accepted (owner, 2026-08-26) with a §6 implementation record; the CorPay approval story stays with T21's adopter proof (the sample doesn't compose approvals yet — wiring it would be a demo invented for the test).
  • RFC index row and the T21 open-threads addendum updated; package README documents the new verbs.

🤖 Generated with Claude Code

The api-portal product's approval engine proved six rules the ladder
engine lacked; the owner accepted goldpath-approvals-v2 and they land
here additively:

- Withdraw: WithdrawAsync takes back a pending request, requester-only
  (NotRequester refusal), trailed.
- Quorum rungs: GoldpathApprovalRung.RequiredApprovals (default 1);
  each grant is a signature toward the rung, completion at quorum.
- Distinct-eyes across the chain: one identity signs at most once per
  request, held across escalation (AlreadySigned).
- Mandatory rejection reason: a blank reason is refused (ReasonRequired).
- Reject -> resubmit chain: ResubmitAsync links the fresh request by
  SupersedesId with both trails cross-referenced.
- Store seam: AddSignatureAsync/GetSignaturesAsync on both stores; the
  EF store maps a GoldpathApprovalSignatures table.

Proof: 50 new deterministic facts (v2 rules, EF restart/round-trip,
model shape, composition seam, trail/refusal wording) beside the
original 20, and the package joins the mutation gate
(stryker/Goldpath.Approvals.json) at 79.13% against break 70.

Ledgers: RFC flipped to accepted (owner, 2026-08-26) with the
implementation record, RFC index and T21 addendum updated, package
README documents the new verbs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@omercelikdev
omercelikdev merged commit 371ab7b into main Aug 27, 2026
4 checks passed
@omercelikdev
omercelikdev deleted the approvals-v2 branch August 27, 2026 07:03
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