Skip to content

fix(docx-compare): preserve aligned inline note reader bindings - #994

Open
stevenobiajulu wants to merge 8 commits into
mainfrom
979-preserve-inline-note-reader-bindings-20260917
Open

stevenobiajulu wants to merge 8 commits into
mainfrom
979-preserve-inline-note-reader-bindings-20260917

Conversation

@stevenobiajulu

Copy link
Copy Markdown
Member

Outcome

Keep safe aligned footnote anchors stable while retaining fine-grained definition history. When that reconciliation leaves multiple unique anchors, normalize references and definitions together so LibreOffice does not rotate note bodies. Preserve lone-anchor collision IDs, copied footnote/endnote separation, reserved definitions, source-ID evidence and foreign history.

Ambiguous or property-changing anchor edits retain the conservative existing fallback. Invalid reachability is fail-closed; this is not a general endnote-inline or arbitrary cross-story normalization.

Verification

  • All six mandatory local gates pass on head efa602b: full root suite 3,443 passed / 57 skips. The note-reader opt-in cases are separately exercised below, not counted as successful skipped tests.
  • Required note/auxiliary suite: 67 passed, zero skips, with actual unresolved LibreOffice Accept/Reject against independent original/revised identity controls.
  • Required SHA-pinned public corpus: 21/21, all 23 manifest rows replayed, 316.36 seconds.
  • Built-code public NVCA Management Rights Letter: all five note bindings match both native complete-package and AST source projections; actual reader Accept/Reject each match 33 paragraph/heading entries. Five main-document and ten explicit ancillary note XML instances validate against the vendored schema.
  • Public bundled ILPA: all 23 note bindings independently match corresponding original/revised states through native and AST Accept/Reject. The manifest updater changes only the ILPA main/footnote bytes and projected XML hashes. Source identities, text hashes, formatting scores, safety outcomes, divergence approvals and unrelated package parts are unchanged.
  • Fresh dynamic Claude Opus 5 APPROVE of runtime parent0b05c6c3 and exact final manifest-only head efa602b. Complete reports and actual execution traces collected before publication.

Explicit limits

Word remains UNVERIFIED. The complete ILPA comparison is NOT claimed XSD-clean: tracked and native Reject fail the already-open #944 CT_SectPrBase historical header/footer-reference restriction on both built main ca61878 and this branch; both source packages and native Accept validate. New note repair does not introduce or solve it. Fresh characterization: #944 (comment) .

#990 tracks coarse history for property-changing note anchors. #992 tracks content-dependent reachability validation/availability; fail-closed is retained rather than returning a package with misbound notes. Public counters remain documented main-story pre-ancillary evidence, not final package wrapper totals.

The ILPA audit is non-regression evidence, not an ILPA binding-bug red/green test: baseline passes the same resolved content/order assertions. Its emitted shape improves redline quality (18 redundant anchor delete/reinsert pairs removed) and separates all anchors from shared definition identities. Equal-text definitions are not distinguished by that content-level audit. Actual reader misbinding red/green evidence comes from the synthetic five-note and real public NVCA controls, independently rerun by Opus.

Normal integration of PR988 is preserved; no force push, primary checkout mutation, hosted API work or branch-protection change.

Fixes: #979
Ref: #990, #992, #944, #763

LibreOffice Accept discarded revised inline footnote content when collision-safe original/revised anchors were reconciled to one shared tracked definition, even without copied footnote paragraphs. Retain side-specific definitions whenever both anchors are emitted, and normalize decimal-equivalent note IDs before collision resolution so lexical identity differences do not omit a definition or bind Reject to the revised body. Scoped copying remains fail-closed for section and annotation markers. Fifty-four focused tests pass including actual reader Accept/Reject against independent identities, mixed moved endnotes, lexical IDs, lone stable anchors, and duplicate-definition rejection. Word remains unverified; required root/corpus and review gates remain prerequisites to pushing.

Fixes: #979
… edits

Keeping both inline side definitions avoided a LibreOffice import loss but disabled all corresponding definition reconciliation and retained superseded note bodies. Preserve the existing copied-footnote fallback and restore one redlined definition for dedicated adjacent same-author, same-format aligned anchors. Publish one stable anchor in that bounded shape so resolving a deleted duplicate cannot make LibreOffice discard the shared revised body. Ambiguous or foreign history is not flattened. The raw aligned reference count intentionally changes from two tracked copies to one stable reference; both projections still bind once, definition-level redlining and unchanged-text granularity remain, and all 63 definition/actual-reader controls pass. Canonicalize note configuration IDs as well as definitions and anchors while leaving unrelated story IDs unchanged.

