From e0bf5ca57a915bf814e98dd6770fe2e88f3c0f83 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Mon, 2 Nov 2026 16:50:16 +0000 Subject: [PATCH] Plan read-only publication reconciliation --- docs/roadmap/publication-reconciliation.md | 225 +++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 docs/roadmap/publication-reconciliation.md diff --git a/docs/roadmap/publication-reconciliation.md b/docs/roadmap/publication-reconciliation.md new file mode 100644 index 0000000..ca07aab --- /dev/null +++ b/docs/roadmap/publication-reconciliation.md @@ -0,0 +1,225 @@ +# Roadmap: read-only publication reconciliation + +Status: planned capability; recommendations under Open Decisions await resolution. + +## Purpose + +Let maintainers revisit a failed or uncertain source-publication attempt through +one ReleaseKit operation. PromptKit currently copies the endpoint checks, exact +tag query, and result interpretation into its runbook. ReleaseKit should own +these mechanics and the handoff of original attempt evidence. + +The target includes a public Go API and a CLI command with equivalent behavior. +This roadmap describes the end state and required work, without selecting a +release version or prescribing a staged implementation plan. + +## Current baseline + +The current checkout contains the v0.7.0 release notes and publication workflow. +The [publication guide](../consumers/publish.md) describes existing outcomes; +the [maintainer runbook](../release.md#resolve-failures) describes manual recovery. + +- `PublicationResult` supplies the repository and module identity, semantic + version, full tag, candidate commit, captured endpoint, tag object when known, + phase, and publication state. Its endpoint can contain credentials. +- Internal `reconcilePush` makes a bounded authoritative observation after a + failed push. It compares the annotated tag object and available peeled commit + evidence, returning published, absent, conflicting, or unknown outcomes. +- `internal/git.Endpoint.QueryTag` verifies the captured endpoint's scoped URL + resolution before querying the full tag and peeled ref. Inconsistent exact-ref + records remain unresolved. +- The CLI masks HTTP(S) endpoint userinfo in diagnostics. The runbook still asks + maintainers to copy the displayed endpoint and compare remote object IDs. +- There is no public operation or CLI command for later reconciliation, and no + reusable CLI attempt record for preserving the exact transport endpoint. + +These existing observations and classifications provide the implementation +foundation. The main additions are a reusable operation, original-evidence +handoff, and documented operator and automation interfaces. + +## Targeted end state + +After connectivity or authentication is restored, a maintainer can give +ReleaseKit the original publication evidence and receive a fresh observation +of that attempt's destination and full tag. Library consumers use typed evidence; +CLI consumers use a record produced by ReleaseKit without parsing diagnostics. + +| Observation | Reconciliation outcome | +| --- | --- | +| Intended annotated tag object, with consistent available commit evidence | Published | +| Authoritative full tag absent | Not published | +| Different tag object, including one pointing at the same commit | Conflict | +| Observation failure, inconsistent records, or insufficient original evidence | Unknown | + +The implementation preserves existing exact-object semantics, including current +handling of an unavailable peeled ref. A matching commit alone is insufficient. +Absence describes the current observation; it does not establish that the tag +never existed. A record identifies the intended attempt and is not proof that a +push happened or that the remote accepted it. + +Reconciliation uses the original captured endpoint and full tag, including nested +module prefixes. It checks that URL rewriting still permits observation of that +endpoint. A changed remote configuration does not substitute a new destination. +Authentication remains locally supplied through the supported Git mechanisms. + +The operation observes remote state without creating, pushing, moving, or +deleting tags, changing branches, validating a candidate, or delivering hosted +content. Current branch, worktree cleanliness, and current `HEAD` do not need to +match publication prerequisites. Repository context may still be used for Git +configuration and authentication. Corrective actions remain explicit. + +Successful source publication retains its existing completion point. Later +reconciliation is an optional recovery operation, with no routine read-back, +polling, CI, consumer-installation, or delivery gate. + +## Work needed + +### 1. Extract a shared observation and classification path + +**Rationale:** Immediate and later recovery should interpret the same evidence +consistently. + +**Target:** A reusable internal operation observes the captured endpoint and +classifies its exact tag using the existing publication semantics. + +**Work:** Separate remote observation and classification from the original push +error and publication orchestration. Reuse the scoped endpoint and exact-ref +query behavior. Keep immediate failed-push reconciliation bounded and preserve +its existing error context. Later reconciliation should honor caller cancellation +and return an unresolved outcome when observation cannot complete. It should not +invoke the current-remote equality guards that belong to an active publication. + +### 2. Define public evidence and reconciliation results + +**Rationale:** Consumers need supported types for recovery instead of rebuilding +internal Git behavior or parsing diagnostic strings. + +**Target:** A root-facade operation, provisionally `ReconcilePublication`, accepts +original evidence and returns a useful observation with preserved error causes. + +**Work:** Define the minimum evidence needed for each classification: captured +endpoint, full tag, intended tag object, and candidate commit as applicable. +Carry module/version information for operator context. Reuse existing publication +state meanings while distinguishing the original attempt from the new observation. +Define behavior for incomplete evidence and unsupported record formats without +inferring missing identity from today's remote, tag, or profile. A deleted or +moved local tag should not invalidate otherwise sufficient retained evidence. + +Keep facade ownership and internal Git boundaries. Exact type names, field names, +and signatures belong in API design; no new public implementation package is +needed for this feature. + +### 3. Provide a practical attempt-evidence handoff + +**Rationale:** Redacted diagnostics are useful displays but cannot reliably carry +the original transport URL into a later process. + +**Target:** The CLI can retain and read a small versioned record containing the +original evidence. Library consumers can retain equivalent typed data. + +**Work:** Capture evidence when the endpoint and tag object are established, +before attempting the push. Preserve useful partial evidence if an earlier stage +fails, clearly identifying what is missing. Make record production and loading +available through supported interfaces. Keep original identity separate from +later observations and avoid replacing one attempt's evidence with another's. +Resolve persistence defaults and sensitive-data handling below before defining +the storage contract. Use ordinary file handling proportionate to recovery; +this feature does not require a transactional journal or power-loss guarantees. + +### 4. Expose recovery through the CLI and documentation + +**Rationale:** A single command should replace copied query and comparison steps. + +**Target:** A command provisionally named `reconcile` reads an attempt record and +reports the outcome, selected full tag, intended identity, and actionable cause +context. Automation has a documented structured result and exit behavior. + +**Work:** Map the command to the facade, retaining credential-safe displays and +errors. Document valid invocation, missing or unreadable records, unknown +observations, and cancellation. Replace the runbook's manual endpoint-copy +procedure with this workflow and a concise link from consumer guidance. Explain +how maintainers retain records and deliberately address absence or conflicts. +Keep the distinction between source publication and hosted delivery explicit. +Document recovery limits for older attempts that lack sufficient saved evidence. + +### 5. Verify recovery behavior and integration + +**Rationale:** Incorrect recovery can direct corrective action at the wrong +repository or mistake a different annotated tag for the intended release. + +**Target:** Behavioral coverage establishes equivalent immediate/later +classification and useful recovery across process boundaries. + +**Work:** Use temporary Git repositories and local remotes to cover exact matches, +absence, different objects at the same commit, root and nested tags, changed +current remotes, rewriting that redirects the captured endpoint, inconsistent +observations, unavailable remotes, and cancellation. Test record round trips, +partial evidence, private storage behavior, and redaction with synthetic +credentials. Exercise recording before a failed or interrupted push and a later +invocation after local branch or tag state changes. Verify the diagnostic +operation performs no publication or cleanup actions and runs no candidate tests. +Reuse existing tests for unchanged Git behavior rather than duplicating them. + +Run the normal offline suite and facade checks when code lands. Update GoDoc, +CLI documentation, the publication guide, and recovery instructions together. +Any release-policy clarification should describe later optional recovery without +adding checks to successful publication. This roadmap itself changes no code. + +## Open Decisions + +### 1. How should the CLI persist attempt records? + +**Recommendation:** Retain records automatically in private repository-local Git +metadata, outside the tracked worktree, with a distinct record for each attempt. +Report the record path and allow explicit selection for reconciliation. Record +evidence before the push once the necessary identity exists. Treat storage +failure as a clearly reported loss of the saved handoff, while preserving the +actual publication result and existing publication prerequisites. + +This removes a routine setup decision and keeps records out of commits. The +tradeoffs are local metadata accumulation and possible loss of recovery evidence +when storage fails or the checkout is removed. Document retention and manual +removal; automatic cleanup is not required for the initial capability. + +**Alternative:** Require an explicit output path to enable recording. This makes +persistence deliberate and works naturally with caller-managed storage. It adds +launcher configuration and offers no durable handoff when a maintainer forgets +the option. A requested write could fail before the push if the caller requires +that handoff, but such behavior would need an explicit interface contract. + +### 2. How should a record represent credential-bearing endpoints? + +**Recommendation:** Preserve the exact captured endpoint in the private record, +with owner-only access using platform-supported file permissions. Continue +redacting endpoint credentials in human and machine diagnostic output; expose +only the record location for the handoff. Prefer locally supplied Git credentials +in adoption guidance. Treat exports and copies of the record as potentially +sensitive, just like the existing API result's endpoint. + +This supports existing publication configurations without reconstructing an +endpoint from its display. It also places potentially sensitive material on disk; +permissions and clear documentation reduce accidental exposure but do not promise +encrypted storage or protection from other processes running as the same user. + +**Alternative:** Store a credential-free endpoint and obtain authentication only +through local mechanisms. This reduces secrets in records, but stripping userinfo +can affect transport identity and rewriting. Adopting it requires a deliberate +endpoint-identity contract and migration guidance for credential-bearing URLs. +It cannot simply use the existing redacted display as a transport URL. + +### 3. What should automation receive? + +**Recommendation:** Offer human-readable output by default and a structured mode +with redacted identity, reconciliation state, and cause information. Use success +for confirmed publication, a non-success classification for absence/conflict, +and distinct unknown and invocation-error classifications, following the existing +CLI conventions where practical. Define exact numeric codes during CLI design. + +This makes shell recovery straightforward and keeps structured state authoritative +for detailed consumers. The tradeoff is that a successful observation of absence +still yields a non-success process status; document that distinction explicitly. + +**Alternative:** Return success for every completed observation, including +absence and conflict, and require automation to read the structured state. This +cleanly separates query execution from publication outcome, but a simple exit-code +check could be mistaken for confirmation that publication succeeded.