Summary
packages/docx-core/src/integration/lean-spec-bridge.test.ts →
INV-RT-001: paired round-trip text equality on pre-tracked paragraph-only inplace comparison output
is a fast-check property test with no fixed seed ({ numRuns: NUM_RUNS }, line ~1268). It intermittently
fails in CI when the generator produces a pre-tracked paragraph whose content is entirely <w:ins> (an
insertion that already existed in the original input). It surfaced on the workspace-test (20)/(22) jobs
of PR #337, but it is pre-existing and unrelated to that PR (see "Not caused by #337" below).
Deterministic reproduction
Pin the seed on the failing property (temporary edit at lean-spec-bridge.test.ts:1268):
{ numRuns: NUM_RUNS, seed: -695140806, path: "62:2:1:1:2:2:2:2:2:2:2:2:7", endOnFailure: true },
npm run test:run -w @usejunior/docx-core -- src/integration/lean-spec-bridge.test.ts
# FAIL INV-RT-001: paired round-trip text equality on pre-tracked paragraph-only inplace comparison output
# Got error: triage=inplace-fallback ... fallbackReason=round_trip_safety_check_failed failedChecks=["rejectText"]
# context: original {family:"w:del", paragraphs:["!","!","I"]} / revised {family:"w:ins", paragraphs:["6."], insertedText:"I"}
Root cause
The inplace comparison output (candidateXml) for this scenario is:
<w:p>…PPR-DEL… <w:del><w:r><w:delText>!</w:delText></w:r></w:del></w:p>
<w:p>…PPR-DEL… <w:del><w:r><w:delText>!</w:delText></w:r></w:del></w:p>
<w:p>
<w:ins w:author="Comparison"><w:r><w:t>6.</w:t></w:r></w:ins>
<w:ins w:author="Lean Bridge"><w:r><w:t>I</w:t></w:r></w:ins> <!-- pre-tracked insertion from the ORIGINAL -->
</w:p>
The reject round-trip safety check (pipeline.ts:585-591) computes
compareTexts(originalTextForRoundTrip, extractTextWithParagraphs(rejectAllChanges(candidateXml))).
originalTextForRoundTrip = "!\n!\nI" — the original's text including its own pre-tracked <w:ins>I</w:ins>.
rejectAllChanges(candidateXml) removes all insertions — including the original's pre-tracked "I" — so the third paragraph's text is gone.
→ The round-trip can never reproduce "…\nI" because reject deletes the very "I" the oracle expects to
survive. The engine therefore (correctly) fails its own rejectText safety check and falls back to rebuild;
the test asserts inplace, so it fails. The flake appears only when the random generator happens to place an
all-w:ins (pre-tracked-insertion-only) paragraph such that reject's removal diverges from
originalTextForRoundTrip.
Not caused by PR #337 (mark-based reject)
Reproduced identically on main (4e00489) with the same pinned seed. PR #337 changes reject of an
untracked-mark all-w:ins paragraph from drop to keep-empty, but that is behavior-neutral here:
old reject → "!\n!", new reject → "!\n!\n", and normalizeText collapses both to ["!","!"]. The
failure is about the removed pre-tracked "I", not the drop-vs-keep-empty difference.
Remediation options (pick per design intent)
- Make the property test deterministic in CI — pin a seed and/or add
examples covering the
pre-tracked all-w:ins family, so this no longer randomly red-lights unrelated PRs. (Removes the flake;
does not address the oracle gap below.)
- Fix the round-trip oracle for pre-tracked inputs —
originalTextForRoundTrip should be the
reject projection of the original's own tracked changes (apples-to-apples with rejectAllChanges(candidate),
which also rejects), rather than the original's accepted/as-authored text. The current oracle assumes the
original carries no pre-existing insertions.
- Decide engine semantics for reject of a paragraph stacking insertions from two authors
(Comparison + pre-tracked "Lean Bridge") and align the safety check accordingly.
Option 1 stops the CI flake immediately; options 2/3 address the underlying pre-tracked round-trip
modeling gap.
Summary
packages/docx-core/src/integration/lean-spec-bridge.test.ts→INV-RT-001: paired round-trip text equality on pre-tracked paragraph-only inplace comparison outputis a fast-check property test with no fixed seed (
{ numRuns: NUM_RUNS }, line ~1268). It intermittentlyfails in CI when the generator produces a pre-tracked paragraph whose content is entirely
<w:ins>(aninsertion that already existed in the original input). It surfaced on the
workspace-test (20)/(22)jobsof PR #337, but it is pre-existing and unrelated to that PR (see "Not caused by #337" below).
Deterministic reproduction
Pin the seed on the failing property (temporary edit at
lean-spec-bridge.test.ts:1268):Root cause
The inplace comparison output (
candidateXml) for this scenario is:The reject round-trip safety check (
pipeline.ts:585-591) computescompareTexts(originalTextForRoundTrip, extractTextWithParagraphs(rejectAllChanges(candidateXml))).originalTextForRoundTrip = "!\n!\nI"— the original's text including its own pre-tracked<w:ins>I</w:ins>.rejectAllChanges(candidateXml)removes all insertions — including the original's pre-tracked"I"— so the third paragraph's text is gone.→ The round-trip can never reproduce
"…\nI"because reject deletes the very"I"the oracle expects tosurvive. The engine therefore (correctly) fails its own
rejectTextsafety check and falls back to rebuild;the test asserts inplace, so it fails. The flake appears only when the random generator happens to place an
all-
w:ins(pre-tracked-insertion-only) paragraph such that reject's removal diverges fromoriginalTextForRoundTrip.Not caused by PR #337 (mark-based reject)
Reproduced identically on
main(4e00489) with the same pinned seed. PR #337 changes reject of anuntracked-mark all-
w:insparagraph from drop to keep-empty, but that is behavior-neutral here:old reject →
"!\n!", new reject →"!\n!\n", andnormalizeTextcollapses both to["!","!"]. Thefailure is about the removed pre-tracked
"I", not the drop-vs-keep-empty difference.Remediation options (pick per design intent)
examplescovering thepre-tracked all-
w:insfamily, so this no longer randomly red-lights unrelated PRs. (Removes the flake;does not address the oracle gap below.)
originalTextForRoundTripshould be thereject projection of the original's own tracked changes (apples-to-apples with
rejectAllChanges(candidate),which also rejects), rather than the original's accepted/as-authored text. The current oracle assumes the
original carries no pre-existing insertions.
(Comparison + pre-tracked "Lean Bridge") and align the safety check accordingly.
Option 1 stops the CI flake immediately; options 2/3 address the underlying pre-tracked round-trip
modeling gap.