From 09089bdcfdaa61471a0a00494627490ee1c6cf38 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Fri, 9 Oct 2026 02:48:52 +0100 Subject: [PATCH 1/2] feat(validate): add the repo deed and import the template's validate recipes The inline validate-rsr / validate-state recipes still checked the retired .a2ml layout (0-AI-MANIFEST.a2ml, STATE/META/ECOSYSTEM.a2ml). This replaces them with rsr-template-repo's build/just/validate.just, which reads the repo deed, and adds that deed. - jaffascript_chora.deed: identity, clade, forges, lineage, status and maturity carried from CLADE.a2ml and STATE.a2ml; ecosystem, meta and anchor from this repo's own records and README; the three maintenance policies in the template deed's form. Lints clean with standards deed_lint.js. - scripts/deed-field.sh, scripts/check-no-a2ml.sh: copied unchanged from rsr-template-repo 3e6d4aa. - build/just/validate.just: copied from the same commit, with one change: the licence check names LICENSES/MPL-2.0.txt and LICENSES/CC-BY-SA-4.0.txt (this repo's licences) instead of the template's EXHIBIT files. - Justfile and .machine_readable/contractiles/Justfile: the inline validate-* recipes are replaced by `import? "build/just/validate.just"`. The two files stay byte-identical. - .gitignore: /build/ becomes /build/* with !/build/just/, so the recipe file is tracked while build output stays ignored. `just validate-rsr` now fails on one item only, no-a2ml: the .a2ml files remain until the conversion front end exists (D313). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GpUzjdhWFi26k6s7AWxYcf --- .gitignore | 3 +- .machine_readable/contractiles/Justfile | 123 +-------- Justfile | 123 +-------- build/just/validate.just | 196 ++++++++++++++ jaffascript_chora.deed | 339 ++++++++++++++++++++++++ scripts/check-no-a2ml.sh | 30 +++ scripts/deed-field.sh | 188 +++++++++++++ 7 files changed, 759 insertions(+), 243 deletions(-) create mode 100644 build/just/validate.just create mode 100644 jaffascript_chora.deed create mode 100755 scripts/check-no-a2ml.sh create mode 100755 scripts/deed-field.sh diff --git a/.gitignore b/.gitignore index deaa35b..db39cd3 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,8 @@ Thumbs.db # Build /target/ /_build/ -/build/ +/build/* +!/build/just/ /dist/ /out/ diff --git a/.machine_readable/contractiles/Justfile b/.machine_readable/contractiles/Justfile index 290f655..4d37091 100644 --- a/.machine_readable/contractiles/Justfile +++ b/.machine_readable/contractiles/Justfile @@ -1043,129 +1043,10 @@ sbom: @command -v syft >/dev/null && syft . -o spdx-json > docs/security/sbom.spdx.json || echo "syft not found" # ═══════════════════════════════════════════════════════════════════════════════ -# VALIDATION & COMPLIANCE +# VALIDATION & COMPLIANCE — see build/just/validate.just # ═══════════════════════════════════════════════════════════════════════════════ -# Validate RSR compliance -validate-rsr: - #!/usr/bin/env bash - echo "=== RSR Compliance Check ===" - MISSING="" - for f in .editorconfig .gitignore Justfile README.adoc LICENSE 0-AI-MANIFEST.a2ml; do - [ -f "$f" ] || MISSING="$MISSING $f" - done - for f in .machine_readable/STATE.a2ml .machine_readable/META.a2ml .machine_readable/ECOSYSTEM.a2ml .machine_readable/anchors/ANCHOR.a2ml .machine_readable/policies/MAINTENANCE-AXES.a2ml .machine_readable/policies/MAINTENANCE-CHECKLIST.a2ml .machine_readable/policies/SOFTWARE-DEVELOPMENT-APPROACH.a2ml; do - [ -f "$f" ] || MISSING="$MISSING $f" - done - for f in LICENSES/MPL-2.0.txt LICENSES/CC-BY-SA-4.0.txt; do - [ -f "$f" ] || MISSING="$MISSING $f" - done - if [ ! -d "src/interface/Abi" ] && [ ! -d "src/interface/abi" ]; then - MISSING="$MISSING src/interface/Abi" - fi - for f in src/interface/ffi src/interface/generated; do - [ -d "$f" ] || MISSING="$MISSING $f" - done - for f in docs/governance/MAINTENANCE-CHECKLIST.adoc docs/governance/SOFTWARE-DEVELOPMENT-APPROACH.adoc; do - [ -f "$f" ] || MISSING="$MISSING $f" - done - if [ -f ".machine_readable/META.a2ml" ]; then - grep -q 'axis-1 = "must > intend > like"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:axis-1" - grep -q 'axis-2 = "corrective > adaptive > perfective"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:axis-2" - grep -q 'axis-3 = "systems > compliance > effects"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:axis-3" - grep -q 'scoping-first = true' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:scoping-first" - grep -q 'idris-unsound-scan = "believe_me/assert_total"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:idris-unsound-scan" - grep -q 'audit-focus = "systems in place, documentation explains actual state, safety/security accounted for, observed effects reviewed"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:audit-focus" - grep -q 'compliance-focus = "seams/compromises/exception register, bounded exceptions, anti-drift checks"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:compliance-focus" - grep -q 'effects-evidence = "benchmark execution/results and maintainer status dialogue/review"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:effects-evidence" - grep -q 'compliance-tooling = "panic-attack"' .machine_readable/policies/MAINTENANCE-AXES.a2ml || MISSING="$MISSING MAINTENANCE-AXES.a2ml:compliance-tooling" - grep -q 'effects-tooling = "ecological checking with sustainabot guidance"' .machine_readable/policies/MAINTENANCE-AXES.a2ml || MISSING="$MISSING MAINTENANCE-AXES.a2ml:effects-tooling" - grep -q 'source-human = "docs/governance/MAINTENANCE-CHECKLIST.adoc"' .machine_readable/policies/MAINTENANCE-CHECKLIST.a2ml || MISSING="$MISSING MAINTENANCE-CHECKLIST.a2ml:source-human" - grep -q 'source-human = "docs/governance/SOFTWARE-DEVELOPMENT-APPROACH.adoc"' .machine_readable/policies/SOFTWARE-DEVELOPMENT-APPROACH.a2ml || MISSING="$MISSING SOFTWARE-DEVELOPMENT-APPROACH.a2ml:source-human" - fi - if [ -n "$MISSING" ]; then - echo "MISSING:$MISSING" - exit 1 - fi - echo "RSR compliance: PASS" - -# Validate STATE.a2ml syntax -validate-state: - @if [ -f ".machine_readable/STATE.a2ml" ]; then \ - grep -q '^\[metadata\]' .machine_readable/STATE.a2ml && \ - grep -q 'project\s*=' .machine_readable/STATE.a2ml && \ - echo "STATE.a2ml: valid" || echo "STATE.a2ml: INVALID (missing required sections)"; \ - else \ - echo "No .machine_readable/STATE.a2ml found"; \ - fi - -# Validate AI installation guide completeness (finishbot pre-release check) -validate-ai-install: - #!/usr/bin/env bash - echo "=== AI Installation Guide Check ===" - GUIDE="docs/AI_INSTALLATION_GUIDE.adoc" - README="README.adoc" - ERRORS=0 - - # Check guide exists - if [ ! -f "$GUIDE" ]; then - echo "MISSING: $GUIDE (create from template: docs/AI_INSTALLATION_GUIDE.adoc)" - ERRORS=$((ERRORS + 1)) - else - # Check for unfilled TODO markers - TODOS=$(grep -c '\[TODO-AI-INSTALL' "$GUIDE" 2>/dev/null || true) - if [ "$TODOS" -gt 0 ]; then - echo "INCOMPLETE: $GUIDE has $TODOS unfilled [TODO-AI-INSTALL] markers:" - grep -n '\[TODO-AI-INSTALL' "$GUIDE" | head -10 - ERRORS=$((ERRORS + 1)) - else - echo "$GUIDE: complete (no TODO markers)" - fi - - # Check AI implementation section exists - if ! grep -q 'ai-implementation' "$GUIDE" 2>/dev/null; then - echo "MISSING: [[ai-implementation]] anchor in $GUIDE" - ERRORS=$((ERRORS + 1)) - fi - - # Check privacy notice exists - if ! grep -qi 'privacy' "$GUIDE" 2>/dev/null; then - echo "MISSING: Privacy notice in $GUIDE" - ERRORS=$((ERRORS + 1)) - fi - - # Check install commands exist (not just placeholders) - if ! grep -q 'git clone' "$GUIDE" 2>/dev/null; then - echo "WARNING: No git clone command found in $GUIDE -- install commands may be incomplete" - fi - fi - - # Check README has AI install section - if [ -f "$README" ]; then - if ! grep -qi 'AI-Assisted Installation' "$README" 2>/dev/null; then - echo "MISSING: AI-Assisted Installation section in $README" - echo " Copy from docs/AI-INSTALL-README-SECTION.adoc" - ERRORS=$((ERRORS + 1)) - fi - - # Check README for unfilled TODO markers - README_TODOS=$(grep -c '\[TODO-AI-INSTALL' "$README" 2>/dev/null || true) - if [ "$README_TODOS" -gt 0 ]; then - echo "INCOMPLETE: $README has $README_TODOS unfilled [TODO-AI-INSTALL] markers" - ERRORS=$((ERRORS + 1)) - fi - fi - - if [ "$ERRORS" -gt 0 ]; then - echo "" - echo "AI install guide: FAIL ($ERRORS issues)" - exit 1 - fi - echo "AI install guide: PASS" - -# Full validation suite -validate: validate-rsr validate-state validate-ai-install - @echo "All validations passed!" +import? "build/just/validate.just" # ═══════════════════════════════════════════════════════════════════════════════ # STATE MANAGEMENT diff --git a/Justfile b/Justfile index 290f655..4d37091 100644 --- a/Justfile +++ b/Justfile @@ -1043,129 +1043,10 @@ sbom: @command -v syft >/dev/null && syft . -o spdx-json > docs/security/sbom.spdx.json || echo "syft not found" # ═══════════════════════════════════════════════════════════════════════════════ -# VALIDATION & COMPLIANCE +# VALIDATION & COMPLIANCE — see build/just/validate.just # ═══════════════════════════════════════════════════════════════════════════════ -# Validate RSR compliance -validate-rsr: - #!/usr/bin/env bash - echo "=== RSR Compliance Check ===" - MISSING="" - for f in .editorconfig .gitignore Justfile README.adoc LICENSE 0-AI-MANIFEST.a2ml; do - [ -f "$f" ] || MISSING="$MISSING $f" - done - for f in .machine_readable/STATE.a2ml .machine_readable/META.a2ml .machine_readable/ECOSYSTEM.a2ml .machine_readable/anchors/ANCHOR.a2ml .machine_readable/policies/MAINTENANCE-AXES.a2ml .machine_readable/policies/MAINTENANCE-CHECKLIST.a2ml .machine_readable/policies/SOFTWARE-DEVELOPMENT-APPROACH.a2ml; do - [ -f "$f" ] || MISSING="$MISSING $f" - done - for f in LICENSES/MPL-2.0.txt LICENSES/CC-BY-SA-4.0.txt; do - [ -f "$f" ] || MISSING="$MISSING $f" - done - if [ ! -d "src/interface/Abi" ] && [ ! -d "src/interface/abi" ]; then - MISSING="$MISSING src/interface/Abi" - fi - for f in src/interface/ffi src/interface/generated; do - [ -d "$f" ] || MISSING="$MISSING $f" - done - for f in docs/governance/MAINTENANCE-CHECKLIST.adoc docs/governance/SOFTWARE-DEVELOPMENT-APPROACH.adoc; do - [ -f "$f" ] || MISSING="$MISSING $f" - done - if [ -f ".machine_readable/META.a2ml" ]; then - grep -q 'axis-1 = "must > intend > like"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:axis-1" - grep -q 'axis-2 = "corrective > adaptive > perfective"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:axis-2" - grep -q 'axis-3 = "systems > compliance > effects"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:axis-3" - grep -q 'scoping-first = true' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:scoping-first" - grep -q 'idris-unsound-scan = "believe_me/assert_total"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:idris-unsound-scan" - grep -q 'audit-focus = "systems in place, documentation explains actual state, safety/security accounted for, observed effects reviewed"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:audit-focus" - grep -q 'compliance-focus = "seams/compromises/exception register, bounded exceptions, anti-drift checks"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:compliance-focus" - grep -q 'effects-evidence = "benchmark execution/results and maintainer status dialogue/review"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:effects-evidence" - grep -q 'compliance-tooling = "panic-attack"' .machine_readable/policies/MAINTENANCE-AXES.a2ml || MISSING="$MISSING MAINTENANCE-AXES.a2ml:compliance-tooling" - grep -q 'effects-tooling = "ecological checking with sustainabot guidance"' .machine_readable/policies/MAINTENANCE-AXES.a2ml || MISSING="$MISSING MAINTENANCE-AXES.a2ml:effects-tooling" - grep -q 'source-human = "docs/governance/MAINTENANCE-CHECKLIST.adoc"' .machine_readable/policies/MAINTENANCE-CHECKLIST.a2ml || MISSING="$MISSING MAINTENANCE-CHECKLIST.a2ml:source-human" - grep -q 'source-human = "docs/governance/SOFTWARE-DEVELOPMENT-APPROACH.adoc"' .machine_readable/policies/SOFTWARE-DEVELOPMENT-APPROACH.a2ml || MISSING="$MISSING SOFTWARE-DEVELOPMENT-APPROACH.a2ml:source-human" - fi - if [ -n "$MISSING" ]; then - echo "MISSING:$MISSING" - exit 1 - fi - echo "RSR compliance: PASS" - -# Validate STATE.a2ml syntax -validate-state: - @if [ -f ".machine_readable/STATE.a2ml" ]; then \ - grep -q '^\[metadata\]' .machine_readable/STATE.a2ml && \ - grep -q 'project\s*=' .machine_readable/STATE.a2ml && \ - echo "STATE.a2ml: valid" || echo "STATE.a2ml: INVALID (missing required sections)"; \ - else \ - echo "No .machine_readable/STATE.a2ml found"; \ - fi - -# Validate AI installation guide completeness (finishbot pre-release check) -validate-ai-install: - #!/usr/bin/env bash - echo "=== AI Installation Guide Check ===" - GUIDE="docs/AI_INSTALLATION_GUIDE.adoc" - README="README.adoc" - ERRORS=0 - - # Check guide exists - if [ ! -f "$GUIDE" ]; then - echo "MISSING: $GUIDE (create from template: docs/AI_INSTALLATION_GUIDE.adoc)" - ERRORS=$((ERRORS + 1)) - else - # Check for unfilled TODO markers - TODOS=$(grep -c '\[TODO-AI-INSTALL' "$GUIDE" 2>/dev/null || true) - if [ "$TODOS" -gt 0 ]; then - echo "INCOMPLETE: $GUIDE has $TODOS unfilled [TODO-AI-INSTALL] markers:" - grep -n '\[TODO-AI-INSTALL' "$GUIDE" | head -10 - ERRORS=$((ERRORS + 1)) - else - echo "$GUIDE: complete (no TODO markers)" - fi - - # Check AI implementation section exists - if ! grep -q 'ai-implementation' "$GUIDE" 2>/dev/null; then - echo "MISSING: [[ai-implementation]] anchor in $GUIDE" - ERRORS=$((ERRORS + 1)) - fi - - # Check privacy notice exists - if ! grep -qi 'privacy' "$GUIDE" 2>/dev/null; then - echo "MISSING: Privacy notice in $GUIDE" - ERRORS=$((ERRORS + 1)) - fi - - # Check install commands exist (not just placeholders) - if ! grep -q 'git clone' "$GUIDE" 2>/dev/null; then - echo "WARNING: No git clone command found in $GUIDE -- install commands may be incomplete" - fi - fi - - # Check README has AI install section - if [ -f "$README" ]; then - if ! grep -qi 'AI-Assisted Installation' "$README" 2>/dev/null; then - echo "MISSING: AI-Assisted Installation section in $README" - echo " Copy from docs/AI-INSTALL-README-SECTION.adoc" - ERRORS=$((ERRORS + 1)) - fi - - # Check README for unfilled TODO markers - README_TODOS=$(grep -c '\[TODO-AI-INSTALL' "$README" 2>/dev/null || true) - if [ "$README_TODOS" -gt 0 ]; then - echo "INCOMPLETE: $README has $README_TODOS unfilled [TODO-AI-INSTALL] markers" - ERRORS=$((ERRORS + 1)) - fi - fi - - if [ "$ERRORS" -gt 0 ]; then - echo "" - echo "AI install guide: FAIL ($ERRORS issues)" - exit 1 - fi - echo "AI install guide: PASS" - -# Full validation suite -validate: validate-rsr validate-state validate-ai-install - @echo "All validations passed!" +import? "build/just/validate.just" # ═══════════════════════════════════════════════════════════════════════════════ # STATE MANAGEMENT diff --git a/build/just/validate.just b/build/just/validate.just new file mode 100644 index 0000000..c6ccfa9 --- /dev/null +++ b/build/just/validate.just @@ -0,0 +1,196 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# VALIDATION & COMPLIANCE +# +# Imported by ../../Justfile via `import? "build/just/validate.just"`. +# Recipes here check that this repo conforms to the RSR (Rhodium Standard +# Repository) skeleton: required files, METAdata, AI install guide +# completeness, etc. Run via `just validate`. + +# Validate RSR compliance +validate-rsr: + #!/usr/bin/env bash + cd "{{justfile_directory()}}" + echo "=== RSR Compliance Check ===" + MISSING="" + for f in .editorconfig .gitignore Justfile README.adoc LICENSE; do + [ -f "$f" ] || MISSING="$MISSING $f" + done + # The repo deed's filename carries the repo slug (_chora.deed), so + # this is a glob. + ls *_chora.deed >/dev/null 2>&1 || MISSING="$MISSING repo-deed (*_chora.deed)" + # .a2ml is retired: a repo carrying one is non-conformant, whatever else holds. + bash scripts/check-no-a2ml.sh . >/dev/null || MISSING="$MISSING no-a2ml(run scripts/check-no-a2ml.sh)" + for f in LICENSES/MPL-2.0.txt LICENSES/CC-BY-SA-4.0.txt; do + [ -f "$f" ] || MISSING="$MISSING $f" + done + if [ ! -d "src/interface/abi" ] && [ ! -d "src/interface/Abi" ]; then + MISSING="$MISSING src/interface/abi" + fi + for f in src/interface/ffi src/interface/generated; do + [ -d "$f" ] || MISSING="$MISSING $f" + done + for f in docs/governance/MAINTENANCE-CHECKLIST.adoc docs/governance/SOFTWARE-DEVELOPMENT-APPROACH.adoc; do + [ -f "$f" ] || MISSING="$MISSING $f" + done + # Identity, lifecycle, maintenance axes, the anchor and the maintenance + # policies are all clauses of the repo deed (rsr-template-repo#209). + DEED=$(bash scripts/deed-field.sh --find . || true) + if [ -n "$DEED" ] && bash scripts/deed-field.sh --has "$DEED" status; then + # Prints the field, or nothing when it is absent. + field() { bash scripts/deed-field.sh "$DEED" "$1" "$2" || true; } + # Adds a MISSING entry unless deed field CLAUSE KEY equals the expected value. + want() { + [ "$(field "$1" "$2")" = "$3" ] || MISSING="$MISSING $DEED:$1:$2" + } + [ -n "$(field "" repo-uuid)" ] || MISSING="$MISSING $DEED:repo-uuid" + # CLADE-003/006 on the deed: a closed code set, and the code must agree + # with its name. UNASSIGNED fails on purpose: an unchosen clade must + # never be mistakable for a chosen one. + case "$(field clade primary)|$(field clade primary-name)" in + "fv|Formal Verification & Proofs"|"nl|Nextgen Languages"|"rm|Repo Management & Tooling"|\ + "gv|Governance & Standards"|"db|Databases"|"ap|Applications"|"ix|Infrastructure & Cloud"|\ + "dx|Developer Ecosystem"|"pt|Protocols & Interop"|"ax|AI & Neurosymbolic"|\ + "gm|Games & Interactive"|"sc|Security") ;; + *) MISSING="$MISSING $DEED:clade(primary/primary-name unset or mismatched)" ;; + esac + # CLADE-004/005: the lifecycle phase is a closed set. + case "$(field status phase)" in + reserved|incubating|active|dormant|merged|superseded|archived|extinct) ;; + *) MISSING="$MISSING $DEED:status:phase" ;; + esac + case "$(field maturity level)" in + experimental|alpha|beta|production|lts) ;; + *) MISSING="$MISSING $DEED:maturity:level" ;; + esac + # The ecosystem clause names the repo the deed's header names. + [ "$(field ecosystem project)" = "$(field "" canonical-name)" ] \ + || MISSING="$MISSING $DEED:ecosystem:project" + want meta axis-1 "must > intend > like" + want meta axis-2 "corrective > adaptive > perfective" + want meta axis-3 "systems > compliance > effects" + want meta scoping-first true + want meta/scoping idris-unsound-scan "believe_me/assert_total" + want meta/axis-3 audit-focus "systems in place, documentation explains actual state, safety/security accounted for, observed effects reviewed" + want meta/axis-3 compliance-focus "seams/compromises/exception register, bounded exceptions, anti-drift checks" + want meta/axis-3 effects-evidence "benchmark execution/results and maintainer status dialogue/review" + for c in anchor policies/maintenance-axes policies/maintenance-checklist policies/software-development-approach; do + bash scripts/deed-field.sh --has "$DEED" "$c" || MISSING="$MISSING $DEED:($c)" + done + want policies/maintenance-axes/axis-3-audit compliance-tooling "panic-attack" + want policies/maintenance-axes/axis-3-audit effects-tooling "ecological checking with sustainabot guidance" + want policies/maintenance-checklist/metadata source-human "docs/governance/MAINTENANCE-CHECKLIST.adoc" + want policies/software-development-approach/metadata source-human "docs/governance/SOFTWARE-DEVELOPMENT-APPROACH.adoc" + else + MISSING="$MISSING repo-deed:(status …)-clause" + fi + if [ -n "$MISSING" ]; then + echo "MISSING:$MISSING" + exit 1 + fi + echo "RSR compliance: PASS" + +# Validate the repo's lifecycle state: the deed's (status …) and +# (maturity …) clauses. +validate-state: + #!/usr/bin/env bash + cd "{{justfile_directory()}}" + DEED=$(bash scripts/deed-field.sh --find . || true) + if [ -n "$DEED" ] && bash scripts/deed-field.sh --has "$DEED" status; then + phase=$(bash scripts/deed-field.sh "$DEED" status phase || true) + level=$(bash scripts/deed-field.sh "$DEED" maturity level || true) + if [ -n "$phase" ] && [ -n "$level" ]; then + echo "$DEED: valid (phase $phase, maturity $level)" + else + echo "$DEED: INVALID (needs (status :phase …) and (maturity :level …))" + exit 1 + fi + else + echo "No repo state found: the repo deed has no (status …) clause" + exit 1 + fi + +validate-ai-install: + #!/usr/bin/env bash + cd "{{justfile_directory()}}" + echo "=== AI Installation Guide Check ===" + GUIDE="docs/AI_INSTALLATION_GUIDE.adoc" + README="README.adoc" + ERRORS=0 + + # Check guide exists + if [ ! -f "$GUIDE" ]; then + echo "MISSING: $GUIDE (create from template: docs/AI_INSTALLATION_GUIDE.adoc)" + ERRORS=$((ERRORS + 1)) + else + # Check for unfilled TODO markers + TODOS=$(grep -c '\[TODO-AI-INSTALL' "$GUIDE" 2>/dev/null || true) + if [ "$TODOS" -gt 0 ]; then + echo "INCOMPLETE: $GUIDE has $TODOS unfilled [TODO-AI-INSTALL] markers:" + grep -n '\[TODO-AI-INSTALL' "$GUIDE" | head -10 + ERRORS=$((ERRORS + 1)) + else + echo "$GUIDE: complete (no TODO markers)" + fi + + # Check AI implementation section exists + if ! grep -q 'ai-implementation' "$GUIDE" 2>/dev/null; then + echo "MISSING: [[ai-implementation]] anchor in $GUIDE" + ERRORS=$((ERRORS + 1)) + fi + + # Check privacy notice exists + if ! grep -qi 'privacy' "$GUIDE" 2>/dev/null; then + echo "MISSING: Privacy notice in $GUIDE" + ERRORS=$((ERRORS + 1)) + fi + + # Check install commands exist (not just placeholders) + if ! grep -q 'git clone' "$GUIDE" 2>/dev/null; then + echo "WARNING: No git clone command found in $GUIDE -- install commands may be incomplete" + fi + fi + + # Check README has AI install section + if [ -f "$README" ]; then + if ! grep -qi 'AI-Assisted Installation' "$README" 2>/dev/null; then + echo "MISSING: AI-Assisted Installation section in $README" + echo " Copy from docs/AI-INSTALL-README-SECTION.adoc" + ERRORS=$((ERRORS + 1)) + fi + + # Check README for unfilled TODO markers + README_TODOS=$(grep -c '\[TODO-AI-INSTALL' "$README" 2>/dev/null || true) + if [ "$README_TODOS" -gt 0 ]; then + echo "INCOMPLETE: $README has $README_TODOS unfilled [TODO-AI-INSTALL] markers" + ERRORS=$((ERRORS + 1)) + fi + fi + + # The rest of the provisioning set's AI and manual-setup documents. Their + # locations come from the provisioning engine, so this check and `just doctor` + # agree on where the warm-ups live (root, docs/onboarding/ or docs/). + if [ -f build/just/provision-lib.sh ]; then + for d in $(bash build/just/provision-lib.sh set-files | grep -E '(^|/)(SETUP|llm-warmup-[a-z]+)\.adoc$'); do + if [ ! -f "$d" ]; then + echo "MISSING: $d" + ERRORS=$((ERRORS + 1)) + fi + done + if ! grep -q '^\[\[ai-install\]\]' "$README" 2>/dev/null; then + echo "MISSING: [[ai-install]] anchor in $README (see build/just/provision.just ai-setup)" + ERRORS=$((ERRORS + 1)) + fi + fi + + if [ "$ERRORS" -gt 0 ]; then + echo "" + echo "AI install guide: FAIL ($ERRORS issues)" + exit 1 + fi + echo "AI install guide: PASS" + +# Full validation suite +validate: validate-rsr validate-state validate-ai-install + @echo "All validations passed!" diff --git a/jaffascript_chora.deed b/jaffascript_chora.deed new file mode 100644 index 0000000..93c9c5c --- /dev/null +++ b/jaffascript_chora.deed @@ -0,0 +1,339 @@ +;; SPDX-License-Identifier: MPL-2.0 +; +; The repo deed of jaffascript (one deed per repo: standards#837, owner ruling +; 2026-09-19). It is read by scripts/deed-field.sh and checked by +; `just validate-rsr` / `just validate-state` (build/just/validate.just). +; +; What it carries, and from where: +; - identity, clade, forges, lineage and status: .machine_readable/CLADE.a2ml, +; field for field (standards 1-formats/deed/mappings/clade-to-repo-deed.adoc). +; - maturity and ecosystem: .machine_readable/6a2/STATE.a2ml and ECOSYSTEM.a2ml +; (meta-ecosystem-to-repo-deed.adoc). +; - meta: .machine_readable/6a2/META.a2ml plus the maintenance model that +; policies/MAINTENANCE-AXES.a2ml states. +; - anchor: .machine_readable/anchors/ANCHOR.a2ml. +; - policies: the cross-repo maintenance policies, in the deed form +; rsr-template-repo_chora.deed gives them (jaffascript's policy .a2ml files +; are copies of the template's). +; +; What it does not carry yet: the canon pin, the ply/manifest tree, agentic, +; neurosym, playbook, ensaid, bot-directives, integrations and rsr-profile. +; Those records stay where they are until the A2ML conversion front end exists +; (D313); this deed is not a bulk hand conversion. The .a2ml files are still in +; the tree, so `just validate-rsr` reports no-a2ml as MISSING until then. +(repo-deed + :schema-version "1.0.0" + :canonical-name "jaffascript" + :beholding-chora #u5"estate/chora" + ; uuid5(URL, "github.com/hyperpolymath/jaffascript") = + ; f9ac0bec-692d-536d-b2eb-b3a03337e75d, the uuid CLADE.a2ml records. + :repo-uuid #u5"github.com/hyperpolymath/jaffascript" + ; >>> repo-identity + (identity + :primary-forge github + :owner "hyperpolymath" + :prefixed-name "rm-jaffascript") + ; Carried as CLADE.a2ml records it. The clade should name the project's core + ; value proposition; a language face reads as nl (Nextgen Languages), not rm. + ; Changing it also changes :prefixed-name and the registration, so it is the + ; owner's call, not this conversion's. + (clade + :primary rm + :primary-name "Repo Management & Tooling" + :secondary (gv) + :assigned "2026-03-16" + :rationale "") + (forges + :github "hyperpolymath/jaffascript" + :gitlab "hyperpolymath/jaffascript" + :bitbucket "hyperpolymath/jaffascript") + ; CLADE.a2ml gave parent = "RSR template — scaffold for new repos". :parent + ; names a monorepo parent only, so the template goes in :instantiated-from. + (lineage + :type standalone + :parent "" + :born "2026-03-16" + :previous-names () + :instantiated-from "rsr-template-repo") + (status + :phase active + :since "2026-03-16" + :present #t + :aliases () + :merged-into "" + :superseded-by "" + :successors () + :ended "" + (history + (entry :phase active :since "2026-03-16" :note "backfilled default — correct if the true phase differs"))) + (maturity + :level alpha) + (ecosystem + :project "jaffascript" + :ecosystem "hyperpolymath" + :position-type "language-face" + :purpose "jaffascript-style syntax face for AffineScript providing familiar syntax for jaffascript developers" + :not ("a compiler" + "a type checker or borrow checker" + "a code generator") + (related :name "affinescript" :relationship build-tooling :notes "The compiler, type checker and codegen. bin/jaffa runs affinescript with the jaffa face selected.") + (related :name "rsr-template-repo" :relationship minted-from :notes "The template this repo was created from.")) + ; <<< repo-identity + (meta + :version "0.1.0" + :last-updated "2026-10-09" + :type face-repo + :category "syntax-surface" + :license MPL-2.0 + :author "Jonathan D.A. Jewell (hyperpolymath)" + :build-tool just + :ci-platform github-actions + :scoping-first #t + :execution-order "axis-1 > axis-2 > axis-3" + :axis-1 "must > intend > like" + :axis-2 "corrective > adaptive > perfective" + :axis-3 "systems > compliance > effects" + (scoping + :sources "README, roadmap, status docs, maintenance checklist, CI/security docs" + :marker-scan "TODO/FIXME/XXX/HACK/STUB/PARTIAL" + :idris-unsound-scan "believe_me/assert_total") + :corrective-first #t + :adaptive-second #t + :adaptive-focus "scope-change reconciliation, stale-reference removal, obsolete-work culling" + :perfective-third #t + :perfective-source "axis-1 honest state after corrective/adaptive updates" + (axis-3 + :audit-focus "systems in place, documentation explains actual state, safety/security accounted for, observed effects reviewed" + :compliance-focus "seams/compromises/exception register, bounded exceptions, anti-drift checks" + :effects-evidence "benchmark execution/results and maintainer status dialogue/review")) + ; ANCHOR.a2ml still holds the template's unfilled {{PROJECT_*}} placeholders + ; in [identity]; the values below come from README.adoc. Its + ; [implementation-policy], [golden-path], [satellite-policy] and + ; [semantic-authority-files] are the template's defaults (they name Rust and + ; Idris2, `just test`, and SPECIFICATION.md, none of which apply here), so + ; they are not carried. Stating them for this repo is the owner's call. + (anchor + :schema "hyperpolymath.anchor/1" + :repo "hyperpolymath/jaffascript" + :authority "upstream-canonical" + :purpose ( + "Define canonical semantics and policy boundaries for this repository." + "Declare what downstream/satellite repos can extend but not redefine." + "Provide a stable golden path and invariant contract for release readiness." + ) + (metadata + :version "1.0.0" + :last-updated "2026-10-09") + (identity + :project "jaffascript" + :kind "language" + :one-sentence "JavaScript / TypeScript-syntax AffineScript: AffineScript with its jaffa face pre-selected." + :domain "AffineScript faces")) + (policies + ; Canonical maintenance governance model + (maintenance-axes + (metadata + :version "1.0.0" + :last-updated "2026-10-09" + :scope "repo") + (discovery + :human-entrypoints ( + "README.adoc" + "docs/governance/MAINTENANCE-CHECKLIST.adoc" + "docs/governance/SOFTWARE-DEVELOPMENT-APPROACH.adoc" + ) + :machine-entrypoints ( + "*_chora.deed (policies (maintenance-axes))" + "*_chora.deed (policies (maintenance-checklist))" + "*_chora.deed (policies (software-development-approach))" + "*_chora.deed" + ".machine_readable/ai/README.adoc" + "*_chora.deed (bot-directives)" + ) + :bots ("hypatia" "gitbot-fleet" "repo visitors")) + (axes + :axis-1 "must > intend > like" + :axis-2 "corrective > adaptive > perfective" + :axis-3 "systems > compliance > effects" + :execution-order "axis-1 > axis-2 > axis-3") + (axis-1-scoping + :required #t + :sources "README, roadmap, status docs, maintenance checklist, CI/security docs" + :markers "TODO/FIXME/XXX/HACK/STUB/PARTIAL" + :idris-unsound-markers "believe_me/assert_total" + :output "scoped work assembly in must/intend/like buckets") + (axis-2-maintenance + :corrective-first #t + :adaptive-second #t + :adaptive-focus "scope changes, stale references, obsolete work culling" + :perfective-third #t + :perfective-source "honest state from axis-1 after corrective/adaptive updates") + (axis-3-audit + :systems-check #t + :compliance-check #t + :effects-check #t + :compliance-focus "seams/compromises/exception register and anti-drift" + :compliance-tooling "panic-attack" + :effects-tooling "ecological checking with sustainabot guidance" + :effects-evidence "benchmark evidence and maintainer dialogue/status review")) + ; Cross-repo maintenance baseline (machine-readable canonical) + (maintenance-checklist + (metadata + :version "1.1.0" + :last-updated "2026-02-24" + :scope "cross-repo" + :source-human "docs/governance/MAINTENANCE-CHECKLIST.adoc" + :companion-human "docs/governance/SOFTWARE-DEVELOPMENT-APPROACH.adoc" + :companion-machine "*_chora.deed (policies (software-development-approach))") + (policy + :single-source #t + :notes "Use this clause as canonical machine policy and keep the AsciiDoc synchronized.") + (maintenance-axes + :scoping-first #t + :execution-order ("scoping" "axis-1" "axis-2" "axis-3") + :axis-1 "must > intend > like" + :axis-2 "corrective > adaptive > perfective" + :axis-3 "systems > compliance > effects") + (scoping + :inputs_required ( + "README" + "roadmap" + "status-docs" + "maintenance-checklist" + "ci-and-security-docs" + ) + :marker_scan_required ("TODO" "FIXME" "XXX" "HACK" "STUB" "PARTIAL") + :idris_unsound_scan_required ("believe_me" "assert_total") + :scope_assembly_buckets ("must" "intend" "like")) + (axis-2-maintenance-rules + :corrective-first #t + :adaptive-second #t + :adaptive_examples ( + "scope-change reconciliation" + "stale-reference removal" + "obsolete-work culling" + ) + :perfective-third #t + :perfective_source "axis-1 honest state after corrective/adaptive updates") + (axis-3-audit-rules + :systems-check #t + :documentation-honesty-check #t + :safety-security-accounted-check #t + :effects-review-check #t + :benchmark-evidence-required #t + :maintainer-dialogue-review-required #t + :compliance-seams-check #t + :exception-register-required #t + :exception-bounded-scope-required #t + :policy-drift-contamination-check #t + :example-drift-risk "single TypeScript exception causing broad ->TypeScript migration" + :compliance-tooling "panic-attack" + :effects-tooling "ecological checking with sustainabot guidance") + (generic-cleanup-finish-off + :root-cleanup-required #t + :stale-work-cull-required #t + :docs-parity-required #t + :machine-human-sync-required #t + :compliance-finish-off-required #t + :effects-finish-off-required #t + :release-prep-summary-required #t + :next-actions-required ("corrective" "adaptive" "perfective")) + (must + :root_control_files ( + ".gitignore" + ".gitattributes" + ".editorconfig" + ".tool-versions" + "Containerfile" + "Justfile" + ) + :root_hosting_files ("CNAME" ".nojekyll") + :ownership_files ("MAINTAINER" ".github/CODEOWNERS") + :machine_readable_required ( + "*_chora.deed (anchor)" + ".machine_readable/contractiles/" + ".machine_readable/ai/" + ".machine_readable/bot_directives/" + ) + :contractiles_required ( + ".machine_readable/contractiles/must/" + ".machine_readable/contractiles/trust/" + ".machine_readable/contractiles/intend/" + ) + :security_required ("www/.well-known/security.txt" "ci-security-scan") + :quality_gate_required ( + "format" + "lint" + "unit-tests" + "integration-tests" + "p2p-tests" + "e2e-tests" + "bench-smoke" + "docs-check" + "security-scan" + ) + :abi_ffi_policy ("ABI Idris2 in src/interface/abi/*.idr" "FFI Zig in ffi/**/*.zig")) + (should + :docs_primary_format "adoc" + :docs_structure ( + "docs/theory" + "docs/practice" + "docs/whitepapers/academic" + "docs/whitepapers/industry" + "docs/proofs" + "docs/reports" + ) + :root_minimization #t + :well_known_metadata #t + :roadmap_honesty_with_dates #t + :ci_doc_format_policy #t) + (could + :generate_human_from_machine #t + :mode_aware_bots ("corrective" "adaptive" "perfective" "audit") + :topology_dashboard #t + :exception_registry #t)) + ; General software development approach (machine-readable) + (software-development-approach + (metadata + :version "1.0.0" + :last-updated "2026-02-24" + :scope "cross-repo" + :source-human "docs/governance/SOFTWARE-DEVELOPMENT-APPROACH.adoc") + (execution + :order ("axis-1" "axis-2" "axis-3")) + (axis-1 + :name "scope" + :priority "must > intend > like" + :inputs ("README" "roadmap" "status-docs" "ci-and-security-docs") + :marker-scan ("TODO" "FIXME" "XXX" "HACK" "STUB" "PARTIAL") + :idris-unsound-scan ("believe_me" "assert_total") + :output "scoped-work-assembly") + (axis-2 + :name "maintenance" + :priority "corrective > adaptive > perfective" + :corrective "defect/regression/safety/security fixes" + :adaptive "scope reconciliation, stale-reference removal, obsolete-work culling" + :perfective "quality improvements derived from axis-1 honest state") + (axis-3 + :name "audit" + :priority "systems > compliance > effects" + :systems "required systems present and operating" + :compliance "exceptions explicit, bounded, and drift-resistant" + :effects "benchmark/operational impact evidence captured and reviewed" + :compliance-tooling "panic-attack" + :effects-tooling "ecological checking with sustainabot guidance") + (cleanup-finish-off + :root-cleanup #t + :stale-work-cull #t + :docs-sync-human-machine #t + :compliance-audit #t + :effects-audit #t + :release-summary ("must" "should" "could") + :next-actions ("corrective" "adaptive" "perfective")) + (collaboration + :maintainer-dialogue-required #t + :dialogue-topics ("what changed" "why" "remaining risks"))) + ; Component Readiness Grades (CRG v1.0) — the machine-readable grade + ; standard; the human companion is docs/governance/CRG-CRITERIA.adoc. + ) +) diff --git a/scripts/check-no-a2ml.sh b/scripts/check-no-a2ml.sh new file mode 100755 index 0000000..fd9a514 --- /dev/null +++ b/scripts/check-no-a2ml.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# check-no-a2ml.sh — enforce the estate rule that no .a2ml file exists. The +# format is retired: a repo's facts are clauses of its deed (_chora.deed, +# deed.abnf) and its contracts are .k9 / .k9.ncl files. +# +# Usage: check-no-a2ml.sh [REPO_ROOT] +# Inspects tracked files when REPO_ROOT is a git work tree, and every file +# under it (minus .git/) otherwise, so an untracked mint is covered too. +# Exit: 0 none found; 1 one or more .a2ml files (listed); 2 bad path. +set -euo pipefail + +REPO_ROOT="${1:-.}" +[ -d "$REPO_ROOT" ] || { echo "ERROR: repository path does not exist: $REPO_ROOT" >&2; exit 2; } + +if git -C "$REPO_ROOT" rev-parse --is-inside-work-tree >/dev/null 2>&1; then + FOUND=$(git -C "$REPO_ROOT" ls-files -- '*.a2ml' '*.A2ML') +else + FOUND=$(find "$REPO_ROOT" -path '*/.git' -prune -o -type f -iname '*.a2ml' -printf '%P\n') +fi + +if [ -z "$FOUND" ]; then + echo "PASS: no .a2ml files in the inspected repository" + exit 0 +fi +echo "FAIL: .a2ml is a retired format; move these facts into the repo deed or a .k9 contract:" +printf ' %s\n' $FOUND +exit 1 diff --git a/scripts/deed-field.sh b/scripts/deed-field.sh new file mode 100755 index 0000000..57d27c1 --- /dev/null +++ b/scripts/deed-field.sh @@ -0,0 +1,188 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# deed-field.sh — read one field out of a deed (_chora.deed, or any +# *_praxis.deed: the root is the first form with an ABNF doc-head). +# +# The repo deed holds what the descriptiles CLADE / META / ECOSYSTEM / STATE / +# AGENTIC .a2ml files used to hold (rsr-template-repo#209). This is the one +# shell reader for it, so that every gate, extractor and recipe asks the same +# question the same way. It is a READER: it never writes the deed. +# +# Usage: +# deed-field.sh DEED PATH KEY first value of :KEY in the clause at PATH +# deed-field.sh --list DEED PATH KEY the items of the list :KEY ( … ), one per line +# deed-field.sh --clause DEED PATH the clause, one token per line (for hashing) +# deed-field.sh --has DEED PATH exit 0 iff the clause exists +# deed-field.sh --find [DIR] print the one *_chora.deed in DIR (default .) +# deed-field.sh --uuid DEED the repo uuid, derived from :repo-uuid +# +# PATH names clauses below (repo-deed …), slash-separated: `status`, +# `agentic/integrity`, `meta/maintenance-axes`. An empty PATH is (repo-deed …) +# itself, so `deed-field.sh DEED "" canonical-name` reads the header. +# +# KEY is matched only at the top level of that clause, never inside a nested +# clause: `status` :phase is the clause's own phase, not a (history (entry …)) +# phase. Comments (`;` to end of line, outside strings) are ignored, layout is +# irrelevant, string escapes \" \\ \n \t are decoded, and the booleans #t / #f +# print as true / false, because every caller is a shell test. A tagged +# literal prints its string: `:repo-uuid #u5"github.com/o/r"` gives +# github.com/o/r, the uuid5 name (uuidgen --sha1 --namespace @url --name …). +# +# --uuid derives the uuid5 (RFC 9562, URL namespace) of the header :repo-uuid +# name. It uses uuidgen when that supports --sha1, else bun, and exits 2 when +# neither is available or the result is not uuid-shaped: it never guesses. +# +# Exit: 0 found; 1 clause or key absent (nothing printed); 2 usage error or no +# readable deed. --find exits 1 unless exactly one deed is present. +set -euo pipefail + +mode=value +case "${1:-}" in + --list|--clause|--has|--uuid) mode="${1#--}"; shift ;; + --find) + shopt -s nullglob + deeds=("${2:-.}"/*_chora.deed) + [ "${#deeds[@]}" -eq 1 ] || exit 1 + printf '%s\n' "${deeds[0]}" + exit 0 ;; +esac + +deed="${1:-}"; path="${2-}"; key="${3:-}" +[ "$mode" != uuid ] || { path=""; key=repo-uuid; } +if [ -z "$deed" ] || [ ! -r "$deed" ]; then + echo "deed-field.sh: no readable deed: '${deed}'" >&2; exit 2 +fi +if { [ "$mode" = value ] || [ "$mode" = list ]; } && [ -z "$key" ]; then + echo "deed-field.sh: KEY is required" >&2; exit 2 +fi + +# read_deed MODE -> run the clause reader over $deed for $path / $key +read_deed() { +awk -v mode="$1" -v path="$path" -v key="$key" ' +BEGIN { RS = "\001" } +{ + # Tokenise: "(" ")" , S , A. Comments are dropped here. + s = $0; n = length(s); i = 1; nt = 0 + while (i <= n) { + c = substr(s, i, 1) + if (c == ";") { while (i <= n && substr(s, i, 1) != "\n") i++; continue } + if (c == "(" || c == ")") { tok[++nt] = c; i++; continue } + if (c == "\"") { + v = ""; i++ + while (i <= n) { + c = substr(s, i, 1) + if (c == "\\") { + d = substr(s, i + 1, 1) + if (d == "n") v = v "\n"; else if (d == "t") v = v "\t"; else v = v d + i += 2; continue + } + if (c == "\"") break + v = v c; i++ + } + i++; tok[++nt] = "S" v; continue + } + if (c == " " || c == "\t" || c == "\r" || c == "\n") { i++; continue } + v = "" + while (i <= n) { + c = substr(s, i, 1) + if (c == " " || c == "\t" || c == "\r" || c == "\n" || c == "(" || c == ")" || c == "\"" || c == ";") break + v = v c; i++ + } + tok[++nt] = "A" v + } +} +# Index of the ")" token that closes the clause opening at token o, or 0. +function close_of(o, d, t) { + d = 0 + for (t = o; t <= nt; t++) { + if (tok[t] == "(") d++ + else if (tok[t] == ")") { d--; if (d == 0) return t } + } + return 0 +} +# First direct child clause of the clause opening at o whose head is name. +function child(o, name, e, t, d) { + e = close_of(o); d = 0 + for (t = o + 1; t < e; t++) { + if (tok[t] == "(") { if (d == 0 && tok[t + 1] == "A" name) return t; d++ } + else if (tok[t] == ")") d-- + } + return 0 +} +# A value token rendered for output: the type tag dropped, #t/#f as true/false. +function show(x) { + x = substr(x, 2) + if (x == "#t") return "true" + if (x == "#f") return "false" + return x +} +END { + o = 0 + for (t = 1; t <= nt; t++) + if (tok[t] == "(" && tok[t + 1] ~ /^A(repo-deed|praxis-deed|estate-deed|estate-atlas-deed)$/) { o = t; break } + if (!o) exit 1 + if (path != "") { + np = split(path, part, "/") + for (p = 1; p <= np; p++) { o = child(o, part[p]); if (!o) exit 1 } + } + e = close_of(o) + if (!e) exit 2 + if (mode == "has") exit 0 + if (mode == "clause") { for (t = o; t <= e; t++) print tok[t]; exit 0 } + d = 0 + for (t = o + 1; t < e; t++) { + if (tok[t] == "(") { d++; continue } + if (tok[t] == ")") { d--; continue } + if (d != 0 || tok[t] != "A:" key) continue + nx = tok[t + 1] + if (mode == "value") { + if (nx == "(" || nx == ")" || nx == "") exit 1 + # A tagged literal such as #u5"github.com/o/r" prints its string. + if (nx ~ /^A#[a-z0-9]+$/ && substr(tok[t + 2], 1, 1) == "S") nx = tok[t + 2] + print show(nx); exit 0 + } + if (nx != "(") exit 1 + le = close_of(t + 1); ld = 0 + for (u = t + 2; u < le; u++) { + if (tok[u] == "(") ld++ + else if (tok[u] == ")") ld-- + else if (ld == 0) print show(tok[u]) + } + exit 0 + } + exit 1 +} +' "$deed" +} + +# uuid5_url NAME -> the uuid5 of NAME in the RFC 9562 URL namespace +uuid5_url() { + if uuidgen --sha1 --namespace @url --name x >/dev/null 2>&1; then + uuidgen --sha1 --namespace @url --name "$1" + elif command -v bun >/dev/null 2>&1; then + bun -e ' + const h = new Bun.CryptoHasher("sha1"); + h.update(Buffer.from("6ba7b8119dad11d180b400c04fd430c8", "hex")); + h.update(process.argv[1]); + const b = h.digest().subarray(0, 16); + b[6] = (b[6] & 0x0f) | 0x50; + b[8] = (b[8] & 0x3f) | 0x80; + const x = b.toString("hex"); + console.log([x.slice(0, 8), x.slice(8, 12), x.slice(12, 16), x.slice(16, 20), x.slice(20)].join("-")); + ' "$1" + else + echo "deed-field.sh: --uuid needs uuidgen with --sha1, or bun" >&2; return 2 + fi +} + +if [ "$mode" = uuid ]; then + name="$(read_deed value)" || exit $? + id="$(uuid5_url "$name")" || exit 2 + [[ "$id" =~ ^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$ ]] \ + || { echo "deed-field.sh: derived uuid is not uuid5-shaped: '$id'" >&2; exit 2; } + printf '%s\n' "$id" + exit 0 +fi +read_deed "$mode" From 5eaf0dbf9e4a3fda04a61d67431e449c655957bc Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Fri, 9 Oct 2026 03:04:05 +0100 Subject: [PATCH 2/2] Update jaffascript_chora.deed Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> --- jaffascript_chora.deed | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jaffascript_chora.deed b/jaffascript_chora.deed index 93c9c5c..bbcd1bc 100644 --- a/jaffascript_chora.deed +++ b/jaffascript_chora.deed @@ -25,8 +25,8 @@ :schema-version "1.0.0" :canonical-name "jaffascript" :beholding-chora #u5"estate/chora" - ; uuid5(URL, "github.com/hyperpolymath/jaffascript") = - ; f9ac0bec-692d-536d-b2eb-b3a03337e75d, the uuid CLADE.a2ml records. + ; uuid5(URL, "github.com/hyperpolymath/jaffascript") is the uuid that + ; CLADE.a2ml records; `scripts/deed-field.sh --uuid` derives it. :repo-uuid #u5"github.com/hyperpolymath/jaffascript" ; >>> repo-identity (identity