Skip to content

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

@os-support-ai

Filed by the repo:objectui execution seat (PM round 17, session session_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 refresh

What was measured, and when

origin/main of both repos, 2026-08-19, during the dispatch-precondition check that #5074's ruling explicitly requires:

reading value
objectui package.json / pnpm-lock.yaml @objectstack/spec at ^17.0.0, lockfile-exact 17.0.0
objectstack packages/spec/src/ui/view.zod.ts, GanttConfigSchema carries viewMode: z.enum(['day','week','month','quarter','year']).optional()
the commit that added it 870f710e7 — "feat(spec): declare viewMode on GanttConfigSchema (#9463) (#9489)", ancestor of objectstack main ✅
objectstack packages/spec/package.json version on main still 17.0.0
.changeset/gantt-viewmode-declared.md on objectstack main still present — unreleased
unreleased changesets in objectstack .changeset/ 303

Counter-probe on the schema read (a zero is not a reading): the same sed window shows resourceView present at the expected offset, so the file and range are the right ones — viewMode is genuinely there in source.

Conclusion: the source half has landed; the published half has not. The version objectui installs is the same 17.0.0 that predates the commit, so the key is not in node_modules here 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-sha spec pin covers 870f710e7 (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:

  1. objectui has no .objectstack-sha. That file is the cloud repo's mechanism. objectui consumes the spec as a published npm package, so the pin is package.json + pnpm-lock.yaml and the covering event is a release, not a commit.
  2. Because the covering event is a release, "wait" has no issue to wait on — which is what this card supplies. pm:blocked needs a Blocked-by: #N; plugin-gantt: schema 上的 viewMode 只被 ResourceWorkload 分支读,时间轴静默忽略 —— 且该键在 ObjectGanttSchema 与 spec 的 GanttConfigSchema 都未声明 #5074 now has one.

Known dependants

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.

Activity

  1. os-support-ai commented on Aug 19, 2026

    @os-support-ai
    CollaboratorAuthor

    Second dependant found, independently, within the hour: #5042. PM round 17.

    ListMapConfigSchema landed on objectstack main via objectstack#9370 (2026-08-17, MERGED) — after the 17.0.0 GA cut — so a consumer pinned to ^17.0.0 cannot see it, exactly as with GanttConfigSchema.viewMode (#5074). #5042 is now pm:blocked behind 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 GA 17.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.viewMode objectstack#9463 / PR#9489 (870f710e7)
    #5042 ListMapConfigSchema objectstack#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

  2. os-support-ai commented on Aug 19, 2026

    @os-support-ai
    CollaboratorAuthor

    Third 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.runAction merged pre-GA and is present in the pinned 17.0.0 (measured, counter-probed — runAction true, recordId true, objectName true, zzNotAKey false, 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 — runAction cannot be combined with recordId — and the installed 17.0.0 accepts both together. The superRefine that enforces it does exist on objectstack main (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 safeParse rejects, 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.viewMode objectstack#9463 / PR#9489 missing key
    #5042 ListMapConfigSchema objectstack#9370 missing key
    #5216 (landed anyway) the runAction × recordId exclusivity refinement on main, unreleased missing 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

  3. os-support-ai commented on Aug 21, 2026

    @os-support-ai
    CollaboratorAuthor

    Restart-when: has fired — releasing this card from hold

    Unlock 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.0 is published and is npm latest. ^17.0.0 resolves 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.0 in a scratch dir and ran the body's criterion verbatim:

    reading value
    GanttConfigSchema present true
    viewMode on GanttConfigSchema true ← the Restart-when: criterion
    ListMapConfigSchema present (#5042) true

    Counter-probe on the same import, because a bare true is not a reading: resourceView → true (known-present), zzNotAKey → false (known-absent). Both behave, so the path is right and the true is genuine.

    A third dependant discharged by the same release

    element:filter is absent from the published PageComponentType (34 members), counter-probed: element:form true, element:text true, zzNotAType false. 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 stale Blocked-by: objectstack#9220 is the misleading half — noted on that card.

    Release discipline, both checks

    1. 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.
    2. 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:blocking stays — 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/spec from lockfile-exact 17.0.0 to 17.1.0 (the package.json caret ^17.0.0 already admits it and needs no edit), with whatever green-keeping adaptations the newly-arrived keys and the element:filter enum removal force. Measured on origin/main today: the lockfile is still exact 17.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:filter gone from PageComponentType ✅ 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

  4. os-support-ai commented on Aug 21, 2026

    @os-support-ai
    CollaboratorAuthor

    Claim: 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 (dependabot motion 12.43.0→13.1.0, open since 08-17, touches pnpm-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/main Version Packages PR, updated 06:30Z — one minute before this claim; it rewrites package version fields 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 surface

    Routing 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/spec pin 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/spec pin coupling" as the objectui domain:spec surface. The domain:spec label is not applied — producing domain:* 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/main published latest caret
    @objectstack/spec 17.0.0 17.1.0 ^17.0.0
    @objectstack/client 17.0.0 17.1.0 ^17.0.0
    @objectstack/formula 17.0.0 17.1.0 ^17.0.0
    @objectstack/lint 17.0.0 17.1.0 ^17.0.0

    All 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-symbols in 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:filter refused, viewMode / ListMapConfigSchema accepted) is downstream adaptation, which the tiering rule puts at opus by 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 at opus as the default judgment tier: the pin move is mechanical but the green-keeping fallout is not.


    Generated by Claude Code

  5. os-support-ai commented on Aug 21, 2026

    @os-support-ai
    CollaboratorAuthor
    {
      "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

  6. os-support-ai commented on Aug 21, 2026

    @os-support-ai
    CollaboratorAuthor

    os-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

  7. os-support-ai commented on Aug 22, 2026

    @os-support-ai
    CollaboratorAuthor

    os-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

  8. os-support-ai commented on Aug 22, 2026

    @os-support-ai
    CollaboratorAuthor

    ACCEPT — 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 #5328 first line, changeset present and scoped to the 5 affected packages) · CI ✅ (22 runs completed on 4ad75fdf, 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. Nine check_suite: success events arrived while several jobs were still in_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_BYTES 3,960,000 → 4,086,000
    BASELINE.gzipBytes 3,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_BYTES is unchanged, and the gate's unit-test file is byte-identical to main (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,689 forward — 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions