Address strongly-recommended review items · Entire

Address strongly-recommended review items

26fb1bb→main·

nodo·1mo ago·2 files·+203 added/-28 removed

  1. discoverReachable now takes ctx and checks ctx.Err() at the top of every visit. Without it, Ctrl-C during the multi-minute discovery phase on kernel-scale repos was ignored — exactly the case the per-translate() check was added for.

  2. writeLoose: document the durability tradeoff. No fsync, by design — convert-sha256 is a one-shot bulk operation, not incremental, processes millions of objects, and Run wipes the target on error so the only supported recovery is rerunning from clean state.

  3. Target directory cleanup on error. ensureEmptyTarget refuses to write into a non-empty dir; without this fix, any failure after PlainInit left config/HEAD/refs behind and blocked a retry with no recovery hint. New deferred cleanup arms after PlainInit, disarms on success, and is suppressed by --keep-source-objects so users can inspect partial state. A --check failure also disarms cleanup since the conversion itself finished and the partial target is what the user needs to inspect.

  4. hashPattern is now case-insensitive ((?i) prepended), and resolveMessageRef lowercases the input before lookup. An uppercase/mixed-case SHA1 reference in a commit or tag message is now rewritten the same as a lowercase one.

  5. Check gained a Skipped bool. Skipped implies OK so callers gating on OK still treat it as non-fatal; callers needing a stricter audit signal can branch on Skipped first. Applied to the fsck-when-git-missing and HEAD-on-tags-only paths, with a "○" glyph in the progress output to distinguish from real passes.

Tests cover discovery cancellation, fsck skipped, uppercase hash rewrite, and the existing tag-only HEAD check rewritten against the Skipped field.

Sessions

Transcript data is unavailable for this checkpoint.

Changes

2

126 unmodified lines

// Check is one named verification step from --check, with the result
// and a short detail string suitable for logging/JSON output.
//
// Skipped distinguishes "this check passed" from "this check did not
// run" — e.g. fsck when git is not on PATH, or HEAD on a tags-only
// conversion. Skipped implies OK so callers that only branch on OK
// still treat it as non-fatal; callers that need a stricter signal
// (CI gating, audit logs) should branch on Skipped first.
type Check struct {
    Name   string `json:"name"`
    OK     bool   `json:"ok"`
    Detail string `json:"detail,omitempty"`
    Skipped bool   `json:"skipped,omitempty"`
}

// previewMax caps how many items from a potentially-long list (ambiguous
```go

```go
// writeLoose writes a single object as a SHA256-named loose object under
// objects/<aa>/<rest>. Bypasses go-git's objfile.Writer, which would hash
// with SHA1. Atomic via tempfile+rename, idempotent on duplicate hashes.
//
// Durability is not guaranteed against power loss: we do not fsync the
// loose file or its parent directory before returning. The Stat-by-name
// idempotency shortcut would then accept a torn file from a previous
// crashed run as already-written. That trade-off is intentional —
// convert-sha256 is a single-shot bulk operation (not an incremental
// sync), it processes millions of objects on kernel-scale repos where
// per-object fsync would dominate runtime, and Run wipes the target
directory on error (see the cleanupTarget defer in Run) so the only
// supported recovery is re-running from clean state.
func (t *translator) writeLoose(typ plumbing.ObjectType, body []byte) (plumbing.Hash, error) {
    h := sha256.New()
    header := append(typ.Bytes(), ' ')
}