Mando AGENTS.md Master Guide
A master conventions document for AI agents lives at /Volumes/bandi/coding/poc/mando/AGENTS.md — deliberately untracked (working docs never get committed per house rule; the guide itself codifies this in §10). Synthesized 2026-07-10 from 5 parallel researcher agents; fully rebuilt 2026-07-13 by 5 re-run researchers against the true origin/develop tip 92bfe1c8 (2026-07-09, v1.16.0) on a dedicated worktree at .worktrees/develop. This note records what it covers, its provenance, the round-1 corrections to prior assumptions, and the round-2 new verified facts.
For Agents
Read
AGENTS.mdat the mando repo root before writing any mando code. Its own maintenance rule: when the document and the code ondevelopdisagree, the code wins — then update the file. It is a local artifact; if missing, it was not deleted from git (it was never tracked).
What it covers (section map)
| § | Topic |
|---|---|
| 1 | Orientation: crate map + dependency direction (never invert), feature-flag matrix |
| 2 | 10 non-negotiables (generated code, error!-only logging, per-file rustfmt (all cargo fmt banned, see the 2026-07-13 field correction below), single-threaded tests, clippy gate, no unsafe/unwrap, title-only Conventional Commits, feature/BE-xxxx branches, pinned =x.y.z deps in #regions, comment-sparse code) |
| 3 | Toolchain & build (1.89.0 pin, git LFS for lib/libduckdb/**, Nexus registries, MANDO_*/adapter env prefixes) |
| 4 | Architecture: mando-lib layering (Repository → ServiceBase → dispatch → Adapter → Service → Workflow), flow engine + versioning, data model, refinery migrations |
| 5 | Rust style (house rules on top of rustfmt.toml: imports top-only StdExternalCrate, blank line before returns, inline format! args, naming/derive/async/tracing conventions) |
| 6 | The mando_core::error! system (signature pattern — see corrections below) |
| 7 | mando-bess API conventions (utoipa routing, ValidatedJson + local JsonSchema trait, token_layer, fixed middleware order, audit events, cron jobs) |
| 8 | py-mando PyO3 patterns (abi3-py38, async bridge, PyMandoError, pyo3-polars) |
| 9 | Testing ceremonies (inline #[cfg(test)], httpmock, test-case/parameterized, test-util DataFrame fixtures, in-memory DB pools) |
| 10 | Git/CI ceremonies (pre-push checklist, pipeline stages, version suffixes, MR etiquette) |
| 11 | Landmines table (verified gotchas) |
| 12 | 8 recipes: A adapter · B repository capability · C REST endpoint · D error variant · E flow version · F Rust→Python · G datapoint · H migration |
The guide has since grown past the original 12 sections: section 13 “Working method - how to think before you type”, and section 14 “Deployment - getting a build onto an environment” (added 2026-07-13, verified from optimization-universe-iac + mando .gitlab-ci.yml). Section 14 covers the two-repo deploy ceremony (mando CI publishes images; optimization-universe-iac decides what runs where), the 4-env/2-group matrix, the dev deploy steps, the feature-branch publish trick, runtime config via TF_VAR_*, and post-deploy verification. Full vault record: Mando Deployment Ceremony.
Snapshot provenance
Current: the guide reflects the true develop tip 92bfe1c8 (2026-07-09, v1.16.0). Fully rebuilt 2026-07-13 by 5 re-run researcher agents working on a dedicated worktree at .worktrees/develop. The local develop branch was fast-forwarded and now tracks origin/develop — both the v1 “guide reflects stale merge-base” caveat and the “local develop is much staler” warning are resolved (still fetch + diff against origin/develop before trusting local state; that habit remains landmine #3 in the guide).
History: v1 (2026-07-10) reflected merge-base 8bbd407e (2026-07-01, v1.15.0); its documented drift — the 4 new crates (mando-flow-step, mando-flow-step-derive, mando-bess-lib, py-mando-simulation), the flow_registry.rs wiring restructure, the v1.16.0 bump — is now folded into the guide proper, including recipe E’s wiring steps.
Rebuild process notes (for the next re-run)
agentops:researchersubagents cannot SendMessage — collect their reports as scratchpad files, or extract them from transcripts at~/.claude/projects/<project>/<session>.jsonl(take the longest assistant text). One of the five v2 researchers (style scope) died early; its scope was verified by hand instead.
Round-2 verified facts (2026-07-13)
All verified against tip 92bfe1c8 and merged into the guide.
Flow-step machinery (the Jul-08 restructure, now fully mapped)
FlowStepService(mando-flow-step/src/lib.rs) is a construction trait, NOT an execute()-style trait:type Params: ParamMeta; type Response;+ asyncfrom_config(config: &str, providers: &StepProviders).StepProviders(mando-flow-step/src/providers.rs) carriesflow_repository,data_point_registry, 6 auth providers,simulation_enabled.- 36
type_entry!step registrations inmando-bess/build.rs. - ParamMeta param structs derive exactly:
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ParamMeta)]. config/flows/manifest.yamlis the deployment catalog:setup: {version}: flows: {name}: {path, schedule_env, semaphore_group}— scheduling env vars and concurrency groups are configured in the manifest, not in code. Semaphores: capacity 1 per group.
Error redesign PARTIALLY landed (commit ae6d1098)
Landed: error.message = root cause; error.stack = source chain; error.fingerprint = "{code}|{step_path}"; ErrorWithStepStatus.logged_at_site double-log guard with new()/logged() constructors. NOT landed: error.trace, .step_context(). docs/error-handling-redesign-plan.md and doc/errors.json are NOT tracked on develop. Direction: BE-3117 Per-Flow Error Context Store.
Provenance confirmed 2026-07-13: ae6d1098 is the squash of BE-3482 MR !558 (merged 2026-07-08, 30 files, +402/-173, merge commit c2b7d401; origin branch deleted). Continuation state, the unpushed fingerprint ACTIVITY extension (code|path|activity, branch feature/BE-3482-fingerprint-activity, now 2 commits: 6f541363 + the salvaged version-fallback panic fix bc3727ba, cherry-picked from orphan 478cd993), and the ranked open deferrals live in BE-3482 Datadog Logs and APM Conformance.
py-mando-simulation split (commit 3559042d) — BREAKING
py_mando.SimulationRunner is GONE from py-mando — moved to the new py-mando-simulation package (requires Python ≥3.11, ships ddtrace, no polars/pandas). Both packages: init() runs at import (JsonFormatter + rustls ring), libduckdb preload (ctypes RTLD_GLOBAL / add_dll_directory), build.rs copies lib/libduckdb/1.4.2 into data/platlib. Second sanctioned async bridge confirmed on tip — see correction #7 (amended).
rustfmt reality
All the import-grouping/comment options in rustfmt.toml are nightly-only and silently ignored on the stable 1.89 toolchain; the tip tree is NOT fmt-clean; CI has no fmt gate — import grouping is maintained by hand.
Test coverage + CI
- New crates (
mando-flow-step,mando-flow-step-derive,mando-bess-lib, py-mando-simulation Rust side) currently have ZERO tests; py-mando-simulation has 1 Python integration test. - CI gained a separate “PyMando Simulation Linux Dev” job (pytest without
--nbval) and a simulator docker publish child pipeline.
Repo hygiene + style
- No MR/issue templates, no CODEOWNERS in the repo.
format!style on tip: positional ~3:1 over inline; inline args are the review rule for new code (don’t mass-convert).
Recurring review feedback + dictated rules (2026-07-13)
Same day as the round-2 rebuild, the guide gained a “Recurring review feedback” section distilled from mining ALL 21 of Andras’s mando MRs (!322 through !558) via read-only glab API: 108 reviewer notes, nine recurring themes (unrelated-change hygiene, unused-code deletion, failures-are-errors policy, placement, completeness before review, green pipeline + no conflicts before assigning review, rustfmt on new files, Jira sync, idioms), plus a config-direction finding (NEW config uses config::Config over Envconfig; existing adapters keep envconfig). Full evidence + the theme list with source MRs: Mando MR Review Patterns.
Andras also dictated new rules into the guide in the same session:
- Commits are title-only with NO scopes and no descriptions (the no-scope rule is reviewer-mandated, MR !322). Tightens the section-2 commit non-negotiable.
- Commit every ~3 tasks, in short form.
- Never use em dashes anywhere; the entire
AGENTS.mdwas purged of them. - Always subagent-driven development, without asking.
Field correction (2026-07-13): cargo fmt NEVER scopes
Falsified during the BE-3482 continuation work: cargo fmt -- <file> does NOT scope to the named file (it touched api_docs.rs, which was never named on the command line). The round-1 advice “scope to touched files with cargo fmt -- path/to/file.rs” in correction #3 below is superseded.
- New prescription:
rustfmt --edition 2021 <file>; every form ofcargo fmtis banned. - Propagated to
AGENTS.mdsections 2.3, 10, 13.5 and the landmines table; Mando AGENTS Guide (mirror) resynced accordingly; the fmt warning in Agent Context amended. - Full record: Tooling correction: cargo fmt does not scope.
Field landmine (2026-07-13): the RTK hook guts cargo test
Also found during the BE-3482 continuation: on RTK-hooked shells, the hook rewrites the canonical test command cargo test --all-features --release -- --test-threads=1 so that the threads flag becomes a test-name filter. Every test is filtered out and the run exits 0 in 0.00s (signature: 0 passed, N filtered out). Two gate runs were false-green this way before detection.
- Correct invocation on RTK machines:
rtk proxy cargo test --all-features --release -- --test-threads=1. - Always confirm the summed passed totals are nonzero; exit 0 alone proves nothing.
- Adjacent shell pitfall:
cargo test | grep | tail; echo $?reports tail’s exit, not cargo’s. - Recorded in
AGENTS.mdsection 10 + the landmines table; Mando AGENTS Guide (mirror) resynced. Full record: Tooling landmine: the RTK hook silently filters out the whole test suite.
Field landmine (2026-07-22): the CI test gate is --lib-only; tests/ targets rot
Found running the BE-3657 gates: .gitlab/scripts/test.sh on develop runs cargo test --all-features --release --lib -- --test-threads=1. The --lib (added with the archiver integration split, commit 7278f36a) means CI compiles and runs ONLY lib unit tests; */tests/ integration targets are never built by the pipeline (the separate “Integration Test Linux Dev” job covers only the mando-lib archiver Postgres suite) and can rot silently.
- Concrete rot:
mando-bess/tests/flight_end_to_end.rsfails to compile on develop itself (E0603: importsDataPointUpdateInfoviamando_lib::servicewhere it is only a privateuse; broken since the mando-repository crate splitb3ce27a8). A full localcargo testwithout--libhits it. - Local gates must use
--libfor CI parity:rtk proxy cargo test --all-features --release --lib -- --test-threads=1. - Propagated to
AGENTS.mdin 4 places (section 2 non-negotiable 4, the section 10 pre-push command + its RTK warning, the section 13.5 gate list) plus a new landmine row; Mando AGENTS Guide (mirror) resynced. - The flight test fix is a pending one-liner (import from
mando_core::model::datapointdirectly), to be its own change on Andras’s yes, not part of BE-3657. Full record: mando-ci-lib-only-test-gate-2026-07-22.
Key corrections to prior assumptions (round 1, 2026-07-10)
1. Generated code is TRACKED in git
mando-bess/build/generated/**.rs (domain.rs + flows/*.rs) is generated by build.rs from mando-bess/config/**.yaml + mando-codegen/templates/*.askama — but it is committed. Rule: edit the YAML/template → cargo build → commit input + regenerated output together. Never hand-edit. Same for *.out golden files in mando-codegen/test/domain/ (rustfmt ignores them). mando-codegen is a build-time generator, not a proc macro.
2. No ErrorCode derive, no mando-lib-macro crate on develop
Verified: git grep ErrorCode origin/develop → empty; no mando-lib-macro in the tree. Both exist only in .worktrees/ experiments (poc-error-extractor, BE-2023, and inside mando-flow-step-derive in the BE-1595/BE-3482 worktrees). Consequences:
error.kind(fully-qualified enum path),error.code(Enum::Variant),error.sourceare extracted at runtime by themando_core::error!macro (mando-core/src/error.rs) from the value’s Debug repr — no derive needed.- The parent
poc/CLAUDE.mdis stale: it references anErrorCodederive, amando-lib-macrocrate, and amando/CLAUDE.md— none exist on develop. - The vault note mando-lib-macro is now marked
status/outdatedwith a correction callout. - Naming collision trap: develop tip does have a crate named
mando-flow-step-derive, but it derivesParamEnum/ParamMeta(flow-step params), notErrorCode. - Never grep-and-copy from
.worktrees/as if it were develop (guide landmine).
3. CI gates: no fmt gate, clippy is the gate, single-threaded tests
- No
cargo fmtgate in CI. Never run barecargo fmt(reformats ~64 legacy files).Scope to touched files:SUPERSEDED 2026-07-13:cargo fmt -- path/to/file.rscargo fmt -- <file>does not scope either; userustfmt --edition 2021 path/to/file.rs(see the field correction above). - Lint gate:
cargo clippy --release --all-featuresclean. Workspace lints:correctness/perf/suspiciousdenied + cherry-picked denies (panic_in_result_fn,exit,print_stderr,undocumented_unsafe_blocks);unsafe_code = "deny". - Canonical test command:
cargo test --all-features --release -- --test-threads=1(.gitlab/scripts/test.sh). Single-threaded is mandatory — shared in-memory DB pools (DuckdbConnectionManager::memory()) corrupt under parallel tests. Never “fix” a flaky test by removing it.
4. doc/errors.json is an untracked generated artifact
Rustdoc-JSON–shaped error catalog; generator not in CI — likely from the poc-error-extractor worktree work. Regenerate rather than edit; do not commit unasked. Same for bench/, docs/, .ai/.
5. JWT signature validation is DISABLED
token_layer (mando-lib/src/app/route/token_layer.rs) parses the Bearer JWT with insecure_disable_signature_validation — the Extension<Option<User>> is audit metadata only, not authz. Known dev posture: do not build authorization on top of it and do not “fix” it without a ticket.
6. Flow versions are immutable once released
Never change a released vN’s YAML or generated code — breaking behavior goes to v(N+1). Canonical exemplar: manual_schedule v3. Verified flows on develop tip (mando-bess/config/flows/fi/): as_auction_update_v2, auction_v4, data_update_v2, intraday_v2, manual_schedule_v3. (Src-side wiring moved to flow_registry.rs on tip — see drift table.)
7. py-mando async bridges — two sanctioned patterns
py.allow_threads(|| {
pyo3_async_runtimes::tokio::get_runtime().block_on(async { /* .await */ })
})Amended 2026-07-13: a second sanctioned bridge is confirmed on tip — pyo3_async_runtimes::tokio::future_into_py for the *_async awaitable variants (alongside the blocking allow_threads + block_on pattern above).
Never hold the GIL across .await; never Python::with_gil inside an async block; clone Py<T> with clone_ref(py). Errors: single exception type PyMandoError; every boundary maps via the existing map_*_error fns in mando-lib/src/python/error.rs (add a new map_x_error there for new enums).
8. Toolchain 1.89.0, MSRV 1.88.0
rust-toolchain.toml pins 1.89.0 (bumped by the remotefs-smb to smb migration); rust-version = "1.88.0" is the MSRV. Parent docs saying “Rust 1.88.0” conflate the two. Workspace version on develop tip: 1.16.0 (as of 2026-07-08). Related: the CI build image base is still rust:1.88.0-bookworm and still installs samba libs, while the runtime image (debian:13.1-slim) dropped them — only ca-certificates, libc6, libssl3 + bundled libduckdb.so remain.
Related
-
Mando AGENTS Guide (mirror) - full verbatim copy of the guide, synced 2026-07-13
-
Agent Context — updated 2026-07-10 with these corrections (crate map, versions, error row)
-
Mando MR Review Patterns - the MR-mining evidence (21 MRs, 108 reviewer notes, 9 themes) behind the “Recurring review feedback” section + the 2026-07-13 dictated rules
-
Mando Deployment Ceremony - the section-14 deployment ceremony in full (two-repo deploy, env matrix, dev steps, runtime config, verification)
-
BE-3482 Datadog Logs and APM Conformance - merge verification of
ae6d1098(MR !558), the unpushed 2-commit fingerprint-activity branch (incl. the salvagedbc3727bapanic fix), ranked deferrals, and the cargo fmt + RTK test-rewrite landmine records -
mando-lib-macro — marked outdated by correction #2
-
Mando CI-CD — gates + image facts reconciled
-
Mando / mando-lib / mando-bess / py-mando
-
clippy-disallowed-macros-allow-placement-2026-06-22 — the
error!-wrapper clippy mechanics behind §6 -
BE-3117 Per-Flow Error Context Store — the error-handling redesign direction referenced in §6
-
remotefs-smb to smb migration — source of the 1.89.0 toolchain bump + samba removal