@ansonlai/docx-redline-js 0.9.0 → 0.11.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.
Files changed (36) hide show
  1. package/ARCHITECTURE.md +691 -669
  2. package/CHANGELOG.md +67 -1
  3. package/README.md +39 -8
  4. package/core/word-xml.js +160 -118
  5. package/dist/docx-redline-js.esm.js +528 -312
  6. package/dist/docx-redline-js.esm.js.map +4 -4
  7. package/dist/docx-redline-js.esm.min.js +94 -94
  8. package/dist/docx-redline-js.esm.min.js.map +4 -4
  9. package/dist/docx-redline.bundle.cjs +528 -312
  10. package/dist/docx-redline.bundle.cjs.map +4 -4
  11. package/dist/docx-redline.bundle.js +528 -312
  12. package/dist/docx-redline.bundle.js.map +4 -4
  13. package/docs/AGENT_KNOWLEDGE_BASE.md +64 -5
  14. package/docs/SKILL_AUTHORING.md +5 -1
  15. package/docs/TESTING.md +10 -1
  16. package/docs/schemas/document-operations.schema.json +1 -1
  17. package/engine/oxml-engine.js +748 -736
  18. package/engine/table-mode.js +7 -4
  19. package/index.d.ts +29 -2
  20. package/index.js +3 -0
  21. package/node/cli.js +993 -992
  22. package/package.json +1 -1
  23. package/pipeline/content-analysis.js +2 -1
  24. package/pipeline/markdown-processor.js +5 -2
  25. package/pipeline/structured-content.js +2 -1
  26. package/services/comment-parts-merge.js +124 -0
  27. package/services/comment-replies.js +1 -1
  28. package/services/document-operation-applier.js +1 -0
  29. package/services/document-operation-contract.js +1 -0
  30. package/services/document-operation-mutations.js +3362 -3346
  31. package/services/inspection-comparison.js +82 -0
  32. package/services/operation-heuristics.js +1 -1
  33. package/services/operation-preflight.js +42 -33
  34. package/services/revision-fidelity-verifier.js +5 -19
  35. package/services/standalone-docx-plumbing.js +38 -22
  36. package/services/table-reconciliation.js +11 -6
@@ -71,6 +71,9 @@ instructions that will exist in another clone or in CI.
71
71
  | Full-document operation scheduling or rollback | `services/document-operation-applier.js`, `services/batch-operation-orchestrator.js`, `services/document-operation-session.js` | `tests/standalone_operation_runner_tests.mjs`, `tests/performance_phase1_session_tests.mjs` |
72
72
  | DOCX ZIP wiring or CLI behavior | `node/docx-document.js`, `node/zip-archive.js`, `node/cli.js` | `tests/docx_package_facade_tests.mjs`, `tests/node_zip_archive_tests.mjs`, `tests/agent_cli_tests.mjs` |
73
73
  | Validation, receipts, and lifecycle oracles | `core/redline-validation.js`, `services/receipt-collector.js`, `services/revision-comment-management.js` | `tests/redline_validation_tests.mjs`, `tests/mutation_receipt_tests.mjs`, `tests/roundtrip_oracle_tests.mjs` |
74
+ | Existing-revision policy resolution (`auto`) | `core/word-xml.js` (`resolveExistingRevisionsPolicy`), `services/document-operation-mutations.js`, `services/operation-preflight.js` | `tests/existing_revisions_auto_tests.mjs`, `tests/existing_revisions_auto_paths_tests.mjs` |
75
+ | Comparing a committed document with a prepared one | `services/inspection-comparison.js` | `tests/inspection_comparison_tests.mjs` |
76
+ | Comment parts outside a ZIP | `services/comment-parts-merge.js`, `services/standalone-docx-plumbing.js` (`mergeCommentsPartXml`), `services/comment-thread-parts.js` | `tests/comment_parts_merge_tests.mjs` |
74
77
 
75
78
  Run one focused suite with `node tests/<name>.mjs`. Run `npm test` only when the
76
79
  change crosses several subsystems or before release-level handoff. The Word COM,
@@ -163,6 +166,14 @@ insertions and deletions inside their pending insertion. Pass
163
166
  via CLI) to normalize all prior revisions first, or `'reject-input'` to refuse any
164
167
  paragraph with open revisions. Use `'accept-all-first-keep-normalized'` only when
