**Outcome:** Immediate failed-push recovery and a later observation can share
classification without sharing publication prerequisites.
1. Add `internal/publish/reconcile.go` with internal evidence, observation, and
recovery-error types corresponding to the public shapes specified in Stage 3.
Observation returns its state and available remote object/peeled-commit IDs.
Keep the original evidence separate from the observation.
2. Add an internal Git constructor for observing a captured endpoint. Accept
repository context, the exact endpoint string, and an optional original remote
name. Create a fresh command-scoped remote using the recorded URL for both
read and push URLs. Read the named remote's current supported transport
settings using the existing `transportConfig` path. An empty original name
uses endpoint/global configuration; it does not select `origin` implicitly.
3. Preserve `QueryTag`'s endpoint-resolution verification and exact full/peeled
ref handling. Reading transport settings requires no current fetch/push URL
equality check. Missing settings, including after a remote is renamed or
removed, permit observation; actual configuration-read failures retain their
causes. Reuse the supported transport keys already implemented.
4. Extract classification so the immediate path can supply its already captured
endpoint and transport settings. Keep `reconcilePush` as the publication
adapter: retain its existing detached, bounded recovery context, phase
transitions, and original push-error chain. A successful exact match still
resolves that push error. Successful pushes continue to return directly.
5. The later path uses the caller's context for configuration reads and the
observation. Use the evidence's `RepositoryDir` as Git working-directory
context; an empty value uses the caller's current directory. This preserves
the meaning of relative local endpoints in automatically captured records.
An unavailable recorded directory produces an unresolved observation with
actionable context. Recovery does not discover identity from current HEAD,
local tags, module files, profiles, or current remote URLs.
Use this classification order for later recovery:
| Evidence or observation | State and error behavior |
| --- | --- |
| Missing endpoint or full tag | `unknown`, with `missing_evidence`; list the missing fields and perform no remote query. |
| Invalid supplied full object ID or invalid Git tag ref | `unknown`, with `invalid_evidence`; perform no remote query. |
| Cancellation or deadline prevents completion | `unknown`, with `canceled` and the context cause. |
| Endpoint rewriting changes the captured URL | `unknown`, with `endpoint_changed`; do not query the substituted destination. |
| Transport-configuration read fails | `unknown`, with `transport_configuration`. |
| Query fails or returns unreadable evidence | `unknown`, with `remote_observation`. |
| Exact-ref records are inconsistent | `unknown`, with `inconsistent_observation`. |
| Full tag is authoritatively absent | `not_published`; the observation completed successfully, even if tag-object or candidate-commit evidence is missing. |
| Full tag is present and intended tag-object ID is missing | `unknown`, with `missing_evidence`, including when a commit matches. |
| Observed tag-object ID differs from the intended ID | `conflict`; include both IDs. |
| Tag-object IDs match and no peeled ref is available | `published`, preserving existing behavior. |
| Tag-object IDs match, a peeled ref is available, and candidate commit is missing | `unknown`, with `missing_evidence`. |
| Tag-object IDs match and the peeled commit matches the candidate | `published`. |
| Tag-object IDs match but the peeled commit differs | `conflict`; include expected and observed commit IDs as well as tag-object IDs. |
Reuse existing full SHA-1/SHA-256 ID and Git-ref validation through internal
helpers. Compare hexadecimal IDs by value, accepting their existing supported
letter cases; retain supplied evidence for reporting. Module/version labels and
recording time are context, rather than additional observation prerequisites.
Distinguish a positively invalid ref from tooling, directory, configuration,
or cancellation failures while checking it; operational failures retain their
appropriate unresolved cause. Expose the existing diagnostic formatter through
an internal Git helper for shared error/presentation use, preserving wrapped
causes and the current credential-redaction behavior.
For the later API, a completed observation of `published`, `not_published`, or
`conflict` returns a nil error. An unresolved observation returns an error and
its `unknown` result. The immediate publication adapter continues to preserve
the original push error for known absence/conflict and unresolved recovery.
**Verification:** Extend existing classification tests for the partial-evidence
matrix and expected/observed IDs. Reuse existing Git parser tests for unchanged
duplicate-ref and peeled-only behavior. Add focused Git-boundary coverage for
current transport settings, repaired settings, removed/renamed remotes, fixed
URLs, and configuration-read failure. Preserve the existing lost-acknowledgment,
rejected-push, endpoint-change, and cancellation behavior.
failure, cancellation, or failed/inconsistent observation using the typed
recovery error. Show expected and observed IDs for conflicts, including
commit evidence when that is what conflicts. Explain possible next actions
from known causes, without guessing that a generic Git failure is an
authentication or connectivity failure.
4. Human listing shows path, module identity, full tag, candidate commit, and
recording time when available. Show per-record diagnostics alongside usable
entries and make incomplete discovery clear. Distinguish an enumeration
failure from a successfully enumerated empty directory.
5. Implement explicit CLI JSON DTOs. After successful argument parsing,
`--json` writes one JSON document to stdout for success and failure paths;
normal usage/argument-parse errors retain the existing stderr behavior.
Use these fields, with `schema_version: 1` and the command name:
| Command | JSON fields beyond `schema_version` and `command` |
| --- | --- |
| `reconcile` | `record_path`, safe `evidence`, `state`, `observed_tag_object`, `observed_commit`, and `diagnostic` when unresolved or loading fails. Omit observation fields when loading failed. |
| `publication-attempts` | `record_dir`, `attempts` (each with `record_path` and safe `evidence`), `diagnostics`, and a top-level `diagnostic` for enumeration/cancellation failure. Arrays are present, including when empty. |
Safe evidence uses the Stage 2 snake-case field names with credential-safe
string displays. A diagnostic contains `kind`, `message`, `record_path` when
applicable, and `missing_fields` when applicable. Encode error text explicitly;
keep raw Go errors and private record JSON out of these DTOs. Apply existing
URL/diagnostic redaction before JSON encoding, including nested messages.
Raw endpoint preservation belongs only to private records and typed evidence.
Human and JSON output use the same state/diagnostic interpretation.
6. Use these process statuses and document their distinct meanings:
| Command/result | Status |
| --- | --- |
| Reconciliation confirms publication | 0 |
| Reconciliation observes absence or conflict | 1 |
| Reconciliation invocation, selected-record read, or format failure | 2 |
| Reconciliation remains unknown, including missing evidence or canceled observation | 3 |
| Discovery completes with readable entries and no diagnostics, including an empty existing store | 0 |
| Discovery is incomplete or fails, including cancellation | 1 |
| Discovery argument/usage error | 2 |
A nil Go observation error for absence/conflict still maps to CLI status 1.
Preserve the original context or filesystem cause in the API even when its
CLI status is an invocation classification.
**Verification:** Add parser/dispatch tests and command tests for human/JSON
state parity, exit classifications, mandatory selection, unusable records,
partial discovery, and credential redaction. Assert semantic fields rather than
complete diagnostic wording. Test paths with spaces/apostrophes and running
record-based recovery from another working directory. Verify these commands
work with a dirty worktree, changed branch/HEAD, removed or moved local tag,
and unavailable profile, with no candidate commands or hosted requests.
## Stage 7: Integrate publication's record override and recovery handoff
**Outcome:** The full feature works across process boundaries, with supported
contracts and a short consumer recovery workflow.
1. Add focused assembled tests for publication with a failed/interrupted push,
lost output followed by discovery, and a separate later recovery invocation.
Use a controlled local Git boundary to know when pre-push recording finished;
coordinate cancellation/interruption without arbitrary sleeps. Remove or move
the local tag and change branch, HEAD, remote URLs, or transport settings
before later recovery. Cover root/nested tags and original-record selection.
2. Establish read-only behavior through resulting refs, worktree/branch state,
saved records, and controlled observations of candidate/hosted boundaries.
Reuse lower-level classification and codec tests. Tests use local remotes,
temporary storage, synthetic credentials, and isolated environments; live
services and real credentials are unnecessary.
3. Update GoDoc for evidence, results, errors, request fields, and all new helpers.
Clarify existing publication-state comments where they currently describe
only successful pushes or a single invocation, while preserving those
states' established immediate-publication behavior.
4. Update documentation at its canonical owners:
| Owner | Change |
| --- | --- |
| `docs/cli.md` | New commands, flags, explicit selection, relative-path semantics, human/structured modes, and statuses; update the command inventory. |
| `docs/consumers/publish.md` | Automatic recording, separate recording failures, reusable typed evidence, loader/discovery use, optional later observation, storage placement/lifecycle, overrides, permissions, retention, and sensitive-data handling. |
| New `docs/integrations/publication-records.md` | Versioned private-record and CLI JSON formats and unsupported-format handling. Link to CLI/GoDoc for operation contracts and the publication guide for physical placement/lifecycle. |
| `docs/release.md` | Replace manual endpoint-copy/comparison instructions with explicit-record recovery and local discovery; describe lost/older evidence and unavailable original executable. |
| `docs/internal/overview.md` | Implemented observer, recording, discovery, facade, and CLI responsibilities; link to canonical formats and contracts. |
The runbook must explain that current absence does not prove a version was
never published or permit reuse of a known published version. Keep cleanup
and retry choices explicit and preserve immutable published tags/contents.
Storage failure loses the saved handoff, rather than changing the actual
publication outcome. Explain that direct typed evidence can still support
recovery when recording fails. Document the limits of abrupt process
termination before recording, removed storage, and older attempts lacking
sufficient retained identity. Later recovery adds no successful-publication
read-back, polling, CI, installation, or hosted-delivery gate.
5. Review examples, local links, fragment destinations, privacy language, and
consistency with the feature roadmap. Keep release-version selection and
tagging in later release preparation. Update any existing draft release note
only when its version/scope has been deliberately selected for this feature.
6. Once the assembled implementation is ready, run `go test ./...` and
`go run ./internal/apicheck` with the prepared compatible local Go toolchain
and offline dependencies. Run focused tests while implementing their owners;
reuse successful checks for unchanged content. Add targeted race detection
if new shared mutable state or concurrent record tests expose a distinct risk.
Finish with `git diff --check`, review all implementation/test/doc changes,
and complete the repository's normal commit discipline.
The sprint is complete when automatic API/CLI recording, direct and loaded
evidence reconciliation, partial local discovery, current transport settings
with fixed original endpoints, safe human/structured output, and the assembled
recovery workflow satisfy this plan and the feature roadmap. The final report
should identify implemented interfaces, validation results, and any remaining
limitations. Subsequent architecture review and release/testing decisions take