From baa5393c4069fc946461bc9b9283149f8f451da5 Mon Sep 17 00:00:00 2001 From: Sal Date: Sat, 29 Aug 2026 06:57:03 +0100 Subject: [PATCH 1/2] docs(zsh): require canonical option spellings --- .../instructions/zsh-scripting.instructions.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/instructions/zsh-scripting.instructions.md b/.github/instructions/zsh-scripting.instructions.md index 9b5812881..61fd2043b 100644 --- a/.github/instructions/zsh-scripting.instructions.md +++ b/.github/instructions/zsh-scripting.instructions.md @@ -326,6 +326,21 @@ execution profile. ## Options and emulation +### `zsh/options/canonical-spelling` + +- Level: `required` +- Profiles: `standalone-executable`, `startup-file`, `sourced-library`, `autoload-function`, `test-fixture` +- Minimum Zsh: `null` +- Basis: `official-manual`, `organization-policy` +- Evidence: `options` +- Enforcement: `human-review` + +Write option names in the canonical underscore-separated form used by the Zsh +manual, including in `setopt`, `unsetopt`, option tests, and documentation. For +example, use `local_options`, `no_auto_pushd`, and `warn_create_global`, not +accepted separator-free aliases such as `localoptions`, `noautopushd`, and +`warncreateglobal`. + ### `zsh/options/declare-correctness-state` - Level: `required` From 5de9e4b9eff4d629a9e09bcb582e209844164db4 Mon Sep 17 00:00:00 2001 From: Sal Date: Sat, 29 Aug 2026 07:24:52 +0100 Subject: [PATCH 2/2] fix(zsh): register canonical spelling policy --- .../instructions/zsh-scripting.instructions.md | 2 +- lib/zsh-standard-policy.json | 15 +++++++++++++++ scripts/test_validate_zsh_standard_policy.py | 7 ++++--- scripts/validate-zsh-standard-policy.py | 2 ++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/.github/instructions/zsh-scripting.instructions.md b/.github/instructions/zsh-scripting.instructions.md index 61fd2043b..9b63e4b34 100644 --- a/.github/instructions/zsh-scripting.instructions.md +++ b/.github/instructions/zsh-scripting.instructions.md @@ -331,7 +331,7 @@ execution profile. - Level: `required` - Profiles: `standalone-executable`, `startup-file`, `sourced-library`, `autoload-function`, `test-fixture` - Minimum Zsh: `null` -- Basis: `official-manual`, `organization-policy` +- Basis: `mixed` - Evidence: `options` - Enforcement: `human-review` diff --git a/lib/zsh-standard-policy.json b/lib/zsh-standard-policy.json index 279c4d0f5..a26d92402 100644 --- a/lib/zsh-standard-policy.json +++ b/lib/zsh-standard-policy.json @@ -319,6 +319,21 @@ "evidence": ["functions", "options"], "enforcement": ["runtime-test"] }, + { + "id": "zsh/options/canonical-spelling", + "level": "required", + "profiles": [ + "standalone-executable", + "startup-file", + "sourced-library", + "autoload-function", + "test-fixture" + ], + "minimum_zsh": null, + "basis": "mixed", + "evidence": ["options"], + "enforcement": ["human-review"] + }, { "id": "zsh/options/declare-correctness-state", "level": "required", diff --git a/scripts/test_validate_zsh_standard_policy.py b/scripts/test_validate_zsh_standard_policy.py index b855afce0..7f74b90de 100644 --- a/scripts/test_validate_zsh_standard_policy.py +++ b/scripts/test_validate_zsh_standard_policy.py @@ -203,6 +203,7 @@ def test_startup_profile_has_exact_rule_membership(self) -> None: "zsh/review/report-without-rewrite", "zsh/change/conform-touched-code", "zsh/completion/preserve-trust-boundaries", + "zsh/options/canonical-spelling", "zsh/options/declare-correctness-state", "zsh/options/localize", "zsh/options/no-blanket-error-mode", @@ -249,7 +250,7 @@ def test_startup_profile_has_exact_rule_membership(self) -> None: [rule["id"] for rule in matching_rules], expected_rule_ids, ) - self.assertEqual(len(matching_rules), 48) + self.assertEqual(len(matching_rules), 49) for rule in matching_rules: with self.subTest(rule_id=rule["id"]): if rule["id"] == "zsh/completion/preserve-trust-boundaries": @@ -1977,7 +1978,7 @@ def test_repair_2_consumer_parser_outputs_match_frozen_golden(self) -> None: }, "parsed_rules": validator._markdown_rules(instruction), } - self.assertEqual(len(snapshot["rule_blocks"]), 63) + self.assertEqual(len(snapshot["rule_blocks"]), 64) digest = hashlib.sha256( json.dumps( snapshot, @@ -1989,7 +1990,7 @@ def test_repair_2_consumer_parser_outputs_match_frozen_golden(self) -> None: self.assertEqual( digest, - "15d3c2c6f7bcf5192f8fe4beb1b8e324262f0ea5779407b0c0609beadc13151c", + "e385f4d4c34496495e808b602b59adb88d5ace192619e04669c70f4020afc981", ) def test_rejects_list_and_nested_container_rule_headings(self) -> None: diff --git a/scripts/validate-zsh-standard-policy.py b/scripts/validate-zsh-standard-policy.py index e9fc579e1..fe8ba63e4 100644 --- a/scripts/validate-zsh-standard-policy.py +++ b/scripts/validate-zsh-standard-policy.py @@ -145,6 +145,7 @@ "zsh/test/isolate-environment", "zsh/test/declare-negative-fixtures", "zsh/test/match-production-profile", + "zsh/options/canonical-spelling", "zsh/options/declare-correctness-state", "zsh/options/localize", "zsh/options/no-top-level-leak", @@ -202,6 +203,7 @@ "zsh/review/report-without-rewrite", "zsh/change/conform-touched-code", "zsh/completion/preserve-trust-boundaries", + "zsh/options/canonical-spelling", "zsh/options/declare-correctness-state", "zsh/options/localize", "zsh/options/no-blanket-error-mode",