Skip to content

Commit d5ff0d2

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/project-thread-x004t9
2 parents 472a4e6 + 6746140 commit d5ff0d2

16 files changed

Lines changed: 1125 additions & 155 deletions
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
fix(app-shell): on a narrow window, a toast raised beside the record drawer no longer covers the record's Edit and ⋯ buttons
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
When a right-edge drawer is open and the window is too narrow for a toast beside it (a 720px record drawer on a 1024px window, a split screen, a phone), the console's toaster drops below the drawer's header. It cleared only the drawer's own header, so the success toast raised by creating a record sat on the record header's Edit button and ⋯ menu for its whole four seconds. The toast now also drops below the drawer's first row of controls, measured from the drawer's layout, so it clears the record's actions row for any drawer content. Wide windows keep the toast in the strip beside the drawer, as before.
11+
12+
What to do: nothing.

‎scripts/check-skills-token-ratchet.mjs‎

Lines changed: 82 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,27 @@ export const CEILINGS = new Map([
431431
// decision tables at 487 lines.
432432
// 5833 -> 5828: A2′ — the release-stamp line left the count (see
433433
// STAMP_LINE_REPIN); the file's count fell by the same 5, headroom unchanged.
434-
['skills/objectstack-platform/SKILL.md', 5828],
434+
// 5828 -> 5981 (card #26302, the objectstack-platform row of the skills gap
435+
// audit): the Seed Data section gains `demoStaff` against `devLogins` — a
436+
// seed deals records to people and cannot create one, so the people are
437+
// declared in `demoStaff` and `os dev` creates the accounts (position and
438+
// permission sets from the stack's own declarations, the seed password, never
439+
// in the built artifact), while `devLogins` is banner text that creates and
440+
// grants nothing. Maintainer ruling 2026-10-27 on the seat's decision card
441+
// 「skills 修复卡的教学和 eval 都撞 token 天花板,怎么付?」, his tap verbatim
442+
// and untranslated: 「A:先削重复,余额按实测提高」. Paid down first, as the
443+
// ruling asks — four restatements cut, each with a surviving home in the
444+
// file: the `defineStack()` intro (the opening paragraph and the project
445+
// tree say it), the "read the source for the exact shape" paragraph (the
446+
// References section keeps the rule; one pointer line stays), the boot
447+
// sequence's "(see Ports & networking)" aside and the two cheat-sheet port
448+
// comments (the Port resolution paragraph says both). Arithmetic in bytes:
449+
// on `origin/main` the priced text was 23294 bytes (5824 tokens, headroom 4);
450+
// the cuts remove 309 bytes and the section adds 939, so the LANDED priced
451+
// text is 23924 bytes -> 5981 tokens: the 4 tokens of headroom are absorbed
452+
// and the ceiling moves 5828 -> 5981 (+153). Pinned AT the measurement.
453+
// ceil(($(wc -c < skills/objectstack-platform/SKILL.md) - 20) / 4) == ceil(23924 / 4)
454+
['skills/objectstack-platform/SKILL.md', 5981],
435455
// `skills/objectstack-pm-dispatch/SKILL.md` (9708) and its
436456
// `rules/dev-template.md` (1838) left this table on 2026-09-10 with the files:
437457
// the maintainer deleted the published PM skill whole (verbatim:
@@ -541,7 +561,14 @@ export const CEILINGS = new Map([
541561
// 3778 -> 3676: RE-LOCK at the landed count (#19715, card item 4). A 5-line
542562
// table of contents (+154 tokens) landed inside the row's 256 tokens of
543563
// headroom, so no raise; pinned AT the measurement — zero headroom.
544-
['skills/objectstack-data/rules/relationships.md', 3676],
564+
// 3676 -> 3873 (#26297): `sharing.controlledByParent.ownerMayEdit` — the
565+
// owner of a controlled_by_parent detail row may update it by id with read
566+
// access to the master; what it does not widen; refused off a detail and
567+
// one level up — which the file did not teach beside `controlled_by_parent`.
568+
// +201 tokens on a landed 3672, 4 absorbed by headroom, ceiling +197. No
569+
// repeated passage to cut first (measured: no sentence repeats). Maintainer ruling 2026-10-27 on the decision card 「skills 修复卡的教学和 eval 都撞 token 天
570+
// 花板,怎么付?」, tap A, verbatim and untranslated: 「A:先削重复,余额按实测提高」.
571+
['skills/objectstack-data/rules/relationships.md', 3873],
545572
// NEW FILE (#14296 item 1 = A, condition (b)): the entry's Security & Access
546573
// Control block moved here whole. Pinned at its landed count — no headroom,
547574
// because a split that arrives with budget is a raise wearing a new path.
@@ -571,7 +598,18 @@ export const CEILINGS = new Map([
571598
// first (measured: no sentence repeats in the file). Maintainer ruling
572599
// 2026-10-27 on the decision card 「skills 修复卡的教学和 eval 都撞 token 天
573600
// 花板,怎么付?」, tap A, verbatim and untranslated: 「A:先削重复,余额按实测提高」.
574-
['skills/objectstack-data/rules/security.md', 2956],
601+
// 2956 -> 3693 (#26297): membership keys (`membershipKeys` on the roster
602+
// object — the three members, the refusals, the once-per-request system
603+
// read that fails closed, and the choice rule against owner scoping, a
604+
// position and a sharing rule), the position → `permissionSets` binding
605+
// (a namesake set is reported, never granted) and the `external`
606+
// membership tier for portal users (no baseline, explicit grants only) —
607+
// none of which the file taught, so an author wrote per-row policies and
608+
// expected a position-named set to grant itself. +737 tokens on a landed
609+
// 2956 at headroom 0, ceiling +737. No repeated passage in the file to
610+
// cut first (measured: no sentence repeats). Maintainer ruling 2026-10-27 on the decision card 「skills 修复卡的教学和 eval 都撞 token 天
611+
// 花板,怎么付?」, tap A, verbatim and untranslated: 「A:先削重复,余额按实测提高」.
612+
['skills/objectstack-data/rules/security.md', 3693],
575613
// 3024 -> 3109 (2026-08-31 app-repo-principles raise, see the block above).
576614
// Severity Levels listed the three values and left the CHOICE unstated: a
577615
// block rests on a judgement a person made, so a machine-inferred signal — a
@@ -726,8 +764,22 @@ export const CEILINGS = new Map([
726764
// ceiling +201; nothing duplicated in the file to cut first. Same ruling as
727765
// the `rules/security.md` row above (2026-10-27, tap A:
728766
// 「A:先削重复,余额按实测提高」).
729-
['skills/objectstack-data/evals/hooks-security-seeds-datasources.json', 1095],
730-
['skills/objectstack-data/evals/objects-fields-relationships.json', 946],
767+
// 1095 -> 1404 (#26297): one regression case for the portal membership key
768+
// (a portal user reads only the rows of the accounts they belong to —
769+
// expected: `membershipKeys` on the roster object, `current_user.KEY` in the
770+
// policy, the set bound through a position's `permissionSets`, the
771+
// `external` tier), and the seed case gains the job-owned column declared
772+
// `applyOn: 'create'`. +309 tokens at headroom 0, ceiling +309; nothing
773+
// duplicated in the file to cut first. Maintainer ruling 2026-10-27 on the decision card 「skills 修复卡的教学和 eval 都撞 token 天
774+
// 花板,怎么付?」, tap A, verbatim and untranslated: 「A:先削重复,余额按实测提高」.
775+
['skills/objectstack-data/evals/hooks-security-seeds-datasources.json', 1404],
776+
// 946 -> 1050 (#26297): the invoice-line case gains the owner opt-in
777+
// (`ownerMayEdit` on the controlled_by_parent line) and pins `added_by` as
778+
// `type: 'user'`, never a lookup to a `user` object. +104 tokens at
779+
// headroom 0, ceiling +104; nothing duplicated in the file to cut first.
780+
// Maintainer ruling 2026-10-27 on the decision card 「skills 修复卡的教学和 eval 都撞 token 天
781+
// 花板,怎么付?」, tap A, verbatim and untranslated: 「A:先削重复,余额按实测提高」.
782+
['skills/objectstack-data/evals/objects-fields-relationships.json', 1050],
731783
['skills/objectstack-formula/evals/cel-predicates-formulas.json', 1046],
732784
// 1004 -> 1451 (2026-10-27, the objectstack-i18n fix card of the skills gap
733785
// audit): two eval prompts for the teaching that card adds — the `reports`,
@@ -740,7 +792,17 @@ export const CEILINGS = new Map([
740792
// is the whole addition; pinned AT the measurement, zero headroom. The
741793
// raising PR's body carries the same arithmetic.
742794
['skills/objectstack-i18n/evals/bundles-locales-coverage.json', 1451],
743-
['skills/objectstack-platform/evals/config-plugins-ops.json', 1211],
795+
// 1211 -> 1458 (card #26302): one eval for a demo whose seed names people —
796+
// expected: both in `demoStaff` with a declared `position` /
797+
// `permissionSets`, created by `os dev`; NO `role:` alias and NO platform
798+
// set such as `admin_full_access`. Same ruling as the `SKILL.md` row above
799+
// (2026-10-27, tap A: 「A:先削重复,余额按实测提高」); the file's six fixtures
800+
// share no sentence, so there was no duplicate to cut (0 bytes). On
801+
// `origin/main` the file was 4842 bytes (1211 tokens, headroom 0); the
802+
// fixture adds +989 bytes, so the LANDED file is 5831 bytes -> 1458 tokens,
803+
// ceiling +247, pinned AT the measurement.
804+
// ceil($(wc -c < skills/objectstack-platform/evals/config-plugins-ops.json) / 4) == ceil(5831 / 4)
805+
['skills/objectstack-platform/evals/config-plugins-ops.json', 1458],
744806
['skills/objectstack-query/evals/filters-pagination-search.json', 955],
745807
// 1505 -> 1789 (#26295): two eval prompts — list grouping with `orderBy`, and the copy hole
746808
// + `onSuccess` pair — +284 tokens in the file's shape; fixtures, nothing to delete, the
@@ -769,9 +831,21 @@ export const CEILINGS = new Map([
769831
// absorbed by headroom, ceiling +18. Same maintainer ruling as the SKILL.md
770832
// row above (2026-10-27, verbatim and untranslated): 「A:先削重复,余额按实测提高」.
771833
['skills/objectstack-automation/references/state-machines-and-approvals.md', 5587],
772-
['skills/objectstack-data/references/examples-objects.md', 1779],
834+
// 1779 -> 1769 (#26297): RE-LOCK at the landed count after a net cut — two
835+
// stale `{ type: 'lookup', reference: 'user' }` fields (an object that does
836+
// not exist) became `type: 'user'`; -10 tokens, the row follows the
837+
// measurement down, zero headroom.
838+
['skills/objectstack-data/references/examples-objects.md', 1769],
773839
['skills/objectstack-data/references/lint-rules.md', 970],
774-
['skills/objectstack-data/references/seeds.md', 1299],
840+
// 1299 -> 1566 (#26297): the `columns` dataset key and `applyOn: 'create'`
841+
// — a column a job or an admin owns after the first load is written on
842+
// create and left alone on every `upsert` replay; which modes it touches,
843+
// the refused key, the cross-link to the import door's `applyOn` — which
844+
// the option table lacked, so a replay reverted the app's own writes. +267
845+
// tokens at headroom 0, ceiling +267. No repeated passage to cut first
846+
// (measured: no sentence repeats). Maintainer ruling 2026-10-27 on the decision card 「skills 修复卡的教学和 eval 都撞 token 天
847+
// 花板,怎么付?」, tap A, verbatim and untranslated: 「A:先削重复,余额按实测提高」.
848+
['skills/objectstack-data/references/seeds.md', 1566],
775849
['skills/objectstack-platform/references/bootstrap.md', 1351],
776850
['skills/objectstack-platform/references/operations.md', 3125],
777851
['skills/objectstack-platform/references/plugin-development.md', 3137],

‎scripts/pm/dispatch-gates.data.mjs‎

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,9 +900,52 @@ export const ESCAPABLE_LITERAL_LEDGER_ROWS = Object.freeze([
900900
* already has. ⛔ Nor does either gate happening to go quiet: three of the
901901
* five measured instances involved a green that proved nothing, because a
902902
* sweep that cannot see your file is not evidence about your file.
903+
* - ui-scripts-suite entry: when a workflow runs the `ui/scripts/__tests__`
904+
* suite as a step of its own, under an invocation the discovery reads, the
905+
* row can name that family instead of standing in for a CI job — and when
906+
* the `Test UI` job stops running the suite at all, the binding goes STALE
907+
* by itself. ⛔ A path predicate that narrows the four roots to the files
908+
* each test "really" reads does NOT qualify: that map is a second thing
909+
* that goes stale, and the run is cheap enough not to need one (measured
910+
* below).
903911
*
904912
*
905913
* Delete an entry the day its criterion is met, not before.
914+
*
915+
* ## Why the ui-scripts-suite entry stands in for a CI JOB (#26318)
916+
*
917+
* The 180 test files under `ui/scripts/__tests__/` (178 that run, 2 skipped)
918+
* belong to no package and run
919+
* only inside the 16 `Test UI` shards, as the "always-on" files the affected-test
920+
* selector adds to every run because no package owns them. They pin facts a
921+
* change under ui package source, the Console app, the objectui skill bundle or
922+
* `ui/scripts` itself moves — turbo build inputs, the skill-examples floor, the
923+
* SchemaRenderer channel keys — and no derived family named them: measured on
924+
* PR #26274's head 1ef5c482, three reds there were that PR's own and had passed
925+
* every derived local gate.
926+
*
927+
* Every other gate in this table is a family the workflows run, resolved by
928+
* name. This one cannot be: the only step that runs the suite is the `Test UI`
929+
* job's vitest line, which carries a shard and the selector's filter list, and
930+
* no workflow spells a narrower invocation. So its gate declares the job and the
931+
* runner prefix it narrows (`ciJob`, `ciRunner`), and the engine's
932+
* `ciJobRunsRunner` resolves it against the live workflows the same way a family
933+
* is resolved: a job renamed or a runner respelled renders it STALE, and the
934+
* census guard in the self-test reds on the PR that does it.
935+
*
936+
* It names the WHOLE suite, never an affected subset: a subset map is a second
937+
* list that rots. Measured at 6390fe52 on a 4-vCPU container, after the seven
938+
* @objectstack packages the job builds: 178 files passing in 284 s and 286 s
939+
* (two runs; the card's "about a minute" was read elsewhere), nearly all of it
940+
* module import — so a subset would save minutes, not a CI round trip, and the
941+
* reach it would have to model is the tree itself: by a static scan of each
942+
* file and the helpers it imports, 165 of the 180 read ui package source, 141
943+
* the ui apps, 16 the objectui skill bundle and 170 ui/scripts. What it does not see is
944+
* stated rather than hidden: a ui path outside the four roots (a ui package's
945+
* tests outside `src`, its `package.json`, a root config) is not named here,
946+
* though CI's `Test UI` job still schedules the suite for it — the full battery
947+
* on `main` remains the backstop for that, as it is for the selector's own
948+
* misses.
906949
*/
907950
export const CHANGE_KIND_ROWS = [
908951
{
@@ -1013,8 +1056,37 @@ export const CHANGE_KIND_ROWS = [
10131056
},
10141057
],
10151058
},
1059+
{
1060+
kind: 'edits a file the ui/scripts/__tests__ suite reads (ui package source, the ui apps, the objectui skill bundle, or ui/scripts itself)',
1061+
matches: 'ui-scripts-suite-input',
1062+
gates: [
1063+
{
1064+
name: 'pnpm --dir ui exec vitest run scripts/',
1065+
ciJob: 'Test UI',
1066+
ciRunner: 'pnpm --dir ui exec vitest run',
1067+
why: "the 178 test files under ui/scripts/__tests__ belong to no package and run only in CI's 16 Test UI shards, where the affected-test selector adds them to every run, so no package suite and no check family covers them: they pin turbo build inputs, the skill-examples floor, the SchemaRenderer channel keys and the other facts a change under ui package source, the ui apps, skills/objectui or ui/scripts moves. The whole suite, never a subset: measured at about five minutes on a 4-vCPU container (284 s and 286 s, 178 files passing, import-bound), against the CI round trip of about 25 minutes it saves. It needs the seven @objectstack packages Test UI builds first, or about twenty files red on an import of a missing dist — build them exactly as the job does: pnpm exec turbo run build --filter=@objectstack/spec... --filter=@objectstack/client... --filter=@objectstack/core... --filter=@objectstack/formula... --filter=@objectstack/lint... --filter=@objectstack/sdui-parser... --filter=@objectstack/types... . Positional filter, no bare `--`, from the repo root: ui/scripts/vitest-invocation-guard.mjs refuses every other spelling",
1068+
},
1069+
],
1070+
},
10161071
];
10171072

1073+
/**
1074+
* The roots whose change the `ui/scripts/__tests__` suite can see (#26318), in CI's own `paths:` language
1075+
* — the engine matches them with `triggerListCovers`, the reader of every workflow trigger. They are the
1076+
* card's four, as written there: ui package SOURCE (any depth below `ui/packages`, so a nested package
1077+
* counts), the ui apps, the objectui skill bundle the suite reads through `ui/scripts/skill-bundle-root.mjs`,
1078+
* and the suite's own tree. The bare `src` directory form is listed beside its subtree because a dispatch
1079+
* surface is often given as that directory, and the trigger language reads a directory only through a
1080+
* pattern's literal prefix.
1081+
*/
1082+
export const UI_SCRIPTS_SUITE_ROOTS = Object.freeze([
1083+
'ui/packages/**/src',
1084+
'ui/packages/**/src/**',
1085+
'ui/apps/**',
1086+
'skills/objectui/**',
1087+
'ui/scripts/**',
1088+
]);
1089+
10181090
/**
10191091
* The globs that MANDATE a model tier for any card whose file surface touches
10201092
* them, as DATA. This is the one list in this file besides CHANGE_KIND_GATES,

0 commit comments

Comments
 (0)