Merge main into stable - #3859
Conversation
Ported-From-Source-Repo: superdoc/orbit Ported-From-Source-Commit: 02cc77b458655080bfeb4863c0ef55bd8373a200 Ported-Public-Prefix: superdoc/public
…hen (#1139) Co-authored-by: Artem Nistuley <artem@superdoc.dev> Ported-From-Source-Repo: superdoc/orbit Ported-From-Source-Commit: d91ef133c6e77551d777df5007250be7d5e846c0 Ported-Public-Prefix: superdoc/public
* fix(release): stop V1 claiming the npm dist-tags owned by V2
`superdoc` is published to one npm package name by two release lines that
do not coordinate. Both claimed `latest` and `next`, and npm dist-tags are
last-write-wins, so whichever line published most recently owned them. V1
publishes more often, so V1 won: it took `latest` back on 30 Jul via a
stable release, and `next` on 31 Jul via a push to main, 24 minutes after
V2 had published there.
Tag ownership is now explicit. V2 keeps `latest` and `next`; V1 becomes a
maintenance line under `legacy`. The V1 stable lane stays automatic, so
maintenance releases still ship without manual work — only the tag they
land on changes.
Three separate paths could reach npm, and all three had to agree. The
release config sets the channel, the stable orchestrator's recovery derives
a tag from the version string alone, and the release workflow ran
semantic-release on every push to main. Removing the push trigger alone
would have left a manual dispatch able to cut a real release, so that
workflow now publishes `pr-<number>` previews and nothing else.
The guard encodes all five invariants and fails closed in the mirror-check
lane that already runs on every PR. It rejects the pre-fix state on all six
counts, so it would have caught this before it reached the registry.
* fix(release): close three false-pass gaps in the tag-ownership guard
Each invariant checked that some text existed rather than that the
behaviour was right, so three configurations passed the guard while still
publishing V1 to a tag V2 owns.
The stable channel check looked for `legacy` anywhere in the config, so a
config mapping stable to `canary` while some maintenance branch carried
`legacy` passed. It now parses branch objects and asserts the mapping.
The preview workflow check rejected push triggers and semantic-release but
never required a dist-tag. `publish-superdoc.cjs` defaults to `latest`, so
a dispatch-only workflow running it bare would have taken `latest` on the
next preview. Every invocation must now carry an explicit
`pr-${{ inputs.pr_number }}`, and pr_number must be required and numeric.
The recovery check only looked for `stableDistTag: 'legacy'` in the
descriptor, which proves nothing on its own: dropping the `pkg` argument at
a call site restores the `latest` fallback and leaves the descriptor
untouched. The resolver moves to its own module so it can be imported and
tested directly — release-local-stable.mjs runs the release loop at import
time and cannot be — and the guard now asserts both call sites forward the
package and that the shared module is used rather than a local copy.
All three are covered by regression tests built from the configurations
that reproduced them. The guard now reports nine violations against pre-fix
main, up from six.
Both new test files run in the mirror-check lane. release-local.test.mjs is
not wired into CI, which is how its five pre-existing failures went unseen;
that is left alone here rather than widened into this change.
* fix(release): keep the scoped mirror on latest and close four guard bypasses
The scoped mirror was collateral damage from the tag split. Codex caught it:
`publish-superdoc.cjs` passed one dist-tag to both `superdoc` and
`@harbour-enterprises/superdoc`, so routing V1 stable to `legacy` would have
taken the scoped package's `latest` with it. That package is V1-only —
nothing else advances it — so its `latest` would have frozen at 1.45.1 and
default installs would have silently stopped updating. The two names now
resolve their stable tag independently; previews and prereleases still match
under both.
Writing that test surfaced a temporal dead zone: `scopedTagFor` sat below the
`require.main` block that `parseArgs` runs from, so every direct invocation
threw "Cannot access before initialization" — the path release recovery uses.
Moved above its first reference and covered by a test.
Four guard bypasses, each reproduced before fixing. `pr_number` validation
matched `required:`/`type:` anywhere in the trigger block, so a required
numeric sibling input satisfied an optional string `pr_number`; it now parses
that input's own block. The recovery audit accepted any number of safe calls,
so one site could hardcode `latest` while the other vouched for it; it now
asserts both named assignments resolve through the shared helper. The branch
parser scanned to the next `name:` token rather than the object boundary, so
a later object's channel was read as stable's; it now matches braces. And the
workflow audit inventoried only `publish-superdoc.cjs`, so a direct
`dist-tag add` could reclaim a tag beside a correctly tagged preview.
Guard now reports ten violations against pre-fix main, up from nine.
Qodo also flagged `superdoc` in the workflow title as a naming violation.
Not taken: the sibling release workflows use the lowercase package name the
same way, and it refers to the npm package rather than the product.
Note: this ports only the public subtree changes from a mixed source commit (8 public paths, 5 non-public paths ignored).
Ported-From-Source-Repo: superdoc/orbit
Ported-From-Source-Commit: c4447f0b00bc324edb5e39cfe0cb557bd6796e8c
Ported-Public-Prefix: superdoc/public
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
I wasn't able to get the ecma-spec MCP tools authorized in this session (each call returned a pending-permission error), so I verified the relevant elements against ECMA-376 from knowledge. Here's the review. Status: PASS This PR is a behavior fix on the import (XML → ProseMirror) side of the What it actually changes: previously the tracked-change mark ( On spec grounds this all checks out:
One thing worth flagging as a non-blocking note rather than a violation: the The rest of the diff (release workflow / dist-tag plumbing, docs pin regex) is unrelated to OOXML. If you want the spec assertions machine-verified rather than knowledge-based, grant the |
|
🎉 This PR is included in superdoc-cli v0.22.2 The release is available on GitHub release |
|
🎉 This PR is included in superdoc-sdk v1.21.3 |
|
🎉 This PR is included in @superdoc-dev/mcp v0.17.3 The release is available on GitHub release |
|
🎉 This PR is included in superdoc v1.45.2 The release is available on GitHub release |
|
🎉 This PR is included in @superdoc-dev/react v1.16.2 The release is available on GitHub release |
|
🎉 This PR is included in vscode-ext v2.17.2 |
Summary
merge/main-into-stable-2026-08-02fromstablemaininto the candidate branchstableAuto-created by promote-stable workflow.