Category
Technical Debt (cleanup, refactor)
Component
Tests
Description
The pod job registers each L4 two-machine example as its own hand-written workflow step, while every other worker example is collected by pytest and scheduled by the ST framework in conftest.py. The asymmetry is not cosmetic: it means the L4 examples get none of what that framework provides, and adding one costs four edits to _st-pod.yml instead of zero.
How the L2/L3 examples are wired. Each one ships a thin test_*.py next to its main.py that declares its resource needs as markers and delegates to main.run(...), e.g. examples/workers/l3/allreduce/test_allreduce.py:
@pytest.mark.platforms(["a2a3sim", "a2a3"])
@pytest.mark.runtime("tensormap_and_ringbuffer")
@pytest.mark.device_count(2)
def test_allreduce(st_platform, st_device_ids):
rc = run([int(d) for d in st_device_ids], platform=st_platform)
assert rc == 0
conftest.py::_collect_resource_jobs picks these up as kind="standalone" jobs (any non-class function carrying device_count + runtime), bin-packs them with the L3 SceneTestCase classes through parallel_scheduler.run_jobs, and hands each one its devices via the st_device_ids fixture. One pytest examples tests/st invocation in _st-npu-a2a3.yml collects all of them; --platform filtering, device allocation, marker-based skipping and quarantine (-m "not sdma") all come for free.
Counting test_*.py under examples/workers/: l2 = 5, l3 = 10, l4 = 0. The three L4 examples have only main.py + run_parent.sh.
What the L4 examples get instead. Three near-identical 8-line steps in _st-pod.yml, each with a hand-assigned id:, plus a matching line in the Report pod example results shell script, because continue-on-error: true rewrites a failed step's conclusion to success and only outcome carries the truth.
Consequences:
- Registration is manual and duplicated in two places. Adding a fourth example means: a new step, a unique
id:, a new env-prefix, and a new line in the summary script. Forgetting the summary line is silent — the example runs, fails, and the job still reports green, which is the exact failure mode .claude/rules/ci-change-detection.md §7 warns about ("a gating bug shows up as a green check").
- No platform declaration. The L2/L3 examples state
@pytest.mark.platforms([...]). The L4 examples encode their target platform as a shell default inside run_parent.sh (SIMPLER_..._PLATFORM:=a2a3), so nothing prevents the pod job from invoking one against a platform it was never written for, and nothing skips it when the pod machines don't match.
conftest.py has no concept of a second machine at all. Grepping it for remote / peer / node_count / pod returns nothing. So this is a genuine framework gap, not an example that forgot to opt in — the st_device_ids fixture allocates local devices from a local pool, and there is no fixture that could hand a test the peer's endpoint.
- The two suites can drift. A
conftest.py change to device allocation, platform filtering or quarantine applies to 15 examples and silently skips 3.
Location
- `.github/workflows/_st-pod.yml` — the three enumerated `pod-run-example` steps and the `Report pod example results` script that mirrors them
- `conftest.py::_collect_resource_jobs` — collects `kind="standalone"` jobs from `device_count` + `runtime` markers; no multi-machine notion
- `conftest.py::st_platform`, `conftest.py::st_device_ids` — allocate from a local device pool only
- `examples/workers/l3/allreduce/test_allreduce.py` — the pattern the L4 examples do not follow
- `examples/workers/l4/{vector_add,global_tload,compute_then_tload}_mixed_l3/` — `main.py` + `run_parent.sh`, no `test_*.py`
Proposed Fix
The blocker is that a pod test needs the peer endpoint, and no fixture can currently supply it. Two options, in increasing scope:
(a) Collapse the enumeration without touching conftest.py. Keep the shell driver, but make the step list data instead of copy-paste — a matrix over (example, env-prefix, parent-script), or a single step looping over the examples and accumulating failures. This removes the summary-script duplication (consequence 1) and nothing else. Small, and worth doing regardless.
(b) Give the framework a pod fixture and let pytest collect the L4 examples too. Add a peer_endpoint fixture that reads the pod .env values the workflow already resolves (POD_REMOTE_HOST, POD_L3_DAEMON_PORT, POD_REMOTE_DEVICES) and skips when they're absent, plus a marker for "needs a peer machine" so _collect_resource_jobs can route it. Then each L4 example gets the same thin test_*.py its L2/L3 siblings have, and _st-pod.yml shrinks to one pytest invocation with a peer-selecting marker. This addresses all four consequences, and starting the daemon stays in the action (it must outlive the step).
Note that (b) subsumes (a) but is meaningfully larger, since the daemon lifecycle currently lives in .github/actions/pod-run-example and would need to be reachable from a fixture or hoisted to a once-per-job step. Suggest doing (a) now and treating (b) as the real fix.
Whichever path: the summary-script mirroring should go away, since a registration that can be half-completed and still report green is the part most likely to bite.
Priority
Medium (minor risk, should fix in next few releases)
Category
Technical Debt (cleanup, refactor)
Component
Tests
Description
The pod job registers each L4 two-machine example as its own hand-written workflow step, while every other worker example is collected by pytest and scheduled by the ST framework in
conftest.py. The asymmetry is not cosmetic: it means the L4 examples get none of what that framework provides, and adding one costs four edits to_st-pod.ymlinstead of zero.How the L2/L3 examples are wired. Each one ships a thin
test_*.pynext to itsmain.pythat declares its resource needs as markers and delegates tomain.run(...), e.g.examples/workers/l3/allreduce/test_allreduce.py:conftest.py::_collect_resource_jobspicks these up askind="standalone"jobs (any non-class function carryingdevice_count+runtime), bin-packs them with the L3SceneTestCaseclasses throughparallel_scheduler.run_jobs, and hands each one its devices via thest_device_idsfixture. Onepytest examples tests/stinvocation in_st-npu-a2a3.ymlcollects all of them;--platformfiltering, device allocation, marker-based skipping and quarantine (-m "not sdma") all come for free.Counting
test_*.pyunderexamples/workers/: l2 = 5, l3 = 10, l4 = 0. The three L4 examples have onlymain.py+run_parent.sh.What the L4 examples get instead. Three near-identical 8-line steps in
_st-pod.yml, each with a hand-assignedid:, plus a matching line in theReport pod example resultsshell script, becausecontinue-on-error: truerewrites a failed step'sconclusionto success and onlyoutcomecarries the truth.Consequences:
id:, a newenv-prefix, and a new line in the summary script. Forgetting the summary line is silent — the example runs, fails, and the job still reports green, which is the exact failure mode.claude/rules/ci-change-detection.md§7 warns about ("a gating bug shows up as a green check").@pytest.mark.platforms([...]). The L4 examples encode their target platform as a shell default insiderun_parent.sh(SIMPLER_..._PLATFORM:=a2a3), so nothing prevents the pod job from invoking one against a platform it was never written for, and nothing skips it when the pod machines don't match.conftest.pyhas no concept of a second machine at all. Grepping it forremote/peer/node_count/podreturns nothing. So this is a genuine framework gap, not an example that forgot to opt in — thest_device_idsfixture allocates local devices from a local pool, and there is no fixture that could hand a test the peer's endpoint.conftest.pychange to device allocation, platform filtering or quarantine applies to 15 examples and silently skips 3.Location
Proposed Fix
The blocker is that a pod test needs the peer endpoint, and no fixture can currently supply it. Two options, in increasing scope:
(a) Collapse the enumeration without touching
conftest.py. Keep the shell driver, but make the step list data instead of copy-paste — a matrix over(example, env-prefix, parent-script), or a single step looping over the examples and accumulating failures. This removes the summary-script duplication (consequence 1) and nothing else. Small, and worth doing regardless.(b) Give the framework a pod fixture and let pytest collect the L4 examples too. Add a
peer_endpointfixture that reads the pod.envvalues the workflow already resolves (POD_REMOTE_HOST,POD_L3_DAEMON_PORT,POD_REMOTE_DEVICES) and skips when they're absent, plus a marker for "needs a peer machine" so_collect_resource_jobscan route it. Then each L4 example gets the same thintest_*.pyits L2/L3 siblings have, and_st-pod.ymlshrinks to one pytest invocation with a peer-selecting marker. This addresses all four consequences, and starting the daemon stays in the action (it must outlive the step).Note that (b) subsumes (a) but is meaningfully larger, since the daemon lifecycle currently lives in
.github/actions/pod-run-exampleand would need to be reachable from a fixture or hoisted to a once-per-job step. Suggest doing (a) now and treating (b) as the real fix.Whichever path: the summary-script mirroring should go away, since a registration that can be half-completed and still report green is the part most likely to bite.
Priority
Medium (minor risk, should fix in next few releases)