Documentation
¶
Overview ¶
Package mergeack owns the on-disk shape, identity hash, and full validation of a worktree-merge absorbed-conflict acknowledgement -- the sidecar `wb worktree merge acknowledge-absorbed-conflict` writes next to a worktree-merge receipt whose every receipted source worktree is gone, once each source's content is proved already reachable from the current remote target.
It is a leaf package: it imports nothing from internal/orchestrate or internal/worktrees, so both can depend on it without cycling. Both callers used to carry their own copy of this logic -- internal/orchestrate wrote and richly validated it, internal/worktrees re-validated a much smaller subset when deciding whether to accept an acknowledgement as cleanup landing proof -- which let a hand-edited sidecar with fabricated or emptied proofs slip past the weaker copy. This package is now the single source of truth for both the format and the validation, so a real sidecar written by internal/orchestrate validates byte-identically here, and a tampered one is rejected the same way regardless of which caller reads it.
Index ¶
- Constants
- func ComputeID(ack Acknowledgement) string
- func FileSHA256(path string) (string, error)
- func IsDerivedPathAllowed(path string) bool
- func Path(receiptPath string) string
- func Persist(path string, ack Acknowledgement) error
- func Same(left, right Acknowledgement) bool
- func SameSources(left, right []Source) bool
- type Acknowledgement
- type PathProof
- type ReceiptIdentity
- type Source
- type SourceProof
Constants ¶
const FileSuffix = ".absorbed-conflict.ack.json"
FileSuffix names the sidecar file relative to its receipt's own path: `<receipt path><FileSuffix>`.
const SchemaVersion = 1
SchemaVersion is the current on-disk schema for Acknowledgement. There is exactly one definition of it in the whole module -- here -- so it can never drift between callers.
const Status = "absorbed_conflict_acknowledged"
Status is the only status value a valid Acknowledgement carries.
Variables ¶
This section is empty.
Functions ¶
func ComputeID ¶
func ComputeID(ack Acknowledgement) string
ComputeID hashes every recorded field of ack (excluding RecordedAt, which carries no evidentiary weight) into its content-addressed ID, including Actor and Reason -- a tamper that only rewrites who acknowledged it, or why, must still invalidate the ID. Same, below, compares evidence without Actor/Reason/ID/RecordedAt instead, so a genuine retry that repeats the same receipt, target, and per-source proof is still recognized as the same acknowledgement even when the operator supplies a different actor or reason on the replay.
func FileSHA256 ¶
FileSHA256 hashes path's current bytes -- the same plain SHA-256 an Acknowledgement's ReceiptSHA256 binds to its receipt's exact, unchanged bytes.
func IsDerivedPathAllowed ¶
IsDerivedPathAllowed narrowly allows the one derived-index shape this recovery may excuse: a generated spec/**/README.md listing index, exactly "README.md" nested anywhere under a repo-root "spec/" directory. Chosen over "any README.md the receipt's sources changed" because that would let an operator excuse an unrelated hand-authored README.md merely for appearing in this receipt; this shape check binds to the generated-index location instead, regardless of receipt contents.
func Persist ¶
func Persist(path string, ack Acknowledgement) error
Persist atomically writes ack to path (create-temp, fsync, rename), the same durability shape every other WB receipt/sidecar uses.
func Same ¶
func Same(left, right Acknowledgement) bool
Same compares only the immutable proof evidence two acknowledgements carry, deliberately excluding Actor/Reason/ID/RecordedAt: a retry that repeats the same receipt, target, and per-source proof is idempotent even when the operator supplies a different actor or reason on the replay.
func SameSources ¶
SameSources reports whether left and right name the same sources, in the same order, by task/worktree/branch/SHA.
Types ¶
type Acknowledgement ¶
type Acknowledgement struct {
SchemaVersion int `json:"schema_version"`
ID string `json:"id"`
Status string `json:"status"`
ReceiptPath string `json:"receipt_path"`
AcknowledgementPath string `json:"acknowledgement_path"`
ReceiptID string `json:"receipt_id"`
ReceiptSHA256 string `json:"receipt_sha256"`
ReceiptStatus string `json:"receipt_status"`
Lane string `json:"lane"`
Repository string `json:"repository"`
Target string `json:"target"`
ReceiptTargetSHA string `json:"receipt_target_sha"`
CurrentTargetSHA string `json:"current_target_sha"`
CandidateTask string `json:"candidate_task"`
CandidateWorktree string `json:"candidate_worktree"`
CandidateBranch string `json:"candidate_branch"`
CandidateSHA string `json:"candidate_sha,omitempty"`
Sources []Source `json:"sources"`
SourceProofs []SourceProof `json:"source_proofs"`
ExcusedDerivedPaths []string `json:"excused_derived_paths,omitempty"`
Actor string `json:"actor"`
Reason string `json:"reason"`
RecordedAt time.Time `json:"recorded_at"`
}
Acknowledgement is a separate, append-only acknowledgement for an unpublished prepare-phase conflict receipt whose every receipted source worktree is already gone from disk, yet whose receipted changes are proved, source by source, to already be reachable from the freshly fetched current remote target either by graph ancestry or a recorded per-path absorption proof. ReceiptStatus is carried as a plain string so this leaf package never needs internal/orchestrate's WorktreeMergeStatus type; callers convert at the boundary.
func Load ¶
func Load(path string, receipt ReceiptIdentity) (Acknowledgement, error)
Load reads and fully validates the acknowledgement sidecar at path against receipt: every immutable identity field, the SHA-256 binding to receipt's exact current bytes, every source proof's identity and method, every excused derived path's shape and use, and the recomputed content hash ID. A sidecar that fails any of these checks -- including one that is merely missing -- returns a non-nil error; the two are distinguished with os.IsNotExist, exactly as os.ReadFile itself would report.
type PathProof ¶
type PathProof struct {
Path string `json:"path"`
Method string `json:"method"`
AddedLines int `json:"added_lines,omitempty"`
MatchedLines int `json:"matched_lines,omitempty"`
}
PathProof records how one path a source changed relative to its merge-base with the current target was proved absorbed: "blob_absorbed" (identical git blob on the target), "lines_absorbed" (every line the source added to a `*.jsonl` append-only ledger, relative to the merge-base, is present verbatim as a line in the target's copy -- AddedLines and MatchedLines record the counts), "go_dependency_upgrade" (a jointly verified, monotonic root go.mod/go.sum dependency upgrade), or "derived_excused" (an operator-audited `--derived-path` exclusion for a known generated-index shape).
type ReceiptIdentity ¶
type ReceiptIdentity struct {
Path string
ID string
Status string
Lane string
Repository string
Target string
TargetSHA string
Candidate Source
Sources []Source
}
ReceiptIdentity is the subset of an internal/orchestrate.WorktreeMergeReceipt that Load validates an Acknowledgement against. Path is the receipt's own file path, used both as the immutable ReceiptPath identity and to compute ReceiptSHA256 fresh from the receipt's current bytes.
type Source ¶
type Source struct {
Task string `json:"task"`
Worktree string `json:"worktree"`
Branch string `json:"branch"`
SHA string `json:"sha"`
}
Source identifies one worktree-merge source or candidate by its immutable task, worktree, branch, and commit SHA. It mirrors the fields internal/orchestrate.WorktreeMergeSource and WorktreeMergeCandidate carry in common, so a slice of either converts to []Source with a plain type conversion.
type SourceProof ¶
type SourceProof struct {
Task string `json:"task"`
Worktree string `json:"worktree"`
Branch string `json:"branch"`
SHA string `json:"sha"`
Method string `json:"method"`
MergeBaseSHA string `json:"merge_base_sha,omitempty"`
PathCount int `json:"path_count,omitempty"`
PathProofs []PathProof `json:"path_proofs,omitempty"`
}
SourceProof records, for one receipted source, how its content was proved already reachable from the current remote target: either the receipted source SHA is a direct ancestor of the freshly fetched target head ("ancestor"), or every path it changed relative to its merge-base with the target is individually proved absorbed ("content_absorbed"). MergeBaseSHA and PathCount are populated only for the content_absorbed method; PathProofs details how each changed path was individually proved.