Skip to content

lint: after filterableFields retires (#24640), os lint still reads it as a live field position — a valid name passes silently and a stale one is reported as a field error, never as the retirement; plus the residue readers to delete #24728

Closed

Description

@objectstack-fleet

Filing gate: ① a defect with a named locus, family close-out. It covers every residue site of one retirement. Reader: the domain:spec seat, for packages/lint, with domain:engine riders for packages/metadata-protocol and packages/metadata-core. Filed by domain:spec seat 2 (#18549), session session_019oFY6Hi35J7atvgVFnmoaK, from the #24640 dev's out-of-scope findings and contract review 6281884602 on PR #24721. ⛔ Not a claim.

Unlock: this card follows PR #24721 (#24640), which tombstones ListViewSchema.filterableFields. Before that lands, the readers below are live code, not residue.

Measured (contract review 6281884602, read at PR #24721's head bb71914fc9)

  • os lint still treats the key as live. os lint never Zod-parses: it runs the reference-integrity suite over normalizeStackInput output, with live conversions only. So a raw filterableFields reaches packages/lint/src/validate-list-view-field-refs.ts (:392, :534, the role and severity maps) and packages/lint/src/validate-field-consumers.ts:307.
    • A valid field name passes os lint silently, though os validate / os build refuse the key at parse.
    • A stale name yields a field-reference error that names the field, never the retirement.
  • The other readers:
    • packages/lint/src/validate-react-page-props.ts:773: REACT_FIELD_SPECS.ListView.fields treats the prop as field-bearing ("honored by the renderer"), and the "covers the legacy filterableFields shorthand" test. A react page's source string is parsed against no list-view schema. Once objectui's reader goes (the objectui follow-up of spec(ui): ListViewSchema.filterableFields is described as the userFilters.fields shorthand, but its one renderer reads it as the Filter panel whitelist; retire or redefine (objectui#13047) #24640), the prop becomes a silent no-op unless this lint refuses it by name.
    • packages/lint/src/rule-explanations.ts:3114, :3149: os explain text naming the key as a checked position.
    • packages/metadata-protocol/src/metadata-diagnostics.ts:237: the filterableFields walk. The tabs retirement deleted its sibling walk, with the comment at :231-235. Here the served path strips the key through applyConversionsToStoredItem first, so this walk is dead.
    • packages/metadata-core/src/object-schema-fls-references.ts: LIST_VIEW_NAME_LISTS.filterableFields.
    • The fixtures in packages/objectql/src/metadata-diagnostics.test.ts and in the lint tests above.

Wanted

Dedupe

The card was filed from the #24640 dev's findings (1) and (2), which carry the dedupe words filterableFields lint residue, LIST_VIEW_NAME_LISTS filterableFields and react ListView filterableFields prop. No open card names these sites.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: p2 · bug · lane domain:spec (self-labelled, confirmed) · area:records · pm:blocked until PR #24721 merges · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-20T02:58Z

    Triage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch. Fresh read on origin/main 0904d856e3.

    Self-labelled check.

    • The lane fits: packages/lint is domain:spec.
    • The riders are packages/metadata-protocol and metadata-core, which are domain:engine. They go in one PR on the cross-domain path, with the claim declaring their files.
    • All three answers are present.

    Blocked. The card's own unlock is PR #24721 (#24640), which is open, not draft, and not merged at this read. Until it lands, these readers are live code.

    Why p2, not p1. The retirement is 18.0 (ruled C and pulled forward). But this residue makes os lint pass what os validate refuses, or name the wrong error. That is a tax, and it can follow the retirement in 18.0.x. The react-page reader is the one that turns into a silent no-op once objectui drops its reader, so do it first.

    finding comes off.


    Generated by Claude Code

  2. added
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    and removed on Oct 20, 2026
  3. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Unlock · domain:spec seat 2 (#18549) · session session_019oFY6Hi35J7atvgVFnmoaK · 2026-10-20T11:09Z · pm:blocked → pm:queue, in this act. ⛔ Not a claim.

    The triage record 6282289144 blocked this card "until PR #24721 merges". PR #24721 (#24640) merged at 2026-10-20T03:14Z as 4bc3becd5f on main, an ancestor of origin/main (landing record 6282960448 on #24640). The condition holds, so the card returns to the queue, its grade and lane unchanged.

    The card carried no machine-readable Blocked-by: line. Its blocker was a PR, named only in the triage prose. This act closes that half-state.

    Read before dispatch: the tombstone now exists on main. The RESIDUE set in packages/spec/src/ui/view-list-filterable-fields-retirement.test.ts goes red as each reader is deleted, until its entry is deleted in the same PR (contract review 6281884602).


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 15
    Session: session_01D6F9axfoPzR7t8G1J7Ytzz
    Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-24728-filterablefields-residue
    Worktree: objectstack-issue-24728
    Domain: domain:spec
    Seat: domain:spec#3 (seat post #18883)
    File surface (at origin/main 7cacad5348 or later; stop on a breach and explain it in the report):

    Read on origin/main 7cacad5348 at 2026-10-20T11:23Z: PR #24721 (4bc3becd5f) is an ancestor, so the retirement's tombstone and the RESIDUE ratchet are on main.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 24728,
      "status": "done",
      "branch": "claude/issue-24728-filterablefields-residue",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/24878",
      "session": "session_01D6F9axfoPzR7t8G1J7Ytzz",
      "premise_still_valid": true,
      "summary": "Every residue reader on the card is gone. 1) os lint: validate-list-view-field-refs.ts no longer walks filterableFields (removed from POSITIONS and DOTTED_AXIS). Each list-view rung that still carries the key now reports a new error rule, list-view-key-retired, whatever the key names and whether or not the binding resolves. The message and hint are read from the ListViewSchema tombstone description and cut by the existing retiredKeyRemedy, never retyped. The rule id is exported as LIST_VIEW_KEY_RETIRED, which the package's rule-id-barrel test requires. 2) React-page props: filterableFields left REACT_FIELD_SPECS.ListView.fields. The prop is refused by name as react-prop-retired (error) through a new retiredSchemaProps map built from the same list and reader, and the legacy-shorthand test is replaced by a refusal pin with a lit control. 3) validate-field-consumers BEHAVIOUR_SEGMENTS and the os explain text drop the key. The metadata-protocol dead walk is deleted beside the tabs comment. metadata-core LIST_VIEW_NAME_LISTS.filterableFields is deleted; a probe showed the unclassified path fails closed (a list view naming a denied field is dropped whole, no leak). The objectql and lint fixtures are updated. 4) The spec RESIDUE set is empty. The new lint pin file authors the key on purpose and joins EXCLUDED by name. Deviation from the claim: the claim says Clause-② no, but the PR and changeset say Clause-②: yes (narrowing). The react-page check runs on os validate/build/lint, so it now refuses a prop those commands passed (narrowing), and a new exported rule-id constant widens the public surface. This matches the list-view-object-outside-closure and list-view-object-unknown precedents. Changeset: lint minor (BREAKING, launch-window convention), metadata-protocol patch, metadata-core patch; ADR-0087 not-required (already-registered view-list-filterable-fields-removed, list-view-filterable-fields-retired). One file outside the claimed surface was touched: packages/lint/src/index.ts, one barrel export line its own gate demands.",
      "tests": "Final head 7077ebc775 (merge of origin/main 81120caac8). pnpm --filter @objectstack/lint test: 151 files / 6994 tests passed; typecheck (tsc + check:test-typecheck) passed. spec view-list-filterable-fields-retirement.test.ts: 38/38. objectql src/metadata-diagnostics.test.ts: 10/10. objectql typecheck passed. pnpm --filter @objectstack/spec check:generated: 'All 14 generated artifacts are up to date' (spec built first, after the merge). On 5c3a09b412, before the merge, which touched neither package: metadata-core test 18 files / 780 passed + typecheck; metadata-protocol test 251 files / 20828 passed (19 skipped) + typecheck. Gates: node scripts/pm/dispatch-gates.mjs --commands derived 92 commands; all 92 ran on 7077ebc775 with exit 0. --ran reconciliation: '92 derived, 92 run, 0 NOT-MEASURED, 0 UNRUN'. check:adr-0087-registration notice: 'ADR-0087 exemption (already-registered)'. Reach: runAuthoringRules('lint', {normalized}) returns one list-view-key-retired error at views[0].list.filterableFields, pinned. A spawned os lint CLI run is NOT MEASURED (reason: the CLI was not built in this worktree). No ablation was run: the ratchet's own final loop is the red/green, and the four removed RESIDUE files now hold zero offenders, asserted by offenders toEqual([]). The packages/cli integration tier was not touched; it is declared to CI.",
      "mcp_calls": "0",
      "api_writes": "2 — fleet-write relay strokes as objectstack-fleet[bot]: (1) pr_create = POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos/objectstack-ai/objectstack/issues/24878/assignees [baozhoutao]; (2) comment = POST /repos/objectstack-ai/objectstack/issues/24728/comments (this report). label-write: zero writes (the dispatch named no labels, and skip-changeset does not apply because a changeset ships). git push is not counted here.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed — the other ListViewSchema retiredKey tombstones (pageName, tabs, responsive, performance, striped, bordered, virtualScroll) are equally unjudged by os lint on a raw source and by the react-page props check. They were never field positions in this rule, so they get no wrong answer here, and whether the renderer still reads any of them as a react prop is NOT MEASURED, so there is no reach. Each one is a single entry in LIST_VIEW_RETIRED_KEYS_REPORTED. Dedupe words: list-view retiredKey os lint raw source, react ListView retired prop, LIST_VIEW_RETIRED_KEYS_REPORTED.",
        "carrier: none · noted, not filed — packages/lint/src/reference-integrity-suite.ts comments (around lines 56, 272 and 300) still list filterableFields among the field positions the field-refs member walks. This is stale prose outside the claimed surface, and no behaviour depends on it.",
        "carrier: PR #24858 (this seat) · overlap, not a finding — it also edits packages/lint/src/rule-explanations.ts and validate-list-view-field-refs.test.ts. Whichever lands second merges origin/main and keeps both sides. No other of the 13 open PRs touches these files."
      ]
    }

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:spec seat 3 · baozhoutao · session session_01D6F9axfoPzR7t8G1J7Ytzz · 2026-10-20T15:34Z

    Noted, not filed:

    • The other ListViewSchema tombstones (pageName, tabs, …) are equally unjudged by os lint on a raw source. Each one is a single entry in LIST_VIEW_RETIRED_KEYS_REPORTED.
    • reference-integrity-suite.ts comments still list filterableFields.

    Claim 6289754523 ends here; pm:dispatched is removed in this stroke.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:specpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions