Conversation
Freeze the parent-execute TaskWrite envelope produced by build_alters_task across a representative matrix, before the declarative-spec refactor, so the byte-identity contract has a regression oracle captured from known-good code rather than from the rewrite's own output.
…arsers from ArgFormat Move the alters app onto the framework's canonical (form, resolved) -> RunCommandSpec + assemble_envelope path, matching checksums: annotate AltersCreate with ArgFormat markers, replace the hand-rolled optional/flag arg dicts with build_command_args, and drop the hand-assembled TaskWrite. build_alters_task now threads ResolvedEntities through the spec builder so the resolved executor host drives the envelope target. Add derive_arg_parser_from_model to build make_arg_parser's value/flag mappings from a model's ArgFormat markers, and switch both the alters and checksums reverse parsers onto it, deleting the four hand-maintained mapping dicts so the markers are the single source of truth in both directions. Share the ArgFormat template resolver by relocating find_arg_format / resolve_arg_template into form_dsl/markers.py, and document the two blessed spec signatures in the framework spec module docstring. The emitted TaskWrite payload stays byte-identical (guarded by the new alters payload golden across the spec, task, and legacy-form paths) and the reverse parse round-trips unchanged.
There was a problem hiding this comment.
Pull request overview
Migrates the alters app onto the framework’s canonical declarative spec/envelope path and removes hand-maintained CLI arg mapping dictionaries by deriving reverse-parser mappings from ArgFormat markers (shared with checksums), with payload identity guarded by new golden snapshot tests.
Changes:
- Refactor alters to emit a
RunCommandSpecand rely onassemble_envelopefor uniform connectivity/target meta stamping. - Add
derive_arg_parser_from_model()and switch alters/checksums reverse parsing to use it, removing duplicated mapping dicts. - Add a committed alters payload golden + matrix tests to assert byte-identical envelopes across spec/task/legacy-form paths.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/app/sep/snapshots/payload/alters__payload.json | Adds golden payload matrix snapshot for alters envelopes. |
| tests/app/sep/apps/framework/test_pt_toolkit.py | Adds unit tests for derive_arg_parser_from_model and freezes prior mapping dict expectations. |
| tests/app/sep/apps/alters/test_spec.py | Updates alters spec tests to validate RunCommandSpec output and argument ordering/quoting behavior. |
| tests/app/sep/apps/alters/test_payload_snapshot.py | Adds snapshot tests ensuring spec/task/legacy paths reproduce the golden payload matrix. |
| app/sep/apps/framework/spec.py | Documents blessed spec signatures; relocates ArgFormat helper logic to markers module and uses it in arg building/validation. |
| app/sep/apps/framework/form_dsl/pt_toolkit.py | Introduces derive_arg_parser_from_model for reverse parser mapping derivation. |
| app/sep/apps/framework/form_dsl/markers.py | Adds shared find_arg_format / resolve_arg_template helpers and exports them. |
| app/sep/apps/framework/form_dsl/init.py | Re-exports the new marker helpers and derive_arg_parser_from_model. |
| app/sep/apps/checksums/deps.py | Switches checksums reverse-parser mappings to derived mappings. |
| app/sep/apps/alters/spec.py | Refactors alters spec builder to return RunCommandSpec and use build_command_args. |
| app/sep/apps/alters/models.py | Annotates alters form fields with additive ArgFormat markers for declarative arg rendering/parsing. |
| app/sep/apps/alters/deps.py | Updates task builder to resolve refs then use assemble_envelope(build_alters_spec(...)); switches reverse-parser mappings to derived mappings. |
The reverse parser (derive_arg_parser_from_model) derives a value arg from the
${value} template by dropping the placeholder into a --flag= prefix and matching
on startswith / first-= split, so it round-trips only a terminal =${value}
shape. The forward render_value_arg supports ${value} anywhere and
validate_arg_formats did not guard position, so a mid-token value template would
render forward but silently break reverse parsing. Reject it at app construction,
alongside the existing placeholder-name and flag-on-bool guards.
…rom_model field_info.metadata is already a list and find_arg_format only iterates it read-only; the two spec.py call sites pass it unwrapped. Match them.
…constants Match the module-constant convention of the adjacent _ALTERS_DEFAULTS / _CHECKSUMS_DEFAULTS literals feeding the same make_arg_parser call.
Automated QA — PASSVerified the Tested items against a fresh instance on the PR head, cross-checked against a base-branch (
Observations — pre-existing, out of scope
|
Coverage reportClick to see where and how coverage changed
This report was generated by python-coverage-comment-action |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||







Summary
(form, resolved) -> RunCommandSpec+assemble_envelopepath (matching the already-migrated checksums app): annotateAltersCreatewith additiveArgFormatmarkers, replace the hand-rolledoptional_args/flag_argsdicts withbuild_command_args, and drop the hand-assembledTaskWrite.build_alters_tasknow threads the resolvedResolvedEntitiesthrough the spec builder, so the resolved executor host drives the envelopetargetinstead of being discarded.derive_arg_parser_from_modelto build the reverse (args→form) parser's value/flag mappings from a model'sArgFormatmarkers, and switch both the alters and checksums reverse parsers onto it — deleting the four hand-maintained mapping dicts so the markers are the single source of truth in both directions.ArgFormattemplate resolver by relocatingfind_arg_format/resolve_arg_templateintoform_dsl/markers.py, and document the two blessed spec signatures in the framework spec module docstring.TaskWritepayload stays byte-for-byte identical — locked by a new alters payload golden captured from the pre-refactor baseline and asserted across three legs (pure spec path,build_alters_task, and the legacy flat-form path). The reverse parse round-trips unchanged, guarded by the existing round-trip tests plus a new derived-dict-equality assertion.validate_arg_formatsto reject a value-arg template whose${value}is not in the terminal=${value}position — the only shapederive_arg_parser_from_model's reverse parse round-trips — so the forward (render_value_arg, which supports${value}anywhere) and reverse directions cannot desync on a mid-token placeholder. No current template is affected; the guard fails loud at app construction alongside the existing placeholder-name and flag-on-bool checks.Deviations (all intentional)
alter,progress, andpre_checks_mysql_config_fileintentionally keep noArgFormatmarker — they render in the app-specific prefix/suffix, not throughbuild_command_args.build_command_argsemits all value args before all flags and truthy-gates them, butprogressmust render after the flags,alterbefore the DSN positional, and--defaults-fileis suppressed by an exact~/.my.cnfsentinel compare (not truthiness). This mirrors how checksums keepsrecursion_method/databases/tablesoutsideArgFormat.--recursion-method=,--databases=, and--tables=asextra_arg_mappings.databases/tablescarrySchemaRef/TableRef(notArgFormat) and are emitted specially bybuild_checksums_command_argsfrom resolved refs, so they must be reverse extras. The derived-dict-equality test pins the derived mappings to the deleted dicts byte-for-byte.Tested
Byte-identical internal refactor — verify no behavior change:
POST /api/apps/alters/; confirm 2xx and that the generated parentrun-commandmeta.argsmatches a task created for the same inputs before this change.PUT /api/apps/alters/{task_name}; confirm 2xx and an unchanged payload.POST /alters/); confirm the generated command is identical to the JSON path.GET /api/apps/alters/schemareturns the same schema as before.Checklist
Database migrations generated if models changed(N/A — no DB table model changes; only Pydantic form-model annotations)User-facing changes documented(N/A — pure internal refactor, no user-facing change)Configuration changes documented(N/A — no config changes)