Ref: #979, #763
…ning

Review approved the aligned-anchor repair but requested that ambiguous anchor formatting/reference changes and counter part scope be explicit. Pin separate-definition fallback without calling it fine-grained history, and verify complete-package Accept/Reject prunes the superseded unreferenced footnote. Clarify counters derive from tagged main-story alignment before ancillary repairs, not a final package element inventory; numeric behavior is unchanged. Document the cost of declining consolidation rather than silently losing anchor Reject properties.

Ref: #979
A real public five-note input exposes a reader binding failure that lone-note synthetic controls cannot: editing the first definition leaves anchors numbered 6,2,3,4,5 and LibreOffice attaches later bodies to the wrong references. Reordering definitions alone does not repair it. Normalize anchors and definitions together through the existing conservative identity pass only after safe inline reconciliation and only when multiple unique anchors remain. Preserve the established collision-safe ID for a lone anchor, all unrelated unique documents, reserved definitions, scoped history, and the source-ID evidence mapping. New five-note native/package and actual-reader controls retain fine-grained definition history and independently compare both source projections. All 67 note/auxiliary reader controls pass; the repaired public NVCA control also passes native, AST and actual LibreOffice projections.

Ref: #979, #990, #763
The required public corpus replay catches one stale ILPA row after safe aligned-note reconciliation. Regenerate through the existing SHA-pinned fixture updater, preserving all 23 source identities, text hashes, formatting scores, safety outcomes, divergence approvals and unrelated package parts. The only differences are main-story and footnote-part bytes plus the two projected XML hashes. A separate complete-package native and AST audit confirms every one of the 23 original and revised note bindings on both projections; this is a representation repair, not a waiver of the corpus gate.

Ref: #979, #990, #992
@vercel

vercel Bot commented Sep 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
site Ready Ready Preview Sep 17, 2026 11:54pm UTC

Request Review

@usejunior-llm-gate

usejunior-llm-gate Bot commented Sep 17, 2026

Copy link
Copy Markdown

LLM gate (advisory)

All evaluated rules passed - 6 pass, 0 warn, 0 error, 10 skipped, 16 total

Findings

None.

All 16 rules (6 evaluated, 10 skipped)
Rule Verdict Detail
read_file response metadata parity SKIPPED paths not touched by this PR
Live DOM namespace-safe OOXML writes SKIPPED paths not touched by this PR
Complex-field revisions preserve complete accept/reject state machines PASS The PR touches footnote and endnote reference alignment and canonicalization in packages/docx-compare/src/tagged/noteReferenceIdentity.ts and pipeline.ts, and does not touch field atomization, validateFieldStructure, w:fldChar, w:instrText, w:delInstrText, or collapsed-field comparison logic.
Field validation per story, not global PASS The PR touches footnote handling in packages/docx-compare/src/tagged/pipeline.ts; field validation is run independently per ECMA story via splitStories and validateFieldStructure on the reconciled footnotes and endnotes from both archives, so global counter balance is not treated as sufficient (pipeline.ts:1102-1119).
Revision IDs seeded from all revision-bearing side parts SKIPPED paths not touched by this PR
Accept/reject sweep side parts and caches PASS The PR touches document comparison alignment and note reference identity logic in packages/docx-compare, and does not modify DocxDocument.acceptChanges, DocxDocument.rejectChanges, REVISION_STORY_PART_PATHS, accept_changes, reject_changes, or side-part revision markup.
DocumentViewNode.heading stays canonical SKIPPED paths not touched by this PR
AI-author parity across entry points SKIPPED paths not touched by this PR
Property-change wrapper discipline SKIPPED paths not touched by this PR
SUPPORT.md Table A drift vs. implementation SKIPPED paths not touched by this PR
Table A / Table B boundary on side-part revisions SKIPPED paths not touched by this PR
Canonical-emission surface completeness SKIPPED paths not touched by this PR
Unit-test quality (avoid tautological / change-detector tests) PASS The added tests in packages/docx-compare/src/tagged/noteReferenceIdentity.test.ts construct expected values and DOM fixtures from first principles to verify formatting preservation, change acceptance/rejection, and safety policies (line 12, line 71, line 118, line 259) without mocking the SUT or relying on tautological behavior.
Re-derived facts vs canonical sources PASS The PR does not re-compute any facts derived elsewhere; canonicalizeNoteArchiveIds in packages/docx-compare/src/tagged/noteReferenceIdentity.ts:10 consumes the canonical helper canonicalNoteId imported from packages/docx-compare/src/tagged/ancillaryFieldSafety.ts:131.
.openspec tag ↔ test-assertion drift PASS The PR does not add, move, or change any '.openspec' tags in the modified test files, so the precondition is not met.
Library stays general (no downstream-domain leakage) SKIPPED paths not touched by this PR

