rowan: reconcile three amendments, close three gaps, stage the answers

check found three documents moved and they were the three the gaps were filed
against, so the loop ran the other way for the first time: gaps filed, documents
amended, and the tool reported it rather than somebody saying so.

publication now carries publishing is not an act you can complete alone as its own
section, with the part we asked for — the failure is invisible from the inside,
every check available to the publisher passes — and says publication has a
visibility, which is what externals' confidentiality rule had been depending on.
recording-decisions permits compaction with the four kinds that may never be
dropped, adding that a compaction is itself a decision and gets an entry. cart is
v2 and says converting destroys, so extract first, naming the write-ahead log.

Both closed gap files are deleted at reconciliation rather than at repair, since
each stayed true of the copy held until check reported 200. cart.gaps.md keeps four
of five and gains a reframing of the third-file case: ours appeared because a round
was converted while somebody was still writing, which the agreement already
forbids, so it may be a symptom rather than a category and the fix is upstream.

cart.usages.md gains a v2 section and a note that the cart arrived headed rowan in
a file named loom-osprey.md with no name file — the name is what tags durable
entries, so a disagreement mis-files the record silently.

Answers staged in wal.md as the round runs, which is v2's rule applied to the round
that produced it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018UTxuSizozEA8yDitPuris
This commit is contained in:
2026-09-07 16:49:00 -04:00
co-authored by Claude Opus 5
parent 49c7297d08
commit 104cbd050c
8 changed files with 120 additions and 72 deletions
+3 -3
View File
@@ -4,9 +4,9 @@
git.hypertheory-labs.dev/jeffry/homelab-cluster/gitea.md https://git.hypertheory-labs.dev/jeffry/homelab-cluster/raw/branch/main/.loom/published/gitea.md "530c5bef62bbd325956ed170bb2decf37975e4b9"
git.hypertheory-labs.dev/loom/annotating/annotating.md https://git.hypertheory-labs.dev/loom/annotating/raw/branch/main/.loom/published/annotating.md "9b1f7e6ca92f2339b2d433686c27845362944bdb"
git.hypertheory-labs.dev/loom/bedrock/loom-directory.md https://git.hypertheory-labs.dev/loom/bedrock/raw/branch/main/.loom/published/loom-directory.md "ee0f49cb900c0812678061971194325d9cba366a"
git.hypertheory-labs.dev/loom/bedrock/publication.md https://git.hypertheory-labs.dev/loom/bedrock/raw/branch/main/.loom/published/publication.md "eb0cb63629a36b056f215dfbe24567d1918cec38"
git.hypertheory-labs.dev/loom/bedrock/recording-decisions.md https://git.hypertheory-labs.dev/loom/bedrock/raw/branch/main/.loom/published/recording-decisions.md "970d4b4da76aac99c9b1f1b6580ec20daa42e329"
git.hypertheory-labs.dev/loom/bedrock/publication.md https://git.hypertheory-labs.dev/loom/bedrock/raw/branch/main/.loom/published/publication.md "385e26ef4108029c12a4267600399da1eece52af"
git.hypertheory-labs.dev/loom/bedrock/recording-decisions.md https://git.hypertheory-labs.dev/loom/bedrock/raw/branch/main/.loom/published/recording-decisions.md "d190eeae7929b9a99ecf09211d94e7e5b32635bd"
git.hypertheory-labs.dev/loom/bedrock/sibling-facets.md https://git.hypertheory-labs.dev/loom/bedrock/raw/branch/main/.loom/published/sibling-facets.md "a46446a34ccb8bfc533d3cce19f4c88548c4fa04"
git.hypertheory-labs.dev/loom/bedrock/starting.md https://git.hypertheory-labs.dev/loom/bedrock/raw/branch/main/.loom/published/starting.md "7d997a30248a88c90b23f2f9453d7cfceb03848e"
git.hypertheory-labs.dev/loom/cart/cart.md https://git.hypertheory-labs.dev/loom/cart/raw/branch/main/.loom/published/cart.md "49fc852bdd280293f0f5e0050034e3b89ff7255e"
git.hypertheory-labs.dev/loom/cart/cart.md https://git.hypertheory-labs.dev/loom/cart/raw/branch/main/.loom/published/cart.md "15331f1a9cc81bf61a44830cfbb7c274f4c2b119"
git.hypertheory-labs.dev/loom/externals/externals.md https://git.hypertheory-labs.dev/loom/externals/raw/branch/main/.loom/published/externals.md "a7586eb52caf275d9bcedbbd8042c43e5aaad0b9"
@@ -1,29 +0,0 @@
# Gaps — `publication`
## Whether publishing implies that the audience can read it
**The document says publishing is a change of kind and that `.loom/published/` is
what a repository has handed over for others to depend on.** *It does not say that
the handing over must succeed.*
**We built a command on the assumption that it meant *anyone* could fetch it, and
that was wrong** — *others is not everyone, and a repository may publish to a
private audience deliberately.* **But the opposite is not addressed either:
nothing here says that a document in `published/` which nobody in its intended
audience can fetch has not been published.**
*The sentence we needed is in a sibling and not here:* **publishing is not an act
you can complete alone.** *It appears as an aside about a tool, not as a property
of publication.*
*Local answer: we declined to build the check, on the belief that a registry with
named consumers answers it better than a probe can. **The convention still does not
say whether an unfetchable publication is a publication.***
## Where confidentiality lives
**`externals` now says confidentiality does not travel with the copy.** *That rule
is about adopting, and it exists because of a property of publishing* — **what a
publisher may safely put in `published/` depends on who can read the repository it
is in**, *and this document, which is where publishing is defined, does not
mention visibility at all.*
@@ -15,6 +15,28 @@ should be unmissable.*
**`ls .loom/published/` is *what have we committed to?*** — and it is the question
to ask before changing anything.
## Publishing is not an act you can complete alone
**A file in `.loom/published/` that its intended readers cannot fetch is not
published.** *The move is the act, but the act is not finished until somebody who
is not you can perform the read.*
> **The failure is invisible from the inside.** *Every check available to the
> publisher passes — the file is there, the commit landed, the path is right.*
> **Only a reader can detect it, and a reader who cannot fetch it does not know
> the document exists to ask about.**
*The commonest form is a document that answers "why can you not see this?" and is
published **inside** the thing that cannot be seen.*
**So publication has a visibility, and it is a property of the act rather than of
the file.** *"Others" is not "everyone".* **Naming who the readers are is part of
publishing**, because a repository that depends on this one has to know whether it
is inside that set — *and because a reader who copies a document out inherits the
copy without inheriting the visibility it was published under.*
**The test is a fetch you did not perform.**
## What is published is a document
**Prose, in whatever form its readers need.** *If a repository organises its
@@ -1,28 +0,0 @@
# Gaps — `recording-decisions`
## Whether a log may ever be compacted, and what compaction may not touch
**The document says entries are appended, newest last, and never revised** — *"a
revised record cannot show that anybody changed their mind, which is most of what
a reader wants from it."*
**It also acknowledges no upper bound.** *Ours reached about thirty entries in a
day across three rounds, and `bedrock`'s own README exists because its log needed
a guide.* **At some size the log stops being readable, and the only remedies are
revision, which this forbids, or a guide, which is a second document that can
drift.**
**The gap is not "may we compact".** *It is that **"never revised" and "somebody
must be able to read it" both hold and eventually conflict**, and the document
does not say which gives.*
*Local answer, provisional: **compaction is allowed and git history is where the
uncompacted log lives.*** *An entry may be dropped when a competent reader could
recover it by reading the code.* **An entry may never be dropped when it records a
decline, a measurement, a belief that was shown wrong, or one entry superseding
another** — *because those are precisely the record of somebody changing their
mind, and dropping them is the failure this document names.*
> **Which means compaction is safe in exactly the cases where the entry was
> redundant with the artifact, and unsafe in exactly the cases the log exists
> for.**
@@ -24,6 +24,29 @@ reads.*
you already rejected — because the rejection lived somewhere that did not
survive.*
## Compaction, and the entries it may never touch
**"Never revised" and "somebody must be able to read it" both hold, and far
enough out they conflict** — *a log nobody can get through has stopped being a
record.*
**Compaction is allowed. Dropping an entry is not the same as revising one**, and
the uncompacted log is in git history, which is where a reader who needs it goes.
> **An entry may be dropped when a competent reader could recover it by reading
> the artifact.**
>
> **An entry may never be dropped when it records a decline, a measurement, a
> belief that was shown wrong, or one entry superseding another.**
*Which means **compaction is safe in exactly the cases where the entry was
redundant with the artifact, and unsafe in exactly the cases the log exists
for.*** **The four protected kinds are the ones with no other home:** *the code
shows what was built and can never show what was refused, what was measured, what
turned out false, or that somebody changed their mind.*
**A compaction is itself a decision, and gets an entry.**
## Where it lives
`.loom/event-log.md`. **A stream, so a file.**
@@ -44,19 +44,17 @@ been written.*
presence's daily* — **but "move it" and "reject it" are different acts with
different costs**, *and picking one was ours to invent.*
## What must be extracted before converting, now that conversion destroys
**Added after the fact, and it may dissolve the gap rather than answer it:** *ours
appeared because the round was converted while somebody was still writing.* **The
agreement already has a rule against that** — *do not convert while somebody is
mid-thought* — **so this third file was a symptom and not a category.**
**`v1` makes the cart untracked. So converting deletes the dailies outright**,
*where every earlier conversion left them in git.*
> **Before writing a rule for third files, count how many arrive any other way.**
> *If they are all conversion-timing failures, the fix is upstream of here and the
> two acts never have to be chosen between.*
**The write-ahead log is named in `v1` but not required**, *and nothing says that
at conversion the cart is the only copy.* **Two rules now both push toward loss**
*act as if the shelf is discarded daily, and the cart is not committed* — **and
neither says what has to be written down first.**
*Local answer: a `wal.md` in the cart, staged as we go, so converting is a move
rather than a rewrite. **We would not have thought of it if it had not been
suggested.***
*One instance is not a sample. **We would rather leave this open than freeze a
rule out of a single case**, which is the same reason `v2` did not answer it.*
## Whether an unanswered `Affirm` and a fallback are the same silence
+29 -1
View File
@@ -1,6 +1,6 @@
# Agreement — the cart
**v1.** Depends on `annotating/v0`.
**v2.** Depends on `annotating/v0`.
**How two parties work out what something means before one of them changes it.**
@@ -92,6 +92,34 @@ words.** That costs precision and buys something better:
> **Pinning a defect in place lets you be exact without having understood.
> Restating surfaces the misunderstanding that pinning hides.**
## Converting destroys, so extract first
**The cart is not committed. So conversion does not archive it — it deletes it.**
*Every earlier version of this agreement was wrong about that by accident: a
committed cart left its dailies in history, and "gone" was only ever true of the
tree.*
> **At conversion the cart is the only copy of everything in it.** *The dailies,
> the annotations, the answers to every prompt, and the write-ahead log.*
**So before converting, extract:**
- **every answer to a `Question`, `Select` or `Affirm`** — *an answer lands in a
notes file, a notes file dies at dissolve, and an untracked cart has no history
to fall back on.* **A prompt answered and not extracted was never answered.**
- **every write-ahead entry that survived** — *promote or discard, and both are
acts.*
- **every fallback that quietly became the decision** — *say so in the entry, in
those words.*
**Staging as you go turns conversion into a move rather than a rewrite.** *Keep
the write-ahead log current during the round and there is nothing to reconstruct
at the end, which is when you have least appetite for it.*
*Two rules in this agreement now both push toward loss — **act as if the shelf is
discarded daily**, and **the cart is not committed.** They are both right and
together they mean **nothing in a cart is safe by default.***
## Conversion emits two things
**The artifact** — the code, the decision, the change — **and the declines.**
@@ -64,3 +64,37 @@ no archive*, **so dissolving a notes file destroys the annotations outright.**
*Both documents are loom's. **Recorded here because the conflict is visible from
inside an adopter and not from inside either document.***
---
## Cast against `v2`: extract before converting
**`v2` adds no role.** *It adds an obligation at conversion, and this file is
where an adopter looks for what this repository does about it.*
**The write-ahead log is `wal.md`, in the cart, staged during the round.** *Cast
2026-09-07. It existed here before `v2` named it, as a local answer to the gap
`v2` closed.*
> **What comes out before the `rm`:** *every answer to a `Question`, `Select` or
> `Affirm`; every surviving write-ahead entry; and every fallback that quietly
> became the decision, said in those words.* **Destination is
> `.loom/event-log.md`**, *which is the durable record cast at the top of this
> file.*
**The status of our workaround changed and the code did not.** *Staging as we went
was a thing we invented and would not have thought of unaided.* **It is now
specified behaviour** — *unchanged in practice, entirely changed in standing.*
## Still uncast, because the document does not ask
**Nothing here says what a cart's `name` file must agree with.** *This round
arrived as a daily headed `rowan`, in a file called `loom-osprey.md`, with no
`name` file at all.* **The name is what tags durable entries** — *"everything
tagged with this name was considered in a single sphere of understanding"* — **so a
disagreement between the heading and the file mis-files the record, silently and
permanently.**
*Local answer: **the daily's own heading wins**, `name` is written to match, and
the file is renamed.* **Recorded here rather than filed as a gap**, *because it may
just be somebody typing fast.*