Summary
ops/schema-migration/migrate-legacy-workflow.py:120 calls s.get('type') without validating that each step is a mapping. A valid YAML document with steps: [invalid-scalar] raises AttributeError: 'str' object has no attribute 'get' and exits 1, instead of returning the documented REFUSED diagnostic. The refusal-boundary contract the script advertises is not enforced for this case.
Surfaced during the 2026-09-10 launch-prep PR sweep; reproduced at head bcafd4218c7011cc3ec4214d1c14703547a59fac in an isolated PyYAML 6.0.3 venv against a byte-for-byte source extract. The relevant flows PR is #238, whose commentary called this out but did not fix the guard.
Repro
schema-migration-input.yaml:
version: '1.0'
name: test
workflows:
- name: test
steps:
- invalid-scalar
python3 ops/schema-migration/migrate-legacy-workflow.py schema-migration-input.yaml
Actual:
Traceback (most recent call last):
...
File "ops/schema-migration/migrate-legacy-workflow.py", line 120, in ...
step_type = s.get('type')
AttributeError: 'str' object has no attribute 'get'
Expected
The script emits a REFUSED diagnostic naming the malformed step and its shape, exit 1 with the diagnostic on stderr — same contract the rest of migrate uses for malformed inputs.
Suggested direction
At line 120, validate isinstance(s, dict) before .get. On failure, emit REFUSED [malformed_step] step at index N is not a mapping (got <type>). Add a regression test covering scalar-step and non-dict-step inputs to the migrate test suite.
Acceptance criteria
python3 ops/schema-migration/migrate-legacy-workflow.py <yaml-with-scalar-step> exits 1 with a REFUSED diagnostic instead of a Python traceback.
- Regression test asserts the exact diagnostic shape for a scalar step, a null step, and a step that is a list.
Context
Filed from the sweep report at commit 64de443 on branch sweep/v2-launch-prep-0910. See PR-SWEEP-REPORT-0910.md §#238 and ops/runtime-evidence/pr-sweep-0910.txt for the exact traceback.
Summary
ops/schema-migration/migrate-legacy-workflow.py:120callss.get('type')without validating that each step is a mapping. A valid YAML document withsteps: [invalid-scalar]raisesAttributeError: 'str' object has no attribute 'get'and exits 1, instead of returning the documentedREFUSEDdiagnostic. The refusal-boundary contract the script advertises is not enforced for this case.Surfaced during the 2026-09-10 launch-prep PR sweep; reproduced at head
bcafd4218c7011cc3ec4214d1c14703547a59facin an isolated PyYAML 6.0.3 venv against a byte-for-byte source extract. The relevant flows PR is #238, whose commentary called this out but did not fix the guard.Repro
schema-migration-input.yaml:Actual:
Expected
The script emits a
REFUSEDdiagnostic naming the malformed step and its shape, exit 1 with the diagnostic on stderr — same contract the rest of migrate uses for malformed inputs.Suggested direction
At line 120, validate
isinstance(s, dict)before.get. On failure, emitREFUSED [malformed_step] step at index N is not a mapping (got <type>). Add a regression test covering scalar-step and non-dict-step inputs to the migrate test suite.Acceptance criteria
python3 ops/schema-migration/migrate-legacy-workflow.py <yaml-with-scalar-step>exits 1 with aREFUSEDdiagnostic instead of a Python traceback.Context
Filed from the sweep report at commit
64de443on branchsweep/v2-launch-prep-0910. SeePR-SWEEP-REPORT-0910.md§#238 andops/runtime-evidence/pr-sweep-0910.txtfor the exact traceback.