@stevenobiajulu

Copy link
Copy Markdown
Member Author

Shipping is held: required workspace-test (22) failed on the same existing aggregate ILPA hyperlink annotation test timeout (30000ms), also reproduced twice on PR993. Failure job: https://github.com/UseJunior/safe-docx/actions/runs/35269582431/job/105365705779 . A separate focused test-only fix preserves all four public source/destination combinations and every assertion, with independently named 30-second cases. Its local gates pass; independent Opus review and actual required CI remain mandatory. No automerge is armed, and no checks or protections will be bypassed. Once that fix ships, main will be normally integrated and final exact-head gates/review repeated.

Preserve reviewed history while incorporating main's independently bounded public ILPA annotation cases. Repeat final integration gates and review before pushing this focused runtime repair; do not rewrite or bypass protected history.

Ref: #979
@stevenobiajulu

Copy link
Copy Markdown
Member Author

Final independent dynamic Opus 5 review of local integrated head bb066d37312e10d2ccc5fb5c15c3e7201a1706b0: APPROVE, no blocking findings. Complete analysis was collected and read; exact head/branch and actual model verified, reviewer exited 0. It executed all 67 required note/auxiliary tests with zero skips and actual LibreOffice Accept/Reject dispatches against independent identity controls, regenerated the complete ILPA manifest row byte-for-byte from current source, and tested guarded normalization against main.

Two non-blocking precision/availability observations are explicitly accepted and recorded:

  • When a safe aligned anchor is stabilized and that footnote kind has multiple unique main-story anchors, normalization renumbers the whole main-story footnote kind, including unchanged anchors and non-reserved definitions. It is not a cross-kind/cross-story rewrite, does not activate for a lone anchor, and is not a public displayed-note-number contract. The earlier shorthand “no global ID rewrite” must not imply unchanged footnote IDs are always retained.
  • This activation also reaches existing fail-closed identity checks. A synthetic multi-anchor case with a footnoteReference in a foreign story publishes on main but throws NOTE_REFERENCE_IDENTITY_UNSAFE here. This is a deliberate safety/availability tradeoff, not a claim that availability is unchanged; related malformed-story characterization remains open in fix(docx-compare): validate note references independently of reader rewrites #992. No claim is made about what Word may author.

The six ILPA manifest leaves remain justified: 18 anchor positions stabilize, while five coarse pairs decline for verified formatting, relationship or adjacency reasons. Text/source hashes and the pre-existing formatting-divergence approval are unchanged; other 22 rows remain unchanged. Formatting-changing fine-grained history remains open #990, full ILPA snapshot XSD defects remain inherited #944, and Word projections remain UNVERIFIED.

The integrated head is still held for complete required corpus and fresh CI/post-merge smoke evidence. This comment is review adjudication, not a shipping or full-ILPA XSD pass claim. Public/synthetic inputs only.

@stevenobiajulu

Copy link
Copy Markdown
Member Author

Final local release evidence for head bb066d37312e10d2ccc5fb5c15c3e7201a1706b0, normally integrated with main 24b749524c62f8bf1c9852736482801a129c4b5c / shipped CI blocker #995:

  • All six mandatory local gates passed: 3,446 tests passed, 57 platform/opt-in skips. Required public corpus passed all 21 tests and all 23 reviewed rows without absent-corpus skips. Complete log /private/tmp/979-integration-995-presubmit-final-20260917.log; process exited 0.
  • Independent dynamic Claude Opus 5: APPROVE on this exact head; complete 26,550-byte analysis collected/read, actual model and lifecycle verified. All 67 required note/auxiliary tests passed with zero skips and actual LibreOffice dispatches against unresolved tracked packages and independent original/revised identity controls. The complete ILPA row regenerated byte-identically from source; six changed leaves causally explained, other 22 rows and all source/text/format/divergence assertions unchanged.
  • Fresh built-code SHA-pinned public NVCA management-rights letter: all five note identities survive native complete-package and comparison projections; actual LibreOffice Accept/Reject matches independent identity controls, all four reader states retain the expected 33 paragraph entries. All five source/revised/tracked/accepted/rejected main stories plus ten explicitly extracted footnote/endnote XML parts validate through the repository MCE-aware gate. Log /private/tmp/979-final-995-public-notes-reader-schema-20260917.log; process exited 0. No post-processing of emitted note order or IDs was used to make this smoke pass.
  • Guarded activation renumbers the whole main-story footnote kind, including unchanged anchors; it is not cross-kind/cross-story and does not activate for a lone anchor. Unsafe foreign-story identities can now fail closed rather than publish. These non-blocking review observations are recorded in the earlier adjudication, related availability characterization remains open fix(docx-compare): validate note references independently of reader rewrites #992.
  • Limits: format-changing fine-grained anchor history test(docx-compare): characterize fine-grained note history across anchor property changes #990 remains open; full public ILPA tracked/rejected packages retain inherited illegal inner-section snapshot references fix(docx-compare): filter header/footer relationships from sectPrChange snapshots #944, so this is NOT a full-ILPA XSD-clean claim. Word projections remain UNVERIFIED. Public/synthetic inputs only, no private documents or hosted API work.

