Repository navigation
Commit 9c74d40
fix(lint): one-line fix lines for the last eight fenced author-time rule ids (slice 21); os explain carries what they explained (#24292)
Part of #22161
Clause-②: no
Slice 21 of the card. It covers the other 8 author-time `packages/lint`
ids that slice 2 fenced. Those ids are inside the card's close condition
(triage answer A, comment `6219576699`), and this slice uses the shape
of slices 11–20. Each finding's `hint` for these 8 ids (the CLI's `fix:`
line, and the runtime finding's `hint`) is now one remedy line of at
most 200 characters. What the old lines explained is now in each id's
new `RULE_EXPLANATIONS` entry, which `os explain RULE_ID` prints. The
card stays open. The last section lists what is left.
Claim: `6247309763`. It is the newest `Claim:` on the card and names
this branch; I checked that before any edit. This run resumes from
`claude/issue-22161-s21-validate-hints@c4eca88`, which a dead earlier
run pushed with no PR and no report. It never started over from zero. I
reviewed that head's three commits (`fe9bb145c` fix lines and entries,
`8160ab7da` a `main` merge, `c4eca88ab` changeset) hunk by hunk and kept
them, with the corrections listed under "On top of the inherited head".
Every reading below was taken again in this run.
## What changes
**One remedy line per finding.** The table lists every hint the lint
suite fires for the eight ids, before and after, as distinct hints ·
length range. The instrument is a census preload over the whole lint
suite: `Array.prototype` push / unshift / map / filter / forEach / find
/ some / every / flatMap / concat / slice hooks that record every
finding-shaped object, with its `hint`, `fix`, `message`, `where`,
`path` and `severity`. "Before" is this branch's tests run against
`main`'s rule sources, which are `93b4acb57` blobs written into the tree
and restored under a trap (method below). "After" is this branch at its
final head. The runtime column comes from a scratch probe of the runtime
gate (below), FROM → TO.
| rule id | lint suite, before → after | runtime door
(`runRuntimeAuthoringRules`) |
|---|---|---|
| `flow-template-field-unprovisioned` | 1 · 362 → 1 · 175 | `flow`
write, 2xx advisory, 362 → 175 |
| `flow-template-lookup-traversal` | 5 · 251–316 → 5 · 125–139 | `flow`
write, 2xx advisory, 249 → 131 (trigger root), 314 → 126 (flow variable)
|
| `page-field-unprovisioned` | 1 · 362 → 1 · 175 | does not fire on a
`page` write (a reference-integrity member on the frozen `flow` default)
|
| `page-section-group-unknown` | 4 · 188–279 → 4 · 118–151 | does not
fire on a `page` write (same) |
| `print-page-block-unprintable` | 1 · 362 → 1 · 170 | `page` write, 422
issue, 362 → 170 |
| `form-section-group-unknown` | 5 · 178–275 → 5 · 104–147 | CLI only
(`surfaces: CLI_ONLY`) |
| `filter-token-unknown` | 5 · 132–259 → 5 · 132–170 | CLI only
(`surfaces: CLI_ONLY`) |
| `component-props-invalid` | 33 · 164–258 → 33 · 157–188 | `page`
write, 422 issue, value line 248 → 157 (`page:tabs`), 250 → 159
(`object-grid`), 253 → 162 (`record:details`), 258 → 167
(`record:related_list`) |
**Measured on `main` first, as the order asked.** I ran `main` itself at
`93b4acb57`, with its own rule sources and its own tests. All eight ids
fire over 200 there, at the lengths the seat's record `6217435246`
lists: 362, 316, 362, 279, 362, 275, 259 and 258. On `main` the census
finds 11 ids over 200: these eight, plus the 3 repo-gate ids outside the
condition. Some lines did not change. `filter-token-unknown`'s four "Did
you mean" lines (132–161) were one remedy line already. So were
`component-props-invalid`'s retired-key line (164–181) and its
node-binding line (188). Only the value-rejection line (248–258 →
157–167) moves.
**What each line says now.**
- The two anchor ids print the shared one-line anchor fix
(`unprovisionedAnchorFix()`) that the other unprovisioned-anchor ids
already print.
- The lookup-traversal line names the start node's `config.expand`
opt-in on the trigger root, and never on a variable root.
- The two section-group ids name the nearest declared group ("Did you
mean") instead of listing every group the object declares. For an object
with no groups, the line is: declare a group, or enumerate the section's
`fields`.
- The print line points at `os explain print-page-block-unprintable` for
the printable list. This finding is also refused at the save door, where
no `rule:` line carries the pointer.
- The filter line names the two vocabularies briefly.
- The props line asks for a value the props schema accepts, or for a
schema fix.
**`os explain` carries the rest.** Each of the eight ids gains a
`RULE_EXPLANATIONS` entry, so its `rule:` line now carries the `os
explain` pointer. What the lines stopped saying is there:
- how to vouch for an unprovisioned anchor through `columnMap`, or opt
the object out (`ownership: 'none'`, `systemFields: { audit: false }`),
shared with the earlier anchor entries;
- what `config.expand` does: a one-hop re-read of the triggering record
as the run's identity. It covers the trigger record alone;
- how a section inherits a field group's members, and that membership is
declared on the field;
- the printable block list, held equal to the spec's
`PRINTABLE_PAGE_COMPONENT_TYPES` by the rule's test, and the three
reasons a block is refused;
- the context tokens (held equal to `CONTEXT_TOKENS` by the rule's test)
and the date macros. It also says where `{record_id}` resolves, and that
the runtime refuses an unresolvable placeholder;
- where a page component's props schema lives, why the page, not the
schema, is almost always what to fix, and the retired-key and
node-binding cases.
I checked every fact in the eight entries against the rule source and
its docblock, and against the spec where they cite it:
`date-macros.zod.ts`, `PRINTABLE_PAGE_COMPONENT_TYPES` and
`ComponentPropsMap`. I also checked the runtime they describe: the
automation engine's `expandDeclaredLookups` for `config.expand`, and
`@objectstack/core`'s `UnknownFilterTokenError` for the 400. Why
`Clause-②: no` holds:
- the eight rule-id constants were already root-barrel exports;
- the new entry constants are module-local;
- `RULE_EXPLANATIONS` (already published) gains eight keys.
So no published name is added. The one removed function,
`unprovisionedAnchorHint`, was module-exported from `system-fields.ts`
but is reached by no package entry. `node
scripts/check-platform-checklist.mjs --changed-from origin/main` reads
OK (1 anchor judged, 0 lost).
**Nothing else moves.** Every `message`, rule id, severity and `path` is
unchanged, and so is what each rule accepts or refuses. The census
proves this mechanically: it records the (`message`, `where`, `path`,
`severity`) tuple of every finding. For each of the eight ids, the set
of those tuples is identical with `main`'s sources and with this
branch's: 1, 8, 8, 4, 55, 6, 27 and 123 tuples, 0 differing. Every other
id's rows are identical too: 4067 rows, run under the same instruments,
with one extra row explained in the Verification section.
### The two files the claim named conditionally
- **`packages/lint/src/object-field-groups.ts`: kept.**
`checkSectionGroupRefs()` builds the `hint` of both section-group ids.
`validate-form-layout.ts` and `validate-page-field-bindings.ts` call it
with their rule id, so the one-line form lives there. That is why
`validate-form-layout.ts` itself has no diff.
- **`packages/lint/src/system-fields.ts`: kept.**
`unprovisionedAnchorFix()`, which builds both anchor ids' hint, lives
there. The edit deletes `unprovisionedAnchorHint()`, the long form those
two ids called. They were its last two callers. The edit also rewrites
the shared fix's docblock.
## On top of the inherited head
- **`main` merged first** (`1e1554e15`, clean). Slice 20's
`rule-explanations.ts` entries (`b6805ac0f`) merged without a conflict,
and all 20 entries are present: the twelve `lint-flow-patterns.ts` ids
plus these eight.
- **Two entry sentences made exact.**
- The form entry named only `data.object` as a form's own binding. The
rule reads `objectName`, `object` or `data.object` (`viewObjectName`).
- The page entry skipped the binding a nested component inherits from
its container (`walkPageComponents`).
- **A docblock that overclaimed.** `unprovisionedAnchorFix()`'s docblock
said every unprovisioned-anchor rule in the package prints that wording.
Two (`validate-expressions.ts`, `validate-semantic-roles.ts`) still word
their own fix, as the cause docblock beside it already notes. It now
says so.
- **The changeset carries this run's numbers.** The retired-key range is
164–181 on the merged tree; it was 164–180. The flow lookup-traversal
door readings are this run's probe: 249 → 131 and 314 → 126.
### File surface: the claim's
The diff touches six rule files, but only five have a diff.
`validate-form-layout.ts` has none, because its hint is built in
`object-field-groups.ts`. The rest of the diff:
- each rule file's test;
- `rule-explanations.ts`, entries for these eight ids only;
- `object-field-groups.ts` and `system-fields.ts`, as explained above;
- `.changeset/22161-s21-validate-fix-lines.md`.
It does not touch `lint-flow-patterns.ts`,
`lint-startup-registry-verdict.ts` or `content/docs/**`. 15 files, +674
/ −76.
## Verification
Final head `49e48cd21`. Heavy runs went through
`scripts/pm/os-verify-lock.sh` (slot `issue-22161-s21`), and each
reading below is its `VERDICT` line. Every exit code was captured before
any pipe.
- **Lint suite** at `49e48cd21`: 143 files / 6847 passed, VERDICT 0. The
census run is the same run.
- **The `main` leg.**
- Method: `main`'s `93b4acb57` blobs of the 14 changed lint files were
written into the tree only. Their landing was proved by blob hash. They
were restored from `HEAD` by absolute path under an EXIT/INT/TERM trap,
and the restore was proved by blob hash, an empty `git diff HEAD` and a
clean status.
- Result: 143 files / 6820 passed | 5 skipped, VERDICT 0. The 5 skips
are the dist-dependent `lazy-deps` / `runtime-lazy-deps` cases. The lint
dist did not exist yet, and it does now.
- **Reverse verification.** Only `main`'s 8 rule sources were swapped in
(same method), with this branch's tests: 6 files / 70 tests red, exactly
this slice's six test files. The pins fail on the old text, so they can
fail. Restore proved the same way. This one leg is also the census
"before" column above.
- **Lint build and typecheck** at `49e48cd21`, VERDICT 0 each.
- Build: `tsup` plus `check-dts-emitted`, 6/6 declaration files.
- Typecheck: `tsc` plus `check:test-typecheck` OK (2 files / 6 errors /
2 pinned, unchanged).
- `tsc -p tsconfig.test.json --listFiles` lists all six changed test
files.
- **Spec `repo` project** (`--project repo`, whose cross-package pins
read `packages/lint/src`):
- The 11 files that read `packages/lint`: 11 / 201 passed, VERDICT 0.
- The whole project: 68 files / 1125 passed, VERDICT 0 (the lock held
15m30s on a shared box).
- **Runtime probe.** 9 writes through `runRuntimeAuthoringRules` with
`tsx`: 6 `page` and 3 `flow`. It ran with `main`'s 8 rule sources
swapped in (same method), then on this branch. Results are in the table
above. No write changes channel. Each `page` case ran 4 rules and each
`flow` case 9 rules, on both sides.
- **The one extra census row.** At the final head, one
`validation-rule-json-schema-uncompilable` row appears that the earlier
legs did not record. It comes from the five dist-dependent cases, which
ran once the lint dist existed. It is not one of the eight ids.
- **Derived gates.** `node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack`, no paths, at `49e48cd21`: 64
families over 15 paths since the merge base `93b4acb57`. Each family was
run one by one and its exit code recorded. 62 exit 0. 2 exit 3
(`PREREQUISITE NOT MET`) and are NOT MEASURED:
`check:dual-build-cjs-loads` needs every package built, and
`check:lean-entry-closure` needs `packages/objectql/dist`. `--ran`
reports 64 derived, 62 run, 2 NOT-MEASURED, 0 UNRUN. This diff adds no
import edge, so CI's full build gives those two their reading. For every
family CI runs, this PR's own check-runs are the reading.
`check:dev-prereqs` and `check:skill-frame-freshness` were not run: the
diff touches neither a `packages/spec` build input nor the four-axis
frame files.
- **Control characters:** `grep -naP` over every changed file and this
body finds nothing (exit 1). A planted control byte is found (exit 0).
## Acceptance notes
- **`filter-token-unknown`'s verdict sentence contradicts the runtime it
describes.** It says an unresolvable placeholder "is sent to the data
engine as a literal string, matches no record, and the surface renders
empty". So does the rule file's module header. The runtime refuses such
a filter instead: `UnknownFilterTokenError` (`FILTER_TOKEN_UNKNOWN`,
400, `packages/core/src/utils/filter-tokens.ts`). That is the spec's own
declared behaviour (`date-macros.zod.ts`: "the runtime resolver
throws").
`packages/objectql/src/engine-filter-token-today-spelling.test.ts` pins
the refusal. The new entry states the refusal. This slice keeps messages
unchanged by its shape, so the sentence is not edited here. It was not
measured through `os validate` in this run (the CLI was not built), so
it is noted, not filed.
- **The 200-character bound is measured over the suite's fixtures, as in
slices 11–20.** Some lines interpolate names:
- the group line: about 88 characters plus two copies of the key and the
object name, and a nearest-group suggestion when one is close;
- the shared anchor line: 155 characters plus the field and object
names.
Long enough names can push either past 200. The anchor line's wording
predates this slice. `component-props-invalid`'s test re-measures its
two type-naming lines at the longest type `ComponentPropsMap` declares.
- **The census sees what the lint suite fires.** It measures 213 of the
215 id-shaped rule constants the root barrel exports. The other two
never fire in the suite. `chart-config-missing` has no emit site in
`packages/lint/src`. `react-prop-deprecated`'s hint is the react-blocks
contract's own `note` for a deprecated prop.
- **`main` moved after the one merge.** The branch carries `main` at
`93b4acb57`, and `origin/main` is now at `e15897c0f`. None of the 5
newer commits touches `packages/lint`. Per the order, I merge again only
for a conflict, a `main`-caused red or a queue removal.
- `validate-expressions.test.ts` still names the deleted
`unprovisionedAnchorHint` in a historical comment about an earlier card.
It is outside this slice's surface and left as written.
- **Not run locally, declared to CI.**
- The `packages/cli` tiers. `test/explain-rule-id.test.ts` holds every
`RULE_EXPLANATIONS` key disjoint from the `os explain` schema names and
resolves each through the command.
- `os validate` / `os explain` through a built CLI.
- Both need the CLI build closure: 62 packages, most of them downstream
of `@objectstack/lint`.
## Remaining for this card
The census at `49e48cd21` covers the whole lint suite: 239 ids fire, and
3 are over 200. All 3 are outside the close condition (repo gate, not
author-time): `lint-startup-registry-verdict.ts`'s
`startup-open-vocabulary-verdict` 972,
`startup-verdict-assertive-wording` 972 and `startup-source-unparseable`
254. No author-time `packages/lint` id fires a hint or `fix:` over 200
characters in the suite. The close-out slice still owes two things: the
census re-measured on `main` after this lands, and the
`content/docs/ui/react-pages.mdx` transcript carry from slice 15's
landing record `6136999237`.
---
_Generated by [Claude
Code](https://claude.ai/code/session_019oFY6Hi35J7atvgVFnmoaK)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent ef65646 commit 9c74d40
15 files changed
Lines changed: 674 additions & 76 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
42 | | - | |
| 42 | + | |
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
| |||
149 | 149 | | |
150 | 150 | | |
151 | 151 | | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
152 | 156 | | |
153 | | - | |
154 | | - | |
155 | | - | |
156 | | - | |
157 | | - | |
158 | | - | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
159 | 162 | | |
160 | 163 | | |
161 | 164 | | |
| |||
0 commit comments