Skip to content

feat(gsbot)!: faithful Rust/SPARK port — eliminate Python from the fleet#145

Merged
hyperpolymath merged 8 commits into
mainfrom
feat/gsbot-rust-spark-port
May 16, 2026
Merged

feat(gsbot)!: faithful Rust/SPARK port — eliminate Python from the fleet#145
hyperpolymath merged 8 commits into
mainfrom
feat/gsbot-rust-spark-port

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

Why

bots/gsbot (Garment Sustainability Bot) was the only Python in gitbot-fleet — 35 .py files, the source of the 35 cicd_rules/banned_language_file critical findings in the restored repo. Python is banned estate-wide with no exceptions; per the Rust/SPARK standard the sanctioned target is Rust/SPARK. This is a behaviour-preserving rewrite, not a rescaffold.

Stack

gsbot is the fleet's first Discord bot. Mappings, chosen to match fleet conventions:

Python Rust/SPARK
discord.py cogs poise/serenity prefix commands
SQLAlchemy + Alembic sqlx + SQLite + embedded migrations/
colorlog tracing
asyncio tokio
pandas/numpy not used by gsbot (no port needed)

Rust/SPARK seam

src/domain.rs is the correctness-critical scoring kernel: pure, total functions plus a #[no_mangle] extern "C" FFI surface so a verified SPARK/Ada module can be linked in later via the standard Idris2-ABI / Zig-FFI pattern ("designed to admit SPARK modules even if it contains none yet"). All callers use safe wrappers, so substitution is transparent.

