Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ jobs:
- run: bash scripts/tests/dispatch-paths.sh
- name: Workflow-pin fix scripts keep their contracts
run: bash scripts/tests/fix-workflow-pins.sh
- name: Pre-push gate rejects missing and failed scans
run: bash tests/pre-push-gate-test.sh

gsbot:
name: GSBot build, tests and dependency security
Expand Down
6 changes: 6 additions & 0 deletions .machine_readable/descriptiles/STATE.a2ml
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,9 @@ changes = "Main shell mutation paths blocked with exit 78; Rust fleet simulation
validation = "Shell containment tests passed; existing E2E 36 passed after supplying PyYAML. Rust tests not run: toolchain unavailable."
next = "Read-only estate directive inventory and explicit policy contract. Do not enable execution or increase permissions before local restrictions are enforced."
evidence = "docs/AUTOMATION-QUARANTINE.adoc; audits/fleet-wiring-2026-09-26.md"

[pre-push-enforcement-2026-11-07]
status = "candidate; hosted qualification and consumer deployment pending"
change = "Fail closed on zero scanners, scanner errors, malformed reports, incomplete assail coverage and failed configured consumer execution gates. Preserve custom hooks during installation."
validation = "28 local scanner/runner boundary controls and real Git installation controls pass. A separate actual Hypatia escript run accepted a clean fixture and blocked its changed critical transmute fixture; hosted and consumer deployment evidence is still pending."
contract = "docs/PRE-PUSH-GATE.adoc"
14 changes: 8 additions & 6 deletions bots/rhodibot/canon/pin.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ categories = 11
criteria = 78
weight_sum = 88

# Re-pinned 2026-10-27: the table changed upstream without a version bump
# (still 0.3.0), so the digest, not the version, is what moved.
# Re-pinned 2026-11-07 from standards commit
# fe57d352f0b1a50e5cb07b4aac2581caf355388e: table 0.3.1 recognizes native DEED
# declarations and existing Agda/container layouts; capability counts are unchanged.
#
# The release's second artefact: the gate table. It says which capabilities a
# profile may declare, what a preset expands to, and which module paths belong
Expand All @@ -49,13 +50,14 @@ weight_sum = 88
# drift script checks that all three agree, because a pin nothing verifies is
# not a binding.
[gates]
repo = "hyperpolymath/standards"
repo = "metadatastician/standards"
commit = "fe57d352f0b1a50e5cb07b4aac2581caf355388e"
path = ".machine_readable/template-capability-gates.toml"
slot = "gates"
version = "0.3.0"
version = "0.3.1"
released = "2026-09-19"
pinned = "2026-10-27"
sha256 = "2f31f46d4753432e0aa8c9c28f339e18e062c98dc6e6ef4ecbb76993cf37638b"
pinned = "2026-11-07"
sha256 = "5c510bba025be718deebb12d0333bfe7db2da43c66578b728b1a334df65290b1"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Pin the gate table to the ref CI checks

When the rhodibot matrix job runs, scripts/check-canon-drift.sh defaults to main and compares that branch's gate table and canon.lock against this digest; however, the current standards canon.lock still records the previous 2f31f46d... gate hash, while this change pins fe57d352.../5c510bba... and the checker never reads the new commit field. Consequently the mandatory Rust job exits in the canon-drift step before building or testing. Land the gate table and lock upstream first, or update the checker to fetch and consistently validate the configured repository/commit.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CodeRabbit please fix

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Analysis chain

Script executed:

#!/bin/bash
set -u
printf '%s\n' '=== Checker outline ==='
ast-grep outline scripts/check-canon-drift.sh --items all 2>&1 || true
printf '%s\n' '=== Checker source ==='
nl -ba scripts/check-canon-drift.sh | sed -n '1,260p'
printf '%s\n' '=== Checker references and tests ==='
rg -n -C 3 'check-canon-drift|STANDARDS_REF|CANON_REF|canon\.lock|template-capability-gates' .github scripts tests bots/rhodibot -g '!**/rsr-criteria-v2.a2ml' -g '!**/template-capability-gates.toml' | head -240 || true
printf '%s\n' '=== Upstream artifacts ==='
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
for ref in fe57d352f0b1a50e5cb07b4aac2581caf355388e main; do
  for artifact in canon.lock .machine_readable/template-capability-gates.toml; do
    file="$tmp/${ref}-$(basename "$artifact")"
    url="https://raw.githubusercontent.com/metadatastician/standards/$ref/$artifact"
    if curl -fsSL --max-time 20 "$url" -o "$file"; then
      printf '\n%s\n' "--- $ref $artifact"
      sha256sum "$file"
      if [ "$artifact" = canon.lock ]; then
        rg -n -C 3 'gates|criteria|sha256|commit|version' "$file" | head -100 || true
      else
        sed -n '1,20p' "$file"
      fi
    else
      printf '%s\n' "Fetch failed: $url"
    fi
  done
