Story-2555 · functions lane

Table anchors now carry the grid, not a guess

Mental model: flattened table text is a bag of labels and values. Row and column coordinates are the ruled lines that make it a table.

The truthful path

verbatim Textract vault
        ↓
LAYOUT_TABLE → TABLE → every CELL (including empty cells)
        ↓
{row, col, rowSpan, colSpan, text, confidence}
        ↓
document_pages_v2.blocks JSONB
        ↓
AnchorBlockView.cells → app OpenAPI contract

Why the backfill creates a new version

Activated extraction pages are immutable, and the extraction-version UUID is the Anchor response ETag. Editing version 75b2b479… in place would let a browser reuse a stale grid after receiving 304 Not Modified. The staging replay therefore derives one stable replacement UUID from each source version, reuses the source's immutable vault, and runs the existing atomic projection transaction. The old version becomes superseded; the new current version changes the ETag and carries the cells.

Staging replay receipt

After the Story deploy, temporarily add TEXTRACT_FIXTURE_ENABLED=true and the seven document UUIDs in TEXTRACT_FIXTURE_DOCUMENT_IDS to the extraction worker configuration. Wait for the Lambda configuration update to finish, then invoke pramaan-document-extraction-worker without an alias so the request reaches the newly configured $LATEST. The immutable :live alias cannot receive transient environment changes.

{
  "table_cell_backfill": {
    "firm_id": "<firm-uuid>",
    "document_id": "<allowlisted-document-uuid>",
    "source_extraction_version": "<current-source-uuid>"
  }
}

Invoke once for each of the seven allowlisted fixture documents. The path is disabled unless TEXTRACT_FIXTURE_ENABLED=true, and it rejects documents outside TEXTRACT_FIXTURE_DOCUMENT_IDS. Record each source-to-replacement UUID response, verify the Anchor view's explicit grid, then run the normal extraction-worker deploy so both temporary fixture variables are absent from $LATEST again. Confirm their absence with get-function-configuration; the :live alias remains on its immutable, clean version throughout.

Proof

Scope

No title/footer or cell-bounding-box metadata was added because the Story makes it optional and the explicit grid is already sufficient for truthful rendering. No serving query changed; only the Anchor payload gained table cells.