Skip to content

Commit e034d8b

Browse files
docs(echidnabot): document standalone↔fleet two-purpose split (refs hyperpolymath/echidnabot#51) (#243)
## Summary Documents the **two-purpose split** between this fleet copy (`bots/echidnabot/`) and the standalone repo at `hyperpolymath/echidnabot`. Resolves the file-class question raised by `hyperpolymath/echidnabot#51` (109-file divergence). This tree is canonical for the **deployed production bot** (exact-pinned deps, shared-context co-deployment with sibling bots, `.affine` migration in flight). The standalone repo is canonical for the **SDK / library / reference implementation** (relaxed dep pins, full development surface). ## Changes - New `bots/echidnabot/CANONICAL_SOURCE.md`: purpose / sibling / file-class table / sync policy / contributor decision tree (identical to standalone-side modulo perspective). - `bots/echidnabot/README.adoc` gains one-line `NOTE:` admonition near the top linking to `CANONICAL_SOURCE.md`. ## File-class summary (full table in `CANONICAL_SOURCE.md`) - **standalone → fleet** (most things): `src/**`, ABI, feedback, llm, modes/directives, tests matrix, fuzz targets, packaging, hooks, docs, examples (non-`.affine`), config schema. - **fleet → standalone** (few, this tree owns): `src/trust/migration_scanner.rs` (when API stabilises), `tests/webhook_e2e_test.rs` (recommended promotion), `examples/*.affine` (when `affinescript#56` lands SafeDOM bindings). - **independent**: `.claude/`, `.github/`, `proofs/`, `ffi/`, `contractiles/`, `scripts/governance/`, `0-AI-MANIFEST.a2ml`, `.clusterfuzzlite/`, `RSR_OUTLINE.adoc` are standalone-only; `scripts/batch_driver.sh` is fleet-only; `Cargo.lock` each tree owns its own. ## Sync policy **Manual cherry-pick + quarterly diff sweep.** No automation, no standards-repo workflow, no submodule. The owner runs `diff -rq` periodically and either cherry-picks, updates the table to record intentional divergence, or files a follow-up issue. ## Sibling PR Filed in parallel at `hyperpolymath/echidnabot` with identical content modulo perspective (that PR closes #51; this one references it). ## Test plan - [x] CANONICAL_SOURCE.md renders on GitHub (markdown). - [x] README.adoc admonition renders correctly (AsciiDoc `NOTE:`). - [x] GPG-signed commit (key 4A03639C1EB1F86C7F0C97A91835A14A2867091E). - [ ] Auto-merge SQUASH armed; expect green CI. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent c80fb49 commit e034d8b

2 files changed

Lines changed: 186 additions & 0 deletions

File tree

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
<!-- SPDX-License-Identifier: MPL-2.0 -->
2+
<!-- Copyright (c) 2025-2026 Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk> -->
3+
4+
# Canonical Source Map — echidnabot (fleet copy)
5+
6+
> **You are reading the FLEET tree perspective.** The sibling perspective
7+
> lives at [`hyperpolymath/echidnabot/CANONICAL_SOURCE.md`](https://github.com/hyperpolymath/echidnabot/blob/main/CANONICAL_SOURCE.md)
8+
> and has identical structure with the two roles swapped.
9+
10+
Echidnabot exists in **two trees** by design. Each tree has a different
11+
**purpose**; neither is a stale copy of the other. This document resolves the
12+
seam (issue [`hyperpolymath/echidnabot#51`](https://github.com/hyperpolymath/echidnabot/issues/51)).
13+
14+
---
15+
16+
## 1. Purpose — this tree (`hyperpolymath/gitbot-fleet/bots/echidnabot/`)
17+
18+
The **fleet copy** is the **deployed production bot**:
19+
20+
- Co-deployed with sibling bots (`accessibilitybot`, `finishingbot`,
21+
`glambot`, `panicbot`, `rhodibot`, `seambot`, etc.) under
22+
`gitbot-fleet/bots/`.
23+
- Shares `gitbot-fleet/shared-context/` for cross-bot coordination
24+
(Dependabot watches each bot independently — see
25+
`dependabot/cargo/bots/echidnabot/*` branches).
26+
- **Exact-pinned deps** (e.g. `tokio = "1.52.3"`, `axum = "0.8.9"`,
27+
`serde = "1.0.228"`) — production lockfile alignment, no version drift
28+
between deploy cycles.
29+
- Slimmer development surface: no `.claude/`, no per-bot `.github/`
30+
(fleet-level governance lives in `gitbot-fleet/.github/`), no
31+
`EXPLAINME.adoc`, single fuzz target.
32+
- Carries **production-only modules** that may or may not flow back to the
33+
SDK: `src/trust/migration_scanner.rs`, `tests/webhook_e2e_test.rs`,
34+
`examples/SafeDOMExample.affine` (estate `.affine` migration in flight).
35+
36+
## 2. Sibling — `hyperpolymath/echidnabot` (standalone)
37+
38+
The **standalone repository** is the **SDK / library / reference
39+
implementation**:
40+
41+
- Tagged releases, semver versioning.
42+
- Buildable as a library crate (`echidnabot` on crates.io eventually) and as
43+
a reference binary.
44+
- **Relaxed dependency pins** (e.g. `tokio = "1"`, `axum = "0.8"`,
45+
`serde = "1"`) — version *ranges*, not exact versions. Downstream consumers
46+
pick their own pinned lockfile.
47+
- Carries the **full development surface**: `.claude/`, `.github/` (issue
48+
templates, workflows), `EXPLAINME.adoc`, `RSR_OUTLINE.adoc`, `proofs/`,
49+
`ffi/` (Idris2 ABI bindings), `contractiles/`, `.clusterfuzzlite/`,
50+
governance scripts (`scripts/governance/`), full fuzz target set
51+
(`fuzz_config.rs` + `fuzz_hmac.rs` + `fuzz_webhook_json.rs`), full test
52+
matrix (`integration_tests.rs` + `lifecycle.rs` + `property_tests.rs` +
53+
`seam_test.rs` + `smoke.rs` + `regressions/`).
54+
- Library-shaped src tree: `src/abi/`, `src/feedback/`, `src/llm.rs`,
55+
`src/api/rate_limit.rs`, `src/modes/directives.rs` — features that exist
56+
there are the **forward edge** of the codebase.
57+
58+
---
59+
60+
## 3. File classes — who is canonical for what
61+
62+
| File glob | Canonical | Direction | Rationale |
63+
|---|---|---|---|
64+
| `src/**/*.rs` (library + bot code) | **standalone** | standalone → fleet | Library/SDK is the forward edge. Fleet consumes a snapshot. |
65+
| `src/abi/**` | **standalone** | standalone → fleet (when fleet wants ABI surface) | ABI namespace is owner-managed in standalone; fleet does not need it for deploy. See memory note `feedback_echidna_src_abi_namespace_intentional`. |
66+
| `src/trust/migration_scanner.rs` | **fleet** | fleet → standalone (when promoted) | Production-driven feature; promote to standalone when the API stabilises. |
67+
| `src/feedback/**`, `src/llm.rs` | **standalone** | standalone → fleet (on demand) | Forward-edge research surface (Package 7b double-loop, BoJ-mediated LLM); fleet adopts when production-ready. |
68+
| `src/api/rate_limit.rs` | **standalone** | standalone → fleet | Hardening landed in standalone first; fleet should adopt for production. **See drift note below.** |
69+
| `src/modes/directives.rs` | **standalone** | standalone → fleet | Mode-selection directives are SDK surface. |
70+
| `Cargo.toml` (package metadata) | **shared** | bidirectional — diverge by design | Standalone keeps relaxed ranges; fleet keeps exact pins. Authors string + crate metadata sync periodically. |
71+
| `Cargo.lock` | **each tree owns its own** | n/a | Lockfiles are deployment artefacts; standalone's reflects relaxed-range resolution, fleet's reflects pinned-version resolution. |
72+
| `tests/integration_tests.rs`, `tests/lifecycle.rs`, `tests/property_tests.rs`, `tests/seam_test.rs`, `tests/smoke.rs`, `tests/regressions/**` | **standalone** | standalone → fleet (on demand) | Full test matrix lives in standalone; fleet runs a subset in production CI. |
73+
| `tests/webhook_e2e_test.rs` | **fleet** | fleet → standalone (recommended) | End-to-end webhook test was added during fleet deployment hardening; should be promoted back to standalone. |
74+
| `fuzz/fuzz_targets/fuzz_hmac.rs`, `fuzz_webhook_json.rs` | **standalone** | standalone → fleet (on demand) | Fuzz target expansion lives in standalone (also `.clusterfuzzlite/`). |
75+
| `examples/*.affine` (e.g. `SafeDOMExample.affine`) | **fleet** | fleet → standalone (on `.affine` migration) | Estate `.affine` migration touched the fleet copy first; will reach standalone when the SafeDOM stdlib lands (`affinescript#56`). |
76+
| `examples/*.json`, `examples/*.ts`, `examples/*.rescript` | **standalone** | standalone → fleet | Reference examples for SDK users. |
77+
| `echidnabot.example.toml`, `echidnabot.toml` | **standalone** | standalone → fleet | Configuration *schema* is SDK surface; fleet should mirror schema and only override defaults. |
78+
| `Containerfile`, `flake.nix`, `guix.scm` | **standalone** | standalone → fleet | Reproducible-build manifests are SDK surface. Fleet may override base image for deploy. |
79+
| `packaging/**` (debian/, rpm/, arch/, aur/, chocolatey/, macports/, scoop/) | **standalone** | standalone → fleet (when versions bump) | Distribution packaging is release-process artefact. |
80+
| `hooks/**` (git hooks: SPDX, SHA-pins, CodeQL, permissions, tsjs-blocker) | **standalone** | standalone → fleet | Governance hooks; standalone is the source of truth. |
81+
| `README.adoc`, `README.md`, `CHANGELOG.md` (vs `CHANGELOG.adoc`), `ROADMAP.adoc`, `CITATION.cff`, `codemeta.json`, `PALIMPSEST.adoc` | **standalone** | standalone → fleet | Doc canon. The `.md` vs `.adoc` CHANGELOG split is a long-standing inconsistency; standalone uses both. |
82+
| `EXPLAINME.adoc`, `MAINTAINERS.adoc`, `RSR_OUTLINE.adoc`, `RSR_COMPLIANCE.adoc`, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md` | **standalone** | standalone → fleet (where applicable) | Project-level docs; some (e.g. `RSR_OUTLINE.adoc`) are standalone-only because the SDK is the RSR-compliant artefact. |
83+
| `.claude/`, `.github/`, `.gitattributes`, `.gitignore`, `.editorconfig`, `.guix-channel`, `.well-known/`, `.machine_readable/`, `0-AI-MANIFEST.a2ml` | **standalone-only** | n/a | Per-repo metadata. Fleet-level equivalents live at `gitbot-fleet/.github/` and `gitbot-fleet/.claude/`. |
84+
| `proofs/`, `ffi/`, `contractiles/`, `scripts/governance/` | **standalone-only** | n/a | Research / formal-methods / governance surface that does not belong in a deployed bot. |
85+
| `scripts/batch_driver.sh` | **fleet-only** | n/a | Fleet-orchestration helper; out of scope for SDK. |
86+
| `wiki/Home.md`, `docs/content/api.md`, `docs/templates/default.html` | **standalone** | standalone → fleet (rarely) | Documentation canon. |
87+
| `docs/tech-debt-2026-05-26.md` | **standalone-only** | n/a | Tech-debt log; SDK-internal planning artefact. |
88+
| `BRANDING.md`, `TESTING-REPORT.adoc`, `TESTING-REPORT.scm`, `SESSION_SUMMARY_2026-01-29.md`, `SONNET-TASKS.md`, `RELEASE_CHECKLIST.md`, `Mustfile`, `Containerfile` | **standalone** | standalone → fleet | Shared release/branding/testing surface. |
89+
90+
---
91+
92+
## 4. Sync policy
93+
94+
**Manual cherry-pick with quarterly diff sweep.** No automation.
95+
96+
- **Default flow:** changes land in the canonical tree (per the table above)
97+
via PR. The owner cherry-picks to the sibling when ready, in a separate PR
98+
with a `Refs hyperpolymath/<other-repo>#<PR>` line.
99+
- **Quarterly diff sweep:** the owner runs `diff -rq` between the two trees,
100+
classifies new deltas against the table above, and either (a) cherry-picks
101+
to align, (b) updates the table here to record intentional divergence, or
102+
(c) files a follow-up issue if the delta needs design work.
103+
- **CI gating:** none today. Adding a "no undocumented divergence" check
104+
would require standards-repo work and is explicitly **out of scope**
105+
(issue #51 picked the documentation-first option).
106+
107+
### What this policy explicitly does NOT do
108+
109+
- No auto-mirror / no sync bot / no submodule / no git subtree.
110+
- No "regenerate fleet from standalone on every release" script.
111+
- No standards-repo workflow.
112+
113+
If automation becomes necessary later, a one-off `gitbot-fleet/scripts/sync-bot.sh`
114+
(per-bot, not estate-wide) would be the natural place — but the owner has
115+
deliberately deferred this until the divergence pattern stabilises.
116+
117+
---
118+
119+
## 5. When to PR which — decision tree for contributors
120+
121+
```
122+
What kind of change?
123+
124+
├── New library API / new src module / SDK surface
125+
│ └─→ PR to STANDALONE (hyperpolymath/echidnabot). Owner cherry-picks
126+
│ to fleet when ready.
127+
128+
├── Bug fix in shared src/**/*.rs
129+
│ └─→ PR to STANDALONE. Fix flows fleet-ward at next sweep.
130+
│ (If the bug is production-only and you have a reproduction,
131+
│ a fleet-side hotfix PR is acceptable; cross-reference standalone.)
132+
133+
├── Production hardening (rate limit, retry, observability)
134+
│ ├── If it's a new SDK feature → STANDALONE first, fleet adopts.
135+
│ └── If it's deploy-specific (k8s tuning, fleet routing) → FLEET only
136+
│ (this repo).
137+
138+
├── Dependency bump
139+
│ ├── Patch bump (security) → BOTH trees, simultaneously.
140+
│ ├── Minor/major in standalone → STANDALONE only (relaxed ranges
141+
│ │ absorb it). Fleet updates exact-pin when ready.
142+
│ └── Dependabot-driven exact-pin bump → FLEET only (this is what
143+
│ Dependabot does; standalone's relaxed pins don't need it).
144+
145+
├── `.affine` migration / AffineScript example
146+
│ └─→ FLEET (where the migration is in flight). Promote to STANDALONE
147+
│ once `affinescript#56` lands the SafeDOM stdlib bindings.
148+
149+
├── Documentation / README / CHANGELOG / branding
150+
│ └─→ STANDALONE. Fleet mirrors at next sweep.
151+
152+
├── Governance: SPDX hooks, SHA-pin validators, security policy
153+
│ └─→ STANDALONE. Fleet adopts the hook updates at next sweep.
154+
│ (Fleet-level governance lives separately at gitbot-fleet/.github/.)
155+
156+
├── Deployment config (Containerfile base image, k8s, compose)
157+
│ └─→ FLEET. The standalone Containerfile is a reference; the fleet
158+
│ Containerfile is the deployed one.
159+
160+
└── New issue templates, .claude/ config, workflow files
161+
└─→ STANDALONE for repo-specific. Fleet uses gitbot-fleet/.github/
162+
and gitbot-fleet/.claude/ for fleet-wide.
163+
```
164+
165+
### Quick reference
166+
167+
| You are doing... | PR target |
168+
|---|---|
169+
| Adding a Rust module under `src/` | **standalone** |
170+
| Fixing a bug in `src/` shared by both | **standalone** |
171+
| Adding a `.affine` example | **fleet** (this repo) |
172+
| Updating production deploy config | **fleet** (this repo) |
173+
| Promoting a fleet hotfix back to SDK | **standalone** (then close fleet hotfix) |
174+
| Security patch bump on a transitive dep | **both** |
175+
| Tagging a release | **standalone** |
176+
| Rolling out a release to production | **fleet** (this repo) |
177+
178+
---
179+
180+
## See also
181+
182+
- Issue [`hyperpolymath/echidnabot#51`](https://github.com/hyperpolymath/echidnabot/issues/51) — diagnosis of the 109-file divergence.
183+
- Memory note `feedback_echidna_license_docs_mpl_intentional` — docs stay MPL-2.0 despite AGPL `LICENSE`; do not reconcile.
184+
- Memory note `feedback_echidna_src_abi_namespace_intentional``src/abi/` dual-tree layout is owner-managed.

bots/echidnabot/README.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ image:https://img.shields.io/github/v/release/hyperpolymath/echidnabot?include_p
1313

1414
_Formal verification CI bot that orchestrates ECHIDNA for automatic theorem proof verification on every push._
1515

16+
NOTE: Echidnabot exists in two trees by design — this **fleet copy** (deployed production bot) and the **standalone** repo at `hyperpolymath/echidnabot` (SDK / library / reference implementation). See link:CANONICAL_SOURCE.md[CANONICAL_SOURCE.md] for the file-class canonical map and contributor decision tree.
17+
1618
toc::[]
1719

1820
== Overview

0 commit comments

Comments
 (0)