fix(audit): H4 (reservation signing berth rule) + H13 (manual EOI-sign stage parity)

H4: reservation_agreement completion fired the contract_signed berth rule,
flipping the berth to 'sold' one-to-two stages early. Add a dedicated
reservation_signed berth trigger (defaults to under_offer) and fire it.
H13: the manual signed-EOI upload path advanced only to 'eoi' via the
ungated helper while the Documenso-webhook path advanced to 'reservation';
both now use advanceStageIfBehindGated(..., 'reservation', 'eoi_signed') so
manually- and webhook-signed deals reach the same stage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-02 12:12:02 +02:00
parent 865ae5c072
commit b51d6d3030
2 changed files with 18 additions and 4 deletions

View File

@@ -988,13 +988,18 @@ export async function uploadSignedManually(
if (interest) {
void evaluateRule('eoi_signed', doc.interestId, portId, meta);
// Stage stays at 'eoi' - sub-status badge flips to "signed".
void advanceStageIfBehind(
// EOI signed = formal commitment → advance to 'reservation' via the
// GATED helper, matching the Documenso-webhook path (audit H13).
// Previously this manual-upload path used the ungated helper and only
// reached 'eoi', so manually-signed deals lagged a stage behind
// webhook-signed ones and skewed funnel/stage-duration reports.
void advanceStageIfBehindGated(
doc.interestId,
portId,
'eoi',
'reservation',
meta,
'Signed EOI uploaded manually',
'eoi_signed',
);
}
}
@@ -1680,7 +1685,11 @@ export async function handleDocumentCompleted(eventData: { documentId: string; p
'reservation_signed',
);
void import('@/lib/services/berth-rules-engine').then(({ evaluateRule }) =>
evaluateRule('contract_signed', doc.interestId!, doc.portId, systemMeta),
// Reservation signing is NOT contract signing — firing 'contract_signed'
// here flipped the berth to 'sold' one-to-two stages early (audit H4).
// Use the dedicated 'reservation_signed' trigger (defaults to
// 'under_offer').
evaluateRule('reservation_signed', doc.interestId!, doc.portId, systemMeta),
);
// Tenancies P3 — auto-create pending tenancies (one per in-bundle berth).