Skip to content

Commit 7ca17b2

Browse files
strukalexclaude
andcommitted
ocr.recoverNumericZerosFromCheckboxes: add row-label + positional fallback table finders
Original activity could only find its target table by exact title-text match on cell r0c0. In production, Azure DI often garbles the section heading on otherwise-clean form scans, dropping the activity to a no-op even when the underlying table and its checkbox-misread cells are clearly present. Adds two opt-in fallbacks tried in order when the title anchor misses, gated by a new fallbackTableFinder block on each table config: fallbackTableFinder.labelAnchor (Group A): Scan tables of configured shape (rowCount and columnCount ranges) for one whose col-0 cells contain >= minLabelMatches of the configured row-label texts. Column mapping reuses the existing header-text matcher. Recovers samples where Azure dropped the title but kept the row labels intact. fallbackTableFinder.positionalAnchor (Group B): For each candidate by shape, locate each expected row label as a loose-substring match on the page paragraphs. Pair each match with the candidate's row whose midY is closest. Tally `offset = label_index - row_index` votes; require top_votes >= minVotes AND top_votes >= dominanceRatio * second_votes before committing. Apply the dominant offset uniformly to map rows. Column mapping sorts the candidate's columns by midX and assigns left-to-right to the config's prefixes; if there's one extra column, drop the column whose cells are predominantly pure currency prefix. Per-cell eligibility (no digits/letters + selection mark overlap + field currently empty) is unchanged. Strategies are recorded per config in `metadata.tableFinderStrategy` and flips are bucketed in `metadata.appliedByStrategy` for downstream auditing. Without the fallbackTableFinder block, behavior is identical to the original (title-only) implementation. The SDPR-baked workflow JSON is updated to enable both fallbacks with reasonable defaults: shape 18-21 rows × 2-3 cols, minLabelMatches 12, minVotes 3, dominanceRatio 2.0. Validated on prod benchmark dfaddb26-… (99 SDPR samples, 213 originally- missing zeros): title 60 + label-anchor 33 + positional-anchor 18 = 111 flips total. Remaining 102 cases are out of "checkbox-as-zero" scope. Mirrored in the standalone counterpart at `scripts/benchmark analysis/recover-numeric-zeros.py` (separate branch). 4 new unit tests cover: Group-A title-miss + label-anchor fallback, Group-B successful offset-vote mapping (36 flips on a 19×2 with full label paragraphs), Group-B safe-skip when offset votes are sparse, Group-B 19×3 candidate where the pure-currency column is dropped to match the prefix count. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent aef2f67 commit 7ca17b2

6 files changed

Lines changed: 1105 additions & 124 deletions

File tree

apps/backend-services/src/hitl/tool-manifest.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,13 @@ const TOOL_MANIFEST: ToolManifestEntry[] = [
164164
toolId: "ocr.recoverNumericZerosFromCheckboxes",
165165
label: "Recover Numeric Zeros from Checkboxes",
166166
description:
167-
"Recover numeric values (typically 0) for custom-model fields that Azure DI misread as selection marks. Per-table config in node parameters: locate the table by header text, map prefix→column and suffix→row, recover only cells with selection-mark markers (no digits/letters) that overlap a page-level selectionMark. Never overwrites populated fields.",
167+
"Recover numeric values (typically 0) for custom-model fields that Azure DI misread as selection marks. Per-table config in node parameters: locate the table (title anchor → row-label anchor → positional anchor with offset vote), map prefix→column and suffix→row, recover only cells with selection-mark markers (no digits/letters) that overlap a page-level selectionMark. Never overwrites populated fields. Fallback finders (labelAnchor, positionalAnchor) are opt-in via the fallbackTableFinder block.",
168168
parameters: [
169169
{
170170
name: "tables",
171171
type: "object",
172172
description:
173-
"Array of { find, columns, rows, recoveryValue?, cellEligibility? }. See temporal correction-tool-registry for the full shape.",
173+
"Array of { find, columns, rows, recoveryValue?, cellEligibility?, fallbackTableFinder? }. See temporal correction-tool-registry for the full shape.",
174174
required: false,
175175
},
176176
],

0 commit comments

Comments
 (0)