165
168
  accepted revisions should be returned as a real change even on a no-op edit.
169
+ `existingRevisions: 'auto'` (or `--existing-revisions auto`, capability
170
+ `existing-revisions-auto-v1`) chooses per target: `'merge-same-author'` when the
171
+ target has no tracked changes or only the operation author's, otherwise
172
+ `'slice-cross-author'` (unattributed changes count as another author's).
173
+ Preflight reports the resolved policy. `auto` opts into cross-author slicing
174
+ wherever it is needed, so choose it only when editing inside other reviewers'
175
+ pending insertions is intended for the whole batch; it never accepts or rejects
176
+ anyone's revisions.
166
177
  Same-author merging also fails with `COMMENTED_CONTENT_MERGE` when the revised
167
178
  paragraph contains comment anchors, because reverting the prior revision could
168
179
  remove or orphan those comments. Resolve the comments before re-editing.
@@ -375,6 +386,47 @@ const inspection = inspectDocumentParts({ documentXml, commentsXml, numberingXml
375
386
  Reuse `exactText` plus `paragraphId` or `fingerprint` in an operation. Computed
376
387
  list labels and excerpts are for display, not replacements for exact targets.
377
388
 
389
+ ### Merge comment output into parts held outside a ZIP
390
+
391
+ ```js
392
+ import { mergeCommentParts } from '@ansonlai/docx-redline-js';
393
+ const merged = mergeCommentParts(
394
+ { commentsXml, commentsExtendedXml, commentsIdsXml, commentsExtensibleXml }, // current parts, null when absent
395
+ batchResult // commentsXml / commentsXmlMode, commentsExtendedXml / commentsExtendedXmlMode
396
+ );
397
+ if (merged.status === 'ok') { /* write merged.parts; ensure rels/content types for merged.changedParts */ }
398
+ ```
399
+
400
+ Use it when a host holds package parts as strings (a Flat OPC package from a Word
401
+ add-in, a browser parts map) instead of handing a ZIP to `openDocx`, which does the
402
+ same merge internally. commentsIds.xml and commentsExtensible.xml are reconciled
403
+ only when present, never created. A `'merge'` commentsExtended delta for parts that
404
+ already have thread metadata is refused with
405
+ `UNSUPPORTED_EXISTING_COMMENT_THREAD_METADATA`. Other codes: `PARSE_ERROR`,
406
+ `INVALID_COMMENT_PARTS` (non-string input, wrong root element) and
407
+ `DUPLICATE_COMMENT_ID`; `error.part` names the part (and `error.commentId` the
408
+ duplicate). An unexpected merge failure reports `COMMENT_PARTS_MERGE_FAILED`. It
409
+ never throws for document content. On any error the input parts
410
+ come back unchanged. `addedParts` reflects part presence only; the function cannot see
411
+ relationships, so a host that owns them should ensure one for every part in
412
+ `changedParts` (a package can have comments.xml without its relationship).
413
+
414
+ ### Verify a committed document against the prepared one
415
+
416
+ ```js
417
+ import { inspectDocumentParts, compareDocumentInspections } from '@ansonlai/docx-redline-js';
418
+ const check = compareDocumentInspections(inspectDocumentParts(preparedParts), inspectDocumentParts(committedParts));
419
+ // { matches, differences: [{ path, expected, actual }] }, at most the first 10
420
+ ```
421
+
422
+ Use it when a host writes a prepared package through its own API (for example a
423
+ Word add-in's `insertOoxml`) and then reads the result back. It compares paragraph
424
+ text, table position, list labels, review segments (kind, author, position;
425
+ adjacent same-author segments merged) and comments (text, author, anchor,
426
+ resolved state, thread parent). It ignores revision ids, dates, rsids, paragraph
427
+ ids, comment ids and order, and run boundaries. A mismatch is a signal to
428
+ re-inspect, not something to retry blindly.
429
+
378
430
  ### Safely edit a complete DOCX in Node
379
431
 
380
432
  ```js
@@ -547,7 +599,7 @@ docx-redline apply contract.docx --target "Typo fix" --modified "Fixed typo" --n
547
599
 
548
600
  Key CLI defaults and behaviors:
549
601
  - **Author**: Automatically defaults to `'AI Redliner'` (overridable via `--author` or `DOCX_REDLINE_AUTHOR` environment variable).
550
- - **Existing revisions**: Defaults to `'merge-same-author'`. Pass `--existing-revisions slice-cross-author` to edit inside another reviewer's pending insertions with native carrier slicing.
602
+ - **Existing revisions**: Defaults to `'merge-same-author'`. Pass `--existing-revisions slice-cross-author` to edit inside another reviewer's pending insertions with native carrier slicing, or `--existing-revisions auto` to slice only the targets that carry another reviewer's changes.
551
603
  - **Overwrite behavior**: Destination files provided via `--output` overwrite by default. To protect existing destination files, pass `--no-overwrite` or `--no-clobber`. The source document is never overwritten unless `--in-place` is specified.
552
604
  - **Tracked changes**: Defaults to `generateRedlines: true`. When clean direct text is needed, pass `--no-redlines`.
553
605
  - **Atomic rollback (optional)**: Operations apply progressively by default (`atomic: false`). For all-or-nothing transactional rollback where any error halts and reverts all changes, pass `--atomic`.
@@ -776,7 +828,7 @@ When the CLI or runner returns an error code, follow these specific recovery act
776
828
  | `REVISION_ORDER_CONFLICT` | A text rewrite and formatting/highlight operation overlap the same source. | Consolidate or split the work at an intentional created-content dependency; do not try a different arbitrary order. |
777
829
  | `LIST_FORMAT_COMPOSITION_CONFLICT` | A `redline` and a `list-format` on the same paragraph do not compose (`reason`: `marker-changed` with `sourceMarker`/`modifiedMarker`, `redline-unchanged`, `redline-shape` for a multi-paragraph, ranged, anchored, `list-change` or structured redline), or a `list-format` with `scope: 'list'` rebinds an item another operation also writes (`list-rebind`, `rebindingOperationIndexes`). Detected at batch compilation; nothing was written. | `recovery.action: split_text_and_list_changes` (`recovery.hint`). Keep the typed marker byte-identical in the redline (the list-format strips it) and express a new label through `list-format`; drop a no-op redline; send other writes to rebound items in a separate apply or use `scope: 'range'`. |
778
830
  | `CAPTURE_FANOUT_CONFLICT` | Multiple mutating consumers share one capture without distinct selectors. | Give consumers distinct selectors, chain them explicitly, or split the batch. |
779
- | `EXISTING_REVISIONS` | Target paragraph contains tracked changes from another author. | Fails closed to protect third-party review marks. If editing inside that reviewer's pending insertion is intended, pass `--existing-revisions slice-cross-author` (or `existingRevisions: 'slice-cross-author'`). Do not pass `accept-all-first` without explicit user authorization. |
831
+ | `EXISTING_REVISIONS` | Target paragraph contains tracked changes from another author. | Fails closed to protect third-party review marks. If editing inside that reviewer's pending insertion is intended, pass `--existing-revisions slice-cross-author` (or `existingRevisions: 'slice-cross-author'`; `'auto'` does this per target). Do not pass `accept-all-first` without explicit user authorization. |
780
832
  | `PATCH_ROUNDTRIP_MISMATCH` | A cross-author surgical edit did not reconstruct the requested modified text exactly, or a localized `replacements` operation would not leave the compiled accepted text in the target (checked before commit on every path). | Treat the operation as unapplied. Re-extract the exact paragraph text and split the edit into a narrower operation that does not cross the reported structural boundary. |
781
833
  | `FOREIGN_PARAGRAPH_MARK_DELETION` | A normal edit attempted to write into a paragraph wholly deleted by another reviewer. | Use an explicit `restore` operation if the user intends to counterpropose that paragraph; otherwise leave the deletion unresolved. |
782
834
  | `RESTORATION_STATE_REQUIRED` / `RESTORATION_COUNT_MISMATCH` | A `restore` target is not a wholly foreign-deleted paragraph, or its replacement count does not match the paragraph range. | Re-inspect the document and target the deleted paragraph by stable descriptor; provide exactly one replacement string per source paragraph. |
@@ -866,9 +918,16 @@ Accept/Reject checks.
866
918
 
867
919
  ```js
868
920
  import { reconcileMarkdownTableOoxml } from '@ansonlai/docx-redline-js';
869
- const result = await reconcileMarkdownTableOoxml(tableOoxml, originalText, markdownTable);
921
+ const result = await reconcileMarkdownTableOoxml(tableOoxml, originalText, markdownTable, options); // options optional
870
922
  ```
871
923
 
924
+ A multi-line `redline` of a table-cell paragraph whose first line is the cell's
925
+ current text (`'Cell text.\nSecond line'`) inserts the extra lines as new rows below
926
+ the target row, in the target column (mirrored across columns for symmetric label
927
+ rows such as signature blocks). It does not add paragraphs inside the cell. With
928
+ `structuredContent: false` the new cell text stays literal. One-column tables use
929
+ `| --- |` as the separator.
930
+
872
931
  ## Detailed Architecture
873
932
 
874
933
  Use the layout and task shortcuts at the top of this file for normal work.
@@ -885,10 +944,10 @@ reconstruct the architecture by repeatedly listing the repository.
885
944
  | `generateRedlines` | `boolean` | `true` | When `true`, emits Word-native tracked changes (`w:ins`/`w:del`). When `false`, applies direct text edits without revision markup. **Note: Redlines are not always the preferred method** — pass `generateRedlines: false` (or `--no-redlines` via CLI) when producing clean execution drafts, restructuring documents, or when revision clutter is unwanted. |
886
945
  | `author` | `string` | `'AI Redliner'` | Reviewer/author name stamped on generated tracked changes and comments. Overridable via `DOCX_REDLINE_AUTHOR` environment variable. |
887
946
  | `atomic` | `boolean` | `false` | Batch transaction mode. By default (`false`), valid edits are applied directly and failing operations report errors. When `true`, any operation failure rolls back the entire batch to the original document state (`rolledBack: true`, `hasChanges: false`). Use `atomic: true` (or `--atomic` in CLI) for high-assurance workflows. |
888
- | `structuredContent` | `boolean` | `true` | Auto-detects Markdown tables, headings (`#`), and lists in replacement text and renders them as native Word elements (`w:tbl`, `w:pStyle`, `w:numPr`). Pass `false` to treat replacement text strictly as plain text. |
947
+ | `structuredContent` | `boolean` | `true` | Auto-detects Markdown tables, headings (`#`), and lists in replacement text and renders them as native Word elements (`w:tbl`, `w:pStyle`, `w:numPr`). Pass `false` to treat replacement text strictly as plain text, including paragraphs a redline adds and table-cell text: no headings, and inline Markdown markers (`**`, `__`, `_`, `~~`, `++`) are kept literally. With `true`, underscores follow CommonMark flanking rules, so signature lines (`_____`) and `snake_case` stay literal. |
889
948
  | `pairReplacements` | `boolean` | `true` | Links adjacent `<w:del>` and `<w:ins>` revisions with matching timestamps so Word groups them as a single replacement in the Reviewing Pane. |
890
949
  | `strictTargets` | `boolean` | `true` (CLI/facade) | Requires exact target descriptors (`exactText`, `paragraphId`, `index`, `occurrence`, `fingerprint`) and forbids ambiguous matching. Defaults to `false` in low-level runner for backwards compatibility. |
891
- | `existingRevisions` | `string` | `'merge-same-author'` | How to handle paragraphs with existing tracked changes. `'merge-same-author'` merges the same author's work and protects other authors with `EXISTING_REVISIONS`. `'slice-cross-author'` retains same-author merging while allowing Word-native edits inside another author's pending insertion. Pass `'accept-all-first'` to normalize prior revisions or `'reject-input'` to refuse editing revised paragraphs. |
950
+ | `existingRevisions` | `string` | `'merge-same-author'` | How to handle paragraphs with existing tracked changes. `'merge-same-author'` merges the same author's work and protects other authors with `EXISTING_REVISIONS`. `'slice-cross-author'` retains same-author merging while allowing Word-native edits inside another author's pending insertion. Pass `'accept-all-first'` to normalize prior revisions or `'reject-input'` to refuse editing revised paragraphs. `'auto'` chooses per target: `'merge-same-author'` when the target has no tracked changes or only the operation author's, otherwise `'slice-cross-author'` (preflight reports the resolved policy). |
892
951
  | `removeFormatting` | `boolean` | `false` | When `true` and the text is unchanged with no Markdown hints, strips existing bold/italic/underline/strikethrough formatting. |
893
952
  | `sanitizeInput` | `boolean` | `false` | Opt-in removal of standalone leading assistant-preface lines. Literal dollar signs and `\n` sequences are always preserved. |
894
953
 
@@ -47,6 +47,10 @@ format, or joins lists:
47
47
  - sends a changed-text header (`1. Old` -> `1. New`) as a marker-preserving `redline` plus a `list-format` of that
48
48
  paragraph in one batch, and splits them on `LIST_FORMAT_COMPOSITION_CONFLICT`.
49
49
 
50
+ ### Existing-revision policy (optional)
51
+
52
+ Only with `existing-revisions-auto-v1`: `existingRevisions: 'auto'` consents to slicing around other or unattributed authors' changes for the whole batch. Report the resolved policy.
53
+
50
54
  Do not expose negotiated but unused capabilities as choices in the editing
51
55
  prompt. `command-help-v1`, restore shortcuts, speculative apply, and localized
52
56
  change summaries are optional requirements only for integrations that use them.
@@ -77,7 +81,7 @@ Keep these exceptions separate from the default workflow:
77
81
  | Choice | Default | Override only when |
78
82
  |---|---|---|
79
83
  | Transaction | progressive | Partial output is unacceptable (`--atomic`). |
80
- | Existing revisions | `merge-same-author` | Editing inside another reviewer's pending insertion is intended (`slice-cross-author`). |
84
+ | Existing revisions | `merge-same-author` | Editing inside another reviewer's pending insertion is intended (`slice-cross-author`, or `auto` to slice only targets that carry another reviewer's changes; capability `existing-revisions-auto-v1`). |
81
85
  | Reviewer identity | `AI Redliner` is a valid visible fallback | The host supplies a preferred flag, operation author, or environment value. |
82
86
  | Output | derived sibling | The caller deliberately selects another destination. |
83
87
 
package/docs/TESTING.md CHANGED
@@ -37,6 +37,14 @@ fixtures rarely contain.
37
37
  | List and text-walker parity | `node tests/performance_phase4_list_and_text_parity_tests.mjs` | One shared marker vocabulary and canonical/specialized visible-text agreement across structural characters and revision views | That all specialized mappings are interchangeable |
38
38
  | Universal document facade & ZIP | `node tests/universal_docx_document_tests.mjs`, `node tests/universal_zip_archive_tests.mjs`, `node tests/universal_facade_edge_cases_tests.mjs` | Universal `Uint8Array` binary handling, `fflate` compression/decompression, optimistic concurrency, and complete-DOCX operations without Node built-ins | Desktop Word rendering |
39
39
  | Sandbox bundle isolation | `node tests/sandbox_bundle_isolation_tests.mjs` | Zero-dependency standalone ESM/CJS bundles execute in restricted VM sandboxes without `process`, `Buffer`, or `require`, with zero Node built-in imports | Web Worker latency |
40
+ | Existing-revision policy `auto` | `node tests/existing_revisions_auto_tests.mjs`, `node tests/existing_revisions_auto_paths_tests.mjs` | Per-target resolution to `merge-same-author` or `slice-cross-author` (mixed, unattributed and deletion-only history, whole `targetEnd` ranges, table cells), equivalence with the explicit policy through `applyRedlineToOxml` and the runner, preflight reporting, untracked edits, `openDocx`, `--existing-revisions auto`, schema and the CLI capability | Desktop Word rendering |
41
+ | Existing-revision policy `merge-same-author` | `node tests/merge_same_author_tests.mjs` | Same-author turns merge against their baseline, foreign-author and mixed-history targets are refused or protected, and an unattributed tracked change counts as another reviewer's (merge refused with `EXISTING_REVISIONS`; slicing keeps its baseline) | Desktop Word rendering |
42
+ | Plain-text paragraph insertion | `node tests/plain_text_paragraph_insertion_tests.mjs` | A caller's `structuredContent: false` keeps paragraphs a redline adds literal (before/after/around the target, several, signature lines, headings, changed target, batch vs per-operation, `replace`, untracked, `openDocx`, ranges, list siblings at level 0/1 and bullets) with Reject All restoring the source | Desktop Word rendering |
43
+ | Table-cell multi-line edits | `node tests/table_cell_paragraph_insertion_tests.mjs` | One-column separator recognition (and bare `---` rejection), multi-line cell edits inserting rows below the target in one- and two-column tables in every `structuredContent` mode, caller-written one-column tables (reconcile and text-to-table), the plain-text contract in cells, Reject All and validation, `openDocx` | Desktop Word rendering |
44
+ | Comment parts merge | `node tests/comment_parts_merge_tests.mjs`, `node tests/comment_parts_merge_edge_tests.mjs` | `mergeCommentParts` append/replace, sibling reconciliation (never created, multi-paragraph and paraId-less comments, unique durable ids), structured refusals with unchanged input (types, roots, malformed siblings, duplicates), no-ops, idempotence, special characters, and part-for-part equivalence with `openDocx` for a new comment, a reply, a resolve, a first comment, a comments-only package, sequential batches and a mixed batch | A host's own package and relationship writing |
45
+ | Comment reply paraIds | `node tests/comment_reply_para_id_tests.mjs` | A reply's `w14:paraId` avoids body paragraph ids (case-insensitive) and stays deterministic without a collision | Word's own id allocation |
46
+ | Inspection comparison | `node tests/inspection_comparison_tests.mjs` | `compareDocumentInspections` ignores ids, dates, comment order and run splits and reports text, review-segment (author, kind, position), table, list-label and comment (text, author, anchor, resolved, thread) differences, capped at 10; works on `openDocx` inspections | A host's own write path |
47
+ | Literal underscores and plain text | `node tests/literal_underscore_text_tests.mjs` | Signature lines and `snake_case` survive table reconciliation and rewrites; CommonMark underscore flanking; a caller's `structuredContent: false` keeps inline Markdown literal | Desktop Word rendering |
40
48
  | Cross-author revision slicing | `node tests/cross_author_slicing_fixtures_tests.mjs`, `node tests/cross_author_carrier_splitting_tests.mjs`, `node tests/cross_author_slicing_synthetic_tests.mjs`, `node tests/cross_author_slicing_real_tests.mjs`, `node tests/cross_author_slicing_hyperlink_roundtrip_tests.mjs`, `node tests/cross_author_slicing_insertion_stress_tests.mjs` | Word-native `<w:ins>` splitting, `<w:del>` nesting, multi-author stacking, straddle boundaries, synthetic matrix (SYN-01..12d), strict package differential replay (PKG-01..06), exact hyperlink/NBSP round trips, and 76 insertion stress scenarios | Non-Word consumers beyond OpenXML XSD validation |
41
49
 
42
50
  The package-facade regression opens a real ZIP buffer, adds a comment beside an
@@ -944,7 +952,8 @@ The corpus packager starts from the original `.docx`, replaces only the declared
944
952
  revision part (`word/document.xml` by default, or a named header part), and
945
953
  verifies every untouched ZIP part byte-for-byte before Word opens the result.
946
954
  The Word oracle derives multi-change expectations by applying each independently
947
- declared replacement to Word's source text and reads header-story text separately
955
+ declared replacement to Word's source text and reads header-story text separately.
956
+
948
957
  ## Release validation and independent oracles
949
958
 
950
959
  This package works on OOXML strings and intentionally leaves `.docx` zip
@@ -145,7 +145,7 @@
145
145
  "target": { "$ref": "#/$defs/target" }, "targetRef": { "type": ["integer", "string", "null"] },
146
146
  "part": { "$ref": "#/$defs/headerFooterPart" },
147
147
  "author": { "type": "string", "minLength": 1 }, "generateRedlines": { "type": "boolean" },
148
- "existingRevisions": { "enum": ["merge-same-author", "slice-cross-author", "reject-input", "accept-all-first", "accept-all-first-keep-normalized"] },
148
+ "existingRevisions": { "enum": ["auto", "merge-same-author", "slice-cross-author", "reject-input", "accept-all-first", "accept-all-first-keep-normalized"] },
149
149
  "pairReplacements": { "type": "boolean" },
150
150
  "listMarkers": { "const": "literal", "description": "Accepts list-marker text as literal text. Suppresses LIST_MARKER_NOT_BOUND / UNSUPPORTED_LIST_CONVERSION and LIST_FORMAT_NOT_APPLIED / UNSUPPORTED_LIST_FORMAT_CHANGE for this operation." },
151
151
  "insertionAffinity": {