Repository navigation
fix(tooling): drop the derivation gate's export filter — rule 2 as a one-liner, rule 1 scoped - #7274
Merged
yinlianghui merged 2 commits intoSep 2, 2026
Conversation
…al declarations A spec-alignment claim is read by the next agent editing the FILE, not by an importer, so the `export` modifier was never what made it dangerous. The three module-local mirrors in `packages/react/src/spec-bridge/bridges/form-view.ts` (objectui#5652) had drifted on three keys and inverted one arm with this gate green throughout. Half 1 of the split ruled on objectui#6291, re-measured on this commit against `@objectstack/spec@17.2.0` rather than transcribed from PR #6284's census: rule 2 18 unbacked claims -> 19 (+1 module-local declaration) One, not the two measured at a76b18c — objectui#6285 fixed `CURATED_CAPABILITY_LABELS` in the interval by replacing its prose claim with a parity test. The one that remains, `CONTEXT_TOKEN_SUGGESTIONS`, is a real mirror and goes to the mechanically regenerated CLAIM_DEBT block, with a note recording why a shrink-only block may grow on a jurisdiction widening. The named pin "an unexported declaration — it publishes no surface to be mistaken for the spec" is rewritten, not deleted: it now asserts the inverse, on the same fixture, which turns out to re-export the declaration on the next line and so always did publish a surface. A second case beside it proves the precision rules — renderer skip, tie test, absent claim — are what keep module-local shapes green. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b
…tions, scoped Half 2 of the split ruled on objectui#6291, in the order the ruling set: the two structural narrowings first, then the filter drop, then a mechanically regenerated DEBT block, then the reasoned ALLOW entries. Re-measured on this commit against `@objectstack/spec@17.2.0` rather than transcribed from PR #6284's census: rule 1, filter dropped, NO narrowings 0 untriaged -> 25 (+25) rule 1, filter dropped, narrowings on 0 untriaged -> 19 (+19) 25, not the 29 at a76b18c — `ActionParam` twice (b84dc18 consolidated the disagreeing pair), `SelectOption`, and `EXPLAIN_BATCH_MAX_RECORD_IDS` (objectui#6286) left the population in the interval. The narrowings are `rendersJsx` and `isPureAlias`. `rendersJsx` is deliberately NOT rule 2's `isRendererLike`: rule 2 drops function and class declarations one line before it, rule 1 records every one of them, so reusing it verbatim would have silenced `isContextToken` and `normalizeFilterOperator` — both real mirrors, both classified as such by the census. It tests the judgement the header actually states, that a component RENDERS, by requiring JSX in the declaration. The remaining 19 split 4 / 15. Four different-concept collisions got reasoned ALLOW entries — `SearchResult`, `Dimension`, `ModelConfig`, `DashboardWidget`, each read at its site and, where the spec's symbol is a schema, probed with `safeParse` on this commit. Fifteen findings under fourteen names are real mirrors and were seeded into DEBT by `--ledger`, re-anchored on objectui#7265: the old anchor (objectstack#4115) is no longer open, and this card's own number cannot serve as one either, since the PR retires it. Two ALLOW entries were DELETED, which the ruling did not predict: `@object-ui/auth:AuthProvider` and `@object-ui/plugin-list:UserFilters` stopped matching anything once `rendersJsx` made their judgement structurally, and ratchet 3 requires deleting an entry that excuses nothing. Both deletions are documented in place with what each entry carried beyond the waiver. `scanFile` is exported so the narrowings carry a discrimination proof: one red per widening, one green per narrowing, and the RED near neighbour beside each — a non-rendering function is still a fork, and an alias that widens is still a fork. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b
yinlianghui
marked this pull request as ready for review
September 2, 2026 02:59
yinlianghui
deleted the
claude/issue-6291-derivation-export-filter-split
branch
September 2, 2026 03:14
This was referenced Sep 28, 2026
akarma-synetal
pushed a commit
to akarma-synetal/objectui
that referenced
this pull request
Oct 7, 2026
…ectstack-ai#6286 release note (objectui#9528) (objectstack-ai#10970) Fixes objectstack-ai#9528 Clause-②: no — release-note prose; no contract, accept set or public surface changes (a contract review is still owed: the diff is `.changeset` prose) ## What changes One sentence in the **pending** `.changeset/6286-explain-batch-cap-from-spec.md`. That body publishes verbatim into `@object-ui/plugin-grid`'s CHANGELOG at the next release, and the release PR objectui#5400 regenerates from `main`, so this only helps if it lands before that PR merges. The frontmatter is untouched: `check-changeset-overwrite.mjs` prints `declared at base: @object-ui/plugin-grid: patch` and `declares now: @object-ui/plugin-grid: patch`. Before: > … is exactly the drift `scripts/check-spec-symbol-derivation.mjs` argues about — and could not catch here, because both of its scanners skip non-exported declarations and this const was module-local (objectui#5899). After: > … is exactly the drift `scripts/check-spec-symbol-derivation.mjs` argues about — and could not catch here: when this change landed, both of its scanners skipped non-exported declarations, and this const was module-local (objectui#5899). objectui#6291 has since removed that filter from both scanners. ## Why this wording, and why the history stays The sentence was **true when written and went false later**. It is not a false sentence from the start. So the fix keeps the explanation, puts it in the past tense and dates it. Deleting it would lose true history. **1. True when the changeset landed.** `c38162d7c9` (objectstack-ai#6333, 2026-08-25) added the changeset. At that commit, both scanners in the gate open with the same filter line, once in `scanFileForClaims` (rule 2) and once in `scanFile` (rule 1): ``` if (!hasExportModifier(stmt)) continue; ``` The table below counts that line and two related markers in each revision of the gate file (`git show REV:scripts/check-spec-symbol-derivation.mjs | grep -c …`): | revision | `if (!hasExportModifier(stmt)) continue;` | `const hasExportModifier` | `// No export filter` | |---|---|---|---| | `c38162d7c9` (objectstack-ai#6333 lands) | 2 | 1 | 0 | | `9207c53e45^` | 2 | 1 | 0 | | `9207c53e45` (objectstack-ai#7274, objectui#6291) | 0 | 1 | 2 | | `b120b66077` (this PR's base) | 0 | 0 | 3 (two code comments plus one header mention of them) | **2. False since `9207c53e45`** (objectstack-ai#7274, objectui#6291, 2026-09-02). On the base, the two scanners now carry `// No export filter: a module-local declaration carrying a spec-alignment` in `scanFileForClaims` and `// No export filter (objectui#6291). A module-local declaration under a spec` in `scanFile`. The gate's own header says the same thing: "⛔ HISTORY, NOT BEHAVIOUR. Neither scanner has an export filter today." The order of the two commits was checked on a shallow checkout, so it needs a control leg: - `git merge-base --is-ancestor c38162d 9207c53` exits 0. - The reverse check exits 1. - Control leg: `git merge-base --is-ancestor 62311b6 c38162d` exits 0. `62311b6419` is the gate's first commit (2026-07-30), older than both. **3. Which rule would catch this const, then and now.** I measured this with a 2×2 probe, not read it off the header: - **Fixture A** is the pre-objectstack-ai#6333 hook source, `git show c38162d^:packages/plugin-grid/src/hooks/useRecordCrudVerdicts.ts`. In it, `const EXPLAIN_BATCH_MAX_RECORD_IDS = 200;` is module-local. - **Fixture B** is the same file with `export` added. It is the control. - Both fixtures were fed to the scanners of both gate versions, using today's spec export set (5085 names; `EXPLAIN_BATCH_MAX_RECORD_IDS` maps to `@objectstack/spec/security`). - The only change to the `c38162d7c9` copy was exporting its `scanFile`. The anchor count was checked on disk: 1 plain before and 0 after; 0 exported before and 1 after. | fixture | gate at `c38162d7c9`: rule 1 | rule 2 | gate at `b120b66077`: rule 1 | rule 2 | |---|---|---|---|---| | A — module-local (verbatim) | none | none | `const` finding | none | | B — `export` added (control) | `const` finding | none | `const` finding | none | What the probe shows: - **When objectstack-ai#6286 landed, the export filter is what hid the const from rule 1.** The control proves the old rule 1 flags the const as soon as it is exported. - **Today rule 1 (the name match) reports it.** `DEBT` is empty and no `ALLOW` key names it, so it would be a fresh finding and the gate would exit 1. - **Rule 2 reports it in no cell, and no filter is involved.** `findClaim` returns `null` on the const's doc comment. The comment names `@objectstack/spec@17.0.0-rc.6` but contains none of the `CLAIM_PATTERNS` phrases. - So for this const, the card is right that rule 1 is the operative rule. The claim note's point is also true: both scanners dropped the filter. But that matters for rule 2 only in general, not for this const. The new sentence therefore states only history: the filter existed when the change landed, and objectui#6291 removed it from both scanners. It asserts no live capability of the gate, so a later change to the gate cannot make it false the way the old sentence became false (AGENTS.md objectstack-ai#9). ## The other pending changesets that name the gate `git grep -l check-spec-symbol-derivation b120b66 -- .changeset` lists **seven** files. As a positive control, the same form of search for `plugin-grid` in the 6286 file counts 1. I widened the search to every spelling of the gate (`spec-symbol`, `check:spec-symbols`), which gives **17** files, and read all 17 in full. I also grepped every pending body for `non-exported|unexported|not exported|export filter|hasExportModifier|export modifier|exported only` and for `module-local`. **Only the 6286 file states the export-filter property.** The other 16 say nothing about it: - `7265-core-context-token-mirrors`, `7265-data-objectstack-filter-operator-rename`, `7265-components-sort-direction-bound`, `7265-plugin-detail-record-alert-renderer-props`, `spec-symbol-mirrors-app-shell-7265`, `7265-types-user-filter-field-derives`, `9596-debt-issue-anchor-truthiness`: these describe module-local mirrors that the rule-1 `DEBT` ledger carried, which fits today's behaviour. - `console-form-container-specs-one-declaration-5596`: says derivation is the gate's sanctioned form. - `listview-comment-pair-4559`: says rule 2 reads the *attached* comment block. - `9542-result-dialog-i18nlabel`: names the rule-2 failure class. - `3162-types-ledger-batch8-verdicts`, `spec-pin-17-1-0-5328`, `spec-refresh-17-2-0-5668`: ledger and pin history. - `ci-decide-markdown-trace-9241`: says the gate opens `content/docs/**`. - `8841-tree-view-config-derive` and `date-range-default-range-binding-4984`: explain a miss by **name matching** (and, in 4984, rule 2's tie test). That is a different property, which I did not re-measure here. ## Gates (all read at HEAD `25b8b6eeb2`, the only commit on this branch) | command | exit | verdict line | |---|---|---| | `pnpm check:changeset-claims` | 0 | `✅ No pending changeset names a file this change touches.`; self-contradiction: `Every package declared across those 1 body(ies) is either not negated in its own prose, …`; born-false: `Line addresses read in them: 0.` | | `node scripts/check-changeset-presence.mjs` | 0 | `✅ No source or published contract of a released package changed in this range, so no changeset is owed.` | | `node scripts/check-changeset-overwrite.mjs` | 0 (report-only) | `1 modified` — case 2, "CORRECTING a declaration on purpose … prose that no longer matches the change"; the declared package set is unchanged | | `node scripts/check-changeset-no-major.mjs` | 0 | ✅ No changeset declares a major bump. | | `node scripts/check-changeset-fixed.mjs` | 0 | `✅ All workspace packages are in the changeset fixed group.` | | `pnpm check:control-bytes` | 0 | `✅ check-control-bytes: OK (scanned 9240 tracked text file(s); skipped 85 binary).` | | `pnpm check:new-line-citations` | 0 | `VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0` | | `pnpm exec vitest run --maxWorkers=2` on the 24 `scripts/__tests__/*.test.ts` that mention `.changeset` (via `os-verify-lock.sh`) | 0 | `Test Files 24 passed (24)` / `Tests 914 passed (914)` / `VERDICT command-exit 0` | The 24-file set is a superset of what `node scripts/markdown-test-inputs.mjs --changed -` returns for this file. That helper records `.changeset/**` as the input of `check-changeset-no-major.test.ts`; the positive control is `packages/plugin-dashboard/README.md`, which it echoes back. No package source, gate or test is touched, so nothing else is owed. `node scripts/check-governed-queue-guard.mjs --test` on the file answers `✅ NOT GOVERNED`. ## Acceptance notes - `spec-symbol-mirrors-app-shell-7265` reads "held six declarations … Four are now bound … and three were renamed". That is 4 + 3 against six. Its commit (`14a1b92035`, objectstack-ai#9465) removes six app-shell names from `DEBT`, so one name may have held two declarations. **I did not measure this.** That changeset has empty frontmatter, so it publishes nothing. Nobody is carrying this; it is only noted here. - The 24-file test run printed one `fatal: Invalid symmetric difference expression 0000…` line on stderr while every test passed. The SHA in it is all zeros; `check-changeset-overwrite.test.ts` and `docs-build-trigger.test.ts` are the two files in the set that spell such a SHA. I did not trace it further. It is not a failure. ## Contract review A contract review is owed and the PM seat commissions it. Everything above is meant to be re-runnable: every quoted code string, commit and command reproduces on this repo. This PR touches no gate, adds no checker, and leaves the frontmatter and bump level unchanged. Session: `https://claude.ai/code/session_01EBx9rvB7dufCz4at53x35U` --- _Generated by [Claude Code](https://claude.ai/code/session_01EBx9rvB7dufCz4at53x35U)_ Co-authored-by: Claude <noreply@anthropic.com>
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 #6291
Ruling A (split), implemented in the order it sets: half 1 is rule 2's filter drop, half 2 is the two structural narrowings, then rule 1's filter drop, then a mechanically regenerated DEBT block, then the reasoned ALLOW entries. One branch, two commits, each independently green.
Every figure below is re-taken on
3612110ffagainst@objectstack/spec@17.2.0. PR #6284's census is the evidence base, not a list to transcribe — and it had moved.The population, re-taken
a76b18cf2)3612110ff)Four rule-1 sites left the population in the interval:
ActionParamtwice (b84dc18, "one authority for ActionSchema and the Breadcrumb pair", consolidated the pair that already disagreed with itself),SelectOption, andEXPLAIN_BATCH_MAX_RECORD_IDS— the one whose own comment said it existed only until the spec pin exported the constant (#6286). Rule 2's second site wasCURATED_CAPABILITY_LABELS; #6285 replaced its prose claim with a two-directional parity test, so the burn-down this rule exists to provoke took the site out of the population before this change could reach it.Two sites the census classified as real mirrors — the
FlowNode/FlowEdgepair inFlowNodeInspector.tsx— became pure aliases in the interval, so the narrowing retires them rather than the ledger carrying them.Where the 19 went
4 different-concept collisions → reasoned ALLOW entries. Each read at its site; where the spec's symbol is a schema, probed with
safeParseon this commit rather than judged by name.app-shell:SearchResultISearchService.search()resolves to —{hits, totalHits, processingTimeMs?, facets?}. This is one rendered result row{id, label, href, type, description?}, built from the navigation tree. The two share no key.app-shell:DimensionDimensionSchemais the semantic-layer cube dimension and REQUIRESsql. Probed: the local instance fails withinvalid_typeonsqlandunrecognized_keys: ["field","dateGranularity"]— the two keys carrying this shape's whole meaning are the two the spec rejects. The spec exports noDatasetSchemato bind against.app-shell:ModelConfigid,name,version,capabilities,limits), andmodel/temperature/maxTokensare not registry keys at all.app-shell:DashboardWidgetDashboardWidgetSchema & { id: string }, where@object-ui/types' interface is declaredextends Omit of Partial-of-SpecDashboardWidget(minus four re-typed keys). The intersection restoresidto required. Deliberately NOT covered byisPureAlias— an intersection that widens a spec shape is exactly what this map exists to make someone write a reason for.15 findings under 14 names → DEBT, regenerated by
--ledger, never hand-written.@object-ui/app-shell(AdminScope,AppLike,FlowEdge,FlowRuntimeState,ObjectLike×2 sites,RemoteTable),@object-ui/core(CONTEXT_TOKEN_SUGGESTIONS,isContextToken),@object-ui/types(UserFilterFieldSchema,UserFiltersSchema),@object-ui/components(SortDirection),@object-ui/data-objectstack(normalizeFilterOperator),@object-ui/plugin-detail(RecordAlertProps),@object-ui/plugin-tree(TreeConfig).Rule 2's one addition,
CONTEXT_TOKEN_SUGGESTIONS, went toCLAIM_DEBTthe same way.The DEBT anchor is a new issue, and that is deliberate
DEBT_ISSUEwas4115. That block had been empty since #3162 and objectstack#4115 was itself retired by objectstack#6883, so the gate's own stale-entry message — "delete them … (and close #N once the ledger is empty)" — pointed at an issue nobody can act on. #6291 could not serve either, being the card this PR retires. #7265 is the open burn-down anchor, with the seeded population and its provenance in the body.Noted there and not changed here:
CLAIM_DEBT_ISSUE = 4592has the same dead-anchor defect with a live 19-entry block. Rule 2's ledger is not what this card widened, so it is filed rather than ridden.The narrowings, and one deviation from the ruling's literal wording
The ruling says "extend
isRendererLiketo rule 1". Implemented as a new, narrower predicate,rendersJsx, and the reason is measured rather than stylistic.Rule 2 can afford
isRendererLikebecause it drops function and class declarations one line earlier (if (!nameNode) continue), so that predicate only ever judges aconstinitialised with a call or a function. Rule 1 records every function withderived: false. ReusingisRendererLikeverbatim would therefore skip every spec-named function in the tree — and measured, that is four declarations, not two: the two local ReactFieldcomponents the ruling names, plusisContextTokenandnormalizeFilterOperator, both classified real mirrors by the census, both DEBT entries today.normalizeFilterOperatoris a second normalizer over the spec's own, and two normalizers disagreeing about filter operators is the silent over-fetch class of objectstack#3948. A blanket "functions are renderers" would have made those two invisible instead of tracked — silently, and for good.So
rendersJsxtests the judgement the header actually states — "a component that RENDERS the spec's shape is not a second declaration of it" — literally: the declaration must contain JSX. A predicate returningbooleandoes not; a component returning a JSX element does. This retires exactly the sites the ruling predicted and no others.isPureAliasis the narrowest possible reading of the second narrowing: a bareTypeReferenceNode, one identifier, no type arguments, no qualified name. A generic referenceA of B, a union, andA & { … }are all still forks. It generalises the judgementscanFilealready makes for barrels — "whatever it points at gets judged at its own declaration site".Two ALLOW entries were DELETED — the one place this exceeded the ruling
@object-ui/auth:AuthProviderand@object-ui/plugin-list:UserFiltersstopped matching anything oncerendersJsxmade their judgement structurally, and ratchet 3 requires deleting an entry that excuses nothing (a stale entry reserves the name for a future fork under it). So the narrowing shrank the hand-written part of the map while the collisions grew it: 16 declared dialects → 18.Both deletions are documented in place with what each entry carried beyond the waiver —
auth-spec-parity.test.tsstill fails if the spec'sAuthProviderstops being an enum of provider ids, andAuthProviderConfigis still renamed rather than excused, because that one really does name the spec's OAuth registration shape.@object-ui/plugin-list:ListViewsurvived the same narrowing, and the asymmetry is documented rather than tidied: the finding it now matches is not the component but the bareexport { ListView, … }inpackages/plugin-list/src/index.tsx.scanFile's barrel skip fires only when the re-export carries a module specifier, so a bareexport { X }over a local import is recorded at the barrel. That hole predates this card; it is filed, not fixed here.The named pin was rewritten, not deleted
scripts/__tests__/check-spec-symbol-derivation.test.ts› "an unexported declaration — it publishes no surface to be mistaken for the spec" now asserts the inverse, on the same fixture — which makes the point better than a new one could, because that fixture re-exported the declaration on the very next line (export type { InternalNavigationConfig }) and so always did publish a surface.hasExportModifiernever saw it, because the export was a separate statement. The pin's own fixture contradicted the pin's own name.Beside it, the half the pin was really holding: rule 2 stays quiet on module-local shapes for its OWN reasons — renderer skip, tie test, absent claim — never because of an
exportkeyword.scanFileis now exported (asscanFileForClaimsalready was) so the narrowings carry a discrimination proof: one red per widening, one green per narrowing, and the red near neighbour beside each — a non-rendering function is still a fork, an alias that widens is still a fork. Those two are what keeprendersJsxfrom decaying intoisRendererLikeandisPureAliasinto "type aliases are exempt". 35 cases → 40.Ablation evidence
Each ablation ran against the committed implementation, with the mutation confirmed on disk by injected-marker count before the run, an
EXIT-trapped restore, and the restore proven by comparinggit hash-objectagainst the HEAD blob (not by a trap firing).rendersJsxskip removedField×2 (the retired false positives) plusAuthProviderandUserFilters— which is also the independent confirmation that the two deleted ALLOW entries are accounted for by the narrowing and nothing elseisPureAliasremovedFlowNodeatFlowNodeInspector.tsx:87andFlowPreview.tsx:57. The twoFlowEdgealiases stay green becauseFlowEdgeis already a DEBT-declared name for that package — the ledger absorbing them is correct behaviour, not a missMarker counts, exit codes and restore proofs:
on-disk injected-marker count: 1/1/2 (expect 2);RESTORE_OKafter each, withgit diff HEAD --name-onlyempty.Verification — all on
3612110ffnode scripts/check-spec-symbol-derivation.mjsbefore (67dadd602)✅ spec symbol derivation: 1333 files scanned against 4959 spec export names; 16 declared dialects, 0 untriaged collisions in 0 packages./✅ spec alignment claims: 2 declared deliberate copies, 18 unbacked claims in 5 packages.pnpm check:spec-symbolsafter✅ spec symbol derivation: 1333 files scanned against 4959 spec export names; 18 declared dialects, 14 untriaged collisions in 7 packages./✅ spec alignment claims: 2 declared deliberate copies, 19 unbacked claims in 5 packages.pnpm exec vitest run scripts/__tests__/check-spec-symbol-derivation.test.ts scripts/__tests__/check-doc-component-types.test.ts --maxWorkers=2Test Files 2 passed (2)/Tests 89 passed (89)— the second file is the only other suite inscripts/__tests__naming this scriptpnpm type-check:scriptstsc -p tsconfig.scripts.json, no diagnosticspnpm lint:root(unnarrowed)✖ 29 problems (0 errors, 29 warnings)— all pre-existing, none in either edited file (verified by name against the report)pnpm check:control-bytes✅ check-control-bytes: OK (scanned 5996 tracked text file(s); skipped 85 binary).grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'→ no hitspnpm check:entry-guard✓ check:entry-guard: 58 scripts/ file(s) — no entry guard outside the baseline; 0 file(s) still hand-type one …; 52 export bindings, 52 of them inert on import (0 known-unsafe, ⛔ SHRINK-ONLY).— the newscanFileexport is inert on importpnpm check:esm-specifiersSpecifier leg: no un-ledgered package emits an extensionless relative specifier.pnpm check:shell-escape-residue✅ check-shell-escape-residue: OK (4/4 root(s) resolved … 0 occurrence(s) outside a fence).pnpm check:self-import✅ No package names itself inside its own src/.pnpm check:node-esm-load@object-ui/example-byo-backend-console:build: cache hit … /home/user/objectui-issue-6606/…), and it then reported✗ @object-ui/console: no-build-output. This diff isscripts/-only — 2 files, 0 underpackages/— and that gate grades built package artifacts, which this change cannot reach. Filed separately; CI's clean checkout is the authority.Every exit code was captured by redirect before any pipe.
Changeset: none owed, on the presence gate's own verdict, not on my judgement:
There is no
skip-changesetlabel in this repo — confirmed by PR #6284 and not created here.Scope fence
Two files, both under
scripts/:check-spec-symbol-derivation.mjsandcheck-spec-symbol-derivation.test.ts. Zero package-source edits — none of the 14 mirror sites was fixed; they are ledger entries, per the ruling. #6286 and #6287 remain open on their own merits and are untouched by this branch.Heavy runs were serialised through the container-global lock at
/home/user/objectstack/scripts/pm/os-verify-lock.sh(objectui carries no copy), slotdev-6291.🤖 Generated with Claude Code
https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b
Generated by Claude Code