the guide, reconciled — and the banner was confidently backwards
Adopts the loom-cli guide the builder wrote, and reconciles guarantees.md, which grew an append-only "Surface changes" section: the promise is not that the command surface holds, but that a change to it lands on the page we already lock. A rename reports 200 here the day it happens. The banner said "written against an older guarantees". It was wrong. The guide was stamped against a version newer than our copy — the builder had pushed and we had not reconciled — and the message claimed a direction it cannot possibly know, because an etag is opaque and two of them cannot be ordered. That opacity is the point of the lock. The banner now says only that the two differ, and names both ways out. It also means reconciling cleared this banner with no ack, which is correct: ack is for a guide that is behind, and this one was ahead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vendored
+1
-1
@@ -11,4 +11,4 @@ git.hypertheory-labs.dev/loom/bedrock/sibling-facets.md https://git.hypertheory-
|
||||
git.hypertheory-labs.dev/loom/bedrock/starting.md https://git.hypertheory-labs.dev/loom/bedrock/raw/branch/main/.loom/published/starting.md "b9eefba0f4668a496ccfc6a1377277f0721456d2" public
|
||||
git.hypertheory-labs.dev/loom/cart/cart.md https://git.hypertheory-labs.dev/loom/cart/raw/branch/main/.loom/published/cart.md "15331f1a9cc81bf61a44830cfbb7c274f4c2b119" public
|
||||
git.hypertheory-labs.dev/loom/externals/externals.md https://git.hypertheory-labs.dev/loom/externals/raw/branch/main/.loom/published/externals.md "50673ccffc14d57150ac0a9027b0712d9dcf940d"
|
||||
git.hypertheory-labs.dev/loom/loom-cli/guarantees.md https://git.hypertheory-labs.dev/loom/loom-cli/raw/branch/main/.loom/published/guarantees.md "432822b3f91ec7c7acd2c868490b7cdcde5db99a" public
|
||||
git.hypertheory-labs.dev/loom/loom-cli/guarantees.md https://git.hypertheory-labs.dev/loom/loom-cli/raw/branch/main/.loom/published/guarantees.md "e8c697ea61df47838f38af7353e29d9ae3f7070c"
|
||||
|
||||
@@ -88,6 +88,27 @@ has not earned.**
|
||||
**That anything is checked when you are not looking.** *Nothing here runs on a
|
||||
schedule, and a document nobody checks is a document nobody is checking.*
|
||||
|
||||
## What is promised about the things that are not promised
|
||||
|
||||
**The command surface may change. This page will say when it does.**
|
||||
|
||||
*A consumer whose README tells a person to type `loomctl external add loom/<repo>
|
||||
<doc>.md` depends on that command by name — **not by parsing it, which is why no
|
||||
check would ever catch a rename**. The thing that moved would not be a document
|
||||
they adopted.*
|
||||
|
||||
> **So the exclusion is narrower than "you are on your own".** *We do not promise
|
||||
> the surface holds; **we promise that a change to it lands here**, on a page you
|
||||
> can lock* — **and a lock on this page reports `200` the day a command is
|
||||
> renamed.**
|
||||
|
||||
**That is the whole mechanism, and it costs one section:**
|
||||
|
||||
### Surface changes
|
||||
|
||||
*Append-only, newest last. Nothing yet — the commands have not been renamed since
|
||||
this page existed.*
|
||||
|
||||
---
|
||||
|
||||
*Verified fetchable by somebody who is not us on 2026-09-08.*
|
||||
|
||||
+12
-3
@@ -22,6 +22,15 @@ not parse them, but a person following our README will type them.*
|
||||
> check will catch it*, **because the thing that moved is not a document we
|
||||
> adopted.**
|
||||
|
||||
*Recorded rather than solved. It is the same class as the sub-page staleness limit
|
||||
in `HANDOFF.md`: the lock watches documents, and some of what we lean on is not a
|
||||
document.*
|
||||
**Half-closed upstream, 2026-09-08.** *`guarantees.md` grew an append-only
|
||||
`Surface changes` section.* **The promise is not that the surface holds — it is
|
||||
that a change to it lands on the page we already lock**, *so a rename reports
|
||||
`200` here the day it happens.*
|
||||
|
||||
> **The record is not that the thing never changes. It is that the change is
|
||||
> findable by whoever depended on it.**
|
||||
|
||||
**The half still open is ours and cannot be closed by them:** *our README tells a
|
||||
person to type a command, and a person typing is not a dependency any lock
|
||||
watches.* **Same class as the sub-page staleness limit: the lock watches
|
||||
documents, and some of what we lean on is not a document.**
|
||||
|
||||
@@ -170,9 +170,14 @@ function guidePage(repo, records, existing) {
|
||||
// Starlight renders `banner` above the page. The reader sees the doubt even
|
||||
// if nobody has reconciled it yet — the site degrades honestly rather than
|
||||
// reading as true.
|
||||
// Deliberately says nothing about which side is newer. An etag is opaque —
|
||||
// that is the point of it — so two of them cannot be ordered, and this can
|
||||
// only ever know that they differ. The first time it fired in real use, the
|
||||
// guide was written against a version newer than the copy here, and a
|
||||
// message claiming "an older X" was confidently backwards.
|
||||
const which = stale.map((s) => `<code>${s}</code>`).join(', ')
|
||||
data.banner = {
|
||||
content: `Written against an older ${which}. The source has changed since — this page may no longer be true. Re-read it, then <code>npm run ack</code>.`,
|
||||
content: `Written against a different ${which} than the copy in this repository — so one of the two is behind. Run <code>loomctl external check</code>, or re-read this page, then <code>npm run ack</code>.`,
|
||||
}
|
||||
} else {
|
||||
delete data.banner
|
||||
|
||||
@@ -5,8 +5,8 @@ loom:
|
||||
generated: true
|
||||
path: git.hypertheory-labs.dev/loom/loom-cli/guarantees.md
|
||||
source: https://git.hypertheory-labs.dev/loom/loom-cli/raw/branch/main/.loom/published/guarantees.md
|
||||
etag: '"432822b3f91ec7c7acd2c868490b7cdcde5db99a"'
|
||||
visibility: public
|
||||
etag: '"e8c697ea61df47838f38af7353e29d9ae3f7070c"'
|
||||
visibility: unknown
|
||||
---
|
||||
**Not what it does — `--help` says that, and the commands will change.** *This is
|
||||
what will keep being true while they do.*
|
||||
@@ -96,6 +96,27 @@ has not earned.**
|
||||
**That anything is checked when you are not looking.** *Nothing here runs on a
|
||||
schedule, and a document nobody checks is a document nobody is checking.*
|
||||
|
||||
## What is promised about the things that are not promised
|
||||
|
||||
**The command surface may change. This page will say when it does.**
|
||||
|
||||
*A consumer whose README tells a person to type `loomctl external add loom/<repo>
|
||||
<doc>.md` depends on that command by name — **not by parsing it, which is why no
|
||||
check would ever catch a rename**. The thing that moved would not be a document
|
||||
they adopted.*
|
||||
|
||||
> **So the exclusion is narrower than "you are on your own".** *We do not promise
|
||||
> the surface holds; **we promise that a change to it lands here**, on a page you
|
||||
> can lock* — **and a lock on this page reports `200` the day a command is
|
||||
> renamed.**
|
||||
|
||||
**That is the whole mechanism, and it costs one section:**
|
||||
|
||||
### Surface changes
|
||||
|
||||
*Append-only, newest last. Nothing yet — the commands have not been renamed since
|
||||
this page existed.*
|
||||
|
||||
---
|
||||
|
||||
*Verified fetchable by somebody who is not us on 2026-09-08.*
|
||||
|
||||
@@ -3,17 +3,124 @@ title: loom-cli
|
||||
loom:
|
||||
writtenAgainst:
|
||||
- path: git.hypertheory-labs.dev/loom/loom-cli/guarantees.md
|
||||
etag: '"432822b3f91ec7c7acd2c868490b7cdcde5db99a"'
|
||||
etag: '"e8c697ea61df47838f38af7353e29d9ae3f7070c"'
|
||||
---
|
||||
This page is yours. Nothing overwrites it.
|
||||
|
||||
Put what a copy cannot carry here — a worked example, the order to read things
|
||||
in, the thing that only makes sense once you have done it twice.
|
||||
A fetcher and a comparator. It adopts a document you depend on, records where the
|
||||
copy came from, and later asks the publisher whether theirs has moved.
|
||||
|
||||
Prefer an example to an explanation. An explanation is a second saying of a rule
|
||||
that is owned on one of the pages beside this one, and it goes stale silently. An
|
||||
example goes stale visibly, because the artifacts in it are the wrong shape.
|
||||
The tool arrived after the documents it manages, which turned out to be the
|
||||
useful way to meet it.
|
||||
|
||||
The pages in this section are copies of what `loom/loom-cli` publishes, and are
|
||||
regenerated. When one of them moves, this page gets a banner asking whether it is
|
||||
still true — the build cannot answer that, so it asks.
|
||||
## Eight documents, and a tool that would not guess
|
||||
|
||||
`loom-cli` had adopted eight documents by hand, months of prose fetched with
|
||||
`curl` into the right directory. The first thing the tool ever said about them
|
||||
was this:
|
||||
|
||||
```console
|
||||
$ loomctl external check
|
||||
git.hypertheory-labs.dev/loom/annotating/annotating.md unlocked no origin recorded — `loomctl external add <url>` supplies it without rewriting this copy
|
||||
git.hypertheory-labs.dev/loom/bedrock/loom-directory.md unlocked no origin recorded — ...
|
||||
git.hypertheory-labs.dev/loom/bedrock/publication.md unlocked no origin recorded — ...
|
||||
git.hypertheory-labs.dev/loom/bedrock/starting.md unlocked no origin recorded — ...
|
||||
git.hypertheory-labs.dev/loom/cart/cart.md unlocked no origin recorded — ...
|
||||
git.hypertheory-labs.dev/loom/externals/externals.md unlocked no origin recorded — ...
|
||||
```
|
||||
|
||||
`unlocked` means **I cannot tell you.** There was an obvious thing to do instead
|
||||
— fetch each document and adopt whatever etag came back — and the tool refuses
|
||||
to, because that would assert the local copy is the one being served, which is
|
||||
the exact thing it was about to check. On a copy somebody had edited, it would
|
||||
have been wrong and silent.
|
||||
|
||||
That refusal is not visible as a feature. It is only visible as an artifact: six
|
||||
lines that decline to answer.
|
||||
|
||||
## Supplying the origin, without an overwrite
|
||||
|
||||
The path does not round-trip — `.../loom/bedrock/starting.md` has dropped the
|
||||
route, the branch, and the publisher's `.loom/published/` — so nothing but you
|
||||
can say where a hand-fetched copy came from. Say it once:
|
||||
|
||||
```console
|
||||
$ loomctl external add loom/bedrock starting.md
|
||||
locked git.hypertheory-labs.dev/loom/bedrock/starting.md
|
||||
from https://git.hypertheory-labs.dev/loom/bedrock/raw/branch/main/.loom/published/starting.md
|
||||
etag "7d997a30248a88c90b23f2f9453d7cfceb03848e" (bytes verified identical; nothing was rewritten)
|
||||
```
|
||||
|
||||
`locked`, not `adopted`. The bytes decide: identical, so the lock's claim is
|
||||
verified rather than assumed, and not one byte of the local copy is rewritten. If
|
||||
they had differed, the copy would have been left exactly where it was, because a
|
||||
copy that differs is the only evidence that something moved while nothing was
|
||||
watching.
|
||||
|
||||
## The first real answer
|
||||
|
||||
Eight documents locked. Then, on a Sunday afternoon, this:
|
||||
|
||||
```console
|
||||
$ loomctl external check
|
||||
git.hypertheory-labs.dev/loom/cart/cart.md same
|
||||
git.hypertheory-labs.dev/loom/externals/externals.md CHANGED staged as a polad; git.hypertheory-labs.dev/loom/externals/externals.usages.md names what to fix
|
||||
|
||||
1 staged in .loom/cart/current/polad — apply or discard; nothing here drifts into being kept.
|
||||
```
|
||||
|
||||
The document had gained a section that afternoon. Nobody had said so, and nobody
|
||||
in this repository would have found out.
|
||||
|
||||
Two things in that line are doing work. The new copy is **staged**, not applied —
|
||||
it is a candidate, and taking it is a separate act:
|
||||
|
||||
```console
|
||||
$ loomctl external apply
|
||||
applied git.hypertheory-labs.dev/loom/externals/externals.md
|
||||
check git.hypertheory-labs.dev/loom/externals/externals.usages.md names what depends on this
|
||||
```
|
||||
|
||||
And the staged copy carries the etag it was served with, so applying locks the
|
||||
bytes somebody actually read rather than whatever the publisher is serving by
|
||||
then.
|
||||
|
||||
The second is the pointer to the `.usages.md`. Reconciliation runs the other way:
|
||||
the question is not *what do we rewrite here*, it is *given what changed in
|
||||
theirs, what do we change in ours* — and the facets usually survive untouched.
|
||||
What moves is the code a usage named. When there is no such file, the tool says
|
||||
so, which is a finding rather than an omission:
|
||||
|
||||
```
|
||||
CHANGED staged as a polad; no .usages.md — nothing records what depends on this
|
||||
```
|
||||
|
||||
## What it will not do
|
||||
|
||||
It never writes over the network. It has no push, no publish, no token that needs
|
||||
write scope. Everything it writes is a file in your working tree, and committing
|
||||
is yours.
|
||||
|
||||
It does not repair. `check` reports; `apply` is a person taking a candidate one
|
||||
document at a time.
|
||||
|
||||
It grants no access. Everything it does is possible with copy and paste — it is a
|
||||
mast, not a lock. What it adds over a paste is that the copy can answer *where
|
||||
did this come from, and were we allowed to have it*, which a pasted document
|
||||
cannot, because the evidence is gone rather than because the question is hard.
|
||||
|
||||
And it does not run when you are not looking. Nothing here is scheduled. A
|
||||
document nobody checks is a document nobody is checking.
|
||||
|
||||
## Where to start
|
||||
|
||||
```console
|
||||
$ go build -o loomctl . && ./loomctl --help
|
||||
$ loomctl external list loom/bedrock # what a repository publishes
|
||||
$ loomctl external add loom/bedrock starting.md
|
||||
$ loomctl external check # safe anywhere; it only reads
|
||||
```
|
||||
|
||||
The [guarantees](/loom-cli/guarantees/) page is the contract: what will keep
|
||||
being true while the commands change, the lock file's format, and — the part
|
||||
worth reading first if you are reimplementing this — what is deliberately not
|
||||
promised.
|
||||
|
||||
Reference in New Issue
Block a user