From 68cbfcc080cc270632848d6b9d438fce5dc653ff Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Wed, 26 Aug 2026 20:36:27 +0100 Subject: [PATCH 1/3] =?UTF-8?q?fix(validate):=20match=20BOTH=20machine-tre?= =?UTF-8?q?e=20names=20=E2=80=94=20the=20rename=20broke=2016=20checks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `validate-a2ml.sh` exempts files under a repo's machine tree from the in-file identity requirement, because per RSR convention those carry identity structurally (owning repo + path + filename) rather than via `name`/`agent-id`. That exemption matched `.machine_readable/` only. rsr-template-repo has renamed its machine tree to `machine-readable/` (un-hidden, 2026-08), so its 16 typed manifests fell out of the exemption's reach and this action began reporting 16 spurious "Missing required identity field" errors on a tree that had not changed in any way that matters to identity. MEASURED against rsr-template-repo, run as the action runs it: old single-path form Files scanned: 123 Errors: 16 new dual-path form Files scanned: 123 Errors: 0 Worth recording HOW this was missed. The template vendors its own copy at `.githooks/validate-a2ml.sh`, which was updated with the rename and reported 0 errors locally. This action is a SEPARATE implementation of the same check, in a different repo, invoked as a pinned action — so the local run was green while CI was red, and the local checker was simply not the checker CI uses. Two copies of one rule, only one of them updated. BOTH names are matched, not swapped. The canon, scaffoldia, the julia variant and ~300 minted repos still carry the dotted form; matching only the new name would move the same breakage onto them. The new `case` matches a strict superset of the old pattern, so it can only ever exempt more — a legacy repo cannot regress. Verified: scaffoldia (legacy tree) still reports 0 errors. Remove the legacy alternative once the estate migration completes. Co-Authored-By: Claude Opus 5 --- validate-action/validate-a2ml.sh | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/validate-action/validate-a2ml.sh b/validate-action/validate-a2ml.sh index b053676..0d95ae0 100755 --- a/validate-action/validate-a2ml.sh +++ b/validate-action/validate-a2ml.sh @@ -213,10 +213,23 @@ validate_a2ml() { # files without an in-file identity key, so requiring one produces # estate-wide false positives on every repo built from the canonical # template. Files outside `.machine_readable/` are still validated. + # + # The machine tree is named `machine-readable/` canonically (un-hidden + # 2026-08); `.machine_readable/` is the LEGACY name. BOTH are matched: the + # canon, scaffoldia, the julia variant and ~300 minted repos still carry the + # dotted form, while rsr-template-repo has moved. Matching only one name + # makes whichever half of the estate has not migrated fail this check with + # 16 spurious "missing identity field" errors -- which is exactly what + # happened when the template renamed its tree and this action, being a + # separate implementation from the template's vendored copy, kept matching + # the old name only. local is_structural_identity=false - if [[ "$file" == *"/.machine_readable/"* || "$file" == "./.machine_readable/"* || "$file" == ".machine_readable/"* ]]; then - is_structural_identity=true - fi + case "$file" in + */machine-readable/*|./machine-readable/*|machine-readable/*| \ + */.machine_readable/*|./.machine_readable/*|.machine_readable/*) + is_structural_identity=true + ;; + esac if [[ "$has_identity" == "false" && "$is_manifest" == "false" && "$is_contractile_shape" == "false" && "$is_structural_identity" == "false" ]]; then report_issue "error" "$file" 1 \ From d486ad1e0f0483745e9013516afbd3dd6826748d Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Wed, 26 Aug 2026 22:50:03 +0100 Subject: [PATCH 2/3] refactor(validate): drop redundant ./-prefixed case alternatives CodeRabbit is right, and verified rather than taken on trust: `*` matches the empty string in a case pattern, so */machine-readable/* already covers the ./-prefixed form that `find .` emits. Six alternatives collapse to four. Checked across every path shape the script can see - ./-prefixed (what find "$SCAN_PATH" produces with the default "."), bare, and absolute - plus the negative cases (./docs/..., src/machine-readableish/...). Identical verdicts. Note the redundancy was PRE-EXISTING in the original three-branch test (*"/.machine_readable/"* || "./.machine_readable/"* || ".machine_readable/"*); mirroring it for the second name doubled it. This improves on the original rather than merely undoing the addition. Behaviour unchanged: rsr-template-repo 123 files / 0 errors, scaffoldia (legacy tree) 0 errors. Co-Authored-By: Claude Opus 5 --- validate-action/validate-a2ml.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/validate-action/validate-a2ml.sh b/validate-action/validate-a2ml.sh index 0d95ae0..eae7cac 100755 --- a/validate-action/validate-a2ml.sh +++ b/validate-action/validate-a2ml.sh @@ -224,9 +224,12 @@ validate_a2ml() { # separate implementation from the template's vendored copy, kept matching # the old name only. local is_structural_identity=false + # `*` matches the empty string, so */machine-readable/* already covers the + # ./-prefixed form that `find .` emits; spelling it out separately (as the + # original three-branch test did) is redundant. Verified equivalent across + # ./-prefixed, bare and absolute paths, and on the negative cases. case "$file" in - */machine-readable/*|./machine-readable/*|machine-readable/*| \ - */.machine_readable/*|./.machine_readable/*|.machine_readable/*) + */machine-readable/*|machine-readable/*|*/.machine_readable/*|.machine_readable/*) is_structural_identity=true ;; esac From 900fa5a8268a7d2889a02e2bf046d30f379077bf Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Wed, 26 Aug 2026 23:13:25 +0100 Subject: [PATCH 3/3] docs(validate): reconcile the comments with the dual-path logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codacy is right: adding the dual-path note left the paragraph ABOVE it still calling `.machine_readable/` the "Canonical" tree and saying "Files outside `.machine_readable/` are still validated" — directly contradicting the case statement three lines below, which now matches both names. Two adjacent comments disagreeing about which name is canonical is worse than either being wrong on its own, because a reader cannot tell which one the code follows. Both now describe the machine tree neutrally: `machine-readable/` canonical, `.machine_readable/` legacy, both matched. Also fixed the same stale claim at line 175 (the descriptiles-specific block). Half-fixing a consistency problem leaves the reader in the same position. Comment-only; no behaviour change. Re-verified: rsr-template-repo 123 files / 0 errors, scaffoldia (legacy tree) 0 errors. Co-Authored-By: Claude Opus 5 --- validate-action/validate-a2ml.sh | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/validate-action/validate-a2ml.sh b/validate-action/validate-a2ml.sh index eae7cac..8c57119 100755 --- a/validate-action/validate-a2ml.sh +++ b/validate-action/validate-a2ml.sh @@ -172,7 +172,7 @@ validate_a2ml() { if [[ "$basename" == *"AI-MANIFEST"* ]]; then is_manifest=true fi - # Canonical typed manifests under .machine_readable/descriptiles/ — identity comes + # Canonical typed manifests under /descriptiles/ — identity comes # from the enclosing directory + filename, not an in-file field. Sibling # files in the same directory (ECOSYSTEM.a2ml, STATE.a2ml) DO carry their # own $name/project and continue to be validated normally. @@ -203,16 +203,17 @@ validate_a2ml() { is_contractile_shape=true fi - # Canonical structured A2ML tree. Everything under a `.machine_readable/` - # directory is a typed agent-readable doc (CLADE, ANCHOR, STATE, - # ECOSYSTEM, bot_directives/{debt,coverage,methodology}, ai/AI, - # policies/*, integrations/*, …). Per the RSR convention these carry - # identity structurally — owning repo + path + filename — not via an - # in-file `name`/`agent-id`. This generalises the `.machine_readable/descriptiles/` - # rationale above to the whole tree: rsr-template-repo itself ships these - # files without an in-file identity key, so requiring one produces - # estate-wide false positives on every repo built from the canonical - # template. Files outside `.machine_readable/` are still validated. + # The structured A2ML tree. Everything under a repo's machine tree — + # `machine-readable/` canonically, `.machine_readable/` in the legacy + # layout — is a typed agent-readable doc (CLADE, ANCHOR, STATE, ECOSYSTEM, + # bot_directives/{debt,coverage,methodology}, ai/AI, policies/*, + # integrations/*, …). Per the RSR convention these carry identity + # structurally — owning repo + path + filename — not via an in-file + # `name`/`agent-id`. This generalises the `descriptiles/` rationale above + # to the whole tree: rsr-template-repo itself ships these files without an + # in-file identity key, so requiring one produces estate-wide false + # positives on every repo built from the canonical template. Files outside + # the machine tree are still validated. # # The machine tree is named `machine-readable/` canonically (un-hidden # 2026-08); `.machine_readable/` is the LEGACY name. BOTH are matched: the