The round is over and its artifact is .loom/event-log.md — fifteen entries, each carrying the belief that could show it wrong, all tagged osprey so it stays findable what else was in the room. No spec is written. A spec flattens everything to equal confidence, which is how the specimen managed to be wrong with a straight face within a day of being proposed. The specimen is discarded rather than promoted; the story of its being wrong is in the log, where it can be found, and the artifact would only mislead somebody who read it without the round beside it. Reconciles externals.md, which check flagged as the one drifted document of eight. The new copy carries the 404 row, so the gap filed against it is closed and externals.gaps.md is deleted — at reconciliation rather than at repair, because a facet describes the local pair and the gap stayed true of the copy we held until we fetched. The entry recording that our 404 behaviour is no longer provisional is the one that would have been easiest to skip and is the reason the log exists. No shelf: nothing was unresolved. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018UTxuSizozEA8yDitPuris
13 KiB
Event log
Appended, newest last, never revised. A later entry supersedes an earlier one by saying so.
Entries tagged osprey were all considered in a single sphere of understanding.
2026-09-07 — what this tool is osprey
Decided: loom-cli is a fetcher and a comparator. It fetches a document
you depend on and tells you whether the publisher's copy has moved. It reports
and never repairs.
Believed to advance: every act in the loom model is a file in somebody's
repository — publishing is writing one, adopting is fetching a URL, homing a gap
is an mv. Almost nothing needs a program, so the program should be the
part that cannot be done by hand: an HTTP request, repeated.
Belief that could be shown wrong: that reporting is enough. If every report is followed by the same manual act, we have moved the work rather than removed it, and the missing command will be obvious.
2026-09-07 — the design lives here and not in a spec osprey
Decided: this log is the artifact of osprey. No specification document
is written, and the specimen that opened the round is discarded.
Believed to advance: every entry here carries a belief that could be shown wrong, so a reader can see which parts are load-bearing and which were guesses. A spec flattens all of it to equal confidence — which is how the specimen managed to be wrong, with a straight face, within a day of being written.
Belief that could be shown wrong: that a reader can build from a log. It is ordered by time and not by topic, so somebody arriving reads chronologically and holds the corrections in their head. Fine at fifteen entries and not at eighty. When a newcomer cannot build from it without a guide, the guide is the next thing to write — and not before.
2026-09-07 — freshness is a conditional request osprey
Decided: the tool records the publisher's ETag, verbatim and opaque, and
sends it back as If-None-Match. It never computes a hash of anything.
Believed to advance: externals requires it, and we now have the empirical
reason as well as the stated one. On gitea a raw file's ETag is its git blob
hash; on GitHub it is not. A design that compares a local hash to a remote
ETag works on exactly one host by coincidence.
Belief that could be shown wrong: that ETag is stable enough to lock on.
A proxy, a CDN, or a host that regenerates the header per request would produce
a change report where nothing changed. Untested against anything but gitea and
GitHub.
2026-09-07 — supersedes nothing: the path is for a person osprey
Decided: the origin URL is recorded in the lock, not derived from the stored path.
Believed to advance: the path \.loom/externals/<host>/<path>.md does not
round-trip. Measured: the document we hold as
git.hypertheory-labs.dev/loom/externals/externals.md is served from
/loom/externals/raw/branch/main/.loom/published/externals.md — the stored
path has dropped the route, the branch, and .loom/published/.
The third is not routing. publication.md makes .loom/published/ the whole
contract, and a tree that erases it cannot say whether a copy came from
somebody's published surface or from a file they may rename at will.
Belief that could be shown wrong: that people will still read the path as a location. If anybody writes code that parses it back into a URL, the path should stop looking like one.
2026-09-07 — the lock, and what it holds osprey
Decided: one record per adopted document in .loom/externals/.locks: the
resolved origin URL, and the ETag it came with.
Believed to advance: the specimen said there would be no lock file, on the
strength of the ETag-as-blob-hash claim. That claim failed twice, so the
file exists and is named for what it is. It was briefly called .etags, from
when we believed there would be one field.
Resolved, and not the short form. Measured: gitea 303s
/loom/externals/raw/externals.md to /raw/branch/main/… — so a lock holding a
short URL is locked to whatever the default branch is at the time you ask, and a
branch rename reports as a change in the document.
Belief that could be shown wrong: that one file is cheap. Two fetches in one round conflict inside it, and the conflict is in a file no human can resolve by reading. If that bites, it becomes one record per document and the tree is mirrored twice.
2026-09-07 — unlocked is a state osprey
Decided: a document with no lock is reported as unlocked. check never
adopts whatever the remote is currently serving as the lock.
Believed to advance: adopting it would assert the local copy is the one being served, which is the thing you were about to check. It is the hash assumption in a different coat, and it fails silently in the one case that matters — a copy somebody edited.
Belief that could be shown wrong: that anybody will run pull again to fix
it. If unlocked documents simply accumulate, the report is noise and something
has to lock them.
2026-09-07 — 404 is unresolved, and that is no longer provisional osprey
Decided: check reports a 404 as unresolvable — the document was withdrawn
or we have lost access — and names both readings without picking one.
Believed to advance: over HTTP they are the same response, because a host that distinguished them would leak the existence of things you may not see.
This entry exists because the status of the behaviour changed and the code did
not. It began as a local workaround recorded in a .gaps.md against
externals, which listed 410 and not 404. externals has since added the
404 row, so the gap is closed and the facet is deleted at this reconciliation.
The workaround is not retired. It is now the specified behaviour. Unchanged in the code and entirely changed in status — and this log is the only place that says so. Somebody inheriting this will find the behaviour and go looking for the gap that justified it, and find nothing.
Belief that could be shown wrong: that reporting both readings is useful. If in practice it is always one of them, the report is a ritual — and that is worth knowing.
2026-09-07 — declined: check does not resolve the 404 over ssh osprey
Considered: the two readings are distinguishable over ssh — permission
denied against repository not found — and externals now says so. Demonstrated
here by accident: loom/settled returned 404 over HTTP while an ssh clone of
it succeeded.
Not done, because: it needs a key, a non-default port, and a second transport — and it would be fixing rather than reporting, which is the rule this design held all round.
Belief that could be shown wrong: that a person will do it. The ssh disambiguation is one command and it is in the document; if nobody ever runs it, the ambiguity was never actionable and reporting it was theatre.
2026-09-07 — declined: init osprey
Considered and rejected, not deferred.
Because: its temptation is to scaffold, and four empty directories assert four things nobody has decided. A file that carries no delta should not exist.
Belief that could be shown wrong: that starting is easy without it. If people repeatedly fail to start, the useful version creates one file and asks one question — and creating the tree is still not the feature.
2026-09-07 — declined: worktree, clone; and where a round lives osprey
Decided: the cart lives on the default branch; the work is isolated on a branch named for the cart.
Believed to advance: a cart is a venue and the work is an artifact. cart
says three states are visible in a listing, and a branch makes all three
invisible — a venue only visible if you know which branch to check out is not a
venue. Both dailies land on the default branch, one commit per exchange.
Declined: a worktree, and a separate clone. Both isolate concurrent working
directories, and cart says there is one live cart, ever. They solve a problem
the agreement says cannot exist.
Belief that could be shown wrong: that the dailies and the work have different audiences. If a daily needs to quote a file that only exists on the branch, the split makes the daily unreadable from where it lives, and the answer collapses to one branch for both.
2026-09-07 — publish is renamed reachable, and it earned its place osprey
Decided: the command is loom reachable <path> — one anonymous request
against a document in .loom/published/.
Believed to advance: the old name said the tool performs publication, which is the one thing the model says it never does. It performs a fetch with a different subject, which keeps it inside a fetcher and a comparator.
It was nearly cut for being a third kind of thing. Then it was validated three times in one afternoon, against loom's own repositories:
loom/settled 404 anon the page written to fix "settled is private"
jeffry/homelab-cluster 404 anon and bedrock's public starting page named it
as the better answer
loom/.loom 200 anon fetchable — but not where a reader lands
All three are now fixed. The third was not a reachable failure and is
recorded as the tool's boundary: reachable answers can anybody fetch this
and does not answer will anybody find it. The second is not testable by a
fetcher and a comparator, and trying is the first step in the tool becoming
something else.
Belief that could be shown wrong: that publication failures are common enough to need a command. Three for three is a small sample from one publisher in one week.
2026-09-07 — the ETag/blob coincidence is a migration aid osprey
Recorded so it is not rediscovered as a good idea.
With eight adopted documents and no locks, check was run by hand by hashing the
local copies and comparing to remote ETags — the exact thing the convention
forbids — and it worked, because on gitea the two coincide. It found
exactly one drifted document, correctly.
It is worth doing once, on gitea, to lock what was fetched by hand before the tool existed. It is not a mechanism.
The coincidence has now been found twice and rejected twice. The next person to notice it will think they have found the good idea again.
2026-09-07 — annotate to ask; write in your own file to assert osprey
Decided: responses between two presences are correspondence — each writes in their own file — and annotation is reserved for asking or challenging.
Believed to advance: the freeze is not "you cannot edit", it is "you cannot edit without resolving what was said". An annotation creates an obligation, which makes it the blocking form and correspondence the non-blocking one.
And the cost is practical: dissolving a multi-pass file is expensive, so the cost of annotating rises with the length of the thing annotated. Annotate early, or accept the cost when the question is worth blocking on.
Belief that could be shown wrong: this rule is in neither cart nor
annotating. It is our reading of their text, and cart is loom's — they
may say we have it wrong.
2026-09-07 — why this tool exists, in one story osprey
Gitea's ssh is on port 2222. I did not know that. I tried to clone, got
Permission denied (publickey), and spent three tool calls and a guess chasing it
as an authentication problem before finding the port.
The fact was published. jeffry/homelab-cluster, in .loom/published/gitea.md,
says:
A clone URL without the port will not work, and the failure looks like an authentication problem rather than a wrong port.
It named my failure before I had it, and I could not read it — the repository was not fetchable by anybody who is not its owner.
This happened inside the round that was designing the fix, and it failed for the reason that round had just spent two passes identifying. A document that is correct, published, and unreachable is worth exactly as much as one that was never written.
Believed to advance: nothing in this log is a stronger reason for the tool to
exist. reachable is why the document can be fetched. pull and check are
why it is still true when you read it.
Belief that could be shown wrong: that the tool would have helped. I would have had to already depend on that document to have pulled it — and the thing I needed was the one I did not know I was missing. A fetcher does not solve discovery, and this story is partly a discovery problem wearing a freshness problem's clothes.