@ansonlai/docx-redline-js 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +589 -287
- package/ARCHITECTURE.md +215 -9
- package/CHANGELOG.md +319 -0
- package/README.md +604 -360
- package/adapters/config.js +45 -43
- package/bin/docx-redline.js +3 -0
- package/core/list-targeting.js +101 -110
- package/core/paragraph-targeting.js +501 -61
- package/core/paragraph-text.js +209 -0
- package/core/revision-cloning.js +38 -0
- package/core/types.js +64 -10
- package/core/word-xml.js +43 -15
- package/dist/docx-redline-js.esm.js +2849 -466
- package/dist/docx-redline-js.esm.js.map +4 -4
- package/dist/docx-redline-js.esm.min.js +87 -76
- package/dist/docx-redline-js.esm.min.js.map +4 -4
- package/docs/TESTING.md +342 -23
- package/docs/plans/2026-09-05-structural-revisions-and-fidelity-oracles.md +1669 -0
- package/docs/plans/completed/2026-09-01-performance-and-complexity-reduction.md +669 -0
- package/docs/plans/completed/2026-09-03-agent-friendly-document-workflows.md +427 -0
- package/docs/plans/completed/2026-09-04-comment-anchor-and-cli-reliability.md +519 -0
- package/docs/plans/completed/PERFORMANCE-CONSOLIDATION.md +69 -0
- package/docs/plans/completed/structural-revision-capability-matrix.md +115 -0
- package/docs/schemas/document-operations.schema.json +109 -0
- package/docs/test-comparison-dashboard.html +4250 -7
- package/engine/formatting-removal.js +11 -2
- package/engine/oxml-engine.js +491 -336
- package/engine/reconstruction-mode.js +15 -14
- package/engine/reconstruction-writer.js +247 -142
- package/engine/route-selection.js +35 -0
- package/engine/rpr-helpers.js +334 -35
- package/engine/run-builders.js +239 -196
- package/engine/surgical-diff-application.js +222 -37
- package/engine/surgical-mode.js +134 -6
- package/engine/surgical-spans.js +52 -1
- package/engine/table-cell-context.js +3 -6
- package/engine/table-mode.js +1 -1
- package/index.d.ts +234 -6
- package/index.js +24 -1
- package/node/cli.js +317 -0
- package/node/docx-document.js +302 -0
- package/node/index.d.ts +31 -0
- package/node/index.js +2 -0
- package/node/zip-archive.js +52 -0
- package/orchestration/list-markdown.js +10 -16
- package/orchestration/list-parsing.js +7 -12
- package/orchestration/list-structural-fallback.js +21 -10
- package/package.json +24 -3
- package/pipeline/content-analysis.js +12 -17
- package/pipeline/ingestion-export.js +3 -31
- package/pipeline/ingestion-paragraph.js +10 -5
- package/pipeline/list-generation.js +150 -55
- package/pipeline/list-markers.js +70 -3
- package/pipeline/serialization.js +4 -2
- package/pipeline/structured-content.js +160 -0
- package/scripts/apply_changes.mjs +27 -0
- package/scripts/benchmark-operation-session.mjs +137 -0
- package/scripts/benchmark-targeting-browser.html +74 -0
- package/scripts/benchmark-targeting-hot-paths.mjs +67 -0
- package/scripts/benchmark-test-runner.mjs +59 -0
- package/scripts/build-test-dashboard.mjs +23 -0
- package/scripts/export-lane1-fixtures.mjs +380 -0
- package/scripts/export-reredline-stress-fixtures.mjs +317 -0
- package/scripts/export-validation-fixtures.mjs +1 -1
- package/scripts/extract_text.mjs +7 -0
- package/scripts/generate-paragraph-boundary-fixtures.ps1 +215 -0
- package/scripts/generate-test-dashboard.mjs +362 -11
- package/scripts/lib/word-coverage-catalogue.mjs +6 -2
- package/scripts/profile-route-selection.mjs +19 -0
- package/scripts/render-agenda-multilevel.mjs +0 -5
- package/scripts/render-multilevel-cases.mjs +0 -1
- package/scripts/run-tests.mjs +107 -35
- package/scripts/word-com-corpus-suite.ps1 +3 -0
- package/scripts/word-com-differential.ps1 +64 -4
- package/scripts/word-com-suite.ps1 +3 -0
- package/services/batch-operation-orchestrator.js +494 -0
- package/services/capture-engine.js +226 -0
- package/services/comment-builders.js +23 -6
- package/services/comment-engine.js +108 -47
- package/services/comment-locator.js +187 -82
- package/services/comment-replies.js +95 -0
- package/services/document-inspection.js +258 -0
- package/services/document-operation-applier.js +372 -0
- package/services/document-operation-contract.js +323 -0
- package/services/document-operation-mutations.js +1733 -0
- package/services/document-operation-session.js +258 -0
- package/services/numbering-service.js +14 -5
- package/services/operation-heuristics.js +173 -0
- package/services/operation-preflight.js +366 -0
- package/services/receipt-collector.js +288 -0
- package/services/revision-comment-management.js +37 -5
- package/services/revision-token.js +290 -0
- package/services/standalone-docx-plumbing.js +123 -8
- package/services/standalone-operation-runner.d.ts +296 -0
- package/services/standalone-operation-runner.js +10 -1455
- package/services/table-reconciliation.js +15 -6
- package/docs/VALIDATION.md +0 -183
- package/docs/WORD-MANUAL-REVIEW.md +0 -138
- package/docs/plans/2026-09-01-performance-and-complexity-reduction.md +0 -210
- /package/docs/plans/{2026-08-30-reliability-testing-improvements.md → completed/2026-08-30-reliability-testing-improvements.md} +0 -0
package/ARCHITECTURE.md
CHANGED
|
@@ -12,6 +12,7 @@ This repository contains only the publishable package surface:
|
|
|
12
12
|
- `pipeline/`
|
|
13
13
|
- `services/`
|
|
14
14
|
- `orchestration/`
|
|
15
|
+
- `node/` (separate Node-only package facade)
|
|
15
16
|
- `index.js`
|
|
16
17
|
- `index.d.ts`
|
|
17
18
|
- `dist/`
|
|
@@ -35,6 +36,7 @@ No Word add-in entrypoints or host-specific integration layers are part of this
|
|
|
35
36
|
│ ├── logger.js
|
|
36
37
|
│ └── xml-adapter.js
|
|
37
38
|
├── core/
|
|
39
|
+
│ ├── paragraph-text.js
|
|
38
40
|
│ └── word-xml.js
|
|
39
41
|
├── engine/
|
|
40
42
|
│ ├── oxml-engine.js
|
|
@@ -48,8 +50,19 @@ No Word add-in entrypoints or host-specific integration layers are part of this
|
|
|
48
50
|
│ ├── comment-engine.js
|
|
49
51
|
│ ├── numbering-helpers.js
|
|
50
52
|
│ ├── revision-comment-management.js
|
|
53
|
+
│ ├── document-inspection.js
|
|
54
|
+
│ ├── document-operation-session.js
|
|
55
|
+
│ ├── document-operation-applier.js
|
|
56
|
+
│ ├── document-operation-mutations.js
|
|
57
|
+
│ ├── batch-operation-orchestrator.js
|
|
58
|
+
│ ├── operation-heuristics.js
|
|
51
59
|
│ ├── standalone-docx-plumbing.js
|
|
52
60
|
│ └── standalone-operation-runner.js
|
|
61
|
+
├── node/
|
|
62
|
+
│ ├── docx-document.js
|
|
63
|
+
│ ├── cli.js
|
|
64
|
+
│ ├── zip-archive.js
|
|
65
|
+
│ └── index.js
|
|
53
66
|
├── index.js
|
|
54
67
|
└── index.d.ts
|
|
55
68
|
```
|
|
@@ -72,16 +85,36 @@ No Word add-in entrypoints or host-specific integration layers are part of this
|
|
|
72
85
|
- Namespace-safe Word element creation, tracked-change detection, and OOXML payload source-shape helpers.
|
|
73
86
|
- `core/types.js`
|
|
74
87
|
- Shared model enums/types plus revision metadata generation and document-aware revision ID seeding.
|
|
88
|
+
- `core/paragraph-text.js`
|
|
89
|
+
- Canonical accepted/rejected/current-view text shared by targeting,
|
|
90
|
+
ingestion, and inspection.
|
|
91
|
+
- `core/paragraph-targeting.js`
|
|
92
|
+
- Target descriptors and session-scoped paragraph metadata indexes. The
|
|
93
|
+
index groups IDs and normalized text while retaining canonical text,
|
|
94
|
+
fingerprints, document order, and table context for deterministic reuse.
|
|
75
95
|
- `core/redline-validation.js`
|
|
76
96
|
- Runtime structural validation (`validateRedlineOoxml`) mirroring the test-suite invariants: no nested revisions, `w:delText` inside `w:del`, complete revision metadata, unique revision ids, preserved boundary whitespace.
|
|
77
97
|
- `engine/oxml-engine.js`
|
|
78
98
|
- Main reconciliation router, mode selection, existing-revision policy gate, and status/error result handling.
|
|
99
|
+
- `engine/route-selection.js`
|
|
100
|
+
- Internal reconciliation capability matrix and opt-in diagnostic route
|
|
101
|
+
instrumentation. It observes policy; it does not expose a route override.
|
|
79
102
|
- `engine/run-builders.js`
|
|
80
103
|
- Shared builders for insertion/deletion wrappers, paragraph-mark revisions, visible run content, and run-property changes.
|
|
81
104
|
- `engine/surgical-*.js`
|
|
82
105
|
- Surgical run splitting, diff application, and span helpers for localized edits that preserve surrounding markup.
|
|
83
106
|
- `engine/formatting-removal.js`
|
|
84
107
|
- Shared formatting removal and highlight helpers.
|
|
108
|
+
- `pipeline/list-markers.js`
|
|
109
|
+
- Dependency-light canonical list-marker grammar, classification, numbering
|
|
110
|
+
vocabulary, and parsed list-item representation.
|
|
111
|
+
- `pipeline/list-generation.js`
|
|
112
|
+
- Structural paragraph-to-list generation, paragraph-mark revisions, and
|
|
113
|
+
selective inheritance of source typography for inserted list runs.
|
|
114
|
+
- `pipeline/structured-content.js`
|
|
115
|
+
- Strict decomposition and planning for atomic mixed heading/paragraph/list/
|
|
116
|
+
table replacements. It rejects ambiguous table-like pipe text rather than
|
|
117
|
+
allowing a fallback to literal paragraphs.
|
|
85
118
|
- `pipeline/*`
|
|
86
119
|
- Ingestion, markdown preprocessing, diffing, patching, and serialization stages. Ingestion treats deleted and moved-from content as non-visible text and inserted/moved-to content as visible text.
|
|
87
120
|
- `services/comment-engine.js`
|
|
@@ -93,7 +126,42 @@ No Word add-in entrypoints or host-specific integration layers are part of this
|
|
|
93
126
|
- `services/revision-comment-management.js`
|
|
94
127
|
- OOXML transforms for accepting/rejecting insertion, deletion, move, paragraph-mark, and property-change revisions by author/all-authors, plus deleting comments by author/all-authors.
|
|
95
128
|
- `services/standalone-operation-runner.js`
|
|
96
|
-
-
|
|
129
|
+
- Stable compatibility facade for full-document operations. It only re-exports
|
|
130
|
+
preflight, single-operation application, batch application, and scheduling.
|
|
131
|
+
- `services/document-operation-applier.js`
|
|
132
|
+
- Canonical single-operation validation, author resolution, dispatch, and
|
|
133
|
+
result metadata assembly.
|
|
134
|
+
- `services/document-operation-mutations.js`
|
|
135
|
+
- Coupled OOXML mutation implementations for redline, highlight, and comment
|
|
136
|
+
operations. These use leaf-module imports and never import the root entry.
|
|
137
|
+
- `services/batch-operation-orchestrator.js`
|
|
138
|
+
- Comment-first stable scheduling, atomic policy, artifact aggregation,
|
|
139
|
+
per-operation results, one final document serialization, and deferred
|
|
140
|
+
runtime-context commit.
|
|
141
|
+
- `services/document-operation-session.js`
|
|
142
|
+
- One live document DOM and revision allocator per invocation, immutable
|
|
143
|
+
start-of-batch target snapshot, lazy paragraph metadata, per-operation DOM
|
|
144
|
+
and allocator savepoints, exact original XML rollback, index invalidation,
|
|
145
|
+
artifact/result accumulation, and isolated runtime-context helpers.
|
|
146
|
+
- `services/operation-heuristics.js`
|
|
147
|
+
- DOM-light decisions for list/plain adjacency insertion and explicit-range
|
|
148
|
+
list insertion. Canonical list/table targeting remains in `core/*`.
|
|
149
|
+
- `services/document-operation-contract.js`
|
|
150
|
+
- Compatibility normalization, canonical operation kinds, author precedence,
|
|
151
|
+
and stable runtime validation for document operations.
|
|
152
|
+
- `services/operation-preflight.js`
|
|
153
|
+
- Read-only strict target and anchor resolution, revision-policy diagnostics,
|
|
154
|
+
artifact prediction, and same-paragraph conflict reporting.
|
|
155
|
+
- `services/document-inspection.js`
|
|
156
|
+
- Read-only paragraphs/comments inventory with target identity, headings,
|
|
157
|
+
revision authors, table context, and advisory visible numbering.
|
|
158
|
+
- `node/docx-document.js`
|
|
159
|
+
- Transactional whole-DOCX editing, artifact wiring, validation, and rollback.
|
|
160
|
+
This surface is excluded from the browser/root dependency graph.
|
|
161
|
+
- `node/cli.js` and `bin/docx-redline.js`
|
|
162
|
+
- Cross-platform, JSON-only agent command boundary. Read commands never
|
|
163
|
+
mutate; write commands require attribution, use package transactions, and
|
|
164
|
+
only overwrite source files under explicit `--in-place` authorization.
|
|
97
165
|
- `orchestration/*`
|
|
98
166
|
- Route planning and list fallback orchestration utilities.
|
|
99
167
|
|
|
@@ -102,15 +170,24 @@ No Word add-in entrypoints or host-specific integration layers are part of this
|
|
|
102
170
|
1. Caller imports from `index.js`.
|
|
103
171
|
2. Caller configures XML provider/logger/defaults when needed via `adapters/*`.
|
|
104
172
|
3. Caller invokes reconciliation APIs (`applyRedlineToOxml`, operation runner, ingestion/export helpers).
|
|
105
|
-
4.
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
173
|
+
4. A full-document batch parses once, captures its initial target snapshot, and
|
|
174
|
+
creates an operation savepoint before each mutation.
|
|
175
|
+
5. `engine/oxml-engine.js` routes each selected scope to format, table, list,
|
|
176
|
+
surgical, or reconstruction flows; successful scoped output is imported
|
|
177
|
+
into the live document.
|
|
178
|
+
6. Failed and no-op operations restore their savepoint. A successful changed
|
|
179
|
+
batch serializes the full document once; atomic failures and all-no-op
|
|
180
|
+
batches return the exact input string without serialization.
|
|
181
|
+
7. Pipeline/services return OOXML, optional package artifacts (`numberingXml`, comments payloads), and non-breaking `status`/`error` fields where applicable.
|
|
182
|
+
8. Optional revision/comment management transforms can accept/reject revisions, including move revisions, or delete comments by author.
|
|
183
|
+
9. Caller writes resulting XML back to package/document boundaries.
|
|
109
184
|
|
|
110
185
|
## Public Surfaces
|
|
111
186
|
|
|
112
187
|
- Primary: `index.js`
|
|
113
188
|
- Types: `index.d.ts`
|
|
189
|
+
- Stable XML operation runner: `@ansonlai/docx-redline-js/standalone-runner`
|
|
190
|
+
- Node-only DOCX facade: `@ansonlai/docx-redline-js/node`
|
|
114
191
|
|
|
115
192
|
Keep public exports centralized through `index.js`; deep imports are supported by
|
|
116
193
|
the package `exports` map for advanced consumers, but new public APIs should
|
|
@@ -125,14 +202,138 @@ still be re-exported from `index.js`.
|
|
|
125
202
|
`w:id`, `w:author`, and `w:date` stay consistent and document-unique.
|
|
126
203
|
- Seed revision IDs from parsed input with `seedRevisionIdsFromDocument(xmlDoc)`
|
|
127
204
|
before emitting new tracked changes.
|
|
128
|
-
-
|
|
129
|
-
|
|
205
|
+
- Treat revision metadata inside cloned content as identity-bearing state, not
|
|
206
|
+
ordinary formatting. When a run containing `w:rPrChange` is split or cloned,
|
|
207
|
+
preserve an existing revision ID on at most one output run and allocate a
|
|
208
|
+
fresh document-scoped ID for every additional copy.
|
|
209
|
+
- Use `containsTrackedChanges(xmlDoc)` and `getTrackedChangeAuthors(xmlDoc)`
|
|
210
|
+
to inspect existing revisions. By default (`existingRevisions: 'merge-same-author'`),
|
|
211
|
+
subsequent edits from the same author are merged against the pre-revision baseline
|
|
212
|
+
while revisions from different authors fail closed with `EXISTING_REVISIONS`.
|
|
213
|
+
Revised paragraphs containing comment anchors fail closed with
|
|
214
|
+
`COMMENTED_CONTENT_MERGE`; never discard anchors as a side effect of restoring
|
|
215
|
+
the pre-revision baseline.
|
|
216
|
+
Pass `existingRevisions: 'accept-all-first'` to normalize prior revisions explicitly.
|
|
130
217
|
- Do not write unknown `result.oxml` payloads directly into `word/document.xml`;
|
|
131
218
|
normalize with `extractReplacementNodesFromOoxml(...)` or use
|
|
132
219
|
`applyOperationToDocumentXml(...).documentXml` for full-document replacement.
|
|
133
220
|
- Run `validateRedlineOoxml(oxml)` on generated output before packaging it;
|
|
134
221
|
it reports structural invariant violations as `{ valid, issues }`.
|
|
135
222
|
|
|
223
|
+
## Integration Contracts
|
|
224
|
+
|
|
225
|
+
### Targeting and text fidelity
|
|
226
|
+
|
|
227
|
+
- Paragraph targeting and replacement have different contracts. Targeting may
|
|
228
|
+
use normalized text and fallback heuristics; replacement content is literal
|
|
229
|
+
and must preserve tabs, line breaks, non-breaking spaces, repeated spaces,
|
|
230
|
+
and boundary whitespace.
|
|
231
|
+
- Text extraction used for targeting represents the visible accepted view of
|
|
232
|
+
tracked content: insertions are visible and deletions are excluded.
|
|
233
|
+
- Paragraph indexes are transient integration references, not user-facing
|
|
234
|
+
document identifiers. Prefer paragraph IDs plus exact text where available.
|
|
235
|
+
- Ambiguous matches are unsafe for document mutation. New targeting surfaces
|
|
236
|
+
should report candidate matches or `AMBIGUOUS_TARGET` rather than silently
|
|
237
|
+
choosing the first paragraph.
|
|
238
|
+
- Do not remove operation-session savepoints merely to improve throughput.
|
|
239
|
+
Any replacement must prove that a thrown error or false no-op cannot leak a
|
|
240
|
+
partial DOM mutation or revision-ID allocation into later operations.
|
|
241
|
+
|
|
242
|
+
### Structural paragraph-to-list replacement
|
|
243
|
+
|
|
244
|
+
- In WordprocessingML, `w:numId w:val="0"` suppresses numbering. It represents
|
|
245
|
+
no reusable list context and must never be returned by numbering allocation
|
|
246
|
+
or assigned to a generated list item. Generated lists use a positive `numId`
|
|
247
|
+
bound to a compatible `w:abstractNum` definition.
|
|
248
|
+
- Expanding one non-list paragraph into multiple list paragraphs is a block
|
|
249
|
+
replacement, not an inline replacement. The original content remains in its
|
|
250
|
+
own paragraph with a deleted paragraph mark; every replacement item occupies
|
|
251
|
+
its own paragraph with an inserted paragraph mark and inserted text. This is
|
|
252
|
+
required so Word can accept the edit as the new paragraphs or reject it as
|
|
253
|
+
the exact original paragraph without joining the old heading to item one.
|
|
254
|
+
- Inserted list runs selectively inherit source typography (`w:rFonts`, size,
|
|
255
|
+
language, and related script properties). Semantic emphasis such as bold,
|
|
256
|
+
underline, italic, or strike is emitted only when requested by the replacement
|
|
257
|
+
markup; heading emphasis must not leak into ordinary list body text.
|
|
258
|
+
- Low-level list output can carry a package-fragment sentinel needed by its
|
|
259
|
+
standalone payload shape. Full-document mutation removes that sentinel while
|
|
260
|
+
importing replacement nodes, so it cannot become an empty document paragraph.
|
|
261
|
+
- Tests for this route must verify positive numbering IDs, separate physical
|
|
262
|
+
paragraphs, formatting inheritance/non-inheritance, valid revision markup,
|
|
263
|
+
and exact accepted and rejected paragraph sequences.
|
|
264
|
+
|
|
265
|
+
### Atomic mixed-content replacement
|
|
266
|
+
|
|
267
|
+
- `planStructuredReplacement(...)` converts agent-authored Markdown into one
|
|
268
|
+
replacement operation carrying `structuredContent: true`. The block plan is
|
|
269
|
+
diagnostic metadata; execution remains one mutation so replacing the anchor
|
|
270
|
+
cannot invalidate later blocks.
|
|
271
|
+
- Mixed-content parsing recognizes explicit Markdown headings, blank-line
|
|
272
|
+
paragraph boundaries, adjacent list items, and contiguous table rows. Tables
|
|
273
|
+
require a header separator and consistent column counts. Invalid input fails
|
|
274
|
+
with `STRUCTURED_CONTENT_INVALID`; silently degrading table pipes into visible
|
|
275
|
+
paragraph text is forbidden on this route.
|
|
276
|
+
- Newly inserted tables inside a mixed replacement are tracked once at block
|
|
277
|
+
scope. Cell runs are not nested in additional `w:ins` wrappers, preserving the
|
|
278
|
+
no-nested-revisions invariant while allowing Reject All to remove the table.
|
|
279
|
+
- Agents must use explicit heading markers and valid table grammar rather than
|
|
280
|
+
relying on capitalization or layout inference. The engine preserves the
|
|
281
|
+
declared block types and does not guess legal-document semantics.
|
|
282
|
+
|
|
283
|
+
### Package artifacts and transactions
|
|
284
|
+
|
|
285
|
+
- A real `.docx` stores document markup, comments, numbering, relationships,
|
|
286
|
+
and content types in separate parts. APIs operating on one XML string cannot
|
|
287
|
+
claim to update artifacts held in another part.
|
|
288
|
+
- Comment IDs must be allocated against both document anchors and the existing
|
|
289
|
+
`word/comments.xml` part. Revision IDs must be allocated against the complete
|
|
290
|
+
document revision scope.
|
|
291
|
+
- Numbering payloads must be merged with `mergeNumberingXmlBySchemaOrder` when
|
|
292
|
+
a package already contains numbering definitions; replacement is not a merge.
|
|
293
|
+
- Safe package mutation is transactional: retain the original package, apply
|
|
294
|
+
operations, merge all artifacts, validate redline markup and package wiring,
|
|
295
|
+
and commit only if every required check succeeds.
|
|
296
|
+
- `openDocx(buffer)` implements this transaction for Node without adding a ZIP
|
|
297
|
+
dependency to browser or XML-only consumers. Unmodified part contents remain
|
|
298
|
+
byte-identical after extraction, although the ZIP container is reserialized.
|
|
299
|
+
|
|
300
|
+
### Operation results
|
|
301
|
+
|
|
302
|
+
- `hasChanges: false` does not imply success. Callers must check `status`,
|
|
303
|
+
`error`, and warnings to distinguish errors, missing anchors, and true no-ops.
|
|
304
|
+
- Batch results must preserve the caller's original operation indexes even when
|
|
305
|
+
execution is reordered for stable anchors.
|
|
306
|
+
- Author attribution is externally visible document data. Agent-facing APIs
|
|
307
|
+
should require an explicit author and report the author used for every
|
|
308
|
+
operation rather than relying silently on a configured fallback.
|
|
309
|
+
- Operation-level authors override the batch author. Runtime results expose
|
|
310
|
+
`authorUsed`, `authorsUsed`, `operationType`, `resolvedBy`, and resolved target
|
|
311
|
+
metadata so integrations can audit what the engine actually selected.
|
|
312
|
+
- `preflightOperations` is the read-only safety boundary for agent-generated
|
|
313
|
+
batches. It uses strict targeting by default; mutation APIs retain permissive
|
|
314
|
+
legacy targeting unless `strictTargets: true` is requested. In v1.0.0,
|
|
315
|
+
application will default to strict targeting; in the current warning cycle,
|
|
316
|
+
permissive resolution that chooses among multiple identical paragraphs emits
|
|
317
|
+
`AMBIGUOUS_TARGET_HEURISTIC_USED` with candidate count and migration guidance.
|
|
318
|
+
Both preflight and mutation runners share the same candidate resolver
|
|
319
|
+
(`resolveTargetParagraph`).
|
|
320
|
+
|
|
321
|
+
### Mutation receipts and output reconciliation oracle
|
|
322
|
+
|
|
323
|
+
- `ReceiptCollector` tracks exact allocations (revision IDs with kind and target part,
|
|
324
|
+
comment IDs, numbering IDs, relationship IDs, affected targets, and warnings)
|
|
325
|
+
directly at the point of allocation/attachment during operation execution.
|
|
326
|
+
- Collector state is snapshotted within operation savepoints. Failed or rolled-back
|
|
327
|
+
operations cleanly restore prior collector state without leaking orphaned allocations.
|
|
328
|
+
- Single operations expose `result.receipt`; batches expose per-item `results[i].receipt`
|
|
329
|
+
and top-level `result.receipts`, with dispositions (`applied`, `refused`, `no_change`,
|
|
330
|
+
`rolled_back`, `not_attempted`) and `committed: true/false`.
|
|
331
|
+
- The output reconciliation oracle (`reconcileReceiptsAgainstOutput`) performs an
|
|
332
|
+
independent, non-negotiable verification: every durable ID reported as committed
|
|
333
|
+
is parsed from the serialized output XML parts (`word/document.xml`, `word/comments.xml`,
|
|
334
|
+
`word/numbering.xml`). Any discrepancy immediately fails the transaction and triggers
|
|
335
|
+
atomic rollback.
|
|
336
|
+
|
|
136
337
|
|
|
137
338
|
## Build Output
|
|
138
339
|
|
|
@@ -148,7 +349,12 @@ The bundle inlines `diff-match-patch` and keeps `@xmldom/xmldom` external.
|
|
|
148
349
|
## Testing
|
|
149
350
|
|
|
150
351
|
- `npm test`
|
|
151
|
-
- Runs
|
|
352
|
+
- Runs all `tests/*.mjs` except setup helpers in separate Node processes with
|
|
353
|
+
a conservative four-worker cap. Use `DOCX_TEST_CONCURRENCY=1` to reproduce
|
|
354
|
+
the same sorted suite serially.
|
|
355
|
+
- `npm run benchmark:tests`
|
|
356
|
+
- Compares paired serial and bounded-parallel suite runs and records JSON
|
|
357
|
+
under ignored `tmp/benchmarks/`.
|
|
152
358
|
- `npm run test:isolation`
|
|
153
359
|
- Runs boundary checks for Word API markers and dependency-graph isolation.
|
|
154
360
|
- `npm run check:types`
|
|
@@ -170,7 +376,7 @@ The bundle inlines `diff-match-patch` and keeps `@xmldom/xmldom` external.
|
|
|
170
376
|
- Nightly independent-oracle validation: XSD schema check, LibreOffice
|
|
171
377
|
conversion, and an extended 20k-case fuzz sweep with a fresh seed.
|
|
172
378
|
|
|
173
|
-
Use these checks before publishing or tagging. See
|
|
379
|
+
Use these checks before publishing or tagging. See [docs/TESTING.md](./docs/TESTING.md#release-validation-and-independent-oracles).
|
|
174
380
|
|
|
175
381
|
## Fast Orientation For Contributors
|
|
176
382
|
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
### ⚠️ Breaking changes
|
|
6
|
+
|
|
7
|
+
The following changes can require caller or contributor updates. No public
|
|
8
|
+
export or valid existing function signature was removed.
|
|
9
|
+
|
|
10
|
+
#### Runtime and result-contract changes
|
|
11
|
+
|
|
12
|
+
- **Canonical paragraph text:** `getParagraphText(...)` now returns the
|
|
13
|
+
accepted/current view instead of the earlier simplified `w:t`/`w:tab`
|
|
14
|
+
concatenation. It excludes deleted and `w:moveFrom` content and includes
|
|
15
|
+
structural breaks, soft hyphens, and non-breaking hyphens.
|
|
16
|
+
**Migration:** regenerate compared/cached text with the upgraded library. Use
|
|
17
|
+
`extractCanonicalParagraphText(...)` when accepted/rejected-view semantics
|
|
18
|
+
are intended; integrations that require the former raw traversal must retain
|
|
19
|
+
their own legacy extractor before upgrading.
|
|
20
|
+
- **Paragraph fingerprints:** fingerprints now incorporate canonical paragraph
|
|
21
|
+
text. Stored fingerprints can become stale for paragraphs containing
|
|
22
|
+
revisions, moves, breaks, soft hyphens, or non-breaking hyphens.
|
|
23
|
+
**Migration:** do not carry fingerprints across this upgrade; re-extract the
|
|
24
|
+
document and regenerate target descriptors.
|
|
25
|
+
- **Invalid operations:** malformed or field-incompatible document-operation
|
|
26
|
+
objects now return a structured `INVALID_OPERATION` error at the runner
|
|
27
|
+
boundary instead of reaching later failure/no-op paths.
|
|
28
|
+
**Migration:** validate operation files against the published schema and
|
|
29
|
+
handle `status === 'error'` plus `error.code === 'INVALID_OPERATION'`.
|
|
30
|
+
- **Commented paragraph deletion:** deleting a complete paragraph that contains
|
|
31
|
+
an existing comment now fails with `COMMENTED_CONTENT_DELETE` instead of
|
|
32
|
+
producing OOXML with dangling comment references.
|
|
33
|
+
**Migration:** preserve or deliberately remove/relocate the comment before
|
|
34
|
+
deleting the paragraph, and handle the structured error. Atomic callers keep
|
|
35
|
+
the original document unchanged.
|
|
36
|
+
- **Comment anchor failures:** missing or ambiguous comment anchors now return
|
|
37
|
+
`ANCHOR_NOT_FOUND` or `AMBIGUOUS_ANCHOR` and fail/roll back an atomic batch;
|
|
38
|
+
they are no longer reported as successful `no_change` operations.
|
|
39
|
+
**Migration:** treat these codes as failed operations and use a unique exact
|
|
40
|
+
anchor or stricter target descriptor before retrying.
|
|
41
|
+
- **Stricter package validation:** DOCX package validation now rejects
|
|
42
|
+
unbalanced comment ranges, dangling references/usages, orphan definitions,
|
|
43
|
+
and duplicate comment-definition IDs that earlier validation could allow.
|
|
44
|
+
**Migration:** repair the comment anchors and `word/comments.xml` definitions
|
|
45
|
+
before applying or validating further changes.
|
|
46
|
+
|
|
47
|
+
#### Development workflow change
|
|
48
|
+
|
|
49
|
+
- **Parallel tests by default:** `npm test` now runs up to four isolated child
|
|
50
|
+
processes concurrently. This does not change the published runtime API, but
|
|
51
|
+
contributor automation that depends on test execution order or shared files
|
|
52
|
+
must be updated. **Migration:** make tests independent or set
|
|
53
|
+
`DOCX_TEST_CONCURRENCY=1` for the previous serial scheduling behavior.
|
|
54
|
+
|
|
55
|
+
Strict targeting remains opt-in on existing low-level mutation APIs; it is the
|
|
56
|
+
default only on the newly added Node facade and CLI.
|
|
57
|
+
|
|
58
|
+
### Deprecations and future breaking changes
|
|
59
|
+
|
|
60
|
+
- Replacing an existing numbering part without a merge callback now emits a
|
|
61
|
+
deprecation warning. The Node facade and CLI already merge safely by default.
|
|
62
|
+
**This remains supported in this release but will become an error in the next
|
|
63
|
+
major version.** Migrate low-level callers to
|
|
64
|
+
`mergeNumberingXmlBySchemaOrder` before that release.
|
|
65
|
+
- **Permissive target resolution deprecation (`AMBIGUOUS_TARGET_HEURISTIC_USED`):**
|
|
66
|
+
Lower-level document operation runners currently default to permissive targeting.
|
|
67
|
+
In v1.0.0, application will default to `strictTargets: true`. In this release,
|
|
68
|
+
when permissive resolution encounters multiple identical candidate paragraphs and
|
|
69
|
+
heuristically chooses the first candidate, it emits an `AMBIGUOUS_TARGET_HEURISTIC_USED`
|
|
70
|
+
warning with candidate count and migration guidance.
|
|
71
|
+
**Migration:** Disambiguate operations using `paragraphId`, `index`, `occurrence`,
|
|
72
|
+
or `fingerprint` and pass `{ strictTargets: true }`.
|
|
73
|
+
|
|
74
|
+
### ℹ️ Noteworthy Default & Usability Changes (Non-breaking)
|
|
75
|
+
|
|
76
|
+
The following improvements update default behaviors to maximize agent speed, reduce friction, and eliminate unnecessary errors during iterative editing. These changes are **not technically breaking changes** (no public APIs or exports were removed, and all existing options remain configurable), but represent important behavioral refinements that callers should note:
|
|
77
|
+
|
|
78
|
+
- **Fallback Author Default (`'AI Redliner'`):** `setDefaultAuthor`, `node/cli.js`, and `openDocx` now default to `'AI Redliner'` (configurable via the `DOCX_REDLINE_AUTHOR` environment variable or `--author`). The CLI `apply` command and core APIs no longer error with `AUTHOR_REQUIRED` when operations omit an author.
|
|
79
|
+
- **Output Overwrite by Default:** Destination files provided via `--output` now overwrite by default instead of failing with `OUTPUT_EXISTS`. Callers wanting protection against accidental overwrites can pass `--no-overwrite` or `--no-clobber`. The source document remains protected and is never overwritten unless `--in-place` is explicitly passed.
|
|
80
|
+
- **Replacement Event Pairing (`pairReplacements: true` by default):** Adjacent `<w:del>` and `<w:ins>` revisions now default to sharing linked revision metadata and identical timestamps so Microsoft Word groups them as a single replacement in the Reviewing Pane. Pass `pairReplacements: false` for independent revision timestamps.
|
|
81
|
+
- **Structured Content Auto-Detection (`structuredContent: true` by default):** Markdown tables, headings (`#`), and lists in replacement text automatically render as native Word elements (`w:tbl`, `w:pStyle`, `w:numPr`). Single outline-numbered legal clauses (e.g. `13.2.1.1`) continue to be treated as ordinary paragraphs without spurious list conversion. Pass `structuredContent: false` to treat replacement text strictly as plain text.
|
|
82
|
+
- **Progressive Batch Mode (`atomic: false` default, `atomic: true` opt-in):** Batch operations and CLI `apply` now apply edits progressively by default (`atomic: false`): valid edits commit directly, while failing edits report structured errors in `results` for faster debugging. Pass `{ atomic: true }` (or `--atomic` on the CLI) for all-or-nothing rollback when any operation fails.
|
|
83
|
+
- **Clean Direct Edits (`generateRedlines: false` / `--no-redlines`):** Prominently documented that tracked redlines are not always the preferred method. Callers can pass `generateRedlines: false` (or `--no-redlines` on the CLI) for clean execution drafts, document restructuring, or minor typo fixes without tracked changes markup.
|
|
84
|
+
- **Existing Revisions Policy (`existingRevisions: 'merge-same-author'` by default):** When editing a paragraph that already contains tracked changes from the same author, prior revisions by that author are merged against the pre-revision baseline (prior changes by that author are reverted and re-diffed to the new modified text), avoiding revision accumulation and nested markup. If a paragraph contains tracked changes from another reviewer, the operation fails closed with `EXISTING_REVISIONS` to protect third-party review marks. Commented revision content fails closed with `COMMENTED_CONTENT_MERGE` so comment anchors cannot be removed or orphaned. Callers can explicitly pass `'accept-all-first'` to normalize prior revisions or `'reject-input'` to refuse editing any revised paragraph.
|
|
85
|
+
- **Inline One-Liner CLI Edits:** Added `--target <text>` with `--modified <text>` or `--comment <text>` on `docx-redline apply` for fast 1–2 edit workflows without creating a JSON operations file.
|
|
86
|
+
|
|
87
|
+
### Added
|
|
88
|
+
|
|
89
|
+
- Added **Mutation Receipts** (`receipt` on `DocumentOperationResult` and `receipts`
|
|
90
|
+
on `BatchOperationResult`). Every operation execution returns structured,
|
|
91
|
+
commit-aware telemetry capturing durable revision IDs (with kind and target part),
|
|
92
|
+
comment IDs, numbering IDs, relationship IDs, affected targets, and warnings.
|
|
93
|
+
Supports `not_attempted`, `applied`, `refused`, `no_change`, and `rolled_back`
|
|
94
|
+
dispositions.
|
|
95
|
+
- Added **Commit-Aware Output Reconciliation Oracle** (`reconcileReceiptsAgainstOutput`).
|
|
96
|
+
Before completing any transaction, reported durable IDs are checked against a
|
|
97
|
+
fresh parse of the generated output OOXML parts. Any reconciliation discrepancy
|
|
98
|
+
immediately fails the transaction and triggers atomic rollback.
|
|
99
|
+
- Exported receipt primitives: `ReceiptCollector`, `createEmptyReceipt`, and
|
|
100
|
+
`reconcileReceiptsAgainstOutput` along with `MutationReceipt` and
|
|
101
|
+
`MutationReceiptRevisionItem` TypeScript declarations.
|
|
102
|
+
- Added **Paragraph Mark Revisions** (`w:pPrChange`, `markParagraphMarkInserted`,
|
|
103
|
+
`markParagraphMarkDeleted`) ensuring whole-paragraph deletions and insertions
|
|
104
|
+
cleanly track paragraph mark lifecycles for full Accept All / Reject All symmetry.
|
|
105
|
+
- Added **Paragraph Boundary Mutation Validation** (`validateParagraphBoundaryMutation`)
|
|
106
|
+
guarding against invalid cross-paragraph boundary merges.
|
|
107
|
+
|
|
108
|
+
- Added `analyzeStructuredContent(...)` and `planStructuredReplacement(...)`
|
|
109
|
+
for agent-authored attachments and schedules containing mixed headings,
|
|
110
|
+
paragraphs, lists, and tables. The planner returns typed blocks and produces
|
|
111
|
+
one atomic `structuredContent` operation only when the Markdown is valid.
|
|
112
|
+
|
|
113
|
+
- Added session-scoped paragraph metadata indexing for canonical text,
|
|
114
|
+
normalized text, paragraph IDs, fingerprints, table context, and document
|
|
115
|
+
indexes, plus deterministic targeting and route-profiling benchmarks.
|
|
116
|
+
- Added a shared list-marker grammar and parsed list-item vocabulary used by
|
|
117
|
+
pipeline analysis, orchestration, normalization, and list targeting.
|
|
118
|
+
- Added an internal reconciliation capability matrix and opt-in route
|
|
119
|
+
instrumentation. Public reconciliation result shapes and route selection
|
|
120
|
+
policy remain unchanged.
|
|
121
|
+
|
|
122
|
+
- Added `scripts/extract_text.mjs` and `scripts/apply_changes.mjs` as thin
|
|
123
|
+
compatibility entrypoints for legacy skill installations. They delegate to
|
|
124
|
+
the supported CLI, retain strict atomic validated writes, and accept legacy
|
|
125
|
+
operation files with a top-level `changes` array.
|
|
126
|
+
- Added typed operations, per-operation authors, strict target descriptors,
|
|
127
|
+
deterministic preflight diagnostics, and auditable resolution metadata.
|
|
128
|
+
- Added `inspectDocumentParts(...)`, a structured document inventory using the
|
|
129
|
+
same canonical text extractor as targeting and ingestion.
|
|
130
|
+
- Added `@ansonlai/docx-redline-js/node`. `openDocx(...)` applies batches to
|
|
131
|
+
complete DOCX buffers transactionally and validates before commit.
|
|
132
|
+
- Added the cross-platform `docx-redline` CLI with JSON `inspect`, `extract`,
|
|
133
|
+
`preflight`, `apply`, `accept`, `reject`, `delete-comments`, and `validate`
|
|
134
|
+
commands, plus a published operation-file JSON Schema.
|
|
135
|
+
|
|
136
|
+
### Behavior and reliability
|
|
137
|
+
|
|
138
|
+
- Explicit structured replacements now reject missing Markdown table separator
|
|
139
|
+
- Generated Markdown tables repeat their header row and prevent logical data rows from splitting across pages.
|
|
140
|
+
rows, missing data rows, and inconsistent column counts with
|
|
141
|
+
`STRUCTURED_CONTENT_INVALID` instead of inserting literal pipe-delimited text.
|
|
142
|
+
- Tables created inside mixed replacements are tracked once at block scope,
|
|
143
|
+
avoiding nested revisions while keeping Accept All and Reject All symmetric.
|
|
144
|
+
|
|
145
|
+
- Target preflight and live mutation reuse one document-scoped paragraph index;
|
|
146
|
+
strict duplicate detection and resolution metadata retain their prior
|
|
147
|
+
semantics while avoiding repeated whole-document text traversal.
|
|
148
|
+
- Revision-ID seeding now walks the DOM with child/sibling pointers instead of
|
|
149
|
+
allocating an array containing every element.
|
|
150
|
+
- Single-source-paragraph list expansion uses the focused list generator
|
|
151
|
+
directly. Multi-paragraph marked-list edits deliberately retain the legacy
|
|
152
|
+
run-aware reconciliation pipeline for structural parity.
|
|
153
|
+
- Fixed paragraph-to-list expansion when a manually numbered heading carries
|
|
154
|
+
`w:numId w:val="0"`. Numbering suppression is no longer reused as a generated
|
|
155
|
+
list ID, so inserted bullet and numbered items receive valid positive IDs.
|
|
156
|
+
- Tracked heading-to-list replacements now keep the deleted source heading in
|
|
157
|
+
its own paragraph and track the paragraph marks of every inserted list item.
|
|
158
|
+
This prevents deleted heading text from joining the first item and preserves
|
|
159
|
+
exact Accept/Reject structure without adding a full-document sentinel
|
|
160
|
+
paragraph.
|
|
161
|
+
- Inserted list items now inherit source font family, size, language, and
|
|
162
|
+
related script typography without inheriting heading-only bold, underline,
|
|
163
|
+
italic, or strike formatting unless requested by the replacement markdown.
|
|
164
|
+
- Canonical-only table-cell targeting now consumes the shared paragraph-text
|
|
165
|
+
extractor, while offset- and sentinel-producing walkers remain specialized.
|
|
166
|
+
Their accepted visible projections now agree on soft hyphens as well as tabs,
|
|
167
|
+
breaks, hyperlinks, and non-breaking hyphens.
|
|
168
|
+
|
|
169
|
+
- Comment preflight and application now share one anchor resolver. Exact
|
|
170
|
+
matches take priority, unique ordinary-space/NBSP differences preserve raw
|
|
171
|
+
offsets, and missing or repeated anchors return structured
|
|
172
|
+
`ANCHOR_NOT_FOUND` or `AMBIGUOUS_ANCHOR` errors.
|
|
173
|
+
- Full-document operation batches now share one live DOM and revision-ID
|
|
174
|
+
allocator, reducing complete-document parsing and serialization from once per
|
|
175
|
+
operation to once per changed batch. Scoped reconciliation engines and their
|
|
176
|
+
targeting decisions are unchanged.
|
|
177
|
+
- Each live-session operation uses a DOM and allocator savepoint. Errors and
|
|
178
|
+
reported no-ops restore the savepoint; atomic failures and all-no-op batches
|
|
179
|
+
still return the exact original XML without serializing it.
|
|
180
|
+
- Decomposed the standalone document-operation runner into a stable 13-line
|
|
181
|
+
compatibility facade plus focused session, applier, batch-orchestrator,
|
|
182
|
+
heuristic, and OOXML-mutation modules. Runtime exports and declarations are
|
|
183
|
+
unchanged, and operation internals now use leaf imports instead of importing
|
|
184
|
+
the root entry point.
|
|
185
|
+
- Package comment IDs are seeded from existing anchors and definitions, and
|
|
186
|
+
the Node facade merges numbering without discarding prior definitions.
|
|
187
|
+
- Canonical paragraph text consistently handles revisions, moves, tabs,
|
|
188
|
+
breaks, soft hyphens, and non-breaking hyphens; see the breaking-change note
|
|
189
|
+
above for `getParagraphText(...)` and fingerprint compatibility.
|
|
190
|
+
- Structured inspection now explicitly supports the `current` view as the
|
|
191
|
+
accepted/current document view and resolves comment ranges spanning multiple
|
|
192
|
+
paragraphs as one exact anchor string.
|
|
193
|
+
- Transactional no-op results preserve the original DOCX bytes exactly,
|
|
194
|
+
including when the same facade instance has already committed an edit.
|
|
195
|
+
|
|
196
|
+
### Testing and development
|
|
197
|
+
|
|
198
|
+
- Added focused and semantic visual-failure regressions for suppressed
|
|
199
|
+
numbering, paragraph separation, paragraph-mark revisions, selective
|
|
200
|
+
typography inheritance, and exact accepted/rejected paragraph sequences,
|
|
201
|
+
plus seeded fuzz variants across list length, marker, font, and size.
|
|
202
|
+
Added the independently specified
|
|
203
|
+
`legal-suppressed-heading-to-bullet-list` and
|
|
204
|
+
`legal-structured-attachment-mixed-blocks` Microsoft Word differential
|
|
205
|
+
fixtures; the synthetic catalogue now contains 49 cases and 49 task types.
|
|
206
|
+
|
|
207
|
+
- The JavaScript test runner now uses bounded asynchronous subprocess workers,
|
|
208
|
+
capped at four by default, while retaining one fresh Node process per file,
|
|
209
|
+
sorted reporting, timeouts, captured diagnostics, and failure-marker checks.
|
|
210
|
+
Set `DOCX_TEST_CONCURRENCY=1` for serial reproduction.
|
|
211
|
+
- Added `npm run benchmark:tests` and a Phase 6 runner regression. The checked
|
|
212
|
+
benchmark reduced median suite time from 18.02 seconds to 7.96 seconds
|
|
213
|
+
(55.80%); 20 consecutive parallel runs and a separate serial run passed all
|
|
214
|
+
63 files. Parallel c8 collection remains valid at 89.90% statements/lines,
|
|
215
|
+
77.40% branches, and 93.10% functions.
|
|
216
|
+
|
|
217
|
+
- Added Phase 3 targeting/traversal, Phase 4 list/text parity, and Phase 5 route
|
|
218
|
+
compatibility regressions. Together with the Phase 6 runner regression, the
|
|
219
|
+
suite now contains 63 passing test files.
|
|
220
|
+
- Added `npm run benchmark:targeting` and `npm run profile:routes`. The checked
|
|
221
|
+
10,000-paragraph benchmark showed no single-operation regression and a 47.16x
|
|
222
|
+
Node median improvement for 100 cached resolutions. The equivalent native
|
|
223
|
+
Chrome benchmark showed no single-operation regression and a 36.45x batch
|
|
224
|
+
improvement. All 47 Microsoft Word differential fixtures and all 60 real-
|
|
225
|
+
document Word corpus scenarios passed after the routing changes.
|
|
226
|
+
|
|
227
|
+
- Added subprocess coverage for legacy wrapper selection, operation-file
|
|
228
|
+
compatibility, successful output, atomic anchor failure, source-byte
|
|
229
|
+
preservation, and protection of pre-existing output files.
|
|
230
|
+
- Added a live-session accuracy and instrumentation suite covering accepted and
|
|
231
|
+
rejected text, structural validity, sequential equivalence, comments, lists,
|
|
232
|
+
tables, highlights, one-parse/one-serialize execution, exact no-ops, and
|
|
233
|
+
atomic rollback. Added `npm run benchmark:session`; the checked accuracy-first
|
|
234
|
+
benchmark reduced parse/serialize counts from 10/10 to 1/1 and measured a
|
|
235
|
+
1.58x median speedup with per-operation savepoints retained.
|
|
236
|
+
- Added a Phase 2 architecture regression covering facade export identity,
|
|
237
|
+
direct leaf imports, exact session rollback, isolated context commit, and
|
|
238
|
+
stable comment-first scheduling.
|
|
239
|
+
- Added five edge-case suites for canonical text views, cross-paragraph comment
|
|
240
|
+
inspection, table/list/reference context, sequential package transactions,
|
|
241
|
+
selective multi-author cleanup, ZIP rejection behavior, CLI filters, JSON
|
|
242
|
+
exit contracts, and destructive-output safeguards. Together with the Phase 2
|
|
243
|
+
Phase 1 and Phase 2 regressions, these established the earlier 57-file
|
|
244
|
+
baseline expanded by the subsequent performance phases.
|
|
245
|
+
|
|
246
|
+
## 0.3.0
|
|
247
|
+
|
|
248
|
+
### Breaking changes
|
|
249
|
+
|
|
250
|
+
- Malformed OOXML no longer escapes public transform APIs as a raw parser
|
|
251
|
+
exception. In particular, revision accept/reject and comment-deletion callers
|
|
252
|
+
that previously used `try`/`catch` must now inspect `status === 'error'` and
|
|
253
|
+
`error.code === 'PARSE_ERROR'` on the returned result.
|
|
254
|
+
- Caller content is no longer sanitized by default. Pass `sanitizeInput: true`
|
|
255
|
+
to remove a standalone leading assistant-preface line. Dollar-delimited text
|
|
256
|
+
and literal `\\n` / `\\r\\n` sequences are never removed implicitly.
|
|
257
|
+
- The exported `sanitizeAiResponse` helper no longer removes dollar-delimited
|
|
258
|
+
spans or converts literal `\\n` / `\\r\\n` sequences. Direct callers that
|
|
259
|
+
relied on those transformations must perform them explicitly.
|
|
260
|
+
- `applyOperationsToDocumentXml` is atomic by default. Failed batches return
|
|
261
|
+
the original document with `rolledBack: true`; pass `atomic: false` to retain
|
|
262
|
+
partial-result behavior.
|
|
263
|
+
- Missing multi-line targets now return `TARGET_NOT_FOUND` instead of being
|
|
264
|
+
indistinguishable from a no-op. Stale batch anchors also return
|
|
265
|
+
`TARGET_NOT_FOUND` instead of falling back to a visibly different paragraph.
|
|
266
|
+
|
|
267
|
+
### Behavior changes and fixes
|
|
268
|
+
|
|
269
|
+
- Revision IDs are now allocated per document. Near-limit prior IDs restart in
|
|
270
|
+
a safe low range, and unrelated bookmark/relationship IDs no longer seed the
|
|
271
|
+
revision counter.
|
|
272
|
+
- Concurrent calls with explicit authors keep their revision attribution
|
|
273
|
+
isolated from process-global defaults.
|
|
274
|
+
- `existingRevisions: 'accept-all-first'` now preserves the original OOXML when
|
|
275
|
+
the requested edit is a no-op.
|
|
276
|
+
- Added `existingRevisions: 'accept-all-first-keep-normalized'` for callers that
|
|
277
|
+
explicitly want accepted existing revisions returned even when no redline is
|
|
278
|
+
added.
|
|
279
|
+
- Diff output is deterministic by default. Inputs exceeding 262,144 unique
|
|
280
|
+
tokens return `DIFF_TOKEN_LIMIT` with the original OOXML unchanged instead of
|
|
281
|
+
risking truncated text; leading whitespace is preserved exactly.
|
|
282
|
+
- Reconstruction preserves structural line breaks and body section-property
|
|
283
|
+
placement. A target that names only part of a reconstruction range now
|
|
284
|
+
returns `PARTIAL_TARGET` instead of risking deletion of untargeted content.
|
|
285
|
+
- Paragraph targeting and reconstruction now preserve leading, middle, and
|
|
286
|
+
trailing `w:tab` elements as literal tab characters instead of omitting or
|
|
287
|
+
trimming them.
|
|
288
|
+
- Adjacent redline edits now preserve complex-field instructions, begin/
|
|
289
|
+
separate/end markers, and unchanged cached display results in their original
|
|
290
|
+
field boundary. Field instructions remain inert and are not evaluated.
|
|
291
|
+
- Added structured XML parse results and result-returning ingestion helpers.
|
|
292
|
+
- Hardened deterministic diff token handling and leading-whitespace fidelity.
|
|
293
|
+
|
|
294
|
+
### Testing and development
|
|
295
|
+
|
|
296
|
+
- Expanded the desktop Word differential from 20 to 25 cases, adding structural
|
|
297
|
+
checks for bookmarks, internal hyperlinks, mixed formatting, content
|
|
298
|
+
controls, and tables.
|
|
299
|
+
- Expanded the desktop Word differential from 25 to 28 cases with structural
|
|
300
|
+
tabs and a locked PAGE field, and added tab/field shapes to focused and fuzz
|
|
301
|
+
regression testing.
|
|
302
|
+
- Expanded the desktop Word differential from 28 to 33 cases with comments,
|
|
303
|
+
footnotes, endnotes, headers/footers, and an external hyperlink.
|
|
304
|
+
- Extended the deterministic script-only DOCX packager with opt-in related
|
|
305
|
+
parts, relationship/content-type validation, reusable fixture constructors,
|
|
306
|
+
and SHA-256 verification that supplied parts remain byte-identical. Runtime
|
|
307
|
+
library code and dependencies are unchanged.
|
|
308
|
+
- Added validated task, structure, oracle, and manual-review metadata across the
|
|
309
|
+
33 synthetic and 20 SuperDoc Word cases. `npm run report:word:coverage`
|
|
310
|
+
produces a deterministic coverage matrix with explicit high-priority gap
|
|
311
|
+
dispositions, while `npm run review:word:prepare` creates a pending rotating
|
|
312
|
+
human-review manifest without self-certifying visual results.
|
|
313
|
+
- Added detailed production-function coverage reporting and a checked per-file
|
|
314
|
+
regression baseline. Five behavior-focused Phase 3 suites exercise numbering
|
|
315
|
+
collisions/remapping, every reconciliation route, list construction and
|
|
316
|
+
fallback, patch/format boundaries, table decisions, pipeline modes, and
|
|
317
|
+
standalone rollback/highlight paths. Production function coverage moved from
|
|
318
|
+
437/540 to 496/542 and all reachable P0 functions are covered; no runtime
|
|
319
|
+
behavior or compatibility contract changed.
|