BE-4000 derive transplant onto merged develop (2026-07-29)
Companion to BE-3657 error_stack Adoption (the master error-stack decision trail). Records the 2026-07-29 events: MR !585 merged, and BE-4000 (the derive + DX v2 branch) transplanted onto the new develop, with the opl create_orders blocker and its resolution.
!585 merged, develop advanced
- MR !585 (BE-3657 phase 3, adapters) MERGED via SQUASH at 07:15 UTC 2026-07-29 (squash
c8bf3c84, merge commitf84db378). develop advanced29ed8e34→f84db378; it now contains phase 3. - The opl
create_ordersreview thread resolved by fait accompli: it merged WITH the restore in place (phase-3 tipc3519e73“restore opl order creation” was the merged head), socreate_orders/OplOrderare now ON develop. krisztian’s “not related to the ticket” / Andras’s “should we keep it then?” never formally resolved; kept by default. Any later removal is a separate cleanup PR.
Transplant boundary landmine (the handover command was stale)
Stale transplant one-liner
The handover said
git rebase --onto origin/develop feature/BE-3657-phase3 feature/BE-4000. WRONG after the 2026-07-28 phase3 rebase: that rebase re-wrote phase3’s commit SHAs, sofeature/BE-3657-phase3(nowc3519e73) no longer excludes BE-4000’s orphaned old-phase3 base. The rangefeature/BE-3657-phase3..feature/BE-4000= 54 commits (29 already-merged old-phase3 + 25 derive). Running it would replay the 29 phase3 commits onto a develop that already has them, i.e. conflict hell.
- CORRECT boundary = BE-4000’s true base
ee84ea50(“restore ebs upload block layout”).ee84ea50..feature/BE-4000= exactly the 25 derive commits. Verified: merge-base(BE-4000, develop) =4c3442df;4c3442df..ee84ea50= 29 old-phase3 commits (content now in develop via the squash); 29 + 25 = 54. - Transplant command:
git rebase --onto origin/develop ee84ea50 feature/BE-4000. - General lesson: when a base branch is rebased AFTER you stack on it,
base..yoursstops excluding what you assume. Check commit counts + merge-base before any transplant, never trust a handover’s rebase one-liner blindly.
opl create_orders: dead code AND the sole transplant blocker
- develop’s
create_orders+OplOrder(mando-lib/src/adapter/alpiq/opl.rs) were restored in the OLD raw-Report<OplError>idiom (+94 lines). grep on develop: ZERO callers of either (only their own definitions), i.e. DEAD code. - It never existed on BE-4000’s base, so the derive sweep never transformed it. The derive design deliberately DELETED the lifting
From<Report<C>> for MandoReport<C>in favor of an explicit.lift(). Transplanting the derive branch on top leftcreate_ordersuntransformed, causing 20 compile errors, all in opl.rs (Report<OplError>: Error not satisfied/ no report route). - The transplant auto-merged
create_ordersSILENTLY (no conflict markers) because it comes from the rebase target (develop), not from a replayed commit. First attempt (subagent) correctly ABORTED and restored the branch rather than guess on financial code. - Decision (Andras): SWEEP it into BE-4000 (not remove the dead code). Fix = 7
.lift()edits mirroring the live siblingcreate_strategiesin the same file:get_algorithm().await.lift()?,.map_err(report_polars).lift()?x6,get_token().await.lift()?,handle_non_status_response(...).lift()..lift()is type-onlyReport<C> -> MandoReport<C>, emission-preserving. TheInvalidUrl {..}.into_report()?born-lifted site was left untouched. Landed as a trailingfix: adopt report derive for opl create orderscommit (git rebase -i unsupported in harness, so no mid-history fold; BE-4000 squash-merges anyway). - Lesson: a code restore added mid-review to placate a “why was this deleted?” question can silently block a stacked branch authored before the restore existed.
RTK false-greens clippy output (new; companion to the test-gate trap)
- A
cargo clippy --release --all-featuresthrough RTK showed a 66-line filtered summary “0 warnings, 0 errors” exit 0, while RTK’s full 1692-line log had 20error[...]+ “could not compile mando_lib”. Exit code proved nothing. - Mitigation: run gates via
rtk proxy cargo ...and check the FULL log (greperror[/could not compile/ a genuineFinished), never the filtered tail. Extends the known RTK test-gate false-green (barecargo test ... -- --test-threads=1gets rewritten into a filter that runs nothing).
Result + current state (updated 2026-07-30)
- MR !592 OPEN (
feat: add mando error attribute macro and adopt report derive, Closes BE-4000, reviewers krisztian.fekete1/gabor.nagy6/balint.budavoelgyi/jozsef.nagy1).feature/BE-4000@0bc5fef9, 28 commits on develop tipcc3801de. - After the initial push (
930c2413), two renames + a rebase landed (see Renames + rebase onto the mando-repository refactor 2026-07-30):.lift()→.into_mando_result()(671c1eb2), cratemando-flow-step-derive→mando-macros(0e359086), then rebase onto developcc3801de(0bc5fef9) resolving 3 import conflicts. - Gates (real, RTK-proxied): clippy clean; test —lib = 649 passed / 0 failed / 32 ignored;
mando_macrostrybuild green. - Conflict RESOLVED: !592
has_conflicts=false,merge_status=can_be_merged. Standing blocker:detailed_merge_status=requested_changes(krisztian’s formal review, from his “conflict” comment; a push does not auto-clear it, needs his re-review now the conflict is fixed). - BE-4014 Datadog Error-Rendering Test Harness still ready to MR anytime on Andras’s yes; independent.
Renames + rebase onto the mando-repository refactor (2026-07-30)
.lift()→.into_mando_result()(Andras chose the type-accurate name overinto_mando_report/lift_report). TheLiftExttrait →IntoMandoResultExt; theMandoReport::lift(report)constructor →MandoReport::from_report(incl. the proc-macro codegen). 50 call sites, exhaustive; commit671c1eb2.- Crate
mando-flow-step-derive→mando-macros(the “flow” verb was wrong once BE-4000 put the generic#[mando_error]attribute macro in it, alongside the flow-step derives StepConfig/FlowStepService/ParamEnum/ParamMeta). Folded into BE-4000 since BE-4000 caused the misnomer. 59 files: dir git-mv + packagename = "mando_macros"+ workspace member/dep + ~38 imports. Naming split preserved: hyphens for dir/paths/members, underscores for package name + dep keys. Commit0e359086. - Rebase onto develop
cc3801de: develop had advanced (a day) with a big repository-layer refactor (newmando-repositorycrate,ea3311a0/d72091a3) + tensor type + direct-postgres mode. Only 3 of 9 predicted files actually conflicted (adapter/volue/ems.rs,service/volue/ems.rs,workflow/mod.rs) - all import-block collisions where develop’sRepoError -> MandoServiceErrorrefactor landed next to BE-4000’s derive imports. Resolved by keeping develop’sMandoServiceError/ flattenedmando_repository::RepoError+ BE-4000’suse mando_macros::mando_error;andMandoErrormarker imports; unusedRepoErrorimports dropped.opl.rsreplayed clean. Result0bc5fef9. - LESSON: a develop-side crate-extraction refactor collides with a feature branch mostly in imports + Cargo.toml, not logic, IF the feature branch never touched the moved code. The
comm -12file-intersection gauge (9 candidates) over-predicted; 3 were real.
into_mando_result authoring cheatsheet: when does bare ? work
In a fn returning MandoResult<T, YourError>, bare ? on Result<_, S> works IFF: (1) S: std::error::Error + Send + Sync + 'static, AND (2) #[cause(S)] is declared on a variant of YourError (generates MandoFrom<S>; the blanket impl<S,E> From<S> for MandoReport<E> where E: MandoFrom<S> does the rest). Otherwise, one verb:
- raw
error_stack::Report<C>(a tower fn, or.map_err(report_polars)) →.into_mando_result()?(Report isn’t a std Error, the blanket can’t see it). - an already-born
MandoReport<Inner>you fold into your enum with a static message →.wrapped()?(needs#[cause(wraps(Inner, message="..."))]). - constructing a NEW error →
.into_report()(value) /.reported()?(onResult<_, YourError>). Keystone:MandoReportdeliberately does NOT implstd::error::Error(the anyhow trick) - that is what makes the blanketFromcoherent, and why the two transitions above need explicit verbs instead of?. The#[diagnostic::on_unimplemented]notes onMandoFrom/MandoWrapsname the missing verb/declaration for you.
Roadmap (unchanged, nothing half-done blocking)
- After BE-4000 MRs + merges: UNWALLING phase (convert the 5 frozen auth towers ems/atp/mdr/opl/position_manager so reports flow to the step boundary); the
into_bare_report()helper decision lives there. Then phase 4#[error_meta(...)]. Archiver adapter deferred. - UPDATE 2026-08-04: unwalling DONE. BE-4047 began it, BE-4067 whole-mando error unwalling FINISHED it - zero production raw-
Reportleft inmando-lib(git grep into_mando_result -- mando-lib/src= 0). Theinto_bare_report()question resolved into the sharedwrap_http_callhelper (multi-field +HttpContextreattach, so not a#[cause]route). Phase 4#[error_meta]+ downstream-service conformance remain open.