Skip to content

v1.10.0 — Closure (table alignment 3-layer rework + measurement/gate family)

Choose a tag to compare

@livezingy livezingy released this 30 Sep 05:00
· 156 commits to main since this release
a179f09

Release 1.10.0 notes

Tag: v1.10.0
Date: 2026-09-30
Train: Closure batch — table cell alignment rework + measurement / gate family
Cut: docs-only, on top of a179f09 (the code tree is byte-identical to b4e4a55)

Summary

v1.10.0 closes the P-002 / P-020…P-027 track. The only backend behaviour change is P-002 (table cell
alignment): the single "uniform grid geometric containment" path in table_backfill becomes three layers —
T1 value match (row-band + column-window anchored) → T2 geometric (unchanged) → T3 text cluster — with a
backfill sanity gate in front of the amber (value-replacement) branch. Everything else is measurement tooling,
documentation gates, promotion of R&D conclusions, and Lite-era clean-up. Cloud validation ran three gates
(G4/G5/G6) with real before/after numbers.

Added

  • P-002 — three-layer table cell alignment (value match → geometric → cluster) (2026-09-29): see Summary.
    New host module backend/app/services/table_alignment.py (zero migration: the three existing functions stay put,
    one-way import backfill → alignment). Contract additions are purely additive: cell_align_reason (per-cell
    8-value reason grid; null for non-candidate cells), quality.table_backfill.align_reason_counts (8 keys always
    present, sum == candidates), reason on mismatch_details[] and on debug records, a 6th review-table column,
    and sibling_bboxes sibling-table neighbourhood exclusion.
    Geometry constants calibrated on real layouts: EXP_X_MIN_RATIO 0.15 → 0.05; the other three unchanged.
    Golden pins: bank 12×value_match (was 6 green / 6 red), symbol 4×value_match (was 4 red), and a new
    non-uniform gold sample at 5 green / 2 honest red.
    Correctness evidence: the old funnel silently mis-filled 4 cells on mamba p12 (e.g. a numeric cell backfilled
    with a column-header label); the new sanity gate blocks all four as reviewable red.
  • P-020 — OCR quality measurement harness M1+M2 (2026-09-22): a machine-local bypass instrument under
    scripts/measure/ (deliberately not versioned). It never imports the app — it consumes the pipeline's result
    JSON — so historical results stay re-measurable on the same scale. Degraded-specimen synthesis from one forward
    affine matrix, weak GT from a born-digital text layer, line-level CER (micro/corpus/macro), LCS reading order,
    table / non-table / digit slices, cell accuracy, a pinned 15-column CSV and an HTML report. Pinned design points
    D2 (char-only edit-distance DP with a fixed equal-cost tie-break), D7 (GT quad-ised through the same forward
    affine, exact clipping) and D8 (char-level provenance declared structurally unmeasurable).
  • P-022 — retired-reference (tombstone) gate (2026-09-24): an outward-facing doc that references a path / port /
    command / module deleted by a past retirement fails, unless the same line states that it was retired — a notice
    is documentation, a stale instruction is a defect. Literal substring tokens only: no regex, no subprocess, no
    writes. Scope is an allow-list; archived material is exempt with a printed reason. Wired by import into
    audit_agent_ops.py, so the existing required agent-ops-audit check runs it — no CI configuration change.
  • P-023 — test stub scope is now both a rule and a gate (2026-09-25): born from a P-021 CI run that reddened
    Phase A in a file the branch never touched, because a module-level sys.modules["paddle"] stub is installed at
    collection time and outlived the test that needed it. scripts/test_registry_audit.py gains check 5
    (check_stub_scope, stdlib AST, fail-closed on unparsable files), wired into the required audit check, and the
    kernel testing doc states the criterion plus both failure modes.
  • P-026 — public quality case study (2026-09-26): docs/demo/QUALITY_CASE_STUDY.md tells the P-021 story end to
    end — a silent OCR coordinate defect (scale drift 1.1084–1.2257, non-rigid, rotations flattened) found by the
    local measurement harness, traced to one engine preprocessing default, fixed by one init parameter, and locked by
    contract tests. Before/after: 12/15 fixture×spec combos improved, 0 regressions, text volume recovered up to 2.1×,
    and 26/26 responses byte-identical across two independent cloud runs.
  • P-027 — table-structure GT reconciliation on WTW (P-018 P2) (2026-09-28): the local harness gains a
    structure-side scale for tables on the public WTW dataset (ICCV 2021; 14,581 photographed / scanned / web table
    images) — an XML→GT adapter, a self-implemented structure-only TEDS (APTED-style ordered-tree distance with pinned
    insert/delete/update costs), and an evaluate-table CLI scoring detection recall/IoU, row/column/merge occupancy
    agreement, and S-TEDS. Predictions are captured once into a content-addressed cache, so metric revisions cost no
    GPU time. Baseline (2026-09-28, 300-image stratified subset, seed=42): grid_exact 145/300, grid_f1 mean 0.8989,
    mean_s_teds 0.8399, table_recall 0.8300. WTW's ground truth carries no cell text, so the content dimension is
    out of scope here; scores are reported as our own protocol, not an official leaderboard.

