Skip to content

Commit 87e3665

Browse files
committed
chore(fleet): deletion-guard PR-body marker, BotId::Oikosbot, rhodibot link fix
Follow-ups after the sustainabot→oikosbot extraction (#297). Matter 1 — Repo Integrity Guard: - Implement the documented-but-missing escape hatch: the guard now honours `[mass-delete-ok]` in the PR title/body (via env + grep -F, injection-safe), not only in commit messages. Accidental stale-base gut-merges are still blocked; only explicitly-marked intentional removals pass. The guard is NOT weakened (threshold and critical-file checks unchanged). - CLAUDE.md: new invariant #7 documenting the tripwire + marker convention. Matter 2b — fix rhodibot's broken sibling link: - `bots/rhodibot/README.adoc` linked the non-existent `hyperpolymath/sustainabot` repo. Repoint to the in-repo slot `bots/sustainabot/` and clarify it is the reserved fleet slot, NOT the standalone OikosBot (avoids re-conflation). Matter 2c (fleet side) — distinct fleet identity for OikosBot: - Add `BotId::Oikosbot` to shared-context so the optional `oikosbot-fleet` bridge can publish under its own identity instead of borrowing `BotId::Sustainabot`. Modelled on `Custom`: it is deliberately excluded from `BotId::all()`, so the 11-bot roster and coordinator dispatch are unchanged — OikosBot is an external publisher, not a managed roster bot. - shared-context: 84 tests pass. Note: robot-repo-automaton has a pre-existing, unrelated build error in src/detector.rs (regex `is_match` wants &str, gets &Vec<u8>); out of scope here. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RozeeLxpJsd3WWFngaZWz3
1 parent ded43d0 commit 87e3665

4 files changed

Lines changed: 41 additions & 6 deletions

File tree

.claude/CLAUDE.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ Control (report < 0.85) → Human review required
9292
full copy of OikosBot once lived in `bots/sustainabot/`; it was extracted to
9393
`hyperpolymath/oikosbot` and the slot reset to a placeholder. `oikos` is a
9494
separate DSL (`hyperpolymath/oikos-economics-accounting-dsl`).
95+
7. **Mark intentional mass-deletions.** The Repo Integrity Guard
96+
(`.github/workflows/repo-integrity-guard.yml`) fails any change that deletes
97+
more than `MAX_DELETIONS` (50) tracked files vs. base — it exists because
98+
`main` was once silently gutted from 1777 files to 2. For a *deliberate*
99+
large removal, include the literal marker `[mass-delete-ok]` in a commit
100+
message in the range, **or** in the PR title/body. Never weaken the guard or
101+
trim its critical-file list just to get a change through.
95102

96103
## Repo health
97104

.github/workflows/repo-integrity-guard.yml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ jobs:
6565
BASE_SHA: ${{ github.event.pull_request.base.sha }}
6666
BEFORE_SHA: ${{ github.event.before }}
6767
HEAD_SHA: ${{ github.sha }}
68+
# Untrusted PR text — consumed only via env + grep -F (never eval'd).
69+
PR_TITLE: ${{ github.event.pull_request.title }}
70+
PR_BODY: ${{ github.event.pull_request.body }}
6871
run: |
6972
set -euo pipefail
7073
@@ -86,14 +89,18 @@ jobs:
8689
echo "Deleted tracked files vs $base: $deleted (limit ${MAX_DELETIONS})"
8790
8891
# Intentional large removals: put [mass-delete-ok] in any commit
89-
# message in the range (or the PR title/body).
92+
# message in the range, or in the PR title/body.
9093
if git log --format='%B' "${base}..${HEAD_SHA}" | grep -qF '[mass-delete-ok]'; then
91-
echo "Override marker [mass-delete-ok] present — tripwire bypassed by intent."
94+
echo "Override marker [mass-delete-ok] present in a commit message — tripwire bypassed by intent."
95+
exit 0
96+
fi
97+
if printf '%s\n%s\n' "${PR_TITLE:-}" "${PR_BODY:-}" | grep -qF '[mass-delete-ok]'; then
98+
echo "Override marker [mass-delete-ok] present in the PR title/body — tripwire bypassed by intent."
9299
exit 0
93100
fi
94101
95102
if [ "$deleted" -gt "${MAX_DELETIONS}" ]; then
96-
echo "::error::$deleted files deleted vs base (limit ${MAX_DELETIONS}). If intentional, add [mass-delete-ok] to a commit message in this change. Refusing to let main be silently gutted again."
103+
echo "::error::$deleted files deleted vs base (limit ${MAX_DELETIONS}). If intentional, add [mass-delete-ok] to a commit message OR the PR title/body. Refusing to let main be silently gutted again."
97104
git diff --diff-filter=D --name-only "$base" "$HEAD_SHA" | head -40 | sed 's/^/ deleted: /'
98105
exit 1
99106
fi

bots/rhodibot/README.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,9 +287,9 @@ Rhodibot is a Tier 1 Verifier in the gitbot-fleet hierarchy:
287287
| Tier 1 Verifier
288288
| Sibling (mathematical/formal verification)
289289

290-
| https://github.com/hyperpolymath/sustainabot[sustainabot]
290+
| link:../sustainabot/README.adoc[sustainabot]
291291
| Tier 1 Verifier
292-
| Sibling (ecological/economic standards)
292+
| Sibling (ecological/economic standards) — reserved fleet slot, _not_ the standalone OikosBot (`hyperpolymath/oikosbot`)
293293

294294
| glambot
295295
| Tier 2

shared-context/src/bot.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ pub enum BotId {
3030
Cipherbot,
3131
/// Targeted audit bot wrapping panic-attack static analysis
3232
Panicbot,
33+
/// External ecological/economic code-analysis App (OikosBot,
34+
/// `hyperpolymath/oikosbot`) that publishes findings via the optional
35+
/// `oikosbot-fleet` bridge. NOT the reserved `Sustainabot` fleet slot and
36+
/// NOT a fleet-managed roster bot — like `Custom`, it is deliberately
37+
/// excluded from `all()` so the coordinator never dispatches it.
38+
Oikosbot,
3339
/// Custom/external bot
3440
Custom(u32),
3541
}
@@ -48,6 +54,7 @@ impl fmt::Display for BotId {
4854
BotId::Accessibilitybot => write!(f, "accessibilitybot"),
4955
BotId::Cipherbot => write!(f, "cipherbot"),
5056
BotId::Panicbot => write!(f, "panicbot"),
57+
BotId::Oikosbot => write!(f, "oikosbot"),
5158
BotId::Custom(id) => write!(f, "custom-{}", id),
5259
}
5360
}
@@ -57,7 +64,7 @@ impl BotId {
5764
/// Get the tier this bot belongs to
5865
pub fn tier(&self) -> Tier {
5966
match self {
60-
BotId::Rhodibot | BotId::Echidnabot | BotId::Sustainabot | BotId::Panicbot => Tier::Verifier,
67+
BotId::Rhodibot | BotId::Echidnabot | BotId::Sustainabot | BotId::Oikosbot | BotId::Panicbot => Tier::Verifier,
6168
BotId::Glambot | BotId::Seambot | BotId::Finishbot | BotId::Accessibilitybot => Tier::Finisher,
6269
BotId::Cipherbot => Tier::Specialist,
6370
BotId::RobotRepoAutomaton => Tier::Executor,
@@ -99,6 +106,7 @@ impl BotId {
99106
"accessibilitybot" | "accessibility-bot" => Some(BotId::Accessibilitybot),
100107
"cipherbot" | "cipher-bot" => Some(BotId::Cipherbot),
101108
"panicbot" | "panic-bot" => Some(BotId::Panicbot),
109+
"oikosbot" | "oikos-bot" => Some(BotId::Oikosbot),
102110
_ => None,
103111
}
104112
}
@@ -354,6 +362,19 @@ impl BotInfo {
354362
can_fix: false,
355363
depends_on: vec![BotId::Rhodibot],
356364
},
365+
BotId::Oikosbot => Self {
366+
id,
367+
name: "OikosBot".to_string(),
368+
description: "External ecological/economic code-analysis App (hyperpolymath/oikosbot) that publishes via the optional oikosbot-fleet bridge — distinct from the reserved Sustainabot slot".to_string(),
369+
version: "0.1.0".to_string(),
370+
categories: vec![
371+
"sustainability".to_string(),
372+
"ecological".to_string(),
373+
"economic".to_string(),
374+
],
375+
can_fix: false,
376+
depends_on: vec![],
377+
},
357378
BotId::Custom(_) => Self {
358379
id,
359380
name: "Custom Bot".to_string(),

0 commit comments

Comments
 (0)