For Agents
Reverse-chronological session log. Newest entries at top, grouped by date (
## YYYY-MM-DD). Each bullet: one piece of work, short summary, wikilinks to docs touched. Updated byobsidian-documenteron every project doc write. Read byhistorianat bootstrap (top ~15 entries).
2026-09-02
- BUG: Fatal steps log the same error twice (leaf boundary + ancestor wrapper boundary), still live on develop tip
b5770766. Prod DD incidentexec_id 5937b3e7-d39f-44d0-bdd0-fd8dc721b217emitted two ERROR events from the same sitemando-lib/src/workflow/mod.rs:361, differing only in step path (data_update.load_battery_timeseriesexec 1.809s vsdata_updateexec 5.783s), so the fingerprints diverge and do not aggregate. Mechanism:run_step(mod.rs:465-540) callsstate.log()unconditionally at line 499 for EVERY step;call_parallel!@unwrap(macros.rs:120) runs$step?.status_or_error()?;status_or_error()(mod.rs:382-388) returnsOkfor Skip/Success/Warning/Error butErr(identical ErrorWithStepStatus)for Fatal, so?re-surfaces it at the wrapper node which re-logs via the same line. Confirmed by timing:tokio::join!makes the wrapper wait for the slowest sibling, log gap 3.969s vs exec_time gap 3.974s (within 5ms). Fires ONLY for Fatal; copy count = 1 leaf + one per ancestordescnode, so deeper flows emit >2; NOT parallel-specific (sequential macros lines 11/20/34/45 use the samestatus_or_error()?).git diff --name-only 92213459 85452c3e -- mando-lib/src/workflow/is empty, so MR !601 (BE-4067) never touched the emission path. This is NOT the BE-3541 bug (that was detection-site + boundary); this is boundary + ancestor-boundary, a different axis. Fix must go at the emission decision, not the propagation (Fatal→Err is pinned bystatus_or_error_preserves_error_status_as_okmod.rs:998 andstatus_or_error_propagates_fatal_as_errmod.rs:1005) and must NOT reintroduce alogged_at_site-style flag; suggested: onlyWorkflowStep::Stepemits the error payload, wrapper nodes emit status only. Underlying trigger was a DuckDB duplicate PK on(data_point_id, value_time, generation_time)- exactly what MR !610 (BE-2132) fixes viadab6cba6(hardcoded(data_point_id, value_time)dedup grouping/join replaced by fullschema.pk_columns);git merge-base --is-ancestorshowsdab6cba6/f418e9b3are NOT in prod7c1ef44fbut ARE on develop and test image336ce49f, so prod is hitting an already-fixed bug. — fatal-step-double-logging-ancestor-boundary-2026-09-02 - BUG: zero trace correlation on Rust-origin logs inside Python containers.
bess-os-algo-forecast-fr(dev, FR) log hasasctime,logger.file: mando-lib/src/service_base.rs:937,logger.line, but nologger.name, nothread_name, nodd.trace_id/dd.span_id, noflow.exec_id/flow.step.path. Root cause: TWO Rust formatters.mando-lib/src/app/dd_formatter.rsemitstimestamp/status/logger.file/logger.line/logger.name(meta.target())/logger.thread_name/dd.span_id/dd.trace_id/ddtags;py-mando/src/log_formatter.rsemits onlyasctime/status/logger.file/logger.line/ddtags+ span/event fields.git grep 'dd.trace_id|span_id|DD_LOGS_INJECTION'overpy-mando/returns nothing. Duplicated rather than reused becausestruct TraceInfo(dd_formatter.rs:62) andfn lookup_trace_info(dd_formatter.rs:79) are private ANDmando-lib/src/lib.rs:2gatespub mod appbehind theappfeature, which py-mando does not enable (it enablespython) - unreachable on two counts. Second independent gap:TraceFilterinpy-mando/python/py_mando/tracing.pyinjectsflow.exec_id/flow.step.pathfrom contextvars but is alogging.Filter, so it only runs on Pythonloggingrecords; Rusttracingevents go straight to stdout via the Rust formatter, bypassing Python logging, sorun_with_tracecontextvars never reach them. RULED OUT (verified at develop tipf7fb74ef): the obvious “moveTraceInfo/lookup_trace_infointomando-coreaspuband call them from py-mando” fix does NOT work. It is an OTel helper (span_ref.extensions().get::<OtelData>(), i.e.tracing_opentelemetry::OtelData, imported atdd_formatter.rs:4/:11), so moving it dragsopentelemetry+tracing-opentelemetryinto the crate AGENTS.md 1 requires to stay lightweight (py-mando declares onlytracing/tracing-subscriber). Decisive finding: it would still returnNone-py-mando/src/lib.rsinit()buildsregistry().with(EnvFilter).with(fmt::layer().json().event_format(JsonFormatter))with NO OpenTelemetry layer, so nothing ever populatesOtelDatain any span’s extensions. And even with an OTel layer the ids would be Rust-side, unrelated to the Pythonddtracespansrun_with_tracecreates viatracer.trace(context); DD correlation needs the ddtracetrace_id/span_id. Correct fix is two-part: B1 addlogger.name(meta.target()) +logger.thread_nametopy-mando/src/log_formatter.rsfor parity (small, independent of correlation); B2 (own ticket) bridge the active ddtrace span context Python→Rust so the Rust formatter can stamp it, mirroringset_ddtags(py-mando/src/lib.rs:129→LOG_DDTAGSOnceLock) but per-call not set-once -run_with_traceinpy_mando/tracing.pyholds the span and can pushspan.trace_id/span.span_id, clearing on exit. Ceiling: a naive global is wrong under concurrent flows in one process, so storage must be task/thread-scoped (mando-lib’sTASK_CONTEXTtokio task-local inworkflow/mod.rsis a reusable precedent) or the single-flow-at-a-time assumption must be stated explicitly. The two structural blockers (privateTraceInfo/lookup_trace_info,appfeature gate) explain why a subset was reimplemented; they are NOT the thing to undo. Flow-level Rust/Python correlation remains a further, larger question. Noteset_ddtagsIS wired (py-mando/src/lib.rs:129), so ddtags DO flow; it is specifically trace correlation that is missing. — pymando-rust-log-trace-correlation-gap-2026-09-02
2026-08-18
- DEPLOYMENT PIN MODEL CORRECTED: the
dev_testshared component group is GONE, dev and test are now independently pinnable. Since optimization-universe-iac commit3f50c77(2026-07-14, Jozsef Nagy, “feat: migrate variables from cicd config and auto.tfvars to separate env.tfvars files”),terraform/terraform.auto.tfvars.jsonno longer exists and pins live interraform/environments/{dev,test,int,prod}.tfvars, each with a FLATcomponents = { mando = { version = "..." } }.terraform/main.tfnow readsvar.components["mando"].version/var.ecr_repos["mando"]directly andlocal.environment_groupis gone from the wholeterraform/tree (git grepreturns nothing) - so the AGENTS.md §14.7 “gate onvar.environment, neverlocal.environment_group” warning is moot for the group half. File selection isterraform plan -var-file=environments/${CI_ENVIRONMENT_NAME}.tfvars, whereCI_ENVIRONMENT_NAMEcomes from theenvironment: name:key of.environment-vars:{env}.ecr_reposmoved into the per-env files too (dev/test carry identical dev-ECR strings but as separate copies, so they CAN diverge). PROOF THAT DEV AND TEST DIVERGE: at16e8241^dev was1.17.0-dev.2733155664.358a48b7while test was1.17.0-dev.2729271578.24a0f34b;16e8241(2026-08-11) set both to the same value. SECOND CORRECTION, same commit: runtime config also moved - the.environment-vars:{env}anchors now carry ONLYASSUME_ROLE_ARN/ACCOUNT_ID/ACCOUNT_NAME/AWS_REGION/environment:name, andSIMULATION_MODE,MANDO_FLOW_SCHEDULE_*,EBS_SMB_HOST,MANDO_FLOW_ACTIVE_VERSIONgrep to nothing in the IaC.gitlab-ci.yml; they are now lower-case tfvars keys (simulation_mode,ebs_smb_host,mando_flow_schedule_*) and sizing + active version moved per region underbess_os_regions.{fi,fr}(dev has fi+fr, test has fi only). ⚠️ The local clone/Volumes/bandi/coding/poc/optimization-universe-iacis onrc/1.11.0from 2026-05-27 and still shows the OLD layout - always read viagit -C <iac> show origin/develop:terraform/environments/<env>.tfvars. DISCREPANCY vs the briefing: the claim thatterraform_plan:test/terraform_apply:testare nowonly: developis NOT what origin/develop @9600b34csays - both areonly: [develop, /^rc/.*$/], so rc/* still drives test; apply iswhen: manualas before. Verified branch rules: dev plandevelop|feature/*|bugfix/*, dev applydevelop, test plan+applydevelop|rc/*, int plan+applyrelease/*, prod plan+applymain. — Mando Deployment Ceremony - Test env state pinned down: BE-4067 (MR !601) is NOT live on test. Test runs mando image
1.17.0-dev.2749963346.336ce49f= mando pipeline 2749963346 over develop336ce49f(“Merge branch ‘bugfix/BE-2132-upsert-dedup-key’”, MR !610, 2026-08-11 09:07 UTC); pin set by IaC16e8241at 12:10 UTC, applied green at 14:12 UTC in IaC pipeline 2750845368 @9600b34cafter two failed applies the same day (2750514125 @ 12:37, 2750720634 @ 13:24) - and the timeline lines up exactly with the two intervening “application asset tag” fix commits (cb07b0b13:19,9600b34c13:59), i.e. the failures were NOT the mando bump. Ancestry-verified LIVE on test: !571 BE-3541 (1c4c33a5), !585 BE-3657-phase3 (f84db378), !592 BE-4000 (3ea0366b), !597 BE-4014 (37f95d8b), !599 BE-4047 (c21e65af). NOT live: !601 (squash85452c3e, mergec2c9c9a2, merged 19:26 UTC = ~5h after the apply), plus4d6cf7a1BE-4282 (14:24 UTC) and92213459BE-4017 (15:11 UTC) which also postdate the 09:07 build. Nothing has been applied to test since 2026-08-11 14:12 UTC (9600b34cis still the IaC develop tip). CONSEQUENCE: any Datadog read oferror.errors/error.details/tree-shapederror.stackon test is measuring the PRE-!601 world. Two green-but-unpinned images already carry !601:1.17.0-dev.2751762903.c2c9c9a2(the exact merge) and1.17.0-dev.2756529188.b5770766(develop tip 2026-08-13, also BE-4312 + the forecast-mode fix; tag read verbatim from that pipeline’s “Publish Service Docker Dev” log). — Test Env Deployment State 2026-08-18, Mando Deployment Ceremony
2026-08-13
- Agent Context External Integrations table rebuilt against
poc/e2e-tests- was 7 systems (Entra ID, EBS, MDR, OPL, Volue EMS, Volue ATP, Fingrid), is now ~15 external systems + 6 auth providers, each row carrying its plannedMaintenance/{country}/{Service}datapoint, purpose, protocol, auth model and env prefix: Volue EMS, Volue ATP, Metis, Metis GraphQL, Fingrid, Position Manager, EBS (SMB3 .xlsx drop), OPL, MDR, AWS Kinesis, Mando Algo Forecast, Mando Algo Optimization, Data Platform (Athena). Listed as present-but-datapointless: ET-3000, MS Teams webhook + MS Graph mail, OnePassport, S3 archiver, mando self-clients, mandarrow-client. Likron = OPL confirmed (system = "OPL (Likron)",mando-bess-lib/src/service/intraday/idc_order.rs:122). GOTCHA recorded:#[step(system = "...")]strings are NOT normalized (volue_atp_order_book.rsdeclares"Likron"while implemented against Volue ATP;as_auction_update/energy_bids.rsdeclares bare"Volue"), which breaks telemetry aggregation byflow.step.system. Also recorded: 6 auth providers onStepProviders(mando-flow-step/src/providers.rs:15-20), theparse_config_with_prefixvs#[derive(Envconfig)]split, crates older docs miss (mando-macros,mando-bess-am,mando-repository), and the integration-relevant workspace deps (aws-sdk-athena/s3/kinesis, cynic + graphql-ws-client, smb 0.11.2, scraper, tonic). - External-service outage gate designed: the whole thing is ONE bitmask AND - External Service Outage Gate - bitmask design. Interval-double severity 0/1/2 (Normal/Warning/Outage) at
Maintenance/{country}/{Service}; steps declareexternal:deps with optionaltransient: true. Key insight: the per-service accepted-value set is only ever {0,1} or {0,1,2}, so it is ONE BIT - severity 1 never blocks and falls out of the arithmetic entirely.required = fold s: acc | (R(s) << i(s))(static per-flow codegen const),outagesthe same shape from live reads,blockers = required & outages,can_run = blockers == 0, O(1), u64 covers 64 services vs 13 today. GOTCHAS:propagates_failuremust fold up the ancestor chain or the guard is stricter than the runtime (worth a dedicated test);transient: trueandfailure_status: Warningare identical at the gate so do NOT build two code paths. OR idempotency makes tree dedup a structural fold, no HashSet. Placement:ExternalService/ServiceMask/ExternalGateinmando-core(no I/O),FlowGuardinmando-lib/src/workflow/; theExternalServiceenum should be codegen from the same YAML as the maintenance datapoints so path and bit index cannot drift. Open item:ExternalDependencyneeds an untagged two-variant enum for the bare-string and struct YAML forms. Worked example reproduces the design doc’s second matrix exactly (required = 0b00111).
2026-08-10
- py-mando flaky test root-caused:
test_dd_conformance.py::test_init_populates_identity_and_dd_envintermittently assertsidentity["service"] == None. Chain: constructingAlgoRunner(py-mando/src/algo_runner.rs:~113)std::thread::spawns a permanent Axum server (no shutdown inside pytest);test_algo_runner.py(ports 3002/3003) LEAKS those threads; each thread’sstart_servercallslogger.init()with NO service arg, andpy_mando/python/py_mando/logger.pyinit()setsidentitythen_initializedseveral slow lines apart (gap includesimport ddtrace.auto), so a backgroundinit(service=None)overwritesidentitymid-window. Tell:Starting Algo runner service, listening on 127.0.0.1:3003/3002log lines interleave right before the failing test. Seen developab4c54c1(pipeline2746786029); hits any branch carrying the DD-conformance suite. MITIGATION shipped via MR !601 (feature/BE-4067,fix: guard py-mando logger init against concurrent initialization): double-checkedthreading.Lockaroundlogger.init()— narrows the wide ddtrace-import window by orders of magnitude but NOT a proven 100% fix (residual microsecond window when a background init is in-flight as the test resets_initialized). REAL fix needs its own ticket: stopAlgoRunnerleaking an unstoppable server thread on construction, or isolate the test from the module globals (local monkeypatch / fresh process). REBASE GOTCHA on that MR:merge-treePREVIEWED conflicts inopl.rs+ts_data_retrieve.rsbutgit rebase origin/developresolved them by DROPPING 5 branch commits as “patch contents already upstream” (already merged via another MR) — merge-tree previews such conflicts, rebase drops the duplicate patches. — pymando-logger-init-race-flaky-2026-08-10, mando-known-flaky-tests-2026-07-15 - BE-4067 error DX clarity — grammar rename + mando-bess-lib adoption (branch
feature/BE-4067-grammar@0a3c2382, 10 commits, LOCAL/NOT pushed). Two phases stacked on the unwalling tip9038b0c6. Phase 1 (emission-NEUTRAL): replaced the generic#[cause]with three self-naming verb attributes on#[mando_error]enums —#[reframe(Src)](flatten a FOREIGN error into your{message}, bare?),#[chain(Inner)]/#[chain(Inner,"msg")](wrap a MANDO error + add a frame,.wrapped()?, inner kept underneath),#[transparent(Inner)](re-export a sub-error; macro STRIPS the attr and INJECTS thiserror#[error(transparent)]+#[from]+aMandoFromso it also?s into MandoResult — writing#[error(transparent)]inside#[mando_error]is now a hard macro error). MENTAL MODEL (headline the docs): field shape tells you behavior —{message}=reframe, unit=chain,(SomeError)=transparent; reframe replaces with your message, chain adds on top, transparent shows through. Plus reflexiveMandoFrom<Self>per enum so a bareResult<T,E>?s into MandoResult (“.reported() now rarely needed”, dropped ~35 sites);MandoReportmade OPAQUE (Derefdropped, access viaas_report()/into_inner(), ~30 test fixups, 0 prod breaks);flatten_reportclippy-banned = the no-silent-stack-loss guard. Phase 2 (SEMANTIC / telemetry change): 25 plain-thiserror mando-bess-lib service enums adopted into the error system (#[mando_error], 72 newtypes →#[transparent]) + ~21 step boundaries switched to the rich report path via a newErrorWithStepStatus::reported/from_reporthelper = a deliberate DD TELEMETRY CHANGE on the financial flows (idc_order, auction):error.errors/error.detailsADDED,error.stackreformatted colon-chain→tree,error.messagesource shifts (text usually identical);code/kind/typeUNCHANGED; previously-discarded in-system inner chains now surface as a 2nd frame. Delta captured as inlinedd_emissionasserts (not golden files, so mando-lib Phase-1 goldens stay byte-identical). GOTCHAS: workspaceall=allowsilently disablesdisallowed_methodsexcept in mando-core (fixed in P2.3 bydisallowed_methods=denyat higher priority); py_mando “could not compile (lib)” on a full build = the known macOS cdylib LINK failure (cargo checkis clean);cargo checkskips#[cfg(test)](test-fixup count under-estimated); the#[chain]reshape drops the transparent#[from]and breaks bare?at other construction sites (grep all sites first); whole-file rustfmt reflows legacy lines on this non-fmt-clean tree. Gates green @0a3c2382: clippy--release --all-featuresclean,-p mando_lib --lib379/0,-p mando_bess_lib10/0 (incl. 3 new dd_emission), mando-lib goldens byte-identical vs9038b0c6. PENDING (each a separate explicit yes): Andras’s telemetry sign-off, final whole-branch review, push + MR. Spec/plan/handover untracked underdocs/superpowers/. → BE-4067 error DX clarity.
2026-08-06
- FLOW-COVERAGE REPORTING SHIPPED — the e2e suite’s coverage number is FLOWS EXERCISED, not lines. mando-cli
main5a135b8:mando e2e runends withflow not covered: <name>lines plusflow coverage: N/M flows (X.X%), the denominator taken from the live service flow inventory (same endpoint asmando flow list, so nothing to maintain in the suite); an inventory fetch failure warns and skips, never fails the suite (reporting is observability, not an assertion); +36 unit tests → 1686 total. mandopoc/e2e-tests96b5b89caddscoverage: '/flow coverage: \d+\/\d+ flows \((\d+\.\d+)%\)/'to the E2E job — the regex REQUIRES a decimal digit, so the printed format and the regex are ONE CONTRACT across two repos (a bare20%would match nothing and GitLab shows no coverage with no error, same silent-empty signature as the dotenv trap). The interimcargo-llvm-covunit-coverage job — built, green, 40.36% — was FULLY REVERTED per user decision: flows-only coverage wanted, do not reintroduce line coverage on this pipeline. First live result pipeline2736559170: 20.0% = 1/5 flows (covereddata-update; uncoveredas-auction-update,auction,intraday,manual-schedule) — the honest scope of the earlier 8/8 green. Badge/badges/poc%2Fe2e-tests/coverage.svg?job=E2E+Data+Suite+Linux+Dev. Same day: test set renamedtest_set_1→data-update-beskar-soc(flow+scenario naming; JUnit history was NOT affected — since mando-clifabc589classnames derive from the case’sflow:field, not the directory, so pipelines2735716225pre-rename and2736559170post-rename both emitdata-update.flow/.mock/.logs/.datapoints; the dir name is only a collision fallback when two cases share a flow, which means case dirs can be renamed freely and the junit note’s<test set>.<section>classname table is superseded), mando-clidocs/now untracked + gitignored as AI-internal material (supersedes the junit note’s pointer to a repo-residentdocs/e2e-guide.md), and the agent skill gained an e2e case-anatomy section so an agent can author acase.yaml— the prerequisite for raising that 20%. — mando-cli-flow-coverage-2026-08-06, mando-e2e-ci-green-2026-08-05, mando-cli-junit-per-assertion-2026-08-06 - RESEARCHED then REJECTED replacing mando’s dev-gated CSV seed endpoint with a client-side Arrow insert — the E2E harness KEEPS the CSV endpoint. THE WIRE FORMAT, finally pinned down (
mando-lib/src/app/route/save_data_route.rs):POST /data/inserttakes{"data_points": {"<dp id>": [<bytes>]}}where the bytes are an Arrow IPC STREAM (not file) serialized as a JSON ARRAY OF DECIMAL u8 VALUES — not base64, not a binary body. That shape is not a design choice: polars 0.49.1’sDeserialize for DataFramereaches bytes throughdeserialize_map_bytes’svisit_seqonly under serde_json, so a base64 string simply fails; the reader ispolars-arrow(arrow2 fork)StreamReader. Fixture proofmando-lib/test/adapter/mando/rest/simple-send-test-data.json: 936 IPC bytes → ~9KB of JSON (that expansion ratio is the format’s fingerprint).update_infooptional, 204 on success, Content-Type never enforced (handler takesbody: String). REQUIRED SCHEMA (from the siblingsave_data_csv_route.rs):value_time/generation_time/fetch_timeasTimestamp(Microsecond, None)naive-UTC,value(value_x/value_y)Float64,idUtf8for matrix/trade; aflagcolumn is REJECTED and so is any null cell; consumerget_column_date_timesignores the timezone and normalises ns/us/ms. FEASIBILITY IS NOT THE BLOCKER —mando-repository/src/arrow.rs:59-88already round-trips arrow-rs 56.2StreamWriteroutput through the exact polars reader (both pinned in mando’sCargo.lock:arrow 56.2.0,polars =0.49.1), costed at ~250 LOC + ~17-20 crates on the distributed CLI (a directpolarsdep = 100+ crates, rejected; pre-serialized IPC fixtures rejected because the CSVs are the reviewable spec; hand-rolled flatbuffer rejected as untestable). THE DECIDING FACTOR IS DRIFT: the encoding is an undocumented internal of polars’ serde impl that already changed between=0.45.1and=0.49.1, and if mando-cli produced the bytes no test on either side would put producer and reader in one process — the exact failure class as theDataPointIdserde drift that stayed green locally and 400’d live. The CSV endpoint is server-side, in the same repo as the polars pin, and carries 14 tests that break loudly on a bump. OPEN IMPROVEMENT (not done, ~3 lines): swap the runtimeMANDO_TEST_ENDPOINTSgate for a cargo featuretest-endpoints(#[cfg]on module + route registration, CI e2e image builds--features test-endpoints) so test routes are ABSENT from prod binaries rather than merely unreachable. PRECONDITION if ever revisited: a contract test in mando’s repo round-tripping an arrow-rs stream throughserde_json::from_value::<DataFrame>. Minor: mando-cli’s seedContent-Type: text/csvis decorative, the server ignores it. — mando-data-insert-wire-format-2026-08-06, mando-cli-e2e-harness-2026-08-04, mando-cli-e2e-live-green-2026-08-05 - Per-assertion JUnit is SHIPPED and PROVEN IN CI —
9c39a88pushed straight tomain+release(per user) and released via the release branch; mando pipeline2735668937renders 8 named cases, 0 failed in the Tests tab for suite E2E Data Suite Linux Dev. Classnames{test_set}.{section}overflow/mock/logs/datapoints/spans/outbound; names are human-readable and stable —step load_battery_timeseries is Success,no unmatched requests,POST /ExternalData/DataGroups at most 0x. +20 unit tests, 1632 total. The junit-granularity improvement flagged in the 08-05 CI-green note is now closed. — mando-cli-junit-per-assertion-2026-08-06, mando-e2e-ci-green-2026-08-05 - JUnit reports now carry ONE TESTCASE PER ASSERTION (
feature/junit-per-assertion, commit9c39a88, mando-cli) — closes the open improvement flagged in the CI-green note; GitLab’s MR widget now names the assertion that broke, not the test set that contained it. KEY INSIGHT: this was a plumbing fix, not new evaluation logic —src/e2e/verify.rsalready evaluated every expectation separately into aVec<Assertion>; the collapse happened becauseverify::runthrew that away and returned a bareboolandjunit_casesinsrc/commands/e2e.rsmapped oneSetResultto oneTestCase. General rule: when a report is coarser than the engine behind it, check whether the granularity was discarded at a boundary before assuming it was never computed. THE DUAL-LABEL PATTERN: eachAssertionnow carries two names built together by a newLabeltype —nameis the machine label the terminal prints (mock.requests[GET /path], must stay byte-identical for humans diffing runs) andcaseis the human sentence JUnit uses (GET /path at least 1x); deliberately separate because terminal and GitLab have different stability requirements. THE NON-OBVIOUS CONSTRAINT (most valuable item): JUnit case names must be derived from the EXPECTATION, never from the observed result — GitLab attaches a test’s history to(classname, name), so a label that changes between a passing and a failing run reads as one test disappearing and a new one appearing, not a pass→fail transition, destroying the “newly failed” classification and flakiness history. Hence “step X is Success” comes from the expected status. Pinned by the regression testa_case_label_does_not_move_when_its_assertion_flips_to_failing. THE FALSE-GREEN TRAP: a set that never reaches the verify engine (skipped viaskip:, or failed while running its flow) has zero assertions, so emitting nothing would make the report read GREEN BY OMISSION —set_casesemits one fallback case carrying the set’s own verdict for exactly that case (correct asymmetry: sections merely absent fromcase.yamlstill emit nothing). KNOWN GAP, deliberately not fixed: amock.requestsentry with none ofcount/min/maxasserts nothing and always passes (thegroncounts section guards against this,mockdoes not) — per-assertion reporting makes it look worse, surfacing in CI as a named green testcase labelled “any number of times” that resembles real coverage. Classnames are<test set>.<section>formando e2e run, bare section for standalonemando verify, which gained--junitin this change. Terminal output and exit codes unchanged. Full user-facing reference stays in the repo atdocs/e2e-guide.md. — mando-cli-junit-per-assertion-2026-08-06, mando-e2e-ci-green-2026-08-05, mando-cli-e2e-harness-2026-08-04
2026-08-05
- MILESTONE — “E2E Data Suite Linux Dev” ran GREEN in REAL GitLab CI for the first time ever (mando pipeline
2735150017, job 72s, suite output “all assertions passed”, junit uploaded). The full chain is now proven unassisted: cross-project download of the released mando-cli binary viaCI_JOB_TOKEN+ job-token allowlist,postgres:17+wiremock/wiremock:3xas GitLabservices:(shared network namespace → WireMock onlocalhost:8081, not a service hostname),mando_bessstarted as a background HOST PROCESS from the pipeline’s build artifact, refinery migrations on boot, thenmando e2e run --external-stack—--external-stackis no longer an unproven code path. BOOT-ENV WHACK-A-MOLE, each miss costing one 15-minute pipeline: (1)DataPlatformConfig::init_from_env().unwrap()runs BEFORE its ownDATA_PLATFORM_DISABLEDflag is read, soFINGRID_DATABASE+OUTPUT_LOCATIONmust exist even when the subsystem is “disabled” — a boot-ORDER design wart to raise with the mando team, not a real config requirement; (2) then aFINGRID_API_KEYpanic atfingrid.rs:29(hard unwrap at construction). LESSON RECORDED:/Volumes/bandi/coding/poc/compose.override.ymlis the canonical known-good env set formando_bess— DIFF AGAINST IT instead of deriving requirements from the code; the final missing set was exactlyFINGRID_API_KEY,AFRR_AUCTION_RESULT_DEADLINE,FCR_AUCTION_RESULT_DEADLINE,BATTERY_STATIC_DATA_MDR_PATH. BRANCH RULES: mando’s.branch_rules:devnow includespoc/*(one line), sopoc/e2e-testsgets the dev pipeline; a prematurefeature/e2e-testsmirror branch was deleted and its half-run pipeline failed on a missing ref — deleting a branch mid-pipeline kills the not-yet-started jobs atgit fetch. DEPENDENCY-CACHE FIX committed incontainer.linux.chef.build.Dockerfile: chef cooked bare--releasewhilebuild.shuses--features flightandtest.sh--all-features, so cargo’s per-feature-set keying meant every job missed the cooked cache and recompiledarrow-flight/tonic; now cooks both variants, but the benefit only lands once merged to develop (the rebake trigger is develop-only). Escalation options if still slow: scheduled weekly rebake vsCargo.lockdrift, orsccache+S3 — GitLabcache:cannot help, it cannot hold/init/chef/cook/target(outsideCI_PROJECT_DIR); and PyMando Win Dev at ~2656s remains the pipeline whale regardless. IMPROVEMENT NOTED: junit granularity is currently wholetest_set_1= 1 case; per-assertion cases would make the MR widget show which assertion failed. — mando-e2e-ci-green-2026-08-05, Mando CI-CD, mando-cli-e2e-live-green-2026-08-05, mando-e2e-rebase-2026-08-05 - E2E harness ran LIVE for the first time and is GREEN 8/8 — twice, from wiped volumes — against the rebased mando (
poc/e2e-tests, head now2af0c6c9post history-rewrite). THE PREDICTED TRAP FIRED VERBATIM: the 08-04 handover warned that mando-cli’s hand-mirrored query schema could only be validated live, and upstream had indeed rewrittenDataPointId’sDeserialize/Serializefrom a{id, id_fragments}struct to a BARE JSON STRING — mando-cli’s unit tests stayed green the whole time and only the live run saw the 400 from/data/query/v2. Fix:src/e2e/datapoints.rsdata_point_id()now sendsjson!(dp_id); 4 tests updated including the serde-mirror testquery_body_deserializes_as_the_service_would_read_it(itsFilter.idis now aString). MR !6 onbugfix/e2e-datapoint-id-string. TWO MORE UPSTREAM DRIFTS fixed in mando’se2e/suite.yaml:MANDO_SETUP_ACTIVE_VERSION=V1_4is now REQUIRED (service crashloops without it), andMANDO_FLOW_SCHEDULER_DISABLEDwas renamedMANDO_SETUP_SCHEDULER_DISABLED— the old var is silently dead, so the0 5 * * * *data-update cron would fire mid-suite and breakunmatched_max: 0(sameMANDO_FLOW_*→MANDO_SETUP_*migration as the stale.cargo/config.toml.example). NEW UPSTREAM BEHAVIOR CHANGE TO RAISE WITH THE MANDO TEAM:DataPointId::newnow rejects path fragments that are not purely ASCII alphanumeric — ids with underscores inside a segment (bess/fi_north/soc_state, the wholein_/out_corpus naming) now 400 on query; mando-cli’sdocs/e2e-guide.mddocuments such ids as valid, so that is doc drift to fix once upstream intent is confirmed. — mando-cli-e2e-live-green-2026-08-05, mando-cli-e2e-harness-2026-08-04, mando-e2e-rebase-2026-08-05 - mando-cli v0.4.0 RELEASED — tag
v0.4.0+2734905610, full pipeline green (Version → musl builds → Publish +latest→ Release), unblocking the MR !5 approval wait. The Release job had failed once first, yielding TWO REUSABLE GITLAB CI GOTCHAS: (1)dependencies:overridesneeds:for artifact download — the Release job declared both, so the Version job’sartifacts: reports: dotenvcarryingPACKAGE_VERSIONnever arrived and the job ran with an emptytag=(a dotenv var arriving empty with NO error is the signature; either dropdependencies:and letneeds:do both, or name every artifact-producing upstream job in it); (2) markdown backticks in a release description get shell-evaluated byrelease-cli’s busybox wrapper as command substitution — keep GitLab release notes plain text. — mando-cli-gitlab-release-flow-2026-08-05 - All repo history rewritten attribution-free per standing user policy — mando-cli
main+release+ 4 old tags re-pointed, mandopoc/e2e-tests(head2af0c6c9); merged source branch deleted. Stale clones must re-fetch with--tags --force, not merge. NEW RTK LANDMINE found while verifying the rewrite: rtk-wrappedgrep/git logpipelines returned FABRICATED ZEROS — no matches reported for content demonstrably present. Rawrtk proxy git ...redirected to a file and then read is the only trustworthy check. General rule: an rtk-mediated NEGATIVE result is never evidence of absence. This is the third entry in the rtk hazard family (after the--test-threads=1filter false-green and the piped-exit-code trap) and is now recorded in Agent Context. — mando-repos-history-rewrite-2026-08-05 - Rebased mando
poc/e2e-testsontoorigin/develop— ~135 commits of drift closed, branch now 3 ahead / 0 behind, committed and pushed, gates green (agent-driven). Surviving commits: orphaneddatapoint/json.rsremoval, the dev-gated CSV insert endpointsave_data_csv_route.rs(untracked working-tree-only for weeks, finally committed), and the e2e suite scaffolde2e/test_set_1. All 5 old EBS SMB fix commits were skipped as fully superseded — develop carries them verbatim, confirmed byebs.rsbeing byte-identical after the skip. TWO REBASE-FORCED FIXES: (1)crate::service::MandoServiceConfigwas renamed upstream tomando_repository::model::DataPointRepositoryConfig, and this was only caught with--features app— theappmodule is feature-gated so a defaultcargo testsilently skips it and the branch looks green while the new route does not compile (same failure-mode family as the--lib-only CI gate lesson); (2) the CSV route tests had a real env-var race onMANDO_TEST_ENDPOINTSacross parallel tests, fixed by passing the flag intotest_routerinstead of reading ambient env, plus aMutexaround the remaining set/read/clear. THREE LOCAL GOTCHAS:py_mando/py_mando_simulationfail to link on Apple Silicon with unresolved_Py_*symbols because.cargo/config.tomlis gitignored local config — fresh checkouts mustcp .cargo/config.toml.example .cargo/config.tomlfor the[target.aarch64-apple-darwin]-undefined dynamic_lookuprustflags (the example also holds secrets, hence never committed);mando-bess/build/generated/flows/*.rsre-dirty on every local build (regenerated unformatted; rustfmt makes them byte-identical to HEAD) — pre-existing, never commit them. UPSTREAM FLAKE TO REPORT:mando_bess::debug_error::tests::gate_enabled_when_var_is_trueracesgate_defaults_off_when_var_unsetoverMANDO_DEBUG_MOCK_ERROR, fails ~2/3 parallel runs, passes single-threaded, CI masks it with--test-threads=1— same env-race bug class as (2). — mando-e2e-rebase-2026-08-05, mando-known-flaky-tests-2026-07-15, mando-cli-e2e-harness-2026-08-04 - mando-cli ran its first-ever GitLab pipelines after the project’s
ci_config_pathwas cleared (a stale non-default path meant pushes silently created no pipelines at all — the canonical “committed.gitlab-ci.yml, no pipeline, no error” diagnosis). Windows builds removed entirely (unlike the mando service pipeline, which still carriescontainer.win.*). Implemented a single long-livedreleasebranch flow:releasemints the tag + the GitLab release + moves thelatestpointer, whilemainonly builds and publishes versioned packages. First release is blocked solely on approval of MR !5 — a group-level approval rule applies and the author cannot self-serve it from the CLI, so it needs another group member in the UI. — mando-cli-gitlab-release-flow-2026-08-05 - Discovered the org’s shared GitLab CI component library (
alpiq_cicd/sales-and-origination/flexible-assets/bess/poc/bess-os-ci-components, tagsv1.0.0..v1.4.0, semantic-release via.releaserc.json; components attemplates/<name>/template.yml:mr-jira-check,python-setup,python-test,python-docker-publish,release-notes,simulator-pipeline). Inspected live on GitLab while sizing a CI job for the e2e harness. Consumer.gitlab-ci.ymlfiles are ~40 lines ofinclude: component:+spec: inputs:(bess-optimization passesstage/pre_test_script/extra_apt_packages/timeouttopython-test); pinning is versioned@v1.x.0. KEY MECHANICS behind the cheap 7.4-min/54-case and 13.8-min/68-case data-driven suites: (1)python-setup= the dotenv broadcast — one “Dynamic Env Variable Setup” job derivesPROJECT_VERSIONfrom branch +pyproject.toml(BASE_VERSION+<pipelineIID>.<shortsha>on main/release/*,-dev+on develop, ref-slug on feature/bugfix), plus ECR repo + release metadata, and exports ALL of it viaartifacts: reports: dotenv: build.envso every downstream job inherits throughneeds:with zero duplicated shell; (2)python-testhas NOservices:at all — plain runner,DB_DISABLED=truein bess-optimization,poetry installfrom the Nexus PyPI mirror pulling a prebuiltpy-mandowheel, so ZERO Rust compilation is the entire cost story;pre_test_scriptis the extension hook (Gurobi license), pytest--junitxml→junitparsermerge →artifacts: when: always, reports: junit:(thewhen: alwaysis load-bearing: failing suites still render per-case in the MR widget). Branch rules across components: MR events, develop,rc/*, main,release/*. RELEVANCE: mando-cli’s planned e2e CI job is a HYBRID — it copies the consume-prebuilt-artifact + junit-always halves frompython-testbut MUST takeservices:(wiremock + postgres) from mando’s.integration-test-linux, because the pure data-driven suites are deliberately service-less and the harness’s whole point is a live stack. Long-term option (undecided): package the e2e job as its ownbess-os-ci-componentscomponent withspec: inputs:for suite path / image tag / timeout. NOTE: the Rust mando pipeline does not consume this library at all — it hand-rolls its jobs. → bess-os-ci-components.
2026-08-04
- BE-4067: whole-mando error unwalling FINISHED (the mando-ERRORS axis of the conformance goal; branch
feature/BE-4067@0dff4f2d, stacked onfeature/BE-4047!599, 9 commits one per subsystem). GOAL ACHIEVED: removed ALL remaining production rawerror_stack::Report<C>frommando-liband adopted the full BE-4000 devex idiom, finishing what BE-4047 began. VERIFIED zero raw-Report:git grep into_mando_result -- mando-lib/src= 0; the only productioninto_report().into_inner()is the intentionalwrap_http_callhelper body; zero raw-Report-returning fns. Commits:b6086f79wrap_http_call helper /52205518fingrid /23da1335data_platform /9346d7c9metis /cc638039ebs /92c6da5fopl report_polars born-lift /fa1b1fa2ems service tower /78c567e6atp (deleteVolueAtpAuthenticationProviderError) /0dff4f2dfingrid cleanup. NEW PATTERN:wrap_http_call<E,F>(source: HttpCallError, make: F) -> MandoReport<E>inmando-lib/src/adapter/http_cause.rs- a SHARED helper (NOT a#[cause]macro route) replacing the triplicatedHttpCallError->ApiErrorwrap at metis/fingrid/ems, becauseApiErroris multi-field (carries source) + reattaches an opaqueHttpContextthat a message-only#[cause]route would DROP; MUST keep#[track_caller]to preserve caller file/line. RECIPE step (d) extending BE-4047’s a/b/c: message-only foreign-error maps →#[cause(ForeignErr)]+ bare?; multi-field variants (NonSuccessStatus/InvalidUrl/CannotParseJson) + context-prefixed/multi-source maps (ebsSambaError, data_platformSdkError) KEEP manual construction. EMS SERVICE-tower gotcha: the step-servicetype Error = Report<VolueEmsError>becomestype Error = MandoReport<VolueEmsError>(NOTMandoResult- the assocErrortype ISE); lives underservice/volue/ems/*, notadapter/. Emission preserved via per-subsystem DD goldens (BE-4014 Datadog Error-Rendering Test Harness harness, location-trimmed) - 11dd_emissiontests pass. Final whole-branch review READY-TO-MERGE, no findings; lib 376/0, clippy —all-features clean, no cross-crate ripple (atpnew()’s error change absorbed by anyhow?atmando-bess/lib.rs:198). Spec/plan untracked:docs/superpowers/{specs,plans}/2026-08-04-be4067-whole-mando-unwalling*. Still open (north star): mando trace/instrumentation conformance, error+trace conformance in bess-optimization/bess-forecast-day-ahead/dashboards, phase 4#[error_meta], the unlandederror.tracefield +.step_context(). → BE-4067 whole-mando error unwalling. - Two-repo data-level E2E harness built (
poc/e2e-testsin BOTH mando-cli and mando; UNCOMMITTED, never run against a live stack). Suites authored in the team’s test-data taxonomy (test_set_N/{input,expected}/{system/<sys>/*.csv, bess-os/<dp>.csv});mando e2e run <suite>= wipe (down -v) → up (service_env+ forcedMANDO_TEST_ENDPOINTS) → ready (REST poll 60s) → migrate → seed → per set (mock reset → stubs → seed →flow run --bundle→ verify);mando verify <expect.yaml>runs the same assertions standalone (sections flow/mock/logs/spans/datapoints/outbound). Server side: new dev-gatedPOST /data/insert/csv/{*datapoint_id}(mounted only underMANDO_TEST_ENDPOINTS=true) — needed because the normal insert body carries a polars DataFrame as Arrow IPC bytes, making CSV→insert impossible client-side.mando queryREMOVED entirely (unused), taking the mandarrow-client/mando-core/arrow-array worktree deps with it —cargo build --all-featurescompiles clean for the first time in weeks. TWO CRITICALS from review: (1) datapoints query body wrong on three counts (idmust be an object,rangeREQUIRED and internally tagged,reference_dateRFC3339) and its unit tests asserted the invented shape against itself — the self-confirming-test trap; (2) the runner’s own stack had ZERO WireMock mappings (infra template mounts only__files/), so the EMS auth POST was unmatched and no suite could ever pass. Gate: mando-cli 682 lib + 8 integration, clippy--all-featureszero; mando 370 tests. → mando-cli-e2e-harness-2026-08-04.
2026-07-29
- BE-4014: golden/snapshot JSON matcher added to the DD error-test harness (continuation of the “Error hdl” session;
feature/BE-4014tipeac5fb85→9a8a7538, pushed, still NOT an MR). Andras’s requested A/B style: assert a STATIC expectederror.*JSON against the generated DD JSON. Twopubhelpers besiderender_ddinmando_lib::app::dd_formatter::test_support:assert_dd_matches(generated, expected)+assert_error_renders(body, expected). MATCH SEMANTICS (the golden is a partial spec): objects = recursive SUBSET (expected keys must match, EXTRA generated keys ignored so you omit volatilefile/line); arrays = same-length element-wise; strings = exact OR a leading*=ends_with(grep affordance for the long full-path codes); scalars = exact; on mismatch PANICS with the JSON path to the offending node. The pre-existing field-by-field ABSENCE tests are KEPT as complementary (a positive golden cannot assert a field is absent). Self-tested with 8 tests incl.should_panicnegatives; 3 goldenjson!({...})example tests added as the new “assert the whole shape at once” template (report/plain/http arms) beside the 9 field-assertion examples. Gate: 39 passed / 0 failed under--features app,test-util. → Golden JSON matcher (added 2026-07-29).
2026-07-28
- BE-3657: MR !585 (phase 3) REBASED onto develop + pipeline GREEN + approval RESET (the last phase-3 event of the “Error hdl” 07-28 session).
feature/BE-3657-phase3rebased onto develop29ed8e34(which had advanced 22 commits, opening a merge conflict) to clear it; phase-3 tip0427c68d→c3519e73, force-with-lease pushed. 5-file textual collision (mando-bess/src/lib.rs+ 4 simulator files) resolved SEMANTICALLY (keep develop’s functional changes, re-apply phase-3’s error-stack shape). KEY CATCH + LANDMINE: develop had merged 2 NEW consumers of the simulator-client API phase-3 migrated (mando-lib/src/service/mando/asset_simulator.rs+mando-bess/src/live_simulator_init.rs) - they call the pre-migration signature and BROKE THE BUILD after the rebase WITHOUT being a textual conflict (brand-new files, no overlapping hunk; only a full workspace build surfaced them); both migrated to the phase-3 idiomsimulator_client_error_from_report(e.as_report())and FOLDED into the signature-owning commit so every commit still builds (footprint 81 → 83 files). LESSON: a big-branch rebase can break the build via new develop consumers of a migrated API, invisible to conflict detection - only building catches it (sibling of the-p/cross-crate-fallout gate lesson). VERIFIED: no conflict markers;git range-diff27=/3!(all 30 commits preserved); gates 605 lib / 0, clippy clean. CONSEQUENCE: krisztian.fekete1 had APPROVED !585 after the round-1 comments; the rebase’s new commits RESET that approval (GitLab drops approvals on ANY new commit), so !585 isnot_approvedagain (conflict GONE, pipeline SUCCESS) and needs RE-APPROVAL to merge. Repo handoverdocs/superpowers/HANDOVER-error-handling-2026-07-29.md(untracked) supersedes the 07-24 one. → MR !585 rebased onto develop, pipeline green (2026-07-28). - BE-4014: Datadog error-rendering unit-test harness (develop-based, independent of the error-stack MRs) + develop DD error-emission contract survey (part of the “Error hdl” session; branch
feature/BE-4014@eac5fb85, PUSHED, NOT yet an MR; renamed from the provisionalfeature/dd-error-test-harness, worktree.worktrees/dd-test-harnesshistorical). Motivation: a teammate needed to unit-test “what would this error look like on Datadog”, generate an error, assert its rendered DD JSON. DELIVERABLE: apubtest helperrender_dd(|| error!(...)) -> Vec<serde_json::Value>(+render_dd_one) inmando_lib::app::dd_formatter::test_supportthat drives the REALerror!macro through the REALDatadogFormatterand returns the captured DD JSON (promotes the previously-private capture harness fromdd_formatter.rs’s own test module); consumer feature combo--features app,test-util(NEW mando-libtest-util = ["mando_core/test-util"]); 9 copy-paste worked examples in a#[cfg(all(test, feature="test-util"))] mod render_dd_examples; runcargo test -p mando_lib --features app,test-util. CONTRACT SURVEY (develop, now test-pinned; the error-stack !585/BE-4000 branches change/extend it):error!(report=...)emitserror.errors[](full-path, outermost-first) +error.details[]{code,file,line,message} per level but NO fingerprint, codekindtypeoutermost code, messagedeepest cause;error!(err)plain + the http arm emit a BAREerror.fingerprint==error.code(NOT the{code}|{step_path}|{activity}shape, which comes fromStepResult::login the workflow layer) + NO errors/details; NO redaction at the render layer (http.*.bodyemitted verbatim, the no-leak guarantee is the CALLER passing None, not the formatter);error.detailshas NOattributesobject on develop (ErrorAttr is branch-only). RELATED (same session, separate, DIAGNOSED not fixed): develop’s Windows py-mando job is red on 3test_dd_conformance.pytests (test_log_error_uses_deepest_cause/_without_step_context_omits_path/_extra_does_not_override_error_fields), IndexError on emptycaplog.records= a test-isolation leak, NOT a logic bug (log_erroris a purelogger.error;dictConfigdisable_existing_loggers=True+ thelogger_statefixture not restoring per-logger disabled/propagate makes caplog stop capturing after the first caplog test); feature “pymando logging conformance” (fde2425e), fix directiondisable_existing_loggers=Falseand/or reset the dd-conformance-error logger in theerror_logfixture. → BE-4014 Datadog Error-Rendering Test Harness. - BE-3657/BE-4000: derive branch RENAMED to
feature/BE-4000+ DX v2 ASSURANCE PASS 2 (CLEAN) + standards fix-wave + opl restore on !585 (continuation of the “Error hdl” session; the final derive events of the day). (1) RENAME: the derive MR got its OWN Jira key -feature/BE-3657-deriverenamed tofeature/BE-4000(old remote deleted, new pushed); the WORKTREE DIR stays.worktrees/BE-3657-derive(historical, the branch there isfeature/BE-4000); transplant recipe nowgit rebase --onto origin/develop feature/BE-3657-phase3 feature/BE-4000. (2) ASSURANCE PASS 2 (Andras-requested, because the 07-27 five-lens pass predated the DX v2 commits): 3 fresh Opus lenses over the v2 delta86f3439f..cd5d53a7, verdict CLEAN on all SIX dimensions - compiles; NO CONFIRMED BUGS (reflexive-Fromdisjointness AND attribute-macro expand-before-derives ordering BOTH proven by SCRATCH COMPILE not just reasoning; native-birth towerinto_inner/liftsites verified level-preserving;#[track_caller]intact); spec-conformant; testable (585 lib + 15 trybuild + A/B 5 pairs + 3 location goldens); lintable (clippy 0); SOLID/DRY holds (single shared route-gen engine, the two generators collapsed into one). THREE latent no-instance edges documented: last-path-segment Error/Debug dedup could drop a customderive_more::Debugand silently change codes (but no swept enum has one); generic error enums unsupported by route-gen (pre-existing); hardcoded::thiserrorpath. OPEN JUDGMENT CALL for Andras: aninto_bare_report()helper would collapse ~52into_report().into_inner()tower sites - worth it ONLY if the unwalling phase is NOT the next MR (else those sites vanish anyway). (3) STANDARDS FIX-WAVE (the 2 standards-lens findings):479cc312(scoped rustfmt collapse of theMandoFromon_unimplemented note a v2 commit missed) +cd5d53a7(rename the two “duplicate report mapping” derive-error strings to “duplicate cause mapping” for consistency with the cause grammar + regenerate 3 trybuild.stderr); gates green (clippy 0, report_derive 8, lib 585/0); BE-4000 tip nowcd5d53a7. (4) OPL DEAD-CODE RESTORE on !585 (phase3): reviewer krisztian.fekete1’s comment 2 (opl.rscreate_orders, “why deleted?“) - Andras chose to RESTORE rather than argue; commit0427c68dre-addsOplOrder+create_orders, ADAPTED to compile against the current error-stack idiom (a raw revert would not compile - it referenced removed importsVolueAtpOrderType/TimeDeltaand old tuple error variants; mirrorscreate_strategiesexactly), still dead code (no caller, per the reviewer request); phase-3 tipee84ea50→0427c68d; the BE-4000 derive base STAYSee84ea50(transplant excludes the opl commit, no re-sync). STATUS: BE-4000 is the FINAL derive branch, DX v2 done and DOUBLE-ASSURED; !585 phase3 at0427c68dwith all 3 review comments resolved; both await !585 approval → merge → transplant → Andras’s explicit MR yes for BE-4000. → BE-4000 rename, DX v2 assurance, opl restore (2026-07-28). - BE-3657: derive branch DX OVERHAUL v2 - native
MandoReportbirth (Andras-driven SECOND DX pass, continuation of the “Error hdl” session;feature/BE-3657-derivetip86f3439f→b7b04b71, 4 commits, 21 total on baseee84ea50, pushed; each commit subagent-implemented + reviewed, wire-e2e-verified at the end; still stacked on !585, NOT yet an MR). Goal: bare?for EVERY source regardless of crate + ONE annotation per enum. DESIGN JOURNEY (3 decisions, 2 amendments, recorded in the repo derive spec’s DX v2 section): (1) blanketFromviaMandoFromapproved → E0119 vs the silentReport-to-MandoReportliftingFrom(theorphan-spike’s localFakeReportMASKED open-world coherence - SECOND spike-masking incident after the 07-27 orphan one; LESSON: verify coherence in the REAL crate, scratch crates lie); (2) explicit.lift()approved → measurement found 227 broken seams not the estimated ~11 (LESSON: implicit?seams vastly outnumber visible.into()sites); (3) FINAL - nativeMandoReportbirth:into_report()/reported()returnMandoReport/MandoResultat construction (theMandoErrorwall moves to construction itself),MandoReport’s stdErrorimpl REMOVED (the anyhow trick) making the blanket coherent, ~160 seams vanish, towers pay.into_inner()(~40-50 sites),.lift()/LiftExtsurvive only at tower-crossing edges. SHIPPED:5acd801b(native birth + blanket +.mapped()/MappedExtDELETED),8ebd6ad9(#[cause(Src1, Src2)]bare source lists replacing#[report(from/mapped)];wrapskept; strings re-frozen),4221f00b(#[mando_error]attribute macro = thiserror Error + Debug + marker + cause routes in ONE annotation; sharedgenerate_routesengine with the derive path),b7b04b71(28-enum workspace sweep;#[derive(MandoReport)]export DELETED;thiserrorimports dropped in 20 files). Reviewer empirically DISPROVED the attribute-ordering hazard (attribute macros expand before derives regardless of source order). AUTHORING SURFACE now:#[mando_error]on the enum +#[cause(HttpRetryError, serde_json::Error)]per variant + bare?at every call site any crate; wraps chains =.wrapped()?; escape hatches (.wrap/.attr/into_report/.wrapped) unchanged; towers still verbose until unwalling. VERIFICATION: A/B suite + 3 location goldens byte-identical throughout; wire e2e PASS vs86f3439f(4 event pairs, all contract fields equal incl.detailsfile+line; only 4 column-only location shifts atts_data_retrieve.rs:102mapping exactly to the lift-form change; known Volue data-group HashMap nondeterminism normalized again). KNOWN INTENDED DELTA:mando-simulatoriniterror!switched to the report arm (gainserrors[]/details[], drops fingerprint on that one non-flow path; not byte-compared - separate binary). Status: DX v2 done; branch waits on !585 merge for the transplant (git rebase --onto origin/develop feature/BE-3657-phase3 feature/BE-3657-derive) + Andras’s explicit MR yes. → DX overhaul v2: native MandoReport birth (2026-07-28). - mando-cli: always-on OTel trace capture +
mando tail(landed together, UNCOMMITTED, pending user smoke + push). Everymando upstack now shipsmando-otel-collector(contrib 0.109.0; OTLP 4317/4318, host ports via MANDO_OTEL_GRPC/HTTP_PORT) writing raw OTLP JSON NDJSON to<workspace>/.otel/traces/spans.ndjson(50MB/3 backups);OTEL_EXPORTER_OTLP_ENDPOINTinjected only-when-absent.up --datadognow ALSO ships APM (agent OTLP receiver + collector otlphttp fan-out).flow rungained--span-file(this run’s spans byflow.exec_idattr ±30s, rotated files scanned, verbatim) and--bundle <dir>(logs.ndjson+spans.ndjson+params.json = exact POST body, re-runnable via--params). Bug caught+fixed:ensure_infraran every command and hardcoded the base collector config, somando statusafterup --datadogreverted it and silently killed APM on next restart — fixed by deriving the variant from datadog overlay file presence. Newmando tail [logs|traces|all] [FILTER...] [--svc --since -f --flat]: zero query language, lines gron-flattened (nested→dotted, arrays→[i], non-JSON→raw=, scalars→value=), every term substring-ANDs an assignment; verbatim default (golden-friendly),--flatprints matching assignments only; local-only. Consolidation: ONE piped-child seam (system/logstream.rs, shared by flow run + tail), ONE OTLP walk/reader (flow/spans.rs). Tail-fix subagent died mid-edit on usage limit (half-applied sig, non-compiling); orchestrator finished inline + deleted dead remnant, both reviewers re-verified CLOSED. Gate: 532 lib + 8 integ + smoke, 0 fail; clippy 0; release 0. — mando-cli-otel-capture-and-tail-2026-07-28 - mando-cli: new
mando flowcommand group (reproducible, TEST-MATCHABLE flow execution; landed in the working tree UNCOMMITTED, pending push + live smoke).flow list/flow run <flow> [--params --date --overrides -e --no-follow --log-file --poll]/flow status <flow> <exec-id>; flows auction/intraday/data-update/as-auction-update/manual-schedule (kebab URL segments, snake_caseflow_keybody wrappers, server pins versions). LINCHPIN (cited from mando source): trigger id DB exec id every log line’s rootflow.exec_id(one Uuid); local builds ALWAYS emit dd_formatter JSON (init_loghardcodesdd_enabled=true); server pre-creates all step rows as Queued; trigger returns immediately (tokio::spawn). Follow = two layers: (1) local verbatim byte-preserved streaming via prefix-freedocker logs --sincefiltered by rootflow.exec_id, single-writer (streaming task → mpsc, poll loop sole stdout/file writer, no torn lines); (2) all-targets step digest (Success→pass/Warning→warn/Skip→skip/Error+Fatal→fail, Canceled terminal), exit 1 on Error/Fatal.--log-filetruncate+append verbatim + NDJSON digest in arrival order, mode-independent. Byte-fidelity: tokio Lines strips\n/\r, CLI re-adds\n(lossless for single-line UTF-8 JSON). Terminal conformance kv events: dd_query (@flow.exec_id:<id>, env-scoped from rendered.infra/datadog.builtin.yamlDD_ENV when the local datadog overlay is on), dd_url (DD_SITE-aware, epoch-ms bounds), started_at/stopped_at. Trace hint local+dd→Datadog / local-no-dd→generic OTel (no Jaeger UI in repo) / remote→Datadog. Plumbing: environments un-gated from the broken query feature (config/environments.rs, query behavior unchanged, same 2 pre-existing flight.rs errors); newsrc/flow/{mod,client,input,follow,dd}.rs+commands/flow.rs+ sharedsystem/datetime.rsdate recognizer;docs/flow-guide.md; skill grown to 104 lines. Review: bugs lens APPROVED outright; quality/DRY Importants fixed (dd.rs cohesion split, shared date recognizer) + 7 minors. Gate: 464 lib + 8 integration tests, clippy 0, release 0. → mando-cli-flow-run-2026-07-28.
2026-07-27
- BE-3657: derive FIVE-LENS ASSURANCE PASS + 3-commit FIX WAVE (Andras-requested full review of the whole derive branch
ee84ea50..574d757a; tip moved574d757a→86f3439f, 19 commits total, pushed; still stacked on !585, not yet an MR). FIVE parallel Opus lenses: (1) repo-spec conformance vs the derive spec + the 2026-07-15 design = CONFORMANT both directions (incl. verified NO-reqwest-route + the metis stored-sourcemapped()spec-sanctioned); (2) team-spec vslogs-and-apm.md= CONFORMANT on all 8 applicable construction rules (coded construction, no secret material, chain depth,#[track_caller], sensitive tokens retained, zero logging in construction); (3) coding standards vs AGENTS.md = CLEAN line-by-line, zero Important+; (4) adversarial bug hunt = NO CONFIRMED BUGS (all runtime behavior verified; only 5 compile-error-only robustness gaps in derive attribute tolerance); (5) DX + SOLID/DRY = DX HOLDS (every happy path strictly better, escape hatches unchanged, frozen sites byte-identical) + 2 discoverability cliffs + 1 DRY defect. FIX WAVE (commitsb5ec99f7/81fade1a/86f3439f) for lenses 4-5: (a) derive parser hardening - empty#[report()]/from()/mapped()now derive-time errors,wrapsshape validation added, 3 new frozen strings + trybuild cases (UI suite 12 → 15); (b)#[diagnostic::on_unimplemented]onMandoFrom/MandoWraps(a missing-route.mapped()/.wrapped()now tells the dev to declare the#[report]route, scratch-proven on rustc 1.89) + derive doc one-liner names the three route attrs; (c) metis DRY fix - the FROZENget_tokenhelper reuses the enum’s declared routes via the UNWRAP-AFTER-BRIDGE form (.wrapped()/.mapped()thenmap_err(MandoReport::into_inner)), removing the twice-written auth message WITHOUT unwalling the tower fn (byte-equivalent, auth-level test green). DESIGN NOTE for unwalling: that unwrap-after-bridge form could unfreeze ALL 5 frozen tower auth sites (ems/atp/mdr/opl/position_manager) with routes - recorded as an option, deliberately NOT applied beyond metis this MR. Accepted-without-action (for the record): token-string type matching in the parser, aFrom-qualification hygiene nit, the sharedfrom/mappedroute rule (by design, trybuild-pinned), theMandoReportderive-vs-type name clash (Andras’s named decision), theio::Error::newidiom in two tests, the A/B verbose-side location pin, A/B module placement inlib.rs, two team-spec latent notes (derive permits tuple shapes; markers on enums with pre-existing tuple/transparent variants), the opl/pm two-dialect note, the py-wall marker-bound hole (TODO’d for unwalling). Also: two spec sentences fixed in the repo derive spec (stalefrom(InvalidHeaderValue)wording → it ridesmapped(); stored-source exemption reconciliation). Gates at86f3439f: derive UI 15 cases, full lib 586/0/32, clippy clean. → Five-lens assurance pass + fix wave (2026-07-27, tip 86f3439f). - BE-3657: derive MR IMPLEMENTATION COMPLETE AND PUSHED (
feature/BE-3657-derive@574d757a, 16 commits on baseee84ea50, ls-remote verified; still stacked on !585, NOT yet an MR - waits for !585 to merge). Subagent-driven: the full 14-task plan + a 6-item fix wave, per-task adversarial review + a whole-branch final review on Fable (“with fixes” → fix wave → re-review approved, ZERO new issues); Tasks 1-3 (0a083ecf/c8c0370c/edf0dd32) are the first 3 of the 16. SHIPPED: mando-coreMandoErrormarker +wrap_report+ the bridge traits (MandoFrom/MandoWrapson the local enum +MappedExt/WrappedExtext traits, match-form preserving#[track_caller], nevermap_err(fn-pointer)); the#[derive(MandoReport)]proc macro (bare/from/mapped/wraps grammars, FROZEN derive-time error strings, 12-case trybuild UI suite on the=1.0.118dev-dep); enforcement (MandoErrorbounds on the 4 boundary sites + a clippyReport::newban with 2#[allow]s); six adapter sweep waves (~50 call-site collapses to bare?/.mapped()?/.wrapped()?+ a sharedUtf8BodyErroralias consolidated inutil/http_client.rs). SECOND EXECUTION DISCOVERY = the TOWER FREEZE law (after the orphan-rule pivot): sites inside raw-Report-typed tower fns cannot take the bridge collapses; auth-wrap score = 2 live.wrapped()?sites (metis_graphqlquery_events,microsoftsend_chat_message) vs 5 frozen until the unwalling phase (ems,atp,mdr,opl,position_manager), whose verbose auth ceremony survives this MR BY DESIGN (the derive-branch face of the walled-towers finding). VERIFICATION (refactor = byte-identical gate): A/B equivalence suite (5 pairs, verbose vs derived?, byte-identical); golden#[track_caller]pins for bare?AND.mapped()?AND.wrapped()?(all capture the exact call-site line on thiserror2.0.17, closing the2.0.17-vs-2.0.19spike gap); trybuild frozen strings; e2e wire byte-compare on the local rig PASS (byte-identical incl. locations; one apparent diff root-caused to per-processHashMapordering in Volue data-group selection - environmental, not a build/derive diff). GATES: clippy clean, 586 passed / 0 failed / 32 ignored lib tests, all commits title-only conventional. FOLLOW-UP BUNDLE (SDD ledger, distinct from phase 3’s): trybuild suite NOT CI-gated (test.sh--libonly; ticket to addcargo test -p mando_flow_step_derive); the clippydisallowed-macros/disallowed-methodsbans (both the oldtracing::errorone and the newReport::newone) are INERT under the workspace lint config (clippy::all=allow, no cherry-pick deny) - team should know; derive UX minors (wrapsmessage-on-unit ignored,wrapsshape classification, enum-level attr ignored); supertrait-bound polish deferred to unwalling. NEXT: wait for !585 merge →git rebase --onto origin/develop feature/BE-3657-phase3 feature/BE-3657-derive→ re-gate → MR only on Andras’s explicit yes. → Derive MR complete and pushed (commit 574d757a, 2026-07-27). - BE-3657: derive EXECUTION started (Tasks 1-3) then PIVOTED to the bridge design after the orphan-rule flaw surfaced (subagent-driven on
feature/BE-3657-derive; the major move of the day). Tasks landed review-approved: Task 10a083ecf(MandoErrormarker +wrap_reporthelper,WrapExtdelegates), Task 2c8c0370c(bare#[derive(MandoReport)]marker emission + trybuild harness;trybuild=1.0.118NEW pinned dev-dep; sanctioned collateral = a uuid serde-feature one-liner inmando-core/Cargo.tomlfixing the known standalone-build bug), Task 3edf0dd32(#[report(from(SrcType))]From-impl gen withtrack_caller, 6 trybuild cases). Task 3’s implementer surfaced THE FLAW: the 2026-07-24 spike ran newtype + enums in ONE crate, MASKING the orphan rule; a controller spike (scratchpad/orphan-spike, two-crate topology) proved in mando-lib thatimpl From<ForeignSrc> for MandoReport<LocalEnum>ANDimpl From<MandoReport<A>> for MandoReport<B>are BOTH E0117 - so bare?via From was IMPOSSIBLE for ALL wraps mappings (auth chains) and foreign sources (reqwestInvalidHeaderValue); only crate-local sources (HttpRetryError) ride bare?. ANDRAS DECIDED (option A over local-only) the BRIDGE DESIGN: mando-core local traitsMandoFrom<S>/MandoWraps<I>(the derive implements them ON the local enum = always orphan-legal) + ext traitsMappedExt/WrappedExt; call-site DX = wraps to.wrapped()?, foreign to.mapped()?, crate-local from to bare?. Grammar SPLIT:from(Src)= local only (From, bare?), NEWmapped(Src)= any source (MandoFrom),wraps(Inner, message)= MandoWraps; one route per source type per enum across from+mapped; verified compiling with correct?-residual inference. GOTCHA for posterity: ext methods must use match + direct trait-fn call, NEVERmap_err(fn-pointer)(fn-pointer coercion erases#[track_caller]- the same degradation the phase-3reported()migration fixed). Spec updated (spike finding 4, bridge layer, grammar bullets, north-star now.wrapped()?/.mapped()?, A/B pairs), plan updated (ruling 4b, Task 4 rewritten to bridge traits + wraps/mapped emission in two commits, Task 5 A/B suite, sweep tables usemapped(InvalidHeaderValue)); SDD ledger.worktrees/BE-3657-derive/.superpowers/sdd/progress.md. → Derive execution and the bridge-design pivot (2026-07-27). - BE-3657: derive spec GROUNDED (claim-by-claim audit vs
ee84ea50) + NEW A/B equivalence gate (Andras). Specdocs/superpowers/specs/2026-07-24-be3657-report-derive-design.mdaudited and corrected BEFORE any derive code: alias isMandoResult(spec wrongly described a std-Resultshadow namedResult); theMandoReport<C>newtype is already SHIPPED (report.rs:15-59, commitf771805e) so mando-core work SHRINKS to the marker trait + awrap_reporthelper + bounds (not a from-scratch newtype); emitted paths are::mando_core::report::module paths (crate root has ZERO re-exports, stays that way); the “enum stays Clone / flatten keeps working” claim corrected (only 6 of ~20 participating enums are Clone, the derive changes no Clone status); north-star example dropped its wrongClonederive (realVolueEmsErroris not Clone). RULINGS ADDED: multiple#[report]attrs per variant allowed; from-scope forbidsfrom(reqwest::Error)(sanctioned sources =HttpRetryError+InvalidHeaderValueonly); frozen derive-time error strings; clippydisallowed-methodsis a NEW key with exactly 2 sanctioned#[allow]sites; test-enum marker required in the flip commit; the thiserror2.0.17-vs-2.0.19spike gap closed by a golden test;trybuildas a new=-pinned dev-dep with a Nexus-availability caveat. NEW REQUIREMENT (Andras): the derive MUST emit BYTE-IDENTICAL output to the verbose forms it replaces (a refactor, not a behavior change) - spec gained an “A/B equivalence gate” section and plan Task 5 grew a concrete suite: per grammar arm (from-display, from-source-stored, wraps-message, wraps-unit, attr-chain) build the same failure through the verbose form AND the derived?path, assertreport_codesequal +report_detailsdeep-equal after stripping per-level file/line +render_stack_treeequal after dropping location lines (locations asserted separately per form); by-construction backing = derivefrom()calls the sameinto_reportas the closures and derivewraps()calls the samewrap_reportthatWrapExt::wrapdelegates to; failures are derive bugs, never assertion loosenings; per-adapter equivalence carried by these pairs + the golden e2e wire gate, no verbose twins kept in adapters. Spec and plan now aligned and grounded; derive EXECUTION still awaiting Andras’s go. → derive(MandoReport) MR started, stacked off phase3. - BE-3657: MR !585 REVIEW ROUND 1 (krisztian.fekete1, 3 comments) + ebs upload_file out-of-scope revert. First review pass, breaking the run of zero comments; all three are questions. (1)
mando-bess/src/lib.rsMANDO_DEBUG_MOCK_ERRORdebug_erroremitter ininit_router: “do we want this in the production code?” - Andras pushing back in-thread (env-gated, default off, DD-pipeline verification tool; the known veto path = phase-3 flagged-default 2). (2)opl.rscreate_ordersdeletion: “why was this deleted?” - answer (Andras in-thread): dead code, ZERO callers on develop (git grep verified, only self-references), removed in the opl sweep64d04625with theOplOrderstruct (theme-2 precedent). (3)ebs.rsupload_filerestructure: “is this change really needed?” - reviewer RIGHT, the SMB share/UNC/user hoist was an out-of-scope mix-in from the SMB fix branch (Andras: “its not in scope for this you are right, it got mixed in from the SMB fix branch”); FIXED by commitee84ea50“refactor: restore ebs upload block layout” -upload_file’s diff vs develop is now ONLY the error-shape hunks (tuple to named +into_report) plus theMandoResultsignature; the hoist, the share/upload_path.attr()enrichment, and the branch-added testupload_file_carries_samba_code_and_share_contextall removed (ebs test module matches develop exactly). Gates green (clippy clean, 574 lib tests); pushed, ls-remote verified; MR !585 head nowee84ea50(was4df2562a). NOTE: EBS errors no longer carry the share/upload_pathattributes; re-adding WITHOUT the hoist is possible later. Also:feature/BE-3657-derivefast-forwarded4df2562a→ee84ea50(still zero own commits); transplant recipe switched to the BRANCH-NAME formgit rebase --onto origin/develop feature/BE-3657-phase3 feature/BE-3657-deriveso future tip moves stop invalidating pinned shas. → Review round 1 (2026-07-27, krisztian.fekete1). - BE-3657:
error.stackREVERTED to error-stack’s default Debug tree (Andras; RE-REVISES the 2026-07-24 Caused-by-chain renderer, which had revised the 2026-07-15 locked decision 3 - effectively back to that decision’s original direction). Commite813a84c“refactor: restore default error stack rendering” onfeature/BE-3657-phase3(MR !585, head nowe813a84c, pushed + ls-remote verified). Stack = default indented tree via the ErrorCode debug hook (ASCII, no color, full-path codes per frame; the hook plumbing1f9cd611had deleted is restored); the Datadog list-view newline-collapse quirk that motivated the custom renderer is ACCEPTED as display-only. Deliberate asymmetry survives:error.details[].codestays SHORT (4e519269kept), stack frames carry FULL-path codes. Revert had conflicts vs the three later branch commits, hand-resolved by a subagent; gates green (clippy clean, 578 lib tests; known-flaky scheduler testshould_fire_inner_job_through_rundouble-fired once, passed 3/3 in isolation). → error.stack reverted to the crate default tree (commit e813a84c). - BE-3657:
MandoReportname FINAL (newtype + derive) +derive(MandoReport)MR STARTED, stacked off phase3 (Andras).MandoReportchosen overTrace/ErrChainfor both the mando-core newtype (already shipped in !585,f771805e) and the derive#[derive(MandoReport)]; zero rename churn. The derive MR is now in progress on branchfeature/BE-3657-derive(worktree.worktrees/BE-3657-derive) cut off the phase-3 tipe813a84crather than waiting for !585 to merge (the derive needs the phase-3 report API only on that branch); transplant at !585 squash-merge =git rebase --onto origin/develop e813a84c feature/BE-3657-derive(lineage survivedrebase --ontotwice, patch-id verified). MR !585 through 2026-07-27: still open, still ZERO review comments,not_approvedthe only gate. → Format decisions reverted, name locked, derive MR started (2026-07-27). - BE-3657: SHORT-CODE decisions REVERSED to full path (Andras reversed his own 2026-07-23/24 short-code direction). Commit
4df2562a“refactor: restore full path error codes” onfeature/BE-3657-phase3(the NEW MR !585 head, pushed + ls-remote verified), revertinga58df341(shorterror.code) +4e519269(shorterror.details[].code). Nowerror.codeANDerror.details[].codeare FULL module path again, uniform witherror.kind/error.type/error.errors/error.fingerprint- the short/full split is gone entirely. Clean revert + ONE follow-up import fix; theshort_error_codePascalCase-segment helper DELETED with its tests (zero references workspace-wide). Gates green: clippy clean, 575 lib tests passed / 0 filtered (down from 577/579/580 as the split-pinning tests went with the helper). DD-CUTOVER CONSEQUENCES (reverse the 2026-07-23/24 shrink notes):@error.details.codefacet is full-path now; the legacy-monitor sweep is back to FULL impact (nothing resembles the legacy short codes); the “full-path-kills-mobile-readability” team-spec sentence (logs-and-apm.mdline 100) is UN-WITHDRAWN and needs RE-RAISING with the team. → Short codes reverted to full path (commit 4df2562a). - BE-3657: derive branch REBASED + error-postfix question RESOLVED.
feature/BE-3657-derivehad ZERO own commits so it fast-forwardede813a84c→4df2562a; transplant recipe at !585 squash-merge is nowgit rebase --onto origin/develop 4df2562a feature/BE-3657-derive; the derive implementation plandocs/superpowers/plans/2026-07-27-be3657-report-derive.md(repo, untracked) was updated for the new base + full-path code assertions. Andras’s “were the_reportpostfixes removed?” question answered on-branch: all*_reportedop-twin fns are GONE (~35 flat twins deleted by seam collapsef771805e); the 13*_error_from_reporttower-flattening converters REMAIN BY DESIGN (the walls - flat consumers flatten reports at fixed-error tower edges; removal deferred to the tower-unwalling/services phase); the 5 dead conversion fns were already deleted on the branch. → derive(MandoReport) MR started, stacked off phase3, Error postfix question resolved (*_reported gone, *_error_from_report by design).
2026-07-24
- BE-3657 error-authoring DX overhaul: 3-commit decision series (Andras), north star = error reporting must not break Rust’s natural flow,
?is the API (feature/BE-3657-phase3now headf771805e, ~27 commits, pushed, riding MR !585). (1)f5beabd4“refactor: adopt report vocabulary for error authoring”:new_coded/CodedExt/change_context_codedDELETED workspace-wide, replaced byToReport::into_report(error-stack 0.8 already exports anIntoReporttrait, henceToReport; the method name stays unambiguous),Result::reported(),.wrap(),.attr(k,v)sugar,flatten_reportfor Clone enums (6 conversion fns became one-liners); 307 sites swept across 37 files; BONUS FIND: 20map_err(new_coded)fn-pointer sites - the exact#[track_caller]-losing form - had degraded locations until this commit. (2)4e519269“feat: shorten error detail codes”:error.details[].codegoes SHORT (details = the human panel,file:linecarries precision);errors/kind/type/fingerprintstay full path; split pinned by a test asserting both forms in ONE emission. (3)f771805e“refactor: collapse adapter seams into native report signatures”: the dual*_reportedseam pattern (Andras: “not fit for a codebase this big”) ELIMINATED, ~35 flat twins deleted; bare newtypeMandoReport<C>(Report<C>)in mando-core (Deref,as_report,into_inner, delegating Display/Debug,std::error::Errorwith source None, plainFrom<Report<C>>enabling?auto-lift,MandoResult<T,E>alias); adapters ONE fn per op returningMandoResult; ~50 consumer edits (flatten at tower edges); ems towers keepError = Report<VolueEmsError>internally (into_innerat 5 sites); 5 dead conversion fns deleted per the branch’s own theme-2 precedent. REVISES phase-3 locked decision 2 (seam replication): the once-rejected native-signatures alternative adopted; the walled-towers exception stands but the seam mechanics are gone. Gates: 580/0 workspace lib tests, clippy clean. → Error-authoring DX overhaul (2026-07-24). - NEXT BE-3657 MR designed + spec’d:
#[derive(MandoReport)](docs/superpowers/specs/2026-07-24-be3657-report-derive-design.md, untracked): derive-generatedFromimpls so error handling becomes plain?-#[report(from(SrcType))]display-mapping default (preserves the Clone/message architecture),#[report(wraps(Inner, message = "..."))]chain levels,MandoErrormarker trait bounds at boundaries + clippy ban onReport::new. Spike (scratchpad/spike-trackcaller, rustc 1.89.0, error-stack 0.8.0) PROVED: directFromimpls onReport<LocalEnum>are orphan-blocked (E0117, the naive design is dead), but through the local newtype#[track_caller]propagates?-site locations EXACTLY (without the attribute they degrade to thefrombody) - Andras had offered to sacrifice site tracking for ergonomics, no sacrifice needed. Spec grounding pass caught two design regressions pre-implementation:from(Src)must display-map (source fields would kill Clone/flatten),wraps()needs an explicit static message for struct variants. → Error-authoring DX overhaul (2026-07-24). - BE-3657 local LIVE error stream operational + 2 Datadog operational gotchas: server on 8081 (build carrying the DX batch) with a CONTINUOUS forwarder shipping error/warning lines to Datadog EU within ~5s under
env:dev-local-levander(MANDO_ENVIRONMENT=dev-local-levandernow set AT SOURCE - no forward-time ddtags rewrite); complete field contract verified live: code short, errors full, details codes short per level, fingerprint full, Caused-by stack, nested http blocks on 5xx paths. GOTCHAS: Datadog facet queries with::in the value MUST be quoted (@error.code:"VolueEmsError::ApiError"; unquoted silently matches nothing); the 2026-07-23 session’s survived server instance held port 8081 so the new launch died AddrInUse while the old build’s old-format emissions kept flowing - diagnose with lsof on the port + the holder’s binary path. → Error-authoring DX overhaul (2026-07-24), mando-local-host-run-recipe-2026-07-23. - mando-cli:
bess-os-algo-forecast-as(Project::AsForecast) REMOVED as obsolete (Andras’s call; working tree, uncommitted). Compiler-driven: enum variant + slug/aliases + config default YAML deleted; builtin profiles (mocked-algos/full/fast-dev) now 4 services; e2e + docs truth pass (README five repos/two algos, skill table, datadog guide). LESSON: removing an enum variant used as a persisted-state map key broke.bessstate.jsonbackcompat — a stale"AsForecast"key fails the derivedHashMap<Project,_>deser and theunwrap_or_defaultfallback silently WIPES the whole projects map; caught because the first implementer removed the e2e fixture “so it would deserialize” (the dodge was the tell). Fix: per-key tolerantfilter_known_projectsmirroringsave()’s PascalCase keys viaProject::deserialize(NOTfrom_alias),warn!per dropped key, red-green tested, fixture restored as regression guard. Verified: dead-slug user profiles fail cleanly, leftover dirs ignored. Gate: 403 lib + 8 integration, clippy 0. → mando-cli-as-forecast-removal-2026-07-24. - mando-cli
--datadoglocal log shipping ACCEPTED — Andras confirmed acceptance after a live run; logs land in Datadog EU as designed. Note’s Acceptance section moved pending→confirmed. → Acceptance. - NEW DECISION (Andras):
error.stackswitches to a custom “Caused by” chain renderer (REVISES the 2026-07-15 locked decision 3 “crate’s own tree, codes as sub-lines, accepted trade-off”; the once-rejected prefix style is now adopted after seeing the tree in the real DD UI): Datadog collapses newlines in several views and the error-stack crate’s ASCII connectors (|-, lone|,|->) turned into unreadable pipe soup. New per-level format:{short code}: {message}head (first level bare, subsequent prefixedCaused by:),at file:line:columnlocation line,with key = valueperErrorAttr; opaque attachments no longer mentioned. Implemented as commit1f9cd611onfeature/BE-3657-phase3(new MR !585 head, 23 commits, pushed + ls-remote verified):render_stack_treerewritten to walk frames likereport_details; crate debug-hook plumbing (install_debug_hook,Charset/ColorMode,HOOK_INIT) deleted as dead; 579/0 workspace lib tests incl. an exact multiline golden pin; verified LIVE locally and forwarded to Datadog (env:dev-local-levander2026-07-24 events carry the new stacks AND the shorterror.codetogether). Datadog research backing it (worth keeping): Error Tracking for logs needs error status + service + (error.kindOR a validerror.stack) and mando always emitserror.kind, so stack format never gates tracking/grouping; DD’s “valid stack trace” bar wants at least two lines with one meaningful frame carrying a FUNCTION NAME + filename, and error_stackLocations have no function names, so mando stacks can never be frame-parsed regardless of format; thesourcetag auto-parses only conventional language stacks; log remappers relocate attributes but do not parse. Conclusion recorded: mando’serror.stackis purely presentational - optimize for human readability and graceful newline-collapse (which theCaused by:separators survive). → error.stack Caused-by renderer decision (2026-07-24). - Standing “bess-am migrations MR” dev-DB crash-loop hazard RESOLVED with no action needed (tracked since the 2026-07-22 error-handling handover; verified 2026-07-24). The throwaway dev-deploy commit
6bc418cdhad added exactly two migrations relative to its develop merge-base (2026_Q2/U202605131400__create_event_table.sql+2026_Q2/U202605141900__create_kinesis_checkpoint_table.sql); both are now onorigin/develop, brought in by3ebcc897“feat: add bess-am POC” (feature/BE-2262-bess-am-poc, merge6fae64a5, 2026-07-23).mando-bess/database/on6bc418cdandorigin/developare byte-identical (git ls-tree diff), so develop-built images now carry a superset (identical set) of what dev’srefinery_schema_historyhas applied and the refinery “missing from the filesystem” crash-loop for develop-based dev deploys is gone. The three standing-warning callouts (Dev Deploy, BESS AM, Mando Deployment Ceremony notes) marked resolved; repo handoverdocs/superpowers/HANDOVER-error-handling-2026-07-24.mditem 4 already updated. Same session also verified MR !585 (BE-3657 phase 3, headf771805e) still open, zero comments,has_conflictsfalse against develop even after the BE-3685 mergedaf6b6df, head pipeline success, only gate =not_approved. → Dev Deploy 2026-07-14 (error telemetry), BESS AM (BE-2262) - mando-bess-am, Mando Deployment Ceremony, BE-3657 error_stack Adoption.
2026-07-23
- mando-cli JSON output + agent skill VALIDATED (2-judge pass → PASS): live-behavior judge ran the debug binary with side-effect-free commands and confirmed 6/6 observable contracts (per-line NDJSON,
resultalways-last on success AND error paths, exit code ==result.code,MANDO_OUTPUTexact-match —"JSON"falls through to human mode, human byte-behavior unchanged, stdout purity under stderr redirect,--jsonposition-independent/global=true); fix-closure judge confirmed all 4 inline fixes CLOSED with line evidence + clean standards census (0 comments, 0 non-test unwraps, SKILL.md 64 lines), gate green incl. release-profile 0 warnings and query unchanged at 2 pre-existing errors. Report.agents/council/2026-07-23-vibe-json-output.md; awaiting user commit. → Validation. - (evening) BE-3657 phase 3 IN REVIEW: MR !585 OPENED - “feat: adopt error stack across all adapters”, description
Closes BE-3657(GitLab default),feature/BE-3657-phase3→developat heada58df341(22 commits), no conflicts, branch pipeline green on the same sha; reviewers krisztian.fekete1 / gabor.nagy6 / balint.budavoelgyi / jozsef.nagy1. Head commit = the shorterror.codeimplementation, so it rides the review. → MR !585 opened (2026-07-23 evening). - mando-cli JSON output mode + agent skill (working tree, UNCOMMITTED) -
mando --json <cmd>/MANDO_OUTPUT=json(flag wins, exact-match"json") switches all Element-rendered output to terse NDJSON on stdout (kv/step/err/dataevents + an ALWAYS-LAST{"t":"result","ok","code"}frommain.rs’s single exit path); human mode byte-identical, spinners suppressed, child/compose chatter + logs/exec stay on stderr. One pure mapper (src/ui/json.rselement_to_event) covers all 21 commands via the Element seam,format!-built fort-first key order (payload keys alphabetical,preserve_orderoff). Agent skill at.claude/skills/mando/SKILL.md(64 lines, token-minimal: grammar + minimal invocations + error→remedy map + frugality rules). Review caught a fabricated port-conflict remedy sourced from a TEST fixture (replaced with real workspace-lock contention row), 3 wrong subcommand tables (migrate/profile/volume), an emitterless{"t":"warn"}grammar (removed — warnings aresteps:"warn"), andmock -pposition (before subcommand). Gate: 401 lib + 8 integration tests, clippy 0, release warnings 0, query feature unchanged. → mando-cli-json-output-agent-skill-2026-07-23. - (evening) NEW DECISION (Andras):
error.codegoes SHORT, everything else stays full path -error.codenow carriesEnum::Variant(e.g.VolueEmsError::AuthenticationError; bare struct name when variantless) per the team spec’s line-100 mobile-readability intent;error.kind/error.type/error.errors/error.detailscodes/error.fingerprintALL stay full module path. Implemented as commita58df341(the MR !585 head):short_error_coderesolver in mando-core (PascalCase-segment heuristic, valid due to house naming), applied at the 4 macro emission sites only (span/boundary layers inherit as passthrough), split pinned by testkind_type_fingerprint_stay_full_while_code_goes_short, 577/0 workspace lib tests; verified LIVE in the local run and forwarded to Datadog (env:dev-local-levander). Consequences: the “mobile readability rationale is dead” pending team sentence WITHDRAWN (conformance restored); DD cutover impact for@error.code-keyed assets shrinks (short form resembles legacy codes);@error.sourceconfirmed RETIRED (renamed toerror.messagein the redesign, pinned by a mando-core regression test) - any facet/monitor still keyed on it must be deleted or rekeyed to@error.message/@error.errors(Andras hit exactly this today: an emptyerror.sourceconsumer, since fixed by him). → Short error.code decision (2026-07-23). - MR !580 (BE-3657 phases 1+2) MERGED (squash
de7cd4c6, merge4c3442df, ZERO review comments). The pending DD cutover checklist (facets@error.fingerprint/@error.errors/@error.details.code+ monitor inventory for short codes / flathttp.*/ exact message “Failed running step”) becomes actionable with the first develop-based dev deploy carrying it. → BE-3657 error_stack Adoption. - BE-3657 phase 3 EXECUTED subagent-driven (2026-07-22 evening through 2026-07-23) on
feature/BE-3657-phase3: 14 tasks + a final whole-branch review, every task under an adversarial spec + quality review; initially stacked on the in-review !580 headab8cfd11, laterrebase --onto develop(zero conflicts, patch-id byte-identical); 20 commits, final HEADe0184bc3, PUSHED (ls-remote verified), CI running, NO MR yet (awaits Andras’s explicit yes). Delivered: mando-coreErrorAttr+ per-levelerror.detailsattributes +error_attr_valueone-level nesting +report_first_attachmentoutermost-wins pick +with_reporthttp roll-up; ALL in-scope adapter groups migrated with*_reportedseams and exhaustive no-wildcard*_error_from_reportconversions; full tuple/transparent elimination (final sweep: zeroerror(transparent)inmando-lib/src/adapter, archiver included); auth providers first under the hard no-bodies/no-tokens rule with sentinel leak tests everywhere; PyO3map_report_errorforward plumbing (wiring grep-proven unreachable this phase); sharederror_json_field_valuehook unifying dd_formatter + both python package log formatters; env-gated report-backed mock (MANDO_DEBUG_MOCK_ERROR, default off) replacing the dev-deploy branch’s hardcoded-JSON mock. KEY FINDING (formal spec exception): onlyvolue/emscarries Reports to the step boundary in production (its towers now useError = Report<VolueEmsError>); the other SEVEN adapter groups are WALLED (service towers fix flat error types +pub(crate)seam visibility makes cross-crate wiring structurally impossible), so their rich chains flatten at legacy wrappers until a services-phase tower restructure; every wall independently verified genuine during review. Fix waves on 3 tasks (dead-code deletions per review theme 2: opl dead order code, et3000 + position_manager dead variants); final fix wave de-transparented 4 remaining variants after the reviewer ruled line 157 absolute (transparent named-source singles duplicate the inner level’s message inerror.details). Gates ate0184bc3: workspace clippy exit 0, 574 lib tests passed / 0 failed (--libCI parity), transparent sweep zero, noCargo.lockchurn, 61 files +4390/-1482 vs develop; py-mando/py-mando-simulation pytest deferred to CI (no local venv, Nexus VPN-gated). Follow-up ticket bundle (final reviewer’s triage): auth-provider PRE-EXISTINGinfo!/debug!body logs (real leak surface),ErrorAttrids on non-success terminals only, py delegation tests CI-only,data_platformAWS env test panic-safety, oplclear_strategiesmissing portfolio attr,map_errclosure-form drift; plus the standingflight_end_to_endone-liner + mando-core standalone uuid/serde fix. develop since moved (6fae64a5, merge offeature/BE-2262-bess-am-poc): branch 1 merge behind, pre-MR rebase possible when the MR gets the go. → BE-3657 error_stack Adoption, mando-ci-lib-only-test-gate-2026-07-22. - New CI-gate companion lesson: per-crate task gates miss consumer crates - BE-3657 phase 3 task gates compiled
-p mando_libonly, so 2 tuple-syntax construction sites in themando-simulatorconsumer crate stayed invisible until the final whole-branch review caught them as a Critical; workspace-widecargo clippy --release --all-features(no-p) is the only gate that catches cross-crate fallout, so branch-level gates must always be workspace-wide. Recorded next to the--libgate discovery. → mando-ci-lib-only-test-gate-2026-07-22, BE-3657 error_stack Adoption. - mando-cli
--datadogguide tested end to end (VERDICT: accurate, every claim verified):docs/datadog-guide.mdat tipc2becf1exercised fully. Verified: all four fail-fast paths (DD_API_KEYunset/empty, unresolvable/unsanitizable username) with the exact documented messages and zero docker interaction; agent renders only with the flag; results rowdatadog / env dev-local-levander; ONLYmando-*containers tailed (DD_CONTAINER_INCLUDE_LOGS=name:^mando-.*/ EXCLUDE.*, unrelated containers ignored); 103 logs shipped to the EU org; teardown holds at both levels (flag-offupremoves the agent via--remove-orphans,downcleans everything). GUIDE GAP:env:dev-local-<user>ridesDD_ENVHOST metadata and Datadog’s host-tag join takes up to ~10 min for a brand-new agent host (~8 min observed), so fresh logs are initially untagged (query byservice:/container_name:only, tag lands retroactively); Verifying section should say “wait a few minutes”. HAZARD: a stale pre-feature~/.local/binbinary reporting the SAME 0.4.0 version silently swallows--datadogas a service arg and starts a REALup(the flag-position warning can’t protect; suggest a guide version-check note). Key acquisition: the Alpiq Standard Operations Datadog role LACKS “API Keys Read” (org key page blocked; Personal Settingsddpat_/ddapp_tokens do NOT work asDD_API_KEY); working route = AWS Secrets Manager secretDdApiKeySecret-pkeeEykkaqu3via profilebessos-dev(aws sso login+get-secret-value; source: optimization-universe-iacterraform/secret.tf/ CI varDATADOG_API_KEY_SECRET_NAME); Logs Search APIapi.datadoghq.eu/api/v2/logs/events/searchworks with that key + addapp_app key. Nit: new mando-cli error strings use em dash characters. → 2026-07-23 end-to-end guide test. - BE-3657 phase 3 telemetry VERIFIED LOCALLY end to end (real runtime, not tests): phase-3 branch binary (
b394e0d4, rebase-descendant ofe0184bc3, built in.worktrees/BE-3657-phase3) run as a HOST process againstmando up --datadog -p infra(postgres + wiremock + local-dd-agent). Verified: boot mock (MANDO_DEBUG_MOCK_ERROR=true) 4-level report witherror.errors(4 full-path codes) +error.details(real file:line +attributes,data_groupon the top level) +error.stackbox tree incl. theErrorAttrsub-line and the opaqueHttpContextattachment + codekindtype full path + root-cause message + trace correlation; Volue EMS spot single-level fingerprintcode|step_path(data_update.load_battery_momentary_data,spot_data.rs:79, static-first boundary message); Volue EMS retrieve TWO-LEVEL auth chain in production (VolueEmsError::AuthenticationError+VolueEmsAuthenticationProviderError::FailedRequest,ems.rs:217+ems_auth_provider.rs:155- the final-review auth level confirmed live); Metis full-patherror.codewith NOerror.errors(walled-tower flattening, mixed world as designed); dd_formatter real nested JSON via the shared parse hook. 12 error lines to Datadog EU via DIRECT INTAKE (env:dev-local-levanderservice:bess-os-service-mando; host processes invisible to the local dd agent’smando-*filter). Server left RUNNING on localhost:8081 (health 200);mando down+pkill mando_bessto stop. → Local end-to-end verification (2026-07-23). - NEW: local mando HOST-PROCESS run recipe captured from the verification gauntlet (pre-existing friction, team-valuable):
.cargo/config.toml.exampleis STALE (MANDO_FLOW_ACTIVE_VERSIONdead; wantsMANDO_SETUP_ACTIVE_VERSION=V1_4+MANDO_SETUP_SCHEDULER_DISABLED, prefixMANDO_SETUP, config-crate style;FINGRID_API_KEYmust be non-empty or init panics via unwrap “must contain at least one key”); postgres cert loader reads<cwd>/certs/eu-central-1-bundle.pem(workspace-root runs need a certs symlink tomando-bess/certs; one left untracked in.worktrees/BE-3657-phase3); infra pg credsbess_transactional_db/postgres/postgres @ localhost:5432; MIGRATION RACE between mando’s refinery (DuckDbPostgres mode) and the mando-cli migrations container applying the same set (idle-in-transaction lock pileup wedges boot,move_schema_objectsblocked; recovery =pg_terminate_backendon the idle holder + drop public/data/bess_os cascade + single-writer relaunch;MANDO_MODE=DuckDbskips mando-side pg migrations but the stale container set lacks the setting table, so use DuckDbPostgres);MANDO_PORT=8081(wiremock owns 8080), adapter hosts at localhost:8080 for hermetic 404s. → mando-local-host-run-recipe-2026-07-23 (new note). - Epilogue to the local e2e: the first Datadog forward silently VANISHED (202-accepted, never indexed) - Datadog’s JSON-message parsing PROMOTES the embedded
ddtagsfrom the log line itself; mando emittedenv:local(fromMANDO_ENVIRONMENT=local), overriding the intake envelope’senv:dev-local-levander, and the org does not indexenv:localevents at all. Fix: rewrite the embeddedddtagstoenv:dev-local-levanderbefore forwarding. DURABLE RECOMMENDATION recorded in both notes: local mando runs setMANDO_ENVIRONMENT=dev-local-<user>so emitted ddtags align with the local agent’s env tag (embedded ddtags win over host/env tags on JSON lines, so even a containerized local mando fights the agent’s tagging the same way). Isolation stake: the shared Alpiq org carries REALenv:prodtelemetry under the sameservice:bess-os-service-mando, so the per-developer env tag is the ONLY wall from production views. → Epilogue (2026-07-23): the vanishing first forward, mando-cli-datadog-local-logs-2026-07-22.
2026-07-22
- (evening) Full 4-judge council validated the whole uncommitted mando-cli tree → PASS after one fix round: judges = error-paths, spec-compliance/desired-output, DRY/SOLID, Alpiq-standards; report
.agents/council/2026-07-22-vibe-mando-cli.md(repo). The two Important findings were emergent cross-block seams invisible to per-block reviews (process learning): (1) Datadog flag-offremove_file(...).ok()+ existence-driven compose inclusion meant a failed delete silently restarts the agent on plainmando up— now non-NotFounddelete errors abort with an actionable message; (2)remove_named_volumesrendered Fail rows but exited 0, violating the same session’sexit_on_failureconvention — nowResult<bool>threaded through volume clear +down --volumes. Also fixed: sharedsystem/path::normalize(dedups preflight/init),runtime/paths.rsextracted from thebuild_args.rsgrab-bag, wiremock fetch status guards,http.rspanic→fallback,install.rs300s download cap, preflight skips COPY sources escaping build context, teardown warns. Standards verdict: 0 non-test unwraps, 0 unsafe, format-args clean, Datadog feature BE-3482-conformant (no mando-cli-specific standards doc exists — validated against org DD conformance + mandoAGENTS.md). Final gate: clippy ZERO, 395 lib + 395 bin + 8 integration + smoke, 0 failures. User-only remaining: junk-file cleanup before commit, manual Datadog acceptance. → Validation pass (evening). - (afternoon)
mando up --datadoglocal log-shipping feature landed in the working tree (uncommitted by design — user commits manually): new mando-cli flag that ships a localmando uprun’s error/log telemetry to the real Datadog EU UI to verify BE-3482 Datadog Logs and APM Conformance’sdd_formatterJSON end-to-end (no local→Datadog logs path existed — dev ships via awslogs→CloudWatch→forwarder Lambda; ECS DD agent sidecar is metrics/APM only). Usage:export DD_API_KEY=<key>; mando up --datadog(flag before service args); logs taggedenv:dev-local-<os-username>(sanitized lowercase),DD_SITEdefaultsdatadoghq.eu,upprints adatadog / env dev-local-<user>status row; flag-offupormando downstops shipping (uppasses--remove-orphansso the agent is removed). Acceptance: Datadog Logs explorerenv:dev-local-<you>→service:bess-os-service-mandowitherror.code/error.fingerprint(service tag from bodyddtagsoverrides infra enrichment;dd_formatterddtagscarries NOenv, so agentDD_ENVis authoritative). Mechanism: new templatesrc/runtime/templates/infra/datadog.yml(agent:7,container_name local-dd-agentso thename:^mando-.*include filter can’t match the agent itself; APM/process-agent off; docker.sock + containers mounts) rendered to.infra/datadog.builtin.yamlonly when--datadog;compose::assembleincludes it existence-driven (optional, NOT inINFRA_BUILTIN_FILESto avoid missing-file warns); flag-offupdeletes it. KEY GOTCHA: template MUST use${DD_API_KEY:-}not${DD_API_KEY:?}— compose interpolates on EVERY verb, so:?empirically hard-failsmando down/logsin any shell without the var while the agent file exists (verified live, docker compose 28.5.2, both directions); the up-sideresolve_datadog_envprecheck is the sole guard. Also extractedbuild_args::atomic_write_with_dirunifying 3 write sites (override_gen’swrite_overridebecame atomic as a side benefit). Specdocs/superpowers/specs/2026-07-22-datadog-local-logs-design.md, plandocs/superpowers/plans/2026-07-22-datadog-local-logs.md; triple review caught the:?footgun (Important, fixed + re-verified CLOSED); gate: build clean, clippy zero, 392 lib + 8 integration green. → mando-cli-datadog-local-logs-2026-07-22 (new note). - (afternoon) mando-cli audit fix Block 5 (features) landed in the working tree (uncommitted by design — user commits manually): made the two parsed-but-ignored
mock upflags real, added a clean-clone preflight guard, recorded the default-profile decision, and corrected a false audit claim.mock up -p/--port <n>now injectsWIREMOCK_PORTinto the compose child env (template publishes${WIREMOCK_PORT:-8080}:8080), warns via acompose portcheck if the container already runs on a different port, and targets all admin calls at the requested port.mock up --dir <path>now waits for WireMock readiness (30s cap), resets mappings, then loads sorted*.jsonstubs via admin API with per-file Pass/Fail rows and nonzero exit on any failure (baremock upunchanged). NEWsrc/runtime/preflight.rs— Dockerfile COPY-source guard wired intoupandbuild(runs after cargo prebuild so it can’t block its own remedy); on a clean clonemando upnow fails fast with the exact fixes (mando build mando --mando=artifact --cargoor--mando=pull) instead of a confusing docker COPY error; handles comments (incl. inside line continuations),--fromstages, wildcards,$vars, JSON-form COPY, best-effort skips unreadable files. Decision: default profile mando stays →build, NOT flipped to pull (pull.ymlresolves registry-less${MANDO_IMAGE:-mando:dev}to a bare Docker Hub ref and private ECR needs login — flipping would trade one clean-clone failure for another). Audit correction: the “mock resetdoes NOT clear the request log” claim was WRONG —WireMockBackend::resetDELETEs/requeststoo;mock-guide.mdnow truthful-to-code (also fixedmando down wiremock→mando down mando-wiremock). Triple review approved, 0 Critical/Important, 4 minors fixed (fetch_stub_countdelegates tolist_stubs; newWIREMOCK_CONTAINER_PORTconst;down()usesWIREMOCK_SERVICE; comment-inside-continuation parsing + test). Gate: build clean, clippy ZERO, 385 lib + 8 integration + smoke, 0 failed. → Fix status. - (afternoon) mando-cli audit fix Block 4 (over-engineering cleanup) landed + session wrap (uncommitted by design — user commits manually): executed the ponytail cut list and cleared the known-red clippy baseline. Deps dropped:
bollard,bytes,tar,log,comfy-table. Files deleted:runtime/docker_client.rs,workspace/git/git.rs,network/manager.rs,workspace/projects/{algo,dash,iac}.rs. bollard inspect replaced bydocker inspect --format '{{json .}}'shell-out —status --detailedverified byte-identical by reviewer. Single-impl traits collapsed:MockBackend→concreteWireMockBackend,MigrationRunner→FlywayMigrationRunner,ProjectContext→inherent fn,JoinProjectinlined. Dead per-project wrapper layer + 5 never-readMandoWorkspaceProjectfields deleted; query-feature schema typescfg-gated. Clippy baseline 8 errors → ZERO under-D warnings. Session totals: 4 blocks, 20 audit findings fixed + 4 review-caught issues (incl. an ETXTBSY self-update hazard caught in review); whole tree 43 files changed +815/−998; final gate verified: build clean, clippy zero, 361 lib + 8 integration + smoke all green. Open decisions in repo ledger.superpowers/sdd/progress.md: broken pre-existing--features querybuild (flight.rsvs mando-core drift), unimplemented simulator-runtime spec,mock --dir/--portstub flags, default-profile clean-clone gap; remaining LOW sweep + doc mismatches unfixed. → Fix status. - (afternoon) mando-cli audit fix Block 3 (data safety) landed in the working tree (uncommitted by design — user commits manually): hardened data-safety paths. Bug #15 — flyway Postgres connections now built via one shared
pg_config()usingtokio_postgres::Configtyped setters at all 3 sites (hostile spaces/quotes/backslashes can no longer break libpq keyword parsing). Bug #16 —apply()runscheck_flywaybeforeensure_history_table, no longer mutating a Flyway-managed DB before bailing. Bug #34 —ensure_databaseonly CREATEs on a genuinely empty result, real errors propagate. Bug #17 — git clone token moved off argv intoGIT_CONFIG_COUNT/KEY_0/VALUE_0env (not visible inps; needs git ≥2.31). Bug #18 — self-update cross-device path stages into the destination dir + atomic rename, fixing both non-atomic overwrite of the running binary and ETXTBSY on Linux tmpfs (reviewer-caught Important on first impl, re-verified CLOSED). Bug #19 — new sharedatomic_write(temp with pid+seq, rename) protects.bessstate.jsonandhost-procs.jsonfrom torn writes. Bug #10 — workspace lock probe treats EPERM as alive (no stealing live locks from other users); ESRCH predicate shared viakill_stderr_is_esrch. Triple review approved. Gate: 362 lib tests green, clippy unchanged at 8 baseline errors (Block 4, in flight, will clear them). Parked:REPO_PYMANDO_TOKENstill a docker build-arg (build_args.rs:95, pre-existing);.bess-credentials.jsonwrite_restrictedstill non-atomic; locale-sensitive ESRCH match leaves stale locks uncleared under non-EnglishLC_MESSAGES. → Fix status. - (afternoon) mando-cli audit fix Block 2 landed in the working tree (uncommitted by design — user commits manually): closed the
--volumes/volume clearno-ops, the hardcoded stub-count port, the missing-timeout cluster, and both WireMock findings. Bug #7 —mando down <svc> --volumesnow honored (named volumes discovered viadocker inspect+ removed, anonymous viacompose rm -v). Bug #8 —volume clearreordered tocompose rm -s -fbeforevolume rm; container discovery for bothdownandclearnowcompose ps -aqvia a sharedservice_container_idshelper (wasps -qrunning-only — the block’s one Important review finding, re-verified CLOSED). Bug #11 —statusstub-count resolvesWIREMOCK_PORTenv (mirrors compose${WIREMOCK_PORT:-8080}) with 2s/3s timeouts. Bugs 13 — all reqwest clients now carry timeouts via newsystem/http.rsclient(connect,total)helper (wiremock/check 2s/5s, rest 5s/60s, install connect-only 10s to protect slow downloads). Bug #14 —wiremock.enable()renamedverify_service_stubs(never toggled state, no CLI caller; validation-only semantics made truthful vs speculative admin-API toggle). Bug #30 —wiremock.reset()now checks HTTP status on both admin calls. Triple review approved. Accepted minors:WIREMOCK_PORTenv-file vs shell-var divergence,rest.rs60s hard cap on previously-unbounded queries. Gate: 347 tests green, clippy unchanged at 8 known-baseline errors. → Fix status. - (afternoon) mando-cli audit fix Block 1 landed in the working tree (uncommitted by design — user commits manually): closed both HIGH findings + the three exit-0-on-failure MEDIUMs. Bug #1 mass-kill —
host_process::stop()now rejectspid <= 1before signaling, guard in the sharedstop()so all callers covered (down.rs×3,up.rscleanup). Bug #2 orphan leak —up.rswraps read+merge+recordpersistence in a result-capturing closure and SIGTERMs all just-spawned pids on ANY persistence failure before propagating. Bugs 5 —migrate/get/pullexit nonzero via a sharedexit_on_failure(bool)helper incommands/mod.rs→CommandError::Exit(1). Triple review (quality/bugs/dup) approved, re-review closed residuals. Known-red clippy baseline: 8 pre-existing dead-code errors inschema.rs/backend.rs/project.rsdeferred to the over-engineering block. Parked:host-procs.jsonnon-atomic write; command-level exit-code wiring untested. → Fix status. - (evening) BE-3657 phase 3 PLANNED + approved by Andras (execution NOT started, gated on MR !580 merging): scope locked to “plumbing + adapters” (rejected: plumbing-only, full workspace breadth); mechanics = seam replication per the Volue pilot (
retrieve_ts_data_reported/send_request_reported/volue_error_from_reportinadapter/volue/ems/ts_data_retrieve.rs; rejected: native Report signatures, boundary-only wrapping); keeps riding BE-3657 (branchfeature/BE-3657-phase3off develop AFTER !580 merges, one phase = one MR; subagent-driven per house rule). Conformance pass against Balazs’s team spec (architecture-designdoc/content/doc/ops/logs-and-apm.md@ main, fetched 2026-07-22) tightened the design: line 157 absolute (ALL tuple/transparent variants in migrated enums restructured);error.detailsgains the spec’sattributesfield (lines 150-155) via a new mando-coreErrorAttrattachment + extraction landing BEFORE any adapter migrates; line 159 http roll-up = outermost-wins pick of the report’sHttpContextattachment withwith_reportfillinghttp_contextwhen unset (“force with a macro” wording read positionally → pending team-sentences list); auth provider migrations under a hard sensitive-data rule (lines 121-124: no bodies, no tokens, method/url/status only). Adapter order grounded on the branch: auth providers first (alpiq/authentication + volue ems/atp auth) → volue/ems completion (spot + send join the pilot) → volue/atp → alpiq/ebs (SMB, no http roll-up, share/path ErrorAttr) → alpiq mdr/opl/data_platform/et_3000 → fingrid → alpiq/metis → mando group (rest/algo/simulator/ms_teams/microsoft) → alpiq/position_manager. Two vetoable defaults flagged:adapter/mando/archiver(+ postgres submodule) DEFERRED to the repos phase (data-plane, separate CI harness, no step boundary); startup mock deep error PORTED to mainline mando-bess behindMANDO_DEBUG_MOCK_ERRORdefault-off (one IaC dev env line at deploy, droppable on team objection). New planned mando-core surface (task 1):ErrorAttr(String, serde_json::Value),error_attr_value,report_first_attachment,report_detailsentries gainattributes, sharederror_json_field_valueunifying the error.errors/error.details JSON parse across dd_formatter +py-mando/src/log_formatter.rs+py-mando-simulation/src/log_formatter.rs. Specdocs/superpowers/specs/2026-07-22-be3657-phase3-adapters-design.md, plandocs/superpowers/plans/2026-07-22-be3657-error-stack-phase3.md(15 tasks, untracked). → BE-3657 error_stack Adoption. - (afternoon) Full mando-cli codebase audit documented (~18.7k lines, four parallel passes, no fixes applied): 37 verified bugs (2 HIGH — unguarded
kill -TERM -{pid}mass-kill risk with nopid<=1guard inhost_process.rs:108-133, and orphaned untracked host processes whenhost_process::recordfails inup.rs:262-270; 18 MEDIUM, 17 LOW). Recurring themes: exit-code-0-on-failure (migrate/get/pull), missing reqwest timeouts everywhere,wiremock.enable()a silent no-op. Plus a −280-line / −5-dep over-engineering cut list (drop bollard/bytes/tar/log/comfy-table, collapse single-impl traits), 9 duplication clusters (biggest: compose-context prologue copy-pasted across 8 command files →compose::prepare), the simulator runtime spec being entirely unimplemented on main, and several mock-guide doc/code mismatches. Confirms the uncommitted piped-output fix (opts.rs/compose.rs) is correct but still lacks a commit + regression test. Source:.agents/research/2026-07-22-audit-mando-cli.md. → mando-cli-full-audit-2026-07-22 (new note), mando-cli-v0.4.0-compose-bugs-triage-2026-05-26, mando-cli-v0.4.0-piped-output-invisible-failures-2026-06-25, mando-cli-simulator-runtime-2026-05-30. - (afternoon) MR !578 MERGED; BE-3657 rebased onto the merge: Andras merged !578 (squash
46a9be1b“feat: enrich trace spans with error and http attributes”, merge4a0d297f= new develop tip, 0 review comments).feature/BE-3657then ranrebase --ontodevelop4a0d297f: all 13 commits replayed zero-conflict, head2baea68abecame22ccae93, patch-id verified byte-identical to the reviewed content; branch CI pipeline2696324182on22ccae93success. The BE-3657 MR now waits ONLY on Andras’s explicit yes. → BE-3656 APM Span Enrichment, BE-3657 error_stack Adoption. - (afternoon) DD_SERVICE env fix appended to BE-3657 (commit
ab8cfd11“fix: read dd service name from env”; Andras asked to sneak it into the upcoming MR): the hardcodedbess-os-service-mandoin mando-lib replaced by aDD_SERVICEenv read with the old value as fallback (also on empty string);resolve_dd_service()+ OnceLock-cacheddd_service()inmando-lib/src/app/mod.rs(app-gated), all 6 hardcode sites routed through it (OTel Resourceget_tagging,dd_formatter.rsddtags, 4 rawglobal::meterliterals inservice_base.rsx3 +util/http_client_trace.rsthat bypassed the old const); inline test covers default/empty/override. Deployment-neutral: IaCbess_os_ecs.tf:218ALREADY setsDD_SERVICE = "bess-os-service-mando"on the mando container, so this closes the mando-side root cause of the FR unsuffixed service name. Branch pushed, headab8cfd11ls-remote verified; clippy clean, 516 lib tests passed / 0 failed. → BE-3657 error_stack Adoption, fr-region-missing-datadog-logs-2026-07-21. - (afternoon) Discovered the CI test gate is
--lib-only; integrationtests/targets rot silently (new note):.gitlab/scripts/test.shrunscargo test --all-features --release --lib -- --test-threads=1, so*/tests/targets are NEVER compiled by the pipeline (the separate “Integration Test Linux Dev” job covers only the mando-lib archiver Postgres suite). Concrete rot:mando-bess/tests/flight_end_to_end.rscompile-broken on develop itself (E0603:DataPointUpdateInfoviamando_lib::serviceprivate use, since the mando-repository crate splitb3ce27a8); local gates must use--libfor CI parity; pending one-liner fix (import frommando_core::model::datapoint) to be its own change on Andras’s yes, NOT part of BE-3657. AGENTS.md updated in 4 places + a new landmine row; mirror resynced. → mando-ci-lib-only-test-gate-2026-07-22 (new note), Mando CI-CD, Mando AGENTS.md Master Guide, Mando AGENTS Guide (mirror). - Error-handling merge train completed + vault caught up (covers 07-16..07-22): MR !569 merged (fingerprint activity, squash
b3f39605, merge53912a70, by 07-15), MR !570 merged (pymando-v2 DD conformance, squashfde2425e“feat: pymando logging conformance”, merge14dfb3ad; conformant wheelpy-mando==1.16.1+dev.2691658359.14dfb3adpublished to Nexus dev), MR !571 merged (BE-3541 Single Error Emission: squashd1cf9c75removeslogged_at_site/logged(), one boundary emission withHttpContexton the error; develop tip1c4c33a5); develop since moved toe2ff6b79via the unrelated BE-3685 merge. BE-3482 deferral list re-ranked (1 merged, 2 in review as !578, 3 verified, onlyflow.step.timeout_msopen); Agent Context error-handling row corrected (constructor API changed). → BE-3541 Single Error Emission (new note), BE-3482 Datadog Logs and APM Conformance, BE-3482 pymando Branch Review. - MR !578 open for BE-3656; BE-3657 phases 1+2 built and pushed: !578 “feat: enrich trace spans with error and http attributes” on head
8f50ef2a(3 commits, zero-conflict rebase onto post-!571 develop1c4c33a5), pipeline green, reviewers krisztian.fekete1 / gabor.nagy6 / balint.budavoelgyi / jozsef.nagy1, mergeable with 0 review comments as of 07-22.feature/BE-3657@2baea68a(13 commits atop8f50ef2a, pushed, rebased 07-21; 3 develop-inherited bare-code fallback tests aligned to full-path expectations, squashed into “feat: use full module path in error code”); gates green via the workspace build graph, standalonecargo build -p mando_corebroken by a PRE-EXISTING BE-3643 uuid/serde issue; MR only after !578 merges + Andras yes, thenrebase --onto develop. Decisions updated in the note: boundary template FLIPPED static-first"{static}: {outermost}[: {chain}]"(07-16), bodies never on spans (spec deviation, raise with team),error.errors/detailsexcluded from span tags, first-error-wins guard, nestedhttp.request/response; plus the pending DD cutover at BE-3657 merge (create facets@error.fingerprint/@error.errors/@error.details.code; inventory monitors keyed on short codes, flathttp.*, exact message “Failed running step”). → BE-3656 APM Span Enrichment, BE-3657 error_stack Adoption. - Dev prototype verified in Datadog + BE-3613 code complete (VPN-blocked): dev runs throwaway
1.16.1-feat.2682437891.b7d15e2c(BE-3541 + BE-3656 + BE-3657 phases 1+2 + full-path codes + startup mock deep error + nested http + static-first message +flow.step.system); verified nestederror.details(4-level chain, real file:line),error.errorsarray queries (element/wildcard/negation), nestedhttp.{request,response}shape, trace correlation (sample0dc8d42739a08ac0805808b2d14b6644); mock fires once per task boot, still on the typederror!arm with hardcoded JSON. BE-3613 (algo services onto the conformant wheel) code COMPLETE onbess-optimization(bb0555e/d47212d/71fb146) andbess-forecast-day-ahead(50231b6/927e1e5/e1d5ade+ fork-test deletions), author fixed, branches UNPUSHED, blocked ONLY on VPN/Nexus forpoetry lock --no-update && poetry install && poetry run pytest; catalog names bess-os-algo-optimization / bess-os-algo-forecast, forecast-as OUT of scope. → BE-3657 error_stack Adoption, BE-3613 Algo Services py-mando Conformance (new note). - FR logs now reach Datadog but with unsuffixed service name: mando hardcodes
DD_SERVICE = "bess-os-service-mando"(mando-lib/src/app/mod.rs:38) into the per-lineddtags, which wins over the forwarder’s-frlog-group tag enrichment; all infra tags verified correct; fix belongs in mando (readDD_SERVICEenv with constant fallback). → fr-region-missing-datadog-logs-2026-07-21.
2026-07-21
- Implemented the FR Datadog log-forwarder fix + learned the IaC feature-branch dev-apply trick: seven
dd-logs-forwarderblocks added tomodules/bess_os/cloudwatch.tfon IaC branchbugfix/fr-datadog-log-forwarders(commitc169afc, asset_simulator block count-gated); forwarder module + Lambda policy verified before deploy;terraform_apply:devisonly: [develop], so a temporary CI commit (8592eeb) added the branch regex (drop before merge, mirrors mando AGENTS.md 14.3); watch for develop-based apply reverting the live FR 1.16.1-feat image + asset-simulator drift; bit-tf-modules source clones via ssh only. → fr-region-missing-datadog-logs-2026-07-21. - Root-caused why FR (France) region services have NO logs in Datadog (read-only AWS + IaC analysis, fix not applied): the dev-only
module "bess_os_fr"(terraform/bess_os_fr.tf,region_code = "fr", account 794038257734) instantiates the extractedmodules/bess_osmodule whosecloudwatch.tfcreates the-frlog groups but carries ZEROdd-logs-forwarderblocks; the top-levelterraform/cloudwatch.tfhas one forwarder module per original log group, so the four original/aws/ecs/bess-os/eu-central-1/dev/*groups each have a subscription filter to thedatadog-forwarderLambda while the four-frcounterparts have none (FR services ARE writing to CloudWatch, last events ~27 min old). The forwarding step was dropped at module extraction. Fix direction: mirror the top-leveldd-logs-forwarderinstantiations insidemodules/bess_os/cloudwatch.tf(sibling exemplar:modules/bess_am/ecs.tfDatadog Log Forwarding section). → fr-region-missing-datadog-logs-2026-07-21. - AWS CLI access switched to AWS Identity Center (SSO), replacing saml2aws (verified on Andras’s mac).
~/.aws/confignow has[sso-session alpiq-sso](start URLhttps://identitycenter.amazonaws.com/ssoins-69878836cb6e09c7,sso_region = eu-central-1, scopessso:account:access) plus fourDeveloper-role profiles in eu-central-1:bessos-dev794038257734,bessos-test071128452852,bessos-int621553445748,bessos-prod282467977019 (the same accounts as theAGENTS.mdsection 14.1 deployment matrix). Oneaws sso login --sso-session alpiq-ssobrowser PKCE login covers all four; verified withaws sts get-caller-identity --profile bessos-dev→assumed-role/AWSReservedSSO_Developer_.../andras.lederer@alpiq.com. Gotcha: the RTK shell hook manglesawsoutput (printsAWS: ? ?), so prefix every aws call withrtk proxy. Gotcha: to enumerate accounts/roles before profiles exist, takeaccessTokenfrom the newest~/.aws/sso/cache/*.jsonand useaws sso list-accounts/list-account-roles --access-token $TOKEN --region eu-central-1. eu-west-1 is a read-only IdC replica (a fallback[sso-session alpiq-sso-dub]could be added, not configured);~/.saml2aws(AzureAD) left in place but unused. Practical use: dev/prod ECR + ECS access for mando deployments. → AWS CLI Access via Identity Center.
2026-07-16
- Error-handling night: BE-3656 deployed + verified live, BE-3657 spec’d + phase-1-planned, dev prototype iterated to full-path codes + queryable arrays +
flow.step.system. BE-3656 (APM span enrichment) is now DONE/reviewed/pushed with a third review-hardening commita0735ebb(3 commits total off BE-3541 headdee24ad3; bodies excluded from spans as a deliberate spec deviation, first-error-wins marker guard sinceset_attributeappends under the 128-attr cap,u64try_from, shared OTel test helpers); verified live in Datadog (error.*on errored step spans + Error Tracking pickup,http.*on GET/POST client child spans, log output byte-identical); STILL NO MR (needs Andras’s explicit yes). Dev runs throwaway buildd17227ac(branchfeature/BE-3482-dev-deploy, NEVER merge; IaC pin1.16.1-feat.2680023002.d17227ac, applied 02:07Z): full-path error codes (error.code= full module path), a startup one-shot 4-level mock deep error fired each boot in adebug.mock_deep_errorspan (mando-bess/src/debug_error.rs),error.errors/error.detailsas real JSON arrays via a targeteddd_formatterrecord_strparse of exactly those two field names, andflow.step.systemcherry-picked from !570 (7f3db1ed). Datadog array-attribute queries VERIFIED working (element match, wildcard, object-field, numeric, negation); facets still to create (Andras click):@error.errors,@error.details.code,@error.fingerprint. BE-3657 (fullerror_stack=0.8.0adoption) LOCKED and spec’d: principle “leave what we can to error_stack” (mando adds only theErrorCodefull-path attachment viaCodedExtatchange_context/newsites + extraction fns +error!(report=...)arm); field contracterror.code==kind==type==outermost full-path code,error.errors= codes array,error.details=[{code,file,line,message}]; crate’s own tree rendering with codes as attachment sub-lines; boundary message template"{outermost}: {static}: {chain}"; phase-2 annotation direction#[error_meta(event_type, resolution step, business_message, description)]→ details enrichment + resolution-doc codegen (Andras’s own later work, phase 1 must not preclude). Branchfeature/BE-3657DOES NOT EXIST YET, start off BE-3656 heada0735ebb; spec/plan underdocs/superpowers/{specs,plans}/2026-07-15-*error-stack*; status planned, awaiting go. Three new tooling landmines recorded: Bash cwd resets to the main checkout between calls (a worktree cherry-pick ran on the wrong branch, phantom conflicts), RTK proxy garbles grep/sed output (ground-truth with Read on absolute paths),grep "test result" | tail -1is a cargo-test false green (shows only the last binary). → BE-3656 APM Span Enrichment, BE-3657 error_stack Adoption, BE-3482 Datadog Logs and APM Conformance.
2026-07-15
- Implemented BE-3656 APM span enrichment (branch
feature/BE-3656, 2 commitsa64f9457+6d4f4395stacked on BE-3541 headdee24ad3, pushed, NO MR yet), closing deferral item 2 of BE-3482 (error.*/http.*on trace spans). NewSpanEnrichmentLayerinmando-lib/src/app/span_enrichment.rscopieserror.*/http.*off ERROR-level tracing events onto the active OTel span as Datadog APM tags;instrumented_http_clientrecordshttp.method/url/status_code/version+ request/responsecontent_lengthonce per logical send on the final outcome (success/4xx/final failure); bodies only via error events perlogs-and-apm.md“Only Error” column. Log output byte-identical (8/8 error-macro + 39/39 workflow capture tests); gates green (455 passed, only the 2 known TEST_PG_HOST archiver failures). Four reusable tracing/OTel Layer gotchas recorded: (1)tracing::Span::current()is EMPTY insideLayer::on_eventunder awith_defaultscoped subscriber (scoped-dispatch reentrancy guard), readopentelemetry::Context::current().span()instead (correct in both scoped tests and prod via tracing-opentelemetry 0.32context_activation); (2) opentelemetry_sdk 0.31 in-memory exporter is::trace::InMemorySpanExporternot::testing::trace::; (3) tracing-opentelemetry 0.32 already setsStatus::error("")on ERROR events, layers must not; (4)OtelData.stateispub(crate), only public write path isOpenTelemetrySpanExt::set_attribute(appends, DD keeps last, 128 attr limit). Spec + plan under repodocs/superpowers/{specs,plans}/2026-07-15-be3656-*. → BE-3656 APM Span Enrichment, BE-3482 Datadog Logs and APM Conformance. - Documented a wall-clock-dependent CI flaky test discovered while shepherding MR !570:
scheduler::tests::firing::should_fire_inner_job_through_run(mando-bess/src/scheduler.rs:327, introduced by develop3a8b8f84). The test adds an every-minute cron counter job to a LIVE started scheduler, callsSelfHealingJob::run(), sleeps 100ms, thenassert_eq!(counter, 1); if the ~2s window crosses second:00of a wall-clock minute the real scheduler ALSO fires the job, counter becomes 2, exact-equality assert panics (observed left:2 right:1 at 09:08:00.656, exactly a minute boundary; same SHA passed an hour earlier). Remedy: retried the failed CI job on pipeline2678118132, passed; fix deliberately NOT in !570 (zero-unrelated-changes rule). Proper fix needs a follow-up ticket: either don’t add the counter job to the started scheduler, or relax toassert!(counter >= 1); secondary latent flake is the 100ms sleep being too short on a loaded runner (would fail with 0). → mando-known-flaky-tests-2026-07-15, Mando CI-CD.
2026-07-14
- Hand-deployed the BE-3482 error telemetry to dev (throwaway-branch ceremony on BOTH repos), diagnosed a NEW dev crash-loop class, and got the first live telemetry validation. Goal: get the MR !569 content (fingerprint activity + version-fallback panic fix) flowing on dev while the MR awaits review; dev was nominally on pre-conformance
1.15.0-dev.2655042609.3024e20c(live task labels showed1.15.0-feat.2664534358.627578d7from an earlier hand-applied feature deploy). Mechanism: throwaway mando branchfeature/BE-3482-dev-deploy(NEVER to be merged) = develop tip51d2b516+ the two !569 cherry-picks + one CI commit (branch added to Publish Service Docker Devonly:AND the PyMando Win Devneeds/dependenciesentry commented out; that job is absent on feature branches and a dangling need kills pipeline creation). IaC: branchfeature/error-hdloff IaC develop; bumpedcomponents.dev_test.mando.version; second commit “ci: enable dev apply from error-hdl branch” adds the branch toterraform_apply:devonly:(apply normally exists ONLY on develop); both commits temporary, strip if ever merged. Crash-loop: first apply crash-looped mando withMigrationError::PatchApplicationFailed: migration V202605131400__create_event_table is missing from the filesystem; root cause: dev’srefinery_schema_historyholdsU202605131400__create_event_table+U202605141900__create_kinesis_checkpoint_tablefrom the UNMERGED BE-2262 bess-am/kinesis POC branches (deployed to dev in May as a feat build), so any image lacking those files fails refinery validation at boot; the inverse of the BE-1595 drift case, merging develop cannot fix it. Fix: restored both files byte-exact (single canonical blobf45b6dd4across all source commits, satisfies refinery checksums) as6bc418cd“fix: restore bess-am migrations present in the dev database” → image1.16.1-feat.2674882859.6bc418cd→ re-bumped pin →Apply complete!(4 added / 19 changed / destroys 5 → 4). STANDING WARNING (open action): any develop-based image crash-loops on dev until the two bess-am migration files land on develop (small MR, recommended) or dev’s refinery history rows are cleaned. Telemetry validated from the crash itself:error.code==error.kind==error.type(spec-verified: architecture-designlogs-and-apm.mdlines 87-104 mandate three same-value fields for APM/logs/mobile),error.message= root cause,error.stack= source chain (wrapper-embeds-source Display pattern causes cosmetic text duplication),error.fingerprintabsent as expected for non-step errors; follow-up idea recorded: emit a bare-code fingerprint from the Rusterror!macro outside flow steps (matching py-mando’slog_error), needs one sentence added to the standard. Plan-reading lesson: the version bump’s “17 add / 19 change / 5 destroy” plan was IaC develop drift catch-up (12 genuinely new resources: thebess_os_frincoming_synclambda stack + 2 RDS analytics SG rules) plus immutable task-def replacement mechanics (all destroys were “must be replaced” task definitions), not danger. Ceremony doc updated (PyMando Win Dev needs gotcha, IaC-side apply trick, standing-hazard callout, observed pins); BESS AM + BE-3482 notes cross-updated. → Dev Deploy 2026-07-14 (error telemetry), Mando Deployment Ceremony, BE-3482 Datadog Logs and APM Conformance, BESS AM (BE-2262) - mando-bess-am.
2026-07-13
- Documented the mando deployment ceremony (all facts verified from code in
/Volumes/bandi/coding/poc/optimization-universe-iac+ mando.gitlab-ci.yml; also recorded as new section 14 of the untracked mandoAGENTS.md). Two-repo ceremony: mando CI publishes docker images; optimization-universe-iac (terraform, ECS) decides which version runs where; NEVER deploy from mando alone. Env matrix: 4 envs to 2 component groups interraform/main.tf(dev+test →dev_test, int+prod →int_prod); IaC branch rules: dev/test plan+apply fromdevelop(plan also on feature/bugfix branches), int fromrelease/*, prod frommain; ALLterraform_applyjobswhen: manual; ECR:dev_test→843164609896.dkr.ecr.eu-central-1.amazonaws.com/poc/mando/deploy,int_prod→748634852998.dkr.ecr.eu-central-1.amazonaws.com/poc/mando; int_prod naming trap reconfirmed (historically INT, not real prod). Deploy-to-dev: merge to mandodevelop→Publish Service Docker Dev(only:exactly develop + rc/*) pushes{version}-dev.{pipeline_id}.{short_sha}(the+of APP_VERSION becomes-in docker tags, e.g.1.11.0-dev.2555942905.50575825) → on IaCdevelopeditterraform/terraform.auto.tfvars.jsoncomponents.dev_test.mando.versionto the tag (observed commit convention “feat: bump component versions”) →terraform_plan:devruns on push, review the plan artifact (expected change: mando container image in the bess-os ECS task def ONLY) → manually triggerterraform_apply:dev. Feature-branch trick: temporarily add the branch to theonly:list of Publish Service Docker Dev, publish, bump tfvars; MUST drop/revert that CI commit before the MR merges (reviewers reject unrelated changes; leaving it in would publish on every future push). Runtime config without rebuild: per-env mando config (MANDO_FLOW_SCHEDULE_*crons,MANDO_FLOW_ACTIVE_VERSION,EBS_SMB_HOST,SIMULATION_MODE, CPU/memory, notification channels) lives in IaC.gitlab-ci.yml.environment-vars:{env}blocks flowing toTF_VAR_*; constraint:MANDO_FLOW_ACTIVE_VERSION(V1_4 in all envs) must name a setup version existing in mandoconfig/flows/manifest.yaml, bump together. Post-deploy verification:GET https://mando.{env-domain}/versionequals the bumped tag (also returns component versions);/health200; swagger loads; Datadog sidecar logs onerror.kind+ refinery migration lines at boot (failed migration = most common bad deploy); dev runs SIMULATION_MODE=true; scheduled flows land Success/Warning not Fatal; local pre-deploy E2Etest/pi1/end-to-end.py. Observed onrc/1.11.0: dev_test at1.11.0-dev.2555942905.50575825, int_prod at1.10.0-2533146896.b06b6b59. → Mando Deployment Ceremony. - Mined all 21 of Andras’s mando MRs for review patterns (!322 through !558; 17 merged / 2 closed / 2 open; read-only glab API): 108 reviewer notes (krisztian.fekete1 87, gabor.nagy6 13, balazs.mracsko.alpiq 7), distilled into a new “Recurring review feedback” section of
/Volumes/bandi/coding/poc/mando/AGENTS.md(untracked). Nine themes: (1) zero unrelated changes in the diff, revert incidental churn / drop unrelated commits (!437/!474/!495/!548/!556); (2) delete ALL unused code before review, the most repeated complaint (frustration quote !345); (3) failures are ERRORS never warnings:mando_core::error!with an error-code enum variant,Fatalfails the execution, NO custom error message strings (the error’sto_string()IS the message, human context in themessagefield; 15+ “should be error” comments + policy from balazs, !481); (4) placement: route helpers next to routes,modrows grouped, util code inutil, name modules for what they are (!322/!345/!556); (5) completeness before review: no “you forgot this”/“half done”, mirror sibling configs like data groups (!362/!437); (6) green pipeline + no conflicts before assigning review (!345/!474/!558); (7) rustfmt every new file (!556, gabor); (8) keep the Jira ticket in sync with what was actually implemented (!437); (9) idioms: import errors frommando_core, nothiserror::path prefix, nounwrap(parse at build time or returnResult, !345), bind the service once vs per-type match duplication (!556). Config direction: NEW config goes toconfig::ConfigoverEnvconfig(two reviewers, !556); existing adapters keep envconfig. New dictated rules codified in the guide: commits title-only with NO scopes and no descriptions (no-scope rule reviewer-mandated in !322), commit every ~3 tasks in short form, never use em dashes anywhere (entireAGENTS.mdpurged of them), always subagent-driven development without asking. → Mando MR Review Patterns. - Rebuilt
AGENTS.md(round 2) —/Volumes/bandi/coding/poc/mando/AGENTS.mdfully rebuilt against the trueorigin/developtip92bfe1c8(2026-07-09, v1.16.0) via 5 re-run researcher agents on a dedicated worktree at.worktrees/develop; localdevelopfast-forwarded and now tracksorigin/develop— the round-1 “guide reflects stale merge-base8bbd407e” caveat is obsolete, the Jul-8 drift (4 new crates +flow_registry.rsrestructure + v1.16.0) is folded into the guide proper incl. recipe E. New verified facts: (1)FlowStepService(mando-flow-step/src/lib.rs) is a construction trait, NOT execute()-style —type Params: ParamMeta; type Response;+ asyncfrom_config(config: &str, providers: &StepProviders);StepProviders(src/providers.rs) carries flow_repository, data_point_registry, 6 auth providers, simulation_enabled; 36type_entry!registrations inmando-bess/build.rs; param structs derive#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ParamMeta)]; (2)config/flows/manifest.yaml= deployment catalog (setup: {version}: flows: {name}: {path, schedule_env, semaphore_group}) — schedule env vars + concurrency groups live in the manifest not code, semaphores capacity 1/group; (3) error redesign PARTIALLY landed (ae6d1098):error.message=root cause,error.stack=source chain,error.fingerprint={code}|{step_path},ErrorWithStepStatus.logged_at_sitedouble-log guard (new()/logged()); NOT landed:error.trace,.step_context();docs/error-handling-redesign-plan.md+doc/errors.jsonNOT tracked; (4) py-mando-simulation split (3559042d, BREAKING):py_mando.SimulationRunnerGONE → new package (Python ≥3.11, ships ddtrace, no polars/pandas); both packagesinit()at import (JsonFormatter + rustls ring), libduckdb preload (ctypesRTLD_GLOBAL/add_dll_directory), build.rs copieslib/libduckdb/1.4.2→data/platlib; (5) second sanctioned async bridge:pyo3_async_runtimes::tokio::future_into_pyfor*_asyncawaitable variants (alongsideallow_threads+block_on); (6) rustfmt: import-grouping/comment opts inrustfmt.tomlare nightly-only, silently ignored on stable 1.89; tip NOT fmt-clean; grouping maintained by hand;format!positional ~3:1 over inline (inline = review rule for new code); (7) new crates (mando-flow-step/-derive, mando-bess-lib, py-mando-simulation Rust side) have ZERO tests (1 Python integration test); CI gained “PyMando Simulation Linux Dev” (pytest, no--nbval) + simulator docker publish child pipeline; (8) no MR/issue templates, no CODEOWNERS. Process:agentops:researchersubagents can’t SendMessage — reports via scratchpad files or transcript extraction (~/.claude/projects/<project>/<session>.jsonl, longest assistant text); 1 of 5 v2 researchers (style) died early, scope hand-verified. Vault reconciled: Agent Context (tip hash, crate rows, manifest/type_entry!, error row, fmt warning, CI jobs) + guide note provenance rewritten. → Mando AGENTS.md Master Guide. - BE-3482 continuation: merge state verified, orphan fix flagged for salvage, fingerprint ACTIVITY component built (unpushed). Verified
feature/BE-3482(DataDog logs/APM core conformance) MERGED via MR !558 as squashae6d1098on 2026-07-08 (30 files, +402/-173, merge commitc2b7d401; origin branch deleted); the 2026-07-02HANDOVER-BE-3482.mdis stale on ALL state claims; all 7 delivered field items confirmed on develop tipa01892f9. Orphan commit478cd993(Jul 9, “fall back to crate version when LOG_METADATA.version is None”) exists ONLY on the localfeature/BE-3482branch: addsdd_formatter::app_version(), removes 3 panicking unwraps in mando-bess (api_docs.rs,flow/get_versions.rs,route/version_route.rs); it is the fix for the known “develop panics mando-bess locally” issue; salvage = cherry-pick onto a fresh branch off develop as a small MR, do NOT resurrect the old branch (contains a merge commit, review-rejected shape); worktree.worktrees/logs-apm-conformance-core+ local branch archivable only after the salvage decision. New work:error.fingerprintACTIVITY component per the authoritative standard (architecture-design repologs-and-apm.md: fingerprint = error.code + flow.step.path + specific activity, e.g. Volue EMS data group id) on branchfeature/BE-3482-fingerprint-activity(worktree.worktrees/BE-3482-fingerprint, single title-only commit6f541363): activity is a runtime value so it ridesErrorWithStepStatus(activity: Option<String>, consumingwith_activity()builder, all constructors default None so behavior is bit-identical when absent); privatefingerprint()helper emitscode|path|activityorcode|pathwith no trailing separator; reference wiring inmando-lib/src/service/volue/ems/ts_data_send.rs(every per-data-group error carries the data group name; real win: DA and AS schedule failures in the auction scheduling step no longer collapse into one Datadog error group); 3 new capture tests, clippy 0 warnings, suite green (mando_lib 254 passed,--test-threads=1); NOT pushed, no MR, awaiting Andras. Known limit: at-site-logged variants (VolueEmsError::ApiError) reach the boundary as WARN with no fingerprint at all, so activity is stored but not emitted there until the single-emission migration (own future ticket). Ranked remaining deferrals: single-emission migration (biggest win, unlocks fingerprint+http on at-site errors) >error.*/http.*on trace spans > verifydd.trace_idcorrelation in DD >flow.step.timeout_ms. → BE-3482 Datadog Logs and APM Conformance. - Field-verified:
cargo fmt -- <file>does NOT scope (it touchedapi_docs.rs, which was never named on the command line). New prescription:rustfmt --edition 2021 <file>; every form ofcargo fmtis banned.AGENTS.mdsections 2.3, 10, 13.5 + the landmines table updated; Mando AGENTS Guide (mirror) resynced; the fmt warning in Agent Context and correction #3 in the guide note amended. → Mando AGENTS.md Master Guide, BE-3482 Datadog Logs and APM Conformance. - BE-3482 orphan salvage RESOLVED: folded into the fingerprint branch. Andras chose to fold
478cd993intofeature/BE-3482-fingerprint-activityinstead of a separate MR; cherry-picked asbc3727ba(“fix: fall back to crate version when LOG_METADATA.version is None”, scope dropped from the title, author preserved andras.lederer@alpiq.com). The branch now has 2 title-only commits (6f541363+bc3727ba); gates re-run on the 2-commit branch: clippy exit 0, tests 387 passed / 0 failed across 22 suites (single-threaded); still NOT pushed, MR awaiting Andras. The old worktree.worktrees/logs-apm-conformance-core+ localfeature/BE-3482branch are now purely historical and archivable. → BE-3482 Datadog Logs and APM Conformance. - New field-verified landmine: the RTK shell hook guts
cargo test. The hook rewritescargo test --all-features --release -- --test-threads=1so the threads flag becomes a test-name filter: every test is filtered out and the command exits 0 in 0.00s (output 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, and 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 mandoAGENTS.mdsection 10 + the landmines table; Mando AGENTS Guide (mirror) resynced; warning callouts added to Agent Context and the guide note. → Mando AGENTS.md Master Guide, BE-3482 Datadog Logs and APM Conformance. - Reviewed
feature/BE-3482-pymandoread-only: NEEDS REWORK BEFORE MR (13 commits offdevelop@3024e20c, worktree.worktrees/BE-3482-pymando, judged against mandoAGENTS.md; zero mutations made). The conformance work itself is solid and the gates are genuinely green: clippy clean, 366 passed / 0 failed / 35 ignored viartk proxy, andmando_libbuilds with--no-default-featuresAND with--features python(provingfmt_utilneeds noappfeature). Three blockers (~30 min total): (1) 13/13 commit titles carry scopes, banned per MR !322; (2) 7 orphaned ContextVars + dead set/reset lines inpy-mando/python/py_mando/tracing.pyafterd528b71fremoved their only reader; (3) commits86d7ffd8+34e749d5are off-ticket AND byte-identical duplicates ofbc3727baon the fingerprint branch. Notable should-fixes:error.fingerprintserializescode|Nonewhen no step context (tracing.py:109); deadtracing-serdedep inpy-mando/Cargo.toml; fmt_util extraction only 2/3 done (py-mando-simulation still duplicatesMapVisitor/WriteAdaptor/collect_span_fieldsverbatim and could importmando_libalready); 2 branch-introduced rustfmt hunks (fmt_util.rs:47new file,dd_formatter.rs:373);super::version_orfull-path calls; test hygiene (hand-rolled_Captureinstead ofcaplog, unrestored mutated globals despite the commit title claiming restore). Rebase analysis: exactly ONE file overlaps develop (dd_formatter.rs) but the conflict is semantic and guaranteed: develop’sae6d1098rewrote dd_formatter inline with the same plumbingd0986230extracts. Landing order: fingerprint MR first (based on the develop tip, unblocks the develop panic), then rebase pymando dropping86d7ffd8+34e749d5; sharpest option also dropsd0986230(entire conflict surface, off-ticket, 2/3 done) for a zero-conflict 9-commit on-ticket MR, refiling the fmt_util extraction as its own ticket that unifies all THREE formatters against develop’s conformant dd_formatter (cost: temporary 7-line level-to-status duplication in py-mando). Path to MR-ready: 9 items; python pytest MUST be re-run before MR (not re-verified since 2026-07-09). Third tooling landmine:rustfmt --check --skip-childrenis unrecognized on stable and prints nothing (false green); check without it, attribute hunks by theDiff in <path>:headers (rustfmt followsmoddeclarations), baseline againstgit show <base>:<path>; recorded inAGENTS.mdsection 10 + landmines, Mando AGENTS Guide (mirror) resynced. → BE-3482 pymando Branch Review, BE-3482 Datadog Logs and APM Conformance. - Fingerprint MR OPENED: MR !569 for
feature/BE-3482-fingerprint-activity(“feat: add activity component to error fingerprint”; 2 title-only commits,6f541363+ the salvagedbc3727baversion-fallback panic fix), pushed to origin, awaiting review. Step 1 of the recommended landing order (fingerprint first, then pymando) is now in flight. → BE-3482 Datadog Logs and APM Conformance. - pymando rework EXECUTED: rebuilt from scratch as
feature/BE-3482-pymando-v2(worktree.worktrees/BE-3482-pymando-v2): 15 title-only, no-scope commits offorigin/developtip51d2b516(develop advanced twice mid-session, incl. the BE-1595 Arrow Flight merge, which touches py-mando); zero cherry-pick conflicts; 10 files +374/-55. Commit selection:9b0c4e70KEPT (on-ticket, py-mando-only, independent); DROPPED86d7ffd8+34e749d5(version fix rides MR !569) +d0986230(fmt_util extraction, refile as own ticket); surprise:fe78dc10needed NO level_to_status workaround since the helper was already inline pre-extraction (d0986230is what moved it out), so dropping it cost zero extra code. All review blockers/should-fixes executed: 7 orphaned ContextVars deleted (incl. the deadmetadataparam +run_with_tracecall site), deadtracing-serdedep removed, fingerprint outside a trace scope now emits the bare code instead ofcode|None(new testtest_log_error_without_step_context_omits_path),build_ddtagsmade public, test hygiene real (caplogreplaces_Capture,error_logfixture,logger_statefixture that genuinely restores mutated globals,DD_ENV/DD_VERSIONmonkeypatch-tracked). NEW fieldflow.step.system:flow.step.connectionexists ONLY inmando-lib/src/workflow/mod.rs(stepinfo_span!built fromStepMetadata { flow: DataFlow, system }), so the field is ONE line (flow.step.system = metadata.system) from the structured source, no string parsing; verified 14/14 Wrapper steps declaresystem: "Mando"and externals declare real names (Volue EMS x19, Metis x14, Position Manager x8); 4-case#[test_case]matrix (Receive Volue EMS / Receive Metis / Send Volue EMS / Wrapper Mando) passes; scope tension flagged: one mando-lib commit (52b4d270) on an otherwise py-mando-only branch, trivially splittable if a pure MR is wanted. Gates all green: clippy exit 0 (zero findings in touched files);rtk proxycargo tests 434 passed / 0 failed / 35 ignored; rustfmt zero branch-introduced hunks; pytest 120 passed / 1 skipped (baseline 114) incl. a runtime JSON conformance proof from the Rust stream.Cargo.lockcarries a legitimate extra hunk: develop’s committed lock is STALE (mandarrow-client1.16.0 vs workspace 1.16.1), plaincargo buildregenerates it. Two more AGENTS.md landmines (section 10 + landmines table, mirror resynced): (a) rustfmt base-file checks via scratch-dir copies are FALSE GREEN (mod children unresolvable, 0 hunks reported) AND running rustfmt on a module-declaring file writes into child files (6 unrelated files touched and reverted during the rework); check base files at their real path only; (b) develop’s committedCargo.lockcan be stale, a lock hunk in a diff may be legitimate. Env notes:~/.local/bin/python3.12is broken (venvs crash inensurepip), use/opt/homebrew/bin/python3.12; a transient SIGBUS hit/Volumes/bandiduringmaturin develop, retry succeeded. v2 NOT pushed, no MR; old v1 branch/worktree untouched as fallback; main checkout untouched. → BE-3482 pymando Branch Review, BE-3482 Datadog Logs and APM Conformance.
2026-07-10
- Documented the new master conventions guide for AI agents at
/Volumes/bandi/coding/poc/mando/AGENTS.md(untracked on disk, deliberately never committed; synthesized 2026-07-10 by 5 parallel researcher agents from thedevelopbranch + CI config + review feedback; 12 sections + 8 recipes: crate map/dependency direction, 10 non-negotiables, toolchain, architecture/layering, Rust style, themando_core::error!system, mando-bess API conventions, py-mando PyO3 patterns, testing ceremonies, git/CI ceremonies, verified-landmines table, exemplar recipes A–H). Corrections to prior assumptions recorded (each independently verified againstorigin/develop): (1)mando-bess/build/generated/**.rs(domain.rs + flows) is GENERATED bybuild.rsfrom YAML+Askama but TRACKED in git — edit YAML/template →cargo build→ commit input+output together, never hand-edit (same for*.outgolden files); (2) NOErrorCodederive and NOmando-lib-macrocrate on develop (verifiedgit grepempty) — they live only in.worktrees/experiments (poc-error-extractor, BE-2023, BE-1595/BE-3482);error.kind/error.codeare extracted at runtime bymando_core::error!from the Debug repr; parentpoc/CLAUDE.mdis stale on this (also references a non-existentmando/CLAUDE.md); naming trap: develop’smando-flow-step-derivederivesParamEnum/ParamMeta, NOT ErrorCode; (3) CI has NO fmt gate; lint gate =cargo clippy --release --all-features; canonical test =cargo test --all-features --release -- --test-threads=1(single-threaded MANDATORY, shared in-memory DB pools); (4)doc/errors.json= untracked generated error catalog (rustdoc-JSON shaped), generator not in CI (likely poc-error-extractor worktree); (5) mando-bess JWTtoken_layerhas signature validation DISABLED (insecure_disable_signature_validation) —Userextension is audit metadata only, NOT authz; (6) flow versions immutable once released (new behavior → v(N+1); exemplar manual_schedule v3; tip flows: as_auction_update_v2/auction_v4/data_update_v2/intraday_v2/manual_schedule_v3); (7) py-mando async bridge =py.allow_threads(|| pyo3_async_runtimes::tokio::get_runtime().block_on(…)), singlePyMandoError,map_*_errorfns inmando-lib/src/python/error.rs; (8) toolchain 1.89.0 / MSRV 1.88.0 (parent docs conflated). Provenance pinned: the guide reflects develop @ merge-base8bbd407e(Jul 1, v1.15.0);origin/developtipe5259cbd(Jul 8, v1.16.0) already drifted — 4 new crates (mando-flow-step,mando-flow-step-derive,mando-bess-lib,py-mando-simulation) + flow wiring restructured toflow_registry.rs(per-typesrc/flow/{type}/v{n}/dirs gone → recipe E stale for tip). Vault reconciled: Agent Context crate table/versions/error-row/flow-list/gates rewritten to verified tip state (was v1.4.11 + listed mando-lib-macro); mando-lib-macro markedstatus/outdatedwith correction callout; Mando CI-CD doc debt from 2026-06-25 cleared (samba removal, 1.89.0, gates section). → Mando AGENTS.md Master Guide. - Wrote the approved DESIGN SPEC for BE-1597 (status: design approved, NOT implemented; owner Gergely “Geri” Vászon; repos mando + optimization-universe-iac) — the actionable decision companion to yesterday’s research note (evidence wikilinked, not duplicated). Decision = phased: Approach 1 (dev only) NOW, Quack (all envs) on DuckDB 2.0 in Sept 2026. Approach 1 mechanism: SSM
AWS-StartPortForwardingSessionToRemoteHostpicks the LOCAL port → forward local 4213, browsehttp://localhost:4213(literallocalhost, NOT127.0.0.1— the bundle string-compares"localhost:4213"); no ALB (alreadyinternal=true), no target group / health check //duckdb*prefix / reverse proxy / bundle patching; the bastion hop is required only because ECS Exec is interactive-only. Concrete deliverables: (a) container — addsocatto the mando-bess Dockerfile + adocker-entrypoint.shthat runssocat TCP4-LISTEN:4214,fork,reuseaddr TCP6:[::1]:4213 &whenDUCK_DB_UI_SERVER=truethenexec mando_bess(NO Rust change — env already read atlib.rs:181/:301; noEXPOSE/portMappings in awsvpc; socat ships in the prod image too, ~400KB, the listener just never starts there); (b) terraform — adynamic "ingress"block INSIDE thebess_os_ecsSG (inline-blocks resource, so a standaloneaws_vpc_security_group_ingress_ruleis silently reaped) opening port 4214 from the bastion SG onvar.environment=="dev", plusDUCK_DB_UI_SERVER = tostring(var.environment=="dev")on the mando container (usevar.environment, NOTlocal.environment_group, which collapses int+prod/dev+test); (c) aduckdb-ui.shhelper resolving the bastion + task IP and opening the SSM port-forward. Blocking pre-check (open Q1): does the dev Fargate task actually have egress to extensions.duckdb.org/ui.duckdb.org? No NAT/VPC-endpoints in IaC (VPC is abase-vpcdata lookup owned by another team) — if blocked, Phase 1 can’t work and no terraform fixes it. Production bar: NEVER run the DuckDB UI in int/prod — the frontend is proprietary MotherDuck JS (source unpublished, still no license as of Jul 2026) proxied live from ui.duckdb.org with no auth that can read the live trading cache; the rest of the supply chain (DuckDB core / libduckdb / duckdb-rs / ui-ext SOURCE / quack / ICU / yyjson) is MIT/permissive and safe to vendor. Phase 2 = Quack (core DuckDB-signed MIT ext, 1.5.3+;quack_serve('quack:0.0.0.0:9494', allow_other_hostname=>true)→token, clientATTACH 'quack:host:9494' (TOKEN …)) run withduckdb -uiON THE LAPTOP — deferred to DuckDB 2.0 (Sept 2026) because Quack is Beta in 1.5.x (one upgrade, not two). Upgrade 1.4.2→2.0 assessed low-risk (in-memory-only sidesteps storage churn; keep the=1.4.2pin vs the new1.MAJOR_MINOR_PATCH.xcrate scheme). → BE-1597 DuckDB UI — Design.
2026-07-09
- Researched BE-1597 DuckDB UI exposure (+ the ticket’s 2nd half: remote client access to the in-memory DuckDB). Root cause both prior attempts failed (Andras + Gergely Vászon, Mar 3–4 2026, IaC branches
feature/BE-1597*/feature/expose-duckdb-ui+ mandofeature/BE-1597-add-tunnel-for-duckDB-UIc700fee9/feature/BE-1597-proxy-duckdbUI-thorugh-mando0e06c93e, nothing merged): the DuckDB UI JS bundle hardcodes"localhost:4213" === window.location.host ? "duckdb_ui" : "web", so any other origin silently degrades — Attempt A (socat 4214 + ALB target group +/duckdb*listener rule; died on the 8080/healthcheck, hencetemp: disable healthckeck for duckdbcommits) and Attempt B (reqwest reverse proxymando-bess/src/route/duckdb_proxy.rsrewriting<base href>+ string-patching the JS bundle) were both un-winnable. Fix = SSMAWS-StartPortForwardingSessionToRemoteHostpicks the LOCAL port → forward local 4213, browsehttp://localhost:4213(literallocalhost, NOT127.0.0.1) and the origin check passes; no ALB (mando ALB alreadyinternal=true). Bastion SSM hop is genuinely required because ECS Exec is interactive-only (no port forwarding). UI ext constraints: only settingsui_local_port(4213)/ui_remote_url/ui_polling_interval(284ms), NO bind-address (binds IPv6::1→ socat needed), no auth, proxies the frontend fromui.duckdb.orgper session (internet required),ui_remote_urlonly honored underallow_unsigned_extensions, and theuiext is not statically linked (verifiednm -Don the vendored1.4.2.so→ only Icu/Json) soCALL start_ui_server()auto-downloads it. License blocker (the important one): DuckDB core / libduckdb / duckdb-rs / libduckdb-sys / theuiext SOURCE / quack / ICU / yyjson are all MIT/permissive (IP: Stichting DuckDB Foundation) — but the DuckDB UI FRONTEND assets fromui.duckdb.orgare PROPRIETARY MotherDuck code, source unpublished, still no published license as of Jul 2026, served with no auth that (per DuckDB docs) “can access the data you load into DuckDB” → fine for dev, NOT acceptable for theint_prodtrading service. Ticket’s 2nd half: the ONLY way to remotely connect a client to a running in-memory DuckDB is the Quack remote protocol (core DuckDB-signed MIT ext, DuckDB 1.5.3 / 2026-05-20;quack_serve('quack:0.0.0.0:9494', allow_other_hostname=>true)→auth_token, clientATTACH 'quack:host:9494' (TOKEN …); beta until DuckDB 2.0, Sept 2026); 1.4.2 has no wire protocol at all. Upgrade 1.4.2→1.5.4 = low-risk (in-memory-only sidesteps storage-format churn;=1.4.2pinCargo.toml:60safe against the new1.MAJOR_MINOR_PATCH.xcrate scheme where 1.5.4→1.10504.0; C API additive-only;date_trunc(DATE)→TIMESTAMP and->lambda-deprecation SQL breaks both clear against mando). Infra gotchas: bastion SSM-only + zero-ingress;bess_os_ecsSG uses INLINEingressblocks — a standaloneaws_vpc_security_group_ingress_ruleis silently deleted on next apply, use adynamic "ingress"block; NO NAT/VPC-endpoints so Fargate egress to duckdb.org UNVERIFIED;int+prodboth map toint_prod. → BE-1597 DuckDB UI Exposure Research.
2026-06-25
- Documented a two-bug visibility fix for mando-cli v0.4.0 found while VALIDATING the [[mando-cli-v0.4.0-mando-bess-binary-missing-2026-06-25|
mando up --mando=pullworkaround]]: whenupoutput is piped/redirected (remote tester doesmando … 2>&1 | tee log), failures were INVISIBLE — captured.mando/compose-up.logwas empty and the user saw only a baredocker compose up … failed (exit 1). Two independent, stacking root causes (fixing one is insufficient): (A) the streaming compose runner (src/runtime/compose.rs,run_streaming) pipes child stdout/stderr, butdocker composewrites its pull/up progress AND the error to/dev/tty, bypassing the pipe → empty capture. Fix A: add top-level--progress plainto the compose invocation (compose.rs~L231,Cmd::new("docker").arg("compose").arg("--progress").arg("plain").arg("-p")…) to force plain newline output into the pipe (--ansi neverequivalent). (B)CliBuffer::add_log_line(src/opts.rs:57) forwarded lines viaindicatif::MultiProgress::println, which is a silent no-op on non-TTY (returnsOk, writes nothing) → dropped ALL streamed docker output AND the failure-tail replay block (compose.rs:263-272). Fix B: fall back toeprintln!whenstd::io::stderr().is_terminal()is false (use std::io::IsTerminal; TTY →multi.printlnwitheprintln!fallback on err, non-TTY →eprintln!directly). Validated on macOS: redirected (non-TTY)up --mando=pullwent from ~35 silent lines (barefailed (exit 1)) to 138 lines showing the realpull access denied for mando … 'docker login'error +--- last 40 log lines ---tail +--- full log: .mando/compose-up.logpointer. Reusable gotchas: (1)docker compose’s progress writer targets/dev/tty— any pipe-captured invocation must pass--progress plain/--ansi neveror output+errors vanish from the captured stream; (2)indicatif::MultiProgress::printlnis a silent no-op on non-TTY — any CLI using it for log passthrough must fall back toeprintln!when stderr isn’t a terminal, else piped/CI/teeoutput disappears. Tester’s now-visible failure:pull access denied→ needsdocker login registry.gitlab.com(GitLab PAT,read_registryscope); mando-cli’s “registry auth” line is GitLab API creds (git/glab credential helper), NOT docker login — a misleading-but-important distinction (separate credential stores). Status: both fixes implemented + built + validated on macOS, NOT committed; linux/amd64 build for gabi (WSL) pending. → mando-cli-v0.4.0-piped-output-invisible-failures-2026-06-25. - Documented the BE-1595 Arrow Flight dev deploy + hardening as four durable, reusable notes (distilled from a multi-session dev deploy of the Flight streaming feature: mando server + py-mando wheel + optimization/forecast consumer images). (1) Flight → REST graceful degradation (F4 capability-gap fallback) — the DuckDB/passthrough repo only streams within its cache window; a
retrieve_streamover a range predating the cache (Permanent storage) returnsRepoError::MethodNotSupported(repo_passthrough.rs:335). Originallyrepo_error_to_status(mando-bess/src/flight.rs) mapped it to gRPCFailedPreconditionand the client only fell back to REST onis_retryable(), so it propagated asFataland crashed forecast (fetches historical data). Fix (commit7926278c): mapMethodNotSupported→ gRPCUnimplemented; addClientError::is_unimplemented()(mandarrow-client/src/error.rs); client falls back onis_retryable() || is_unimplemented()(py-mando/src/polars.rs). KEEPCyclicDependencyasFailedPrecondition(real error, REST can’t fix). Net: optimization fully on Flight (cache-window fetches), forecast logsfalling back to RESTthen completes. Resolves the “Known limit” from be-1595-flight-execution-id-parity-2026-06-17 (flipped that note’s callout to[!done]). → be-1595-flight-rest-graceful-degradation-2026-06-24. (2) Wheel ↔ server version skew — the #1 deploy hazard: wheel (mandarrow-client Flight wire types + bess client Python API likeBessOptClient.send(update_id=...)) and server deploy independently, but adevelopmerge bumped sharedDataPointUpdateInfo(renamedfetch_time→update_time, addedupdate_id) breaking old-wheel↔new-server (send() got an unexpected keyword argument 'update_id'). Fix (commit73cbdcf3): tolerant wire types —#[serde(default)]on every optional/added field,#[serde(alias="old")]on renames, NEVER#[serde(deny_unknown_fields)]on boundary structs, + compat tests (old-shape JSON must still deserialize). Two hard constraints: can’t retroactively fix released versions (deploy mando + wheel from the same build on a wire change); send-side signature mismatch only resolves by rebuilding consumers on the matching wheel. → be-1595-flight-wire-type-version-skew-2026-06-24. (3) Consumer wheel-lock deploy script (deploy-arrow-consumers.ps1/ base64iexone-liner) — runs on Windows on corp net (Nexus must resolve). Gotchas: clone via token URL (https://oauth2:$Token@…) +GIT_TERMINAL_PROMPT=0/GCM_INTERACTIVE=Neverto stop the GitLab credential popup hanging; the base64 one-liner is a frozen snapshot so a stale clipboard silently re-locks the WRONG wheel — always re-copy fresh + verify the echoed wheel; dev images gated behind thepython-docker-publishcomponent (Publish Docker Devonly on develop/rc) so the script appends a local rules-override forfeature/*(relatedly needs theoptional: true.Publish→Testpatch, be-1595-publish-docker-dev-feature-branch-test-need-2026-06-16). → be-1595-arrow-consumer-lock-script-2026-06-24. (4) Dev deploy runbook (recurring facts) — migration drift → mando crash-loop (V…__… is missing from the filesystem), fix by merging develop so branch migrations ⊇ DB’s; IaC atoptimization-universe-iac.worktrees/mando-arrowterraformterraform.auto.tfvars.json(mando + optimization-algo + forecast-algo image pins);terraform_apply:devalways red on a pre-existing customer-portal S3 403 HeadObject even though terraform printsApply complete!(harmless, not ours); runtime switchMANDO_FETCH_STRATEGY=flight(default rest) +MANDO_FLIGHT_HOST/PORTon algo task defs; verify in Datadog EUenv:devservicesbess-os-service-mando/bess-os-algo-optimization/bess-os-algo-forecast. → be-1595-arrow-flight-dev-deploy-runbook-2026-06-24. - Documented the NEXT mando-cli v0.4.0
mando upfailure after the 2026-05-26 compose-runtime fixes (commit2233959): on a fresh clone the default profilemando-mocked-algosabortsdocker compose buildat#14 [mando 6/6] COPY target/release/mando_bess …→failed to compute cache key: "/target/release/mando_bess": not found(collateral:bess-trader-dashboardbuild shows CANCELED). Reported by remote QA gabi (gabriel.vasile1) on WSL. Root cause (verified in source):mando/Dockerfileis a THIN runtime image (FROM debian:13.1-slim AS runner,:17COPY target/release/mando_bess …,CMD ["mando_bess"]) that copies a PRE-compiled binary — no Rust build stage;mando/bess-service.yaml:23-32context_includesshipstarget/release/mando_bess(a CI-only assumption thatcargo build --releasealready ran). The default profile mapsmando→buildrunconfig (runprofile.rs:225;mando-full→build:237,mando-fast-dev→build-dev:249) — NO builtin profile mapsmandotopull/artifact. Thebuildrunconfig (templates/runconfig/build.yml:10-12) emits a realbuild:section and NOTHING in theupflow compilesmando_bess(the host-build--cargoflag is gated to theartifactrunconfig only,cli.rs:55). Net: any tester on a fresh clone hits it; works in CI only because CI pre-builds the binary. Workaround (no code change):mando up --mando=pull— thepullrunconfig (templates/runconfig/pull.yml) swapsbuild:forimage: ${MANDO_IMAGE:-…}+docker compose pull; on gabi’s box resolves toregistry.gitlab.com/alpiq_cicd/.../mando:1.10.0-2533146896.b06b6b59(authed → pulls the released image); per-service override syntax atcli.rs:78. Durable fix (decision pending, NOT implemented): (1) flip defaultmando→pull(runprofile.rs:225) — OPEN RISK: confirm a clean checkout’s defaultMANDO_IMAGEpoints at the GitLab registry, NOT a localmando:dev(the ref is NOT hardcoded in mando-cli source; comes from workspace config/env), else pull 404s; (2) add a preflight guard inup:build/build-devrunconfig + missingtarget/release/mando_bess→ fail early with an actionable message. Status: diagnosed, fix pending user decision. → mando-cli-v0.4.0-mando-bess-binary-missing-2026-06-25. - HARDENED the remotefs-smb to smb migration EBS upload path after a two-reviewer (correctness+style) pass — three
ebs.rsfixes: (1) replaced panic-proneResource::unwrap_file()(PANICS if the path resolves to an existing directory, server-state-dependent) with fallibleresource.try_into()::<File>(smbResource: TryInto<File>, err(smb::Error, Self)) — neverunwrap_file()in prod; (2) fixed a workgroup/empty-username auth bug — oldif wg.is_empty(){user}else{format!("{wg}\\{user}")}produced malformed"WORKGROUP\"(trailing\) when workgroup set but username empty AND dropped anonymous-on-empty-username, now a 3-armmatch (wg.is_empty(), user.is_empty())→ empty username ⇒String::new()(anonymous) elseWORKGROUP\user; (3) addedfile.flush().await?(inherentpub async fn flush(&self), NOT a trait) beforeclose()for durability. Plus a formatting finding:rustfmt.tomlsets nightly-only opts (group_imports=StdExternalCrate,imports_granularity=Module) but there’s NO fmt gate in.gitlab-ci.ymland ALL sibling adapters failcargo +nightly fmt --check(mdr/opl/et_3000/data_platform) — the real bar is stablecargo fmt; do NOT nightly-format individual files (breaks import consistency vs siblings);rustfmt --checkoutside the repo root panics. Re-verified:cargo build -p mando_libclean,cargo test -p mando_lib205/32 ignored/0, clippy + stable fmt clean (pkg ismando_lib, underscore). → remotefs-smb to smb migration. - MIGRATED the SMB client off GPL: replaced
remotefs-smb+ companionremotefs(=0.3.1) with the pure-Rustsmbcrate=0.11.2(github.com/afiffon/smb-rs) in mando-lib. Why:remotefs-smb→pavao→pavao-sysFFI-binds the systemlibsmbclient, andpavao/pavao-sysare GPL-3.0 (dynamic-link-only) which Alpiq cannot use;smbis pure Rust (no libsmbclient) so the GPL transitive dep is gone entirely (cargo tree -p mando_lib | grep -iE 'remotefs|pavao'now empty). Blast radius = ONE call site: the Alpiq EBS (Energy Balance System) adaptermando-lib/src/adapter/alpiq/ebs.rs, which is upload-only (mando generates.xlsxbid-templates and pushes them to an SMB/CIFS share);EbsClient::upload_file’s public signature was preserved so the service-layer callers (service/alpiq/ebs.rs,…/ebs_clear_bids.rs) needed no changes. Full cleanup chosen (no dead GPL footprint): bumpedrust-toolchain.toml1.88.0 → 1.89.0 (forced — see MSRV gotcha), swapped workspaceCargo.toml+mando-lib/Cargo.tomldeps, rewrote the upload path and deleted both#[cfg(target_family=…)]create_clientbuilders (pure-Rust ⇒ no unix/windows split), removedpavao=offfrom defaultRUST_LOG(app/mod.rs), and droppedsamba-libs+libsmbclientapt installs fromDockerfile+mando-simulator/Dockerfile. API recipe (low-level + async, vs remotefs’s high-levelRemoteFstrait): default features (sign,encrypt,compress,async,std-fs-impls,netbios-transport) — NOTkerberos(reqwest)/quic;Client::new(ClientConfig::default());UncPath::from_str(r"\\host\share")(needsuse std::str::FromStr);share_connect(&unc, &user, password)where a workgroup is mapped byformat!("{workgroup}\\{username}")(parsed bysspi::Username::parse, acceptsDOMAIN\user);unc.with_path(&path)consumes self (callshare_connect(&unc,…)before movingunc);create_file(&path, &FileCreateArgs::make_overwrite(FileAttributes::new(), CreateOptions::new()))uses dispositionOverwriteIfwhich collapses the oldexists()+remove_file()+create_file()dance into one call (smb has no explicit delete);res.unwrap_file()→File::write_at(&[u8], u64)->usize(loop for partial writes) →File::close(). Import gotcha:write_atis thesmb::WriteAtTRAIT (must be in scope);FileAttributes/CreateOptionslive insmb-fsccbut are re-exported at thesmbroot (pub use smb_fscc::*). Gotchas: (1) MSRV blocker — smb 0.11.2 is edition 2024 and it + all 8 sub-crates declarerust-version="1.89.0", so 1.88.0 hard-errors (“requires rustc 1.89.0”) → toolchain bump; re-verify smb MSRV before any future bump. (2) ~295 crates added pulling the SMB3 signing+encryption stack at RustCrypto release-candidate versions (aes-gcm 0.11.0-rc.1,aead 0.6.0-rc.2,ccm 0.6.0-pre.0) +sspi/NTLM (picky/rsa/curve25519) — mandatory for SMB3, can’t trim much; conscious tradeoff (pure-Rust+no-GPL vs large pre-release-crypto tree). (3)cargo build -p py_mandolink failure is a RED HERRING (pre-existing) — undefined libpython symbols from pyo3_ffi is standard pyo3extension-modulecdylib behavior (verified identical on clean baseline; smb compiles fine in py_mando closure); build the Python bindings withmaturin develop, notcargo build. (4) cargo package name ismando_lib(underscore), notmando-lib. Verify (all green):cargo build -p mando_libclean; whole-workspace build green except the pre-existing py_mando maturin link (gotcha 3);cargo test -p mando_lib= 205 passed / 32 ignored / 0 failed;cargo clippy -p mando_libclean. OPEN acceptance step: the#[ignore]d live testslocal_hourly_test/local_quarter_hourly_test(envEBS_SMB_HOST/USERNAME/PASSWORD/SHARE/WORKGROUP/SUB_FOLDER) need running against a real SMB share to confirm the new crate authenticates+uploads end-to-end — could not be validated in dev; flag before merge. Doc debt: Mando CI-CD + Agent Context still listsamba-libs/libsmbclient+ Rust1.88.0(now1.89.0) — flagged, not yet reconciled. → remotefs-smb to smb migration. - FIXED the
mando-codegenexpand_variantspython_field casing bug from the BESS AM (BE-2262) - mando-bess-am note (was:min1.Meaninstead of all-lowercasemin1.meanfor multi-segment Named variants, affecting BESS AM 1-min aggregate datapoint names). Fix lowercases the value segment atmando-codegen/src/util.rs:41→format!("{pf}.{name_lower}.{}", v.to_lowercase()). Commitcc4720b2“fix: lowercase value segment of variant python_field” onfeature/BE-2262-bess-am-poc, pushed to MR !512. Verifiedcargo test -p mando_codegennow 51/51 passing (was 50/1). Residual (unrelated): two PRE-EXISTING rustfmt drifts remain in that same file (~lines 50 and 390, author’s code), left untouched — flagged by nightly rustfmt. Flipped the note’s> [!warning]callout to> [!done]. → BESS AM (BE-2262) - mando-bess-am.
2026-06-24
- Documented BESS AM (BE-2262) as durable reference knowledge (newly discovered from
mandogit history, not previously in the vault). BESS AM = BESS Asset Management: a headless Kinesis stream processor (new cratemando-bess-am/mando_bess_am) for per-second WAGO battery-telemetry events (real-time SoC/SoH) on the FI/Valkeakoski/Beskar asset, authored almost exclusively by Gergely Vászon (ext). Pipeline:WAGO Box → AWS IoT Core → Kinesis (bess-am-events) → mando-bess-am → Kinesis (bess-os-events) → mando-bess. The service consumes the rawbess-am-eventsstream, persists raw per-second events to Postgres schemabess_am(eventtable), computes 1-minute aggregates (Mean/Max/Min/Last/StdDev/Count/Sum) via a windowing + grace-period closure mechanism (service/window_closure), and forwards results tobess-os-eventswhich mando-bess ingests. Introduces a NEWEvent-typed data-point class (real-time telemetry) distinct from the existingTimeSeriesDouble/TimeSeriesDoubleMatrix/StaticDatatime-series flows — the flow-engine list (Trading/Manual Schedule/Auction/Intraday/Data Update/AFRR) does NOT include AM. Code fingerprints: crate modulespipeline/service/aggregation/service/forward/service/window_closure/startup/metrics;mando-lib/src/adapter/kinesis/(consumer/producer/pipeline/checkpoint/config);mando-core/src/model/{event,wago}.rs;mando-bess/src/kinesis.rs;mando-bess/config/parts/battery_online.yaml(Event datapointsBATTERY_SOC_ONLINE/BATTERY_SOH_ONLINEunderAsset/FI/Valkeakoski/Beskar/Battery/.../Online, keyed to Kinesis external IDs[bess-am-events, OnlineSOC/OnlineSOH]);container.bess-am.Dockerfile;config/bess-am.yaml. Infra: schemabess_am, migrationscreate_bess_am_schema/create_event_table/create_kinesis_checkpoint_table/add_event_latest_historization; env prefixBESS_AM_*; Kinesis streamsbess-am-events&bess-os-events; CI job “Publish BESS-AM Docker Dev” (ECR tagbess-am-<version>); local-devdoc/kinesis-local-setup.md+ MiniStack (ministackorg/ministack). Related tickets: BE-2341 (generic Kinesis producer in mando-lib, no standalone MR, folded into the BE-2262 MR) and BE-2132 (interval/Event datapoint groundwork AM builds on). MR landscape (2026-06-24): core MR !512feat: add kinesis consumer and event processing(feature/BE-2262-bess-am-poc→ develop) is OPEN,requested_changes, reviewers krisztian.fekete1/gabor.nagy6/balint.budavoelgyi/andras.lederer/jozsef.nagy1, empty description, created 2026-05-19 / updated 2026-06-17; !524feat: add basic interval functionality(feature/BE-2132-interval-poc-2, closes BE-2132, OPEN/not_approved); !500 same title (feature/BE-2132-interval-poc, OPEN/DRAFT, stale, superseded by !524); branchfeature/BE-2262-bess-am-poc-build-test+ commit5a739baa“feat: separate out bess-am” splits AM into its own crate/image but has NO own MR (downstream of !512). Nothing BESS AM has merged todevelopyet — still in flight, blocked on review. Added pointers from Agent Context (new crate row + dedicated BE-2262 section) and Alpiq BESS (Key Concepts). → BESS AM (BE-2262) - mando-bess-am. - Appended an Update 2026-06-24 section to the BESS AM note with two facts verified from the
mandorepo. (1)origin/developmerged into the !512 branchfeature/BE-2262-bess-am-poc(was 46 commits behind), pushed fast-forwardf9a1f81d..80a17e78(merge commit80a17e78); conflicts resolved inmando-lib/src/repo_postgres.rs(kept BOTH newDataSchemaPostgresdefaults — branch’shas_override()+ develop’slatest_pk_columns()),py-mando/bess-csv/defaults.csv(kept the 3 BESS AMEventrows, took develop’s newerEUR/MW/hFINGRID units), and the generateddomain.rsfiles (regenerated viabuild.rs, converged CRLF→LF to match develop — branch had committed them CRLF); post-merge compiles clean (cargo check, 0 errors), 428 lib unit tests pass. (2) Pre-existingmando-codegenbug:expand_variantsmis-casespython_fieldfor multi-segment Named variants — aMin1/Meanvariant yieldsmarket.da.price.min1.Meaninstead of all-lowercasemarket.da.price.min1.mean(lowercases the first path segment but not later ones); caught by failing testmando-codegen/src/util.rs→util::tests::expand_variants::named_variant_generates_datapoint(~line 291); affects BESS AM 1-minute aggregate names (Min1/Mean, Min1/Max, Min1/StdDev, …); NOT caused by the develop merge (mando-codegenbyte-identical before/after) — originated in the branch’s ownfeat: separate out bess-amcommit5a739baa; fix = lowercase every segment of the variant path; left unfixed/separate per decision, merge push didn’t change it. → BESS AM (BE-2262) - mando-bess-am.
2026-06-22
- Captured a reusable clippy tooling gotcha discovered while designing the mando error-handling redesign: for clippy’s
disallowed_macroslint (mando banstracing::error!/log::error!viaclippy.tomlto force logging through themando_core::error!wrapper inmando-core/src/error.rs), an#[allow(clippy::disallowed_macros)]placed at or around the call site — on thetracing::error!invocation, on a wrapping#[allow] { ... }block, or on the enclosing fn/match arm/let— is silently ineffective on a newer clippy (probe reported1.95); the lint still fires and clippy additionally warns the attribute is “unused, since it’s applied to a macro invocation”. The only robust placement is a module-root inner attribute#![allow(clippy::disallowed_macros)]at the file that DEFINES the wrapper macro, becausedisallowed_macrosresolves the lint level at the lexical site where the banned tokens physically appear (the macro definition, not the call site) — so one allow in mando-core covers all cross-crate callers (mando-lib, mando-bess). Caveat: the workspace pins toolchain1.88.0(rust-toolchain.toml) and the macro ondevelopcurrently uses the block-level#[allow]form which presumably passes CI on 1.88; the probe used a newer clippy, so the block form is fragile across clippy versions while the module-root#![allow]can’t be worse on 1.88 and is confirmed on newer clippy — verify clippy-clean under the pinned toolchain. General lesson: for clippy lints that fire on macro expansions,#[allow]at the expansion/call site often no-ops; put the#![allow]at the macro’s definition site. → clippy-disallowed-macros-allow-placement-2026-06-22.
2026-06-17
- Implemented Flight execution_id parity on
feature/BE-1595to fix a dev regression: enablingMANDO_FETCH_STRATEGY=flighthard-broke the optimization/forecast algo runners (they always fetch with anexecution_id) because py-mando’s flight guard HARD-ERRORED"Flight strategy does not support access_token/headers/execution_id; use REST". Root cause: REST applies execution-bound manual overrides server-side (look up flow execution byexecution_id, inject eachmanual_overridesentry into matchingDataPointFilters wheremanual_override.is_none()), but the Flight path had no equivalent and the client refused any execution_id/headers. Fix: (1) extracted the REST override block (was inline inmando-lib/src/app/route/query_data_route.rs) into sharedmando_lib::app::execution_override::apply_execution_overrides(&FlowRepository, Uuid, &mut [DataPointFilter])+ pureinject_overrides; both RESTget_dataand the Flight server call it (DRY). (2) Addedexecution_id: Option<Uuid>to BOTH clientQueryTicket(mandarrow-client/src/ticket.rs, +uuiddep) and serverFlightTicket(mando-bess/src/flight.rs),#[serde(default)]for mixed-deploy safety. (3) Flight server applies overrides at the HANDLER layer:do_getresolvesticket.execution_idand mutatesticket.data_pointsBEFOREretrieve_stream(mirrors REST, NO trait change);MandoFlightServicegained anArc<FlowRepository>threadedserve→spawn_flight_server, andlib.rsrestructured so each DB-mode branch buildsflow_repositoryonce and shares the Arc with both flight server +get_app. (4) Client guard (py-mando/src/polars.rsfetch_with_strategy) relaxed to error ONLY on non-emptyaccess_token; execution_id+headers no longer block.headersdropped on flight path (trace stitching stays REST-only — deferred); access_token REST-fallback safety net also deferred (still errors). KEY correctness fact (verified):retrieve_streamhonorsDataPointFilter.manual_overrideidentically to REST (sharedget_retrieve_sql+:manual_overridebinding,repo.rs:497/repo_duckdb.rs:911; materializable path callsretrieve), so handler-layer injection is sufficient. Known limit: manual-overridegeneration_timepredating the DuckDB cache window for Permanent/DataPlatform DPs → streamed path returnsMethodNotSupportedwhere REST serves from permanent storage (repo_passthrough.rs:335). Deploy note: client changes are in the py-mando wheel, so this needs rebuilding the mando image AND the wheel AND the optimization/forecast consumer images. Plan:docs/superpowers/plans/2026-06-17-flight-execution-id-parity.md. → be-1595-flight-execution-id-parity-2026-06-17. - Found two latent FlowRepositorySqlite bugs while writing the test seed (local Sqlite dev/test path only, NOT Postgres prod; worth a ticket). Both in
mando-lib/src/workflow/repository/flow_repository_sqlite.rs: (1)create_flow(:111) uses lazystmt.query(params![...])for an INSERT and drops theRowswithout iterating → the SQL may never execute and the row never persists (rusqlite footgun; should use.execute()/.insert()). (2)flow_execution.started_atschema default iscurrent_timestamp(stores TEXT) butget_executionreads column 2 asi64(Utc.timestamp_micros), so a row created without an explicit integerstarted_atcannot be read back (InvalidColumnTypeTEXT vs i64). → be-1595-flow-repository-sqlite-bugs-2026-06-17.
2026-06-16
- Documented how to actually turn ON the Arrow Flight client path in the BESS consumers (BE-1595). Runtime switch is py-mando env var
MANDO_FETCH_STRATEGY(defaultrest; Flight only when ==flight, case-insensitive;flight.rs:16, read per-fetch atpolars.rs:224-236), plusMANDO_FLIGHT_HOST/PORT/PROTOCOL. Whole path is#[cfg(feature="flight")]but the dev wheel ships with-F flight, so enablement is purely the env var — no rebuild. CRITICAL gotcha: on a Flight fetch error py-mando SILENTLY falls back to REST (polars.rs:234), so no-errors ≠ Flight-in-use; must confirm via logs/metrics, and setting the var where the gRPC port is unreachable is a noisy no-op. Per-service ECS topology decides the action:bess-os-algo-optimization+bess-os-algo-forecastshare the SAME ECS task asbess-os-service-mando(bess_os_ecs.tf, reach mando overlocalhost) → enabling = add 3 env vars (MANDO_FETCH_STRATEGY=flight,MANDO_FLIGHT_HOST=localhost,MANDO_FLIGHT_PORT=tostring(var.mando_flight_port)); DONE onfeature/mando-arrow(commitd3db63e).bess-os-dashboard-traderis a SEPARATE task (trader_dashboard_ecs.tf, reaches mando overlocal.mando_domainHTTPS) — the Flight gRPC port (50051) is only a host port inside the bess-os task with NO NLB/target-group/SG path for the dashboard, so Flight there is NOT an env flip (needs gRPC-over-network plumbing); left on REST. Server side already in place: mando exposesvar.mando_flight_port(default 50051) viaMANDO_FLIGHT_PORT+ gRPC port mapping (bess_os_ecs.tf~211-213, ~307) + SG rule (security_group.tf). → be-1595-enabling-arrow-flight-consumers-2026-06-16. - CI/CD gotcha while deploying BE-1595 Arrow Flight to dev: enabling
Publish Docker Devonfeature/*in the BESS Python consumer repos fails the pipeline ('Publish Docker Dev' job needs 'Test' job, but 'Test' does not exist) because.Publish’sneeds:hard-depends onTest, whose rules only fire on MR/develop/rc/main/release — not feature/*. Fix: addoptional: trueto the Test need in.Publish. Applies to bess-optimization + bess-forecast-day-ahead; bess-trader-dashboard’s.Publishhas no Test need so it’s unaffected (automation must guard on presence of- job: Test). Tradeoff: dev image ships without the test suite on feature branches (vs. adding /^feature/ to Test rules, which would block the image on unrelated failures) — optional chosen for disposable arrow-deploy branches. → be-1595-publish-docker-dev-feature-branch-test-need-2026-06-16.
2026-06-15
- mando session: implemented Per-Flow Error Context Store (“OEF v2”) on
feature/BE-3117(worktree, NOT yet committed; replaces the committed OEF v1 on the same branch). Goal: emit EXACTLY ONE aggregate businessERRORper flow run retaining 100% of error data, replacing OEF v1’sdd_formatterERROR→WARN demotion + thin repo-read aggregate (lost fidelity, coupled on magic strings). Mechanism, all in mando-lib: (1)ErrorRecordstruct intracing/tracing.rs—Clone+ HAND-WRITTENserde::Serializethat redacts HTTP req/resp bodies whenhttp_context.sensitive; carries timestamp/step/error_kind/error_code/error_source(full anyhow{:#}chain)/message/http_context/validation_results/event_type/call_site/extra. (2)FLOW_ERROR_CONTEXT=tokio::task_local!Arc<Mutex<Vec<ErrorRecord>>>, sibling toTASK_CONTEXT. (3)record_error!macro intracing/error.rs(#[macro_export]): in-flow-scope → build record (kind/code viamando_core::error::kind_code), push to store, emit INFO breadcrumb (never raw bodies); out-of-scope → fall back tomando_core::error!(ERROR). TT-muncher (__record_error_parse!/__record_error_emit!) because naive$(...)?optional-named-field hitslocal ambiguity. (4) Flow boundary inworkflow/flow.rs: store created INSIDE the spawned task (task-locals don’t propagate into a detachedtokio::spawn— same class as BE-1842 Datadog Observability); scopedFLOW_ERROR_CONTEXT.scope(store, TASK_CONTEXT.scope(ctx, service.oneshot(param)).instrument(span)); after scope returns (OUTSIDE span)flush_flow_errors(trace_id,&store,completed)->booldrains (mem::take) + emits ONEtracing::error!with flat facetsflow.summary=true/flow.exec_id/flow.error.count/flow.error.codes/flow.error.failed_steps/event_type=Integration+ fullflow.errorsJSON.FlowCompletionGuardholds same Arc, flushes on Drop (completed=false) for panic/cancel;mem::take+completed+empty-store early-return ⇒ no double emit. (5) Step-level:StepResult::logErr arm records via localrecord_step_error!usingErrorRecord::from(&ErrorWithStepStatus)(reuse precomputed kind/code), gated on!logged_at_site;Fromimpl lives inworkflow/mod.rs(struct fields module-private). dd_formatter ERROR→WARN demotion REMOVED. Invariant — record exactly once per flow, gated byErrorWithStepStatus.logged_at_site(successor to thelogged_at_failure_siteflag of flow-step-log-message-dropped-2026-05-26): a site that records itself viarecord_error!MUST returnlogged_at_site=true(viamessage_logged/mark_logged) so steplog()takes WARN and does NOT re-record; errors not logged at site are recorded by the step path (fires only when!logged_at_site). Gotcha fixed: 4MarketNotFoundsites (intraday/v2 + manual_schedule/v3energy_bids_step&open_position_notification_step) had a PRE-EXISTING double-log (siteerror!+ stepstep_error!, both ERROR); fixed viamark_logged()⇒ one record. DD-facing:flow.failed_steps→flow.error.failed_steps(newflow.error.*flat hierarchy, continues BE-2272);event_type=Integrationpreserved. Constraint:record_error!in mando-lib NOT mando-core (mando-core can’t depend on mando-lib; needs ErrorRecord/FLOW_ERROR_CONTEXT/HttpErrorContext). Status: TDD two-stage review per task; all green (mando_core+mando_lib+mando_bess tests, py_mando compiles, clippy clean on touched files); uncommitted. Non-blocking follow-up: no E2E failing-flow test through the real spawned task; three out-of-scope infraerror!calls (DelayCalculationFailed, cancel_queued_steps, PostFlowServiceFailed) can co-emit by design. → BE-3117 Per-Flow Error Context Store.
2026-06-02
- mando-cli session: simulator env contract realigned to real images + arbitrary-extras passthrough (commit
c3f0af7onfeature/simulator-runtime; 8 files, +440/−67; 813 tests pass, no new clippy; sole author andras.lederer, no co-author trailer). §A of mando-cli-simulator-runtime-2026-05-30 is now SUPERSEDED. Real orchestrator contract:SIMULATOR_DATABASE_{HOST,NAME,USERNAME,PASSWORD,SCHEMA,MAX_CONNECTIONS}(replacesPOSTGRES_*/SIMULATOR_DB_SCHEMA); newSIMULATOR_START_DATE/_END_DATE/_SHUTDOWN_AT_END; per-runnerSIMULATOR_<NAME>_HOSTdefaulting tosimulator-<name>:<port>(replacesSIMULATOR_RUNNERSCSV); repo URL/branch/commit_hash MOVED off orchestrator onto the runners. Runners read unprefixedSIMULATOR_REPO_URL/BRANCH/COMMIT_HASHinside the container (assumption — verify when runner image lands); workspace.envkeeps prefixed${SIMULATOR_<NAME>_*}override convention. Schema renamedbess_simulation→simulator. Healthcheck reverted Python →curl; Gurobi reverted from file mount →GUROBI_LICenv var. Recommended orchestrator image:registry.gitlab.com/.../simulator:1.11.0-feat.2569583284.7d69a070. New extras passthrough:filter_extrasinsrc/runtime/templates.rs:~116filters any workspace.envkey againstMANAGED_SIM_ENV_KEYSconst (templates.rs:~56); survivors auto-injected asKEY: "${KEY}"into every simulator service (sorted alpha, deterministic); each emitstracing::info!(env_var, simulator, "passing env var to simulator").bootstrap.rs::ensure_all_generatedreads.envviaAdapter::Dotenvand threads filtered set intoSimulatorGenCtx. sim-postgres aliasing pattern (broadly reusable): aliased the postgres image’s native env (POSTGRES_USER/PASSWORD/DB) to the orchestrator’sSIMULATOR_DATABASE_*so one.envoverride controls both — kills the silent-auth footgun where two services had independent credential defaults. Pluspg_isreadyhealthcheck. Audit polish patterns kept: (1) derive UI summary strings from the actual invocation-args function (pre-fix bug: success row literally said"up -d --build --remove-orphans"whileup_compose_argshad omitted--buildfor sim → silent drift; fix: derive both fromup_compose_argsoutput); (2) single-source the image tag (SIM_IMAGE_TAG="dev") and service name (SIM_ORCHESTRATOR_SERVICE="mando-simulator") via placeholders (PH_SIM_IMAGE_TAG,PH_SIMULATOR_SERVICE) threaded by the renderer attemplates.rs:354-355; (3)volume.rserror string usesCOMPOSE_PROJECT_NAME/SIMULATOR_PROJECT_NAMEconsts; (4)-b/--buildhelp text reworded (“no-op on dev, primarily for sim”); (5)MANDO_SIMULATOR_IMAGE-without-pull Warn row added to the simulator plan render. → mando-cli-simulator-env-contract-2026-06-02.
2026-05-30
- mando-cli session: simulator runtime landed on
feature/simulator-runtime(commitb244f2e, +1280/−240, 27 files, 2 new). Adds a second first-class Docker Compose stackmando-simcoexisting with the devmandoproject — neither evicts the other. Six runners (forecast/optimization/execution/market/asset/post-delivery-market) generated from a single data-driven Rust listSIMULATOR_RUNNERS; own Postgres (sim-postgres, host port 5433, DBbess_simulation); droppedhost_project()(mando-simulator is a service, onlyProject::SimulatorRunneris a real cloned repo + newProject::DEVsubset excludes it);RunProfilegainscompose_project/layers(); env merged viafill_build_args(not--env-file); Python healthcheck; Gurobi license as file mount. Two-stack ergonomics centralized in newsrc/runtime/service_stack.rs::select_profile— shared resolver forlogs/exec/volume. Supersedes GitLab MR !2 /feature/BE-2256(balint) which was hardcoded YAML. Defines the §A orchestrator↔runner env contract (CLI-defined, services implement): runner env (SERVER_PORT,APP_NAME,SIMULATION_MANDO_HOST/PORT,GITLAB_TOKEN,NEXUS_INDEX_URL, optimization-onlyGRB_LICENSE_FILEmount,GET /health); orchestrator env (per-runnerSIMULATOR_<NAME>_REPO_URL/BRANCH/COMMIT_HASH, comma-separatedSIMULATOR_RUNNERS, Postgres +SIMULATOR_DB_SCHEMA). Services (mando_simulatorcrate,simulator-runnerimage, six sim repos) do NOT exist yet — CLI leads the contract. Multi-perspective audit found + closed: HIGH (run_captureempty-files guard for spurious status row), 3 functional bugs (volume clearresolved against dev files,getnot alias-aware,pull/status loud on un-cloned runner), 6 DRY violations (added sharedSIMULATOR_PROJECT_NAME/PROFILE_NAME/sim-service-name consts; removed redundantSimRunner.repo;volume clearjoined the single-resolver flow). Fresh-eyes re-review confirmed all closed. Process lesson: per-task verification usedcargo test --bin mandowhich skipstests/integration tests — masked a compile break intests/up_compose_smoke.rs(RunProfileliterals missing newcompose_projectfield). Final-review caught it. Going forward: fullcargo test, never--bin mandofor green-light. Fullcargo test: 785 passed, 1 ignored (docker-requiring smoke). Clippy unchanged frommainbaseline. Authored solely by andras.lederer (no co-author). End-to-endmando up -p simulatordeferred until service images land. → mando-cli-simulator-runtime-2026-05-30.
2026-05-26
- Investigation captured (diagnosed, not fixed):
ErrorWithStepStatus::log(status, message)returned from any flow step silently dropsmessageat the parent log site.StepResult::log()(mando-lib/src/workflow/mod.rs:150-229) destructures theLogvariant with..(lines 155-159), droppingmessage; only the generic wrapper string +flow.step.status+flow.step.execution_timereachtracing::error!/warn!(lines 196-225).Displayimpl (mod.rs:443) is#[error("status: {status}")]— message also dropped from stringification.status_or_error(mod.rs:231-239) collapsesLog→Ok(status), losing it again. Top-level catch atmando-bess/src/workflow/flow.rs:289only sees"status: Error".Error(anyhow)arm is correctly logged viaerror!(mod.rs:160-171) — only::Logis broken. Tests atmod.rs:548-605assert level + wrapper string only, nevermessagepayload — how the regression shipped. Affects all environments. Possible overlap with follow-up commitsc945514e,4c543cb1,567373a5,63d6fa69,8f9297e4onfeature/BE-2272— diff before patching. Secondary:mando-lib/src/app/dd_formatter.rs:122-124record_errorusesvalue.to_string()(Display only), but niche path. → flow-step-log-message-dropped-2026-05-26. - mando-cli session: triaged Gabi’s 2026-05-25 bug report against v0.4.0 compose-runtime rewrite (commit
6ba0d61). Both reported bugs CONFIRMED real. (1)src/runtime/templates/runconfig/build.yml:11+build_dev.yml:18usecontext: .— Compose resolves relative paths from the compose-file’s parent dir, so context becomes<project>/runconfig/(no Dockerfile). Fix:context: ... (2) Mocked runconfig —mocked.ymlonly defines<service>-mocks, butup.rs:192passes bare slug; reporter’s diagnosis was incomplete — the exact “Must specify either image or build” error originates inrender_override(templates.rs:298-325) which emits a malformed<service>:stub perdocker_targetinto.mando/override.builtin.yaml. The stub is normally dormant viaprofiles: ["{run_tag}"](templates.rs:317) — that’s a load-bearing invariant. Cleanest fix: rename positional arg AND skip mocked entries in override generation. Smoke-test round (8de8f64) missed both: Bug 1 masked by image cache; Bug 2 not exercised withmando-mocked-algosset as default profile against fresh checkout. Fixes not yet committed. → mando-cli-v0.4.0-compose-bugs-triage-2026-05-26.
2026-05-22
- mando-cli session: documented the local macOS (Apple Silicon) cross-compile recipe for producing a Linux x86_64 / WSL release binary of
mandov0.4.0. Targetx86_64-unknown-linux-musl(static-pie). Two gotchas captured: (1) Docker pulls the arm64 image on Apple Silicon →ring 0.17C build fails withcc1: unrecognized command-line option -m64→ fix is--platform linux/amd64; (2) optionalqueryfeature has path deps into../mando/.worktrees/BE-1595/*that Cargo reads during resolution even when disabled → must mount thepoc/parent dir. Verified binary inubuntu:24.04+alpine(mando --version→mando cli 0.4.0). Distinct from the CI build mirror; cross-linked both ways. → mando-cli-wsl-linux-build.
2026-05-18
- Investigation captured (diagnosed, not yet fixed): Calculated and Virtual DPs leak rows past
toin all four retrieval methods (retrieve/retrieve_at/retrieve_history/retrieve_client). Root cause inMandoServiceBase::handle_data_point_types(mando-lib/src/service_base.rs:94-159) — Virtual/Calculated branches lack a finalfilter_data_frame_by_rangeafter Polars transformations. Two leak mechanisms: (A)convert_to_metadataupsampling explodes 1 row → N (convert_resolution.rs:39-95); (B)evaluate_expressionFull-join/concat-group_by produces union of dep timestamps (evaluation.rs:62-72, 175-178).EvaluationMetaData.rangeis plumbed but only consumed byFillMissing. Proposed fix: trim per-DP at final Virtual/Calculated branches usingevaluation_metadata[&dp_id].range. → calculated-virtual-dp-range-cutoff-bug-2026-05-18.
2026-05-06
- mando-cli session: 5 fixes shipped + 1 design shelved.
0be3458feat:mando mock downwith idempotent teardown (404 fromremove_container= success). Pins canonical 7-step pattern for docker-backed lifecycle commands. → mando-cli-mock-down-idempotent-2026-05-06.f8a54bffix: WireMock healthcheck targets/__admin/health(200) instead of/__admin(302→404) usingcurl -fsS. Diagnostic technique:docker inspect --format '{{json .State.Health}}'(wget exit 8 = HTTP error). → mando-cli-mock-down-idempotent-2026-05-06.68bcc63fix:mando statusmade read-only and bounded under 2s. Newconnect_readonly(single connect + 2s timeout, no retries, noensure_database) andtable_existshelpers indb/flyway.rs; setsstatement_timeout = '2s'post-connect. Status commands must be pure reads. → mando-cli-status-readonly-2026-05-06.6b1f7c7feat: yaml-driven build context to stop COPY-everything hangs. Newbuild.context_includes: Vec<String>onServiceBuildDef+ newruntime/build_context.rs::build_filtered_tarused by bothcommands/build.rsandruntime/runner.rs. Caught + fixed runner.rs hard-coded"Dockerfile"regression in same commit. → mando-cli-build-context-filter-2026-05-06.302be50feat: shippedcontext_includesdefaults for all 5 app services insrc/config/defaults/*.yaml. → mando-cli-build-context-filter-2026-05-06.- SHELVED: profile-driven build variants (dev runtime-only Dockerfile +
cargo build --releasepre-step vs release multi-stage chef Dockerfile). Captured design + open questions; no code shipped. → mando-cli-build-variants-shelved-2026-05-06.
- Parallel-release CI restructure shipped to mando-cli-github-build-mirror (
a939117on master): split monolithicgitlab-releasejob intoinit-gitlab-release→buildmatrix (each matrix job uploads + links its own binary) →release+gitlab-finalize(checksums only). Linux/macOS no longer block on Windows aarch64. New “Parallel release flow (2026-05)” section in the doc.
2026-05-05
- BE-2272 branch
feature/BE-2272(renamed from priorbugfix/BE-2023) — continuation of the BE-1842 Datadog Observability arc; flattens DD log JSON. - Removed the
span.*namespace from formatter output:flow.exec_id,flow.context,step.name,step.connectionnow sit at the document root alongsideerror.*/http.*(symmetric DD facet layout). - Single-file change in mando-lib
src/app/dd_formatter.rs(+295/-16): droppedserialize_entry("span", ...), addedMapVisitor: tracing::field::Visitto collect event fields intoserde_json::Map<String, Value>, span-fields-first / event-fields-second merge with explicit event-wins precedence. - Removed magic
nameinjection incollect_span_fields(was outermost span name; unused in DD dashboards). - 11 unit tests added with a reusable capture harness (
tracing::subscriber::with_default+ customMakeWriteroverMutex<Vec<u8>>); pattern reusable for futuredd_formatterchanges. - 262 workspace tests pass, 0 regressions; scope strictly contained to the formatter.
- Plan in repo:
docs/superpowers/plans/2026-05-05-flatten-log-fields-to-root.md. - Open follow-ups: DD dashboard column migration (
@span.X→@X),execution.idvsflow.exec_idnaming unification, deadErrorCodederive arms in mando-lib-macro. - Branch state: local-only on
feature/BE-2272, uncommitted.
2026-05-04
dc7b4259chore: bumpedCargo.lockfor py-mando after pulling inthiserrordep.cd97fc35fix: converted py-mando error logs tomando_core::error!macro so Python-binding errors carry typederror.kind(parity with Rust pattern from MR !481).923603f0refactor: removed inlinestep.name/step.connectionevent fields now that the step span carries them — children inherit viadd_formatterroot→leaf scope walk.b8d3278dfix: addedstep.nameandstep.connectiononto the step span atmando-lib/src/workflow/mod.rs:350so child events inherit them in Datadog (see BE-1842 Datadog Observability).c945514efix: log step errors at the failure site to preserve realerror.kindinstead of generic wrapper at the catch boundary.4c543cb1fix: downgraded parent flow error logs towarnwhen the child step has already logged the error (deduplicates Datadog noise).ab622e29fix: instrumented everytokio::spawncall with tracing spans so async tasks no longer drop trace context.5618603efix: removed per-layerFilterFnfrom the OTel layer — the filter was suppressing events and breaking span field inheritance (root cause of BE-1842 Datadog Observability regressions).117f7b58fix: foundation commit onbugfix/BE-2023— deduped step error logging, upgraded OTel deps, threadedexecution_idthroughFlowInfo.- All 9 commits are follow-ups to MR !481 (
feat: error handling redesign, BE-2023) addressing reviewer feedback (Balazs Mracsko, Krisztian Fekete) and Datadog defects; iterative debugging captured in screenshots under/Volumes/bandi/coding/poc/mando/(datadog-tab2-broken.png,dd-doublelog-1.png,dd-current-state.png,dd-log-expanded.png, etc.). Context: Agent Context. - Initialized activity log.