Add first-class links and bookmarks (#451) - #480
Merged
Conversation
JSv4
force-pushed
the
agent/issue-448-introspection
branch
from
August 14, 2026 09:49
1271a0c to
86fa85e
Compare
JSv4
force-pushed
the
agent/issue-451-links-bookmarks
branch
from
August 14, 2026 09:49
f86de5a to
07ecc65
Compare
JSv4
force-pushed
the
agent/issue-448-introspection
branch
from
August 14, 2026 10:07
86fa85e to
fa4a628
Compare
JSv4
force-pushed
the
agent/issue-451-links-bookmarks
branch
from
August 14, 2026 10:07
07ecc65 to
8370fee
Compare
JSv4
force-pushed
the
agent/issue-448-introspection
branch
from
August 14, 2026 11:11
fa4a628 to
8cd7304
Compare
JSv4
force-pushed
the
agent/issue-451-links-bookmarks
branch
from
August 14, 2026 11:11
8370fee to
8d46a3f
Compare
JSv4
force-pushed
the
agent/issue-448-introspection
branch
from
August 14, 2026 11:39
8cd7304 to
739ad51
Compare
JSv4
force-pushed
the
agent/issue-451-links-bookmarks
branch
from
August 14, 2026 11:39
8d46a3f to
14fb635
Compare
Review fixes on the links/bookmarks surface. - Bookmark references now cover BOTH consumer families. Beyond w:hyperlink/@w:anchor, REF/PAGEREF/NOTEREF/HYPERLINK \l instructions in w:instrText and w:fldSimple/@w:instr are scanned, retargeted by RenameBookmark (splicing only the name token, so switches survive; a split instruction coalesces onto its first w:instrText) and counted by the BookmarkInUse guards in RemoveBookmark and ValidateBookmarkRemoval. Renaming a bookmark a TOC cites no longer leaves "Error! Bookmark not defined." behind. - Word's _GoBack/_Toc*/_Ref*/_Hlt*/_Hlk* namespace is closed to creation (AddBookmark and RenameBookmark's destination). Bookmarks Word already placed there stay readable and mutable; the policy is documented in docx_mutation_api.md. - AddHyperlink relocates the whole contiguous sibling range it covers, so a w:bookmarkStart/End or w:commentRangeStart/End sitting between selected runs moves INTO the new w:hyperlink at its original position instead of being stranded after it. A bookmark whose start lay inside the span used to end up ordered after its own end, which made the pair unresolvable and the bookmark permanently unmutatable. - A cross-part MoveBookmark takes a fresh document-global w:id. w:id is part-scoped and Word reuses decimals across parts, so carrying the source id into another part could collide and make BOTH bookmarks unresolvable. - The tracked-move bookmark rejection moved into a shared predicate, so ValidMoveTargets mirrors MoveBlock and a drag UI cannot advertise a drop the engine refuses. - SplitHyperlinkAt no longer clones PtOpenXml.Unid, so the two halves of a split link get distinct ids and both stay addressable by Update/RemoveHyperlink. - The comments part joined OwnedPartRelationships.StoryParts. ProjectionScopes.Comments was silently empty and FindOwner returned null for comment paragraphs, which made PromoteHyperlinkRelationships throw on ReplaceText over a comment paragraph (DS364). MCP gained the matching "comments" link scope. - docx_agent_server.md documented targetKind where the schema key is kind. Tests: LB021-LB027, ValidMoveTargets_TrackedMode_RoundTripsWithMoveBlock, python/tests/test_links_bookmarks.py, npm/tests/docx-session-links.spec.ts.
JSv4
marked this pull request as ready for review
August 15, 2026 02:39
JSv4
added a commit
that referenced
this pull request
Aug 15, 2026
Brings the structural tracked-revision work up to date with the five sibling PRs from the same stack that landed on main while this branch sat still: #479 atomic batches, #481 isolated preview, #477 introspection, #480 links/bookmarks and #482 images. One file conflicted, Docxodus.Tests/McpServerDispatcherTests.cs, and only because both sides appended tests at the same point. Both sides' tests are kept in full; none was dropped, weakened or merged together. The sole real collision was the test number MCP099, claimed independently by main's MCP099_BatchedTableStep_KeepsTableAnchorMappingInItsReceipt (from d558c00) and by this branch's tracked-changes batch test. Main's numbering is left untouched because it is already merged and referenced, so this branch's test takes the next free number instead: MCP099_TrackChangesBatchPreviewIsIsolatedAndAtomicApplyResolvesRevision -> MCP146_TrackChangesBatchPreviewIsIsolatedAndAtomicApplyResolvesRevision MCP102 and MCP103 do not collide with anything on main and keep their numbers. The batch changeset comparison converged as intended: this branch's f761e49 and main's 983c5bf made the same serialized-projection change, and the merged tree holds exactly one such comparison with no record-equality remnant. The comments part added to OwnedPartRelationships.StoryParts by 96f4c2f survives, and both sides' CHANGELOG entries accumulated under a single [Unreleased]. Verified on the merged tree: the library and the test project build with 0 errors, the full suite is 3712 passed / 0 failed / 3 skipped, and the Release builds of tools/mcp-server and tools/python-host are clean. Test-attribute counts are exactly additive across the merge (Fact 2195, Theory 173, InlineData 1545 = base plus main's additions plus this branch's), confirming no test was lost.
JSv4
added a commit
that referenced
this pull request
Aug 15, 2026
Bring the native content-control work up to date with main after PRs #479, #481, #477, #480, #482 and #485 landed. CHANGELOG.md was the only conflict: both sides added an entry at the top of [Unreleased]. Resolved by keeping both, main's #455 structural tracked revisions first and this branch's #452 native content-control operations second; the rest of main's list is unchanged. Two semantic fixes a clean textual merge would have hidden: - Renumber this branch's MCP content-control tests from MCP146/147/148 to MCP147/148/149. Main's #485 independently claimed MCP146 for MCP146_TrackChangesBatchPreviewIsIsolatedAndAtomicApplyResolvesRevision in the same file, so both sides had defined an MCP146. - docs/architecture/docx_agent_server.md: correct the tools/list count from 17 to 19 (the catalog now registers 19 tools, three lifecycle plus sixteen read/grouped-intent), add docxodus_track_changes to the docxodus_mutations batch-step list so it matches the catalog enum and the dispatcher's accepted set, and add images/content-controls to the grouped-intent enumeration.
JSv4
added a commit
that referenced
this pull request
Aug 15, 2026
Brings the native-image branch up to date with main (PRs #479, #481, #477, #480, #482, #485). Two conflicts, both additive-on-both-sides EditErrorCode collisions, resolved by keeping every code from both sides: - npm/src/types.ts: kept the eight image codes from this branch and main's unresolved_structural_revision. - python/src/docx_scalpel/enums.py: same resolution. The C# EditErrorCode enum in DocxSession.cs auto-merged and remains the single owner; all three surfaces now carry the same 58 codes.
JSv4
added a commit
that referenced
this pull request
Aug 15, 2026
Brings the branch up to date with main, which had advanced by 20 commits (PRs #479, #481, #477, #480, #482, #485 and #484). CHANGELOG.md was the only conflict: both sides appended to the same [Unreleased] / ### Added region. Resolved by keeping every entry from both sides, with this branch's idempotent mutation transaction entry ahead of main's accumulated entries. Main's block is otherwise unchanged, and the historic "[Unreleased] - .NET 8" heading further down the file is untouched. EditErrorCode gained four transaction codes on this branch and image and revision codes on main; the merged enum retains all of them, and the npm and Python mirrors carry this branch's four. The enum has no explicit ordinals and is serialized by name, so the reordering #485 introduced does not affect the wire. This PR remains MCP-transport-only: DocxSessionOps, DocxSessionJson and the WASM bridge are byte-identical to main after the merge.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Validation
git diff --checkand builds passedStack
This draft targets
agent/issue-448-introspection(draft PR #477) so the review contains only issue #451 changes.Closes #451
Fixes #469
Fixes #470