fix(sync): derive uuid from the repo's actual owner, not a hardcoded one - #48
Merged
Merged
Conversation
The uuid is DERIVED, not allocated — the registry spec defines it as
uuid = UUIDv5(namespace = URL, name = "github.com/<owner>/<name>")
so the owner segment is part of the identity. Both derivation sites hardcoded
that segment to "hyperpolymath":
sync/deploy-clade-a2ml.sh:80
sync/export-json.sh:28
Every estate repo is hyperpolymath-owned today, so the bug was invisible. It
stops being invisible the moment a repo is hosted anywhere else: the script
derives a uuid from an owner path that does not exist, writes it into
CLADE.a2ml as fact, and the repo ends up wearing an identity that belongs to
nothing.
Found while creating metadatastician/cadastra. Its true uuid is
uuidgen --sha1 --namespace @url --name "github.com/metadatastician/cadastra"
-> da97ea76-1715-5331-963b-27f011b10d22
but these scripts would have written
uuidgen --sha1 --namespace @url --name "github.com/hyperpolymath/cadastra"
-> 78c31c34-79c3-584d-bc94-50064431ca33
derived from a github.com/hyperpolymath/cadastra that does not exist.
Changes:
* parse-repos.sh — optional `owner` field, emitted as TSV column 7, defaulting
to "hyperpolymath". Existing entries need no edit and parse unchanged. It is
the last column, so any consumer reading the first six fields is unaffected.
* deploy-clade-a2ml.sh — takes owner as $7; uses it for the uuid, primary-owner
and all three forge lines. Reads 7 fields from the parser (a 7th column would
otherwise have been absorbed into `description`).
* export-json.sh — same derivation fix. No new JSON key: the schema is unchanged
on purpose, since the existing `github` field already carries "owner/name".
Two related hazards fixed while here:
* Registry/remote disagreement is now a loud failure, not a silent wrong
identity. If repos.a2ml says one owner and `git remote get-url origin` says
another, deploy warns and skips rather than deriving from the wrong one.
* ALREADY-exists now checks BOTH layouts in use across the estate:
.machine_readable/CLADE.a2ml (this script + CLADE-001)
.machine_readable/descriptiles/CLADE.a2ml (rsr-template-repo, chronicles-of-slavia)
Checking only the first meant a descriptiles-layout repo looked like it had no
CLADE, so the script wrote a SECOND one — two files, two identities, no error.
Which layout is authoritative is an unresolved canon disagreement and the
owner's to settle; until then, never overwriting an existing declaration is
the safe reading.
Verified in a clean worktree from origin/main:
* repos.json regenerated before and after the change is BYTE-IDENTICAL — all
319 existing entries derive exactly as before (none sets an explicit owner).
* The registry's own worked examples still reproduce:
januskey e216170e-ff47-5a5c-bbdd-15e61c8190c8
gv-clade-index c88e9ff3-9aac-5de8-b891-19b5de64aedd
rsr-template-repo a5ea1382-a34c-5334-8a46-a2ebe904c810
* A temporary entry with owner = "metadatastician" derives
da97ea76-1715-5331-963b-27f011b10d22 and github "metadatastician/cadastra"
— the correct values. The seed entry was then reverted: registering cadastra
is outward-facing and the owner's act (doctrine 11), not this PR's.
Every uuid quoted above was recomputed with uuidgen, not recalled.
Not addressed (pre-existing, reported not fixed): the committed worker/data/
artifacts do not match what export-json.sh currently produces — repos.json is
pretty-printed in git but the generator emits compact (3646 vs 321 lines), and
index.json differs by ~1380 lines. Regenerating is a separate, owner-facing
decision, so worker/data/ is deliberately untouched here.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
hyperpolymath
marked this pull request as ready for review
July 16, 2026 22:30
This was referenced Jul 16, 2026
hyperpolymath
added a commit
that referenced
this pull request
Jul 17, 2026
…lds (#50) Two problems, both in how a `CLADE.a2ml` gets written. The second one **defeats my own merged #48** — details below. ## 1. A code cannot express a wrong belief, so it cannot be checked for one CLADE-003 checks the code is one of the 12. It **cannot check the author meant that clade** — every code is valid whatever you thought it stood for. So these passed every gate: | repo | wrote | believing | `pt`/`gv` actually mean | |---|---|---|---| | paint-type | `primary = "pt"` | "**P**ain**T**-type" | Protocols & Interop (it is an image editor → `ap`) | | gossamer | `primary = "gv"` | "**G**raphical/**V**isual" | Governance & Standards (there is no graphical clade → `dx`) | **The two letters abbreviate the CLADE's name. They never abbreviate the REPO's name.** It is a closed taxonomy of categories, not an abbreviation scheme — but nothing said so at the point of authoring, and nothing could catch it. ### Fix: write the name beside the code, and check the pair ```toml [clade] primary = "ap" primary-name = "Applications" ``` CLADE-006 (BLOCK, pre-commit) rejects any pair disagreeing with `verisim/seed/clades.a2ml`. **The redundancy is the point** — the *pair* can express the wrong belief, so the pair can be rejected. Verified on all 10 cases, including both real historical errors: ``` ap|Applications PASS dx|Developer Ecosystem PASS gv|Governance & Standards PASS (ampersand survives) pt|PainT-type FAIL <- the actual paint-type error gv|Graphical/Visual FAIL <- the actual gossamer error pt|Applications FAIL valid code, wrong name ap|Protocols & Interop FAIL valid name, wrong code zz|Applications FAIL invalid code ap|<missing> FAIL cannot omit the name UNASSIGNED|UNASSIGNED FAIL template default fails loudly ``` `clades.a2ml` and the spec now state the rule and name both real errors, so the next author reads *why* before choosing. `deploy-clade-a2ml.sh` emits `primary-name` and refuses to write an identity it cannot name. ## 2. The TSV reader collapsed empty fields — 153 files already corrupted **Tab is IFS whitespace**, so `IFS=$'\t' read` treats a run of tabs as **one** delimiter: empty fields vanish and everything after shifts left. **316 of 319** seed entries have an empty `parent` — this was the normal case, not an edge case: ``` proven <tab> fv <tab> [] <tab> standalone <tab><tab> Formally verified… <tab> hyperpolymath ^^ empty parent collapses -> parent="Formally verified…" description="hyperpolymath" owner="" ``` **The damage is real and committed — 153 CLADE.a2ml files** carry `rationale = ""` with the repo's *description* sitting in `parent`: ``` panic-attack parent = "Security scanning tool — static analysis…" flat-mate parent = "Flat/apartment sharing management…" rpa-elysium parent = "Robotic Process Automation framework…" live-files parent = "Live file synchronisation tool…" ``` ### This defeated #48, and #48's own test could not see it The `owner` support I added in #48 **never worked here**: `$7` was always empty, so `owner` always fell back to `hyperpolymath` and an explicit `owner = "metadatastician"` was ignored. #48's byte-identical regression test passed because `export-json.sh` uses `awk -F'\t'`, which does **not** collapse — the two derivation sites disagreed and only the tested one was correct. My apologies: I shipped that. ### Fix Translate tabs to US (`0x1f`) before reading. It is not IFS whitespace so runs are not collapsed, it cannot occur in the data (0 occurrences in `repos.a2ml`), and it is exactly what the ASCII unit separator is for. The parser's TSV contract is unchanged. ## Verification Scratch tree, end to end: ``` proven (empty parent — the 316-entry case) rationale = "Formally verified safety library — Idris2 dependent types…" (was "") parent = "" (was the description) uuid = ffa8e1f5-… (unchanged, matches registry) cadastra (owner = "metadatastician" in seed) uuid = da97ea76-1715-5331-963b-27f011b10d22 <- correct; #48 works for the first time primary-owner = "metadatastician" ``` Also: `repos.json` regenerates **byte-identical** (no uuid moves), both a2ml files still parse as **TOML** (the dogfood gate uses `tomllib`), and the spec renders under asciidoctor. ## Not in this PR Repairing the **153 already-corrupted files** is a separate, owner-facing job — this only stops the script producing more. Related: #49. Draft: this changes the clade contract for every repo, so it is yours to review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
hyperpolymath
added a commit
to metadatastician/gossamer
that referenced
this pull request
Jul 17, 2026
…tradicted itself (#113) This file declared two things that cannot both be true: ```toml primary-owner = "hyperpolymath" [forges] github = "metadatastician/gossamer" ``` The uuid was correctly derived from the owner it declared: ``` uuidgen --sha1 --namespace @url --name "github.com/hyperpolymath/gossamer" -> 62caa738-137e-5390-bdff-453f475e94b7 # the old value ``` **but that URL 404s.** gossamer does not exist in the hyperpolymath org. It exists at `metadatastician/gossamer` — which is what `git remote get-url origin` says, and what `[forges]` already said. So gossamer's identity was derived from a repo that is not there. **Not a typo.** `gv-clade-index/sync/deploy-clade-a2ml.sh:80` hardcoded the owner segment to `hyperpolymath` for every repo it wrote, so any repo hosted elsewhere got an identity belonging to nothing. gossamer is a live victim. Fixed upstream in hyperpolymath/gv-clade-index#48. ## The fix ``` uuid = UUIDv5(URL, "github.com/<owner>/<name>") uuidgen --sha1 --namespace @url --name "github.com/metadatastician/gossamer" -> 16eef45c-0690-5b12-8018-904891430cae ``` Method verified by reproducing the registry's own worked examples byte-for-byte first (`januskey`, `gv-clade-index`, `rsr-template-repo`). Nothing depended on the old value — gossamer is in neither the seed nor `worker/data/repos.json`. **Not registered** by this PR; that is outward-facing and yours (doctrine 11). ✅ Verified: the uuid now **self-checks**, and `primary-owner`, `[forges]` and the real git remote all agree. ## Separate problem, NOT fixed here — needs your call The clade rationale reads: > `rationale = "Gossamer is a webview/GUI-layer project; gv (graphical/visual) clade."` But in the registry taxonomy (`verisim/seed/clades.a2ml`), **`gv` is Governance & Standards** — "licensing, compliance, policy enforcement". There is no "graphical/visual" clade. So the rationale appears to have picked `gv` from a misreading of the code, and a webview/GUI project would more plausibly be `ap` (Applications) or `dx` (Developer Ecosystem). That also makes `prefixed-name = "gv-gossamer"` suspect. I left all of it untouched: the clade is a judgement, not a derivation, and it is yours to ratify. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



The uuid is derived, not allocated. The spec defines it as
so the owner segment is part of the identity. Both derivation sites hardcoded it to
hyperpolymath:sync/deploy-clade-a2ml.sh:80sync/export-json.sh:28Every estate repo is hyperpolymath-owned today, so the bug is invisible. It stops being invisible the moment a repo is hosted anywhere else: the script derives a uuid from an owner path that does not exist, writes it into
CLADE.a2mlas fact, and the repo wears an identity belonging to nothing.Found while creating
metadatastician/cadastra. Its true uuid is:but these scripts would have written:
Changes
parse-repos.sh— optionalownerfield, emitted as TSV column 7, defaulting tohyperpolymath. Existing entries need no edit. Last column, so consumers reading the first six fields are unaffected.deploy-clade-a2ml.sh— takes owner as$7; uses it for the uuid,primary-owner, and all three forge lines. Now reads 7 fields (a 7th column would otherwise be absorbed intodescription).export-json.sh— same fix. No new JSON key — schema unchanged on purpose, sincegithubalready carriesowner/name.Two related hazards fixed while here
repos.a2mlsays one owner andgit remote get-url originsays another, deploy warns and skips rather than silently deriving a wrong identity.ALREADYchecks both layouts. Two are in use:.machine_readable/CLADE.a2ml(this script + CLADE-001) and.machine_readable/descriptiles/CLADE.a2ml(rsr-template-repo, chronicles-of-slavia). Checking only the first meant a descriptiles-layout repo looked like it had no CLADE, so this script wrote a second one — two files, two identities, no error. Which layout is authoritative is an unresolved canon disagreement and yours to settle; until then, refusing to overwrite is the safe reading.Verification
Clean worktree from
origin/main:repos.jsonregenerated before/after is BYTE-IDENTICAL — all 319 existing entries derive exactly as before (none sets an explicit owner).januskey → e216170e-…,gv-clade-index → c88e9ff3-…,rsr-template-repo → a5ea1382-….owner = "metadatastician"derivesda97ea76-…andgithub "metadatastician/cadastra". The seed entry was reverted — registering cadastra is outward-facing and yours (doctrine 11), not this PR's.Every uuid quoted was recomputed with
uuidgen, not recalled.Not addressed (pre-existing)
The committed
worker/data/artifacts do not match whatexport-json.shproduces —repos.jsonis pretty-printed in git but the generator emits compact (3646 vs 321 lines);index.jsondiffers by ~1380 lines. Regenerating is a separate, owner-facing decision, soworker/data/is deliberately untouched.Draft: this changes how estate identity is derived, so it is for the owner to review and merge.
🤖 Generated with Claude Code