Skip to content

SEP-1790: Reconcile list_view column gate with synthetic and dotted column keys - #1353

Merged
yyyyyyyan merged 7 commits into
mainfrom
copilot/sep-1790-reconcile-list-view-column-gate
Aug 18, 2026
Merged

SEP-1790: Reconcile list_view column gate with synthetic and dotted column keys#1353
yyyyyyyan merged 7 commits into
mainfrom
copilot/sep-1790-reconcile-list-view-column-gate

Conversation

Copilot AI commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

_validate_view_columns rejects column keys whole-string against serialized field names, so both synthetic keys (_actions with format=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 — Declare NON_ROW_BOUND_FORMATS beside ColumnFormat so the exempt set and enum are co-located and cannot drift
  • responses.py — Add root_segment() (relocated from conformance.py's private _root_segment) as the single shared path-splitting helper
  • conformance.py — Import root_segment from responses instead of owning a local copy
  • apps.py — Widen _validate_view_columns:
    • Skip columns whose format ∈ NON_ROW_BOUND_FORMATS
    • Compare root_segment(key) against serialized fields instead of the full key
    • Error message surfaces the unresolvable root for dotted keys
  • test_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] strip
# Previously rejected — now exempt by format:
Column(key="_actions", label="Actions", format=ColumnFormat.ACTIONS)

# Previously rejected — now resolves root segment "status" against the model:
Column(key="status.label", label="Status Label")

Tested

  • pytest tests/app/sep/apps/framework/test_apps.py::TestDefinitionValidation — 49 passed
  • pytest tests/app/sep/apps/framework/test_conformance.py — 81 passed, 11 skipped (registry-wide construction of every registered app, unchanged by the widened gate)
  • Error-message shape checked by hand against the real validator: a flat unknown key renders ['ghost'] as before, a dotted one renders ['ghost.service' (root: 'ghost')]

Co-authored-by: yyyyyyyan <24644216+yyyyyyyan@users.noreply.github.com>
Copilot AI requested a review from yyyyyyyan August 16, 2026 04:45
@yyyyyyyan
yyyyyyyan marked this pull request as ready for review August 18, 2026 02:07
Copilot AI lite review requested due to automatic review settings August 18, 2026 02:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_FORMATS next to ColumnFormat and exempt those formats from list-view column-key validation.
  • Introduce root_segment() in responses.py and reuse it from both apps.py and conformance.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.

Comment thread app/sep/apps/framework/responses.py
@yyyyyyyan yyyyyyyan added the qa passed Tests for this PR are completed and successful. label Aug 18, 2026
@github-actions

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  app/sep
  inventory.py
  app/sep/apps/framework
  apps.py
  conformance.py
  responses.py
  schema.py
  app/sep/sync/syncers
  pmm.py
Project Total  

This report was generated by python-coverage-comment-action

@yyyyyyyan

Copy link
Copy Markdown
Contributor

Follow-up, deliberately out of scope for this PR.

app/sep/apps/framework/rules.py:1743-1750_declared_on_model is a third root-segment resolution inside app/sep/apps/framework/, testing a dotted field reference's root against a model's field set:

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_fields

SEP-1790 consolidates root-segment resolution for the two surfaces its acceptance criteria name — list-view columns and detail-view fields — and root_segment() in responses.py is now that shared helper. This third copy belongs to the Tier-3 @apply_conditional_rules decoration-time check, which the criteria do not cover.

Worth noting why it is not folded in here rather than just untouched: the swap is not behaviour-preserving. root_segment() strips [N], so an indexed reference with no dot (items[0]) would newly resolve to items and be accepted where the current code rejects it. That widens what @apply_conditional_rules admits on a surface this PR does not otherwise touch, which wants its own ticket and its own test rather than riding along here.

@yyyyyyyan yyyyyyyan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 in root_segment() would widen what @apply_conditional_rules accepts (items[0] would newly resolve to items), so it wants its own ticket and test. Marked as a follow-up on this PR.

Worth re-confirming:

  • python / test was red on 3.11.9, 3.12.3 and 3.13 at the previous head, with label-gate green — 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, because Column.label is NonEmptyStr; the test died before reaching the gate, leaving the headline synthetic-key criterion unverified. Fixed in ab90c979e using label="Actions", matching the four live columns in app/sep/apps/inventory/schema.py. The qa passed label 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'] on main) because the parts were repr-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_root could not fail: match="items" matches the raw key, so it passed with or without the [N] strip. Tightened to match=r"root: 'items'", and a positive case (name[0].label, whose root is serialized) now pins the strip.

@yyyyyyyan
yyyyyyyan merged commit c3e1d57 into main Aug 18, 2026
19 checks passed
@yyyyyyyan
yyyyyyyan deleted the copilot/sep-1790-reconcile-list-view-column-gate branch August 18, 2026 18:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python qa passed Tests for this PR are completed and successful.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants