From 9d9315439acbaf8abf3de89858ede5f97f28512b Mon Sep 17 00:00:00 2001 From: Karl Date: Wed, 12 Aug 2026 12:50:36 +0800 Subject: [PATCH] Correct CalVer generator smoke contract --- README.md | 6 +- .../generation_parameters_2026.08.12.2.json | 77 ++++++++++++++++ dataset/README.md | 6 +- .../ACCEPTANCE_CRITERIA_2026.08.12.2.md | 65 +++++++++++++ docs/corpus/COVERAGE_MATRIX_2026.08.12.2.csv | 30 ++++++ ...NTHETIC_DATA_SPECIFICATION_2026.08.12.2.md | 68 ++++++++++++++ ...NTHETIC_DATA_SPECIFICATION_2026.08.12.2.md | 55 +++++++++++ ...TIC_DATA_SPECIFICATION_2026.08.12.2.sha256 | 1 + pyproject.toml | 2 +- .../synthetic_table_record_2026.08.12.2.json | 91 +++++++++++++++++++ src/borderless_table_structuring/__init__.py | 2 +- 11 files changed, 395 insertions(+), 8 deletions(-) create mode 100644 configs/generation_parameters_2026.08.12.2.json create mode 100644 docs/corpus/ACCEPTANCE_CRITERIA_2026.08.12.2.md create mode 100644 docs/corpus/COVERAGE_MATRIX_2026.08.12.2.csv create mode 100644 docs/corpus/SYNTHETIC_DATA_SPECIFICATION_2026.08.12.2.md create mode 100644 docs/experiment-records/EVIDENCE_CARD_SYNTHETIC_DATA_SPECIFICATION_2026.08.12.2.md create mode 100644 docs/experiment-records/EVIDENCE_CARD_SYNTHETIC_DATA_SPECIFICATION_2026.08.12.2.sha256 create mode 100644 schemas/synthetic_table_record_2026.08.12.2.json diff --git a/README.md b/README.md index 641eb75..89383d3 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,9 @@ OmniDocBench is used as one document-parsing evaluation protocol. The methods and infrastructure in this repository are designed around the broader research problem of table structure recognition. -## Research snapshot 2026.08.12.1 +## Research snapshot 2026.08.12.2 -The `2026.08.12.1` snapshot establishes the shared representation, evaluation, +The `2026.08.12.2` snapshot establishes the shared representation, evaluation, and synthetic-corpus specification for two independent modeling tracks. It includes Canonical Table normalization, order-invariant topology targets, candidate-integrity checks, table-only model interfaces, a frozen 256-record @@ -143,7 +143,7 @@ compression, blur, background, and scanning artifacts. Dataset roles are assigned by document, template, content, renderer, and seed families before rendering. Exact and near-duplicate audits operate on images, text, normalized structure, geometry, and provenance. See the -[synthetic data specification](docs/corpus/SYNTHETIC_DATA_SPECIFICATION_2026.08.12.1.md) +[synthetic data specification](docs/corpus/SYNTHETIC_DATA_SPECIFICATION_2026.08.12.2.md) and [data governance guide](docs/corpus/DATA_GOVERNANCE_2026.08.12.1.md). ## Installation diff --git a/configs/generation_parameters_2026.08.12.2.json b/configs/generation_parameters_2026.08.12.2.json new file mode 100644 index 0000000..bda0823 --- /dev/null +++ b/configs/generation_parameters_2026.08.12.2.json @@ -0,0 +1,77 @@ +{ + "configuration_release": "2026.08.12.2", + "dataset_release": "data-smoke-2026.08.12.2", + "schema_release": "synthetic-table-record-2026.08.12.2", + "seed_namespace": "borderless-table-structuring-data-smoke-2026.08.12.2", + "seed_start": 202608120200000, + "requested_records": 256, + "allow_failed_seed_replacement": false, + "gate_costs": { + "false_edit": 4.0, + "missed_edit": 1.0, + "uncertain_action": "KEEP" + }, + "categories": { + "exact_keep": {"count": 64, "gate_label": "KEEP"}, + "hard_keep": {"count": 64, "gate_label": "KEEP"}, + "single_minimal_edit": {"count": 64, "gate_label": "EDIT"}, + "complex_correction": {"count": 64, "gate_label": "EDIT"} + }, + "roles_per_category": { + "train": 44, + "development": 12, + "holdout": 8 + }, + "counterfactual_pairs": { + "minimum_pairs": 64, + "same_role_required": true, + "shared_fields": [ + "content_family_id", + "template_family_id", + "font_family_id", + "renderer_family_id", + "base_degradation" + ] + }, + "structure": { + "rows": {"minimum": 2, "maximum": 28}, + "columns": {"minimum": 2, "maximum": 14}, + "header_depth": {"minimum": 0, "maximum": 4}, + "span_fraction": {"minimum": 0.0, "maximum": 0.45}, + "empty_cell_fraction": {"minimum": 0.0, "maximum": 0.35}, + "maximum_cells": 240 + }, + "rendering": { + "canvas_width_px": [960, 1280, 1600, 2048], + "dpi": [96, 150, 200, 300], + "font_size_px": {"minimum": 12, "maximum": 32}, + "cell_padding_px": {"minimum": 4, "maximum": 18}, + "rotation_degrees": {"minimum": -4.0, "maximum": 4.0}, + "border_alpha": {"minimum": 0.0, "maximum": 1.0}, + "jpeg_quality": {"minimum": 55, "maximum": 100}, + "gaussian_blur_radius": {"minimum": 0.0, "maximum": 1.8}, + "noise_sigma": {"minimum": 0.0, "maximum": 12.0} + }, + "corruptions": { + "single_minimal_edit_exactly_one": true, + "complex_correction_minimum_operations": 2, + "complex_correction_maximum_operations": 4, + "accepted_prior_must_remain_canonical_legal": true, + "invalid_grid_fixtures_are_test_only": true, + "allowed": [ + "extra_split", + "missing_split", + "incorrect_merge", + "missing_merge", + "span_extent_error", + "token_ownership_error", + "geometry_inconsistency", + "row_or_column_assignment_error" + ] + }, + "determinism": { + "semantic_replay_runs": 2, + "normalized_pixel_replay_runs": 2, + "sha256_algorithm": "sha256" + } +} diff --git a/dataset/README.md b/dataset/README.md index ab9a368..4a4b34f 100644 --- a/dataset/README.md +++ b/dataset/README.md @@ -6,13 +6,13 @@ dataset references used by reproducible experiments. ## Active dataset entry template ```yaml -dataset_name: data-2026.08.12.1 +dataset_name: data-2026.08.12.2 service: private-hugging-face-or-approved-object-store repository: DearKarl/borderless-table-structuring-data revision: null root_manifest_sha256: null -schema_release: synthetic-table-record-2026.08.12.1 -research_snapshot: 2026.08.12.1 +schema_release: synthetic-table-record-2026.08.12.2 +research_snapshot: 2026.08.12.2 roles_available: [] license_manifest_sha256: null overlap_audit_sha256: null diff --git a/docs/corpus/ACCEPTANCE_CRITERIA_2026.08.12.2.md b/docs/corpus/ACCEPTANCE_CRITERIA_2026.08.12.2.md new file mode 100644 index 0000000..c57e645 --- /dev/null +++ b/docs/corpus/ACCEPTANCE_CRITERIA_2026.08.12.2.md @@ -0,0 +1,65 @@ +# Acceptance Criteria 2026.08.12.2 + +Status: `FROZEN_FOR_GENERATOR_SMOKE` + +## Preregistered smoke gate + +`data-smoke-2026.08.12.2` passes only when all criteria below pass. No failed +seed may be silently replaced, no category quota may be rebalanced after +generation, and no model performance metric may be used to select records. + +| Criterion | Required result | Failure action | +|---|---:|---| +| Requested records | 256 | Stop | +| Generated records | 256 | Stop | +| Accepted records | 256 | Stop | +| Exact KEEP / Hard KEEP / Single / Complex | 64 / 64 / 64 / 64 | Stop | +| Counterfactual pairs | at least 64 complete same-role pairs | Stop | +| Schema validation | 256/256 | Stop | +| Canonical legality of Gold and prior | 256/256 | Stop | +| Complete grid coverage of Gold and prior | 256/256 | Stop | +| Gold recompilation | 256/256 semantic identity | Stop | +| Unique OCR-token ownership | 100% of owned tokens | Stop | +| Finite complete geometry | 256/256 | Stop | +| KEEP semantic identity | 128/128 | Stop | +| EDIT replay to Gold | 128/128 | Stop | +| Explicit KEEP empty diff | 128/128 | Stop | +| LoRA target completeness | 256/256 | Stop | +| Semantic replay | identical across 2 runs | Stop | +| Normalized-pixel replay | identical across 2 runs | Stop | +| Source and license inventory | complete and approved | Stop | +| Cross-role exact overlap | 0 | Stop | +| Cross-role unresolved near overlap | 0 | Stop | +| Terminal-input usage | false for every record | Stop | +| Incomplete-grid rejection fixture | rejected as `GRID_INCOMPLETE` | Stop | +| Complete count accounting | requested/generated/accepted/quarantined/failed | Stop | + +## Validation reason codes + +Every failure uses a stable reason code, including: + +- `SCHEMA_INVALID`; +- `CANONICAL_ILLEGAL`; +- `GRID_INCOMPLETE`; +- `GOLD_RECOMPILE_MISMATCH`; +- `TOKEN_OWNERSHIP_INVALID`; +- `GEOMETRY_INVALID`; +- `KEEP_NOT_IDENTITY`; +- `EDIT_NOT_REPLAYABLE`; +- `NONDETERMINISTIC_SEMANTICS`; +- `NONDETERMINISTIC_PIXELS`; +- `SOURCE_OR_LICENSE_INCOMPLETE`; +- `CROSS_ROLE_EXACT_OVERLAP`; +- `CROSS_ROLE_NEAR_OVERLAP`; +- `TERMINAL_DERIVATION_RISK`. + +Quarantine manifests preserve every failed record identifier, frozen seed, +reason code, and diagnostic hash. The intentionally incomplete-grid fixture is +test evidence and is not part of the 256-record corpus manifest. + +## Post-pass boundary + +A sealed pass authorizes a new non-overwriting shared-corpus build with frozen +distributions. It does not authorize Explicit or LoRA training. Corpus scale is +chosen from measured generation cost, coverage, and quarantine rate, not from +current official benchmark scores. diff --git a/docs/corpus/COVERAGE_MATRIX_2026.08.12.2.csv b/docs/corpus/COVERAGE_MATRIX_2026.08.12.2.csv new file mode 100644 index 0000000..73f2716 --- /dev/null +++ b/docs/corpus/COVERAGE_MATRIX_2026.08.12.2.csv @@ -0,0 +1,30 @@ +category,gate_label,phenomenon,requested_count,train_count,development_count,holdout_count,counterfactual_pair_required,primary_risk +exact_keep,KEEP,simple_regular,12,8,2,2,false,false_edit +exact_keep,KEEP,hierarchical_header,12,8,2,2,false,false_edit +exact_keep,KEEP,row_or_column_span,12,8,2,2,false,false_edit +exact_keep,KEEP,empty_or_sparse_cells,8,6,2,0,false,false_edit +exact_keep,KEEP,dense_or_multiline_text,8,6,2,0,false,text_loss +exact_keep,KEEP,mixed_script_or_formula,6,4,2,0,false,text_loss +exact_keep,KEEP,clean_high_resolution_control,6,4,0,2,false,false_edit +hard_keep,KEEP,multilevel_irregular_header,12,8,2,2,true,false_edit +hard_keep,KEEP,mixed_two_dimensional_spans,12,8,2,2,true,false_edit +hard_keep,KEEP,weak_missing_or_partial_borders,12,8,2,2,true,false_edit +hard_keep,KEEP,empty_near_empty_or_sparse,8,6,2,0,true,false_edit +hard_keep,KEEP,dense_small_long_or_multiline_text,8,6,2,0,true,text_loss +hard_keep,KEEP,rotation_blur_compression_or_noise,8,4,2,2,true,false_edit +hard_keep,KEEP,color_background_or_alignment_trap,4,4,0,0,true,false_edit +single_minimal_edit,EDIT,extra_split,12,8,2,2,true,cell_inflation +single_minimal_edit,EDIT,missing_split,10,6,2,2,true,under_segmentation +single_minimal_edit,EDIT,incorrect_merge,10,6,2,2,true,content_reassignment +single_minimal_edit,EDIT,missing_merge,10,6,2,2,true,over_segmentation +single_minimal_edit,EDIT,span_extent_error,8,6,2,0,true,topology_error +single_minimal_edit,EDIT,token_ownership_error,6,4,2,0,true,text_loss +single_minimal_edit,EDIT,geometry_inconsistency,4,4,0,0,true,location_error +single_minimal_edit,EDIT,row_or_column_assignment_error,4,4,0,0,true,topology_error +complex_correction,EDIT,multilevel_header_with_spans,12,8,2,2,false,topology_error +complex_correction,EDIT,joint_split_and_merge,12,8,2,2,false,cell_inflation +complex_correction,EDIT,weak_border_with_topology_error,10,6,2,2,false,missed_edit +complex_correction,EDIT,empty_cells_with_spans,8,6,2,0,false,ownership_error +complex_correction,EDIT,dense_multiline_with_topology_error,8,6,2,0,false,text_loss +complex_correction,EDIT,mixed_script_formula_with_topology_error,6,4,2,0,false,text_loss +complex_correction,EDIT,rotation_noise_with_topology_error,8,6,0,2,false,geometry_error diff --git a/docs/corpus/SYNTHETIC_DATA_SPECIFICATION_2026.08.12.2.md b/docs/corpus/SYNTHETIC_DATA_SPECIFICATION_2026.08.12.2.md new file mode 100644 index 0000000..4bd4c95 --- /dev/null +++ b/docs/corpus/SYNTHETIC_DATA_SPECIFICATION_2026.08.12.2.md @@ -0,0 +1,68 @@ +# Synthetic Data Specification 2026.08.12.2 + +Status: `FROZEN_FOR_GENERATOR_SMOKE` + +Dataset identifier: `data-smoke-2026.08.12.2` + +Schema identifier: `synthetic-table-record-2026.08.12.2` + +Supersedes: `2026.08.12.1` + +## Purpose of this revision + +This revision resolves one contradiction discovered during implementation +review. The earlier coverage matrix requested four accepted records whose prior +contained incomplete grid coverage, while the acceptance gate correctly +required complete and legal prior geometry for all 256 accepted records. + +Incomplete-grid examples remain useful validator rejection fixtures, but they +must be `QUARANTINE` records outside the accepted 256-record smoke. The four +accepted records are now legal row-or-column assignment errors that preserve +complete grid coverage while requiring a deterministic topology correction. + +## Inherited research contract + +All unchanged requirements of +[`SYNTHETIC_DATA_SPECIFICATION_2026.08.12.1.md`](SYNTHETIC_DATA_SPECIFICATION_2026.08.12.1.md) +remain binding, including: + +- `KEEP`, `EDIT`, and `QUARANTINE` gate semantics; +- direct Canonical Table and order-invariant supervision; +- Explicit topology-only targets with prior text frozen; +- complete LoRA Canonical Table targets; +- a four-to-one false-edit versus missed-edit cost; +- uncertainty resolving to KEEP; +- 64 Exact KEEP, 64 Hard KEEP, 64 Single Minimal Edit, and 64 Complex + Correction records; +- 176 train, 48 development, and 32 holdout records; +- at least 64 same-role counterfactual pairs; +- no failed-seed replacement; +- source, license, provenance, deterministic replay, and overlap gates; +- no model training or performance claim. + +## Active frozen artifacts + +- Coverage matrix: + [`COVERAGE_MATRIX_2026.08.12.2.csv`](COVERAGE_MATRIX_2026.08.12.2.csv) +- Generation parameters: + [`generation_parameters_2026.08.12.2.json`](../../configs/generation_parameters_2026.08.12.2.json) +- Record schema: + [`synthetic_table_record_2026.08.12.2.json`](../../schemas/synthetic_table_record_2026.08.12.2.json) +- Acceptance criteria: + [`ACCEPTANCE_CRITERIA_2026.08.12.2.md`](ACCEPTANCE_CRITERIA_2026.08.12.2.md) +- License policy: + [`LICENSE_AND_SOURCE_POLICY_2026.08.12.1.md`](LICENSE_AND_SOURCE_POLICY_2026.08.12.1.md) +- Split policy: + [`SPLIT_AND_ISOLATION_POLICY_2026.08.12.1.md`](SPLIT_AND_ISOLATION_POLICY_2026.08.12.1.md) + +## Negative rejection fixtures + +The generator test suite must additionally create at least one intentionally +invalid incomplete-grid fixture. It must be rejected with +`GRID_INCOMPLETE`, remain outside the 256 accepted records, and appear in test +evidence rather than the released corpus manifest. + +## Escalation boundary + +A sealed pass of `data-smoke-2026.08.12.2` authorizes a new non-overwriting +shared-corpus build. It does not authorize Explicit or LoRA model training. diff --git a/docs/experiment-records/EVIDENCE_CARD_SYNTHETIC_DATA_SPECIFICATION_2026.08.12.2.md b/docs/experiment-records/EVIDENCE_CARD_SYNTHETIC_DATA_SPECIFICATION_2026.08.12.2.md new file mode 100644 index 0000000..a8aba66 --- /dev/null +++ b/docs/experiment-records/EVIDENCE_CARD_SYNTHETIC_DATA_SPECIFICATION_2026.08.12.2.md @@ -0,0 +1,55 @@ +# Evidence Card: Synthetic Data Specification 2026.08.12.2 + +Status: `PASS_SEALED_FOR_BOUNDED_GENERATOR_IMPLEMENTATION` + +## Objective + +Resolve the implementation-review contradiction between an accepted +incomplete-grid prior and the mandatory complete-grid acceptance rule, while +preserving the frozen 256-record composition and all source, license, split, +determinism, and non-training boundaries. + +## Change + +- Replaced four accepted `localized_grid_coverage_error` records with four + accepted `row_or_column_assignment_error` records. +- Required both Gold and prior to be legal Canonical Tables with complete grid + coverage for all 256 records. +- Moved incomplete-grid corruption to an explicit negative rejection fixture + outside the accepted corpus manifest. +- Advanced the specification, configuration, schema, dataset smoke, and public + research snapshot to `2026.08.12.2`. + +## Unchanged boundary + +- Requested/generated/accepted records: `256/256/256`. +- Category counts: `64/64/64/64`. +- Role counts: `176/48/32` train/development/holdout. +- Current OmniDocBench or Customer50 contents used: `false`. +- Model training started: `false`. +- Current official benchmark evaluation run: `false`. +- Historical tags and sealed artifacts modified: `false`. + +## Validation + +- All JSON and JSON Schema documents parsed successfully. +- Coverage and role totals closed exactly. +- All local Markdown links resolved. +- The data-free regression suite passed `18/18` tests under Python 3.12. +- Repository diff passed `git diff --check`. + +## Frozen artifact hashes + +| Artifact | SHA256 | +|---|---| +| `configs/generation_parameters_2026.08.12.2.json` | `4d5730db1e814256bd0c3287e3a8f36bc6f968038da01fcb0ef7300ebd29b625` | +| `docs/corpus/SYNTHETIC_DATA_SPECIFICATION_2026.08.12.2.md` | `0c66f64d6e9be7fbb8e554e57500b176b7486a93445ad6f7d259b01668818cb7` | +| `docs/corpus/COVERAGE_MATRIX_2026.08.12.2.csv` | `dd35f920d5614e609213dc9bce22bf0dd0549d2c8b78a64b7788aa22fd9ed8d2` | +| `docs/corpus/ACCEPTANCE_CRITERIA_2026.08.12.2.md` | `c232d2a638005ef13ecb72c1fbe697c7b31e37be64413981398e3a56ecc7c147` | +| `schemas/synthetic_table_record_2026.08.12.2.json` | `ccab367184358f75cf653235034eb33de0688618b2e9923b0c58871fae059f0e` | + +## Result + +The `2026.08.12.2` specification revision passes and is the only active input +to the bounded generator smoke. The immutable `2026.08.12.1` tag remains +preserved as historical research evidence. diff --git a/docs/experiment-records/EVIDENCE_CARD_SYNTHETIC_DATA_SPECIFICATION_2026.08.12.2.sha256 b/docs/experiment-records/EVIDENCE_CARD_SYNTHETIC_DATA_SPECIFICATION_2026.08.12.2.sha256 new file mode 100644 index 0000000..75a5e21 --- /dev/null +++ b/docs/experiment-records/EVIDENCE_CARD_SYNTHETIC_DATA_SPECIFICATION_2026.08.12.2.sha256 @@ -0,0 +1 @@ +f095803788923f32bf633e9cc86fadaf7564d2fbdf6a68692fce607b257ff377 EVIDENCE_CARD_SYNTHETIC_DATA_SPECIFICATION_2026.08.12.2.md diff --git a/pyproject.toml b/pyproject.toml index 0685775..863e586 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "borderless-table-structuring-lab" -version = "2026.8.12.1" +version = "2026.8.12.2" description = "Research on canonical representations, explicit topology modeling, and generative adaptation for borderless table structure recognition." readme = "README.md" requires-python = ">=3.10" diff --git a/schemas/synthetic_table_record_2026.08.12.2.json b/schemas/synthetic_table_record_2026.08.12.2.json new file mode 100644 index 0000000..2d7bc7f --- /dev/null +++ b/schemas/synthetic_table_record_2026.08.12.2.json @@ -0,0 +1,91 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "borderless-table-structuring/synthetic-table-record/2026.08.12.2", + "title": "Synthetic Table Record 2026.08.12.2", + "type": "object", + "required": [ + "schema_release", + "dataset_release", + "sample_id", + "role", + "gate_label", + "category", + "identity", + "provenance", + "rendering", + "payloads", + "gold", + "prior", + "views", + "audits" + ], + "properties": { + "schema_release": {"const": "synthetic-table-record-2026.08.12.2"}, + "dataset_release": {"const": "data-smoke-2026.08.12.2"}, + "sample_id": {"type": "string", "pattern": "^data-smoke-2026\\.08\\.12\\.2-[0-9]{6}$"}, + "role": {"enum": ["train", "development", "holdout"]}, + "gate_label": {"enum": ["KEEP", "EDIT", "QUARANTINE"]}, + "category": {"enum": ["exact_keep", "hard_keep", "single_minimal_edit", "complex_correction"]}, + "identity": { + "type": "object", + "required": ["generation_seed", "document_cluster_id", "source_family_id", "template_family_id", "content_family_id", "renderer_family_id", "font_family_id", "counterfactual_pair_id"], + "properties": { + "generation_seed": {"type": "integer", "minimum": 0}, + "document_cluster_id": {"type": "string", "minLength": 1}, + "source_family_id": {"type": "string", "minLength": 1}, + "template_family_id": {"type": "string", "minLength": 1}, + "content_family_id": {"type": "string", "minLength": 1}, + "renderer_family_id": {"type": "string", "minLength": 1}, + "font_family_id": {"type": "string", "minLength": 1}, + "counterfactual_pair_id": {"type": ["string", "null"]} + }, + "additionalProperties": false + }, + "provenance": { + "type": "object", + "required": ["generator_release", "source_id", "license_decision", "license_manifest_sha256", "terminal_inputs_used"], + "properties": { + "generator_release": {"const": "2026.08.12.2"}, + "source_id": {"type": "string", "minLength": 1}, + "license_decision": {"enum": ["APPROVED_REDISTRIBUTABLE", "APPROVED_REBUILD_ONLY", "QUARANTINED"]}, + "license_manifest_sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"}, + "terminal_inputs_used": {"const": false} + }, + "additionalProperties": true + }, + "rendering": {"type": "object", "required": ["parameters", "font_sources", "normalized_pixel_sha256"]}, + "payloads": {"type": "object", "required": ["image_path", "image_sha256", "record_sha256"]}, + "gold": {"$ref": "#/$defs/canonicalTable"}, + "prior": {"$ref": "#/$defs/canonicalTable"}, + "views": { + "type": "object", + "required": ["gate", "explicit", "lora"], + "properties": { + "gate": {"type": "object", "required": ["label", "false_edit_cost", "missed_edit_cost"]}, + "explicit": {"type": "object", "required": ["prior_state_sha256", "order_invariant_difference", "raw_text_frozen"]}, + "lora": {"type": "object", "required": ["complete_canonical_target", "table_only"]} + }, + "additionalProperties": false + }, + "audits": { + "type": "object", + "required": ["schema_valid", "canonical_legal", "prior_canonical_legal", "grid_complete", "prior_grid_complete", "gold_recompiled", "token_ownership_valid", "geometry_valid", "semantic_replay_valid", "normalized_pixel_replay_valid", "cross_role_overlap_clear"] + } + }, + "$defs": { + "canonicalTable": { + "type": "object", + "required": ["rows", "columns", "cells", "tokens", "semantic_state_sha256", "full_state_sha256"], + "properties": { + "rows": {"type": "integer", "minimum": 1}, + "columns": {"type": "integer", "minimum": 1}, + "cells": {"type": "array", "minItems": 1}, + "tokens": {"type": "array"}, + "semantic_state_sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"}, + "full_state_sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"} + }, + "additionalProperties": true + } + }, + "additionalProperties": false +} diff --git a/src/borderless_table_structuring/__init__.py b/src/borderless_table_structuring/__init__.py index c756aeb..d2c4f4e 100644 --- a/src/borderless_table_structuring/__init__.py +++ b/src/borderless_table_structuring/__init__.py @@ -1,5 +1,5 @@ """Research primitives for borderless table structure recognition.""" -__release__ = "2026.08.12.1" +__release__ = "2026.08.12.2" __all__ = ["__release__"]