Fresh required CI, Codecov and actual advisory/legacy deployment verdicts still required. Automerge remains unarmed; exact-merge own clean build/full tests/public feature smoke/local meaningful visuals/production SHA proof still required after merge.

@codecov

codecov Bot commented Sep 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 74.60317% with 16 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
packages/docx-compare/src/tagged/pipeline.ts 65.11% 0 Missing and 15 partials ⚠️
...s/docx-compare/src/tagged/noteReferenceIdentity.ts 95.00% 0 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

Verify the note reader repair against the latest independently shipped terminal-mark cleanup, retaining all existing review commits and repeating release gates before shipping.

Ref: #979
@stevenobiajulu

Copy link
Copy Markdown
Member Author

Latest-main final-head verification and remaining scope

Exact head 40fc49a050aed0765bcdb8ad940534b68e7b5438, normal merge of shipped main 9d82bab9 into reviewed bb066d37. No history rewrite. All six local gates passed: 3,479 passed / 57 documented platform/opt-in skips; required public corpus 21/21, all 23 reviewed rows, 335.49 seconds. Full log /private/tmp/979-integration-993-presubmit-20260917.log, actual process exit0 collected.

Fresh independent dynamic Claude Opus5 APPROVE at this exact head: 100 required note/auxiliary/cleanup tests passed with zero skips, including 14 actual LibreOffice reader cases against independently imported original/revised controls. Additional independently extracted main-vs-head red/green controls, fresh byte-identical ILPA manifest-row replay and package interactions executed. Complete collected 19,596-byte analysis .peer-review/979-integration-993-opus5-20260917.review.txt, actual claude-opus-5 session 050bbceb-e21c-410c-999f-b9b0e317fff6, exit0. Relevant implementation is pipeline.ts and noteReferenceIdentity.ts; serializer/terminal cleanup are interaction surfaces, not new branch changes.

Fresh built real public API smoke: source SHA-verified against this head's NVCA Management Rights Letter manifest; its five genuine note anchors retain the corresponding native complete-package and AST bindings. Actual LibreOffice dispatches consume the unresolved tracked comparison and match all 33 paragraph/heading entries in each corresponding independent source control. All 5 main-document plus 10 explicitly extracted ancillary footnotes/endnotes XML instances schema-validate. No emitted XML/IDs/order postprocessed to force a pass. Local public-only proof .peer-review/979-public-integration-993-reader-schema.log; no document upload.

Scope and open follow-ups: aligned edited footnote stabilization and moved unchanged endnotes are covered; general edited endnotes are not repaired. Reviewer independently reproduced edited-endnote reader misbinding beside stable endnotes on both main and this head; now tracked as #996: #996 . Its additional scratch probes are not claimed schema-certified or measured in Word. #990 property-changing anchor granularity, #992 widened fail-closed availability, #944 inherited full ILPA historical section-schema restriction and #973 terminal move ownership remain separate. Native/AST content and binding checks do not establish universal serialized empty-container parity.

Stable-anchor activation can renumber unchanged anchors/definitions within the same main-story footnote kind when multiple unique anchors are present, not just the edited anchor; lone IDs/reserved/unreferenced definitions and unrelated note kinds are separately covered. Existing foreign-story identity checks intentionally fail closed on the newly stabilized path; no assertion about Word authoring is made. All Word projections remain UNVERIFIED.

Normal push only. Automerge stays unarmed pending this head's full CI/legacy Vercel and actual advisory verdicts. Exact-merge own dependencies/clean full suite/real public reader/schema smoke and meaningful local renders/production exact-SHA proof still follow after merge. No hosted API, primary checkout or branch-protection mutation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test(docx-compare): characterize remaining LibreOffice note projection gaps

1 participant