feat(slice-21 FR-4c): rename lastNudgeResult 'sent-unverified' → 'delivered-ack-pending' (OPR.0.3.2.21.FR-4)

The prior literal "sent-unverified" reads as a partial-failure
even when the underlying delivery was fine. The common case
for this value is "delivery confirmed but the synchronous ack
window expired" — which is normal for codex seats mid-task
(the seat received the nudge but didn't surface an ack in time
because it was working). Operators reading the JSON output saw
"sent-unverified" and assumed something was wrong.

The new literal "delivered-ack-pending" reads as the
healthy-and-expected case: delivery happened, ack is pending.

Scope:

(1) packages/daemon/src/domain/queue-repository.ts:315 — the
    single source-of-truth assignment site. Replaced the
    literal in the `result` ternary. Added an inline comment
    naming the rename and the rationale so future readers
    don't second-guess.

(2) packages/daemon/src/db/migrations/037_mission_control_actions.ts:38
    — JSDoc comment naming the migration's `notify_result`
    column values updated to reflect the new vocabulary; a
    short trailing note documents the rename + reason so
    grep-back-from-migration-history works.

(3) packages/daemon/test/queue-repository.test.ts +23 — new
    discriminator test asserting that the ok-but-unverified
    nudge case records `lastNudgeResult === "delivered-ack-pending"`
    AND explicitly asserts `not.toBe("sent-unverified")` so
    any future regression that re-introduces the old wording
    fails immediately.

Backward-compat:

- The "verified" positive literal is UNCHANGED. Tooling that
  consumes the positive value continues to work.
- The "failed:<reason>" prefix is UNCHANGED.
- Only the middle case (ok && !verified) changes literal value.
  Any tooling that specifically compared against the literal
  "sent-unverified" would break, but a codebase-wide grep
  confirmed no internal consumer does this — the only matches
  for the old literal pre-rename were the assignment site +
  the migration JSDoc comment (both updated here). External
  tooling outside this repo that parses queue JSON for the old
  literal would need to update; this is operator-facing UX, not
  a wire-contract guarantee.

Verification:
- packages/daemon queue-repository.test.ts: 26/26 PASS (25
  existing + 1 new discriminator).
- packages/daemon FULL test/ suite: 272 files, 3997 PASS + 1
  skipped, ZERO failures (one transient flake on first pass
  cleared on retry; same cold-start class as prior slices).
- packages/daemon tsc EXIT=0.
- grep for 'sent-unverified' in packages/ post-commit:
  remaining hits are EXPLANATORY PROSE in test comments +
  JSDoc rationale + the inline source comment in
  queue-repository.ts. No functional code references remain.
- Commit body verification grep clean per banked discipline.
- git diff --cached --stat: 3 files (+36 / -2).

Branch: slice-21-fr-4-queue-ergonomics off LOCAL main
58713e0c. Chain: 2f731b84 (FR-4a body-file+stdin, guard
CLEAR via qitem-20260601123549-f66d52a5) → 207ad5f1
(FR-4b mission/slice flags, per-commit handoff filed) →
this commit. LOCAL only, NO push.
This commit is contained in:
mvschwarz committed 2026-06-01 05:37:03 -07:00
1 parent 207ad5f1cb
commit 50b17c73d5
3 files changed
+36 -2

No files matched your search

@@ -35,7 +35,11 @@ import type { Migration } from "../migrate.js";
* - reason (TEXT) — required for hold + drop
* - annotation (TEXT) — required for annotate
* - notify_attempted (INTEGER 0|1) — for handoff
* - notify_result (TEXT) — verified | sent-unverified | failed:<reason>
* - notify_result (TEXT) — verified | delivered-ack-pending | failed:<reason>
* (post-OPR.0.3.2.21.FR-4(c) wording: "sent-unverified" was misleading
* because it read as a partial-failure even when delivery was fine;
* "delivered-ack-pending" reads as the normal-and-expected case for
* codex seats whose synchronous ack window expired while busy)
* - audit_notes_json (TEXT) — operator-supplied evidence map
*
* Indexes:
@@ -311,8 +311,15 @@ export class QueueRepository {
const text = wrapPaneEnvelope(sourceSession, destinationSession, bareBody);
try {
const res = await this.transport.send(destinationSession, text, { verify: true });
// OPR.0.3.2.21.FR-4(c) — wording rename: the prior literal
// "sent-unverified" read as a failure even in the common case
// (delivery confirmed but the synchronous ack window expired,
// which is normal for codex seats mid-task). The new literal
// "delivered-ack-pending" reads as healthy. The old "verified"
// case is unchanged for backward-compat with any tooling that
// already consumed the positive literal.
const result = res.ok
? (res.verified ? "verified" : "sent-unverified")
? (res.verified ? "verified" : "delivered-ack-pending")
: `failed:${res.error ?? res.reason ?? "unknown"}`;
this.recordNudgeAttempt(qitemId, result);
} catch (err) {
@@ -343,6 +343,29 @@ describe("QueueRepository", () => {
expect(fresh.state).toBe("pending");
});
// OPR.0.3.2.21.FR-4(c) — wording rename for the delivered-but-ack-expired
// case. Prior literal "sent-unverified" read as a partial-failure even
// when the underlying delivery was fine; "delivered-ack-pending" reads
// as the healthy-and-expected case (codex seats mid-task commonly miss
// the synchronous ack window).
it("ok-but-unverified nudge records lastNudgeResult as 'delivered-ack-pending' (was 'sent-unverified')", async () => {
const stubTransport = {
send: async () => ({ ok: true, verified: false }),
};
const nudgingRepo = new QueueRepository(db, bus, { transport: stubTransport });
const item = await nudgingRepo.create({
sourceSession: "alice@rig",
destinationSession: "bob@rig",
body: "delivered but ack window expired",
});
const fresh = nudgingRepo.getById(item.qitemId)!;
expect(fresh.lastNudgeResult).toBe("delivered-ack-pending");
// Discriminator: the old wording must NOT appear anywhere on
// the freshly-read row (proves the literal was renamed end-to-end,
// not just shadowed).
expect(fresh.lastNudgeResult).not.toBe("sent-unverified");
});
it("handoff nudges new destination by default", async () => {
const sends: Array<{ session: string }> = [];
const stubTransport = {