Draft: feat(publish-confluence): export documentation to Confluence
Plan
- Stage the complete documentation tree and related material with deterministic source identities and explicit MDX handling.
- Normalize Docusaurus routes and connect the pinned Confluence publisher with persistent remote page identities and non-destructive attachment/comment settings.
- Add mocked API coverage, component documentation and required dedicated xrow-site publication/readback, including repeated publication.
Closes #444
Delivered foundation
- Added a standalone staging adapter preserving nested Markdown and material, plus a deterministic source/hash manifest.
- Unhandled MDX fails before creating output; an explicit Markdown replacement retains the original MDX source identity. Symlinks, path collisions, unknown mappings and existing destinations are rejected.
- Six local regressions pass and are wired into the catalog's required Bash regression discovery.
- A current-source smoke test stages all 32 files as 15 pages and 17 material files with an explicit Changelog representation; repeated manifests are identical. This checks staging only: route normalization, dynamic release-content expansion and remote publication are not implemented or claimed.
Acceptance criteria
- Complete nested source/material staging and explicit, fail-closed MDX handling.
- Route normalization without disabling strict URL validation; complete Changelog representation.
- Component inputs, pinned publisher and persistent source-to-page identities.
- Repeated publication preserves managed identities and unrelated attachments/comments/content state.
- Mocked API create/update, hierarchy, links, attachments, pagination and error coverage.
- Required current-docs export to the configured dedicated subtree on https://xrow.atlassian.net/ and verified readback/re-export.
- Documentation, required CI and final DoD complete before review.
This is a draft implementation increment. No Confluence API calls or site writes have occurred. Availability of CI credentials is not yet verified; the required token remains ATLASSIAN_TOKEN.
Closes #444
Complete source preparation increment
Connected full-tree staging to strict Markdown-AST URL normalization in d3b57b06, after rebasing onto current main. Inline/reference/image links and HTML URL attributes resolve explicitly; front matter, source identities and literal nested code fences are preserved. Unknown routes fail before a partial output tree is published. The explicit Changelog expander retains the complete captured release window, descriptions, assets and original all-releases link; its snapshot URL must match the source component.
All 23 local regressions pass through the required isolated-parser test entrypoint. The current documentation tree prepares all 15 pages and 17 material files, including the 100 releases returned by the source Changelog URL. Pinned markdown-to-confluence==0.6.5 converts all 15 pages locally with strict URL validation; two independent preparations/conversions produce byte-identical storage-format output. This is conversion evidence only, not remote publication or persistent Confluence identities.
Both work-CI slots are occupied and the CI Tools default-branch guard is not clear, so complete current-head CI is deferred without an overlapping dispatch. Decision: preserve draft/no reviewers and continue independent publisher integration. Component inputs, persistent remote page IDs, non-destructive synchronization, mocked API coverage and dedicated xrow-site publish/readback remain unfinished.
Scoped identity preparation increment
Added a local-only publication-state adapter in b853c516, after rebasing the existing work onto current main. It binds saved source and generated-directory page IDs to the exact domain, space, dedicated parent and source key. Missing state never initializes a new publication implicitly. Partial captures preserve known/retired IDs without claiming success; conflicting IDs, target changes, directory content and symlink aliases fail closed. State replacement is atomic under a local writer lock.
The pinned publisher's real metadata writer/parser and CLI parser are used by regressions. Explicit options retain unreferenced attachments, inline comments and content state, disable manual-content overwrite and notifications, preserve hierarchy/page IDs and keep strict URL validation. Generated directory titles use the complete source-relative identity: real current-docs conversion caught duplicate images basenames before that correction.
All 35 local regressions pass. Two fresh offline exports of the actual 15-page/17-material input reuse all 19 synthetic fixture IDs (including four generated directories) and yield identical 19-page storage-format output. These are explicitly offline fixture IDs, not remote Confluence identities or publication evidence. Bash syntax and whitespace pass.
No Confluence API calls or site writes occurred. The helper does not publish: remote ancestry/ownership preflight, safe first-publication initialization, durable CI-state integration, component inputs, all-material synchronization and dedicated xrow-site publication/readback remain unfinished. Existing source documentation is untouched.
Replacement full CI also remains gated: prior root 2999362908 returns HTTP 404, and the MR pipeline listing contains only the two skipped source pipelines. This is incomplete lifecycle evidence, not proof that all previous children/resources drained. Do not dispatch overlapping CI or declare DoD from it. Draft and reviewer choices are preserved.
Remote-scope validation primitive
Added eadae217 on current main, with eight additional mocked-reader regressions (43 total). The primitive requires an exact dedicated-parent publication ownership marker, matching space, unique current page IDs and bounded parent chains reaching that parent. It refuses cross-space/archived/out-of-subtree pages, cycles, mismatched ownership, incomplete property containers and reader failures. It re-reads all page witnesses and parent ownership to refuse concurrent moves or changes without mutating local state.
This is an injected-reader boundary, not an implemented HTTP transport or live Confluence proof. Exact-domain authenticated GET readers, complete property pagination, safe first-publication initialization, durable CI state, component wiring, all-material synchronization and dedicated-site publish/readback remain unfinished. No Confluence API calls or site writes occurred.
The prior CI root 2999362908 still returns HTTP 404, so its terminal lifecycle/children cannot be established. Current main's failed build:ubi trace is a registry signing-layer BLOB_UPLOAD_UNKNOWN; other failed main jobs report Runner configuration errors. No repository-source defect was established, no default-branch pipeline was retried, and no overlapping MR pipeline was dispatched. Keep the MR draft with no reviewers; independent integration remains runnable despite the CI pause.
Exact-domain Cloud GET transport
Published d28dbea2 after a current-main rebase: the existing dedicated-subtree preflight now has opt-in authenticated Confluence Cloud v2 GET readers. They bind credentials to the exact HTTPS Cloud domain and page/space/property endpoint, reject redirects, and fully collect ownership properties through body or Link-header pagination, including multiple header fields. Repeated/conflicting cursors or property identities, malformed/incomplete responses and exhausted pagination bounds fail without partial success. HTTP errors withhold credential-bearing URLs, response bodies and exception details. The restore/capture CLI remains local-only; no publishing or state initialization is added.
All 51 Confluence regressions pass, including eight new reader cases, real urllib redirect processing without network access, header-only continuation, cross-origin/downgrade refusal and transport-backed ancestry preflight with unchanged local state. Comparison against the preceding source reports no new Ruff diagnostics; three pre-existing diagnostics remain. Final diff/whitespace checks and exact-source GitLab CI compilation pass; existing duplicate-pipeline warnings remain visible.
These are mocked-transport/compiler checks, not a live xrow-site preflight or publication. No Confluence API request or site write occurred. Safe first-publication initialization, durable CI identity-state integration, component wiring, complete material synchronization, dedicated-site publication/readback and complete required CI/DoD remain unfinished. The prior unavailable CI lifecycle is still unresolved and both work-CI slots are active, so no replacement root or reviewer request was made. Keep draft/paused.
Explicit read-only CLI preflight
Added an explicit read-only CLI preflight at source 388f94ac, after rebasing onto delivered main. All six earlier commits remain patch-equivalent. The command validates the complete local restoration plan, then uses the existing exact-domain Cloud GET readers and environment-only ATLASSIAN_EMAIL / ATLASSIAN_TOKEN. Prepared files and saved identities remain unchanged. Restore/capture remain local-only, and missing state never initializes a publication.
All 57 Confluence regressions pass, including six real-main/transport boundary cases for successful scoped GETs, local identity conflicts, absent state/credentials, remote ownership refusal and local-only restore/capture. Changed-file Ruff, whitespace and actual CLI help checks pass. Exact-source GitLab compilation is valid; existing duplicate-pipeline warnings remain visible.
This is mocked-reader/source evidence, not live tenant preflight, publication or content/material readback. First-publication initialization still needs an explicit non-adoption contract: Atlassian's children API returns only content visible to the caller, so an empty list must not be treated as proof of an empty subtree or permission to recreate lost identities.
Durable CI identity-state integration, safe initialization, component/publisher wiring, complete material synchronization, dedicated-site publish/readback and complete required CI/DoD remain unfinished. Both work roots are active; the push skips CI and no third root, reviewer or live site request was introduced. The earlier unavailable lifecycle is not claimed as verified. Keep draft/paused.
New-subtree initialization primitive
Published 6dcf538c with an explicit new-subtree initialization primitive. It creates a fresh nonce-named child through an injected writer, not by adopting an existing page or inferring emptiness from permission-filtered child listings. The exact domain/space/parent/source scope is rechecked before writes; only the returned new child may receive the ownership marker. Existing content is never deleted or reused.
A private, fsynced initialization receipt is reserved before creation and records the returned page ID before marking it. Ambiguous responses, failed marking and readback changes preserve that receipt and refuse automatic retries. Identity state is atomically published without replacing a competing state file, only after ownership/readback succeeds. This is publication-product identity storage, not agent queue or cycle state.
All 67 Confluence regressions pass, including ten new initialization cases for lost responses, marker failure, duplicate ownership, wrong/changed scope, existing state/receipts/symlinks, parent reuse, concurrent moves and a noncooperating state writer. Ruff comparison introduces zero new diagnostics; the same seven pre-existing diagnostics remain visible. The two-file diff, whitespace and no-op current-main rebase are reviewed; exact-source GitLab compilation is valid with the existing duplicate-pipeline warnings.
This is an injected-writer source primitive, not a wired HTTP writer/CLI or live initialization/publication. Existing CLI preflight stays GET-only and missing state still refuses implicit initialization. HTTP/CLI write integration, durable CI receipt/state retention, component/publisher wiring, full material synchronization and dedicated-site publication/readback remain unfinished. No tenant API request, live content write, extra CI root or reviewer request was made. Complete required CI/DoD and the earlier unavailable lifecycle remain unverified; keep draft/paused.
Explicit Cloud initialization path
Published e8c95e7d, wiring the new-subtree primitive to an explicit initialize CLI action and exact-domain Confluence Cloud v2 HTTP creates. The adapter permits one new-child create and one exact ownership-property create for its returned ID; it has no update/delete or automatic write retry. Redirects, denied/malformed responses and ambiguous create failures fail with authenticated details withheld. Local prepared-page validation precedes credential/transport use.
All 76 Confluence regressions pass, including actual HTTP-adapter-to-initialization/readback integration and real-main CLI cases. The new CLI refuses existing state or unmanaged prepared IDs, returns the new target scope and leaves source/prepared files unchanged. The actual rendered --help example is inspected; state/receipt durability and the distinction between initialization and documentation export are stated beside the command. Changed-file Ruff adds zero diagnostics against the same seven inherited findings. Final two-file diff/whitespace and exact-source GitLab compilation pass; existing duplicate-pipeline warnings remain visible.
The create contracts were checked against Atlassian page creation, property creation and its current OpenAPI schema. All execution here is local/mocked: no tenant API call, page creation or documentation publication occurred.
Remaining: durable CI state/receipt retention and explicit interrupted-create recovery, component/publisher integration, complete material synchronization, dedicated-site initialization/publication/readback and complete required CI/DoD. Existing restore/capture stay local and preflight stays GET-only; no missing-state fallback was introduced. Both permitted work roots are active, and the earlier unavailable lifecycle is still not represented as inspected or absent. Keep draft/paused without reviewers; no extra CI root or live site write was made.