Skip to content

Signed WOPC ERL-WOPC/2025-020 reads as "Pending" with no signed PDF — signature.requestId dangles, all surviving requests voided, WOPC.pdf + revisions empty

Symptom

Owner, 2026-06-25 (verbatim): "a signed WOPC (ERL-WOPC/2025-020) is not being shown to the records page, and the status of the WOPC changed to Pending."

The WOPC is signed (the owner signed it), but on the Records WOPCs tab it reads Pending and the signed PDF isn't accessible.

Root cause (proven against live Firestore — tebs-epl + aote-system)

The WOPC parent doc (payees/JC/wopc/ERL-WOPC|2025-020) is internally inconsistent — it believes it's signed but every durable home for the signed PDF is empty or dangling:

Source the app can read the "signed PDF" from State
WOPC.signature on the parent present{ at: 2026-06-13T06:46:40Z, requestId: lGUUsWLTqSuobCMTq949 }
The signing request it points at (lGUUsWLTqSuobCMTq949 in aote-system/wopcSigningRequests) DELETED — does not exist (swept)
WOPC.pdf on the parent (Phase 4's durable signed-PDF pointer) ABSENT
revisions/ subcollection (Phase 4 archives signed attempts here) EMPTY (0 docs)
Any findable signing request for wopcRef = ERL-WOPC/2025-020 3 exist, ALL status: voided (T6m8geqGBO325C8tXJKX, dg7d69o8iau8WDJ4zCLB, HUjw90a6rQVHy9V1QLYz)

So the parent says "signed at 06-13 06:46 via request lGUUsW…" but that request was swept, and the 3 requests that survive are all from earlier sign→void cycles (06-11 → 06-13). The 06-13 06:46 sign (the current signature) left no resolvable artifact: no live request, no WOPC.pdf, no revision doc.

Why the Records page renders it as Pending

pages/api/records/wopcs.ts resolves the signed-PDF Drive id only via the signing-request lookup (lines 145-151) — it never reads WOPC.pdf:

const direct = directId ? await findRequestById(directId) : null   // lGUUsW… → null (deleted)
if (direct?.status === 'signed' && direct.signedDriveFileId) { … }  // no
else {
  const latest = await findLatestRequestForWopc(ref)               // newest by createdAt = HUjw90a6…
  if (latest?.status === 'signed' && latest.signedDriveFileId) { … } // latest.status = 'voided' → no
}
// → driveFileId = null

With no resolvable signed request, the row has no signed-PDF link and the lifecycle reads Pending, even though WOPC.status = active and WOPC.signature.at is set.

How it got here

This WOPC went through repeated sign → void cycles on 06-11 → 06-13 (3 voided requests + a 4th, final sign at 06-13 06:46). The T-089 signing-request sweep (ephemeral-request model: terminal requests get deleted) removed the final signed request lGUUsWLTqSuobCMTq949, but the migration never backfilled the parent's WOPC.pdf (or a revisions/1 doc) for it — so the signed artifact pointer was lost. The voided requests survived (they weren't swept), which is what makes the parent's dangling signature.requestId so visible.

