add appended .md unconditionally, so openapi.json became openapi.json.md. Reported
from use against a repository that publishes an OpenAPI document beside its prose.
It is now supplied only when the name carries no extension of its own.
Two consequences came with it that the report could not have seen. A facet's name
was built by stripping the extension, so openapi.json would have taken
openapi.usages.md and collided with the facet for a sibling openapi.md; only a
trailing .md is stripped now. And the unlocked walk matched *.md only, so a
hand-fetched .json under .loom/externals was adopted, unlocked, and invisible to
check; it now walks everything that is not the lock file or a dotfile.
The assumption was never decided, it was typed. externals says a repository
publishes documents and publication says prose in whatever form its readers need.
Neither says markdown and three places in this tool did.
Also records that the wrong diagnosis cost more than the bug: the repository is
private, a scratch config with no token made every fetch look broken, and loomctl
config would have said so in one line.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018UTxuSizozEA8yDitPuris
Go, standard library only, with git shelled out for list alone. list enumerates a
publisher's .loom/published by partial clone and ls-tree; add fetches one document,
writes it under .loom/externals and records the resolved origin and the publisher's
ETag in .loom/externals/.locks; check asks conditionally and reports.
The first real run did what the tool exists for. All eight documents adopted by
hand before it existed reported unlocked — the tool refuses to invent a lock by
adopting whatever the remote currently serves, since that would assert the local
copy is the one being served, which is the thing it was about to check. Locking
them fetched two that had moved: bedrock/starting.md, which now says the worked
example is private and will not link to something you cannot fetch, and cart.md,
which went to v1.
cart v1 changes a role we cast: a cart is not committed, because a committed cart
grows a third file by itself — version control does not require anybody to ask, so
the two-file rule is never invoked — and because ignored, gone means gone. Adds
.loom/cart/ to .gitignore and supersedes the isolation entry rather than editing
it. osprey and marmalade are already in history and are left there: rewriting to
honour a rule adopted afterwards costs more than it buys.
Records the conflict this creates rather than settling it: the annotation protocol
here says commit before dissolving because git is the only archive, and an ignored
cart has no archive, so dissolving would destroy the annotations outright.
Credentials are read-only, per host, and passed to git through the environment
rather than argv, because argv is visible to every process on the machine.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018UTxuSizozEA8yDitPuris