done

Length of output: 31336


Script executed:

#!/bin/bash
set -u
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
base='https://raw.githubusercontent.com/metadatastician/standards'
for ref in fe57d352f0b1a50e5cb07b4aac2581caf355388e main; do
  printf '\n=== canon.lock entries at %s ===\n' "$ref"
  if curl -fsSL --max-time 20 "$base/$ref/canon.lock" -o "$tmp/lock"; then
    rg -n -A4 -B2 '^[[:space:]]*(criteria|gates)[[:space:]]*=' "$tmp/lock" || true
  else
    printf '%s\n' 'Lock fetch failed'
  fi
done
printf '\n=== criteria at configured default ===\n'
url='https://raw.githubusercontent.com/hyperpolymath/standards/main/0-canon/rsr/rsr-criteria-v2.a2ml'
if curl -fsSL --max-time 20 "$url" -o "$tmp/criteria"; then
  sha256sum "$tmp/criteria"
else
  printf '%s\n' 'Criteria fetch failed'
fi
printf '\n=== vendored artifact digests ===\n'
sha256sum bots/rhodibot/canon/template-capability-gates.toml bots/rhodibot/canon/rsr-criteria-v2.a2ml
printf '\n=== base revision pin, if available ===\n'
git show origin/HEAD:bots/rhodibot/canon/pin.toml 2>/dev/null | sed -n '25,80p' || true

Length of output: 4589


@hyperpolymath The gate table at the pinned commit matches the vendored digest, but canon.lock at that same commit still records the old digest. Changing the ref alone will not make the check pass. The upstream lock must be corrected before this gate update can pass without weakening validation.

  • Update the checker to use each artifact’s configured repository and ref.
  • Add tests for matching pins, lock mismatches, and fetch failures.
  • After the upstream lock is corrected, pin a commit where the gate table and lock agree.

Failed to start Coding Agent task. Please try again.

You are interacting with an AI system.


# The shape of the pinned table. A vocabulary that shrank would leave profiles
# declaring the lost words unparseable, and criteria gated on them permanently
Expand Down
12 changes: 9 additions & 3 deletions bots/rhodibot/canon/template-capability-gates.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# Arrays are kept single-line so the checker can parse them with grep.

[meta]
version = "0.3.0"
version = "0.3.1"
policy = "0-canon/TEMPLATE-APPLICABILITY-POLICY.adoc"

