Uh oh!
There was an error while loading. Please reload this page.
fix(app-shell): name the field and the Formula (CEL) editor in the retired formula 422 diagnostic - #6624
Conversation
…tired `formula` 422 diagnostic Card context: objectui#6526, adjudicated option B — keep the objectui#6043 migration path, make the blocked state actionable. A stored object can carry the retired `formula` alias inside a formula field; `FieldSchema` refuses it by name and that hard 422 blocks every later save. The client gate's diagnostic now appends a pointer to the spec's own rejection: it names the field carrying the key and points at the field inspector's Formula (CEL) editor, where one edit commits `expression` and clears the alias. Presentation only — verdict, issue set and paths unchanged; fires only for formula-type fields, where the inspector renders that editor (objectui#4306). The spec message is appended to, never replaced, so other retired keys riding the same `unrecognized_keys` issue keep their own rename prescriptions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CRJge11jso9TpXRWFt1Z49
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
os-sales
commented
Aug 27, 2026
ACCEPT on substance (ui execution seat, It implements the ruling and nothing elseOption B as ruled by the director seat on the maintainer's 「其他同意」: the migration path is untouched, ⭐ Presentation-only, and pinned as such — verdict, issue set and paths are parity-checked against a raw Three things the order did not ask for and should have
⭐⭐ The ablation caught its own no-op — that is the finding to keepFour legs, each with the direction predicted before running: A (annotation wiring removed, i.e. today's behaviour) → 4 red; B (formula-type guard removed) → 1 red; C (keys-membership check removed) → 1 red; D (issue relocated to ⭐⭐ Leg D's first attempt did not mutate anything and was caught by its own anchors — a perl That is the whole discipline in one event: an ablation that silently fails to mutate produces a green that reads exactly like proof. The anchor counts and the blob-hash comparison are what separate "the pin held" from "the experiment never happened," and they are only worth having if you actually stop when they disagree. Equally good: the one pin that cannot go red is named as such — the annotation runs only on the failure path, so no mutation of the added code can move the green-side canary. Saying which assertion is structurally incapable of failing is more useful than quietly counting it as coverage. Narrowing declared as a measurement, not a claimThe lint narrowing is argued rather than asserted: population is the 3-file diff against a recorded BASE, the third file is the changeset Also correct: the first type-check hit a cannot-find-module wall and was treated as an unbuilt closure, not a red gate; green only after building Scope
Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#6526
What this does (adjudicated option B — not re-litigable)
Maintainer ruling via the director seat (2026-08-27, batch #1): keep the objectui#6043 migration path — do NOT strip
formulaat the read door — and make the client-side 422 on a draft carrying the retiredformulakey actionable. The object staying unsaveable until the author migrates is the ruled, accepted cost; this PR gives that cost a signposted way out.validateMetadataDraft('object', ...)now appends a pointer to the spec's ownunrecognized_keysrejection atfields.FIELDwhen the offending key isformulaon a formula-type field:designer.field.formula), the platform's sanctioned migration surface — the legacy value seeds it viadef.expression ?? def.formulaand the first edit commitsexpressionand clears the alias.ObjectSchema.safeParse. Nothing about what the gate accepts or rejects changes; no published type is touched.keysarray (a pre-objectui#6041 body can listreferenceToalongsideformula); its own rename prescription survives.type: 'formula'(objectui#4306 ruling) — any other field type keeps the bare spec message rather than a pointer to a destination that does not render.Fence respected: only
clientValidation.ts, its new test file, and a changeset.RETIRED_FIELD_KEYS,ObjectFieldInspectorand its migration pin,object-fields-io.ts's strip set, and the tombstone registry are untouched — #6527 remains open and out of scope here; objectui#6043 and objectui#6519 are context, not addressed here.Mechanism measurements (PM assumptions, verified)
ObjectSchema.safeParsereportscode: 'unrecognized_keys'at path['fields', FIELD]withkeys: ['formula'](measured on the installed@objectstack/spec17.2.0). The array-shapefieldsdraft rejects wholesale (invalid_typeatfields) before any per-field issue exists, so the record-shape path is the only population.Verification (all at 76c4940, tree clean)
clientValidation.retiredFormulaKey.test.ts— 8 passed. Every load-bearing pin was shown RED by committed-first ablation (mutation proven on disk via anchored grep counts + blob-hash difference vs HEAD; restores proven bygit diff HEADempty + blob-hash match, each leg trap-guarded with absolute paths):fields.FIELD.formula): predicted parity + path-addressed pins red; observed 5 failed | 3 passed../clientValidationrelatively (root vitest aliases workspace packages to src), so no dist can go stale.clientValidation.*test files +createConformance+ 3ResourceEditPagegate tests — 11 files, 152 passed.retiredFormulasuites (MetadataService,MetadataFieldsPage) pin the spec/write side directly and never callvalidateMetadataDraft; the append cannot reach them.pnpm run type-check(app-shell, both tsconfigs) green after building the dependency closure;--listFilesconfirms both the edited file and the new test file are in the closure (1 hit each).--format jsoncounts). Sound narrowing: the root flat config enables no type-aware linting (noprojectService/parserOptions.project), so this diff cannot move any untouched file's verdict; the third diff file is the changeset.md, outside the lint population.Generated by Claude Code
Generated by Claude Code