Skip to content

corpus: mirror rvt-rs #226/#230/#231 — relations and storeys join the surface; spec 1.1.0 - #6

Merged
DrunkOnJava merged 1 commit into
mainfrom
corpus/mirror-rvt-rs-1-1-0
Aug 30, 2026
Merged

corpus: mirror rvt-rs #226/#230/#231 — relations and storeys join the surface; spec 1.1.0#6
DrunkOnJava merged 1 commit into
mainfrom
corpus/mirror-rvt-rs-1-1-0

Conversation

@DrunkOnJava

@DrunkOnJava DrunkOnJava commented Aug 30, 2026

Copy link
Copy Markdown
Owner

Brings the umbrella to OctetProof 1.1.0 and mirrors the current rvt-rs corpus state (rvt-rs main 5da2570, PRs #226 / #230 / #231). The protocol gains two additive field classes; the corpus gains two agreement classes it did not have — topology, and labels-with-units.

The result

Artifact Before After
g-2026-0001 (20 KB element fixture) PASS, 4 surface fields, 9 excluded PASS, 6 surface fields, 10 excluded
g-2026-0002 (full project export) PASS, 10 surface fields, 4 excluded PASS, 13 surface fields, 3 excluded

g-2026-0002 now claims, agreed exactly by all three witnesses at tolerance 0: 360 IFCWALL, 256 IFCCOLUMN, 132 IFCDOOR, 80 IFCSLAB, 20 IFCSHADINGDEVICE, 15 IFCBUILDINGSTOREY, 6 IFCWINDOW, 1 IFCUNITASSIGNMENT, three zeroes — plus 138 IfcRelFillsElement [host Tag, filling Tag] pairs and the 15 [name, elevation] storeys, Basement 2 at −40 ft through Level 13 at 185.5 ft.

Three known_gap exclusions remain, and they are the deliverable: IFCSPACE 116 vs 18, IFCMATERIAL 10 vs 102 (an over-count), IFCPROPERTYSET 0 vs 854 (an over-count against zero). That table used to have nine rows.

g-2026-0001 stays thin — three of its five counts are zero on both sides — with one exception worth recording: Revit writes the complete fifteen-storey spatial hierarchy into even a one-element 20 KB export, so storeys.IFCBUILDINGSTOREY is as strong on the fixture as on the 19,879-entity project export. relations.IFCRELFILLSELEMENT goes the other way and is excluded decoder_baseline: that fixture carries no IfcRelFillsElement at all, so the two sides of that edge are not comparable on it.

What changed

ProtocolSPEC.md 1.0.2 → 1.1.0 and both schemas, byte-identical copies from rvt-rs (the same policy as the registry). schema_version now an enum of ["1.0.0","1.1.0"]; optional observation.relations / observation.storeys; verdict diffs gain only_in_a / only_in_b. Minor and additive (§16.1, §20) — the diff function, canonicalizer, provenance model and status vocabulary are unchanged, and a 1.0.0 observation is still valid input. registry/witnesses.json was already byte-identical and is untouched.

Gatetools/verdict.py ports both field classes from tools/ci/witness-verdict.py: exact sorted-multiset equality, no tolerance concept, diffs carrying set sizes plus the members each side holds alone. The surface is built counts → relations → storeys, the order the committed verdict records. A witness compared on a set-valued class must declare it in semantic_surface_covered or the verdict is MANIFEST_ERROR. The umbrella-manifest shape is kept — semantic_surface / excluded stay explicit and now cross-check against all three blocks. tools/witness-ifcopenshell.py ports the extraction, resolving the elevation with ifcopenshell.util.unit. tools/jsonschema_mini.py implements maxItems, the one keyword the new schemas introduce — it fails loudly on unimplemented keywords, so without it the corpus would not validate at all. compare-verdict.py, fetch.py, index.py, check-registry.py and replay.sh needed nothing.

Witness gluewitnesses/ifc-lite/ re-mirrored from rvt-rs a0044f4 (PR #230), gaining fills_element_pairs and building_storey_set (units via ifc_lite_core::extract_length_unit_scale). The only deviation from upstream remains the manifest-reading path. Cargo.lock unchanged, no new dependency, §9.6 pin still one number: ifc-lite-core = "=7.1.1".

Corpus — observations and verdicts copied verbatim from research/witness/<alias>/; both manifests rebuilt from the project-count fixtures under the documented drop rules, gaining relations and storeys blocks and levels as known; both declare octetproof_version: "1.1.0" because both now carry 1.1.0 blocks. MANIFEST_INDEX.json regenerated, chain head 5e6a64228083.

Local verification — clean _replay, both artifacts end to end

g-2026-0001: PASS — witnesses ifc-lite, ifcopenshell, rvt-rs
  surface: 6 fields, excluded: 10, diffs: 0
  replay ifc-lite: match
  replay ifcopenshell: match
  replay rvt-rs: match
verdict matches the committed record (ignored: artifact_id, replay, timestamp, verdict_hash_sha256)

g-2026-0002: PASS — witnesses ifc-lite, ifcopenshell, rvt-rs
  surface: 13 fields, excluded: 3, diffs: 0
  replay ifc-lite: match
  replay ifcopenshell: match
  replay rvt-rs: match
verdict matches the committed record (ignored: artifact_id, replay, timestamp, verdict_hash_sha256)

plus tools/index.py --check (chain head ok), tools/check-registry.py (47 witnesses, 2 manifests resolve, §9.6 pin held) and tools/validate-corpus.py (6 observations + 2 verdicts conform to the 1.1.0 schemas).

Both bridge witnesses hash identically on both artifacts99e6cd7a… on g-2026-0001, 5a101408… on g-2026-0002 — across all 14 entity types, all 138 relation pairs and all 15 storey pairs, including the unit resolution, which each reader performed with its own code.

Fail-closed paths exercised, not assumed. Mutating one relation host tag and one storey elevation in a fresh ifc-lite observation produces DISAGREE with only_in_a / only_in_b naming exactly the changed members; stripping storeys from a witness's semantic_surface_covered produces MANIFEST_ERROR; a three-element pair and an out-of-enum schema_version are both rejected by jsonschema_mini.

Docs

README's "what exists today" rewritten around the three agreement classes with the real numbers; both PROVENANCE.md files rewritten (witness-set hashes, surfaces, exclusion tables); corpus/README departure table updated for the 1.1.0 blocks and the octetproof_version policy; tools/README gains the field-class table and the reasons a storey elevation travels as a string and storey names are deliberately not Unicode-normalised; CONTRIBUTING's coverage vocabulary extended.


Note

Medium Risk
Touches the verification gate’s diff logic and committed corpus verdicts; mistakes could pass wrong agreement or break CI replay, but the change is additive and schema-backward-compatible.

Overview
OctetProof 1.1.0 adds two comparable surface classes — relations (sorted host/filling pair multisets) and storeys (sorted [name, elevation-in-feet] sets with per-file unit normalization) — and this PR lands the spec, schemas, gate, witnesses, and golden corpus on that release.

Protocol & CI: SPEC.md and observation/verdict JSON Schemas move to 1.1.0 (schema_version accepts 1.0.0 and 1.1.0; optional observation.relations / observation.storeys; verdict diffs may include only_in_a / only_in_b). .github/workflows/verdict.yml and docs now validate against 1.1.0 schemas.

Gate & witnesses: tools/verdict.py diffs the new set-valued fields with exact multiset equality and requires witnesses to declare relations / storeys in semantic_surface_covered or fail MANIFEST_ERROR. tools/witness-ifcopenshell.py emits the new payload keys; tools/jsonschema_mini.py gains maxItems for pair-shaped arrays. witnesses/ifc-lite/ is re-mirrored from rvt-rs (PR #230) with relation and storey extraction.

Corpus: Both artifacts declare octetproof_version: "1.1.0", gain relations / storeys manifest blocks, and ship regenerated observations and verdicts (updated hashes; MANIFEST_INDEX chain head refreshed). g-2026-0002 widens the claimed surface (e.g. walls, doors, slabs, 138 IFCRELFILLSELEMENT pairs, 15 storeys; exclusions shrink from nine gaps to three). g-2026-0001 adds storey agreement on the thin fixture while excluding the relation field where the bridge has no fills.

Reviewed by Cursor Bugbot for commit 9ef497e. Configure here.

… surface; spec 1.1.0

Brings the umbrella to OctetProof 1.1.0 and mirrors the current rvt-rs corpus
state. The protocol gains two additive field classes and the corpus gains two
agreement classes it did not have: topology, and labels-with-units.

Protocol (byte-identical copies from rvt-rs, the same policy as the registry)

  SPEC.md                                   1.0.2 -> 1.1.0
  schemas/witness-observation.schema.json   schema_version enum ["1.0.0","1.1.0"],
                                            optional observation.relations and
                                            observation.storeys
  schemas/witness-verdict.schema.json       diff only_in_a / only_in_b
  registry/witnesses.json                   already byte-identical, unchanged

1.1.0 is minor and additive (SPEC.md 16.1, 20). The diff function, the
canonicalizer, the provenance model and the verdict statuses are unchanged; a
1.0.0 observation is still valid input.

Gate (tools/)

  verdict.py           ports the two field classes from rvt-rs
                       tools/ci/witness-verdict.py. A `relations` category
                       carrying relation_ifc_type contributes
                       relations.<TYPE>; a `storeys` category carrying
                       storey_ifc_type contributes storeys.<TYPE>. Both are
                       exact sorted-multiset equality with no tolerance
                       concept (7.2); a diff carries the set sizes in
                       value_a / value_b plus only_in_a / only_in_b and
                       tolerance_applied: false. The surface is built counts
                       -> relations -> storeys, which is the order the
                       committed verdict records. A witness compared on a
                       set-valued class must declare it in
                       semantic_surface_covered, else MANIFEST_ERROR. The
                       umbrella-manifest shape is kept: semantic_surface and
                       excluded stay explicit and now cross-check against all
                       three blocks, so a status flip is still MANIFEST_ERROR
                       rather than a silent surface change.
  witness-ifcopenshell.py
                       ports the relation and storey extraction. The storey
                       elevation is resolved through
                       ifcopenshell.util.unit.calculate_unit_scale and
                       rendered in feet at 1e-6 as a fixed six-decimal
                       string, -0 normalised to 0.
  jsonschema_mini.py   implements maxItems, the one keyword the new schemas
                       introduce. It fails loudly on unimplemented keywords,
                       so without this the corpus would not validate at all.
  validate-corpus.py   reports against the 1.1.0 schemas.
  compare-verdict.py, fetch.py, index.py, check-registry.py, replay.sh
                       unchanged; the new fields needed nothing from them and
                       the 9.6 pin is still one number (ifc-lite-core =7.1.1).

Witness glue (witnesses/ifc-lite/)

  Re-mirrored from tools/ci/witness-ifc-lite/ in DrunkOnJava/rvt-rs at
  a0044f4a11361626c2a4b9fb93c4696ac6b1c6e6 (PR #230): fills_element_pairs and
  building_storey_set, the latter resolving units with
  ifc_lite_core::extract_length_unit_scale. The only deviation from upstream
  remains the manifest-reading path (bridge.file_hash_sha256 / bridge.bytes /
  bridge.schema, bridge file passed directly). Cargo.lock unchanged, no new
  dependency, version pin unchanged.

Corpus

  Observations and verdicts for both artifacts copied verbatim from
  research/witness/<alias>/ in rvt-rs. Both manifests rebuilt from the
  project-count fixtures under the documented drop rules (decoder_* dropped, a
  category kept iff it carries its block's type key), gaining `relations` and
  `storeys` blocks and `levels` as `known`. Both declare
  octetproof_version 1.1.0, because both now carry 1.1.0 blocks.
  MANIFEST_INDEX.json regenerated: chain head 5e6a64228083.

  g-2026-0001   4 surface fields, 9 excluded  ->   6 surface, 10 excluded
  g-2026-0002  10 surface fields, 4 excluded  ->  13 surface,  3 excluded

  g-2026-0002 now claims 360 IFCWALL, 256 IFCCOLUMN, 132 IFCDOOR, 80 IFCSLAB,
  20 IFCSHADINGDEVICE, 15 IFCBUILDINGSTOREY, 6 IFCWINDOW, 1 IFCUNITASSIGNMENT
  and three zeroes, plus 138 IfcRelFillsElement [host Tag, filling Tag] pairs
  and the 15 [name, elevation] storeys. Three known_gap exclusions remain:
  IFCSPACE (116 vs 18), IFCMATERIAL (10 vs 102) and IFCPROPERTYSET (0 vs 854).

  g-2026-0001 stays thin — three of its five counts are zero on both sides —
  with one exception worth the record: Revit writes the complete fifteen-storey
  spatial hierarchy into even a one-element 20 KB export, so
  storeys.IFCBUILDINGSTOREY is as strong on the fixture as on the full export.
  relations.IFCRELFILLSELEMENT goes the other way and is excluded
  decoder_baseline: that fixture carries no IfcRelFillsElement at all.

Local verification, clean _replay, both artifacts end to end

  $ OCTETPROOF_PYTHON=.../ifcos/bin/python tools/replay.sh corpus/artifacts/g-2026-0001
  corpus: 9 observation(s) and 2 verdict(s) conform to the 1.1.0 schemas
  g-2026-0001: PASS - witnesses ifc-lite, ifcopenshell, rvt-rs
    surface: 6 fields, excluded: 10, diffs: 0
    replay ifc-lite: match
    replay ifcopenshell: match
    replay rvt-rs: match
  verdict matches the committed record (ignored: artifact_id, replay, timestamp, verdict_hash_sha256)
  == replay OK: g-2026-0001 PASS, observations replayed, verdict matches

  $ OCTETPROOF_PYTHON=.../ifcos/bin/python tools/replay.sh corpus/artifacts/g-2026-0002
  corpus: 9 observation(s) and 2 verdict(s) conform to the 1.1.0 schemas
  g-2026-0002: PASS - witnesses ifc-lite, ifcopenshell, rvt-rs
    surface: 13 fields, excluded: 3, diffs: 0
    replay ifc-lite: match
    replay ifcopenshell: match
    replay rvt-rs: match
  verdict matches the committed record (ignored: artifact_id, replay, timestamp, verdict_hash_sha256)
  == replay OK: g-2026-0002 PASS, observations replayed, verdict matches

  $ python3 tools/index.py --check
  corpus/MANIFEST_INDEX.json: chain head 5e6a64228083... ok (2 artifact(s))
  $ python3 tools/check-registry.py
  witnesses.json: valid - 11 nodes, 47 witnesses, 7 artifacts, 3 edges, 9 agreements; 2 corpus manifest(s) resolve
  $ python3 tools/validate-corpus.py
  corpus: 6 observation(s) and 2 verdict(s) conform to the 1.1.0 schemas

  Both bridge witnesses hash identically on both artifacts - 99e6cd7a on
  g-2026-0001, 5a101408 on g-2026-0002 - across all 14 entity types, all 138
  relation pairs and all 15 storey pairs, including the unit resolution, which
  each reader performed with its own code.

Fail-closed paths exercised, not just assumed: mutating one relation host tag
and one storey elevation in a fresh ifc-lite observation produces DISAGREE
with only_in_a / only_in_b naming exactly the changed members; stripping
`storeys` from a witness's semantic_surface_covered produces MANIFEST_ERROR; a
three-element pair and an out-of-enum schema_version are both rejected by
jsonschema_mini.

Docs: README's "what exists today" rewritten around the three agreement
classes with the real numbers, both PROVENANCE.md files rewritten (witness-set
hashes, surfaces, exclusion tables), corpus/README's departure table updated
for the 1.1.0 blocks and the octetproof_version policy, tools/README gains the
field-class table and the reasons the storey elevation is a string and storey
names are not Unicode-normalised, CONTRIBUTING's coverage vocabulary extended.
@cursor

cursor Bot commented Aug 30, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_02b93722-8fdd-45e7-98d0-2e57a6d796d0)

@DrunkOnJava
DrunkOnJava merged commit a5bfe41 into main Aug 30, 2026
5 checks passed
@DrunkOnJava
DrunkOnJava deleted the corpus/mirror-rvt-rs-1-1-0 branch August 30, 2026 19:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant