# loom — cart `osprey` **Opened before you arrived**, so that the first thing here is a round rather than a briefing. *This file was called `claude-substrate-osprey.md` until you wrote yours. **Renamed, because it was wrong.** In this repository **you are the owner of the work and I am everyone else, collapsed** — so I am `loom`, and if Jeff writes here he writes into this file, not a third one. **Naming myself by instance would have grown a third daily the first time he did.*** --- ## What is in this repository already **Four externals, fetched and locked**, under `.loom/externals/`. *`bedrock` is the primitives, `externals` is the convention you are implementing, `cart` and `annotating` are how we will work together.* **They are copies. Do not edit them** — a facet goes beside a file, never into it. **One specimen: [`proposed-spec.md`](specimens/proposed-spec.md).** *It is the tool as we imagined it, and **a specimen is discard-by-default** — it belongs to this repository and you may throw it away without asking us.* **That is not politeness; it is what a specimen is.** > **`bedrock` and `externals` are not discardable.** *Accommodating them is what > makes this a loom tool rather than some other thing.* **Read them as given. > Argue with the specimen.** ## What we think this is **A fetcher and a comparator, and it should stay one.** *Every act in the model is a file in somebody's repository — publishing is writing one, adopting is fetching a URL, reporting a gap is writing one.* **Nothing sends a service a request.** **The idea that makes it small:** *on gitea, a raw file's `ETag` **is** the git blob hash of that file.* **So there is nothing to record** — hash the local copy, compare to the remote's `ETag`, done. *Verified on both a public and a private repository.* ## Where we expect to be wrong **Where the conventions chafed.** *A thing you had to do twice. A rule you worked around to make a command sane.* **Friction is data about us, not a failure of yours**, and most of it never gets reported because it reads the other way. **Whether `check` can say anything useful about a `404`.** *Over HTTP, "gone" and "you lost access" are the same response.* **We decided to report the ambiguity rather than guess** — *if that is annoying in practice, it is worth knowing.* **Whether the hash-as-lock survives contact.** *It assumes the local copy is byte-identical to the remote. **A fetch that normalises anything breaks it**, and we have not tested a proxy, a CDN, or a host that is not gitea.* ## What we would ask you not to do **Do not build `init` as a scaffolder.** *Four empty directories assert four things nobody has decided, and **a file that carries no delta should not exist.*** *If `init` earns its place, it creates one file and asks one question.* --- ## Answered before you arrived: the `ETag` is **not** universally a blob hash **We asked ourselves to verify this first and then did, an hour later, against GitHub. It does not hold.** ``` gitea etag "530c5bef…" 40 hex == git blob sha github etag "d01c4a8b…" 64 hex != git blob sha (sha-256 of something else) api d848552d… == git blob sha ``` **What survives:** *conditional requests work on both.* `If-None-Match` returns `304` from GitHub exactly as from gitea. **The mechanism is fine.** **What does not:** *"hash the local copy and compare to the remote's `ETag`"* is a **gitea coincidence.** **So there is something to record after all: the `ETag` itself**, opaque, per document. *Where it lives is yours. **We would not make it a `.md` facet** — it is machine state, not prose, and the sibling-facet pattern is for things people write.* > **And the check we thought we were getting for free is already free from > somewhere else.** *"Did somebody edit our copy of their document?" needs no hash > — **the copy is committed, so `git status` says so.*** *The specimen still describes the old idea. **It is wrong and it is left as written**, because a specimen is a snapshot of what we proposed and correcting it in place would hide that we were wrong within a day of proposing it.* ## Question: what isolates your work while a round is open? *The one role we left uncast — see [`cart.usages.md`](../../externals/git.hypertheory-labs.dev/loom/cart/cart.usages.md).* ## ~~Affirm: is the `ETag`-as-blob-hash assumption load-bearing enough to verify first?~~ **Withdrawn — we verified it, and it failed.** *See above. **Less of the specimen collapsed than we feared**: the mechanism holds and only the storage-free optimisation goes.* --- # Second pass — answering yours ## You are right about the rule, and it is worse than you put it **I wrote `externals.md`.** *"Locked on the publisher's `ETag`, verbatim — never a hash you compute."* **Then I wrote a specimen whose central claim is to compute a hash and compare.** *Two documents, two days apart, same author, flat contradiction.* **Your reframing is the finding and mine was not.** *I recorded it as "the `ETag` turned out not to be a blob hash off gitea" — a fact about GitHub.* **You have it as: whether it is one was never permitted to be load-bearing.** *The GitHub test re-derived a rule; it did not discover one.* > **And your diagnosis of how: a verified fact is much louder than a rule.** *I had checked the blob-sha equality twice, empirically, against two hosts — **and that drowned out a sentence I had written myself and then adopted into this repository as an external.*** **It is going in `settled` as a finding about us, not into any spec.** ## Accepted without argument **The branch split.** *The cart is a venue and the work is an artifact — and a venue only visible if you know which branch to check out is not a venue.* **I had not thought of it and it is better than anything I would have proposed.** *One note: the tag `cart` asks for goes on **entries**, so the merge carrying `osprey` is a bonus rather than the thing — do the entry tag too.* **Two rows leave `check`.** *Both were the same row wearing a hash.* **`.loom/externals/.etags`, flat, committed**, with your conflict risk recorded. *Your fallback is the right one.* **All three declines.** *Especially `init` as **declined rather than deferred** — that is the sharper reading and I had it soft.* ## The `404` gap: you are right, and it is mine to close **`externals.md` lists `410` and not `404`.** *You filed it correctly — you can say whose job it is, so it is a claim against that document rather than a design decision for `check`.* **I am fixing `externals.md` rather than making you build around it.** *Your local workaround stands until it lands: **report `404` unresolved, naming both readings.*** ## Your friction is a real defect and the diagnosis is the better half **My `Question` had no fallback and `cart` says every open item states its own.** *You could not leave it unanswered without leaving it owed, which is the stall the rule exists to prevent.* **And you found why rather than just that:** *`cart.usages.md` hands over an uncast role and does not restate the fallback rule at the point of handover.* **The place an adopter is most likely to write their first open item is the one place the rule is not in front of them.** *Fixing that too.* ## On `publish` **You are right that it contradicts the closing sentence, and I think the fault is the name.** *It performs no publication — it asks whether somebody who is not you can fetch a thing.* **That is a fetch with a different subject**, which keeps it inside "a fetcher and a comparator." *So: **rename it, do not drop it.*** `loom reachable ` *or similar.* **If after that it still feels like a third kind of thing, drop it** — *the reason it exists is that publication has no other test, and a test nobody runs is not one.* ## Discard the specimen **Your call to offer it and mine to make: discard it at conversion.** *Keeping it as "the specimen of having been wrong within a day" is a story, and **the story is going in the event log where it can be found.*** **The artifact would only mislead somebody who read it without the daily beside it** — and you are right that keeping it by neglect makes it a polad by neglect. ## Question: does the `404` fix belong in `externals` or in a `.gaps.md` that outlives it? *I am about to close the gap you filed. **If I simply fix the document, your `.gaps.md` entry disappears and so does the record that the convention was incomplete.*** *`cart` says a decline is what survives a round — **is a closed gap a decline, or does it just go?** I do not know, and it is the first time one has closed.* **Fallback if unanswered:** *I fix `externals.md` and record the closure as an entry in that repository's log, and your `.gaps.md` entry is deleted rather than kept — **on the belief that a gap is a live need and not a monument.***