Handoff — Production Step 7A/7B with dash fusion (modelling-lines 0.13.0) from existing Step 6 clusters
Summary
Goal. Produce Step 7A (skeletonize, parallel on T4 GPUs) and Step 7B (connect + road axis, CPU) outputs on Azure ML for Abschnitte 1, 2 and 3, reusing the already-finished Step 6 mask clusters, with the new boundary dash fusion: dashes that straddle a segment plane are exported as one <line> fitted from both point clusters instead of two touching halves. The helper pipelines pipelines/helpers/abschnitt_{1,2,3}_from_step6.yaml run exactly this graph (Prepare 7 → 7A → 7B → 7C overlay; no Step 8/10).
State. Package iolabs-point-cloud-modelling-lines 0.13.0 is on Nexus (tag v0.13.0). Orchestrator master @ 6de8934 pins env s7_cluster_stepper:23 in both Step 7 components. todo Env v23 is not registered in the workspace (checked 2026-09-04: az ml environment show --name s7_cluster_stepper --version 23 → "No environment exists"). Register it first; submitting before that fails. Battlebox checkout was 2 commits behind master when this was written.
Deliverable. One successful *_from_step6 run per Abschnitt on env v23, with the verification in §Verification done (sidecars present, fusion summary > 0 pairs, XML line count lower than the previous run, control plots sane), and run names + child GUIDs recorded in docs/handoff_abschnitt_1_step3_planes.md §3 style (or a new docs note) and reported back to Miro.
Current state code done nothing submitted yet
- What changed in Step 7 (0.13.0). Stage 1 flags DASHED segments whose axis end lies within 0.5 m of the segment's first/last plane (
boundary_end) and writes their points to a sidecarNNNN_lane_state_partial_boundary_clusters.npznext to each partial JSON (snapshot schemaiolabs.step7.lane_state.v4). Stage 2 merges lanes as before, thenfuse_touching_dashesrefits each facing pair as one segment from the union cloud (gates: gap ∈ [−0.5, 0.5] m, lateral ≤ 0.25 m, heading ≤ 5°; axis-join fallback only if the fit throws). Config sectiondash_fusionincluster_stepper.default.json, enabled by default. - Orchestrator side. PR #6 (merged,
b999c96): conda pin 0.13.0,environments/s7_cluster_stepper/environment.ymlversion 23,components/s7a_skeletonize.yml+s7b_connect_axis.yml→azureml:s7_cluster_stepper:23, comment fixes only. No script change: 7A passes onlyoutput_path, 7B passes the partials folder; the package writes/finds the sidecar itself. 7A'sstep7a_snapshotsoutput isrw_mount, so the sidecars are uploaded with the JSONs. - Validated locally (Battlebox, CPU, Abschnitt 1 segments 0–21, run3 data): 72 dashes flagged, 19 facing pairs in 9 lanes fused (all by refit), XML
<line>827 → 808, stage-1 lane/segment counts unchanged (266 / 841). Scratch:/mnt/d/a123-data/ai3d318/step7ab_v4/. - Compatibility. 0.13.0 reads v1–v3 partials (fuses in axis mode without sidecars). 0.12.x cannot read v4 partials → 7A and 7B must run on the same env version; never mix v22/v23 in one run.
- Battlebox tooling (checked 2026-09-04).
az2.88.0 withml2.44.1, logged in asms@iolabs.ch, defaultsgroup=AI3D-rg workspace=ai3d-lf-mlw-pc-01already set. Repo venv.venvPython 3.12.13;uv,claude,cursor-agent,codexin~/.local/bin//usr/local/bin..claude/settings.local.jsonin the repo allows only git → az calls will prompt unless run under an allow rule.
Inputs per Abschnitt (child-job GUIDs on workspaceblobstore)
Mount form is mandatory: azureml://datastores/workspaceblobstore/paths/azureml/<guid>/<output>/. Raw https:// blob URLs fail with ScriptExecution.StreamAccess.Authentication. Keep step3 and step6 from the same chain: prepare_data_for_step_7 joins step3_output/manifests/branches.json against step6_output/<geometry_dir>/lane_points/segment_*/clusters_mask/run6_cluster_*.npz.
| Abschnitt | step3_output | step4_output (7C only) | step6_output | step1 trajectory_output | Previous step7_output (baseline) |
|---|---|---|---|---|---|
| A1, July chain (what the helper YAML points at today) | 77f7ac77-a89a-446c-911c-37182f8caf4d | 1e5a9e8f-e2aa-4fe7-ade5-e8e413839ff5 | 9d21f6cf-59aa-46e7-a5ef-c3d037caa2d9 | 17853b44-4e50-422d-a3b2-f3c5049bf04b | 7b3292b5-ec5b-488e-81fc-f7c795c19883 (run …from_step6_20260722082250) |
| A1, return-count / no-angle-filter chain (AI3D-382, 2026-09-03, Step 6 on T4 nodes) | e2b345bc-f1a2-434b-b02d-ebb944735b0a | 05482cf3… prefix | 9fe47e47… prefix | reuse 17853b44… | none yet |
| A2 | c678ba94-9691-421c-a62b-9963e3e74227 | f9d7d5da-f4aa-46b7-95c1-f865d2bb2d24 | 7d177605-2380-4a1c-a7ac-934ec90ecf63 | f5757d3b-9930-4c14-af44-be1671767718 | 5361bf44-540f-4182-9b70-f94e7f7477b7 |
| A3 | f290eb36-6390-4a74-83a0-1aaf75197390 | 0e616d05-0099-4a08-bcf4-f5569fad8a3c | f51a37f7-ec11-46c5-967c-b2e5860f74c6 | 8d3072e4-3acf-45cc-ae35-67e2810dc888 | look up in the A3 from_step6 helper history / job list |
The A2/A3 helper YAMLs already carry their GUIDs; verify them against the table before submitting (grep existing_ pipelines/helpers/abschnitt_2_from_step6.yaml). For the A1 return-count chain the full Step 4/6 GUIDs must be resolved first (see step 3 below); the source table is docs/handoff_abschnitt_1_step3_planes.md §3.
Run procedure (on Battlebox, in the orchestrator repo)
- Sync the repo.
cd ~/dev/3dai.iolabs.orchestrator && git status --short && git pull --ff-only origin master git log --oneline -1 # expect 6de8934 or newer grep -n "s7_cluster_stepper" components/s7a_skeletonize.yml components/s7b_connect_axis.yml # both :23 .venv/bin/python -m pytest -q tests/test_env_pins.py - Register env v23 (skip only if
showsucceeds). The first job on a new env builds the image (~10–20 min); validate/submit after registration.
Do not printaz ml environment show --name s7_cluster_stepper --version 23 -o table \ || az ml environment create --file environments/s7_cluster_stepper/environment.yml az ml environment list --name s7_cluster_stepper --query "[0].version" -o tsv # expect 23conda.ymlin logs or chats: the pip index line embeds Nexus credentials. - Decide the A1 input chain (open question 1). If Miro wants the return-count chain, resolve the full GUIDs:
Note: on 2026-09-04 the blob listing for prefixaz storage blob list --account-name ai3dlfmlwpc011354919387 \ --container-name azureml-blobstore-919dd9b5-5c3a-4888-80a3-6b3f79f2fc48 \ --prefix "azureml/9fe47e47" --delimiter / --auth-mode key --query "[].name" -o tsv # same for azureml/05482cf3 ; or: az ml job list --parent-job-name <from_step5_to_step6b parent> -o tableazureml/9fe47e47returned no entries, so the Step 6 output of that chain is probably stored under a different job GUID than the prefix in the doc; resolve it viaaz ml job list --parent-job-nameon the AI3D-382 from_step5_to_step6b parent run (experimentlanefinder_abschnitt_1, 2026-09-03) and check thestep6_outputblob folder exists before submitting. Then override at submit time instead of editing the YAML (--set inputs.existing_step6_output.path=azureml://datastores/workspaceblobstore/paths/azureml/<guid>/step6_output/, likewise step3 and step4). - Validate, then submit one Abschnitt at a time (7A takes all 6 T4 instances; A1 has 131 + 11 segments across two branches).
export RUN="lanefinder_abschnitt_2_from_step6_$(date -u +%Y%m%d%H%M%S)" az ml job validate --file pipelines/helpers/abschnitt_2_from_step6.yaml -o json az ml job create --file pipelines/helpers/abschnitt_2_from_step6.yaml --set name="$RUN" \ --query "{name:name,status:status,studio:services.Studio.endpoint}" -o json--set name=…is mandatory (fixedname:in the YAML, AML rejects duplicates). Suggested order: A2 first (smallest risk, has a baseline), then A3, then A1. - Monitor.
Child display names:az ml job show --name "$RUN" --query "{status:status}" -o tsv az ml job list --parent-job-name "$RUN" --query "[].{n:display_name,s:status,id:name}" -o table az ml job stream --name <7A child id> # live logsPrepare Data for Step 7,Step 7A - Skeletonize,Step 7B - Connect and Axis,Step 7C - Overlay XML on Topdown Tiles. Kibana (data viewlogs-iolabs-*):ai3d.pipeline_step: "s7a"/"s7b", correlate withai3d.aml_root_run_id. Expected duration from earlier runs: 7A about 1–2 h per Abschnitt on 6 T4 instances; 7B minutes. - Record run name, 7A/7B child GUIDs and the
step7_outputpath per Abschnitt (needed later by Step 8/10 helpers), and report to Miro with the verification numbers.
Verification (what "done" means)
- Env actually used. In the 7A/7B child job details the environment must be
s7_cluster_stepper:23; in 7B logs the XML metadatasoftware_version/pkg_version("iolabs-point-cloud-modelling-lines")must read0.13.0. - Sidecars exist. In the 7A output (
azureml/<7A child>/step7a_snapshots/<geometry_dir>/lane_points/) expectNNNN_lane_state_partial.jsonandNNNN_lane_state_partial_boundary_clusters.npzfor most segments (segments without boundary dashes legitimately have no sidecar). 7A logs: eventstep7_partial_boundary_clustersper segment.az storage blob list --account-name ai3dlfmlwpc011354919387 \ --container-name azureml-blobstore-919dd9b5-5c3a-4888-80a3-6b3f79f2fc48 \ --prefix "azureml/<7A child>/step7a_snapshots/" --auth-mode key \ --query "[?ends_with(name,'.npz')] | length(@)" - Fusion happened. 7B log event
step7_dash_fusion_summaryper branch:fused_count > 0,refit_count ≈ fused_count,axis_count0 or near 0. On the local A1 subset the ratio was 19 pairs per 22 segments; whole A1 should be in the order of 100+ pairs. Iffused_count = 0with sidecars present, stop and diagnose (flags not facing → checkboundary_endvalues in a partial JSON). - XML sanity. Download
step7_output/branches/<branch>/run7_lanes_*.xmland compare with the baseline run of the same Abschnitt:<line>count lower by roughly the fused-pair count; feature (lane) count about equal; no line longer than ~12 m for dashed features (a 20 m+ dash means two neighbours got fused; the gates should make this impossible — report it).az ml job download --name <7B child> --download-path /tmp/ai3d-aml/$RUN --all grep -c "<line" /tmp/ai3d-aml/$RUN/named-outputs/step7_output/branches/*/run7_lanes_*.xml - Control plots.
run7_control_plot_<branch>_*.pdfpresent per branch and the 7C overlay collages look like the previous run (dashes continuous across segment limits, no doubled strokes at plane positions). - Manifest.
step7_output/manifests/step7_branches.jsonpresent with all branches (Step 10 hard-requires it).
Risks & open questions
- decide Which A1 Step 6 is production? The committed helper points at the July chain (angle filter on, 118 GB Step 3). AI3D-382 produced a newer no-angle-filter / return-count chain (188.8 GB, Step 6 on T4 nodes, GUID prefixes only). Ask Miro before submitting A1; default to the helper as committed if unreachable, and say so.
- fail-fast
error_threshold: 0in 7A. One failed segment fails the whole 7A job (3 h timeout per mini-batch, 1 retry). Historic causes: CUDA driver mismatch (torch pinned to cu124 for the T4 driver — keep it), OOM on very large segments (the return-count Step 6 is bigger than July's). On failure read the mini-batch log of the failing segment before resubmitting; do not raise the threshold to mask it. - env Silent old env. Forgetting to register v23 means the components reference a non-existent asset → submit error; but if someone registered a v23 from a different conda.yml earlier, AML would happily use it. Check
az ml environment show … --version 23creation time is after 2026-09-04 and its conda hasmodelling-lines==0.13.0. - first run Refit on GPU stage-1 path was never exercised on AML. Locally everything ran CPU-only. The sidecar write happens on the 7A node (
rw_mount); if uploads lag, 7B may see JSONs without sidecars → it still succeeds but fuses in axis mode (axis_counthigh). That is a symptom to report, not a pass. - quota 6 T4 instances for 7A, F4s_v2 quota 10 vCPU for CPU steps; run Abschnitte sequentially.
- stale docs README's
pipelines/main.yamlandhelpers/pipeline_long_from_step7.yamldo not exist; the azure-cli skill's child display names are outdated. Use the names in §Run. - out of scope Step 8/9 and Step 10 ACC export are not part of this handoff;
pipelines/helpers/abschnitt_1_steps_8_9.yamlandabschnitt_2_from_step7.yaml(placeholder GUIDs) exist for later.
Suggested skills
azure-cli— constants block, job list/stream/download recipes, blob listing with--auth-mode key.battlebox-ssh— only if operating Battlebox from another machine (heredoc form, 10-minute call limit; AML jobs are unaffected by ssh session death).
Key artifacts & handles
- Orchestrator:
~/dev/3dai.iolabs.orchestratoron Battlebox,/mnt/data/dev/3dai.iolabs.orchestratoron Miro's machine; PR #6 bitbucket …/orchestrator/pull-requests/6 (merged6de8934). - Helper pipelines:
pipelines/helpers/abschnitt_1_from_step6.yaml,abschnitt_2_from_step6.yaml,abschnitt_3_from_step6.yaml. Components:components/prepare_data_for_step_7.yml,s7a_skeletonize.yml,s7b_connect_axis.yml,s7c_overlay_topdown.yml. Env:environments/s7_cluster_stepper/. - Step 7 wrapper scripts:
scripts/s7a_skeletonize/s7a_skeletonize.py,scripts/s7b_connect_axis/s7b_connect_axis.py. Earlier run/GUID notes:docs/handoff_abschnitt_1_step3_planes.md,README.md("Pipelines And Reruns", "Environment Strategy"),CLAUDE.md(env bump procedure). - Package: modelling-lines PR #11 (merged), release commit
7f16b14, tagv0.13.0; design/plan with drawings: miro-plans.pages.dev/merge-dashed-lanes-across-segment-boundaries-20260901; docsdocs/2d-lane-connection.md§Boundary dash fusion, modulesrc/iolabs_point_cloud_modelling_lines/dash_fusion.py. - Local validation on Battlebox:
/mnt/d/a123-data/ai3d318/(step7ab_v4/,compare_v4.py,run_7a_v4_chunk.sh), code copy~/dev/wt-ai3d318(tar-synced, not git; now obsolete since 0.13.0 is released). - AML: subscription
ba81b555-ffe9-4625-b90a-d0011d0b57c9, RGAI3D-rg, workspaceai3d-lf-mlw-pc-01, storageai3dlfmlwpc011354919387, containerazureml-blobstore-919dd9b5-5c3a-4888-80a3-6b3f79f2fc48, computesCPU-Compute-4x(F4s_v2) andNvidia-TeslaT4-2x-GPU-Compute.