Record remaining recovery findings and recommended fixes

This commit is contained in:
2026-11-03 00:00:42 +00:00
parent 363f7cd513
commit 16d1c072e3

View File

@@ -1,12 +1,14 @@
# Publication reconciliation remediation
Status: complete. R01–R13 are addressed and individually verified. The full
offline suite (`go test ./...`) and compiled facade/dependency checks
(`go run ./internal/apicheck`) passed with Go 1.26.8 after remediation.
Status: open. R01–R13 are addressed and individually verified. R14–R17 record
remaining findings from the subsequent stage-by-stage review of `363f7cd`.
Address the two handoff defects first, then the classification and format gaps.
The findings describe commits `4dff808` through `599ad81`, against planning
baseline `447b42a`. Audit evidence and defect descriptions below refer to that
reviewed baseline; each completion marker records the implemented correction.
R01–R13 describe commits `4dff808` through `599ad81`, against planning baseline
`447b42a`. Their audit evidence and defect descriptions refer to that reviewed
baseline; each completion marker records the implemented correction. The full
offline suite (`go test ./...`) and compiled facade/dependency checks
(`go run ./internal/apicheck`) passed with Go 1.26.8 after that remediation.
The [feature roadmap](publication-reconciliation.md) defines the requested
behavior; the [implementation plan](implementation.md) supplies the intended
@@ -583,3 +585,189 @@ Handle zero-entry failures and cancellation consistently with R04. Add a narrow
fault-injected regression for entries-plus-error, verifying readable attempts,
retained causes, and API/CLI partial-result behavior. This concerns data
preservation, separate from R04's cancellation/error classification.
## Follow-up stage review evidence
The subsequent review examined all eight completed stages in the implementation
plan, including the R01–R13 corrections, at `363f7cd`. Existing tests for
classification, Git endpoints, records, public recovery, publication evidence,
discovery, CLI parsing/presentation, cold Go-tool handoffs, and the assembled
lost-output workflow passed with Go 1.26.8. The compiled facade/dependency checks
and local documentation link/fragment checks also passed.
Disposable local probes reproduced R14–R17 using temporary Git repositories and
Go source overlays. Repository production code and tests remained unchanged.
No additional defects were identified in Stages 3–6. Stage 8 needs regression
coverage for the cases below and plan wording aligned with the implemented
record and handoff decisions. Existing passing coverage does not establish
correctness for these additional combinations.
## R14: Support recovery for vendored API-only consumers — P2
**Relevant code:** `internal/gotool/recovery.go:95–107`; the command assembly in
`cmd/releasekit/main.go:126–145`. Affects Stage 7 and its Stage 8 coverage.
The API-only handoff prepares its private alternate module files with
`go list -mod=mod`, then prints a `go tool` command running from the consumer's
module directory. Go automatically selects vendor mode when that directory
contains a suitable `vendor` tree. An API-only consumer vendors its imported
library packages, so the CLI package can be absent from that tree.
**Evidence:** A temporary consumer imported ReleaseKit through its Go API,
vendored its dependencies, and used the current CLI for a locally rejected
publication. A complete record and recovery command were produced. Executing
the command failed before reconciliation with `import lookup disabled by
-mod=vendor`. Supplying `GOFLAGS=-mod=mod` also failed to change this Go-tool
behavior. Existing vendored-tool coverage uses an explicitly registered and
vendored CLI, which does not exercise this API-only case.
**Expected behavior:** A consumer's ordinary library vendoring remains compatible
with the supported API-only recovery handoff. The command observes the explicitly
selected record using the selected ReleaseKit dependency.
**Remediation:** Prepare the API-only Go-tool entry point in a private bootstrap
module root whose tool resolution is independent of the consumer's vendor tree.
Preserve the selected dependency graph, checksums, versioned replacements, and
the meaning of relative local replacements when relocating module metadata.
Keep source files and consumer vendoring intact, retain private storage handling,
and keep bootstrap ownership within ReleaseKit. Preserve registered-tool and
native entry points. Update Stage 7's handoff instructions to describe this
module-selected approach and the supported native fallback.
**Regression coverage:** Add an assembled API-only consumer that vendors the
library without a tool declaration. Execute the printed command from another
directory after publication and launcher cleanup; assert that reconciliation
runs against the saved identity and returns its expected state/status. Cover
relative local replacements and unchanged consumer source/vendor contents.
Retain existing cold-build, registered/vendored-tool, quoting, and status cases.
## R15: Preserve the recovery handoff after publication cancellation — P2
**Relevant code:** `cmd/releasekit/main.go:116–134`, especially the caller context
passed to `git.CommonDirectory`. Affects Stage 7 and its Stage 8 coverage.
Command preparation reuses the publication context after publication returns.
When cancellation caused the failure, that context is already canceled. The
metadata lookup fails immediately and the CLI prints `recovery command
unavailable`, even when it has saved the record and a usable native entry point
is available. The native fallback is reached only when module selection returns
no Go invocation; a preparation error bypasses it.
**Evidence:** A probe synchronized cancellation with a blocked tag push. The
publication returned status 1 after immediate reconciliation found the tag
absent. Standard error reported a saved record and an unavailable recovery
command, with no copyable handoff. This was cancellation during execution,
rather than termination before the record could be saved.
**Expected behavior:** An ordinary canceled publication with a saved record
retains a usable recovery entry point. Its preparation leaves the original
publication outcome, cause, and exit classification intact.
**Remediation:** Arrange handoff preparation so the failed publication's canceled
context does not prevent command construction. Prepare necessary durable launch
metadata before cancellation-sensitive publication work where appropriate, and
retain a usable native-command fallback when module-based preparation fails.
Account for cold Go-tool executables that disappear when the original driver
exits. Keep publication and later observation cancellation behavior from R04;
any separate post-failure preparation that performs subprocess work needs a
bounded lifetime. Update Stage 7 to cover cancellation and preparation failures.
**Regression coverage:** Cancel an actively blocked push after pre-push recording,
then execute the resulting command using a fresh invocation/context. Cover a
persistent native executable and supported cold Go-tool adoption paths after
launcher cleanup. Assert saved identity selection, unchanged publication status
and original cancellation cause, and preservation of immediate recovery's bounded
context. Coordinate the push boundary explicitly and retain the existing
no-recovery-step behavior for successful publication.
## R16: Classify endpoint setup failures by their actual cause — P3
**Relevant code:** `internal/publish/reconcile.go:116–128` and
`internal/git/remote.go`'s endpoint setup. Affects Stages 1 and 6.
An `ObserveEndpoint` error defaults to `endpoint_changed` when the evidence has
no original remote name. With a name, the fallback is `transport_configuration`.
The choice can therefore describe the presence of optional context rather than
the failure that occurred.
**Evidence:** A local checkout with malformed Git configuration and evidence
whose `Remote` was empty returned `unknown` with `endpoint_changed`. Its retained
cause was Git's bad-configuration error; no changed destination had been
established. CLI guidance consequently points the operator toward URL rewrite
settings despite the configuration-read failure.
**Expected behavior:** `endpoint_changed` identifies a positively detected
destination change. Configuration and other operational setup failures retain
an appropriate unresolved classification and their original causes, including
when the original remote name is absent.
**Remediation:** Distinguish setup failures at the internal Git boundary where
their source is known, then map them to the supported recovery kinds. Use the
existing endpoint-change sentinel for positively detected rewrites. Preserve
configuration/tooling causes through the facade and use the same interpretation
for human guidance and structured diagnostics. Clarify this mapping in Stage 1
and its Stage 6 presentation requirements using the existing recovery kinds.
**Regression coverage:** Exercise malformed local configuration with an empty
original remote name, a genuine rewrite mismatch, and a separate operational
setup failure at the Git boundary. Verify typed kinds, retained causes, unknown
state, and corresponding CLI human/JSON diagnostics. Keep remote queries from
reaching a substituted endpoint when a rewrite mismatch is detected.
## R17: Validate the documented version-2 byte-field representation — P3
**Relevant code:** `internal/publish/record.go:48–59`;
[private record format](../integrations/publication-records.md#private-attempt-record).
Affects Stage 2 and its Stage 8 format coverage.
Version-2 byte fields are documented as standard base64 strings. The loader
unmarshals each known field directly into `[]byte`; Go's JSON decoder also accepts
numeric arrays for that destination type. Consequently, an invalid structural
type under the documented format is silently treated as usable evidence.
**Evidence:** Both `"djEuMi4z"` and `[118,49,46,50,46,51]` as the value of
`evidence_bytes.tag` loaded as `v1.2.3` without a format error. The array case is
outside the declared representation. This is a format-validation gap; the probe
did not demonstrate altered bytes or an incorrect remote observation.
**Expected behavior:** Known byte fields follow the documented base64-string
representation. Structural and encoding failures return `record_format` with
their available causes. Supported partial evidence and ignored additional fields
retain their existing behavior.
**Remediation:** Decode known byte-field values as strings explicitly, then use
the standard base64 decoder to recover their bytes, preserving decoding causes.
Keep version-1 behavior and version-2 lossless identity from R10. Update Stage 2
to describe both supported versions and the writer's version selection, linking
to the canonical format definition.
**Regression coverage:** Add known byte-field cases for valid base64, malformed
base64, numeric arrays, and other invalid structural types. Assert typed format
errors and retained causes for invalid inputs. Reuse the existing all-field
round trips, non-UTF-8 endpoint observation, partial-evidence, and unknown-field
tests rather than duplicating their fixtures.
## Implementation plan and verification follow-through
When implementing R14–R17, update [implementation.md](implementation.md) alongside
the corresponding changes:
- Stage 1: record the cause-based endpoint setup classification from R16.
- Stage 2: describe ordinary version-1 records and version-2 byte-preserving
records, including the structural validation from R17.
- Stage 6: align typed failures, human guidance, and structured diagnostics with
R16; retain the implemented JSON output-failure handling from R06.
- Stage 7: replace the original executable-only handoff instructions with R07's
module-selected/durable API-only approach, extended for vendoring and
cancellation by R14 and R15. Retain a usable native fallback and explicit
record selection.
- Stage 8: add the regression coverage assigned above, update affected canonical
documentation as behavior lands, and run the offline suite and compiled
facade/dependency checks after assembly. Review local links and prose changes.
Preserve earlier completion evidence and distinguish these follow-up corrections
from the original completed implementation. Add completion markers as the new
issues are addressed. The corrections retain the existing public facade,
publication completion point, separate recording failures, and operator-owned
recovery choices; they introduce no consumer pilot, intermediate release, or
external review gate.