Two gaps — both T-089 scope

  1. Data: this WOPC (and possibly other re-signed/voided-then-re-signed WOPCs) has a dangling signature.requestId + missing WOPC.pdf + empty revisions/. Needs a repair that re-attaches the current signed PDF — i.e. decide which Drive file is the canonical 06-13 06:46 signed copy (the deleted request's signedDriveFileId is gone; the file itself may still be in Drive / the file-archive) and write it to WOPC.pdf (+ a revisions/ entry per the Phase 4 model).
  2. Code (reader robustness): pages/api/records/wopcs.ts should prefer view.WOPC.pdf when present (the Phase 4 canonical home) and only fall back to the signing-request lookup. As written it can't surface a signed WOPC whose request was swept, even after a WOPC.pdf backfill.

Escalated to T-089 (WOPC doc-shape restructure + revisions + signing-request sweeping; owner Accounting (Diagnostics)https://claude.ai/code/session_01G58Y71noihrYCDEDMexmea). The repair needs that migration's model (which Drive file is canonical, how revisions/sweep are meant to interact), so Records (Infrastructure) is not guess-fixing the prod data — wrong choice could attach a voided PDF as the "signed" copy.

NOT a T-047 clash

T-047 (IR56M, EOP Local Assistance fork) touches only the sign-flow UI + signature/chop compositionapp/wopc/sign/[requestId]/*, components/wopc/*, lib/wopc/signing/composition.server.ts, lib/wopc/signing/placement.ts (how a signature/chop is drawn and stamped onto the PDF). It does not touch lib/wopc/signingRequests/* (request lifecycle/sweeping), pages/api/records/wopcs.ts (the records reader), or lib/wopcDocShape.ts / lib/wopc.server.ts (doc shape/read). The broken state here is in the signing-request lifecycle + records display = T-089, not T-047. (Confirmed by diffing the file footprint of the recent T-047 commits.)

Decision log

2026-06-25 — opened + escalated to T-089 (diagnosed, handed off)

  • Attestation (Records (Infrastructure)): read AGENTS.md; scope-scanned — the WOPC doc-shape + revisions + signing-request sweep is T-089's scope, so this ticket cross-links there rather than opening a parallel task. The reader-robustness gap (#2) is the same WOPC read-path I touched for the empty-tab fix (I-011/T-110), but the resolution depends on T-089's signed-state model, so it belongs with T-089.
  • Source: Records (Infrastructure) · https://claude.ai/code/session_018RDB37kCqfouHdygVXTAtD
  • Not actioned by me: no prod-data writes, no reader change — the canonical-signed-PDF choice + the revisions/sweep contract are T-089's to define. Full live-data evidence captured above so that agent can verify without re-deriving.

2026-06-25 — owner supplied the canonical signed PDF + extra root-cause finding

  • Attestation (Records (Infrastructure)): read AGENTS.md; appending evidence after the owner identified the canonical signed Drive file. No prod write — the repair remains T-089's call.
  • Source: Records (Infrastructure) · https://claude.ai/code/session_018RDB37kCqfouHdygVXTAtD

Canonical signed PDF (verified)

The owner provided https://drive.google.com/file/d/10F29sJZ6UCSCpncUYvnIemeG5xoL5FSs/view. Confirmed via Drive v3 metadata + a download with the accounting SA:

Field Value
id 10F29sJZ6UCSCpncUYvnIemeG5xoL5FSs
name ERL-WOPC/2025-020_20260613.pdf (ref + the 06-13 final-sign date)
mimeType application/pdf
size 2437560 bytes (≈ 2.4 MB)
driveId 0ADgMmnOYpTQuUk9PVA (ERL shared drive)
parents 15EGlDQloITkY_KKLVgf8YpC322AEagyT
trashed false

The filename matches the convention the WOPC signing flow uses (<ref>_<YYYYMMDD>.pdf) and the date matches the parent's WOPC.signature.at = 2026-06-13T06:46:40Z. This is the file markWOPCSigned would have referenced via the deleted request's signedDriveFileId.

Repair specification (now fully defined — for T-089's writer)

lib/wopc.server.ts:markWOPCSigned writes the signed pointer as WOPC.pdf.signedFileId (line 946, NOT WOPC.pdf.fileId). The repair on payees/JC/wopc/ERL-WOPC|2025-020:

parentUpdate = {
  'WOPC.pdf.signedFileId': '10F29sJZ6UCSCpncUYvnIemeG5xoL5FSs',
  // Optionally also: storagePath: 'drive:10F29sJZ6UCSCpncUYvnIemeG5xoL5FSs' if
  //   T-089's getPdf accessor enforces a storagePath companion (see below — it does).
}

WOPC.currentRevision = 1 is already correct (1 sign, 0 voids on parent — the prior void cycles should have produced revisions/0, but none exist; this is a separate data debt the repair may want to backfill or leave as orphaned audit lost-to-sweep).

Extra finding — Phase 4d safety net has a field mismatch (likely separate bug)

lib/wopc/signingRequests/synthesize.ts:51,75 synthesises the swept request's signedDriveFileId from view.WOPC.pdf?.fileId — but the writer (markWOPCSigned) puts the id in WOPC.pdf.signedFileId, and WOPCViewPdf (lib/wopcDocShape.ts:86-91) doesn't even declare signedFileId on the view type (only fileId + storagePath). So even after the prod repair above lands, the synthesis safety net would still return signedDriveFileId: null and the records endpoint's findLatestRequestForWopc fallback would still hand back one of the surviving voided requests → Pending would persist.

Two ways T-089 could reconcile this: - Reader-side: widen WOPCViewPdf to expose signedFileId (and voidedFileId too, for symmetry with getVoid) and switch synthesize.ts to read it. Then any WOPC.pdf.signedFileId repair is enough for badge + download to follow. - Writer-side: change markWOPCSigned to also (or instead) write WOPC.pdf.fileId. Less invasive on consumers; more risky on existing prod docs that already use signedFileId.

Either is T-089's call; I'm flagging the inconsistency, not picking.

One more reader gap (separate from the synthesis fix)

pages/api/records/wopcs.ts:142-153 resolves the signed Drive id ONLY via the signing-request lookup chain (findRequestById(directId)findLatestRequestForWopc(ref)). For this WOPC the direct id is dangling (request swept) AND findLatestRequestForWopc returns the newest-by- createdAt request, which here is the 2026-06-13 voided one (HUjw90a6rQVHy9V1QLYz). Even if synthesis is fixed, the records list query doesn't go through the lookup endpoint — it does its own resolution and never reads WOPC.pdf. So the records-list fix is one of: - Read view.WOPC.pdf?.signedFileId first, fall back to the request lookup. - Or route through getSigningRequest / synthesizeFromWopcView so a single fix in synthesis covers both surfaces.

Again — T-089's choice; flagged for completeness.

Summary handoff

What T-089 needs to do, from the prod-data evidence above:

  1. Write WOPC.pdf.signedFileId = 10F29sJZ6UCSCpncUYvnIemeG5xoL5FSs (+ storagePath if your accessor requires it) on tebs-epl payees/JC/wopc/ERL-WOPC|2025-020. (The 4 surviving signing requests can stay as-is; they're correctly voided and signed-but-swept.)
  2. Reconcile the signedFileIdfileId naming between markWOPCSigned, WOPCViewPdf/getPdf, and synthesize.ts so the Phase 4d safety net actually surfaces the signed Drive id after a sweep.
  3. Decide whether the records list (pages/api/records/wopcs.ts) should read WOPC.pdf directly or route through the lookup endpoint for a single resolution path.

No code changes from this session — handoff is complete with the canonical Drive id + the field naming gap on record.

2026-07-01 — fixed (via T-089)

Resolved via T-089 (done) — WOPC signed-PDF doc-shape + repair. Closed per owner. WARNING: if ERL-WOPC/2025-020 still reads 'Pending' on Records, reopen (T-089 done doesn't itself prove that one prod-data repair landed). [owner: close I-014] - Source (edit): EOP Local Assistance (fork) · session edb0abc7-6373-449b-8e31-379fd38d391b