Skip to content

Commit 6465cc0

Browse files
claude[bot]claude
andauthored
docs(approvals): the resubmit discriminator states what main measured, not an invariant main falsified (#17686)
* docs(approvals): the resubmit discriminator states what main measured, not an invariant main falsified `resolveRecordedContinuation` argued its `action: 'resubmit'` discriminator was "exact and structural" on three clauses. The first two hold. The third — "a resubmit opens the next round as a NEW row, so at most one such action row exists per request" — was measured false: a resubmit whose own resume strands opens no next round, the row stays `returned`, and after `restoreConsumedSuspension` re-arms the pause a second `resubmit` by the same submitter lands a SECOND `action: 'resubmit'` row. Prose only, zero behaviour change. No door narrowed, no guard touched: the comment now records the doubling, states why the read is correct anyway (it is a presence check with `limit: 1`, deciding identically on one row or two), and points at the pin that measured it. The pin's header gains one line recording that the ruling landed and chose prose, so the doubling is accepted residue; none of its assertions move. Claude-Session: https://claude.ai/code/session_01ToDPcx9AESFubJkDiFMtKW Co-authored-by: Claude <noreply@anthropic.com> * chore(changeset): patch @objectstack/plugin-approvals for the resubmit discriminator prose Claude-Session: https://claude.ai/code/session_01ToDPcx9AESFubJkDiFMtKW Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 49cd715 commit 6465cc0

3 files changed

Lines changed: 45 additions & 4 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@objectstack/plugin-approvals': patch
3+
---
4+
5+
Correct the `resolveRecordedContinuation` discriminator's stated invariant in
6+
`approval-service.ts` to what was measured. The comment claimed the
7+
`action: 'resubmit'` audit row was "at most one per request"; a `resubmit` whose
8+
own resume strands opens no next round, so the row stays `returned` and a second
9+
`resubmit` after `restoreConsumedSuspension` lands a second such row. The
10+
comment now records that more than one row can exist, states why the read is
11+
correct anyway (it is a presence check with `limit: 1`, deciding identically on
12+
one row or two), and points at the pin that measured it.
13+
14+
Prose only — no behaviour change, no door narrowed, no guard touched. The audit
15+
trail's one-row-per-advancement shape is accepted residue; requiring one row per
16+
advancement is a separate change.

packages/plugins/plugin-approvals/src/approval-service.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4874,11 +4874,31 @@ export class ApprovalService implements IApprovalService {
48744874
// fallback (#4414) warns and evaluates every out-edge, so the flow
48754875
// proceeds with `{decision:'revise'}` where `{resubmitted:true}` was owed.
48764876
//
4877-
// The discriminator is exact and structural: `action: 'resubmit'` has
4878-
// exactly ONE writer in this file (`resubmit`), it is inserted before
4879-
// that resume, and a resubmit opens the next round as a NEW row — so at
4880-
// most one such action row exists per request, and its presence means
4877+
// The discriminator's first two clauses are exact and structural:
4878+
// `action: 'resubmit'` has exactly ONE writer in this file (`resubmit`),
4879+
// and it is inserted before that resume. Its presence therefore means
48814880
// the last continuation this row issued was the resubmit.
4881+
//
4882+
// ⚠️ What does NOT hold is the third clause this comment used to claim —
4883+
// "a resubmit opens the next round as a NEW row, so at most one such
4884+
// action row exists per request". A resubmit whose own resume STRANDS
4885+
// opens no next round at all, so the row stays `returned`; once an
4886+
// operator re-arms the pause with `restoreConsumedSuspension`, a second
4887+
// `resubmit` by the same submitter passes every door guard and writes a
4888+
// SECOND `action: 'resubmit'` row. ⇒ MORE THAN ONE such row CAN exist
4889+
// for one request. Measured guard by guard, on that very row in that
4890+
// very state, in `stranded-resubmit-second-door.test.ts` (#17601 probe,
4891+
// PR #17613) — read it there rather than re-deriving it from here.
4892+
//
4893+
// The read below is correct anyway, for a reason that clause never
4894+
// needed: it is a PRESENCE check (`limit: 1`), so it decides identically
4895+
// on one row or two — the pin's MEASUREMENT C drives this resolver on
4896+
// the doubled row and it still answers `resubmit`. What the doubling
4897+
// costs is the audit trail's one-row-per-advancement shape, ⛔ not the
4898+
// edge picked here, and that cost is ACCEPTED RESIDUE under the #17601
4899+
// ruling of 2026-09-11 (option B: scope this prose to what was measured,
4900+
// narrow no door). Requiring one row per advancement is a new card, ⛔
4901+
// not a local fix here.
48824902
const resubmitted = await this.engine.find('sys_approval_action', {
48834903
where: { request_id: requestId, action: 'resubmit' }, limit: 1, context: SYSTEM_CTX,
48844904
});

packages/plugins/plugin-approvals/src/stranded-resubmit-second-door.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313
* this behaviour, THIS PIN is the thing to update, and its update is the
1414
* repair's evidence.
1515
*
16+
* ⭐ THAT RULING LANDED (#17601, 2026-09-11): option B — the discriminator's
17+
* prose in `approval-service.ts` was scoped to this measurement and NO door was
18+
* narrowed, so the doubling measured below is ACCEPTED RESIDUE and every
19+
* assertion in this file stands exactly as it was.
20+
*
1621
* ## The hypothesis, and what it tested
1722
*
1823
* `resolveRecordedContinuation` discriminates the two continuation issuers of a

0 commit comments

Comments
 (0)