Repository navigation
The locked @objectstack/spec@17.0.0 does not carry the spec keys already merged upstream — GanttConfigSchema.viewMode (#5074) is the first card measurably stalled on it #5328
Description
Activity
os-support-ai commented
on Aug 19, 2026 CollaboratorAuthorMore actionsSecond dependant found, independently, within the hour: #5042. PM round 17.
ListMapConfigSchemalanded on objectstackmainvia objectstack#9370 (2026-08-17, MERGED) — after the17.0.0GA cut — so a consumer pinned to^17.0.0cannot see it, exactly as withGanttConfigSchema.viewMode(#5074). #5042 is nowpm:blockedbehind this card.That makes the pattern worth stating plainly, because it is the reason this card exists rather than a note on one issue:
merged upstream ≠ published ≠ pinned here. Three distinct states.
Blocked-by: <objectstack card>closing only proves the first.#5042's own history is the cautionary version: it was probed on 2026-08-18 08:06Z and stopped ("the pin is
rc.2, which predates the landing"), then the pin moved to GA17.0.0— and it still failed, for the second of the three states. A card that reads "the pin moved past the blocker" is not the same statement as "the published build carries the key".Running list of dependants
card key it needs upstream landing #5074 GanttConfigSchema.viewModeobjectstack#9463 / PR#9489 ( 870f710e7)#5042 ListMapConfigSchemaobjectstack#9370 #5057, #5126 — chained behind #5074 Both keys are in the same unreleased changeset backlog, so one release discharges both. Any further objectui card needing a post-GA spec key belongs here too — ⛔ and none of them should be worked around by declaring the key objectui-side only, which would publish a key the save gate refuses.
Generated by Claude Code
os-support-ai commented
on Aug 19, 2026 CollaboratorAuthorMore actionsThird instance, and this one is a different shape — worth recording because it shows the gap is not only about missing keys. PM round 17, found while implementing #5216 (PR5354).
The first two dependants need a key that is merged-but-unpublished. This one needed nothing:
ObjectNavItemSchema.runActionmerged pre-GA and is present in the pinned17.0.0(measured, counter-probed —runActiontrue,recordIdtrue,objectNametrue,zzNotAKeyfalse, all through the same import, so the true is a reading rather than a wrong-path artefact).What is missing from the pin is a refinement, not a key. The card #5216 was written against describes a parse-level exclusivity —
runActioncannot be combined withrecordId— and the installed17.0.0accepts both together. ThesuperRefinethat enforces it does exist on objectstackmain(packages/spec/src/ui/app.zod.ts, message"runAction cannot be combined with recordId"), so this is the same merged-but-unpublished state, arriving through a rule rather than a field.Nothing filed as a defect, correctly — it is this card, not a new one.
Why the distinction matters for whoever unblocks this
A missing key announces itself: the consumer cannot compile, or
safeParserejects, and the dev stops. A missing refinement does not — the pinned schema accepts the input and the consumer proceeds, so the gap is only visible if someone thinks to check that a documented constraint is enforced by the pin rather than assuming it. #5216's dev checked, and the consequence was concrete: it made that PR's list-surface-only precedence load-bearing rather than defensive, because the schema will not refuse the combination for it.So the running rule gets a clause: merged upstream ≠ published ≠ pinned here applies to refinements and error messages as well as to fields, and the refinement case fails silent.
Running list of dependants
card what it needs upstream landing shape #5074 GanttConfigSchema.viewModeobjectstack#9463 / PR#9489 missing key #5042 ListMapConfigSchemaobjectstack#9370 missing key #5216 (landed anyway) the runAction×recordIdexclusivity refinementon main, unreleasedmissing refinement — fails silent #5057, #5126 — — chained behind #5074 #5216 is not blocked by this — its key is in the pin and its PR compensates in the consumer — so it is listed for the record, not as a dependant. One release still discharges all of it.
Generated by Claude Code
os-support-ai commented
on Aug 21, 2026 CollaboratorAuthorMore actionsRestart-when:has fired — releasing this card from holdUnlock scan by the spec@objectui seat (
session_01BisYvhR7yZ7ggXAwthTZH5), 2026-08-21T05:0xZ. Measured against this card's own criterion, not by inference from the upstream card's state.@objectstack/spec@17.1.0is published and is npmlatest.^17.0.0resolves to it. The release that this card said was the covering event has happened.The card's own check, run
Installed the published
17.1.0in a scratch dir and ran the body's criterion verbatim:reading value GanttConfigSchemapresenttrueviewModeonGanttConfigSchematrue← theRestart-when:criterionListMapConfigSchemapresent (#5042)trueCounter-probe on the same import, because a bare
trueis not a reading:resourceView→true(known-present),zzNotAKey→false(known-absent). Both behave, so the path is right and thetrueis genuine.A third dependant discharged by the same release
element:filteris absent from the publishedPageComponentType(34 members), counter-probed:element:formtrue,element:texttrue,zzNotATypefalse. That retirement (objectstack#9220 / PR#9250) shipped on the 17.x line exactly as its tombstone said it would — "v17.0.0 was cut before this landed, so the tombstones ship on the 17.x line". So objectui#4935 unblocks on this same bump, and its staleBlocked-by: objectstack#9220is the misleading half — noted on that card.Release discipline, both checks
- Most-recent-condition check. The operative condition is the
Restart-when:in this card's body. The two later comments add dependants; neither states a new or narrower condition. Released against the body's line only — no earlier blocker on the thread was used. - Newer-merged-PR check. This card has no linked PRs (
closed_by_pull_requests: 0), so nothing indicates the card moved on after the hold was written. No refusal trigger.
State change
pm:on-hold→pm:queue.pm:blockingstays — the dependants below are still open, so this card is still gating them until the bump lands.What this card now is
Dispatchable work, and it is a pin bump, which is never a rider: a dedicated lockfile refresh moving
@objectstack/specfrom lockfile-exact17.0.0to17.1.0(thepackage.jsoncaret^17.0.0already admits it and needs no edit), with whatever green-keeping adaptations the newly-arrived keys and theelement:filterenum removal force. Measured onorigin/maintoday: the lockfile is still exact17.0.0.⛔ Unchanged: this card still does not authorise anyone to publish a release. It no longer needs to — the release already happened.
Dependants, all discharged by the one bump
card what it needs now in 17.1.0 #5074 GanttConfigSchema.viewMode✅ measured #5042 ListMapConfigSchema✅ measured #4935 element:filtergone fromPageComponentType✅ measured #5057, #5126 chained behind #5074 ✅ transitively ⛔ None of them should be returned to the queue until the bump has actually landed — merged upstream ≠ published ≠ pinned here, and only the third state has changed today.
Generated by Claude Code
- Most-recent-condition check. The operative condition is the
os-support-ai commented
on Aug 21, 2026 CollaboratorAuthorMore actionsClaim: PM loop round 1
Session:session_01BisYvhR7yZ7ggXAwthTZH5
Branch:claude/issue-5328-spec-pin-17-1-0
Worktree:objectui-issue-5328
Domain:domain:spec(objectui spec stream — see routing note below)
File surface:package.json,pnpm-lock.yaml, and the minimum green-keeping adaptations the newly-resolved versions force (stop on breach; explain in the report)
Container & model:M,mode:subagent,model: opus
Clause-②: no
Serial constraints cleared: #4958 (dependabotmotion12.43.0→13.1.0, open since 08-17, touchespnpm-lock.yaml— the one direct same-file collision; not merged, so this branch takes main as-is and the merge queue arbitrates whichever lands second); #5400 (changeset-release/mainVersion Packages PR, updated 06:30Z — one minute before this claim; it rewrites packageversionfields and CHANGELOGs, and is maintainer-merge-only, so ⛔ do not merge, rebase onto, or otherwise touch it); in-flight dev cards #5469 #5454 #5452 #5451 #5439 #5416 #5367 read for overlap — none declares the root manifest or lockfile, closest is #5439 (per-package typings/build config), no intersection with this surfaceRouting note — authority for this claim
objectui carries no
domain:*label objects yet (blocked on #5491), so this card could not be routed by label. Claimed under the maintainer's direct-dispatch channel, instruction quoted verbatim:spec 面的卡你自己判着认领
and, on the target version:
objectstack 应该升级到 17.1
Read as the
@objectstack/specpin going to 17.1 — this card. If a different repo was meant, say so and this claim is withdrawn.This card is spec-face by the stream definition itself, which names "
@objectstack/specpin coupling" as the objectuidomain:specsurface. Thedomain:speclabel is not applied — producingdomain:*remains the triage seat's, and this claim does not pre-empt it.Why this is dispatchable now
The
Restart-when:fired and was measured against this card's own criterion earlier today (see the release comment above). Restating only the delta the dev acts on:package locked on origin/mainpublished latestcaret @objectstack/spec17.0.017.1.0^17.0.0@objectstack/client17.0.017.1.0^17.0.0@objectstack/formula17.0.017.1.0^17.0.0@objectstack/lint17.0.017.1.0^17.0.0All four carets already admit 17.1.0, so no manifest edit is needed — this is a lockfile refresh. All four move in lockstep: a split resolution is what produced the dual-version spec graph that reddened
check:spec-symbolsin this repo's history.Clause-② reasoning, stated rather than asserted
no, on both limbs. Path limb: the diff touches no contract source —packages/spec/src/**lives in objectstack, not here. Content limb: this card adopts a contract that upstream already authored, reviewed and published; it does not change one. The accept-set movement it causes (element:filterrefused,viewMode/ListMapConfigSchemaaccepted) is downstream adaptation, which the tiering rule puts atopusby default.⛔ Stop-and-report trigger: if keeping green turns out to require changing objectui's own declared contract surface — a public schema in
packages/types, a published Zod shape, anything that widens or narrows what this repo accepts beyond mechanically following the new pin — that is a Clause-② event. Stop, do not push it, report it. It becomes a separate card at contract-review tier.Tier derivation
node scripts/pm/dispatch-gates.mjs --tier package.json pnpm-lock.yaml, run at dispatch time, returns no path-derived mandate ("floor sonnet · default opus · ceiling fable", and that Clause ② is judged from card content, not paths). Set atopusas the default judgment tier: the pin move is mechanical but the green-keeping fallout is not.
Generated by Claude Code
os-support-ai commented
on Aug 21, 2026 CollaboratorAuthorMore actions{ "issue": 5328, "status": "needs_decision", "branch": "claude/issue-5328-spec-pin-17-1-0", "pr": "https://github.com/objectstack-ai/objectui/pull/5529", "premise_still_valid": true, "summary": "The pin bump is implemented, merged with main, pushed, and green on everything except one gate I deliberately did not touch. All four @objectstack/* packages move 17.0.0 -> 17.1.0 by lockfile refresh alone; no manifest edit was required, confirming the PM assumption (all 38 declarations across 33 packages are ^17.0.0, one distinct range each). Green-keeping fallout was larger than the card anticipated: eleven failures across five gates/suites, all counter-probed against origin/main to confirm they are bump fallout and not pre-existing. Eight were mechanical and are fixed here; three are capability-wiring or contract calls and are recorded in each gate's own ratcheted ledger with cards filed (#5493, #5494, #5495). The blocker is check:eager-closure: the closure grows 129,692 gzipped bytes and lands 41,689 over MAX_EAGER_CLOSURE_GZIP_BYTES. I did not raise the ceiling because objectui#5468 was ruled by the maintainer TODAY (closed 05:21Z, outcome recorded in #5490) as option A, 'the absolute aggregate ceiling stays as shipped', and that card states 'Gate-strength policy is the maintainer's. No seat should pick this.' Raising it is also not one line: the headroom invariant is an expect() that would force rewriting the hardcoded BASELINE in the gate's own test, dismantling the assertion #5468 cites as the ceiling's guarantee. This regression (126.7 KiB) is larger than the 89 KiB incident the gate was built to catch, so the gate is working as designed.", "tests": "All run on merged HEAD 97c1162af (branch after `git merge origin/main`), each exit code captured before any pipe (redirect-then-capture), verdicts quoted from the tool's own output rather than a bare $?. BUILD: `pnpm build` -> turbo 'Tasks: 43 successful, 43 total'. TYPE-CHECK: `pnpm type-check` -> 'Tasks: 81 successful, 81 total'. LINT: `pnpm lint` -> 'Tasks: 47 successful, 47 total' (turbo run lint over every package - the full farm, so no narrowing claim is needed). TESTS: `pnpm test` in four shards, run from the repo root per AGENTS.md (never `pnpm --filter <pkg> test`, which is trap #1): shard1 441 files/5598 passed/1 skipped; shard2 441/6004; shard3 440/5668; shard4 440/5163 - union 1,762 files, 22,433 passed, 1 skipped, 0 failed. GATES, all PASS: check:spec-symbols ('spec symbol derivation: 1282 files scanned against 4966 spec export names; 13 declared dialects, 4 untriaged collisions in 2 packages'), check:action-forward-parity ('5 surfaces checked against 40 runtime-read keys from 4 consumers; 19 justified omissions, 11 known gaps'), check:phantom-deps, check:self-import, check:control-bytes, check:published-dist, check:node-esm-load, check:esm-specifiers, check:doc-types, check:doc-snippets, check:i18n-keys, check:i18n-drift, check:i18n-dead-keys, check:skills-paths, lint:coverage, type-check:coverage, quick-reference:check, changeset:check, check-changeset-presence ('8 source file(s) of 6 released package(s) changed, and this change declares 1 changeset(s)'). GATE FAIL (deliberate): check:eager-closure - 'Console eager closure is 3907.9 KB gzipped across 52 chunks - 40.7 KB over the 3867.2 KB budget'. BASELINE METHOD: every failure was classified by building a second worktree at origin/main 2524e7450 with the 17.0.0 lockfile and running the same gate there - check:spec-symbols, check:action-forward-parity and check:eager-closure all exit 0 on that tree and non-zero here, so each is bump fallout, not pre-existing. Spec surface probed before and after with paired counter-probes (a bare true is not a reading): viewMode false->true, ListMapConfigSchema false->true, element:filter true->false, with resourceView/element:form/element:text true (known-present) and zzNotAKey/zzNotAType false (known-absent) on both pins. No ablation was performed; none was called for.", "open_questions": [ { "question": "check:eager-closure is 41,689 gzipped bytes over MAX_EAGER_CLOSURE_GZIP_BYTES because @objectstack/spec 17.1.0 adds 129,692 bytes to the console's eager closure (essentially all of it in the vendor-objectstack chunk, 1493.3 KB -> 1619.5 KB). The mandated 17.1 upgrade cannot land green without resolving this. How should it be resolved?", "options": [ "A - Re-baseline the ceiling deliberately: raise MAX_EAGER_CLOSURE_GZIP_BYTES and rewrite the hardcoded BASELINE in scripts/__tests__/check-eager-closure-budget.test.ts so the headroom invariant (MAX - BASELINE < 91,136) still holds. Accepts +126.7 KiB on every console page load. NOTE this is the move #5468's ruling declined and that #5490 is queued to make harder by adding a per-chunk budget on vendor-objectstack specifically.", "B - Land a cleave first (#5325 / #5359) and let this PR follow, keeping the ceiling untouched. Costs the five dependant cards (#5074, #5042, #4935, #5057, #5126) more waiting, since they all unblock only when this pin lands.", "C - Rule that a dependency-mandated increase is a distinct case from the gate-strength question #5468 answered, and authorise the re-baseline as a one-off with the per-chunk budget from #5490 landing alongside it to keep the chunk visible." ], "recommendation": "No recommendation - this is outside a dev seat by the ruling's own words. objectui#5468 states 'Gate-strength policy is the maintainer's. No seat should pick this', and #5490 records the maintainer's answer to it as 'the absolute aggregate ceiling stays as shipped (PR #5466)', closed 2026-08-21T05:21Z, roughly an hour before this card was dispatched. I measured the fork fully and stopped there. The measurements needed to decide are in the PR body and above; what I can add is that the two constraints interact - option A cannot be done without also weakening the test assertion that #5468 cited as the ceiling's guarantee, so it is a larger act than 'bump a constant'." } ], "out_of_scope_findings": [ "filed as #5493: onSuccess is authorable as of spec 17.1.0 and honoured by ActionRunner.ts:1197, but all four declared action surfaces (action:button/icon/group/menu) drop it before the runner - an author's declared follow-up silently does not run. Recorded as KNOWN_GAPS in scripts/check-action-forward-parity.mjs rather than forwarded, because forwarding is capability wiring, the same class as #5074/#5042 which this card defers to its dependants.", "filed as #5494: spec 17.1.0 started exporting ReferenceRailEntry, colliding with objectui's local interface of the same name. The shapes disagree on icon, which the spec's $strict schema refuses while packages/plugin-detail's renderer reads it - the preview-works/save-refuses trap this very card was filed about, as a real instance. Recorded in the DEBT ledger of scripts/check-spec-symbol-derivation.mjs; resolving it decides icon's fate and is a contract call.", "filed as #5495 (label: finding): the page-editor palette offers the LEGACY record:chatter and, after this PR, explicitly excludes the canonical record:discussion - the pair is advertised under the alias. Flipping which one is offered changes what authors drag, so it is a decision, not a pin edit.", "NOT filed, reported here as a measurement worth keeping: PageComponentType has 34 members both before and after 17.1.0. element:filter left as record:discussion arrived, so any member-COUNT assertion is blind to this release. The PM assumption's '34 members now' is true of 17.1.0 but is not a distinguishing reading - on 17.0.0 it is also 34, with element:filter present." ], "gates": { "build": "pass", "type-check": "pass", "lint": "pass", "test (4 shards, union)": "pass", "check:spec-symbols": "pass (was FAIL on the bump; fixed via DEBT ledger)", "check:action-forward-parity": "pass (was FAIL on the bump; fixed via KNOWN_GAPS ledger)", "check:phantom-deps": "pass", "check:self-import": "pass", "check:control-bytes": "pass", "check:published-dist": "pass", "check:node-esm-load": "pass", "check:esm-specifiers": "pass", "check:doc-types": "pass", "check:doc-snippets": "pass", "check:i18n-keys": "pass", "check:i18n-drift": "pass", "check:i18n-dead-keys": "pass", "check:skills-paths": "pass", "lint:coverage": "pass", "type-check:coverage": "pass", "quick-reference:check": "pass", "changeset:check": "pass", "check-changeset-presence": "pass", "check:eager-closure": "FAIL - deliberate, see open_questions; 4,001,689 B vs ceiling 3,960,000 B", "added_beyond_the_dispatched_list": [ "check:self-import", "check:control-bytes", "check:doc-types", "check:doc-snippets", "check:i18n-keys", "check:i18n-drift", "check:i18n-dead-keys", "check:skills-paths", "lint:coverage", "type-check:coverage", "quick-reference:check", "changeset:check", "check-changeset-presence", "type-check (the dispatched list omitted it; objectui spells it type-check with a hyphen, and it caught a real compile error in plugin-view)" ] }, "line_budget": { "files_changed": 13, "insertions": 316, "deletions": 97, "net": 219, "note": "pnpm-lock.yaml accounts for 79 insertions / 66 deletions of that. No skills/** file is touched, so the published-skills line-budget clause does not apply." }, "deviations": [ "The dispatched gate list omitted `pnpm type-check`. I ran it anyway (objectui spells it `type-check`, hyphenated) and it found a real compile error - packages/plugin-view's CANONICAL_TO_BUILDER is keyed by ViewFilterOperator, so the new icontains member was TS2741, not a silent gap. Reported as an addition rather than treated as licence.", "The card and claim comment scoped the file surface to 'package.json, pnpm-lock.yaml, and the minimum green-keeping adaptations the newly-resolved versions force'. The adaptations turned out to touch 11 files beyond the lockfile and changeset. Each is named in the PR body with the gate or test that demanded it; none was a drive-by. package.json itself is NOT in the diff - pnpm update rewrote all 31 manifests to ^17.1.0 by default and I reverted that, since the card ruled the caret needs no edit.", "I did NOT raise MAX_EAGER_CLOSURE_GZIP_BYTES even though it is the gate's own documented remedy for intended growth, and even though the card authorises 'the minimum needed to keep CI green'. Reason in open_questions: a maintainer ruling closed roughly an hour before dispatch says that ceiling stays as shipped and that no seat should pick gate-strength policy. Flagging it explicitly because it is the one place I declined an action the dispatch arguably permitted.", "Three cards were filed (#5493, #5494, #5495). The dispatch expected out-of-scope findings to be filed unassigned, which they are; #5495 carries the `finding` label as an observation, the other two carry none and are left for PM triage." ], "files_changed": [ "pnpm-lock.yaml", ".changeset/spec-pin-17-1-0-5328.md", "scripts/check-spec-symbol-derivation.mjs", "scripts/check-action-forward-parity.mjs", "packages/app-shell/src/views/metadata-admin/previews/block-types.ts", "packages/data-objectstack/src/index.ts", "packages/plugin-view/src/config/view-config-utils.ts", "packages/plugin-list/src/ListView.tsx", "packages/plugin-list/src/__tests__/filter-operator-ast-parity.test.ts", "packages/plugin-list/src/__tests__/UserFilters.tabPresetOperators.test.tsx", "packages/core/src/actions/actionKeys.ts", "packages/test-support/src/__tests__/spec-tombstones.test.ts", "apps/console/src/__tests__/registry-inputs-spec-parity.test.ts" ], "resolved_versions": { "@objectstack/spec": "17.0.0 -> 17.1.0", "@objectstack/client": "17.0.0 -> 17.1.0", "@objectstack/formula": "17.0.0 -> 17.1.0", "@objectstack/lint": "17.0.0 -> 17.1.0", "transitive_lockstep": "@objectstack/core 17.0.0 -> 17.1.0, @objectstack/sdui-parser 17.0.0 -> 17.1.0 (both pulled by the four; moving with them is what keeps the graph single-version)", "unrelated_transitive": "@mongodb-js/saslprep 1.4.13 -> 1.5.0, re-resolved inside its own caret by the refresh", "dual_version_check": "grep -c '@objectstack/[a-z-]*@17\\.0\\.0' pnpm-lock.yaml == 0, so no dual-version spec graph", "manifest_edit_required": false, "manifest_evidence": "38 declarations of the four across 33 package.json files, every one ^17.0.0 (one distinct range per package name), no pnpm catalog, and no @objectstack/* entry in pnpm.overrides. ^17.0.0 admits 17.1.0, so only the lockfile moved. The lockfile's importers still record specifier ^17.0.0 with version 17.1.0.", "in_flight_collision": "PR #4958 (dependabot motion 12.43.0 -> 13.1.0) was NOT absorbed - `git diff -U0 -- pnpm-lock.yaml | grep -i motion` is empty, so the branch point is correct." }, "element_filter_removal": { "reddened_anything": true, "where": [ "packages/app-shell/.../previews/__tests__/block-config.test.ts - 'every exclusion names a real spec type and carries a reason' failed: PALETTE_EXCLUSIONS['element:filter'] is a stale exclusion now that the type has left PageComponentType.", "packages/test-support/src/__tests__/spec-tombstones.test.ts - two failures. 17.1.0 retires element:filter WHOLLY: it leaves PageComponentType while its props schema stays in ComponentPropsMap with every key tombstoned, so authorableShapeKeys is 0. The judge assumed a tombstoned block always retains at least one authorable key, and it also took its control key from found[0], which sorts to element:filter." ], "what_i_did": [ "Deleted the PALETTE_EXCLUSIONS['element:filter'] entry in packages/app-shell/src/views/metadata-admin/previews/block-types.ts.", "In the tombstone judge's test: the 'not narrowed to nothing' floor now applies only to types PageComponentType still offers (a wholly retired block legitimately reads zero), and the control key is searched for across candidates instead of taken from found[0]." ], "overlaps_4935": "YES, partially, and precisely one of #4935's two halves. #4935 covers (a) the PALETTE_EXCLUSIONS['element:filter'] entry in block-types.ts and (b) a stale comment at packages/components/src/renderers/basic/elements.tsx:18. This PR does (a) - it had to, because block-config.test.ts fails without it. It does NOT touch (b): elements.tsx:18 is untouched, per the dispatch instruction, since that half is bound up with the separate open question about element:form. The tombstone-judge change is a THIRD element:filter location that #4935 does not mention and that only appears once the pin actually moves. #4935 should be re-scoped to (b) plus whatever else survives, not closed by this PR - which is why the PR body says 'Fixes #5328' and names #4935 without any closing keyword." } }
Generated by Claude Code
os-support-ai commented
on Aug 21, 2026 CollaboratorAuthorMore actionsos-dev-report
⚠️ Marker note for the PM scan: the previous comment is the same report, but its HTML-comment marker was eaten by GitHub's body sanitizer on write (the documented short-angle-bracket-fragment strip — it does not survive even inside backticks). This comment repeats the report with the marker as literal text so the scan can find it. Angle-bracket fragments in the prose have been rewritten for the same reason. This comment is the authoritative copy.{ "issue": 5328, "status": "needs_decision", "branch": "claude/issue-5328-spec-pin-17-1-0", "pr": "https://github.com/objectstack-ai/objectui/pull/5529", "premise_still_valid": true, "summary": "The pin bump is implemented, merged with main, pushed, and green on everything except one gate I deliberately did not touch. All four @objectstack/* packages move 17.0.0 to 17.1.0 by lockfile refresh alone; no manifest edit was required, confirming the PM assumption (all 38 declarations across 33 packages are ^17.0.0, one distinct range each). Green-keeping fallout was larger than the card anticipated: eleven failures across five gates/suites, all counter-probed against origin/main to confirm they are bump fallout and not pre-existing. Eight were mechanical and are fixed here; three are capability-wiring or contract calls and are recorded in each gate's own ratcheted ledger with cards filed (#5493, #5494, #5495). The blocker is check:eager-closure: the closure grows 129,692 gzipped bytes and lands 41,689 over MAX_EAGER_CLOSURE_GZIP_BYTES. I did not raise the ceiling because objectui#5468 was ruled by the maintainer TODAY (closed 05:21Z, outcome recorded in #5490) as option A, 'the absolute aggregate ceiling stays as shipped', and that card states 'Gate-strength policy is the maintainer's. No seat should pick this.' Raising it is also not one line: the headroom invariant is an expect() that would force rewriting the hardcoded BASELINE in the gate's own test, dismantling the assertion #5468 cites as the ceiling's guarantee. This regression (126.7 KiB) is larger than the 89 KiB incident the gate was built to catch, so the gate is working as designed.", "tests": "All run on merged HEAD 97c1162af (branch after `git merge origin/main`), each exit code captured before any pipe (redirect-then-capture), verdicts quoted from the tool's own output rather than a bare dollar-question. BUILD: `pnpm build` gives turbo 'Tasks: 43 successful, 43 total'. TYPE-CHECK: `pnpm type-check` gives 'Tasks: 81 successful, 81 total'. LINT: `pnpm lint` gives 'Tasks: 47 successful, 47 total' (turbo run lint over every package - the full farm, so no narrowing claim is needed). TESTS: `pnpm test` in four shards, run from the repo root per AGENTS.md (never the per-package filter form, which is that file's trap #1): shard1 441 files/5598 passed/1 skipped; shard2 441/6004; shard3 440/5668; shard4 440/5163 - union 1,762 files, 22,433 passed, 1 skipped, 0 failed. GATES, all PASS: check:spec-symbols ('spec symbol derivation: 1282 files scanned against 4966 spec export names; 13 declared dialects, 4 untriaged collisions in 2 packages'), check:action-forward-parity ('5 surfaces checked against 40 runtime-read keys from 4 consumers; 19 justified omissions, 11 known gaps'), check:phantom-deps, check:self-import, check:control-bytes, check:published-dist, check:node-esm-load, check:esm-specifiers, check:doc-types, check:doc-snippets, check:i18n-keys, check:i18n-drift, check:i18n-dead-keys, check:skills-paths, lint:coverage, type-check:coverage, quick-reference:check, changeset:check, check-changeset-presence ('8 source file(s) of 6 released package(s) changed, and this change declares 1 changeset(s)'). GATE FAIL (deliberate): check:eager-closure - 'Console eager closure is 3907.9 KB gzipped across 52 chunks - 40.7 KB over the 3867.2 KB budget'. BASELINE METHOD: every failure was classified by building a second worktree at origin/main 2524e7450 with the 17.0.0 lockfile and running the same gate there - check:spec-symbols, check:action-forward-parity and check:eager-closure all exit 0 on that tree and non-zero here, so each is bump fallout, not pre-existing. Spec surface probed before and after with paired counter-probes (a bare true is not a reading): viewMode false to true, ListMapConfigSchema false to true, element:filter true to false, with resourceView/element:form/element:text true (known-present) and zzNotAKey/zzNotAType false (known-absent) on both pins. No ablation was performed; none was called for.", "open_questions": [ { "question": "check:eager-closure is 41,689 gzipped bytes over MAX_EAGER_CLOSURE_GZIP_BYTES because @objectstack/spec 17.1.0 adds 129,692 bytes to the console's eager closure (essentially all of it in the vendor-objectstack chunk, 1493.3 KB to 1619.5 KB). The mandated 17.1 upgrade cannot land green without resolving this. How should it be resolved?", "options": [ "A - Re-baseline the ceiling deliberately: raise MAX_EAGER_CLOSURE_GZIP_BYTES and rewrite the hardcoded BASELINE in scripts/__tests__/check-eager-closure-budget.test.ts so the headroom invariant (MAX minus BASELINE stays under 91,136) still holds. Accepts +126.7 KiB on every console page load. NOTE this is the move #5468's ruling declined, and #5490 is queued to make it harder by adding a per-chunk budget on vendor-objectstack specifically.", "B - Land a cleave first (#5325 / #5359) and let this PR follow, keeping the ceiling untouched. Costs the five dependant cards (#5074, #5042, #4935, #5057, #5126) more waiting, since they all unblock only when this pin lands.", "C - Rule that a dependency-mandated increase is a distinct case from the gate-strength question #5468 answered, and authorise the re-baseline as a one-off with the per-chunk budget from #5490 landing alongside it to keep the chunk visible." ], "recommendation": "No recommendation - this is outside a dev seat by the ruling's own words. objectui#5468 states 'Gate-strength policy is the maintainer's. No seat should pick this', and #5490 records the maintainer's answer to it as 'the absolute aggregate ceiling stays as shipped (PR #5466)', closed 2026-08-21T05:21Z, roughly an hour before this card was dispatched. I measured the fork fully and stopped there. The measurements needed to decide are in the PR body and above; what I can add is that the two constraints interact - option A cannot be done without also weakening the test assertion that #5468 cited as the ceiling's guarantee, so it is a larger act than 'bump a constant'." } ], "out_of_scope_findings": [ "filed as #5493: onSuccess is authorable as of spec 17.1.0 and honoured by ActionRunner.ts:1197, but all four declared action surfaces (action:button/icon/group/menu) drop it before the runner - an author's declared follow-up silently does not run. Recorded as KNOWN_GAPS in scripts/check-action-forward-parity.mjs rather than forwarded, because forwarding is capability wiring, the same class as #5074/#5042 which this card defers to its dependants.", "filed as #5494: spec 17.1.0 started exporting ReferenceRailEntry, colliding with objectui's local interface of the same name. The shapes disagree on icon, which the spec's strict schema refuses while packages/plugin-detail's renderer reads it - the preview-works/save-refuses trap this very card was filed about, as a real instance. Recorded in the DEBT ledger of scripts/check-spec-symbol-derivation.mjs; resolving it decides icon's fate and is a contract call.", "filed as #5495 (label: finding): the page-editor palette offers the LEGACY record:chatter and, after this PR, explicitly excludes the canonical record:discussion - the pair is advertised under the alias. Flipping which one is offered changes what authors drag, so it is a decision, not a pin edit.", "NOT filed, reported here as a measurement worth keeping: PageComponentType has 34 members both before and after 17.1.0. element:filter left as record:discussion arrived, so any member-COUNT assertion is blind to this release. The PM assumption's '34 members now' is true of 17.1.0 but is not a distinguishing reading - on 17.0.0 it is also 34, with element:filter present." ], "gates": { "build": "pass", "type-check": "pass", "lint": "pass", "test (4 shards, union)": "pass", "check:spec-symbols": "pass (was FAIL on the bump; fixed via DEBT ledger)", "check:action-forward-parity": "pass (was FAIL on the bump; fixed via KNOWN_GAPS ledger)", "check:phantom-deps": "pass", "check:self-import": "pass", "check:control-bytes": "pass", "check:published-dist": "pass", "check:node-esm-load": "pass", "check:esm-specifiers": "pass", "check:doc-types": "pass", "check:doc-snippets": "pass", "check:i18n-keys": "pass", "check:i18n-drift": "pass", "check:i18n-dead-keys": "pass", "check:skills-paths": "pass", "lint:coverage": "pass", "type-check:coverage": "pass", "quick-reference:check": "pass", "changeset:check": "pass", "check-changeset-presence": "pass", "check:eager-closure": "FAIL - deliberate, see open_questions; 4,001,689 B vs ceiling 3,960,000 B", "added_beyond_the_dispatched_list": [ "check:self-import", "check:control-bytes", "check:doc-types", "check:doc-snippets", "check:i18n-keys", "check:i18n-drift", "check:i18n-dead-keys", "check:skills-paths", "lint:coverage", "type-check:coverage", "quick-reference:check", "changeset:check", "check-changeset-presence", "type-check (the dispatched list omitted it; objectui spells it type-check with a hyphen, and it caught a real compile error in plugin-view)" ] }, "line_budget": { "files_changed": 13, "insertions": 316, "deletions": 97, "net": 219, "note": "pnpm-lock.yaml accounts for 79 insertions / 66 deletions of that. No file under skills/ is touched, so the published-skills line-budget clause does not apply." }, "deviations": [ "The dispatched gate list omitted `pnpm type-check`. I ran it anyway (objectui spells it `type-check`, hyphenated) and it found a real compile error - packages/plugin-view's CANONICAL_TO_BUILDER is keyed by ViewFilterOperator, so the new icontains member was TS2741, not a silent gap. Reported as an addition rather than treated as licence.", "The card and claim comment scoped the file surface to 'package.json, pnpm-lock.yaml, and the minimum green-keeping adaptations the newly-resolved versions force'. The adaptations turned out to touch 11 files beyond the lockfile and changeset. Each is named in the PR body with the gate or test that demanded it; none was a drive-by. package.json itself is NOT in the diff - pnpm update rewrote all 31 manifests to ^17.1.0 by default and I reverted that, since the card ruled the caret needs no edit.", "I did NOT raise MAX_EAGER_CLOSURE_GZIP_BYTES even though it is the gate's own documented remedy for intended growth, and even though the card authorises 'the minimum needed to keep CI green'. Reason in open_questions: a maintainer ruling closed roughly an hour before dispatch says that ceiling stays as shipped and that no seat should pick gate-strength policy. Flagging it explicitly because it is the one place I declined an action the dispatch arguably permitted.", "Three cards were filed (#5493, #5494, #5495). The dispatch expected out-of-scope findings to be filed unassigned, which they are; #5495 carries the `finding` label as an observation, the other two carry none and are left for PM triage.", "This report is posted twice. The first copy lost its HTML-comment marker to the body sanitizer; this copy uses a literal-text marker and is authoritative." ], "files_changed": [ "pnpm-lock.yaml", ".changeset/spec-pin-17-1-0-5328.md", "scripts/check-spec-symbol-derivation.mjs", "scripts/check-action-forward-parity.mjs", "packages/app-shell/src/views/metadata-admin/previews/block-types.ts", "packages/data-objectstack/src/index.ts", "packages/plugin-view/src/config/view-config-utils.ts", "packages/plugin-list/src/ListView.tsx", "packages/plugin-list/src/__tests__/filter-operator-ast-parity.test.ts", "packages/plugin-list/src/__tests__/UserFilters.tabPresetOperators.test.tsx", "packages/core/src/actions/actionKeys.ts", "packages/test-support/src/__tests__/spec-tombstones.test.ts", "apps/console/src/__tests__/registry-inputs-spec-parity.test.ts" ], "resolved_versions": { "@objectstack/spec": "17.0.0 to 17.1.0", "@objectstack/client": "17.0.0 to 17.1.0", "@objectstack/formula": "17.0.0 to 17.1.0", "@objectstack/lint": "17.0.0 to 17.1.0", "transitive_lockstep": "@objectstack/core 17.0.0 to 17.1.0, @objectstack/sdui-parser 17.0.0 to 17.1.0 (both pulled by the four; moving with them is what keeps the graph single-version)", "unrelated_transitive": "@mongodb-js/saslprep 1.4.13 to 1.5.0, re-resolved inside its own caret by the refresh", "dual_version_check": "counting occurrences of the 17.0.0-pinned objectstack identity in pnpm-lock.yaml gives 0, so no dual-version spec graph", "manifest_edit_required": false, "manifest_evidence": "38 declarations of the four across 33 package.json files, every one ^17.0.0 (one distinct range per package name), no pnpm catalog, and no @objectstack entry in pnpm.overrides. ^17.0.0 admits 17.1.0, so only the lockfile moved. The lockfile's importers still record specifier ^17.0.0 with version 17.1.0.", "in_flight_collision": "PR #4958 (dependabot motion 12.43.0 to 13.1.0) was NOT absorbed - grepping the lockfile diff for motion returns nothing, so the branch point is correct." }, "element_filter_removal": { "reddened_anything": true, "where": [ "packages/app-shell previews __tests__/block-config.test.ts - 'every exclusion names a real spec type and carries a reason' failed: the element:filter entry in PALETTE_EXCLUSIONS is a stale exclusion now that the type has left PageComponentType.", "packages/test-support/src/__tests__/spec-tombstones.test.ts - two failures. 17.1.0 retires element:filter WHOLLY: it leaves PageComponentType while its props schema stays in ComponentPropsMap with every key tombstoned, so authorableShapeKeys is 0. The judge assumed a tombstoned block always retains at least one authorable key, and it also took its control key from the first sorted entry, which is element:filter." ], "what_i_did": [ "Deleted the element:filter entry from PALETTE_EXCLUSIONS in packages/app-shell/src/views/metadata-admin/previews/block-types.ts.", "In the tombstone judge's test: the 'not narrowed to nothing' floor now applies only to types PageComponentType still offers (a wholly retired block legitimately reads zero), and the control key is searched for across candidates instead of taken from the first sorted entry." ], "overlaps_4935": "YES, partially, and precisely one of #4935's two halves. #4935 covers (a) the element:filter entry in PALETTE_EXCLUSIONS in block-types.ts and (b) a stale comment at packages/components/src/renderers/basic/elements.tsx line 18. This PR does (a) - it had to, because block-config.test.ts fails without it. It does NOT touch (b): elements.tsx line 18 is untouched, per the dispatch instruction, since that half is bound up with the separate open question about element:form. The tombstone-judge change is a THIRD element:filter location that #4935 does not mention and that only appears once the pin actually moves. #4935 should be re-scoped to (b) plus whatever else survives, not closed by this PR - which is why the PR body says 'Fixes #5328' and names #4935 without any closing keyword." } }
Generated by Claude Code
- added a commit that references this issue
on Aug 22, 2026 os-support-ai commented
on Aug 22, 2026 CollaboratorAuthorMore actionsos-dev-report
(Marker as literal text: the HTML-comment form was eaten by GitHub's body sanitizer on the first round of this card, so it is not used here. Patch round 2 — this supersedes the earlier report comments on this card.)
{ "issue": 5328, "status": "done", "branch": "claude/issue-5328-spec-pin-17-1-0", "pr": "https://github.com/objectstack-ai/objectui/pull/5529", "premise_still_valid": true, "summary": "Patch round implementing the maintainer's option-A ruling on #5531: the eager-closure ceiling is raised permanently, together with the BASELINE it is derived from, in one commit. That was the only thing blocking this card, so the status moves from needs_decision to done. I merged current origin/main first (62 commits had landed since the last round; clean merge), rebuilt, and re-measured the closure on this branch rather than reusing the earlier 4,001,689 figure - main's own commits had taken it up 4,222 bytes to 4,005,911. MAX goes 3,960,000 to 4,086,000 and BASELINE.gzipBytes 3,881,609 to 4,005,911, leaving headroom of 80,089 (2.00%), which is under the 91,136 limit with 11,047 to spare. REGRESSION_THIS_GATE_MUST_CATCH_BYTES is untouched. check:eager-closure now passes and all 19 gates are green; the four-shard test union is 23,010 passed, 0 failed.", "tests": "All on HEAD 4ad75fdfe, exit codes captured before any pipe (redirect-then-capture); verdicts quoted from each tool's own output. BUILD `pnpm build` -> turbo 'Tasks: 43 successful, 43 total'. TYPE-CHECK `pnpm type-check` -> 'Tasks: 81 successful, 81 total'. LINT `pnpm lint` -> 'Tasks: 47 successful, 47 total' (full farm). TESTS `pnpm test` four shards from repo root: 455/5758+1skip, 455/6062, 455/5929, 454/5261 - union 1,819 files, 23,010 passed, 1 skipped, 0 failed. GATE UNIT TEST scripts/__tests__/check-eager-closure-budget.test.ts: 27 passed, and the two load-bearing ones confirmed BY NAME in verbose output - 'the ceiling itself > passes on the measured baseline, with headroom' and 'the ceiling itself > would have failed on the regression it exists to catch'. ALL 19 check:* GATES PASS including check:eager-closure. CONSTRAINT CHECK, computed from the exported constants rather than asserted in prose: MAX 4,086,000 minus BASELINE 4,005,911 = 80,089 headroom (2.00% of baseline); 80,089 < 91,136 SATISFIED, margin 11,047; MAX > BASELINE SATISFIED; and the substantive property - an 89 KiB repeat of #5266 measured from the NEW baseline lands at 4,097,047, which is still over the 4,086,000 ceiling, so the gate is exactly as sensitive as before.", "eager_closure_ceiling_move": { "ruling": "objectui#5531, maintainer verbatim 'A' - raise the ceiling permanently together with the headroom assertion that guards it", "measured_on_ref": "4c1623c0c (this branch after `git merge origin/main`; committed as 4ad75fdfe, and nothing between the two touches console bundle inputs)", "fresh_measurement": { "eagerGzipBytes": 4005911, "eagerChunkCount": 52, "totalChunkCount": 508, "eagerRawBytes": 13761755, "note": "NOT the 4,001,689 from the previous round. main advanced 62 commits in between and carried the closure up 4,222 bytes of its own, which is exactly why the PM said to re-measure rather than copy." }, "MAX_EAGER_CLOSURE_GZIP_BYTES": { "old": 3960000, "new": 4086000 }, "BASELINE_gzipBytes": { "old": 3881609, "new": 4005911 }, "BASELINE_other_fields": { "old": { "chunks": 58, "totalChunks": 507, "commit": "77f846a8b" }, "new": { "chunks": 52, "totalChunks": 508, "commit": "4c1623c0c" } }, "headroom_MAX_minus_BASELINE": 80089, "headroom_as_percent_of_baseline": "2.00%", "constraint_limit_REGRESSION_THIS_GATE_MUST_CATCH_BYTES": 91136, "constraint_comparison": "80,089 < 91,136 -> SATISFIED, margin 11,047", "regression_sensitivity_preserved": "an 89 KiB regression from the new baseline lands at 4,097,047 > MAX 4,086,000, so a repeat of #5266 still fails the gate", "REGRESSION_THIS_GATE_MUST_CATCH_BYTES_changed": false, "verdict_line_before": "❌ Console eager closure is 3912.0 KB gzipped across 52 chunks — 44.8 KB over the 3867.2 KB budget.", "verdict_line_after": "✅ Console eager closure is 3912.0 KB gzipped across 52 of 508 chunks (budget: 3990.2 KB, headroom: 78.2 KB).", "header_prose_updated": "Yes - the ceiling section now carries 4,005,911 / 80,089 / 2.00% and the '80,089 < 91,136' arithmetic, plus a new section recording why the number moved once and that the sensitivity constant did not. The `77f846a8b` table near the top is KEPT and explicitly relabelled as the motivating measurement rather than the current reading, so it no longer reads as a stale claim about today." }, "open_questions": [], "out_of_scope_findings": [ "filed as #5493 (earlier round, unchanged): onSuccess is authorable as of spec 17.1.0 and honoured by ActionRunner.ts:1197, but all four declared action surfaces drop it before the runner. Recorded as KNOWN_GAPS; forwarding it is capability wiring.", "filed as #5494 (earlier round, unchanged): spec 17.1.0 exports ReferenceRailEntry, colliding with objectui's local interface; the shapes disagree on icon, which the spec's strict schema refuses while the renderer reads it. Recorded in the DEBT ledger.", "filed as #5495 (earlier round, unchanged, label: finding): the palette offers the legacy record:chatter and now explicitly excludes the canonical record:discussion.", "NOT filed, reported as an operational note: the ceiling is an ABSOLUTE number pinned to a measurement taken on 4c1623c0c, and main moved 1 further commit while the union run was in progress. 80,089 bytes of headroom absorbs ordinary drift, but this class of ceiling goes red on any future release-sized jump regardless of who causes it - which is the known trade-off #5490's per-chunk budgets and #5325/#5359's cleave are queued to address. No action requested." ], "gates": { "build": "pass", "type-check": "pass", "lint": "pass", "test (4 shards, union)": "pass", "check:eager-closure": "pass (was FAIL last round; resolved by this ruling)", "check-eager-closure-budget.test.ts (the gate's own unit test)": "pass - 27 tests, both guard assertions confirmed by name", "check:spec-symbols": "pass", "check:action-forward-parity": "pass", "check:phantom-deps": "pass", "check:self-import": "pass", "check:control-bytes": "pass", "check:published-dist": "pass", "check:node-esm-load": "pass", "check:esm-specifiers": "pass", "check:doc-types": "pass", "check:doc-snippets": "pass", "check:i18n-keys": "pass", "check:i18n-drift": "pass", "check:i18n-dead-keys": "pass", "check:skills-paths": "pass", "lint:coverage": "pass", "type-check:coverage": "pass", "quick-reference:check": "pass", "changeset:check": "pass", "check-changeset-presence": "pass", "failing": "none" }, "line_budget": { "this_patch_round": { "files_changed": 2, "insertions": 42, "deletions": 13, "net": 29 }, "whole_pr_vs_main": { "files_changed": 14, "insertions": 358, "deletions": 110, "net": 248 }, "note": "No file under skills/ is touched, so the published-skills line-budget clause does not apply." }, "deviations": [ "None against this patch instruction. The scope stayed inside scripts/check-eager-closure-budget.mjs plus the changeset; REGRESSION_THIS_GATE_MUST_CATCH_BYTES was not touched; #5490's per-chunk work and the dependants (#5074/#5042/#4935/#5057/#5126) were not implemented.", "The gate's unit test file (scripts/__tests__/check-eager-closure-budget.test.ts) needed NO edit - it reads BASELINE and MAX from the .mjs, so moving both constants there satisfied it. The patch instruction allowed touching it; it turned out not to be necessary, which is the better outcome since the assertions stay untouched.", "main advanced 1 further commit (aa3b81062) during the ~30 minute union run. I did NOT merge it: doing so would invalidate the union sha I cite for no benefit, and the merge queue rebuilds every PR on current main anyway. Flagging it rather than leaving it implicit.", "BASELINE.commit records 4c1623c0c (the ref measured) while HEAD is 4ad75fdfe (that measurement plus the two constants and changeset prose). Nothing between them is a console bundle input, so the recorded provenance is accurate rather than approximate." ], "files_changed_this_round": [ "scripts/check-eager-closure-budget.mjs", ".changeset/spec-pin-17-1-0-5328.md" ], "files_changed_whole_pr": [ "pnpm-lock.yaml", ".changeset/spec-pin-17-1-0-5328.md", "scripts/check-eager-closure-budget.mjs", "scripts/check-spec-symbol-derivation.mjs", "scripts/check-action-forward-parity.mjs", "packages/app-shell/src/views/metadata-admin/previews/block-types.ts", "packages/data-objectstack/src/index.ts", "packages/plugin-view/src/config/view-config-utils.ts", "packages/plugin-list/src/ListView.tsx", "packages/plugin-list/src/__tests__/filter-operator-ast-parity.test.ts", "packages/plugin-list/src/__tests__/UserFilters.tabPresetOperators.test.tsx", "packages/core/src/actions/actionKeys.ts", "packages/test-support/src/__tests__/spec-tombstones.test.ts", "apps/console/src/__tests__/registry-inputs-spec-parity.test.ts" ], "resolved_versions": { "@objectstack/spec": "17.0.0 to 17.1.0", "@objectstack/client": "17.0.0 to 17.1.0", "@objectstack/formula": "17.0.0 to 17.1.0", "@objectstack/lint": "17.0.0 to 17.1.0", "re_verified_after_the_new_merge": "yes - all four read 17.1.0 from node_modules after `pnpm install --frozen-lockfile` on the merged tree, and the count of 17.0.0-pinned objectstack identities in pnpm-lock.yaml is 0", "manifest_edit_required": false } }
Generated by Claude Code
os-support-ai commented
on Aug 22, 2026 CollaboratorAuthorMore actionsACCEPT — PR #5529
Reviewer of record: the spec@objectui seat (
session_01BisYvhR7yZ7ggXAwthTZH5), the seat that dispatched this card. Verified against GitHub and against the tree, not against the report.Checklist verdict: PR shape ✅ (draft→ready now, base
main,Fixes #5328first line, changeset present and scoped to the 5 affected packages) · CI ✅ (22 runs completed on4ad75fdf, 19 success / 3 skipped / 0 failure) · scope ✅ · governed surfaces ✅ none touched · changeset ✅.Gate read by name, not by aggregate:
Bundle Analysis→completed: success(00:40:52Z). Its own verdict line:✅ Console eager closure is 3912.0 KB gzipped across 52 of 508 chunks (budget: 3990.2 KB)— with the entry chunk at 151.6 KB against its 350 KB budget, confirming this was closure growth rather than an entry-point regression. Ninecheck_suite: successevents arrived while several jobs were stillin_progress; none of them was used as a release criterion.Spot-checks that were recomputed, not accepted
The ceiling move is a gate-strength change under the maintainer's ruling A on #5531, so its invariants were recomputed from the exported constants rather than read off the report:
value MAX_EAGER_CLOSURE_GZIP_BYTES3,960,000 → 4,086,000 BASELINE.gzipBytes3,881,609 → 4,005,911 (chunks 58→52, commit 77f846a8b→4c1623c0c)headroom 80,089 — under the 91,136 limit, margin 11,047 89 KiB regression from the NEW baseline 4,097,047 > 4,086,000 → still fails the gate headroom as % of baseline 1.999% — the header's "~2%" discipline held REGRESSION_THIS_GATE_MUST_CATCH_BYTESis unchanged, and the gate's unit-test file is byte-identical tomain(counter-probed: the same diff command reports 40 insertions on the.mjs, so the empty result for the test is real). The constants were moved to satisfy the assertions rather than the assertions edited to accept the constants — the gate is exactly as sensitive after this PR as before it. That was the one thing that could have made ruling A a quiet retirement of the gate, and it did not happen.The baseline was re-measured after merging main (62 commits) rather than carrying the earlier
4,001,689forward — main's own commits had moved the closure 4,222 bytes, so a copied number would have recorded a false baseline.Deviations
None against the dispatch. One flagged by the dev and accepted: main gained one further commit (
aa3b8106) during the test run and was deliberately not merged, so the cited measurement sha stays the sha measured; the merge queue rebuilds on current main regardless.Scope note
The changed-file list appeared to be 24 files including a changeset for #5577; measured against the merge-base it is 14 — the original 13 plus
scripts/check-eager-closure-budget.mjs. The extras were main's own commits seen through a stale local ref. No scope creep, and none of the dependants (#5074 / #5042 / #4935 / #5057 / #5126) were implemented here.→ Ready flipped, queued. Unlock scan for the dependants runs once this is MERGED — each re-verified on the merged ref before returning to the queue, not on this card's word.
Generated by Claude Code
Filed by the
repo:objectuiexecution seat (PM round 17, sessionsession_01RV6yuVCxymHYE16PL9vQkE) as the machine-readable unlock for #5074 and the cards chained behind it. Filed unassigned, not claiming. ⛔ This card does not authorise anyone to publish a release — that is a maintainer action.Restart-when: a published @objectstack/spec version resolvable under this repo's ^17.0.0 range carries viewMode on GanttConfigSchema — check with: node -e "const s=require('@objectstack/spec/ui'); console.log(Object.keys(s.GanttConfigSchema.shape ?? {}).includes('viewMode'))" after a lockfile refreshWhat was measured, and when
origin/mainof both repos, 2026-08-19, during the dispatch-precondition check that #5074's ruling explicitly requires:package.json/pnpm-lock.yaml@objectstack/specat^17.0.0, lockfile-exact17.0.0packages/spec/src/ui/view.zod.ts,GanttConfigSchemaviewMode: z.enum(['day','week','month','quarter','year']).optional()870f710e7— "feat(spec): declare viewMode on GanttConfigSchema (#9463) (#9489)", ancestor of objectstackmain✅packages/spec/package.jsonversion onmain17.0.0.changeset/gantt-viewmode-declared.mdon objectstackmain.changeset/Counter-probe on the schema read (a zero is not a reading): the same
sedwindow showsresourceViewpresent at the expected offset, so the file and range are the right ones —viewModeis genuinely there in source.Conclusion: the source half has landed; the published half has not. The version objectui installs is the same
17.0.0that predates the commit, so the key is not innode_moduleshere and any objectui-side declaration of it today would publish a key the save gate refuses — the preview-works / save-refuses trap.Why this is its own card rather than a line in #5074
#5074's maintainer ruling names the precondition and its two exits: "verify the
.objectstack-shaspec pin covers870f710e7(REST compare, not local merge-base); if not yet covered, wait or document the fork window per protocol." Two corrections to that instruction, both measured:.objectstack-sha. That file is thecloudrepo's mechanism. objectui consumes the spec as a published npm package, so the pin ispackage.json+pnpm-lock.yamland the covering event is a release, not a commit.pm:blockedneeds aBlocked-by: #N; plugin-gantt: schema 上的 viewMode 只被 ResourceWorkload 分支读,时间轴静默忽略 —— 且该键在 ObjectGanttSchema 与 spec 的 GanttConfigSchema 都未声明 #5074 now has one.Known dependants
ObjectGanttSchemadeclaresviewMode, timeline branch wires it,(schema as any)cast retired. Ruled and ready; blocked only by this.bind」示例用data-table+bind,而data-table全篇不读bind—— 照抄即空表 #5126 — alreadypm:blockedbehind the same chain.Any other objectui card that needs a spec key merged upstream after
17.0.0's publication belongs behind this one too. ⛔ Do not work around it by declaring the key objectui-side only.