[capabilities]
Expand Down Expand Up @@ -42,6 +42,9 @@ known = ["rust", "zig", "agda", "idris2", "haskell", "gleam", "elixir", "affines
# (#851); the root spelling is kept for repos that have not moved.
# * 3-practice/: hyperpolymath/standards keeps its own contributing and
# conduct guides in a district, not at the root of a 45-directory monorepo.
# A single repo chora deed may carry the manifest and descriptive records.
# The checker recognizes their substantive native AST clauses, not a wildcard
# filename alternative: malformed, empty and wrong-repository records fail.
paths = ["README.adoc", "EXPLAINME.adoc|docs/EXPLAINME.adoc", "LICENSE", "SECURITY.md|.github/SECURITY.md", "CONTRIBUTING.md|.github/CONTRIBUTING.md|CONTRIBUTING.adoc|3-practice/CONTRIBUTING.adoc", "CODE_OF_CONDUCT.md|.github/CODE_OF_CONDUCT.md|CODE_OF_CONDUCT.adoc|3-practice/CODE_OF_CONDUCT.adoc", "CHANGELOG.adoc|CHANGELOG.md", "0-AI-MANIFEST.a2ml|0-AI-MANIFEST.deed", ".machine_readable/descriptiles/|machine-readable/descriptiles/", ".machine_readable/rsr-profile.a2ml|machine-readable/rsr-profile.a2ml", ".well-known/|www/.well-known/", ".gitignore", "Justfile"]

[gates]
Expand Down Expand Up @@ -71,9 +74,12 @@ paths = ["README.adoc", "EXPLAINME.adoc|docs/EXPLAINME.adoc", "LICENSE", "SECURI
"abi.ipkg" = "abi"
"src/interface/abi/|src/interface/Abi/" = "abi"
"src/interface/generated/" = "abi"
"verification/proofs/" = "formal-proofs"
# Both layouts carry proof sources. The checker requires a nonempty prover
# source file: an empty directory or a README is not a proof capability.
"verification/proofs/|proofs/agda/" = "formal-proofs"
".github/workflows/e2e.yml" = "api-service"
"build/container/|container/" = "container"
# A root Containerfile is already an accepted recipe. Requiring an additional
# container/ directory creates empty scaffolding without another obligation.
"build/container/Containerfile|container/Containerfile|Containerfile" = "container"
# Guix is primary; Nix is fallback-only (criterion 1.2.1). As two separate rows
# this demanded BOTH, so every repo that correctly retired Nix failed the gate.
Expand Down
2 changes: 1 addition & 1 deletion bots/rhodibot/src/canon/profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ version = \"2.0.4\"
#[test]
fn the_vendored_gate_table_has_the_expected_shape() {
let table = gates();
assert_eq!(table.version(), "0.3.0");
assert_eq!(table.version(), "0.3.1");
assert_eq!(
table.known_count(),
28,
Expand Down
22 changes: 9 additions & 13 deletions docs/BRANCH-PROTECTION-SETUP.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -74,24 +74,20 @@ Then add the status checks in *Settings > Branches* as described above.

=== Local Pre-Push Hook

A local hook mirrors the CI gate so developers catch critical findings
before pushing. Install it from `+gitbot-fleet/hooks/pre-push-gate.sh+`:
A local static-analysis hook catches critical findings before pushing.
Use the installer from a reviewed fleet checkout; it preserves existing hooks
and resolves configured hooks paths and linked worktrees through Git:

[source,bash]
----
# Symlink (recommended — always picks up updates)
ln -sf ~/Documents/hyperpolymath-repos/gitbot-fleet/hooks/pre-push-gate.sh \
.git/hooks/pre-push

# Or copy
cp ~/Documents/hyperpolymath-repos/gitbot-fleet/hooks/pre-push-gate.sh \
.git/hooks/pre-push
chmod +x .git/hooks/pre-push
bash /path/to/gitbot-fleet/scripts/install-pre-push-gate.sh /path/to/consumer
----

The hook gracefully degrades: if neither panic-attack nor hypatia is
installed locally, it prints a notice and allows the push (CI will catch
it).
The hook blocks if no scanner completes, a configured scanner is unavailable,
a report is malformed, a scanner fails or times out, or a critical finding is
reported. Static scanning is not CI execution parity. Configure the consumer's
owned execution adapter separately. See xref:PRE-PUSH-GATE.adoc[the gate's
dependencies, configuration, installation and validation limits].

'''''

Expand Down
40 changes: 40 additions & 0 deletions docs/PRE-PUSH-GATE.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: CC-BY-SA-4.0
= Local pre-push gate
:revdate: 2026-11-07

Run `bash scripts/install-pre-push-gate.sh /path/to/consumer` from a reviewed
fleet checkout. The installer uses Git's hooks path, including linked worktrees
and `core.hooksPath`. It refuses to replace a different existing hook. Compose
such a hook explicitly; do not overwrite its checks. A second identical
Comment thread
hyperpolymath marked this conversation as resolved.
Resolved
installation is a no-op. A future upgrade also requires reviewing the existing
copy rather than overwriting custom changes.

The gate requires `jq`, GNU `timeout`, and at least one available scanner on
the hook's PATH. With the default `auto` selection it runs every available
scanner; a failure from either blocks even if another scanner succeeds.
Set repository config `fleet.prePushScanners` to `hypatia`, `panic-attack`, or
`hypatia panic-attack` to require those particular scanners. An unavailable
required scanner blocks. `fleet.prePushTimeoutSeconds` defaults to 180 and
accepts 1 through 1800 seconds per scanner.

Hypatia uses `hypatia-cli.sh scan` with JSON output and the critical threshold.
Both its Elixir findings array and Bash submission envelope are validated.
Panic-attack uses `assail --headless --output-format json --fail-on-incomplete`;
its 2.6 report must record complete, non-empty declared coverage. Older reports
with no coverage receipt cannot certify this gate. Unknown formats, severities,
malformed output, scanner errors and timeouts block. Explicit suppressed or
advisory findings do not block; unsuppressed critical findings do.

Static scanning does not execute changed workflows. Set `fleet.prePushCiRunner`
to an absolute executable path for the consumer's owned execution gate. It runs
in the consumer working tree and receives the original pre-push arguments and
ref-update stdin. A missing or failed configured runner blocks. Without one,
the output explicitly reports static scanning only; it is not local CI parity
or hosted validation. The consumer remains responsible for selecting changed
scripts and fixtures and validating unsupported hosted semantics.

`bash tests/pre-push-gate-test.sh` uses fixture scanner processes to exercise
failure boundaries, actual Git hook installation and a real script/fixture
execution adapter. Those controls are not deployment evidence or a real scan.
Record actual scanner and consumer execution receipts separately before
claiming a consumer has adopted the full gate.
Loading
Loading