From f7d740dce441e8420abc289e8ad4ba05a71c55f6 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Mon, 14 Sep 2026 20:55:09 +0100 Subject: [PATCH 1/3] docs: propose "elegance by default" as the fourth operating principle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Owner instruction, 2026-09-14: treat the most elegant and correct long-term solution as the default choice, and label which option that is every time a choice is put to the owner; where a recommendation departs from that standard, name both arms and justify the departure. The owner asked for this as "a fundamental starting point as part of the software design methodology", written into principles, testing and methodology material rather than left as a conversational habit. Six files, each in its own register: * RSR-PHILOSOPHY.adoc — new `== Elegance by default` section stating the principle and its three obligations, in the same form as `== Solutions at source`. Two pre-existing enumerations that this makes stale are repaired in the same commit: the sibling paragraph said "two siblings" and named three dimensions of work (order / manner / locus), now three siblings and four dimensions (adding the standard of work); and `== The full Doctrine` said "the three principles above", now four. Leaving either would be a silent inconsistency in the document that forbids silent inconsistency. * testing-and-benchmarking/TESTING-TAXONOMY.adoc — the testing corollary, as a subsection of `== Scope`: every category can be satisfied more than one way and the cheapest way is rarely the most correct, so the elegant arm is the default and a departure is recorded in the Debtfile or the N/A justification. Placed here rather than in ZIGZAG-TESTING.adoc, which is a technique document (aspect-oriented analysis, meandering routes) and not a home for testing methodology. * AGENTS.adoc — the operational binding for agents changing this repo, beside the existing authority-class paragraph. * EXPLAINME.adoc — one row in `== Architecture decisions (the durable ones)`. * ai-instruction/opus.adoc, ai-instruction/sonnet.adoc — one numbered rule each in `=== Hard rules to include verbatim`. Per that directory's README this is the only channel that transfers a rule to a delegated subagent ("memory and global CLAUDE.md do not transfer"), so it is the load-bearing placement. The two rules are deliberately different: Opus gets the full obligation including choices put to the owner, Sonnet gets it framed as the companion to its own "Ask, don't invent" rule, because Sonnet's recorded failure mode is fabricating a plausible design decision without its rejected alternative. Deliberately NOT changed: * ai-instruction/haiku.adoc — Haiku is constrained read-only, "raw rows, no synthesis", and makes no design calls and puts no choices to the owner. A rule to label the elegant option would contradict its own no-synthesis rule. Omitted for consistency, not economy. * .machine_readable/ — ai-instruction/README.adoc explicitly separates editorial guidance for prompters from A2ML consumed mechanically by the bot fleet, and calls mixing them wrong. This is the former. Validated: asciidoctor renders all six clean; `git diff --check` clean. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_014QN8x5x4kNKY8EYCFsCmWB --- AGENTS.adoc | 7 +++ EXPLAINME.adoc | 2 + RSR-PHILOSOPHY.adoc | 43 ++++++++++++++++--- ai-instruction/opus.adoc | 10 +++++ ai-instruction/sonnet.adoc | 8 ++++ .../TESTING-TAXONOMY.adoc | 20 +++++++++ 6 files changed, 85 insertions(+), 5 deletions(-) diff --git a/AGENTS.adoc b/AGENTS.adoc index 46a25a109..1a1c0a928 100644 --- a/AGENTS.adoc +++ b/AGENTS.adoc @@ -12,6 +12,13 @@ applicable change procedure is completed. Evidence records what currently holds; it does not gain authority merely by being generated or machine-readable. +Where a change admits more than one shape, treat the most elegant and correct +long-term option as the default arm and name it as such. A recommendation that +departs from it must name both arms and state why the departure is made on this +occasion. This binds design calls taken without asking, not only choices put to +the owner: report the departure rather than absorb it. See +`+RSR-PHILOSOPHY.adoc+`, _Elegance by default_. + Canonical sources include `+constitution/+`, domain standard sources, profile sources, and the registry source consumed by `+scripts/build-registry.sh+`. `+.machine_readable/REGISTRY.a2ml+` and diff --git a/EXPLAINME.adoc b/EXPLAINME.adoc index 2ba626eaf..da2bd25d3 100644 --- a/EXPLAINME.adoc +++ b/EXPLAINME.adoc @@ -52,6 +52,8 @@ link:REGISTRY.adoc[REGISTRY.adoc]). | Guix-first package management | Reproducible builds via Guix. +| Elegance is the default arm +| Every choice put to the owner names which option is the most elegant and correct in the long run; a recommendation that departs from it names both arms and justifies the departure. A methodology, not a question-formatting rule — see link:RSR-PHILOSOPHY.adoc[RSR-PHILOSOPHY.adoc]. |=== == How to use this repo diff --git a/RSR-PHILOSOPHY.adoc b/RSR-PHILOSOPHY.adoc index 342d87cb5..fa258f098 100644 --- a/RSR-PHILOSOPHY.adoc +++ b/RSR-PHILOSOPHY.adoc @@ -41,10 +41,11 @@ own, a change gated on owner ratification — remediate the downstream *and* rec the source fix as the real work still owed. Silently patching the symptom as if it were the cure is itself a soundness hole (see _fail loudly_). -This principle stands beside its two siblings: *holes before goals* and *always -fail loudly*. Together they govern the order of work (holes first), the manner of -work (loudly, never silently green), and the locus of work (at the source, never -the symptom). +This principle stands beside its three siblings: *holes before goals*, *always fail +loudly*, and *elegance by default*. Together they govern the order of work (holes +first), the manner of work (loudly, never silently green), the locus of work (at the +source, never the symptom), and the standard of work (the elegant, long-term-correct +arm, named even where it is not the arm taken). == Holes before goals @@ -59,11 +60,43 @@ No silent green. A check that cannot fail is not a check; a fallback that hides broken precondition is a forged result. Seams (ABI / FFI) are sealed and proven, not assumed. Prefer a build that breaks to a build that lies. +== Elegance by default + +*Treat the most elegant and correct long-term solution as the default choice — and say +which option that is, every time a choice is put to the owner.* + +A set of options presented as merely _different_ is not neutral. Whichever option is +listed first, or described most fluently, becomes the recommendation whether or not +anyone intended it — so an unlabelled list quietly substitutes the convenience of +whoever wrote it for the standard the estate is held to. That is the same category error +as a symptom patched in place of a source: a choice backed by authority rather than +justified by the construction that produced it. + +Three obligations follow, and none is optional: + +. *Label it.* Exactly one option is marked as the elegant and correct long-term arm. + Elegance is judged on long-run grounds alone — correctness, no deferred breakage, no + special cases, fixing the generator rather than the instance — and never on effort, + speed, or convenience. If two options genuinely tie, say so explicitly; silence is not + a tie. +. *Justify any departure.* A recommendation that is not the elegant arm must name both + arms and state, in the offer itself, why the departure is made on this occasion — an + irreversible step already taken, a live outage, a precondition still gated. An + unexplained departure is a defect in the question, not a matter of style. The two + labels are never merged to avoid having to write the explanation. +. *It binds unasked decisions too.* This is a methodology, not a formatting rule for + questions. Where the non-elegant arm is taken without asking, that is reported, not + absorbed. + +The default is a *starting point, not a prediction*. The owner may take the other arm +with full information, and often will; what may not happen is an expedient choice made +in ignorance that it was the expedient one. + == The full Doctrine The complete, always-current operating Doctrine is maintained as estate-common content in the arrival-pack and projected into every repository's `CLAUDE.md`. In -addition to the three principles above it holds: ground-truth by running the tool, +addition to the four principles above it holds: ground-truth by running the tool, not trusting status docs; distrust the neural for exactness (licences, invariants, equivalence belong to PLASMA, not an LLM); squabble, don't bypass (reach green by satisfying the gate, never by admin-override); no automated licence edits; no diff --git a/ai-instruction/opus.adoc b/ai-instruction/opus.adoc index f1f7cc6d9..ee950ed46 100644 --- a/ai-instruction/opus.adoc +++ b/ai-instruction/opus.adoc @@ -187,6 +187,16 @@ releases). `+standards/session-management-standards+`, flip TaskCreate `+activeForm+` to `+CLOSING DOWN — +` and end the final message with literal `+SAFE TO CLOSE+` on its own line. +. *Elegance is the default arm.* Every choice put to Jonathan must LABEL +which option is the most elegant and correct long-term one, judged on +long-run grounds alone — correctness, no deferred breakage, no special +cases, fixing the generator rather than the instance — and never on +effort, speed, or convenience. Where your recommendation differs, name +both arms and state in the offer itself why you depart on this occasion; +an unexplained departure is a defect in the question, not a matter of +style. This binds unasked design calls too: where you take the +non-elegant arm without asking, report it rather than absorb it. See +`+standards/RSR-PHILOSOPHY.adoc+`, _Elegance by default_. === Trust level & verification diff --git a/ai-instruction/sonnet.adoc b/ai-instruction/sonnet.adoc index 850e77b64..38e1ae70f 100644 --- a/ai-instruction/sonnet.adoc +++ b/ai-instruction/sonnet.adoc @@ -134,6 +134,14 @@ integration boundary works end-to-end before moving on. . *No stubbing by default* — wire it through; do not leave `+unimplemented!()+` / `+todo!()+` / placeholder returns unless the prompter explicitly said to stub. +. *Elegance is the default arm.* The companion to "`Ask, don’t +invent`": where you must choose, do not choose silently. Name the option +that is most elegant and correct in the long run — judged on +correctness and the absence of deferred breakage, never on which is +quickest — and where you take a different one, say which and why. A +design decision recorded without the arm it rejected is exactly the +plausible-looking fabrication the rule above warns about. See +`+standards/RSR-PHILOSOPHY.adoc+`, _Elegance by default_. === Trust level & verification diff --git a/testing-and-benchmarking/TESTING-TAXONOMY.adoc b/testing-and-benchmarking/TESTING-TAXONOMY.adoc index 077b8589a..493f7ed0b 100644 --- a/testing-and-benchmarking/TESTING-TAXONOMY.adoc +++ b/testing-and-benchmarking/TESTING-TAXONOMY.adoc @@ -69,6 +69,26 @@ fact, is worse than no test — it is read as evidence. If no honest test exists for a category yet, mark it N/A with justification, as Scope requires above. That is a truthful state; a passing-but-vacuous test is not. +=== Choosing how to satisfy a category: the elegant arm is the default + +Every category below can be satisfied in more than one way, and the cheapest way is +rarely the most correct. Where a choice exists — adapt the proven Idris2 test or write +a quick local one; fix the code under test or weaken the assertion; fix the generator +or add a special case for this repo — the *most elegant and correct long-term* option +is the default arm, and it must be named as such whenever the choice is put to the +owner. + +Judge elegance on long-run grounds only: correctness, absence of deferred breakage, no +special cases, and a fix at the generator rather than at the instance. Never on how +quickly a category can be marked satisfied. Where the other arm is taken, record both +arms and the reason for departing — in the `Debtfile` where a shortfall is being +tolerated, in the N/A justification where the category is being declined. An +unlabelled choice between a sound test and a convenient one is how a suite quietly +becomes evidence for something nobody checked. + +This is the estate doctrine _elegance by default_ applied to testing; see +link:../RSR-PHILOSOPHY.adoc[`RSR-PHILOSOPHY.adoc`]. + == Part I: Test Categories === 1. Unit Tests From 8af3f61e68058c0600f748a5e5a5f27c3063f201 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2026 20:24:07 +0000 Subject: [PATCH 2/3] feat(debtfile): require taxonomy departure records Mark elegance-by-default guidance provisional and validate taxonomy choice metadata. --- AGENTS.adoc | 7 -- EXPLAINME.adoc | 4 +- RSR-PHILOSOPHY.adoc | 39 ++++++++--- ai-instruction/opus.adoc | 2 +- ai-instruction/sonnet.adoc | 2 +- docs/DEBTFILE-SPEC.adoc | 25 ++++++- scripts/check-debtfile-structure.sh | 49 ++++++++++++- scripts/tests/debtfile-structure-test.sh | 69 +++++++++++++++++++ scripts/tests/run-debtfile-test.sh | 11 ++- .../TESTING-TAXONOMY.adoc | 12 ++-- 10 files changed, 189 insertions(+), 31 deletions(-) diff --git a/AGENTS.adoc b/AGENTS.adoc index 1a1c0a928..46a25a109 100644 --- a/AGENTS.adoc +++ b/AGENTS.adoc @@ -12,13 +12,6 @@ applicable change procedure is completed. Evidence records what currently holds; it does not gain authority merely by being generated or machine-readable. -Where a change admits more than one shape, treat the most elegant and correct -long-term option as the default arm and name it as such. A recommendation that -departs from it must name both arms and state why the departure is made on this -occasion. This binds design calls taken without asking, not only choices put to -the owner: report the departure rather than absorb it. See -`+RSR-PHILOSOPHY.adoc+`, _Elegance by default_. - Canonical sources include `+constitution/+`, domain standard sources, profile sources, and the registry source consumed by `+scripts/build-registry.sh+`. `+.machine_readable/REGISTRY.a2ml+` and diff --git a/EXPLAINME.adoc b/EXPLAINME.adoc index da2bd25d3..2ef9907f0 100644 --- a/EXPLAINME.adoc +++ b/EXPLAINME.adoc @@ -52,8 +52,8 @@ link:REGISTRY.adoc[REGISTRY.adoc]). | Guix-first package management | Reproducible builds via Guix. -| Elegance is the default arm -| Every choice put to the owner names which option is the most elegant and correct in the long run; a recommendation that departs from it names both arms and justifies the departure. A methodology, not a question-formatting rule — see link:RSR-PHILOSOPHY.adoc[RSR-PHILOSOPHY.adoc]. +| Elegance is the default arm (proposed) +| Provisional methodology pending the ratification record in link:RSR-PHILOSOPHY.adoc[RSR-PHILOSOPHY.adoc]; it is not yet an effective architecture decision. |=== == How to use this repo diff --git a/RSR-PHILOSOPHY.adoc b/RSR-PHILOSOPHY.adoc index fa258f098..020250482 100644 --- a/RSR-PHILOSOPHY.adoc +++ b/RSR-PHILOSOPHY.adoc @@ -11,6 +11,10 @@ and that the estate arrival-pack projects, in summary form, into the top of ever `CLAUDE.md`. The owner's `manifesto` states the same doctrine in its own voice; where wording must be reconciled, the manifesto prevails. +Material explicitly marked *PROVISIONAL* is a proposal within this otherwise +canonical document. It is not operating doctrine and must not be projected into +`CLAUDE.md` until its ratification record is complete. + The principles are deliberately few and blunt. They describe not only *what* good work is but the *order* and *manner* in which it is undertaken. @@ -41,11 +45,9 @@ own, a change gated on owner ratification — remediate the downstream *and* rec the source fix as the real work still owed. Silently patching the symptom as if it were the cure is itself a soundness hole (see _fail loudly_). -This principle stands beside its three siblings: *holes before goals*, *always fail -loudly*, and *elegance by default*. Together they govern the order of work (holes -first), the manner of work (loudly, never silently green), the locus of work (at the -source, never the symptom), and the standard of work (the elegant, long-term-correct -arm, named even where it is not the arm taken). +This principle stands beside its two canonical siblings: *holes before goals* and +*always fail loudly*. A proposed fourth principle, *elegance by default*, is recorded +below pending ratification. == Holes before goals @@ -62,6 +64,20 @@ not assumed. Prefer a build that breaks to a build that lies. == Elegance by default +[IMPORTANT] +==== +*Status: PROVISIONAL — not canonical policy.* + +* Owner decision: pending; the 2026-09-14 instruction authorised this proposal, + but no completed ratification decision is recorded. +* Dissent: not yet recorded. +* Effective version/hash: none. + +Before this principle becomes canonical or is propagated into `CLAUDE.md`, the +ratification record must replace all three pending values with the owner decision, +recorded dissent (including an explicit `none`), and an effective version or hash. +==== + *Treat the most elegant and correct long-term solution as the default choice — and say which option that is, every time a choice is put to the owner.* @@ -74,11 +90,12 @@ justified by the construction that produced it. Three obligations follow, and none is optional: -. *Label it.* Exactly one option is marked as the elegant and correct long-term arm. - Elegance is judged on long-run grounds alone — correctness, no deferred breakage, no - special cases, fixing the generator rather than the instance — and never on effort, - speed, or convenience. If two options genuinely tie, say so explicitly; silence is not - a tie. +. *Label it.* Mark exactly one option as the elegant and correct long-term arm unless + options genuinely tie. In a genuine tie, mark every tied option with the exact label + `Elegant-arm tie`; do not give that label to an option outside the tie. Elegance is + judged on long-run grounds alone — correctness, no deferred breakage, no special + cases, fixing the generator rather than the instance — and never on effort, speed, or + convenience. A tie must be stated with the label; silence is not a tie. . *Justify any departure.* A recommendation that is not the elegant arm must name both arms and state, in the offer itself, why the departure is made on this occasion — an irreversible step already taken, a live outage, a precondition still gated. An @@ -96,7 +113,7 @@ in ignorance that it was the expedient one. The complete, always-current operating Doctrine is maintained as estate-common content in the arrival-pack and projected into every repository's `CLAUDE.md`. In -addition to the four principles above it holds: ground-truth by running the tool, +addition to the three canonical principles above it holds: ground-truth by running the tool, not trusting status docs; distrust the neural for exactness (licences, invariants, equivalence belong to PLASMA, not an LLM); squabble, don't bypass (reach green by satisfying the gate, never by admin-override); no automated licence edits; no diff --git a/ai-instruction/opus.adoc b/ai-instruction/opus.adoc index ee950ed46..a2439f768 100644 --- a/ai-instruction/opus.adoc +++ b/ai-instruction/opus.adoc @@ -196,7 +196,7 @@ both arms and state in the offer itself why you depart on this occasion; an unexplained departure is a defect in the question, not a matter of style. This binds unasked design calls too: where you take the non-elegant arm without asking, report it rather than absorb it. See -`+standards/RSR-PHILOSOPHY.adoc+`, _Elegance by default_. +`+RSR-PHILOSOPHY.adoc+`, _Elegance by default_. === Trust level & verification diff --git a/ai-instruction/sonnet.adoc b/ai-instruction/sonnet.adoc index 38e1ae70f..dba0ebc8a 100644 --- a/ai-instruction/sonnet.adoc +++ b/ai-instruction/sonnet.adoc @@ -141,7 +141,7 @@ correctness and the absence of deferred breakage, never on which is quickest — and where you take a different one, say which and why. A design decision recorded without the arm it rejected is exactly the plausible-looking fabrication the rule above warns about. See -`+standards/RSR-PHILOSOPHY.adoc+`, _Elegance by default_. +`+RSR-PHILOSOPHY.adoc+`, _Elegance by default_. === Trust level & verification diff --git a/docs/DEBTFILE-SPEC.adoc b/docs/DEBTFILE-SPEC.adoc index 64e89c612..7cc8239e2 100644 --- a/docs/DEBTFILE-SPEC.adoc +++ b/docs/DEBTFILE-SPEC.adoc @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 = Debtfile Specification Jonathan D.A. Jewell -v1.0.0, 2026-08-07 +v1.1.0, 2026-09-14 :toc: :toclevels: 3 @@ -105,6 +105,10 @@ Location: `.machine_readable/Debtfile.a2ml`, one per repository. - policy: remediable | flag-only - tri: eliminate | substitute | control (optional, Safety Triangle) - tracking: (optional) +- taxonomy-default-arm: (required for a taxonomy choice) +- taxonomy-selected-arm: (required for a taxonomy choice) +- taxonomy-departure-reason: + (required for a taxonomy choice) - accepted-until: YYYY-MM-DD ---- @@ -129,6 +133,23 @@ per the standing owner directive in `.claude/CLAUDE.md`: licence changes are manual, per-file and owner-only, and every prior bulk sweep scrambled identifiers or reverted owner decisions. +`taxonomy-default-arm`, `taxonomy-selected-arm`, `taxonomy-departure-reason`:: +The required, machine-checkable encoding for an entry that records a testing +taxonomy choice. The first two fields are stable identifiers matching +`[a-z0-9][a-z0-9._-]*`; they record the elegant long-term arm and the different +arm actually selected. `taxonomy-departure-reason` records why the non-default +arm is accepted on this occasion. All three fields must appear together, the +two arm identifiers must differ, and the reason must be non-empty. Neither +`description` nor `tracking` substitutes for any member of this group: those +fields continue to describe the debt and point to its external work item. + +[source] +---- +- taxonomy-default-arm: adapt-proven-idris2-test +- taxonomy-selected-arm: write-local-test +- taxonomy-departure-reason: the proven suite cannot yet exercise this host API +---- + `accepted-until`:: An expiry. Once passed, the entry fails the runner even while holding under its ceiling. Debt without an expiry is debt nobody revisits — the 697-issue pile is what that looks like. @@ -326,7 +347,7 @@ just debt-ratchet-down # re-measure and write back (lowers ceilings only) Three suites under `scripts/tests/`, discovered automatically by `.github/workflows/self-test.yml`: -* `debtfile-structure-test.sh` — 14 cases +* `debtfile-structure-test.sh` — 19 cases * `run-debtfile-test.sh` — 16 cases * `debt-ratchet-test.sh` — 12 cases diff --git a/scripts/check-debtfile-structure.sh b/scripts/check-debtfile-structure.sh index 4c477476c..bd5e7a2ba 100755 --- a/scripts/check-debtfile-structure.sh +++ b/scripts/check-debtfile-structure.sh @@ -45,11 +45,14 @@ entries=0 seen_ids=" " name="" probe="" count="" ceiling="" severity="" policy="" accepted="" +taxonomy_default="" taxonomy_selected="" taxonomy_reason="" +taxonomy_default_seen=0 taxonomy_selected_seen=0 taxonomy_reason_seen=0 note() { printf ' %s\n' "$*"; } bad() { printf ' ❌ %s\n' "$*"; fail=1; } is_uint() { case "${1:-}" in ''|*[!0-9]*) return 1;; *) return 0;; esac; } +has_nonspace() { case "${1:-}" in *[![:space:]]*) return 0;; *) return 1;; esac; } validate() { [ -n "$name" ] || return 0 @@ -90,6 +93,31 @@ validate() { *) bad "'$name' policy '$policy' is not one of remediable|flag-only" ;; esac + if [ "$taxonomy_default_seen" -ne 0 ] || [ "$taxonomy_selected_seen" -ne 0 ] || [ "$taxonomy_reason_seen" -ne 0 ]; then + if [ "$taxonomy_default_seen" -eq 0 ] || [ -z "$taxonomy_default" ]; then + bad "'$name' has a partial taxonomy choice: missing '- taxonomy-default-arm:'" + fi + if [ "$taxonomy_selected_seen" -eq 0 ] || [ -z "$taxonomy_selected" ]; then + bad "'$name' has a partial taxonomy choice: missing '- taxonomy-selected-arm:'" + fi + if [ "$taxonomy_reason_seen" -eq 0 ] || ! has_nonspace "$taxonomy_reason"; then + bad "'$name' has a partial taxonomy choice: missing '- taxonomy-departure-reason:'" + fi + + case "$taxonomy_default" in + ''|*[!a-z0-9._-]*|[!a-z0-9]*) + [ -n "$taxonomy_default" ] && bad "'$name' taxonomy-default-arm '$taxonomy_default' is not a stable arm id" ;; + esac + case "$taxonomy_selected" in + ''|*[!a-z0-9._-]*|[!a-z0-9]*) + [ -n "$taxonomy_selected" ] && bad "'$name' taxonomy-selected-arm '$taxonomy_selected' is not a stable arm id" ;; + esac + + if [ -n "$taxonomy_default" ] && [ "$taxonomy_default" = "$taxonomy_selected" ]; then + bad "'$name' taxonomy-selected-arm must differ from taxonomy-default-arm when recording a departure" + fi + fi + if [ -n "$accepted" ]; then case "$accepted" in [0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]) ;; @@ -100,7 +128,11 @@ validate() { fi } -reset_block() { name="$1"; probe=""; count=""; ceiling=""; severity=""; policy=""; accepted=""; } +reset_block() { + name="$1"; probe=""; count=""; ceiling=""; severity=""; policy=""; accepted="" + taxonomy_default=""; taxonomy_selected=""; taxonomy_reason="" + taxonomy_default_seen=0; taxonomy_selected_seen=0; taxonomy_reason_seen=0 +} while IFS= read -r raw || [ -n "$raw" ]; do line="${raw#"${raw%%[![:space:]]*}"}" @@ -111,6 +143,21 @@ while IFS= read -r raw || [ -n "$raw" ]; do '- ceiling: '*) ceiling="${line#- ceiling: }" ;; '- severity: '*) severity="${line#- severity: }" ;; '- policy: '*) policy="${line#- policy: }" ;; + '- taxonomy-default-arm:'*) + [ "$taxonomy_default_seen" -eq 0 ] || bad "'$name' repeats '- taxonomy-default-arm:'" + taxonomy_default_seen=1 + taxonomy_default="${line#- taxonomy-default-arm:}" + taxonomy_default="${taxonomy_default# }" ;; + '- taxonomy-selected-arm:'*) + [ "$taxonomy_selected_seen" -eq 0 ] || bad "'$name' repeats '- taxonomy-selected-arm:'" + taxonomy_selected_seen=1 + taxonomy_selected="${line#- taxonomy-selected-arm:}" + taxonomy_selected="${taxonomy_selected# }" ;; + '- taxonomy-departure-reason:'*) + [ "$taxonomy_reason_seen" -eq 0 ] || bad "'$name' repeats '- taxonomy-departure-reason:'" + taxonomy_reason_seen=1 + taxonomy_reason="${line#- taxonomy-departure-reason:}" + taxonomy_reason="${taxonomy_reason# }" ;; '- accepted-until: '*) accepted="${line#- accepted-until: }" ;; esac done < "$DEBT" diff --git a/scripts/tests/debtfile-structure-test.sh b/scripts/tests/debtfile-structure-test.sh index c762e7fbd..a38dee391 100755 --- a/scripts/tests/debtfile-structure-test.sh +++ b/scripts/tests/debtfile-structure-test.sh @@ -33,6 +33,75 @@ expect 0 "a complete entry is valid" <<'EOF' - accepted-until: 2030-01-01 EOF +expect 0 "a complete taxonomy choice is valid" <<'EOF' +### alpha +- description: d +- probe: echo 1 +- count: 1 +- ceiling: 1 +- severity: high +- policy: remediable +- taxonomy-default-arm: adapt-proven-idris2-test +- taxonomy-selected-arm: write-local-test +- taxonomy-departure-reason: the host API is not supported by the proven suite +- accepted-until: 2030-01-01 +EOF + +expect 1 "a partial taxonomy choice is rejected" <<'EOF' +### alpha +- description: d +- probe: echo 1 +- count: 1 +- ceiling: 1 +- severity: high +- policy: remediable +- taxonomy-default-arm: adapt-proven-idris2-test +- taxonomy-selected-arm: write-local-test +- accepted-until: 2030-01-01 +EOF + +expect 1 "an empty taxonomy-choice encoding is rejected" <<'EOF' +### alpha +- description: d +- probe: echo 1 +- count: 1 +- ceiling: 1 +- severity: high +- policy: remediable +- taxonomy-default-arm: +- taxonomy-selected-arm: +- taxonomy-departure-reason: +- accepted-until: 2030-01-01 +EOF + +expect 1 "a taxonomy choice must select the non-default arm" <<'EOF' +### alpha +- description: d +- probe: echo 1 +- count: 1 +- ceiling: 1 +- severity: high +- policy: remediable +- taxonomy-default-arm: adapt-proven-idris2-test +- taxonomy-selected-arm: adapt-proven-idris2-test +- taxonomy-departure-reason: no departure actually recorded +- accepted-until: 2030-01-01 +EOF + +expect 1 "taxonomy arm identifiers use the stable-id grammar" <<'EOF' +### alpha +- description: d +- probe: echo 1 +- count: 1 +- ceiling: 1 +- severity: high +- policy: remediable +- taxonomy-default-arm: Adapt proven test +- taxonomy-selected-arm: write-local-test +- taxonomy-departure-reason: the host API is not supported by the proven suite +- accepted-until: 2030-01-01 +EOF + expect 1 "an entry with no probe is rejected (a number nothing re-measures)" <<'EOF' ### alpha - description: d diff --git a/scripts/tests/run-debtfile-test.sh b/scripts/tests/run-debtfile-test.sh index d713f9024..f14a6f124 100755 --- a/scripts/tests/run-debtfile-test.sh +++ b/scripts/tests/run-debtfile-test.sh @@ -34,6 +34,9 @@ entry() { # entry [accepted-until] - ceiling: $3 - severity: high - policy: remediable +- taxonomy-default-arm: adapt-proven-idris2-test +- taxonomy-selected-arm: write-local-test +- taxonomy-departure-reason: the host API is not supported by the proven suite - accepted-until: ${4:-2030-01-01} EOF } @@ -74,8 +77,12 @@ expect 0 "the same probe guarded with || true is correct and passes" < <(entry ' # --write lowers a ceiling that has been paid down, and never raises one. entry 'echo 2' 4 4 > Debtfile.a2ml bash "$SCRIPT" --write Debtfile.a2ml >/dev/null 2>&1 || true -if grep -q '^- ceiling: 2$' Debtfile.a2ml && grep -q '^- count: 2$' Debtfile.a2ml; then - pass=$((pass+1)); echo " ok --write lowers the ceiling to the measured value and updates count" +if grep -q '^- ceiling: 2$' Debtfile.a2ml && + grep -q '^- count: 2$' Debtfile.a2ml && + grep -q '^- taxonomy-default-arm: adapt-proven-idris2-test$' Debtfile.a2ml && + grep -q '^- taxonomy-selected-arm: write-local-test$' Debtfile.a2ml && + grep -q '^- taxonomy-departure-reason: the host API is not supported by the proven suite$' Debtfile.a2ml; then + pass=$((pass+1)); echo " ok --write updates measurements and preserves taxonomy-choice fields" else fail=$((fail+1)); echo " FAIL --write did not ratchet down"; sed -n '1,20p' Debtfile.a2ml fi diff --git a/testing-and-benchmarking/TESTING-TAXONOMY.adoc b/testing-and-benchmarking/TESTING-TAXONOMY.adoc index 493f7ed0b..e94dc061a 100644 --- a/testing-and-benchmarking/TESTING-TAXONOMY.adoc +++ b/testing-and-benchmarking/TESTING-TAXONOMY.adoc @@ -81,13 +81,17 @@ owner. Judge elegance on long-run grounds only: correctness, absence of deferred breakage, no special cases, and a fix at the generator rather than at the instance. Never on how quickly a category can be marked satisfied. Where the other arm is taken, record both -arms and the reason for departing — in the `Debtfile` where a shortfall is being -tolerated, in the N/A justification where the category is being declined. An +arms and the reason for departing — using `taxonomy-default-arm`, +`taxonomy-selected-arm`, and `taxonomy-departure-reason` in the `Debtfile` where a +shortfall is being tolerated, and in the N/A justification where the category is +being declined. An unlabelled choice between a sound test and a convenient one is how a suite quietly becomes evidence for something nobody checked. -This is the estate doctrine _elegance by default_ applied to testing; see -link:../RSR-PHILOSOPHY.adoc[`RSR-PHILOSOPHY.adoc`]. +This is the proposed estate doctrine _elegance by default_ applied to testing; it +remains provisional until the ratification record in +link:../RSR-PHILOSOPHY.adoc[`RSR-PHILOSOPHY.adoc`] has an owner decision, dissent +record, and effective version or hash. == Part I: Test Categories From 772c72475a01bc4d48b84d40774b6e1b8f61a077 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Tue, 15 Sep 2026 12:06:42 +0100 Subject: [PATCH 3/3] Clarify proposed elegance doctrine and validate taxonomy debt metadata (#786) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clarify that “Elegance by default” remains non-canonical pending ratification, define tie-labeling rules, and correct AI-instruction links. Add explicit Debtfile fields and structural validation for testing-taxonomy departures, with coverage for complete, partial, invalid, and preserved metadata records. Update the testing taxonomy to reference the new encoding. Validation was not run. [View coding task](https://app.coderabbit.ai/code/tasks/5e073657-b50f-4ba2-92d3-2ecbd389f8bb?source=coding_agent_github_pr_description) Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> --- RSR-PHILOSOPHY.adoc | 71 +++++++++++-------- docs/DEBTFILE-SPEC.adoc | 29 ++++++-- scripts/check-debtfile-structure.sh | 56 +++++---------- scripts/tests/debtfile-structure-test.sh | 59 +++++++++++++++ scripts/tests/run-debtfile-test.sh | 19 +++++ .../TESTING-TAXONOMY.adoc | 13 ++-- 6 files changed, 168 insertions(+), 79 deletions(-) diff --git a/RSR-PHILOSOPHY.adoc b/RSR-PHILOSOPHY.adoc index 020250482..9ebdf9008 100644 --- a/RSR-PHILOSOPHY.adoc +++ b/RSR-PHILOSOPHY.adoc @@ -5,11 +5,14 @@ :icons: font [.lead] -This is the *canonical* statement of the operating principles every hyperpolymath -repository is worked under. It is the source that `rsr-template-repo` operationalises -and that the estate arrival-pack projects, in summary form, into the top of every -`CLAUDE.md`. The owner's `manifesto` states the same doctrine in its own voice; -where wording must be reconciled, the manifesto prevails. +This is the *canonical* statement of the ratified operating principles every +hyperpolymath repository is worked under. It is the source that +`rsr-template-repo` operationalises and that the estate arrival-pack projects, in +summary form, into the top of every `CLAUDE.md`. The owner's `manifesto` states the +same doctrine in its own voice; where wording must be reconciled, the manifesto +prevails. The _Elegance by default_ section below is an explicitly non-canonical +proposal and is excluded from that projection until its recorded ratification is +complete. Material explicitly marked *PROVISIONAL* is a proposal within this otherwise canonical document. It is not operating doctrine and must not be projected into @@ -45,9 +48,12 @@ own, a change gated on owner ratification — remediate the downstream *and* rec the source fix as the real work still owed. Silently patching the symptom as if it were the cure is itself a soundness hole (see _fail loudly_). -This principle stands beside its two canonical siblings: *holes before goals* and -*always fail loudly*. A proposed fourth principle, *elegance by default*, is recorded -below pending ratification. +This principle stands beside its two ratified siblings: *holes before goals* and +*always fail loudly*. Together they govern the order of work (holes first), the +manner of work (loudly, never silently green), and the locus of work (at the source, +never the symptom). A proposed fourth principle, *elegance by default*, follows; +it has no canonical force unless and until the proposal record shows completed +ratification. == Holes before goals @@ -66,16 +72,17 @@ not assumed. Prefer a build that breaks to a build that lies. [IMPORTANT] ==== -*Status: PROVISIONAL — not canonical policy.* - -* Owner decision: pending; the 2026-09-14 instruction authorised this proposal, - but no completed ratification decision is recorded. -* Dissent: not yet recorded. -* Effective version/hash: none. - -Before this principle becomes canonical or is propagated into `CLAUDE.md`, the -ratification record must replace all three pending values with the owner decision, -recorded dissent (including an explicit `none`), and an effective version or hash. +*Proposal status — not canonical.* + +* *Owner decision:* Pending ratification. The 2026-09-14 owner instruction + authorised drafting this proposal, not its adoption as permanent policy. +* *Dissent:* Pending the required contest and review period; no completed dissent + record exists yet. +* *Effective version/hash:* Not assigned. +* *Propagation:* This principle MUST NOT be treated as canonical or added to the + estate-common `CLAUDE.md` policy until the owner decision, dissent, effective + version/hash, superseded material, and migration limits are recorded under + `constitution/CHANGE-PROCEDURE.adoc`. ==== *Treat the most elegant and correct long-term solution as the default choice — and say @@ -90,12 +97,13 @@ justified by the construction that produced it. Three obligations follow, and none is optional: -. *Label it.* Mark exactly one option as the elegant and correct long-term arm unless - options genuinely tie. In a genuine tie, mark every tied option with the exact label - `Elegant-arm tie`; do not give that label to an option outside the tie. Elegance is - judged on long-run grounds alone — correctness, no deferred breakage, no special - cases, fixing the generator rather than the instance — and never on effort, speed, or - convenience. A tie must be stated with the label; silence is not a tie. +. *Label it.* When there is one elegant and correct long-term arm, mark exactly that + option *Elegant arm*. If two or more options genuinely tie, mark every tied option + *Elegant arm (tie)* and state explicitly that they are co-equal on the long-run + criteria; do not give any tied option the unqualified label. Elegance is judged on + long-run grounds alone — correctness, no deferred breakage, no special cases, fixing + the generator rather than the instance — and never on effort, speed, or convenience. + A close call is not a tie, and silence is never a tie. . *Justify any departure.* A recommendation that is not the elegant arm must name both arms and state, in the offer itself, why the departure is made on this occasion — an irreversible step already taken, a live outage, a precondition still gated. An @@ -113,13 +121,14 @@ in ignorance that it was the expedient one. The complete, always-current operating Doctrine is maintained as estate-common content in the arrival-pack and projected into every repository's `CLAUDE.md`. In -addition to the three canonical principles above it holds: ground-truth by running the tool, -not trusting status docs; distrust the neural for exactness (licences, invariants, -equivalence belong to PLASMA, not an LLM); squabble, don't bypass (reach green by -satisfying the gate, never by admin-override); no automated licence edits; no -deletion by access-recency; wire first; always sign; report faithfully (no -overclaim); stop-first on costly or outward-facing actions; boundaries are real; -and equivalence as identity. +addition to the three ratified principles above it holds: ground-truth by running +the tool, not trusting status docs; distrust the neural for exactness (licences, +invariants, equivalence belong to PLASMA, not an LLM); squabble, don't bypass +(reach green by satisfying the gate, never by admin-override); no automated +licence edits; no deletion by access-recency; wire first; always sign; report +faithfully (no overclaim); stop-first on costly or outward-facing actions; +boundaries are real; and equivalence as identity. _Elegance by default_ joins +this list only after the proposal record above is complete. == See also diff --git a/docs/DEBTFILE-SPEC.adoc b/docs/DEBTFILE-SPEC.adoc index 7cc8239e2..9b2661157 100644 --- a/docs/DEBTFILE-SPEC.adoc +++ b/docs/DEBTFILE-SPEC.adoc @@ -105,15 +105,19 @@ Location: `.machine_readable/Debtfile.a2ml`, one per repository. - policy: remediable | flag-only - tri: eliminate | substitute | control (optional, Safety Triangle) - tracking: (optional) -- taxonomy-default-arm: (required for a taxonomy choice) -- taxonomy-selected-arm: (required for a taxonomy choice) -- taxonomy-departure-reason: - (required for a taxonomy choice) +- taxonomy-choice: non-default (required for a testing-taxonomy departure) +- taxonomy-default-arm: +- taxonomy-non-default-arm: +- taxonomy-departure-reason: - accepted-until: YYYY-MM-DD ---- `##
` headings group entries and are otherwise ignored. +The four `taxonomy-*` fields are required together only when an entry records a +departure under `testing-and-benchmarking/TESTING-TAXONOMY.adoc`; otherwise omit +all four. + === Fields `probe`:: A shell command emitting one non-negative integer on stdout. This is @@ -154,6 +158,23 @@ fields continue to describe the debt and point to its external work item. holding under its ceiling. Debt without an expiry is debt nobody revisits — the 697-issue pile is what that looks like. +[[testing-taxonomy-choice]] +=== Testing-taxonomy choice encoding + +A Debtfile entry that tolerates the non-default arm of a testing-taxonomy choice +MUST use the dedicated `taxonomy-*` fields shown above. `taxonomy-choice` is the +literal `non-default`; `taxonomy-default-arm` names the elegant, long-term-correct +arm; `taxonomy-non-default-arm` names the different arm actually chosen; and +`taxonomy-departure-reason` states why that departure is being tolerated now. + +These values MUST NOT be hidden in `description` or `tracking`: those fields +describe the debt and point to its work item, respectively, and neither identifies +the rejected arm unambiguously. The structural validator rejects a partial choice +record, an unknown `taxonomy-choice` value, empty arm or reason values, and identical +default and non-default arms. The runner does not interpret this governance +metadata; its `--write` pass preserves it unchanged while updating only `count` and +`ceiling`. + [[probe-discipline]] == Probe discipline diff --git a/scripts/check-debtfile-structure.sh b/scripts/check-debtfile-structure.sh index bd5e7a2ba..bbfac55df 100755 --- a/scripts/check-debtfile-structure.sh +++ b/scripts/check-debtfile-structure.sh @@ -45,8 +45,7 @@ entries=0 seen_ids=" " name="" probe="" count="" ceiling="" severity="" policy="" accepted="" -taxonomy_default="" taxonomy_selected="" taxonomy_reason="" -taxonomy_default_seen=0 taxonomy_selected_seen=0 taxonomy_reason_seen=0 +taxonomy_seen=0 taxonomy_choice="" taxonomy_default="" taxonomy_non_default="" taxonomy_reason="" note() { printf ' %s\n' "$*"; } bad() { printf ' ❌ %s\n' "$*"; fail=1; } @@ -93,28 +92,17 @@ validate() { *) bad "'$name' policy '$policy' is not one of remediable|flag-only" ;; esac - if [ "$taxonomy_default_seen" -ne 0 ] || [ "$taxonomy_selected_seen" -ne 0 ] || [ "$taxonomy_reason_seen" -ne 0 ]; then - if [ "$taxonomy_default_seen" -eq 0 ] || [ -z "$taxonomy_default" ]; then - bad "'$name' has a partial taxonomy choice: missing '- taxonomy-default-arm:'" - fi - if [ "$taxonomy_selected_seen" -eq 0 ] || [ -z "$taxonomy_selected" ]; then - bad "'$name' has a partial taxonomy choice: missing '- taxonomy-selected-arm:'" - fi - if [ "$taxonomy_reason_seen" -eq 0 ] || ! has_nonspace "$taxonomy_reason"; then - bad "'$name' has a partial taxonomy choice: missing '- taxonomy-departure-reason:'" - fi - - case "$taxonomy_default" in - ''|*[!a-z0-9._-]*|[!a-z0-9]*) - [ -n "$taxonomy_default" ] && bad "'$name' taxonomy-default-arm '$taxonomy_default' is not a stable arm id" ;; - esac - case "$taxonomy_selected" in - ''|*[!a-z0-9._-]*|[!a-z0-9]*) - [ -n "$taxonomy_selected" ] && bad "'$name' taxonomy-selected-arm '$taxonomy_selected' is not a stable arm id" ;; + if [ "$taxonomy_seen" -ne 0 ]; then + case "$taxonomy_choice" in + non-default) ;; + '') bad "'$name' has taxonomy choice fields but no '- taxonomy-choice: non-default'" ;; + *) bad "'$name' taxonomy-choice '$taxonomy_choice' is not 'non-default'" ;; esac - - if [ -n "$taxonomy_default" ] && [ "$taxonomy_default" = "$taxonomy_selected" ]; then - bad "'$name' taxonomy-selected-arm must differ from taxonomy-default-arm when recording a departure" + [ -n "$taxonomy_default" ] || bad "'$name' has no '- taxonomy-default-arm:'" + [ -n "$taxonomy_non_default" ] || bad "'$name' has no '- taxonomy-non-default-arm:'" + [ -n "$taxonomy_reason" ] || bad "'$name' has no '- taxonomy-departure-reason:'" + if [ -n "$taxonomy_default" ] && [ "$taxonomy_default" = "$taxonomy_non_default" ]; then + bad "'$name' taxonomy-default-arm and taxonomy-non-default-arm must name different arms" fi fi @@ -130,8 +118,7 @@ validate() { reset_block() { name="$1"; probe=""; count=""; ceiling=""; severity=""; policy=""; accepted="" - taxonomy_default=""; taxonomy_selected=""; taxonomy_reason="" - taxonomy_default_seen=0; taxonomy_selected_seen=0; taxonomy_reason_seen=0 + taxonomy_seen=0; taxonomy_choice=""; taxonomy_default=""; taxonomy_non_default=""; taxonomy_reason="" } while IFS= read -r raw || [ -n "$raw" ]; do @@ -143,21 +130,14 @@ while IFS= read -r raw || [ -n "$raw" ]; do '- ceiling: '*) ceiling="${line#- ceiling: }" ;; '- severity: '*) severity="${line#- severity: }" ;; '- policy: '*) policy="${line#- policy: }" ;; + '- taxonomy-choice:'*) + taxonomy_seen=1; taxonomy_choice="${line#- taxonomy-choice:}"; taxonomy_choice="${taxonomy_choice# }" ;; '- taxonomy-default-arm:'*) - [ "$taxonomy_default_seen" -eq 0 ] || bad "'$name' repeats '- taxonomy-default-arm:'" - taxonomy_default_seen=1 - taxonomy_default="${line#- taxonomy-default-arm:}" - taxonomy_default="${taxonomy_default# }" ;; - '- taxonomy-selected-arm:'*) - [ "$taxonomy_selected_seen" -eq 0 ] || bad "'$name' repeats '- taxonomy-selected-arm:'" - taxonomy_selected_seen=1 - taxonomy_selected="${line#- taxonomy-selected-arm:}" - taxonomy_selected="${taxonomy_selected# }" ;; + taxonomy_seen=1; taxonomy_default="${line#- taxonomy-default-arm:}"; taxonomy_default="${taxonomy_default# }" ;; + '- taxonomy-non-default-arm:'*) + taxonomy_seen=1; taxonomy_non_default="${line#- taxonomy-non-default-arm:}"; taxonomy_non_default="${taxonomy_non_default# }" ;; '- taxonomy-departure-reason:'*) - [ "$taxonomy_reason_seen" -eq 0 ] || bad "'$name' repeats '- taxonomy-departure-reason:'" - taxonomy_reason_seen=1 - taxonomy_reason="${line#- taxonomy-departure-reason:}" - taxonomy_reason="${taxonomy_reason# }" ;; + taxonomy_seen=1; taxonomy_reason="${line#- taxonomy-departure-reason:}"; taxonomy_reason="${taxonomy_reason# }" ;; '- accepted-until: '*) accepted="${line#- accepted-until: }" ;; esac done < "$DEBT" diff --git a/scripts/tests/debtfile-structure-test.sh b/scripts/tests/debtfile-structure-test.sh index a38dee391..d9e078759 100755 --- a/scripts/tests/debtfile-structure-test.sh +++ b/scripts/tests/debtfile-structure-test.sh @@ -144,6 +144,65 @@ expect 0 "count below ceiling is fine (debt paid down, ceiling not yet lowered)" - accepted-until: 2030-01-01 EOF +expect 0 "a complete testing-taxonomy departure records both arms and its reason" <<'EOF' +### alpha +- description: a temporary local test is tolerated +- probe: echo 2 +- count: 2 +- ceiling: 4 +- severity: high +- policy: remediable +- taxonomy-choice: non-default +- taxonomy-default-arm: adapt the proven Idris2 test +- taxonomy-non-default-arm: retain the temporary local test +- taxonomy-departure-reason: upstream fixture is gated on the next release +- accepted-until: 2030-01-01 +EOF + +expect 1 "a partial testing-taxonomy choice record is rejected" <<'EOF' +### alpha +- description: a temporary local test is tolerated +- probe: echo 2 +- count: 2 +- ceiling: 4 +- severity: high +- policy: remediable +- taxonomy-choice: non-default +- taxonomy-default-arm: adapt the proven Idris2 test +- taxonomy-non-default-arm: retain the temporary local test +- accepted-until: 2030-01-01 +EOF + +expect 1 "testing-taxonomy default and non-default arms must differ" <<'EOF' +### alpha +- description: a temporary local test is tolerated +- probe: echo 2 +- count: 2 +- ceiling: 4 +- severity: high +- policy: remediable +- taxonomy-choice: non-default +- taxonomy-default-arm: retain the local test +- taxonomy-non-default-arm: retain the local test +- taxonomy-departure-reason: no actual departure was named +- accepted-until: 2030-01-01 +EOF + +expect 1 "an unknown taxonomy-choice selector is rejected" <<'EOF' +### alpha +- description: a temporary local test is tolerated +- probe: echo 2 +- count: 2 +- ceiling: 4 +- severity: high +- policy: remediable +- taxonomy-choice: convenient +- taxonomy-default-arm: adapt the proven Idris2 test +- taxonomy-non-default-arm: retain the temporary local test +- taxonomy-departure-reason: upstream fixture is gated on the next release +- accepted-until: 2030-01-01 +EOF + expect 1 "a non-integer count is rejected" <<'EOF' ### alpha - description: d diff --git a/scripts/tests/run-debtfile-test.sh b/scripts/tests/run-debtfile-test.sh index f14a6f124..e1887da32 100755 --- a/scripts/tests/run-debtfile-test.sh +++ b/scripts/tests/run-debtfile-test.sh @@ -87,6 +87,25 @@ else fail=$((fail+1)); echo " FAIL --write did not ratchet down"; sed -n '1,20p' Debtfile.a2ml fi +# Governance metadata validated by check-debtfile-structure.sh is opaque to the +# runner and must survive its targeted count/ceiling rewrite unchanged. +entry 'echo 2' 4 4 > Debtfile.a2ml +cat >> Debtfile.a2ml <<'EOF' +- taxonomy-choice: non-default +- taxonomy-default-arm: adapt the proven Idris2 test +- taxonomy-non-default-arm: retain the temporary local test +- taxonomy-departure-reason: upstream fixture is gated on the next release +EOF +bash "$SCRIPT" --write Debtfile.a2ml >/dev/null 2>&1 || true +if grep -q '^- taxonomy-choice: non-default$' Debtfile.a2ml \ + && grep -q '^- taxonomy-default-arm: adapt the proven Idris2 test$' Debtfile.a2ml \ + && grep -q '^- taxonomy-non-default-arm: retain the temporary local test$' Debtfile.a2ml \ + && grep -q '^- taxonomy-departure-reason: upstream fixture is gated on the next release$' Debtfile.a2ml; then + pass=$((pass+1)); echo " ok --write preserves testing-taxonomy choice metadata" +else + fail=$((fail+1)); echo " FAIL --write changed testing-taxonomy choice metadata"; sed -n '1,24p' Debtfile.a2ml +fi + entry 'echo 9' 4 4 > Debtfile.a2ml bash "$SCRIPT" --write Debtfile.a2ml >/dev/null 2>&1 || true if grep -q '^- ceiling: 4$' Debtfile.a2ml; then diff --git a/testing-and-benchmarking/TESTING-TAXONOMY.adoc b/testing-and-benchmarking/TESTING-TAXONOMY.adoc index e94dc061a..9d08cebad 100644 --- a/testing-and-benchmarking/TESTING-TAXONOMY.adoc +++ b/testing-and-benchmarking/TESTING-TAXONOMY.adoc @@ -81,12 +81,13 @@ owner. Judge elegance on long-run grounds only: correctness, absence of deferred breakage, no special cases, and a fix at the generator rather than at the instance. Never on how quickly a category can be marked satisfied. Where the other arm is taken, record both -arms and the reason for departing — using `taxonomy-default-arm`, -`taxonomy-selected-arm`, and `taxonomy-departure-reason` in the `Debtfile` where a -shortfall is being tolerated, and in the N/A justification where the category is -being declined. An -unlabelled choice between a sound test and a convenient one is how a suite quietly -becomes evidence for something nobody checked. +arms and the reason for departing — in the `Debtfile` where a shortfall is being +tolerated, using the required `taxonomy-choice`, `taxonomy-default-arm`, +`taxonomy-non-default-arm`, and `taxonomy-departure-reason` encoding defined in +link:../docs/DEBTFILE-SPEC.adoc#testing-taxonomy-choice[Debtfile Specification: +Testing-taxonomy choice encoding]; or in the N/A justification where the category +is being declined. An unlabelled choice between a sound test and a convenient one is +how a suite quietly becomes evidence for something nobody checked. This is the proposed estate doctrine _elegance by default_ applied to testing; it remains provisional until the ratification record in