Plan read-only publication reconciliation
This commit is contained in:
225
docs/roadmap/publication-reconciliation.md
Normal file
225
docs/roadmap/publication-reconciliation.md
Normal file
@@ -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.
|
||||
Reference in New Issue
Block a user