Removed

  • Lite track references stripped from all outward-facing material (documentation catching up with the v1.8 code
    deletion, not a capability change), and dead Lite instructions removed from the living docs.
  • Lite-era files deleted (explicitly authorized, second pass): the 2.9 MB DocVision_Lite.gif, the dead
    lite-preview.e2e.js spec, the broken bootstrap_lite_models.{py,sh}, the orphan
    packages/docuvision-core/models/ tree, and two stale test-support files. Verified after deletion: core
    pytest -q still reports 13 passed, matching the v1.8 baseline.
  • .zcode/ retired by user decision (expected unused for the next six months), together with its .gitignore rule
    and PENDING P-006.
  • ZCode retired from the agent roster; review duty becomes "whoever takes the round", not a named agent.

Changed

  • Acceptance material explicitly archived: the v1.3.0/1.3.1/1.4/1.5/1.6 cloud checklists each got an
    Archived / frozen (2026-09-24) header. Bodies are deliberately untouched — frozen is not the same as rewritten.
  • P-022 promoted out of PENDING into a living doc (docs/architecture/doc-governance.md), registered as
    DOC-1 / DOC-2. The token list deliberately stays in scripts/docs_refs_audit.py as the single source.
  • P-024 — the "propose a new chat" rule gains forced trigger points instead of pure introspection; every
    commit / PR and every CHANGELOG / PENDING write carries one Session-check: line, zero counts included.
  • P-025 — R&D promotion becomes a gate (DOC-3: every PENDING entry carries one > status: line, and a
    landed entry older than 90 days warns) plus a checkpoint (one Promotion-check: line per PENDING / CHANGELOG
    write). Deliberately not machine-checked, with the reason written down.
  • E2 — the unit suite can no longer shrink silently (scripts/unit_suite_pin.py; first pin 7 files / 67 case
    declarations / 0 skips), wired into the required audit check.
  • OCR quality-measurement harness promoted into a living doc (docs/architecture/ocr-quality-harness.md); the
    two transitional local-only drafts were deleted and docs/R&D/README.md was corrected in the same pass.
  • CI core install line de-Lite'd and then dropped (it was installing nothing); stale CI workflow-comment figures
    replaced by pointers at their pins.

Fixed

  • P-021 — POST /api/v1/ocr returned polygons outside the uploaded pixel frame (fix landed 2026-09-24):
    ocr_service._init_engine built the engine without use_doc_unwarping, so PaddleOCR's doc preprocessor ran
    UVDoc unwarping (default on) and the returned polygons described a warped canvas rather than the input image
    (measured as a non-rigid frame: scale 1.11–1.23 per probe, rotations flattened). One-line fix, net-zero on lines;
    locked by backend/tests/test_ocr_service_engine_params.py (stubs paddle, no GPU / Paddle) with a negative
    control. Post-fix cloud readings: scale 0.9992–1.0001, residual 0.6–1.1 px, rotation amplitude preserved; text
    usability 12 improved / 0 regressions / 3 unchanged. Accepted side effect: book.jpg (a genuinely curved spread)
    loses 27% of its text.
  • Two kind: full test files no longer leak their paddle / cv2 stubs (P-023; found by the new check 5 on its
    first real run) — the local suite had been red for that reason alone.
  • P-019 — module-map §6 A3 row single-sourced: the row's own copies of five §3 infra numbers are gone (one had
    already drifted); §3 is now the single numeric source.

Verification

Gate Result
G4 (cloud) judge 1-6/9 PASS; judge 7 (golden-diff whitelist) closed with the approved whitelist; judges 8/9 covered by G1 unit tests + golden pins
G5 (cloud) INV-A1 / A2 / A3 zero violations; candidate-cell set identical before/after; red rate p12 58.2% → 0.8%, p29 97% → 25.4%
G6 (cloud) WTW sentinel PASS — re-scoring the same cache is byte-identical and wtw_metrics.csv sha256 matches the P-027 baseline
Local pytest 442 passed; audit / lint / docs_refs 0 error / 0 warning

Full detail — including the honest boundaries and the execution-time rulings X1–X5 — is in the CHANGELOG
[1.10.0] section and docs/architecture/provenance-review.md §4/§5.

Upgrade / migration

  • No schema, API or configuration migration.
  • Contract additions are purely additive (new reason grid + counts + reason fields + a 6th review-table column),
    so existing consumers keep working. Consumers that assert an exact review_list shape or a fixed review-table
    column count must add the new column.
  • Known discrepancy: APP_VERSION in backend/app/core/config.py is still 1.9.0 — this cut was docs-only and
    did not bump it, so /health reports 1.9.0 for the v1.10.0 tag. Logged for a follow-up code change (a code
    change would break the "code tree byte-identical" property of this tag, so it was deliberately not bundled here).