Repository navigation
fix(lint): one-line fix lines for 16 more author-time rule ids; os explain RULE_ID carries what they enumerated - #22909
Conversation
Part of the #22161 slice 12 work: each hint of the ten claimed rule files becomes one remedy line, and what it enumerated moves into the ids' RULE_EXPLANATIONS entries. Claude-Session: https://claude.ai/code/session_01KNKBCRDJCu5tGy3TEbvtrF Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KNKBCRDJCu5tGy3TEbvtrF Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KNKBCRDJCu5tGy3TEbvtrF Co-authored-by: Claude <noreply@anthropic.com>
…-lint-slice-12-hints
Claude-Session: https://claude.ai/code/session_01KNKBCRDJCu5tGy3TEbvtrF Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 6 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 4 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin d8096e2c5d162fea8007fc5aa7c1cb9620f2c3ca && git checkout d8096e2c5d162fea8007fc5aa7c1cb9620f2c3ca
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin eb20c33c456f4b9fdeafd0e7a5b5de274888848e 9d56f0f4310049e79805aa54afc9b78a9180805a && git checkout -B drift-repro eb20c33c456f4b9fdeafd0e7a5b5de274888848e && git merge --no-ff 9d56f0f4310049e79805aa54afc9b78a9180805a
node scripts/docs-audit/affected-docs.mjs --json eb20c33c456f4b9fdeafd0e7a5b5de274888848e
|
Landing pre-checks at
|
Part of #22161
Clause-②: no
Stage 2 of the card, slice 12: the over-long
fix:lines, continued in slice 11's shape. Each finding'shint(the CLI'sfix:line, the runtime issue'shint) of 16 morepackages/lintrule ids, in ten whole rule files, is now one remedy line of at most 200 characters, and what the lines used to enumerate or explain is each id'sRULE_EXPLANATIONSentry behindos explain RULE_ID. The card stays open: 91 author-time ids still carry a hint over 200 characters (the last section).What changes
validation-rule-json-schema-unknown-formatvalidate-rule-schema-formats.tsobjectwrite, 422measure-aggregate-field-type-refusedvalidate-dataset-measure-aggregates.tsdatasetwrite, 422dimension-json-stored-field-refuseddatasetwrite, 422predicate-rhs-path-shapedvalidate-predicate-path-refs.tsviewwrite, 422 (dotted) / 2xx advisory (bare word)predicate-path-unrootedviewwrite, 422predicate-path-unresolvedviewwrite, 422rls-predicate-unknown-user-variablevalidate-rls-predicate-enforceability.tspermissionwrite, 422rls-predicate-unparseablepermissionwrite, 422hook-api-update-readonly-when-fieldvalidate-readonly-hook-writes.tsaction-name-undefinedvalidate-action-name-refs.tsai-skill-tool-unresolvedvalidate-ai-tool-references.tsorg-axis-permission-inheritancevalidate-org-axis-red-lines.tsorg-axis-cross-org-bu-grantobject-reference-unknownvalidate-object-references.tsdatasetwrite (itsobject), 422object-reference-unregistered-platformdatasetwrite (itsobject), 2xx advisoryfilter-empty-nodevalidate-empty-combinators.tsflow/reportwrite, 422A count that falls is several old hints that differed only in what the new line no longer carries: the stack's object or action list, the site's consequence sentence, the kernel key list's position against the suggestion.
object-reference-unknowndrops "Defined objects: …" andaction-name-undefineddrops "Defined actions: …" and the related object's action list: the verdict's "Did you mean" already names the nearest one.validation-rule-json-schema-unknown-formatnames the nearest registered format and moves the full registered set (26 names) into its explanation, written out there and held toregisteredFormatNames()by the rule's test.ai-skill-tool-unresolvedmoves the family prefixes into its explanation, held toPLATFORM_TOOL_FAMILY_PREFIXES.rls-predicate-unknown-user-variablekeeps the six kernel keys and the nearest one, so its line holds no author text at all (a test holds the worst-case suggestion under 200).object-reference-*: eachcheck()site passed a consequence sentence that closed every hint (the record picker, the view container's index, the dashboard filter, the dataset's reports, the nav gate). Those are now one paragraph in both ids' explanations; thecheck()argument is aremedy, which only the view-container site passes (the namespace-prefixed spelling, which is then the whole line).measure-aggregate-field-type-refused: the line names the aggregates the declaration accepts (the "accepts: count." pins hold); whycount/count_distinctreach further, the stored-numeric route and the two doors that refuse the pair later (DATASET_COMPILE_DOOR/CUBE_QUERY_DOOR, now deleted with thedoorparameter) are the explanation's.hook-api-update-readonly-when-field: the two routes and "runAs: 'system' and sudo() do not waive this lock"; why (the system context, the sandbox), the drop-the-field alternative and "never blocks a build" are the explanation's.rls-predicate-unparseable: the SQL-to-CEL translations in one line; the subquery route (ADR-0055, ADR-0105 D11) is the explanation's.predicate-rhs-path-shaped: both spellings in one line, and the bare-word arm keeps "Do NOT simply add the root in place" (pinned byruntime-gate.test.ts); why quoting changes nothing today and why two paths cannot be compared are the explanation's.filter-empty-node:OMIT_THE_KEY/MATCH_NONE_SPELLINGare deleted from the rule and their text is the explanation's.org-axis-*,ai-skill-tool-unresolved,action-name-undefined, the two other predicate ids,dimension-json-stored-field-refused(multi-value arm) andvalidation-rule-json-schema-unknown-format: likewise, one line each.object-reference-unknown("how an object name resolves, and what a miss costs") andorg-axis-permission-inheritance("why access never walks the organization tree"). Theirrule:line now ends with theos explainpointer, whichexplainPointerprints for every id the table holds. The two object-reference entries share the sites, the ladder and the per-site cost paragraphs; the two org-axis entries share the ADR-0105 D6 opening. The other 14 entries gain paragraphs.message, rule id, severity andpath, and what each rule accepts or refuses, is unchanged: every hunk in the ten rule files is ahintexpression, a comment, a deleted hint constant, or (two places) a parameter that only fed a hint (door, andfixrenamedremedywith a default). No condition, branch, skip or dedupe moved..changeset/22161-lint-slice-12-one-line-fix.md:@objectstack/lintpatch,Clause-②: no, naming every door that printsfix:and the runtimehintFROM → TO.The runtime wire (Zone 2 item 3)
Measured at the door with
runRuntimeAuthoringRuleson the base dist and on the rebuilt one (a scratch probe, 28 writes):objectwrite:validation-rule-json-schema-unknown-format(422issues[].hint, 638 / 606 → 175 / 143, with and without a nearest name);datasetwrite:measure-aggregate-field-type-refused(422, 606 / 581 → 147 / 122),dimension-json-stored-field-refused(422, multi-value 259 → 166, structured JSON 177 unchanged),object-reference-unknownon the dataset'sobject(422, 331 → 134) andobject-reference-unregistered-platform(2xxadvisories[].hintand the[Protocol] authoring advisorylog line, 449 → 187);viewwrite of a schema-bound metadata form:predicate-rhs-path-shaped(422 dotted 384 → 156; 2xx advisory bare word 631 → 180),predicate-path-unrooted(422, 214 → 122),predicate-path-unresolved(422, 100 → 36 with a nearest key);permissionwrite:rls-predicate-unparseable(422, 523 → 171),rls-predicate-unknown-user-variable(422, 566 / 590 / 634 → 158 / 180 / 190, without a nearest key, withemail, withorganization_id);floworreportwrite:filter-empty-node(422, 515 / 278 / 170 → 113 / 107 / 69);hook-api-update-readonly-when-field,action-name-undefined,ai-skill-tool-unresolvedor the twoorg-axis-*ids (ahook,skill,page,sharing_rule,viewbulk-action andpermissionwrite were probed), nor the object-reference ids on anobjectorviewwrite.Readers of
hint, read-only against objectuimainatf3d5408141(fetched into a ref of its own,git grep, no edit): Studio'ssaveAdvisoryToast.tsformatFindingrenders[rule] where — message hintfor every 2xx advisory;DraftChangesPanel.tsxrendersp.hint || p.messagefor the in-browser security-posture lint (none of the 16);metadata-client.tsreadSaveAdvisorieschecks only thathintis a string; the 422issuesrenderers readpathandmessage. REST (PUT /api/v1/meta,SaveMetaItemResponseSchema.advisories, the error envelope'sissues) forwards the array as JSON;packages/mcphas no metadata write tool, so an MCP or AI author reaches the gate through REST. In this repositorytoIssueforwardshintverbatim, the advisory log line prints it, andbuild-probes.tsreadshintonly forobject-field-ref-unknown(not one of the 16). No reader in either repository matches onhinttext.check:watch-hint-literalguards something else of the same name (every*_WATCH_HINTSpopulation declaration in a gate script is a literal array): exit 0, 72 declarations across 4 rostered names, standalone and inside the gate set.Census (taken first, before any edit, at the base
63739521d8)Method: slices 4 to 11's scratch preload (
NODE_OPTIONS=--import, never committed) patchingArray.prototype.pushto record every finding-shaped object, deduped by (rule, hint) per process, with its push site. Lengths are thehintalone. Runs, each before and after:packages/lintsuite (137 files, 6,497 tests at the base): 240 ids fire, 131 carry a hint over 200 = 21 of the 26 fenced ids, 3 repo-gate ids (lint-startup-registry-verdict.ts) and 107 author-time ids; the 16 here match slice 11's census lengths exactly. After, at the merged head26fe94f3e1with the lint dist rebuilt: 115 over 200 = 21 fenced + 3 repo-gate + 91 author-time.@objectstack/metadata-protocolsuite reading@objectstack/lintfrom its built dist (base dist before, rebuilt after): firesmeasure-aggregate-field-type-refused(588 → 129) andrls-predicate-unparseable(523 → 171) of the 16.packages/cliunit tier (283 files): fireshook-api-update-readonly-when-field(604 → 170) andobject-reference-unknown(7 hints · 242–348 → 1 · 134).os validate(the built CLI) onapp-crm,app-todo,app-showcase,app-multi-package, exit 0 each, before and after: none of the 16 fires on any of them; each app prints the same 9 / 7 / 70 / 3rule:lines, and the printed output is byte-identical before and after.Tests
Every heavy run went through
scripts/pm/os-verify-lock.sh(slotissue-22161-s12); its VERDICT lines are in the report.fix:line of its converted ids to one line of at most 200 characters behind a coverage control (each arm fired: both format arms; the measure id on a type row and a flagged declaration and the dimension id on both classes; both unresolved arms and both right-hand arms; the variable id with and without a nearest key; the generic action arm with both placements and both related-list arms; both ai-skill arms; both org-axis ids; the object-reference id with and without the namespace remedy; all three empty-node positions), plus a check per id thatexplainRule(id)holds what the line stopped saying. The three RLS sibling files' bounds now cover everyrls-predicate-*id. Pins that read the old hint text moved to the explanation, text-only, except two that needed a new reading: the related-list drawn-locations pin now reads its own paragraph (the new fix paragraph names the header'srecord_header/record_more), and the artifact-context pin reads the verdict's "Did you mean" on a near miss instead of the dropped object list.26fe94f3e1: Test Files 137 passed (137), Tests 6,528 passed (6,528); VERDICT command-exit 0 (6,518 before the merge oforigin/main).pnpm --filter @objectstack/lint build(check-dts-emitted6/6), rebuilt with its closure after the merge, andrun typecheckat9d56f0f431(check:test-typecheckOK, 2 files / 6 errors / 2 pinned signatures held), VERDICT command-exit 0 each. The rebuilt dist carries the new text (constraint with \pattern`, which is enforcedandtest an app-staged membership1 hit each inindex.js,index.cjs,runtime.js,runtime.cjs; the oldThe registered names are: ${` 0).packages/cliorpackages/metadata-protocoltest asserts these ids' hint text, so the declared rider went unused.@objectstack/metadata-protocolsuite, after: Test Files 226 passed, 3 skipped (229), Tests 28,171 passed, 19 skipped; VERDICT command-exit 0.9d56f0f431, throughscripts/ablation-replace.mjsunder the lock, with a shelltraprestoringHEADby absolute path). The rule suites import the rule source, so there is no dist leg.rls-predicate-unparseable's pre-slice line was restored:hint: UNPARSEABLE_FIX,→ the 523-character SQL-to-CEL hint as one literal (anchor x1 → x0, blob1e997b3fc7cc→371d8e008841). Predicted before the run: exactly the new bound pin goes red, and the oldercanonical CEL/&&pins stay green. Observed:src/validate-rls-predicate-enforceability.test.tsTests 1 failed, 132 passed (133), exactly that pin, which read 523. Restored: blob1e997b3fc7cc== HEAD,git diff HEADempty,git status --porcelainempty.packages/lint/src:pnpm --filter @objectstack/spec test:repoat9d56f0f431: Test Files 55 passed (55), Tests 971 passed (971); VERDICT command-exit 0. No new text carries anos migrate meta --fromsentence, and no tracker id is in a printed hint or explanation (citations stay in comments and test names).npx eslint --no-inline-config --format jsonover the 24 changed.tsfiles: 24 files in the report, 0 errors, 0 warnings. The population iseslint.config.mjs's**/*.{ts,…}block plus itspackages/**blocks; the config never enables type-aware linting (noparserOptions.project), so no untouched file's verdict can move. A control-character scan of every changed file found no match.origin/mainthroughscripts/pm/os-regen-merge.sh(0cc2194a2b→26fe94f3e1, onto9fdb12752c; no conflict, and the branch edits no generated artifact).node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackwith no paths at the final head9d56f0f431(25 paths vs the merge base) derived 62 commands; 60 ran, each exit code captured before any pipe, all 0 (longest:check:query-options-erasure348s,check:slot-lookup175s,check-comment-mask-corpus142s). NOT MEASURED, as dispatched:check:dual-build-cjs-loads(needs every package's dist) andcheck:type-check-debt(its script is--re-measure;check:type-check-coverageran).--ran:Run reconciliation — 62 derived, 60 run, 2 NOT-MEASURED, 0 UNRUN.The artifact-roster block (51 families): the 48 that need no pull request exited 0 at9d56f0f431,check:published-readme-exportsafter building its four missing dists (client-react,embedder-openai,knowledge-ragflow,organizations, 54 tasks) under the lock (its first answer was the exit-3 prerequisite refusal, not a verdict); the three PR-context guards run against this PR and report on the card.26fe94f3e1(the merge;9d56f0f431adds one changeset figure only); the CLI unit tier, the metadata-protocol suite,os validateand the runtime probe on the pre-merge head0cc2194a2b, whose hint text the merge did not touch (main brought no change to the ten rule files orrule-explanations.ts).Acceptance notes
action-name-undefinedat 195.rls-predicate-unknown-user-variableandrls-predicate-unparseablecarry no author text at all.fix:line. The card's "Asked for" names no list, and slice 11 made the same call forrls-predicate-unknown-field's field list.rule:lines gain theos explainpointer (object-reference-unknown,org-axis-permission-inheritance), through the new entries. That is the printer's own rule for an id the table holds, not a printer change.runtime-gate.test.ts(outside this slice's files) pins it.Remaining for this card
91 author-time
packages/lintids still carry a hint over 200 characters in the final lint census (at26fe94f3e1: 115 over 200 = 91 + 21 fenced + 3 repo-gate), by file, longest first:lint-flow-patterns.ts(2):flow-double-brace-interpolation1339,flow-bare-dollar-reference1231lint-flow-credential-literals.ts(1):flow-credential-literal646data-model-rules.ts(6):unique/legacy-organization-composite578,unique/unscoped-declared-index380,object/missing-name-field327,rollup/non-numeric-aggregand282,unique/double-declaration279,field/select-missing-options207validate-widget-bindings.ts(11):dashboard-filter-field-unprovisioned561,chart-field-unknown415,dashboard-filter-field-unknown403,chart-measures-missing369,widget-legacy-analytics-shape338,widget-measures-missing330,widget-filter-field-unknown322,widget-legacy-analytics-unrenderable320,table-count-only311,chart-dimensions-missing291,dashboard-filter-field-not-included218validate-readonly-flow-writes.ts(2):flow-update-readonly-when-field549,flow-update-readonly-field400validate-action-dispatch-contract.ts(1):action-dispatch-contract-mismatch514validate-security-posture.ts(5):security-controlled-by-parent-ambiguous-relation496,security-master-detail-ungranted314,security-controlled-by-parent-no-relation294,security-fls-unknown-field293,security-wildcard-vama218validate-sharing-rule-enforceability.ts(2):sharing-rule-object-not-shareable482,sharing-rule-object-controlled-by-parent395validate-page-visualization-bindings.ts(1):page/visualization-without-binding480validate-readonly-action-writes.ts(1):action-api-update-readonly-when-field470validate-flow-trigger-readiness.ts(5):flow-api-trigger-secret-missing461,flow-time-relative-descriptor-unroutable441,flow-trigger-unroutable295,flow-trigger-unknown-event268,flow-trigger-unknown-object210validate-searchable-fields.ts(3):searchable-field-unknown448,searchable-field-unprovisioned362,searchable-field-unsearchable328validate-flow-filter-tokens.ts(1):flow-filter-token-unknown427validate-action-locations.ts(1):action-no-placement424validate-mapping-target-fields.ts(1):mapping-target-field-unknown405validate-dashboard-widget-options.ts(1):unconsumed-widget-option396validate-sortable-fields.ts(3):sort-field-unprovisioned378,sort-field-unsortable332,sort-field-unknown301validate-visibility-predicates.ts(3):visibility-predicate-unknown-function375,visibility-bare-identifier221,visibility-predicate-syntax214validate-nav-access.ts(1):nav-object-ungranted370validate-hook-body-writes.ts(3):hook-body-write-unprovisioned-anchor365,hook-body-write-unknown-field275,hook-body-source-unparseable254validate-ai-agent-authoring.ts(2):agent-authoring-withdrawn363,default-agent-outside-roster237validate-react-page-props.ts(4):react-chart-field-unprovisioned362,react-prop-missing-required277,react-page-source-unparseable254,react-block-needs-record-context228validate-translatable-sections.ts(1):translation-section-name-missing359validate-action-body-writes.ts(4):action-body-write-unprovisioned-anchor358,action-body-write-unknown-field323,action-record-write-discarded309,action-body-source-unparseable254validate-flow-node-writes.ts(2):flow-node-write-unprovisioned-anchor358,flow-node-write-unknown-field289validate-managed-api-methods.ts(1):object/managed-api-method-unaffordable357validate-nav-object-servability.ts(1):nav-object-unservable348validate-rule-compilability.ts(2):validation-rule-json-schema-uncompilable341,validation-rule-regex-uncompilable300validate-dataset-references.ts(2):dataset-include-unknown336,dataset-field-unknown206validate-translation-references.ts(1):translation-target-unknown317validate-approval-approvers.ts(3):approval-approver-not-membership-tier313,approval-expression-no-empty-policy294,approval-expression-invalid292validate-seed-replay-safety.ts(1):seed-insert-mode-duplicates-on-replay309validate-chart-bindings.ts(1):chart-measure-unknown285validate-object-field-refs.ts(1):object-field-ref-unknown284validate-capability-references.ts(1):capability-reference-unknown273validate-record-title.ts(2):title-format-retired267,title-unresolvable237validate-list-view-field-refs.ts(2):list-view-field-unknown258,list-view-field-dotted233validate-view-containers.ts(1):view-container-shape256validate-seed-state-machine.ts(1):seed-value-outside-state-machine251validate-ai-surface-affinity.ts(1):ai-skill-surface-mismatch235validate-page-source-styling.ts(1):page-source-className-tailwind231lint-liveness-properties.ts(1):liveness-planned-property230validate-list-view-mode.ts(1):list-view-filters-in-views-mode219Not in the 91: the 26 fenced ids as PR #22448 lists them (21 fire a hint over 200), the 3 repo-gate ids (
startup-open-vocabulary-verdict,startup-source-unparseable,startup-verdict-assertive-wording), and thepackages/cliids on #22841.Generated by Claude Code