Faithful behaviour

  • Identical env vars / defaults / validation.
  • Same schema incl. garment_materials M2M; identical scoring (material mean, grade ladder, garment lifespan multiplier + 100 cap, environmental-impact averaging, user points/level ratchet, ranks, brand summary).
  • Every command preserved — names, aliases, argument shapes, point awards (+5/+5/+3/+2, +5/+7/0, +5, admin), embed fields, the exact on_command_error messages, presence string.
  • !loaddata fixtures: same 10 materials / 7 garments / 6 brands.
  • scripts/*.py → 3 bins (gsbot-load-fixtures, -export-data, -backup-db).
  • Containerfile/docker-compose/Justfile rewritten for Rust (fleet convention: rust builder + debian-slim, non-root); Mustfile lint/test/fmt recipes preserved.

Verification (local)

  • cargo build --all-targets — clean
  • cargo clippy --all-targets -- -D warnings — clean
  • cargo fmt --all -- --check — clean
  • cargo test18/18 pass (domain 9, models 5, services 4)
  • All Python removed (requirements.txt, setup.py, pytest.ini, alembic.ini, 35 .py) → banned_language_file clears for gsbot.

Scope / safety

  • Surgical to bots/gsbot/ only. 38 tracked-file deletions — under the repo-integrity-guard's 50-file tripwire, so no [mass-delete-ok] marker needed; no critical paths touched.
  • The original bots/gsbot/CLAUDE.md is a stale generic template proposing Python; superseded by the estate Rust/SPARK standard (left as-is, out of scope).

Refs hyperpolymath/hypatia#252

🤖 Generated with Claude Code

gsbot (Garment Sustainability Bot) was the fleet's only Python code
(35 .py files) and the source of the 35 `cicd_rules/banned_language_file`
critical findings. Python is banned estate-wide with no exceptions;
this is a behaviour-preserving rewrite in Rust/SPARK, the sanctioned
target.

Stack (fleet conventions; gsbot is the fleet's first Discord bot):
poise/serenity (prefix commands ↔ discord.py cogs), sqlx+SQLite
(SQLAlchemy/Alembic ↔ models + embedded migrations), tracing
(colorlog), tokio.

Rust/SPARK seam: `src/domain.rs` is the correctness-critical scoring
kernel — pure, total functions plus a `#[no_mangle] extern "C"` FFI
surface so a verified SPARK/Ada module can be linked in later via the
standard Idris2-ABI / Zig-FFI pattern (per the standard: "designed to
admit SPARK modules even if it contains none yet"). All callers go
through safe wrappers, so substitution is transparent.

Faithful behaviour:
- Identical env vars/defaults/validation (config.rs ↔ settings.py).
- Same schema incl. garment_materials M2M; same scoring (material mean,
  grade ladder, garment lifespan multiplier + 100 cap, environmental
  impact averaging, user points/level ratchet, ranks, brand summary).
- Every command preserved: names, aliases, argument shapes, point
  awards (+5/+5/+3/+2 / +5/+7/0 / +5 / 0/0 / admin), embed fields,
  the `on_command_error` message mapping, presence string.
- `!loaddata` fixtures: same 10 materials / 7 garments / 6 brands.
- scripts/*.py → 3 bins (gsbot-load-fixtures/-export-data/-backup-db).
- Containerfile/docker-compose/Justfile rewritten for Rust (fleet
  convention: rust builder + debian-slim, non-root); Mustfile recipes
  (lint/test/fmt) preserved.

Verification: `cargo build --all-targets` clean; `cargo clippy
--all-targets -- -D warnings` clean; `cargo fmt --check` clean;
`cargo test` 18/18 pass (domain 9, models 5, services 4). All Python
removed (requirements.txt, setup.py, pytest.ini, alembic.ini, 35 .py)
— `banned_language_file` clears for gsbot.

Refs hyperpolymath/hypatia#252

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hyperpolymath hyperpolymath enabled auto-merge (squash) May 16, 2026 11:47
hyperpolymath and others added 3 commits May 16, 2026 13:07
Closes the one deliberate fidelity gap in the Rust/SPARK port: !stats
showed a hardcoded `0ms` where the Python bot rendered
`bot.latency * 1000`. poise's `ctx.ping()` is the gateway heartbeat
latency (serenity `Shard::latency()`), the exact equivalent — zero
only until the shard's first heartbeat ack, matching discord.py.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Every doc still described the deleted Python bot. Faithfully rewritten
from the actual source: poise/serenity + sqlx/SQLite + tracing, the
4 cargo binaries, env vars, command surface, and the pure `domain.rs`
kernel documented as the C-ABI SPARK verification seam. CLAUDE.md's
stale Python-proposing template replaced with an accurate agent guide
that states the estate Rust/SPARK standard governs and Hypatia
self-scans this repo (no Python, ever). docs/ and content/docs/ both
updated; CHANGELOG keeps the Python era as labelled history.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Root-cause sweep of the legacy `.hypatia-baseline.json` (99 -> 59). Every
real defect is fixed; every false positive is suppressed at the precise
site with a documented inline directive; only genuinely-still-present
entries remain baselined.

REAL FIXES (idiomatic Rust/SPARK: propagate with `?`, `.expect(<invariant>)`
for constant literals, explicit lock/rwlock poisoning handling — never a
bare `.unwrap()` or silent dangerous default). Each crate verified green
(build + clippy -D warnings + test):

- cipherbot: 74 `Regex::new(..).unwrap()` -> `.expect("static regex is
  valid")` across 11 analyzers; completed the non-compiling `hashing.rs`
  stub; policy.rs clippy.
- echidnabot: adapters {bitbucket,github,gitlab} clone-path + response
  parsing now propagate via `?`/`ok_or_else` (were `.unwrap()` / silent
  wrong defaults); stale test port assertion corrected at source.
- finishingbot: analyzer regexes already `?`/`.ok()?`/`.expect()`; fixed
  pre-existing in-crate clippy blockers (default_constructed_unit_structs).
- glambot: 3 constant accessibility regexes -> `.expect(..)`.
- seambot: critical `count_seams(..).unwrap_or(0)` (masked a corrupt seam
  register as "0 seams, clean") -> `?` + context; rwlock anti-pattern fixed.
- sustainabot-analysis: critical `load_snapshot` `.unwrap_or(0.0)`
  (fabricated false critical health regressions) -> anyhow context
  propagation; `compute_velocity` bounds `.expect(..)`.
- the-hotchocolabot: mock Mutex `.lock().unwrap()` -> poisoning-safe
  `.unwrap_or_else(|e| e.into_inner())`; unwrap_without_check -> `.expect`;
  resolved pre-existing crate breakage so it builds/tests green (safety-
  relevant EuroBot hot-chocolate robot — robustness matters even in mocks).
- shared-context: 15 bench `.unwrap()` -> `.expect("bench setup: ..")`.

FALSE POSITIVES — suppressed with file-level `hypatia: allow` directives
naming the rule and the reason (fix > inline > ignore > baseline):

- 9 security_errors/secret_detected: cipherbot config.rs/infra.rs are
  secret-DETECTION analyzers (their pattern literals are not credentials);
  echidnabot {toml,example.toml} + docs and sustainabot DEPLOY.md /
  GITHUB_APP_SETUP.md are documentation placeholders; scripts/
  fix-{hardcoded-secrets,secret-to-env}.sh are remediation tools whose
  illustration strings are the patterns they rewrite.
- 2 code_safety/shell_download_then_run: scripts/fix-{eval-to-safe,
  heredoc-install}.sh are remediation tools that necessarily contain the
  curl|bash/eval patterns they search for and annotate.

RESOLVED AT SOURCE:

- root_hygiene/banned docker-compose.yml: renamed `docker-compose.yml` ->
  `compose.yml` (compose-spec canonical; podman-compose compatible) and
  pointed both build refs at the existing `Containerfile`s (the referenced
  `dashboard/Dockerfile` / `shared-context/fleet-cli/Dockerfile` did not
  exist — a real broken-build bug); updated tests/e2e.sh. Aligns with the
  estate Docker-policy change (Podman/Containerfile highly preferred;
  hypatia PR hyperpolymath/hypatia#255).

REMAIN BASELINED (legitimately, with rationale):

- 35 cicd_rules/banned_language_file: gsbot Python — still present on
  `main`; eliminated by the Rust/SPARK port PR #145.
  Baseline reduction tracked there (item C), not here.
- 22 migration_rules/deprecated_api + 2 code_safety/obj_magic: all
  `bots/sustainabot/bot-integration/**/*.res` — ReScript is hands-off for
  bulk ops per estate policy; these are a deliberate, documented policy
  baseline, not unaddressed negligence.

Refs hyperpolymath/hypatia#252

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath and others added 4 commits May 16, 2026 14:44
- rsr-antipattern.yml: remove an orphaned dead second copy of the
  TypeScript-check program (lines after the first heredoc's PYEOF had
  no python3 opener, so bash executed 'BUILTIN_GLOBS = [' -> exit 127).
  The first step is complete and passes; the duplicate was a botched
  prior edit. Fails identically on main (pre-existing, not gsbot-port).
- secret-scanner.yml: trufflehog action already passes --fail; the
  extra_args also passed --fail -> 'flag fail cannot be repeated'.
  Drop the duplicate, keep --only-verified. Pre-existing on main.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…145/#146)

Brings the full resolve-at-source sweep (8-crate idiomatic Rust fixes,
11 false-positive inline hypatia directives, docker-compose.yml ->
compose.yml with real Containerfile refs) onto the gsbot Rust/SPARK
port branch so #145 lands fully green in one piece. Baseline is
regenerated post-merge for the post-port reality (Python eliminated).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…food-gate

Closes the remaining #145 CI blockers (all pre-existing estate-wide, not
introduced by the gsbot port — dogfood-gate fails identically on main):

- .hypatia-baseline.json regenerated for the post-port reality: Python is
  eliminated (35 banned_language_file entries dropped — files no longer
  exist), every real defect is fixed and every false positive is
  suppressed via inline directives (merged from the resolve-at-source
  sweep), so the baseline is now exactly the 24 deliberately-retained
  ReScript bot-integration entries (22 migration_rules/deprecated_api +
  2 code_safety/obj_magic; ReScript is hands-off per estate policy).
  This is item C, folded into #145.
- A2ML: 6 `.a2ml` manifests lacked the validator's required identity
  field (agent-id|name|project). Added a meaningful identity key to each
  (CICD-PATTERNS, CLADE, anchors/ANCHOR, agent_instructions/{coverage,
  debt,methodology}); verified 0 identity errors against the upstream
  hyperpolymath/a2ml-validate-action logic.
- K9: deploy-bot-fleet.k9.ncl used the flat pedigree shape with no name;
  added `pedigree.name = "deploy-bot-fleet"` (validator accepts
  pedigree.name). Verified 0 errors with the upstream
  hyperpolymath/k9-validate-action (strict:false, as the workflow runs).

The gsbot Rust/SPARK port itself introduces no new critical/high Hypatia
findings (0 `.unwrap()`, no unsafe/panic!/secret literals; `unwrap_or`
uses are benign config defaults faithful to the Python original).

Refs hyperpolymath/hypatia#252

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reproduced all three remaining #145 failures against the EXACT
CI-pinned validators and fixed at source:

- Hypatia gate (.github/workflows/hypatia-scan.yml): the matcher
  projected findings as a 5-tuple including `action` and did exact
  object equality, but its own contract comment says identity is the
  4-tuple {severity,rule_module,type,file}. `action` is advisory,
  varies by run/strategy, and made every baseline entry fail to match
  (all 34 deliberately-baselined ReScript findings reported "new").
  Dropped `action` from the projection and the regen hint so the
  documented 4-tuple is used; the 24-entry ReScript baseline now
  matches (Router.res ×3 etc. all collapse to one baseline entry).

- A2ML (13 errors): the CI action is pinned to b2f28c39, an older,
  stricter validator than `main` (its is_manifest only exempts
  *AI-MANIFEST*; 6a2 typed manifests + contractiles are NOT exempt —
  why the earlier main-based simulation was wrong). Added a top-level
  `name` identity field to the 13 genuinely-failing files
  (.machine_readable/6a2/{AGENTIC,META,NEUROSYM,PLAYBOOK},
  contractiles dust/trust/intend/must, robot-repo-automaton/6a2/*).

- K9 (6 errors): the pinned validator (f985acb6) has a brace-tracking
  quirk — it doesn't count the `{` on the `pedigree =` line, so the
  first nested `}` ends pedigree scope prematurely and a
  `pedigree.metadata.name` is seen as outside pedigree. Added `name`
  as the FIRST pedigree field (before any nested block) to the 6
  robot-repo-automaton k9 templates/examples.

Verified locally with the byte-exact CI-pinned validator scripts
(INPUT_STRICT=false, GITHUB_OUTPUT set): both now exit 0, Errors: 0.
antipattern-check and trufflehog already pass from the prior commit.

Refs hyperpolymath/hypatia#252

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 100 issues detected

Severity Count
🔴 Critical 0
🟠 High 34
🟡 Medium 66
View findings
[
  {
    "reason": "Obj.magic bypassing type safety (2 occurrences, CWE-704)",
    "type": "obj_magic",
    "file": "/home/runner/work/gitbot-fleet/gitbot-fleet/bots/sustainabot/bot-integration/src/Analysis.res",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "high"
  },
  {
    "reason": "Obj.magic bypassing type safety (2 occurrences, CWE-704)",
    "type": "obj_magic",
    "file": "/home/runner/work/gitbot-fleet/gitbot-fleet/bots/sustainabot/bot-integration/lib/ocaml/Analysis.res",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "high"
  },
  {
    "reason": "expect() in hot path (1 occurrences, CWE-754)",
    "type": "expect_in_hot_path",
    "file": "/home/runner/work/gitbot-fleet/gitbot-fleet/bots/gsbot/src/services.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "medium"
  },
  {
    "reason": "expect() in hot path (3 occurrences, CWE-754)",
    "type": "expect_in_hot_path",
    "file": "/home/runner/work/gitbot-fleet/gitbot-fleet/bots/glambot/src/analyzers/accessibility.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "medium"
  },
  {
    "reason": "expect() in hot path (3 occurrences, CWE-754)",
    "type": "expect_in_hot_path",
    "file": "/home/runner/work/gitbot-fleet/gitbot-fleet/bots/finishingbot/src/analyzers/claims.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "medium"
  },
  {
    "reason": "expect() in hot path (1 occurrences, CWE-754)",
    "type": "expect_in_hot_path",
    "file": "/home/runner/work/gitbot-fleet/gitbot-fleet/bots/finishingbot/src/analyzers/license.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "medium"
  },
  {
    "reason": "expect() in hot path (1 occurrences, CWE-754)",
    "type": "expect_in_hot_path",
    "file": "/home/runner/work/gitbot-fleet/gitbot-fleet/bots/accessibilitybot/src/analyzers/aria.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "medium"
  },
  {
    "reason": "expect() in hot path (5 occurrences, CWE-754)",
    "type": "expect_in_hot_path",
    "file": "/home/runner/work/gitbot-fleet/gitbot-fleet/bots/accessibilitybot/src/analyzers/forms.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "medium"
  },
  {
    "reason": "expect() in hot path (4 occurrences, CWE-754)",
    "type": "expect_in_hot_path",
    "file": "/home/runner/work/gitbot-fleet/gitbot-fleet/bots/accessibilitybot/src/analyzers/media.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "medium"
  },
  {
    "reason": "expect() in hot path (2 occurrences, CWE-754)",
    "type": "expect_in_hot_path",
    "file": "/home/runner/work/gitbot-fleet/gitbot-fleet/bots/accessibilitybot/src/analyzers/language.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@hyperpolymath hyperpolymath merged commit e366109 into main May 16, 2026
28 checks passed
@hyperpolymath hyperpolymath deleted the feat/gsbot-rust-spark-port branch May 16, 2026 14:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant