From a623d7cf5864ba38929840c7192b68eab3aeefcf Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Wed, 9 Sep 2026 23:14:30 +0100 Subject: [PATCH 1/3] fix(ci): detect retired descriptile policy and preserve repair routing --- .../recipe-retired-descriptile-policy.json | 16 ++++++ lib/hypatia/cli.ex | 1 + lib/rules/structural_drift.ex | 55 ++++++++++++++++++- test/retired_descriptile_policy_test.exs | 38 +++++++++++++ 4 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 data/verisim/recipes/recipe-retired-descriptile-policy.json create mode 100644 test/retired_descriptile_policy_test.exs diff --git a/data/verisim/recipes/recipe-retired-descriptile-policy.json b/data/verisim/recipes/recipe-retired-descriptile-policy.json new file mode 100644 index 00000000..f545410b --- /dev/null +++ b/data/verisim/recipes/recipe-retired-descriptile-policy.json @@ -0,0 +1,16 @@ +{ + "id": "recipe-retired-descriptile-policy", + "name": "Align CI descriptile checks with the canonical tree", + "description": "Repair the policy reference only after the canonical descriptile exists; never recreate retired copies.", + "triangle_tier": "eliminate", + "pattern_ids": ["SD024", "structural_drift/SD024"], + "target_categories": ["RetiredDescriptilePolicy"], + "languages": ["yaml", "shell", "bash", "just"], + "confidence": 0.95, + "auto_fixable": true, + "fix_script": "fix-retired-descriptile-policy.sh", + "action": "replace", + "formally_proven": false, + "successful_fixes": 0, + "failed_fixes": 0 +} diff --git a/lib/hypatia/cli.ex b/lib/hypatia/cli.ex index 8857ca00..ac91c045 100644 --- a/lib/hypatia/cli.ex +++ b/lib/hypatia/cli.ex @@ -791,6 +791,7 @@ defmodule Hypatia.CLI do reason: f.reason, action: to_string(f.action) } + |> Map.merge(Map.take(f, [:line, :category, :recipe_id, :fix_script, :target])) end) results ++ normalized diff --git a/lib/rules/structural_drift.ex b/lib/rules/structural_drift.ex index d75c5b3d..07b5d1a3 100644 --- a/lib/rules/structural_drift.ex +++ b/lib/rules/structural_drift.ex @@ -745,7 +745,8 @@ defmodule Hypatia.Rules.StructuralDrift do sd013_path_specific_gitignore(repo_path) ++ sd014_safedom_example_dialect(repo_path) ++ sd022_stale_path_after_rename(repo_path) ++ - sd023_state_a2ml_divergence(repo_path) + sd023_state_a2ml_divergence(repo_path) ++ + sd024_retired_descriptile_policy(repo_path) needs_intensive = Enum.any?(findings, & &1[:trigger_intensive]) needs_alert = Enum.any?(findings, & &1[:alert_user]) @@ -762,6 +763,58 @@ defmodule Hypatia.Rules.StructuralDrift do # ─── Helpers ─────────────────────────────────────────────────────────── + @doc """ + SD024: Detect executable policy that requires descriptiles in retired paths. + + A canonical tree can never satisfy such a check and SD004 simultaneously. + Report the policy file for reference repair; do not suggest recreating the + retired file. Documentation and commented examples are outside this rule. + """ + def sd024_retired_descriptile_policy(repo_path) do + files = + Path.wildcard(Path.join(repo_path, ".github/workflows/*.{yml,yaml}")) ++ + Path.wildcard(Path.join(repo_path, "scripts/*.sh")) ++ + Path.wildcard(Path.join(repo_path, ".githooks/*.sh")) ++ + Enum.map(["Justfile", "justfile"], &Path.join(repo_path, &1)) + + Enum.flat_map(files, fn file -> + case File.read(file) do + {:ok, content} -> + content + |> String.split("\n") + |> Enum.with_index(1) + |> Enum.flat_map(fn {line, number} -> + legacy = + ~r/\.machine_readable\/(?:6a2\/)?(?:STATE|META|ECOSYSTEM|AGENTIC|NEUROSYM|PLAYBOOK|ANCHOR)\.a2ml/ + + if not String.starts_with?(String.trim_leading(line), "#") and + Regex.match?(~r/(?:\s-f\s|\s-e\s|check_file\s)/, line) and + Regex.match?(legacy, line) do + [ + %{ + rule: "SD024", + file: Path.relative_to(file, repo_path), + line: number, + severity: :high, + reason: + "CI policy requires a retired descriptile path; align the check with .machine_readable/descriptiles/", + category: "RetiredDescriptilePolicy", + action: :update_reference, + recipe_id: "recipe-retired-descriptile-policy", + fix_script: "fix-retired-descriptile-policy.sh" + } + ] + else + [] + end + end) + + {:error, _} -> + [] + end + end) + end + defp group_by_severity(findings) do findings |> Enum.group_by(& &1.severity) diff --git a/test/retired_descriptile_policy_test.exs b/test/retired_descriptile_policy_test.exs new file mode 100644 index 00000000..26a2e85c --- /dev/null +++ b/test/retired_descriptile_policy_test.exs @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: MPL-2.0 +defmodule Hypatia.RetiredDescriptilePolicyTest do + use ExUnit.Case, async: true + alias Hypatia.Rules.StructuralDrift + + test "detects the contradictory check and routes reference repair" do + repo = + Path.join(System.tmp_dir!(), "descriptile-policy-#{System.unique_integer([:positive])}") + + File.mkdir_p!(Path.join(repo, ".github/workflows")) + on_exit(fn -> File.rm_rf!(repo) end) + file = Path.join(repo, ".github/workflows/compliance.yml") + File.write!(file, "run: |\n if [ ! -f .machine_readable/STATE.a2ml ]; then exit 1; fi\n") + [finding] = StructuralDrift.sd024_retired_descriptile_policy(repo) + assert finding.rule == "SD024" + assert finding.line == 2 + assert finding.action == :update_reference + assert finding.fix_script == "fix-retired-descriptile-policy.sh" + + normalized = + Hypatia.CLI.collect_findings(repo, [:structural_drift]) + |> Enum.find(&(&1.type == "SD024")) + + assert normalized.category == "RetiredDescriptilePolicy" + assert normalized.recipe_id == "recipe-retired-descriptile-policy" + assert normalized.fix_script == "fix-retired-descriptile-policy.sh" + assert normalized.line == 2 + + File.write!( + file, + "run: |\n if [ ! -f .machine_readable/descriptiles/STATE.a2ml ]; then exit 1; fi\n" + ) + + assert StructuralDrift.sd024_retired_descriptile_policy(repo) == [] + File.write!(file, "# if [ ! -f .machine_readable/6a2/STATE.a2ml ]; then exit 1; fi\n") + assert StructuralDrift.sd024_retired_descriptile_policy(repo) == [] + end +end From 8be087922ea93e81d5c9db7288e0829cb6908cdf Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Wed, 9 Sep 2026 23:38:41 +0100 Subject: [PATCH 2/3] fix(ci): refresh renamed and repaired manifest actions --- .github/workflows/actions.lock | 14 +++++++------- .github/workflows/bridge-gate.yml | 1 + .github/workflows/build-gossamer-gui.yml | 1 + .github/workflows/ci-health-sweep.yml | 1 + .github/workflows/ci.yml | 1 + .github/workflows/clusterfuzzlite.yml | 1 + .github/workflows/codeql.yml | 1 + .github/workflows/dependabot-automerge.yml | 1 + .github/workflows/dogfood-gate.yml | 5 +++-- .github/workflows/estate-rescan.yml | 1 + .github/workflows/governance.yml | 1 + .github/workflows/hypatia-remediation-sweep.yml | 1 + .github/workflows/hypatia-scan.yml | 1 + .github/workflows/inbox-steward-intake.yml | 1 + .github/workflows/label-triage.yml | 1 + .github/workflows/labels.yml | 1 + .github/workflows/language-blockers.yml | 1 + .github/workflows/merge-orchestrate.yml | 1 + .github/workflows/mirror.yml | 1 + .github/workflows/pages.yml | 1 + .github/workflows/push-email-notify.yml | 1 + .github/workflows/quality.yml | 1 + .github/workflows/release.yml | 1 + .github/workflows/roadmap-sync.yml | 1 + .github/workflows/rust.yml | 1 + .github/workflows/scorecard.yml | 1 + .github/workflows/secret-scanner.yml | 1 + .github/workflows/security-policy.yml | 1 + .github/workflows/tests.yml | 1 + .github/workflows/verify-proofs.yml | 1 + 30 files changed, 38 insertions(+), 9 deletions(-) diff --git a/.github/workflows/actions.lock b/.github/workflows/actions.lock index 759c3445..d6a36002 100644 --- a/.github/workflows/actions.lock +++ b/.github/workflows/actions.lock @@ -35,8 +35,8 @@ workflows: - 'dependabot/fetch-metadata@v3.1.0' '.github/workflows/dogfood-gate.yml': - 'actions/checkout@v7.0.1' - - 'hyperpolymath/a2ml-ecosystem@main' - - 'hyperpolymath/k9-ecosystem@main' + - 'hyperpolymath/deed-ecosystem@main' + - 'hyperpolymath/k9-ecosystem@codex/science-ci-20260909' '.github/workflows/estate-rescan.yml': - 'actions/cache@v6.1.0' '.github/workflows/governance.yml': [] @@ -294,14 +294,14 @@ dependencies: commit: 'sha1-6037f33647c3f17758a2356c80fc4a53d7e0685d' owner_id: 75048950 repo_id: 623796603 - 'hyperpolymath/a2ml-ecosystem@main': + 'hyperpolymath/deed-ecosystem@main': ref: 'main' - commit: 'sha1-c992d2882ee1e62bf5c78b5f9a1893a6a16730e4' + commit: 'sha1-f7a40a4d5cc82b2e73f861119baa6818d77a448d' owner_id: 6759885 repo_id: 1275649586 - 'hyperpolymath/k9-ecosystem@main': - ref: 'main' - commit: 'sha1-3f250fba42e432c7ff47b48f59525bec3357136b' + 'hyperpolymath/k9-ecosystem@codex/science-ci-20260909': + ref: 'codex/science-ci-20260909' + commit: 'sha1-2ee51eed590b4722efcdca2fe4685ef24600bced' owner_id: 6759885 repo_id: 1275650185 'ruby/setup-ruby@v1.321.0': diff --git a/.github/workflows/bridge-gate.yml b/.github/workflows/bridge-gate.yml index cbd400f3..c52295eb 100644 --- a/.github/workflows/bridge-gate.yml +++ b/.github/workflows/bridge-gate.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Copyright (c) 2026 Jonathan D.A. Jewell diff --git a/.github/workflows/build-gossamer-gui.yml b/.github/workflows/build-gossamer-gui.yml index 10f75d2b..e0296ea8 100644 --- a/.github/workflows/build-gossamer-gui.yml +++ b/.github/workflows/build-gossamer-gui.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Build the Hypatia GUI wasm artifact from the Ephapax/Gossamer sources. diff --git a/.github/workflows/ci-health-sweep.yml b/.github/workflows/ci-health-sweep.yml index 41307ba1..c26d8ecc 100644 --- a/.github/workflows/ci-health-sweep.yml +++ b/.github/workflows/ci-health-sweep.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Owner: Jonathan D.A. Jewell diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 635b0aca..d1cb2927 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Main CI workflow for hypatia diff --git a/.github/workflows/clusterfuzzlite.yml b/.github/workflows/clusterfuzzlite.yml index 54325ca0..997373e9 100644 --- a/.github/workflows/clusterfuzzlite.yml +++ b/.github/workflows/clusterfuzzlite.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Consolidated workflow (behaviour-preserving merge). diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 5c4e581b..99ca3959 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. name: CodeQL Security Analysis diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml index e9bc6c96..4742b314 100644 --- a/.github/workflows/dependabot-automerge.yml +++ b/.github/workflows/dependabot-automerge.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # diff --git a/.github/workflows/dogfood-gate.yml b/.github/workflows/dogfood-gate.yml index 43b9a0cb..56888501 100644 --- a/.github/workflows/dogfood-gate.yml +++ b/.github/workflows/dogfood-gate.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) @@ -47,7 +48,7 @@ jobs: - name: Validate A2ML manifests if: steps.detect.outputs.count > 0 - uses: hyperpolymath/a2ml-ecosystem/validate-action@main + uses: hyperpolymath/deed-ecosystem/validate-action@main with: path: '.' strict: 'false' @@ -108,7 +109,7 @@ jobs: - name: Validate K9 contracts if: steps.detect.outputs.k9_count > 0 - uses: hyperpolymath/k9-ecosystem/validate-action@main + uses: hyperpolymath/k9-ecosystem/validate-action@codex/science-ci-20260909 with: path: '.' strict: 'false' diff --git a/.github/workflows/estate-rescan.yml b/.github/workflows/estate-rescan.yml index 3ec768fc..55b97534 100644 --- a/.github/workflows/estate-rescan.yml +++ b/.github/workflows/estate-rescan.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Hypatia Estate Rescan — refresh verisimdb-data/scans with current truth diff --git a/.github/workflows/governance.yml b/.github/workflows/governance.yml index f43e5995..c656a376 100644 --- a/.github/workflows/governance.yml +++ b/.github/workflows/governance.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: PMPL-1.0-or-later # This workflow is managed by gh actions-lock. name: Governance diff --git a/.github/workflows/hypatia-remediation-sweep.yml b/.github/workflows/hypatia-remediation-sweep.yml index 8653900f..c7c96598 100644 --- a/.github/workflows/hypatia-remediation-sweep.yml +++ b/.github/workflows/hypatia-remediation-sweep.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Hypatia Remediation Sweep — fleet-wide proactive scan diff --git a/.github/workflows/hypatia-scan.yml b/.github/workflows/hypatia-scan.yml index 53bf1884..ff5ee89b 100644 --- a/.github/workflows/hypatia-scan.yml +++ b/.github/workflows/hypatia-scan.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: PMPL-1.0-or-later # This workflow is managed by gh actions-lock. name: Hypatia Security Scan diff --git a/.github/workflows/inbox-steward-intake.yml b/.github/workflows/inbox-steward-intake.yml index 728b82db..a8d0b089 100644 --- a/.github/workflows/inbox-steward-intake.yml +++ b/.github/workflows/inbox-steward-intake.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Inbox Steward Intake — Process reports from gitbot-fleet inbox-steward diff --git a/.github/workflows/label-triage.yml b/.github/workflows/label-triage.yml index e61baef9..3e747485 100644 --- a/.github/workflows/label-triage.yml +++ b/.github/workflows/label-triage.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 name: Label Triage diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index c536afb9..a4208d7f 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 name: Labels diff --git a/.github/workflows/language-blockers.yml b/.github/workflows/language-blockers.yml index 3262df36..a90f2996 100644 --- a/.github/workflows/language-blockers.yml +++ b/.github/workflows/language-blockers.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Consolidated workflow (behaviour-preserving merge). diff --git a/.github/workflows/merge-orchestrate.yml b/.github/workflows/merge-orchestrate.yml index 746195bc..1532b6ce 100644 --- a/.github/workflows/merge-orchestrate.yml +++ b/.github/workflows/merge-orchestrate.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Copyright (c) 2026 Jonathan D.A. Jewell diff --git a/.github/workflows/mirror.yml b/.github/workflows/mirror.yml index 92623846..5440e468 100644 --- a/.github/workflows/mirror.yml +++ b/.github/workflows/mirror.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. name: Mirror to Git Forges diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 3be681d6..6fdc0d3a 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. name: GitHub Pages (Ddraig SSG) diff --git a/.github/workflows/push-email-notify.yml b/.github/workflows/push-email-notify.yml index 9e133d7c..52757af7 100644 --- a/.github/workflows/push-email-notify.yml +++ b/.github/workflows/push-email-notify.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Dormant push-email notification. ARMED by setting the repo variable diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index c5349a6e..12096113 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Consolidated workflow (behaviour-preserving merge). diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 56d6946d..fd5f0ba4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Consolidated workflow (behaviour-preserving merge). diff --git a/.github/workflows/roadmap-sync.yml b/.github/workflows/roadmap-sync.yml index afdcfc09..5afaab76 100644 --- a/.github/workflows/roadmap-sync.yml +++ b/.github/workflows/roadmap-sync.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Centralized roadmap sweeper: adds recently-touched issues & PRs from every diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 197e2f17..8fe34863 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Consolidated workflow (behaviour-preserving merge). diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index cf10069e..f9e7cb0f 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: PMPL-1.0-or-later # This workflow is managed by gh actions-lock. name: OSSF Scorecard diff --git a/.github/workflows/secret-scanner.yml b/.github/workflows/secret-scanner.yml index 414eed91..52c6f1e8 100644 --- a/.github/workflows/secret-scanner.yml +++ b/.github/workflows/secret-scanner.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. name: Secret Scanner diff --git a/.github/workflows/security-policy.yml b/.github/workflows/security-policy.yml index 239c5ad8..4ca09e3b 100644 --- a/.github/workflows/security-policy.yml +++ b/.github/workflows/security-policy.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Consolidated workflow (behaviour-preserving merge). diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ca53e18e..a0fda1ca 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Consolidated workflow (behaviour-preserving merge). diff --git a/.github/workflows/verify-proofs.yml b/.github/workflows/verify-proofs.yml index 2323ca72..4c4dad72 100644 --- a/.github/workflows/verify-proofs.yml +++ b/.github/workflows/verify-proofs.yml @@ -1,3 +1,4 @@ +# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 # This workflow is managed by gh actions-lock. # Consolidated workflow (behaviour-preserving merge). From 204a000add6bd1ffbe10cd621f89f7db60a2ab14 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Thu, 10 Sep 2026 00:58:51 +0100 Subject: [PATCH 3/3] fix(rules): distinguish quoted policy examples and consume merged K9 repair --- .github/workflows/actions.lock | 8 ++++---- .github/workflows/dogfood-gate.yml | 3 +-- lib/rules/structural_drift.ex | 19 +++++++++++++++++-- test/retired_descriptile_policy_test.exs | 17 +++++++++++++++++ 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/.github/workflows/actions.lock b/.github/workflows/actions.lock index d6a36002..04da3687 100644 --- a/.github/workflows/actions.lock +++ b/.github/workflows/actions.lock @@ -36,7 +36,7 @@ workflows: '.github/workflows/dogfood-gate.yml': - 'actions/checkout@v7.0.1' - 'hyperpolymath/deed-ecosystem@main' - - 'hyperpolymath/k9-ecosystem@codex/science-ci-20260909' + - 'hyperpolymath/k9-ecosystem@main' '.github/workflows/estate-rescan.yml': - 'actions/cache@v6.1.0' '.github/workflows/governance.yml': [] @@ -299,9 +299,9 @@ dependencies: commit: 'sha1-f7a40a4d5cc82b2e73f861119baa6818d77a448d' owner_id: 6759885 repo_id: 1275649586 - 'hyperpolymath/k9-ecosystem@codex/science-ci-20260909': - ref: 'codex/science-ci-20260909' - commit: 'sha1-2ee51eed590b4722efcdca2fe4685ef24600bced' + 'hyperpolymath/k9-ecosystem@main': + ref: 'main' + commit: 'sha1-2155aa26a21758f2ba119f61bc7e0e1981c106fb' owner_id: 6759885 repo_id: 1275650185 'ruby/setup-ruby@v1.321.0': diff --git a/.github/workflows/dogfood-gate.yml b/.github/workflows/dogfood-gate.yml index 56888501..0be6e453 100644 --- a/.github/workflows/dogfood-gate.yml +++ b/.github/workflows/dogfood-gate.yml @@ -109,7 +109,7 @@ jobs: - name: Validate K9 contracts if: steps.detect.outputs.k9_count > 0 - uses: hyperpolymath/k9-ecosystem/validate-action@codex/science-ci-20260909 + uses: hyperpolymath/k9-ecosystem/validate-action@main with: path: '.' strict: 'false' @@ -346,4 +346,3 @@ jobs: *Generated by the [Dogfood Gate](https://github.com/hyperpolymath/rsr-template-repo) workflow.* *Dogfooding is guinea pig fooding — we test our tools on ourselves.* EOF - diff --git a/lib/rules/structural_drift.ex b/lib/rules/structural_drift.ex index 07b5d1a3..992a3180 100644 --- a/lib/rules/structural_drift.ex +++ b/lib/rules/structural_drift.ex @@ -787,9 +787,24 @@ defmodule Hypatia.Rules.StructuralDrift do legacy = ~r/\.machine_readable\/(?:6a2\/)?(?:STATE|META|ECOSYSTEM|AGENTIC|NEUROSYM|PLAYBOOK|ANCHOR)\.a2ml/ + # Quoted examples are prose, but quoted literal paths and shell + # command substitutions still participate in executable checks. + code = + Regex.replace(~r/"(?:\\.|[^"\\])*"|'[^']*'/, line, fn quoted -> + value = String.slice(quoted, 1, String.length(quoted) - 2) + + if Regex.match?(~r/^#{legacy.source}$/, value) or + (String.starts_with?(quoted, "\"") and + (String.contains?(value, "$(") or String.contains?(value, "`"))) do + value + else + " " + end + end) + if not String.starts_with?(String.trim_leading(line), "#") and - Regex.match?(~r/(?:\s-f\s|\s-e\s|check_file\s)/, line) and - Regex.match?(legacy, line) do + Regex.match?(~r/(?:\s-f\s|\s-e\s|check_file\s)/, code) and + Regex.match?(legacy, code) do [ %{ rule: "SD024", diff --git a/test/retired_descriptile_policy_test.exs b/test/retired_descriptile_policy_test.exs index 26a2e85c..8673520a 100644 --- a/test/retired_descriptile_policy_test.exs +++ b/test/retired_descriptile_policy_test.exs @@ -34,5 +34,22 @@ defmodule Hypatia.RetiredDescriptilePolicyTest do assert StructuralDrift.sd024_retired_descriptile_policy(repo) == [] File.write!(file, "# if [ ! -f .machine_readable/6a2/STATE.a2ml ]; then exit 1; fi\n") assert StructuralDrift.sd024_retired_descriptile_policy(repo) == [] + + for prose <- [ + ~s(echo "test -f .machine_readable/STATE.a2ml"), + ~s(printf '%s' 'check_file .machine_readable/META.a2ml') + ] do + File.write!(file, "run: |\n #{prose}\n") + assert StructuralDrift.sd024_retired_descriptile_policy(repo) == [] + end + + for command <- [ + ~s(test -f ".machine_readable/STATE.a2ml"), + ~s(test -e '.machine_readable/6a2/META.a2ml'), + ~s(check_file '.machine_readable/AGENTIC.a2ml') + ] do + File.write!(file, "run: |\n #{command}\n") + assert [%{rule: "SD024"}] = StructuralDrift.sd024_retired_descriptile_policy(repo) + end end end