Repository navigation
Commit 33ae4bf
fix(lint): one-line verdicts for the widget, dataset, security-posture and visibility rules;
Part of #22161
Clause-②: no
Stage 2 of the card, slice 2: 26 `packages/lint` rule ids, four whole
source files. The card stays open for the later slices listed under
"Remaining" below.
## What changes
- **One verdict line per finding.** Each finding of the 26 ids prints a
`message` of one verdict sentence. Every finding the rules' own suites
fire is now 197 characters or fewer (the longest of each id was 205 to
697 before). The values the author wrote still close the verdict: field
paths, the candidate roster, the selection list, and the predicate
excerpt, now capped at 72 characters. `visibility-predicate-over-budget`
no longer echoes the predicate at all; its `path` locates it.
- **The reasoning moves to `RULE_EXPLANATIONS`**
(`packages/lint/src/rule-explanations.ts`), 26 new entries, so `os
explain RULE_ID` prints it and the CLI's `rule:` line ends with the
pointer for these ids. No CLI file changes: `explainPointer()` and `os
explain` resolve any key the table holds
(`packages/cli/test/explain-rule-id.test.ts` iterates every key; run
below).
- **Nothing else moves.** Rule ids, severities, `path`, `hint` (the
`fix:` line) and what each rule accepts or refuses are unchanged. Every
fired message of every other rule id is byte-identical, measured below.
- **One shared clause added:** `unprovisionedAnchorVerdict()` in
`system-fields.ts` is the one-clause form of
`unprovisionedAnchorCause()`, for a rule whose finding is one sentence
(here `dashboard-filter-field-unprovisioned`). The eight rule files
still on the long clause converge on it when their slices shorten them.
- `.changeset/22161-lint-slice-2-one-line.md`: `@objectstack/lint`
`patch`, naming every door that prints the new text (below). `Clause-②:
no` follows the contract review on slice 1 (its section ②):
`RULE_EXPLANATIONS` entries are data in an existing export.
The shape, through the CLI's real printers against the rebuilt
`@objectstack/lint` dist (a scratch stack, `runAuthoringRules('build',
…)`):
```text
• dataset "deal_metrics" › dimension "region": dimension field "account.region" resolves, but its relationship prefix "account" is not declared in this dataset's `include`, so no join reaches the column
fix: Add "account" to include (declaring "a.b" implicitly includes "a"), or bind this position to a field on "crm_deal" itself. Declared include paths: (none).
rule: dataset-field-not-included at datasets[0].dimensions[1].field — `os explain dataset-field-not-included` for why a relationship prefix must be in include
⚠ dashboard "sales_board" › widget "deals_by_stage": 'bar' widget selects no dimensions, so the renderer draws a single KPI number instead of a 'bar' chart
fix: Plot the chart against a dataset dimension — dimensions: ['NAME'] (declared dimensions: stage, region) — or, if a single value IS what this tile should show, declare it as a 'metric' or 'kpi' widget so the type matches what renders. Suppress with: suppressWarnings: ['chart-dimensions-missing']
rule: chart-dimensions-missing at dashboards[0].widgets[0] — `os explain chart-dimensions-missing` for why a chart with no dimensions draws one number
```
(The `fix:` line prints the rule's unchanged `hint`; its placeholder is
spelled `NAME` here only because this page's sanitizer eats
angle-bracket tokens.)
## Census (taken first, before any edit)
Method: a scratch preload (`NODE_OPTIONS=--import`, never committed)
recorded every finding-shaped object (`rule` + `message`) pushed into an
array or produced by `map`/`flatMap`, deduped by (rule, message), with
its push site, in every vitest worker and every process a test spawns.
- **`packages/lint` suite** at `05c7c3fa3b` (the base): 128 files, 5,894
tests passed; 241 rule ids fired, 147 over 200 characters.
- **`packages/cli` suite**, unit and integration, against the base's
lint dist: 372 files, 4,961 passed / 2 skipped. It fires 75 ids. Rows
from `os lint`'s own printer (`commands/lint.ts`), whose `message` is
the printed `where: message` line, are excluded. It adds one over-200
lint id the lint suite never fires that long
(`relationship/delete-behavior` 201), longer variants of five others
(marked below), and nine over-200 ids owned by `packages/cli`.
- Not measured: the `metadata-protocol`, `spec` and example suites (the
functional-completeness ids were measured over the spec suite by slice
1). The census counts what some test fires; a variant no test fires is
not in it, and `chart-config-missing`, `react-prop-deprecated`,
`relationship/association-inline-edit` and `rollup/missing-summary`
fired in neither suite.
- Lengths are `message` alone; the printed line adds `where` and `: `.
**Author-time ids over about 200 characters, after slice 1: 146 in
`packages/lint`** (26 this slice, 26 in fenced files, 94 later), plus 9
in `packages/cli` and the action-governance boot-log lines in
`packages/objectql/src/action-governance.ts` (named by stage 1, its own
later slice). `lint-startup-registry-verdict.ts`'s two ids (779, 731)
belong to the repo gate `check:startup-registry-verdict`, not to an
author, and are not counted.
### This slice — 26 ids, before → after (every distinct message each id
fires in the `packages/lint` suite)
| rule id | file | severity | before: messages · longest | after:
messages · shortest–longest |
|---|---|---|---|---|
| `dashboard-filter-field-unprovisioned` | `validate-widget-bindings.ts`
| warning | 3 · 509 | 3 · 163–192 |
| `chart-field-unknown` | `validate-widget-bindings.ts` | warning | 5 ·
407 | 5 · 134–185 |
| `dashboard-filter-field-not-included` | `validate-widget-bindings.ts`
| error | 1 · 370 | 1 · 197–197 |
| `widget-filter-field-unknown` | `validate-widget-bindings.ts` | error
| 5 · 364 | 5 · 62–156 |
| `dashboard-filter-field-unknown` | `validate-widget-bindings.ts` |
error | 11 · 333 | 11 · 119–189 |
| `chart-dimensions-missing` | `validate-widget-bindings.ts` | warning |
13 · 306 | 13 · 102–124 |
| `widget-filter-field-not-included` | `validate-widget-bindings.ts` |
error | 1 · 282 | 1 · 169–169 |
| `widget-measures-missing` | `validate-widget-bindings.ts` | warning |
7 · 255 | 7 · 175–188 |
| `widget-sortby-unselected` | `validate-widget-bindings.ts` | error | 2
· 242 | 2 · 177–191 |
| `chart-measures-missing` | `validate-widget-bindings.ts` | warning |
13 · 224 | 13 · 170–181 |
| `widget-legacy-analytics-unrenderable` | `validate-widget-bindings.ts`
| error | 3 · 205 | 3 · 148–176 |
| `security-controlled-by-parent-ambiguous-relation` |
`validate-security-posture.ts` | error | 8 · 697 | 6 · 159–194 |
| `security-fls-unknown-field` | `validate-security-posture.ts` | error
| 7 · 593 | 7 · 173–197 |
| `security-controlled-by-parent-no-relation` |
`validate-security-posture.ts` | error | 7 · 526 | 2 · 165–165 |
| `security-master-detail-ungranted` | `validate-security-posture.ts` |
warning | 10 · 449 | 10 · 134–178 |
| `security-owd-alias` | `validate-security-posture.ts` | error | 9 ·
354 | 9 · 61–186 |
| `security-delegation-missing-reason` | `validate-security-posture.ts`
| error | 3 · 210 | 3 · 100–100 |
| `visibility-predicate-unknown-function` |
`validate-visibility-predicates.ts` | error | 9 · 655 | 9 · 156–190 |
| `visibility-predicate-over-budget` |
`validate-visibility-predicates.ts` | error | 6 · 507 | 4 · 156–163 |
| `visibility-bare-identifier` | `validate-visibility-predicates.ts` |
error | 23 · 411 | 23 · 135–169 |
| `visibility-predicate-syntax` | `validate-visibility-predicates.ts` |
error | 16 · 341 | 16 · 140–175 |
| `visibility-root-mislayered` | `validate-visibility-predicates.ts` |
warning | 4 · 304 | 4 · 167–169 |
| `dataset-field-not-included` | `validate-dataset-references.ts` |
error | 1 · 446 | 1 · 152–152 |
| `dataset-field-unknown` | `validate-dataset-references.ts` | error |
13 · 296 | 13 · 59–100 |
| `dataset-filter-field-unknown` | `validate-dataset-references.ts` |
error | 5 · 294 | 5 · 55–98 |
| `dataset-include-unknown` | `validate-dataset-references.ts` | error |
6 · 260 | 6 · 77–152 |
The message counts fall for three ids because the old messages repeated
the object's name (the two `controlled_by_parent` ids) or echoed the
predicate (`visibility-predicate-over-budget`), which the finding's
`where` and `path` already carry.
### Fenced off by the claim — 26 ids (open PRs and the serial
flow-template queue)
- `lint-flow-patterns.ts` (15): `flow-multi-write-unfiltered` 656,
`flow-decision-mode-invalid` 528, `flow-loop-body-uncontained` 522,
`flow-try-catch-without-catch` 520,
`flow-approval-revise-target-not-service-owned` 366,
`flow-decision-unconditional-branch` 342, `flow-error-label-not-fault`
315, `flow-inert-node-condition` 286, `flow-runas-unscoped` 284,
`flow-branch-label-unmatched` 272, `flow-decision-inclusive-overlap`
250, `flow-default-edge-with-condition` 239,
`flow-multiple-default-edges` 211, `flow-time-relative-antipattern` 208,
`flow-date-equality-filter` 208
- `validate-flow-template-paths.ts` (3):
`flow-template-field-unprovisioned` 440,
`flow-template-lookup-traversal` 349, `flow-template-unknown-field` 258
- `validate-component-props.ts` (2): `component-props-invalid` 994,
`component-props-unknown-key` 844
- `validate-page-field-bindings.ts` (2): `page-field-unprovisioned` 484,
`page-section-group-unknown` 214
- `validate-expressions.ts` (1): `expression-invalid` 2077
- `validate-filter-tokens.ts` (1): `filter-token-unknown` 386
- `validate-form-layout.ts` (1): `form-section-group-unknown` 214
- `validate-print-page-blocks.ts` (1): `print-page-block-unprintable`
368
### Remaining for later slices — 94 ids in `packages/lint`, by file
(longest fired message; "cli" marks a length only the cli suite reached)
- `data-model-rules.ts` (6): `unique/legacy-organization-composite` 480
cli, `relationship/master-detail-required` 462,
`unique/unscoped-declared-index` 427, `unique/double-declaration` 402
cli, `rollup/non-numeric-aggregand` 364, `relationship/delete-behavior`
201 cli
- `validate-flow-trigger-readiness.ts` (5):
`flow-time-relative-descriptor-invalid` 796,
`flow-time-relative-descriptor-unroutable` 532,
`flow-trigger-unroutable` 518, `flow-api-trigger-secret-missing` 336,
`flow-trigger-unknown-event` 222
- `validate-react-page-props.ts` (5): `react-chart-drilldown-invalid`
784, `react-chart-aggregate-invalid` 507,
`react-chart-field-unprovisioned` 429,
`react-block-needs-record-context` 267, `react-page-source-unparseable`
211
- `validate-rls-predicate-enforceability.ts` (5):
`rls-predicate-unparseable` 2056, `rls-predicate-unenforceable` 1679,
`rls-predicate-unknown-user-variable` 1544,
`rls-predicate-unknown-field` 1399, `rls-predicate-over-budget` 1259
- `validate-action-body-writes.ts` (4):
`action-body-write-unprovisioned-anchor` 778,
`action-body-write-unknown-field` 433, `action-record-write-discarded`
293, `action-body-source-unparseable` 212
- `validate-sharing-rule-enforceability.ts` (4):
`sharing-rule-unlowerable-condition` 1093,
`sharing-rule-object-not-shareable` 774,
`sharing-rule-object-controlled-by-parent` 660,
`sharing-rule-runtime-variable-condition` 492
- `validate-ai-agent-authoring.ts` (3): `default-agent-legacy-alias`
466, `default-agent-outside-roster` 388, `agent-authoring-withdrawn` 352
- `validate-hook-body-writes.ts` (3):
`hook-body-write-unprovisioned-anchor` 792,
`hook-body-write-unknown-field` 527 cli, `hook-body-source-unparseable`
212
- `validate-predicate-path-refs.ts` (3): `predicate-rhs-path-shaped`
648, `predicate-path-unrooted` 434, `predicate-path-unresolved` 371
- `validate-searchable-fields.ts` (3): `searchable-field-unprovisioned`
512, `searchable-field-unsearchable` 449, `searchable-field-unknown` 295
- `validate-sortable-fields.ts` (3): `sort-field-unprovisioned` 844,
`sort-field-unsortable` 369, `sort-field-unknown` 287
- `lint-view-refs.ts` (2): `view-ref-nav-view-missing` 437,
`view-key-collision` 278 cli
- `validate-approval-approvers.ts` (2):
`approval-approvers-may-resolve-empty` 451,
`approval-approver-not-membership-tier` 272
- `validate-chart-bindings.ts` (2): `chart-measure-unknown` 442,
`chart-axis-not-selected` 327
- `validate-dashboard-action-refs.ts` (2):
`dashboard-action-route-unresolved` 242,
`dashboard-action-target-undefined` 239
- `validate-dataset-measure-aggregates.ts` (2):
`measure-aggregate-field-type-refused` 809,
`dimension-json-stored-field-refused` 531
- `validate-empty-combinators.ts` (2): `filter-empty-combinator` 352,
`filter-empty-node` 226
- `validate-flow-node-writes.ts` (2):
`flow-node-write-unprovisioned-anchor` 739,
`flow-node-write-unknown-field` 421
- `validate-list-view-field-refs.ts` (2): `list-view-field-dotted` 445,
`list-view-field-unknown` 355
- `validate-readonly-flow-writes.ts` (2): `flow-update-readonly-field`
410, `flow-update-readonly-when-field` 317
- `validate-readonly-hook-writes.ts` (2):
`hook-api-update-readonly-field` 464,
`hook-api-update-readonly-when-field` 323 cli
- `validate-rule-compilability.ts` (2):
`validation-rule-json-schema-uncompilable` 517,
`validation-rule-regex-uncompilable` 482
- `validate-translation-references.ts` (2): `translation-target-unknown`
345, `translation-option-key-unknown` 230
- `lint-flow-credential-literals.ts` (1): `flow-credential-literal` 390
- `validate-action-dispatch-contract.ts` (1):
`action-dispatch-contract-mismatch` 927
- `validate-action-name-refs.ts` (1): `action-name-undefined` 409
- `validate-ai-surface-affinity.ts` (1): `ai-skill-surface-mismatch` 281
- `validate-ai-tool-references.ts` (1): `ai-skill-tool-unresolved` 441
- `validate-capability-references.ts` (1):
`capability-reference-unknown` 219
- `validate-component-types.ts` (1): `component-type-unknown` 807
- `validate-flow-filter-tokens.ts` (1): `flow-filter-token-unknown` 278
- `validate-managed-api-methods.ts` (1):
`object/managed-api-method-unaffordable` 412
- `validate-mapping-target-fields.ts` (1):
`mapping-target-field-unknown` 466
- `validate-nav-access.ts` (1): `nav-object-ungranted` 353
- `validate-nav-object-servability.ts` (1): `nav-object-unservable` 528
- `validate-nav-target-refs.ts` (1): `nav-target-unresolved` 426
- `validate-object-field-refs.ts` (1): `object-field-ref-unknown` 320
- `validate-object-references.ts` (1):
`object-reference-unregistered-platform` 324
- `validate-org-axis-red-lines.ts` (1): `org-axis-cross-org-bu-grant`
365
- `validate-page-visualization-bindings.ts` (1):
`page/visualization-without-binding` 629
- `validate-preset-comparands.ts` (1): `filter-preset-comparand` 669
- `validate-readonly-action-writes.ts` (1):
`action-api-update-readonly-when-field` 396
- `validate-retired-permission-residue.ts` (1):
`permission-retired-lifecycle-residue` 235
- `validate-rule-schema-formats.ts` (1):
`validation-rule-json-schema-unknown-format` 1049
- `validate-seed-replay-safety.ts` (1):
`seed-insert-mode-duplicates-on-replay` 222
- `validate-seed-state-machine.ts` (1):
`seed-value-outside-state-machine` 320
- `validate-semantic-roles.ts` (1): `semantic-role-field-unprovisioned`
291
- `validate-translatable-sections.ts` (1):
`translation-section-name-missing` 553
- `validate-view-containers.ts` (1): `view-container-shape` 290
### Outside `packages/lint` — 9 ids owned by `packages/cli` (fired by
the cli suite)
- `packages/cli/src/lint/hook-body-lowering.ts` (4):
`hook-body/not-lowerable` 661, `hook-body/unparseable` 469,
`hook-body/bundled-fallback` 334, `hook-body/extraction-failed` 331
- `packages/cli/src/utils/collect-docs.ts` (4):
`docs/uncollected-directory` 558, `docs/duplicate-name` 330,
`docs/nav-target` 299, `docs/frontmatter-tags` 285
- `packages/cli/src/utils/picklist-references.ts` (1):
`picklist-reference-unverified` 245
## Picking the slice
Whole files, fenced files excluded, most over-200 ids first, at most 30:
| file | over-200 ids | taken? |
|---|---|---|
| `validate-widget-bindings.ts` | 11 | yes |
| `validate-security-posture.ts` | 6 | yes |
| `data-model-rules.ts` | 6 (5 in the lint suite; the cli suite fires
`relationship/delete-behavior` at 201) | no:
`relationship/master-detail-required` and `rollup/non-numeric-aggregand`
have no exported rule id constant, and a `RULE_EXPLANATIONS` key must be
one (`rule-explanations.test.ts`). Exporting two new constants adds
public surface, which is not `Clause-②: no`. |
| `validate-visibility-predicates.ts` | 5 | yes |
| `validate-flow-trigger-readiness.ts` | 5 | no:
`flow-time-relative-descriptor-invalid` (796) ends with the
time-relative trigger schema's own refusal prose, which lives in
`packages/spec`, so it needs a spec edit |
| `validate-react-page-props.ts` | 5 | no:
`react-chart-drilldown-invalid` (784) and
`react-chart-aggregate-invalid` (507) are the chart schemas' own refusal
prose (`packages/spec/src/ui/chart.zod.ts`) |
| `validate-rls-predicate-enforceability.ts` | 5 | no: each verdict
quotes the whole predicate and composes a per-clause consequence from
builders the five ids share (1,259 to 2,056 characters). That
security-critical rework is a slice of its own. |
| `validate-dataset-references.ts` | 4 | yes: the dataset half of the
widget family (the same object-graph account and the same "compiled into
the analytics query" consequence) |
| `validate-action-body-writes.ts`,
`validate-sharing-rule-enforceability.ts` | 4 each | no: the first
shares its unprovisioned-anchor and unknown-field wording with
`validate-hook-body-writes.ts` and `validate-flow-node-writes.ts`, a
nine-id family to shorten together. The second shares the RLS
consequence prose. |
So the slice is 11 + 6 + 5 + 4 = **26 ids**.
## Doors that print the new text
Read from the registry entries (`authoring-rules.ts`,
`reference-integrity-suite.ts`) and the runtime gate
(`metadata-protocol/src/runtime-authoring-gate.ts`,
`lint/src/runtime-gate.ts`):
| door | ids | what changes |
|---|---|---|
| `os validate`, `os build` (and `os compile`, which `os dev` runs per
compile), `os lint`, `os verify`, `os init` scaffold check | all 26
(every entry is `commands: ALL`) | the text-face verdict line; the
`rule:` line gains the `os explain` pointer; `os validate --json`
`warnings` and `os build --json` author-time `issues` carry the new
`message` |
| `os doctor` dashboard widget check | the 11 widget ids | prints
`where: message`, no `rule:` line (see Acceptance notes) |
| runtime publish gate, `dashboard` writes (Studio, REST `/meta`, MCP) |
the 11 widget ids | errors: the 422 issue `message` and the
`OS_ALLOW_UNLINTED_METADATA_WRITES` refusal log line. Warnings
(`dashboard-filter-field-unprovisioned`, `chart-field-unknown`,
`chart-measures-missing`, `widget-measures-missing`,
`chart-dimensions-missing`): the 2xx `advisories` `message` and the
deduped `[Protocol] authoring advisory` log line |
| same gate, `dataset` writes | the 4 dataset ids (all errors) | the 422
issue `message`, the hatch log line |
| same gate, `view` writes | the 5 visibility ids | four errors (the
422, the hatch log); `visibility-root-mislayered` is a warning (the 2xx
`advisories`, the advisory log) |
| same gate, `object` / `permission` / `seed` writes |
`security-controlled-by-parent-*` (object), `security-fls-unknown-field`
(permission), `security-master-detail-ungranted` (object or permission,
a warning), `security-delegation-missing-reason` (seed) | as above, by
severity |
| never at the runtime gate | `security-owd-alias` | the object schema's
closed OWD enums refuse those values at parse, with their own message,
before the gate runs |
| unchanged | every `hint`; every other rule id | |
Every row is named in the changeset.
## Tests (round 0, head `7564f71b04`)
- **Each rule's own suite pins the new shape.** The four test files
record every finding their cases fire for the shortened ids, through a
wrapper around the imported rule. A final case then holds each recorded
verdict to one line of at most 200 characters, behind a coverage control
that each shortened id fired at least once. So the pin covers every
firing variant the suite exercises, not a chosen few, which is the gap
slice 1's landing recorded. A second block pins, per id, that
`explainRule(id)` exists and still names what the verdict stopped
saying. Existing message pins now read the verdict's substance, the
path, names and outcome, never the full prose; every refusal assertion
is unchanged.
- `pnpm --filter @objectstack/lint exec vitest run --maxWorkers=2` →
Test Files 128 passed (128), Tests 5,928 passed; lock VERDICT
command-exit 0.
- `pnpm --filter @objectstack/lint run typecheck` → VERDICT command-exit
0. `check:test-typecheck` OK: 2 files, 6 errors and 2 pinned signatures
held.
- cli, after `pnpm --filter @objectstack/lint build`: `pnpm --filter
@objectstack/cli exec vitest run --project unit --maxWorkers=2
test/explain-rule-id.test.ts test/commands.test.ts` → 2 files, 62
passed. `explain-rule-id.test.ts` iterates every `RULE_EXPLANATIONS`
key, so all 26 new ids resolve through `os explain` and through
`explainPointer`. The two sets stay disjoint from the schema names. The
rebuilt dist carries the new entries (marker grep: 1 hit each in
`dist/rule-explanations.js` and `.cjs`).
- Sibling suites that fire these ids, run although the public surface is
byte-identical:
- `metadata-protocol`, three runtime-gate files
(`runtime-authoring-gate.dataset-writes`,
`protocol-publish-drafts-closure`,
`protocol.dashboard-dataset-publish-gate`) → 3 files, 21 passed;
- `examples/app-showcase`, three files (`nav-and-detail-grants`,
`dashboard-filter-vocabulary`, `my-work-visibility`) → 3 files, 14
passed, after building the showcase's dependency closure.
- **Ablations**, one-shot and on committed state through
`scripts/ablation-replace.mjs` (wrap mode, trap-armed). The tests import
the rule source directly, so no dist leg applies.
- (a) `chart-dimensions-missing`'s verdict lengthened to 240 characters
(blob `c07dd85c` → `449306c6`) → `validate-widget-bindings.test.ts` 1
failed | 161 passed, the one-line case.
- (b) `BY NAME` removed from the `chart-field-unknown` explanation (blob
`da3574bc` → `7288a22f`) → 1 failed | 161 passed, that id's explanation
case.
- Both restored: blob == HEAD, `git diff HEAD` empty, `git status
--porcelain` empty.
- **Nothing else moved:** the census preload re-run over the whole lint
suite at the head shows every fired message of every id outside the 26
byte-identical to the base.
- **ESLint, narrowed:** `npx eslint --no-inline-config --format json`
over the 11 changed `.ts` files → 11 files in the report, 0 errors, 0
warnings, none ignored. `eslint.config.mjs` never enables type-aware
linting (its comment at `:327`), so no untouched file's verdict can
move.
- **Gates:** `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 62 commands from the 11 changed
paths (merge base `05c7c3fa3`). All 62 ran sequentially, each with its
own log and an exit code captured before any pipe; 61 exited 0 on the
first run. `pnpm check:dual-build-cjs-loads` exited 3, PREREQUISITE NOT
MET, because eight packages outside this tree's builds had no `dist/`;
after building them it exited 0. `--ran` → `✓ dispatch-gates --ran: 62
derived famil(ies) accounted for — 62 run, 0 NOT-MEASURED`. A
control-character scan of every changed file: no match.
## Patch round 1 (head `6258d37185`)
- CI on `7564f71b04` went red in `@objectstack/spec`'s `repo` project:
`retired-key-migrate-sentence.test.ts` walks `packages/lint/src` and
judged the new `chart-field-unknown` explanation's sentence "`os migrate
meta --from 17` lists the mechanical edits for existing sources" neither
house-form nor MIXED (REWORK `6078055875` on #22161).
- `77a246b85d` drops that sentence from the explanation; the house
sentence still prints on the rule's xAxis fix line in
`validate-widget-bindings.ts`. The rule's MOVED-fact pin now names
"refused on a dataset-bound widget".
- Spec `repo` project 54 files / 915 passed; with the old sentence
restored, exactly the three `retired-key-migrate-sentence.test.ts` cases
go red (3 failed / 912 passed). Lint suite 129 / 5,938.
- `origin/main` merged twice (`2e5eb5aed3`, `6258d37185`); the net diff
is unchanged in scope (12 files, +903 / −197).
- Report `6079174263` on #22161; seat ACCEPT `6079204385`.
## Acceptance notes
- **`os doctor` prints the widget ids without a `rule:` line.** Its
dashboard check prints `where: message`, with the `hint` only under
`--verbose`. It never named the rule id, and the `os explain` pointer
stage 1 put on the other printers never reached it, so a doctor reader
now sees the short verdict and no pointer. `os validate` on the same
project prints the `rule:` line with the pointer. That is a `domain:cli`
printer change, outside this slice's files, and is recorded rather than
built.
- **The `rule:` line with its pointer runs up to about 190 characters**
for the longer ids (`security-controlled-by-parent-ambiguous-relation`
plus its `covers`). This is stage 1's printer shape, carried as before.
- **Author values extend a verdict.** The fixed text of every verdict is
short; the field path, the candidate roster, the selection list and the
predicate excerpt (capped at 72) are what an author needs, so they stay,
and a long one lengthens the line. The changeset says so.
- **`unprovisionedAnchorCause()` keeps its other callers.** Only
`dashboard-filter-field-unprovisioned` moves to the new one-clause
`unprovisionedAnchorVerdict()`; the eight other rule files converge when
their slices shorten them, which the helper's docblock states.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01VZqqwTj2wsihZEbfT6yyYN)_
---------
Co-authored-by: Claude <noreply@anthropic.com>os explain RULE_ID carries their reasoning (#22448)1 parent c7a3234 commit 33ae4bf
12 files changed
Lines changed: 903 additions & 197 deletions
File tree
- .changeset
- packages/lint/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
923 | 923 | | |
924 | 924 | | |
925 | 925 | | |
926 | | - | |
927 | | - | |
| 926 | + | |
| 927 | + | |
| 928 | + | |
| 929 | + | |
928 | 930 | | |
929 | 931 | | |
930 | 932 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
207 | 207 | | |
208 | 208 | | |
209 | 209 | | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
210 | 224 | | |
211 | 225 | | |
212 | 226 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
11 | 32 | | |
12 | 33 | | |
13 | 34 | | |
| |||
557 | 578 | | |
558 | 579 | | |
559 | 580 | | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
163 | 163 | | |
164 | 164 | | |
165 | 165 | | |
166 | | - | |
167 | | - | |
168 | | - | |
169 | | - | |
170 | | - | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
171 | 170 | | |
172 | 171 | | |
173 | 172 | | |
| |||
232 | 231 | | |
233 | 232 | | |
234 | 233 | | |
235 | | - | |
236 | | - | |
| 234 | + | |
237 | 235 | | |
238 | 236 | | |
239 | 237 | | |
| |||
246 | 244 | | |
247 | 245 | | |
248 | 246 | | |
249 | | - | |
250 | | - | |
251 | | - | |
| 247 | + | |
252 | 248 | | |
253 | 249 | | |
254 | 250 | | |
| |||
279 | 275 | | |
280 | 276 | | |
281 | 277 | | |
282 | | - | |
| 278 | + | |
283 | 279 | | |
284 | 280 | | |
285 | 281 | | |
| |||
300 | 296 | | |
301 | 297 | | |
302 | 298 | | |
303 | | - | |
304 | | - | |
305 | | - | |
306 | | - | |
| 299 | + | |
| 300 | + | |
307 | 301 | | |
308 | 302 | | |
309 | 303 | | |
| |||
0 commit comments