20 KiB
Roadmap: read-only publication reconciliation
Status: planned capability; storage, selection, credential handling, and output decisions resolved.
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 describes existing outcomes; the maintainer runbook describes manual recovery.
PublicationResultsupplies 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
reconcilePushmakes 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.QueryTagverifies the captured endpoint's scoped URL resolution before querying the full tag and peeled ref. Inconsistent exact-ref records remain unresolved.- The temporary remote carries selected remote-specific transport settings, including proxy, upload-pack, and server options, alongside the captured URL.
- 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. Both Go API and CLI publication automatically retain attempt records through the shared publication path. Recovery selects a stored record explicitly; Go callers may also supply sufficient retained typed evidence directly. Maintainers can discover saved attempts through a local, read-only listing when the original publication output is unavailable. Discovery leaves record selection explicit.
| 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 original remote name is optional transport context. Later reconciliation uses its current supported transport settings while keeping the recorded endpoint fixed, allowing operators to repair local configuration before observation.
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. Read the supported transport settings using the recorded remote name when available, and apply them to the temporary remote with the recorded endpoint. Keep the endpoint-resolution check. Missing remote settings permit observation with available endpoint/global configuration; configuration-read failures remain unresolved with their causes. Distinguish these cases from a changed destination.
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. Expose the saved record location and any recording failure separately from the publication outcome. Accept retained typed evidence directly for reconciliation so observation does not depend on filesystem persistence. Return a single facade-owned evidence value from publication that reconciliation accepts directly. Provide a supported record-loading helper returning that same type so Go consumers can recover without copying fields or implementing JSON parsing. Include the original remote name as optional context in typed evidence and saved records. Recovery uses current connection settings rather than a stored snapshot of transport configuration; the recorded endpoint retains its identity role.
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: Shared publication automatically retains a small versioned record for both Go API and CLI consumers. Library callers receive typed evidence, record location, and recording-failure information; the CLI presents that result.
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. Implement automatic private storage with an optional path override and the sensitive-data handling recorded below. Use ordinary file handling proportionate to recovery; this feature does not require a transactional journal or power-loss guarantees. Keep recording inside the shared publication path so library callers receive the same default and optional path override without consumer-owned hooks.
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 explicitly selected
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. During publication, print a copyable recovery command when a saved record is available and recovery is relevant. Include the explicit record path, with appropriate argument quoting, and preserve credential-safe output. Select the record supplied by the caller rather than inferring the latest attempt.
Add a local, read-only attempt listing for the default or explicitly selected storage location. Show each record's path, module, full tag, candidate commit, and recording time when available, with credentials redacted. Record the time as discovery metadata; it does not establish whether a push occurred. Listing reads saved records without querying remotes or choosing an attempt for recovery. Include discovery in the recovery guide for interrupted processes and lost output. Return readable attempts alongside per-record diagnostics for unreadable, malformed, or unsupported-format records. Identify the affected paths and retain credential redaction. Expose entries and diagnostics to Go callers and structured output; the CLI shows usable entries and indicates incomplete discovery. Report failure to enumerate the storage location as a discovery failure, not an empty collection. An explicitly selected unreadable or unsupported record produces its own error without selecting a different attempt.
Make unresolved diagnostics identify missing evidence, unreadable records, endpoint rewriting, and failed remote observation distinctly. Identify the specific missing information or configuration issue when known and explain the next useful operator action. For conflicts, show expected and observed tag-object IDs. Preserve cause information without guessing whether a transport failure is an authentication or connectivity problem. Apply these diagnostics to human and structured output while leaving corrective actions explicit.
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, default and overridden storage paths, storage failures, private storage behavior, and redaction with synthetic credentials. Cover automatic recording through both API and CLI publication, direct typed-evidence recovery, and explicit selection among records for multiple modules and retries. Verify that recording failure remains separate from publication outcome and that the printed recovery command selects its original record. 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. Verify that publication and record loading yield evidence directly usable by the Go reconciliation API. Cover discovery across modules and retries, default and overridden storage locations, partial records, and credential redaction. Verify that listing performs no remote observation or automatic attempt selection. Cover the diagnostic distinctions and expected/observed conflict identities without requiring incidental error wording. Cover current remote-specific transport settings, repaired configuration, missing or renamed remotes, and configuration-read failures. Verify that changed fetch or push URLs do not replace the recorded endpoint and that endpoint rewriting still receives the existing check. Exercise discovery containing both readable and damaged or unsupported records, storage-enumeration failure, and explicit selection of an unusable record. Preserve useful partial discovery results and credential-safe diagnostics across the API and CLI.
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.
Resolved decisions
1. Automatic storage with an optional path override
Retain records automatically in private repository-local Git metadata by default, outside the tracked worktree, with a distinct record for each attempt. The standard location should serve nearly all consumers without configuration. Provide an optional storage-path override for consumers with particular needs. Apply the same record handling and privacy behavior at either location; exact configuration syntax belongs in interface design.
Automatic recording belongs in the shared publication path for both Go API and CLI callers. Publication results expose the saved record location and any recording failure separately from the publication outcome. The library returns this information and the CLI presents it.
Report the record path and require explicit selection for stored-record 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. An override changes the location, not publication's response to a recording failure.
Automatic storage removes a routine setup decision and keeps default records out of commits. Records accumulate locally, and recovery evidence can be lost when storage fails or its location is removed. Document retention and manual removal, including the sensitive nature of records at overridden locations. Automatic cleanup is not required for the initial capability.
2. Preserve the exact endpoint in private records
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.
3. Human-readable and structured outcomes
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. A successful observation of absence still yields a non-success process status; document that distinction explicitly.
4. Explicit attempt selection
Reconciliation of a stored attempt requires an explicit record path. This keeps selection unambiguous across modules, retries, and changed repository state. When a record is available and recovery is relevant, publication prints a copyable command selecting that record. Automatic selection of the latest record is outside this workflow.
Go callers may instead reconcile sufficient retained typed evidence directly. Explicit stored-record selection does not make filesystem storage a prerequisite for the observation API.
5. Recovery ergonomics
Provide local attempt discovery to recover the record path after an interrupted process or lost publication output. Listing exposes useful, credential-safe identity and recording metadata while preserving explicit selection.
Publication returns one reusable typed evidence value. Reconciliation accepts that value directly, and the supported record loader returns the same type. These interfaces keep evidence transfer and serialization mechanics in ReleaseKit.
Diagnostics distinguish missing evidence, unreadable records, endpoint rewriting, and failed remote observation, and identify useful next actions when known. Conflict output includes expected and observed tag-object IDs. This makes recovery actionable while preserving the existing outcome classifications and explicit corrective-action workflow.
6. Current transport settings with a fixed recorded endpoint
Record the original remote name as optional transport context. During later reconciliation, read its current supported transport settings and use them with the exact recorded endpoint. The remote's current fetch and push URLs do not replace that endpoint. Retain the existing check that URL rewriting leaves the recorded endpoint unchanged.
A missing or renamed remote alone does not invalidate the evidence. Observation can use available endpoint/global configuration; operators may restore required settings locally. Configuration-read failures and failed observations remain unresolved with cause information. This separates original publication identity from repairable connection settings without snapshotting transport configuration.
7. Discovery preserves readable attempts
An unreadable, malformed, or unsupported record produces a diagnostic while other readable attempts remain discoverable. Results expose both entries and per-record diagnostics, identifying affected paths with credential-safe output. The CLI presents usable entries and makes incomplete discovery clear.
Failure to enumerate storage is a discovery failure rather than an empty result. Explicit reconciliation of an unusable record reports that record's error and retains the caller's selection. Discovery and record errors do not authorize automatic selection or corrective actions.