Skip to content

Commit 795ff70

Browse files
docs(adr): ADR-0047 records the 18.0 retirement of filterableFields — no replacement key, no rewrite (#24756)
Fixes #24727 Clause-②: no ADR-0047's Decision 1 (§3.3 item 1) still said `filterableFields` "stays as the legacy shorthand; loaders auto-upgrade it to `userFilters.fields` entries". The maintainer's ruling C on #24640 (record 6278975049, verbatim 「C」; pulled into 18.0 by record 6279033298, verbatim 「提前」) retired the key in 18.0, and PR #24721 (`4bc3becd5`) executed it with a `retiredKey()` tombstone and a conversion that DROPS the key. Prime Directive 13: a reversed decision is amended in its own record. Docs only, one file, no package touched. ## What changed — `docs/adr/0047-object-ui-run-modes.md` only (+24 / −2) 1. **Status block.** A dated `Amendment (2026-10-20)` blockquote joins the existing `Revision (2026-06-19)` / `Amendment (2026-07-07)` chain: the same blockquote chain, a bare quote-marker separator line, the same bold-lead shape. It records that the key retired in 18.0; that there is no replacement key; that there is no rewrite (the conversion `view-list-filterable-fields-removed` drops the key, and record 6278907207 says why a rewrite to `userFilters.fields` keeps nothing an author saw); and that the auto-upgrade loader was never built. It cites #24640, records 6278975049 and 6279033298 (verbatim rulings kept untranslated), and PR #24721 `4bc3becd5`. 2. **Decision 1, §3.3 item 1.** The sentence is struck in place with a strikethrough and annotated. It is not deleted. This follows the file's own precedent: TL;DR #2's struck "iron rule" carries an italic "Superseded by …" note. No other ADR text moves. The `**Status**:` line, §4 Non-goals and the Context measurement line that names `filterableFields` are untouched. ### Before / after (Decision 1) Before (`origin/main` `580fd4ed3c`, lines 154–155): `filterableFields` stays as the legacy shorthand; loaders auto-upgrade it to `userFilters.fields` entries. After (lines 174–177): ~~`filterableFields` stays as the legacy shorthand; loaders auto-upgrade it to `userFilters.fields` entries.~~ *(Struck by the 2026-10-20 amendment — `filterableFields` retired in 18.0 by ruling C on #24640, with no replacement key and no rewrite; see the status block above.)* Rendered locally with `marked` 16.4.2 (GFM). The struck sentence is one strikethrough span across its line break. The new amendment renders inside the status blockquote, after the 2026-07-07 one. ## Premise readings (the dispatch's mechanism assumptions 1–3) Base: the worktree was created at `origin/main` `580fd4ed3c`. The dispatch named `f7005cbd8c`; `origin/main` advanced between dispatch and worktree creation, and `git diff f7005cb 580fd4e -- docs/adr/0047-object-ui-run-modes.md` is empty. 1. **Holds.** Lines 154–155 carried the quoted sentence. Line 3 is `**Status**: Accepted (2026-06-12; revised 2026-06-19) — …`, followed by the Revision and Amendment blockquotes. The file's only other strikethrough is TL;DR #2 (line 38), the precedent followed here. 2. **Holds.** `git grep -n filterableFields -- packages/spec/src` at `580fd4ed3c` returns 92 lines, all in the retirement kit: - `ui/view.zod.ts`: the `retiredKey()` tombstone and its prescription. - `conversions/registry.ts`: `view-list-filterable-fields-removed`, whose `apply` is `stripKeys(payload, ['filterableFields'], …)`, and its fixture. - `migrations/entries/retired-keys/18.ui__ListView__filterableFields.ts` and `18.ui__ObjectListView__filterableFields.ts`. - `migrations/entries/semantic/18.list-view-filterable-fields-retired.ts` and `migrations/registry.ts.template`. - `ui/view.form.ts`: a comment on the removed input. - Tests: `ui/view-list-filterable-fields-retirement.test.ts`, `ui/view-list-tabs-retirement.test.ts`, `ui/view.test.ts` and `shared/retired-key-removal-version.pin.test.ts`. No read path rewrites the key to `userFilters.fields`. - **Control on the tree the retirement replaced.** That tree is `4bc3becd5^` = `0904d856e3`; `git merge-base --is-ancestor 4bc3bec HEAD` exits 0. `git grep -n filterableFields 4bc3bec^` over the whole repository, excluding `*.md`/`*.mdx` and test files, returns 25 lines. They are the schema declaration (described as "Legacy shorthand for userFilters.fields"), the form input, its generated form translations, the authorable-surface and liveness artifacts, field-reference checks in `packages/lint` and `packages/metadata-protocol`, and the FLS scrubber's name-list classification in `packages/metadata-core`. None rewrites the key into `userFilters.fields`: the loader the sentence promised did not exist when the key retired. - The clone is shallow, so "never built" is read on that tree and on today's, not by walking all history. - Supplementary: the local `../objectui` checkout at `f9401e6` has no line that pairs `filterableFields` with `userFilters` or with an upgrade. 3. **Holds.** §4 Non-goals (now lines 275–276; 253–254 before the insert) calls the `filterableFields` and `userFilters.elements` aliases "one-release courtesies, not commitments". That is consistent with the amendment, so it is left unchanged. ## Gates — all at `6d1c09b965`, the final commit `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` was re-derived on the actual diff and gives the same 19 commands as the dispatch. Each command ran with its output redirected first and `$?` captured before any read. The `--ran` reconciliation reads `19 derived, 19 run, 0 NOT-MEASURED, 0 UNRUN`, a derived zero: every line recorded an exit code. | command | exit | |---|---| | `node scripts/check-adr-links.mjs` | 0 — 770 relative link destinations under docs/adr/ resolve | | `node scripts/check-adr-links.mjs --self-test` | 0 | | `node scripts/check-adr-symbol-anchors.mjs` | 0 — 2369 anchors across 142 records resolve, 0 line anchors | | `node scripts/check-adr-symbol-anchors.mjs --self-test` | 0 | | `node scripts/check-ci-filter-parity.mjs` | 0 | | `node scripts/check-closing-keyword-parity.mjs` | 0 | | `node scripts/check-closing-keyword-parity.mjs --self-test` | 0 | | `node scripts/check-comment-mask-corpus.mjs` | 0 — 9639 files, 0 disagree | | `pnpm --filter @objectstack/lint run check:doc-formula-expressions` | 0 (see the note below) | | `pnpm check:adr-anchors` | 0 | | `pnpm check:cross-package-test-inputs` | 0 | | `pnpm check:doc-authoring` | 0 | | `pnpm check:driver-memory-census` | 0 | | `pnpm check:gitlink-declared` | 0 | | `pnpm check:nul-bytes` | 0 — no raw ASCII control bytes | | `pnpm check:pm-governed-merges` | 0 | | `pnpm check:pm-prior-rulings` | 0 | | `pnpm check:refd-timer-probe` | 0 | | `pnpm check:watch-hint-literal` | 0 | - `check:doc-formula-expressions` first exited **3, PREREQUISITE NOT MET**: the fresh worktree had no `@objectstack/formula` / `@objectstack/lint` `dist`. That exit is not a measurement. The gate's own fix ran under the verify lock (`turbo run build --concurrency=2 --filter=@objectstack/formula --filter=@objectstack/lint`, 4/4 tasks, `VERDICT command-exit 0`), and the re-run exited 0. - No package is touched, so there is no dependency-closure build and no package test or typecheck run. There is no ablation either: the change is documentation, and no tested behaviour moves. - A self-scan of the ADR for control bytes found none. - Not run locally, owned by CI: the repo-wide scans and the families outside the derived total. ## Acceptance notes - **Pre-existing rendering, kept as it was.** The `**Deciders**` / `**Builds on**` / `**Consumers**` lines follow the status blockquote with no blank line. Markdown lazy continuation therefore folds them into the blockquote's last paragraph: before this PR, the 2026-07-07 amendment's paragraph; after it, the new one's. The insert keeps that adjacency byte for byte, because the card says no other ADR text moves; adding a blank line would change how those three lines render. Polish, not filed. Carrier: none. If wanted, the fix is one blank line. - **The `**Status**:` line is left alone.** It still reads "Accepted (2026-06-12; revised 2026-06-19)". The dated amendment block carries the 2026-10-20 change, as the card scoped it. - **Residual readers of the retired key after PR #24721.** These are an observation, not filed. They read a key that every list-view door now refuses at parse, so on the authored path they get no input: - `packages/lint/src/validate-list-view-field-refs.ts`, `validate-field-consumers.ts`, `reference-integrity-suite.ts` and `rule-explanations.ts`; - `packages/metadata-protocol/src/metadata-diagnostics.ts`; - `packages/metadata-core/src/object-schema-fls-references.ts` (`LIST_VIEW_NAME_LISTS`). `validate-react-page-props.ts` reads a JSX `ListView` prop with the same name; that is a React prop, not stored metadata. Carrier: none. ## 维护者速读(草稿) **改了什么**:只动了一个文件 ADR-0047(对象 UI 的两种运行模式),两处改动: - 文件顶部状态区追加一段带日期(2026-10-20)的修订说明。 - 「决定 1」里那句话用删除线划掉并加注。原话是「`filterableFields` 作为旧简写保留,加载器会把它自动升级成 `userFilters.fields`」。原句保留可查,没有删除。 其余 ADR 文字一字未动。 **为什么改**:您在 #24640 裁了「C」并「提前」到 18.0,PR #24721 已经落地: - 这个键在 18.0 退役,没有替代键; - 存量数据里的这个键直接丢弃,不会改写成 `userFilters.fields`; - 那个「自动升级」的加载器从来没有建成过。 所以 ADR 里那句话已经与现实相反。按第一指令 13,被推翻的决定要在原记录里修订。不改的话,后来读 ADR 的人(和 AI)会以为这个键还能写、还会被自动转换。 **风险与代价(含回滚)**:纯文档改动,没有运行时影响,不发包,也没有 changeset。回滚就是 revert 这一个 commit。有一处取舍:顶部 `**Status**:` 那一行没有改成「amended 2026-10-20」,修订信息只放在新增的引用块里,这是为了遵守卡上「其余文字不动」的要求。 **席位意见**: **你要做的**:看一下新增修订段的措辞和划线位置是否合适。同意就在 PR 上批准(Tier H,批准后由席位落地)。 --- _Generated by [Claude Code](https://claude.ai/code/session_01HEdP5tPhqQfzwRmKDxwn85)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 576d0f3 commit 795ff70

1 file changed

Lines changed: 24 additions & 2 deletions

File tree

‎docs/adr/0047-object-ui-run-modes.md‎

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,26 @@
2424
> (need named presets on an object → use `listViews`). Enforced by a new
2525
> `ObjectUserFiltersSchema` (element narrowed to `dropdown`/`toggle`, `tabs`/
2626
> `showAllRecords` omitted), which `ObjectListViewSchema` now `.extend`s back in.
27+
>
28+
> **Amendment (2026-10-20) — `filterableFields` is retired in 18.0, with no
29+
> replacement key and no rewrite (#24640: the maintainer ruled 「C」, record
30+
> 6278975049, and pulled it into 18.0 with 「提前」, record 6279033298;
31+
> executed by PR #24721, `4bc3becd5`).** §3.3 item 1 below said
32+
> `filterableFields` "stays as the legacy shorthand; loaders auto-upgrade it to
33+
> `userFilters.fields` entries". That loader was never built: on the tree the
34+
> retirement replaced, the key was declared, offered as a Studio form input and
35+
> checked for field references, and nothing rewrote it into
36+
> `userFilters.fields`; its one renderer, objectui's `ListView`, read it as the
37+
> Filter panel's field whitelist instead. The ruling retires the key with no
38+
> replacement key: the list-view shapes (`ListViewSchema`,
39+
> `ObjectListViewSchema`) refuse it at parse with a `retiredKey()` tombstone
40+
> that names the fix, and the conversion `view-list-filterable-fields-removed`
41+
> drops it from stored views. No conversion rewrites it to
42+
> `userFilters.fields`: that rewrite keeps nothing an author saw — the
43+
> whitelist would vanish and quick-filter chips would appear (record
44+
> 6278907207). A curated end-user filter bar is authored as `userFilters`.
45+
> §3.3 item 1's sentence is struck in place, not deleted; §4 already called
46+
> the alias a one-release courtesy, not a commitment.
2747
**Deciders**: ObjectStack Protocol Architects
2848
**Builds on**: [ADR-0005](./0005-metadata-customization-overlay.md) (one Zod source per type, org overlay), [ADR-0017](./0017-object-has-many-view.md) (independent view entities, `viewKind`), [ADR-0019](./0019-app-as-consumer-unit.md) (App is the consumer-facing unit — navigation decides what users see), [ADR-0027](./0027-metadata-authoring-lifecycle.md) (draft · publish lifecycle), [ADR-0033](./0033-ai-assisted-metadata-authoring.md) (**AI is the long-term author of metadata — the design center this ADR inherits**)
2949
**Consumers**: `@objectstack/spec` (view + page Zod schemas), `@objectstack/objectql` (registry validation/diagnostics), `../objectui` (console `ObjectView` / `PageView`, `plugin-list`), framework templates (`hotcrm`, `app-showcase`), the `objectstack-ui` authoring skill
@@ -151,8 +171,10 @@ have; we do not rely on lint to forbid what the type can simply not express.
151171

152172
Attached as `ListViewSchema.userFilters` (view-level convenience) and
153173
`InterfacePageConfigSchema.userFilters` (the primary home).
154-
`filterableFields` stays as the legacy shorthand; loaders auto-upgrade it
155-
to `userFilters.fields` entries.
174+
~~`filterableFields` stays as the legacy shorthand; loaders auto-upgrade it
175+
to `userFilters.fields` entries.~~ *(Struck by the 2026-10-20 amendment —
176+
`filterableFields` retired in 18.0 by ruling C on #24640, with no
177+
replacement key and no rewrite; see the status block above.)*
156178

157179
2. **Runtime visualization whitelist.**
158180
`UserActionsConfigSchema.visualizations?: z.union([z.boolean(), z.array(ViewTypeEnum)])`

0 commit comments

Comments
 (0)