test: retire the local assertions objectstack lint already reds on at error severity - #1629
Merged
Merged
Conversation
…ds on
Retires `chart-measure-unknown`, `widget-dataset-unknown`,
`widget-measure-unknown` and `filter-token-unknown` from
`test/analytics-integrity.test.ts` (50 lines).
All four gate at error severity on the pinned @objectstack/lint@17.3.0 with
no `--strict`: each defect below was injected into this branch's base and
`objectstack lint` exited 1 naming the rule.
- `every chart yAxis is a measure of the report dataset` — a non-measure
yAxis gives `chart-measure-unknown` at error, exit 1.
- `every widget dataset / values / dimensions entry resolves` — all three of
its sub-checks are covered: `widget-dataset-unknown`,
`widget-measure-unknown` and `widget-dimension-unknown`, each error/exit 1.
- `every {placeholder} in a temporal filter position is a recognised date
macro` — `filter-token-unknown` fires at error/exit 1 on BOTH surfaces this
assertion walks, report `runtimeFilter` and dashboard widget `filter`.
`MACRO_RE` and the `isDateMacroToken` import were used solely by the third
assertion and go with it.
⛔ Deliberately NOT retired from this file: A1 (a chartless report block's
dataset is never resolved — objectstack#16105), A4 (`rows`/`columns` are
matched by no rule at all) and A8 (`filter-preset-comparand` never fires on
this authoring path — objectstack#16106).
Refs #1613 #1621
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuzfS5chho38Yx1jxx9DEj
…eds on
Retires `sort-field-unknown`, `filter-token-unknown` and
`action-name-undefined` (73 lines: 41 from view-references, 32 from
action-references).
Each defect was injected into this branch's base and `objectstack lint`
exited 1 naming the rule, on the pinned @objectstack/lint@17.3.0:
- `every list sort targets a real field` (47 sort entries inspected) — a
dangling sort field gives `sort-field-unknown` at error, exit 1.
- `list view and page filters only use user tokens or date macros` —
`filter-token-unknown` fires at error/exit 1 at BOTH positions this
assertion walks (a view list filter and a page component filter), and on
all three near-miss spellings its sibling assertion pins as unresolvable:
`{this_quarter_start}`, `{current_user}` and `{not_a_token}`. That sibling,
`the widened list-view rule still rejects what neither path resolves`,
stays — it pins the local allow-list's own boundary, which no rule reports.
- `every rowAction / bulkAction names a defined action` — measured
non-vacuous first (0 rowActions but 2 bulkActions authored), then
`action-name-undefined` at error/exit 1 on that live population.
`actionNames` was left used solely by the retired assertion and goes with it.
⛔ Deliberately NOT retired: `kanban groupByField is a select field with
options`. `list-view-field-unknown` covers only its missing-field half — a
groupByField naming a real field with NO options gives exit 0 and nothing,
while the local assertion reds. Gate 3 fails; the assertion stays.
Refs #1613 #1621
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuzfS5chho38Yx1jxx9DEj
…s on Retires `security-controlled-by-parent-no-relation`, `sharing-rule-unlowerable-condition` and `sharing-rule-runtime-variable-condition` (38 lines: 18 from authorization-coverage, 20 from sharing-seeding). Each defect was injected into this branch's base and `objectstack lint` exited 1 naming the rule, on the pinned @objectstack/lint@17.3.0: - `controlled_by_parent objects expose a parent the engine can resolve` — demoting `crm_quote_line_item`'s master-detail and its required lookup gives `security-controlled-by-parent-no-relation` at error, exit 1. - `seeds all of them — seeded + 0 skipped` — every refusal class the compiler has is reported: a nested path and a `has()` guard both give `sharing-rule-unlowerable-condition`, a `current_user.id` read gives `sharing-rule-runtime-variable-condition`, all at error/exit 1. The file's own live-driver guards keep the local half independently: a rule that stops seeding drops out of `seeded`, which reds `every seeded rule has a witness, and no witness is stale`, and `%s materialises exactly the records it declares` asserts `compiled.ok` per rule. ⛔ Deliberately NOT retired, each on a MEASURED gate-3 failure at this base: - `every FLS key is object-qualified and names a real field` — an unqualified key gives `security-fls-unqualified-key` at error/exit 1, but a qualified-but-dangling key (`crm_account.description_nope`) gives exit 0 and nothing, while the local assertion reds on both. objectstack#16108 has not landed. - `every predicate is pushdownable and names real fields` and `the first field of a using predicate exists` — the platform covers only the non-pushdownable half (`rls-predicate-unenforceable`, error/exit 1). An RLS predicate naming a field the object does not have, and one reading an un-pre-resolved `current_user.nope`, BOTH give exit 0 while the local assertions red. Conversely `rls-predicate-unparseable` fires on a shape the local regex accepts. Neither side subsumes the other. - `a sharing rule only targets an object whose OWD lets shares apply` — `sharing-rule-object-not-shareable` and `sharing-rule-object-controlled-by-parent` both fire at error/exit 1, but the third case the local assertion covers, a read-level share on a `public_read` object, gives exit 0 while the assertion reds. Refs #1613 #1621 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DuzfS5chho38Yx1jxx9DEj
…dy reds on Retires `flow-update-readonly-field` (8 lines), and adds the changeset. Group A only. Adding `is_escalated: true` to `escalate_case`'s user-context `update_record` node gives `flow-update-readonly-field` at error, exit 1 on the pinned @objectstack/lint@17.3.0, naming the flow, the node and the field. Exactly one local case reds on it, and the readonly-specific half of that case is what comes out. ⛔ Its first line stays byte-identical: `expect(written.sort()).toEqual(['escalation_reason', 'priority', 'status'])` is an EXACT-SET pin, and no platform rule reports a write set that lost `status` or gained an ordinary editable column. That half is not a duplicate, so it is not group A. ⛔ Deliberately NOT retired from F1, each on a MEASURED gate-3 failure at this base: - `references only namespaces the evaluator binds` (`test/view-predicate-dialect.test.ts`). A bare `status` gives `visibility-bare-identifier` at error/exit 1 — but the moment the same identifier also appears inside a `has()`, the rule goes silent for it entirely: `has(status) && status == "qualified"` gives exit 0 and nothing, while the local sweep reds. Control, same file, same site, same run: the unwrapped spelling exits 1. The local assertion is strictly broader. - `visibility-predicate-syntax` has no standalone local assertion — its only local counterpart is the parse guard inside the sweep above, which stays. - `visibility-predicate-unknown-function` and `expression-invalid` red only live-engine TOTALITY assertions (`answers on a brand-new record with no keys at all` and its siblings) and the null-guard sweeps. Those catch predicates that parse, resolve and are record-bound yet still abort at runtime — the #688 and #630 regressions — which no static rule sees. Retiring them would lose that coverage silently. Refs #1613 #1621 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DuzfS5chho38Yx1jxx9DEj
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
os-steve
marked this pull request as ready for review
September 6, 2026 02:17
This was referenced Sep 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1625
Retires 11 rule ids across 9 local assertions in 6 files — 169 lines removed, 0 added. Test-only: no metadata change, no suppression, no local re-severity, no new test.
pnpm verifygreen (160 files, 3386 passed, 1 skipped, exit 0).The soundness check, before anything was deleted
Both gates hold, so the surveys' measurements carry.
@objectstack/specis17.3.0inpackage.json;@objectstack/lintis transitive through@objectstack/cliand pinned17.3.0inpnpm-lock.yaml. Read back fromnode_modulesafter install:lint 17.3.0 · spec 17.3.0 · cli 17.3.0 · formula 17.3.0.src/drift.git diff 1670557..HEAD -- src/ package.json(the F2–F6 base) is empty — every F2/F3/F5/F6 measurement carries verbatim.git diff a0362a37..HEAD -- src/ package.json(the F1 base) is one comment-only hunk:src/objects/_case-assignment.ts, +24/-4, all//lines, from docs(case-assignment): guard 4's comment names the triage rule, not the flag #1615 (a docs commit). No effective metadata moved.passed:true · errors:0 · warnings:17 (16 component-props-invalid + 1 component-props-unknown-key) · suggestions:12 · hiddenPlatform:2319, exit 0.Rows re-run anyway: every row below, all 11 — each deletion carries its own fresh injection at this base, so the "re-run if
src/moved" clause is satisfied by construction rather than by argument.Base cut from
origin/mainatff4332161745a34c5eb2a45a95ccbfc8bf902ca4(ff43321).What was deleted — one row per rule id, with its three-gate citation and its observed exit 1
Every "observed" cell is a fresh injection into this branch's base, restored by blob hash and verified by observation (
git statusclean ANDgit hash-object PATHequal togit rev-parse HEAD:PATH), never by exit code.Citation legend (the
#form is kept out of the table below so no closing keyword can end up adjacent to a card number): F1 = survey #1613, report comment5555835078; F2-6 = survey #1621, report comment5556100629.analytics-integrity· every chart yAxis is a measure of the report datasetchart-measure-unknownchart-measure-unknownerror, exit 1; only that case redsanalytics-integrity· every widget dataset / values / dimensions entry resolveswidget-dataset-unknownwidget-dataset-unknownerror, exit 1widget-measure-unknownvalues[0]⇒widget-measure-unknownerror, exit 1widget-dimension-unknown(unclaimed, fires)dimensions[0]⇒widget-dimension-unknownerror, exit 1analytics-integrity· every placeholder in a temporal filter position is a recognised date macrofilter-token-unknown{fortnight_ago}⇒ error, exit 1 on BOTH surfaces this assertion walks: reportruntimeFilterand dashboard widgetfilterview-references· every list sort targets a real fieldsort-field-unknownsort-field-unknownerror, exit 1view-references· list view and page filters only use user tokens or date macrosfilter-token-unknown{this_quarter_start},{current_user},{not_a_token}action-references· every rowAction / bulkAction names a defined actionaction-name-undefinedbulkActionspopulation ⇒action-name-undefinederror, exit 1authorization-coverage· controlled_by_parent objects expose a parent the engine can resolvesecurity-controlled-by-parent-no-relationcrm_quote_line_item's master-detail and its required lookup ⇒ error, exit 1sharing-seeding· seeds all of them — seeded + 0 skippedsharing-rule-unlowerable-conditionhas()guard ⇒ error, exit 1sharing-rule-runtime-variable-conditionrecord.owner_id == current_user.id⇒ error, exit 1readonly-write-semantics· escalate_case writes only user-writable columns (readonly half only)flow-update-readonly-fieldescalate_case writes only user-writable columnsis_escalated: trueon the user-context node ⇒ error, exit 1, naming flow, node and field; exactly one case reds(12 rows, 11 distinct rule ids — rows 2–4 are three sub-checks of one assertion, and
filter-token-unknownis retired once in F3 and once in F2, which is how the surveys count it.)Line counts removed, per file
test/analytics-integrity.test.tstest/view-references.test.tstest/action-references.test.tstest/sharing-seeding.test.tstest/authorization-coverage.test.tstest/readonly-write-semantics.test.tsTwo helpers were left used solely by a retired assertion and go with it:
MACRO_REplus theisDateMacroTokenimport inanalytics-integrity, andactionNamesinaction-references. Nothing else in any of these files changed — group B is byte-identical in all six.The 10 rows I did NOT take, each on a measurement rather than a hunch
⭐ This is the substance of the run. The card named 21 rows; I took 11. Every decline below is a gate-3 failure I measured at this base, with a control that fired in the same run. Retiring any of them would have removed coverage the platform does not have — silently, with nothing going red to say so.
visibility-bare-identifierstatus == "qualified"⇒ error, exit 1 (control). Buthas(status) && status == "qualified"⇒ exit 0, nothing, while the local sweep reds — once the identifier also appears inside ahas(), the rule goes silent for it entirely. That is the guarded-but-unprefixed spelling an author is most likely to write. Filed as objectstack#16118.visibility-predicate-syntaxvisibility-predicate-unknown-functionanswers on a brand-new record with no keys at alland siblings). Those catch predicates that parse, resolve and are record-bound yet still abort at runtime — the #688 class — which no static rule sees.expression-invalidexpression-invaliddoes not see it.rls-predicate-unenforceablecurrent_user.nope⇒ exit 0, while both local sweeps red. Filed as objectstack#16119.rls-predicate-unparseableis_private == = falseas field/op/rhs, so the suite stays green. Nothing to retire; and see the row above for the converse.sharing-rule-object-not-shareablepublic_read_write⇒ error, exit 1 (control). But the third case the local assertion covers — a read-level share on apublic_readobject — ⇒ exit 0, local RED.sharing-rule-object-controlled-by-parentpublic_readcase.security-fls-unqualified-keycrm_account.description_nope⇒ exit 0, local RED. #16108 has not landed.list-view-field-unknown(kanban.groupByField)Declared no-ops — not silently retried
has(status) && status == "qualified"as avisibility-bare-identifierinjection. It reached disk (blob hash moved, marker counted) but produced no verdict. That first attempt was out of the rule's class, so it proved nothing about reachability; re-run with the unwrapped spelling, which fired. The negative it produced is reported above on its own merits, with its own control — it is not being banked as the failed measurement.sortfield incase.view.tsandobject: 'crm_account'inaccount.sharing.ts. Both re-run against unique anchors.Out of scope, as the card requires
Untouched, and none of them measured as a candidate: the 21 "nothing to retire" rows (no new test was written to match any rule), the 18 waiting on #1581, the 18 blocked upstream, the 22 unmeasured,
test/metadata-references.test.tsagainstcomponent-props-*(the clean tree still carries those 16+1 warnings and that test is still green on them),rls-predicate-over-budget(dormant by design until the GA limits flip),security-private-no-readscope(ships atinfo), and the mis-credited rows.chart-dimension-unknowndeserves a note: F2-6 §1a lists A3 (every chart xAxis is a dimension) as retirable "once the id is corrected", but the card nameschart-field-unknownamong the mis-credited rows and scopes this PR to 21. Taking A3 would have been a 22nd row, so it is left in place and reported rather than deleted.Verification
pnpm verify— exit 0:validatepassed,typecheck,lint(errors:0),lint:i18n-gate,hygiene,hygiene:tokens,build, thenTest Files 160 passed (160) · Tests 3386 passed | 1 skipped (3387).git statusempty for the path ANDgit hash-objectequal togit rev-parse HEAD:PATH.objectstack lint --jsonwas parsed withJSONDecoder().raw_decode, so pnpm'sELIFECYCLEtail after the payload on exit 1 cannot turn a real exit-1 verdict into "no verdict" — the trap Survey part 2 — run F2–F6 through the three-gate test that #1613 proved necessary on F1 (epic #1579, step 3; needs no release) #1621 hit in its own harness.VERDICT command-exitline..changeset/retire-assertions-the-platform-already-reds-on.md, empty frontmatter (the sanctioned "releases nothing" declarationchangeset-check.ymldocuments).Refs #1579 · #1613 · #1621 · new upstream cards objectstack#16118 and objectstack#16119.
🤖 Generated with Claude Code
https://claude.ai/code/session_01DuzfS5chho38Yx1jxx9DEj
Generated by Claude Code