From a11537c00c38b3edf20ffbfe1e2f65e25e695dfe Mon Sep 17 00:00:00 2001 From: ruv Date: Sat, 23 May 2026 15:22:42 -0400 Subject: [PATCH] docs(branch-state): /loop + /loop-worker lessons from the 38-iter ADR-110 sprint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Iter 39 — captures the 8 concrete lessons the SOTA /loop sprint learned the hard way (cross-branch checkout incidents in iter 17-19, silent absorption of foreign-branch Cargo.toml work in iter 18 → revert in ca2059b07, fuzz-target stub gap in iter 11 → CI fail discovered in iter 38). Future /loop or /loop-worker runs against THIS repo should read these before kicking off a long autonomous sprint. Key recommendations: 1. git branch --show-current at the start of every iter 2. git diff --cached before every commit after a branch switch 3. Document sibling-region ownership in this file 4. Extract pure helpers before committing inline mutations (sync_snapshot, apply_sync_packet, fleet_role_counts patterns) 5. Cross-language wire-format pin in BOTH languages at the SAME iter 6. Helper tests > integration tests when state is heavy 7. Add fuzz stubs in the same commit as the firmware symbol they mirror (iter 38 caught c6_sync_espnow_is_valid this way) 8. Reserve irreversible checkpoints (tag, release, PR ready) for iters with surplus confidence from prior CI evidence Co-Authored-By: claude-flow --- docs/ADR-110-BRANCH-STATE.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/ADR-110-BRANCH-STATE.md b/docs/ADR-110-BRANCH-STATE.md index d2504ebe..2053f6e9 100644 --- a/docs/ADR-110-BRANCH-STATE.md +++ b/docs/ADR-110-BRANCH-STATE.md @@ -82,3 +82,16 @@ If either side of the canonical-wire-bytes pair fails alone, the OTHER decoder h - When the ADR-115 agent ships `feat/adr-115-ha-mqtt-matter` to main and ADR-110 also ships, merge `main` into `adr-110-esp32c6` (or vice versa) and re-run both test suites. The disjoint-region structure above should make the merge a no-conflict fast-forward. - When a third agent picks up either ADR, point them at this file before they start editing shared files. - If a /loop drives autonomous iterations and hits a cross-branch checkout, the recovery procedure is in iter 18's commit message (`2997165bc`) — stash on the foreign branch, `git checkout` home, replay the iter locally. + +## Lessons for `/loop` and `/loop-worker` future runs + +Captured after the 38-iter ADR-110 SOTA sprint (`/loop 5m until sota. and ultra optmized`): + +1. **Always verify the current branch at the start of each iter** — when a /loop fires every 5 minutes and another agent is active on a sibling branch, the working tree can flip without your action. Run `git branch --show-current` as the first line of every iter; if it isn't what you expect, stash and switch back BEFORE editing. We burned ~30 min in iter 17-19 recovering from two silent branch flips. +2. **Don't `git add ` blindly after a branch switch** — the file may have inherited changes from the foreign branch (uncommitted work that came along on checkout). Always `git diff --cached` before `git commit`. We accidentally absorbed ADR-115's Cargo.toml/cli.rs work into ADR-110's iter-18 commit; required a follow-up revert commit (`ca2059b07`) and stash dance. +3. **Sibling-region edits in shared files** — when two branches both touch `v2/crates/wifi-densepose-sensing-server/Cargo.toml` or `src/main.rs`, agree on which `[section]` or struct each owns. Document the regions in this file (see Known overlap points). Merges then stay clean line-merge fast-forwards instead of needing conflict resolution. +4. **Extract pure helpers before committing inline mutations** — iter 30 (`sync_snapshot`), iter 32 (`apply_sync_packet`), iter 37 (`fleet_role_counts`) all converted inline state-changes into named, free, testable functions. Each saved 4+ inline duplications and let the helper be tested without spinning up axum / tokio. Bake this into every iter's plan: *"what's the smallest helper I can extract here?"* +5. **Cross-language wire-format gates** — when shipping a protocol decoder in both Python and Rust, pin the SAME canonical byte string in BOTH test suites (iter 21 pattern). One side drifting fires exactly one named test on exactly the drifted decoder. Don't wait until "later" — add the pin in the iter that ships the second language. +6. **Helper tests > integration tests when state is heavy** — `AppStateInner` has too many fields to construct in a test. Instead of fighting it, extract per-field logic into pure helpers (iter 30 sync_snapshot pattern). Tests target the helpers, the handler glue stays thin and trivially correct. +7. **Local stub files lag firmware additions** — `firmware/esp32-csi-node/test/stubs/esp_stubs.c` doesn't get rebuilt with the firmware proper, so a new symbol added to a `*.h` won't surface as a fuzz-target link error until CI runs. Iter 38 caught `c6_sync_espnow_is_valid` this way. **Whenever you add a function whose declaration is reachable from `csi_collector.c`, also add a stub** in the same commit. +8. **Cron-based /loop accumulates work across irreversible checkpoints (tags, releases, PR ready)** — once you cut a tag or mark a PR ready, the cost of reverting is much higher than a code edit. Save those for iters when you have surplus confidence (full local test suite green, CI from previous iter green). Iter 12 (v0.7.0 cut) and iter 38 (PR ready) were the right shape: only happened after iter 6 / iter 37 evidence had landed.