SEP-1790: Reconcile list_view column gate with synthetic and dotted column keys - #1353
Conversation
Co-authored-by: yyyyyyyan <24644216+yyyyyyyan@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the SEP app framework’s list-view column validation so it aligns with the schema DSL’s documented column-key patterns (synthetic keys for non-row-bound formats and dotted paths), and centralizes the “root segment” parsing helper so both construction-time validation and the conformance suite apply the same path-splitting logic.
Changes:
- Add
NON_ROW_BOUND_FORMATSnext toColumnFormatand exempt those formats from list-view column-key validation. - Introduce
root_segment()inresponses.pyand reuse it from bothapps.pyandconformance.py. - Extend tests to cover synthetic keys (
ACTIONS,SCHEDULE) and dotted keys with valid/invalid roots.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
tests/app/sep/apps/framework/test_apps.py |
Adds coverage for synthetic and dotted list-view column keys (valid/invalid roots). |
app/sep/apps/framework/schema.py |
Defines NON_ROW_BOUND_FORMATS to co-locate format exemptions with ColumnFormat. |
app/sep/apps/framework/responses.py |
Adds shared root_segment() helper (and adjusts a cast() call). |
app/sep/apps/framework/conformance.py |
Reuses root_segment() instead of maintaining a local copy. |
app/sep/apps/framework/apps.py |
Widens _validate_view_columns to exempt non-row-bound formats and validate only the root segment for dotted/indexed keys. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Coverage reportClick to see where and how coverage changed
This report was generated by python-coverage-comment-action |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Follow-up, deliberately out of scope for this PR.
def _declared_on_model(name: str) -> bool:
if name in model_fields:
return True
if "." not in name:
return False
return name.split(".", 1)[0] in model_fieldsSEP-1790 consolidates root-segment resolution for the two surfaces its acceptance criteria name — list-view columns and detail-view fields — and Worth noting why it is not folded in here rather than just untouched: the swap is not behaviour-preserving. |
yyyyyyyan
left a comment
There was a problem hiding this comment.
Pushed fixes for everything this review could act on. Not approving yet — one item is deliberately left open, and one thing is worth re-confirming before merge.
Left open:
app/sep/apps/framework/rules.py:1743-1750— a third root-segment resolution in this package, on a surface SEP-1790's criteria do not name. Not folded in here because swapping inroot_segment()would widen what@apply_conditional_rulesaccepts (items[0]would newly resolve toitems), so it wants its own ticket and test. Marked as a follow-up on this PR.
Worth re-confirming:
python / testwas red on 3.11.9, 3.12.3 and 3.13 at the previous head, withlabel-gategreen — so those were real failures, not the QA-window skip.Column(key="_actions", label="", format=ColumnFormat.ACTIONS)in the new ACTIONS test could not construct at all, becauseColumn.labelisNonEmptyStr; the test died before reaching the gate, leaving the headline synthetic-key criterion unverified. Fixed inab90c979eusinglabel="Actions", matching the four live columns inapp/sep/apps/inventory/schema.py. Theqa passedlabel was applied against the red run, so the new head is worth re-running.
Two other things changed in the fixes that are worth knowing about, since neither was a review comment:
- The gate's error message was double-quoting every key (
["'ghost'"], a regression from['ghost']onmain) because the parts wererepr-ed before the list itself was interpolated. Now joined explicitly, so a flat key reads exactly as it did before and a dotted one reads['ghost.service' (root: 'ghost')]. test_list_view_indexed_key_resolves_rootcould not fail:match="items"matches the raw key, so it passed with or without the[N]strip. Tightened tomatch=r"root: 'items'", and a positive case (name[0].label, whose root is serialized) now pins the strip.
_validate_view_columnsrejects column keys whole-string against serialized field names, so both synthetic keys (_actionswithformat=ACTIONS) and dotted paths (target.service) fail — despite the schema DSL documenting both as valid. The frontend already handles them; the backend gate is the wrong half of the contradiction.Changes
schema.py— DeclareNON_ROW_BOUND_FORMATSbesideColumnFormatso the exempt set and enum are co-located and cannot driftresponses.py— Addroot_segment()(relocated fromconformance.py's private_root_segment) as the single shared path-splitting helperconformance.py— Importroot_segmentfromresponsesinstead of owning a local copyapps.py— Widen_validate_view_columns:format ∈ NON_ROW_BOUND_FORMATSroot_segment(key)against serialized fields instead of the full keytest_apps.py— Cover both axes: ACTIONS/SCHEDULE synthetic keys construct cleanly; dotted keys with valid roots pass, invalid roots and indexed segments are still rejected; an indexed key whose root is serialized constructs cleanly, which is what pins the[N]stripTested
pytest tests/app/sep/apps/framework/test_apps.py::TestDefinitionValidation— 49 passedpytest tests/app/sep/apps/framework/test_conformance.py— 81 passed, 11 skipped (registry-wide construction of every registered app, unchanged by the widened gate)['ghost']as before, a dotted one renders['ghost.service' (root: 'ghost')]