a changed external is a polad, and add no longer overwrites anything
Restores something the specimen said and the round that discarded the specimen lost with it: a changed external becomes a polad in the cart, and somebody decides. check now stages what moved into .loom/cart/current/polad/ with the ETag that was served alongside the bytes, and prints the .usages.md beside it, because reconciliation runs the other way — the facets usually survive and what moves is the code a usage named. It says so when there is no usages file, which is its own finding. With no cart open, check reports and stages nothing. The tool does not open a round: a cart is a bounded exchange between two presences and starting one is somebody's act, not a side effect of asking about freshness. add now adopts what is not here and refuses what is already adopted, superseding the entry that had it announce an overwrite — it no longer overwrites at all. The one exception is the only way out of a dead end: a document present but unlocked was fetched by hand, nothing records its origin, and the path does not round-trip, so check cannot ask about it and a refusal would strand it forever. add accepts it and the bytes decide — identical locks it without rewriting anything, which makes the lock's assertion verified rather than assumed, and different stages a polad and leaves the local copy alone because it is the only evidence anything moved. apply exists because the lock is the half a person forgets: moving a polad by hand leaves a lock describing the copy you just replaced. Recorded with its limit — for an external, discard does not mean the change goes away, so discarding is really knowingly stale and nothing yet records that choice. Measured end to end on this repository: eight hand-fetched documents, all eight locked, nothing rewritten. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018UTxuSizozEA8yDitPuris
This commit is contained in:
@@ -19,10 +19,19 @@ const usage = `loomctl — fetch what you depend on, and find out when it change
|
||||
loomctl external list <repo-url> what a repository publishes
|
||||
loomctl external add <url> [--path p] adopt one document and lock it
|
||||
loomctl external check ask every publisher whether theirs moved
|
||||
loomctl external apply [path...] move a staged polad into place, lock and all
|
||||
|
||||
check reports and does not fix. A changed document is a candidate, not a
|
||||
replacement, and somebody decides. It exits 0 whether or not anything moved:
|
||||
the report is the answer.
|
||||
check reports and does not fix. A document that moved is staged as a polad in
|
||||
.loom/cart/current/polad/ — a candidate shaped exactly like what it would
|
||||
become — and somebody decides. Its exits are apply or discard; nothing there
|
||||
drifts into being kept. With no cart open, check says what moved and stages
|
||||
nothing, because opening a round is somebody's act and not a side effect.
|
||||
|
||||
add adopts what is not here yet, and refuses what is already adopted. Given a
|
||||
document that is present but unlocked — fetched by hand before this existed —
|
||||
it supplies the missing origin: identical bytes lock it, differing bytes are
|
||||
staged, and the local copy is never overwritten, because a copy that differs is
|
||||
the only evidence that anything moved while nothing was watching.
|
||||
|
||||
Adopted documents live in .loom/externals/<host>/<owner>/<repo>/<name>.md, and
|
||||
their origins in .loom/externals/.locks. The path is for a person to read; the
|
||||
@@ -57,7 +66,7 @@ func run(args []string) error {
|
||||
|
||||
func runExternal(args []string) error {
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("external needs a subcommand: list, add, check")
|
||||
return fmt.Errorf("external needs a subcommand: list, add, check, apply")
|
||||
}
|
||||
switch args[0] {
|
||||
case "list":
|
||||
@@ -88,6 +97,13 @@ func runExternal(args []string) error {
|
||||
}
|
||||
return external.Check(root, os.Stdout)
|
||||
|
||||
case "apply":
|
||||
root, err := root()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return external.Apply(root, args[1:], os.Stdout)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unknown external subcommand %q", args[0])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user