Skip to content

docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤) - #13777

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-13772-skills-sweep-ui
Aug 31, 2026
Merged

docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤)#13777
os-zhuang merged 1 commit into
mainfrom
claude/issue-13772-skills-sweep-ui

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes#13772
Part of #13658

Flight ⑤ of the published-skills factual sweep: skills/objectstack-ui/**. Every
behavioral claim was settled against the implementation — the Zod schemas in
packages/spec/src/ui/** and packages/lint/src/** in this repo, and the
@object-ui/* renderer sources probed read-only in a detached objectui worktree —
never against another document.

8 distinct false facts / 8 landing sites, all in SKILL.md.
Net -12 tokens / -2 lines; no ratchet ceiling touched.

The dominant class: three retired "silently dropped" claims

Three of the eight are one defect: the doc teaches that a bad key is silently
dropped
, when the protocol-17 strict-unknown-keys cutover closed those schemas and
they now reject by name. This is the most expensive direction for an AI author —
"silently dropped" says your build succeeds and the key is inert, so the author goes
hunting for a rendering bug; the truth is a loud os validate failure with a
prescription attached.

Per-item: 落点 | before | after

#落点beforeafter
1L328 — object-view userFilters"a tabs element is untypable at author time and dropped at parse""…and rejected at parse, not dropped"
2L689 — legacy inline widget query"the inline fields are dropped and a widget lacking dataset fails os validate""the closed schema REJECTS the inline keys by name, and one lacking dataset fails os validate"
3L2055 — widget position pitfall"there is no position key on a widget, so a position object is silently dropped""position is not a widget key and the closed schema REJECTS it by name (it was silently dropped before protocol 17)"
4L63 — List Views table9 rows; page absentadded page row (pageName; no rows of its own)
5L669 — Widget Types table19 of 20 ChartTypeSchema members; combo absentadded Mixed row for combo
6L1664 — Date macro table, Next period4 tokens (_start only) — table enumerated 32 while the heading says 36next_*_start / _end ×4, matching the sibling rows; table now enumerates all 36
7L1669 — parameterised token grammar"N is any positive integer""N is any non-negative integer"
8L1524 — comparison-overlay stylingdash + opacity: 0.5 claimed "for line/area/scatter"; opacity: 0.4 for bars"muted per family (dashed '4 4' on line/area only; reduced opacity on all)"

Items 4–6 are the hidden-shipped-capability direction flight ② named as the
majority: the surface is live and authorable, and the skill's own table says it is not
there. Item 6 is self-contradicting in place — the heading counts 36, the table lists
32.

Item 8 in detail: packages/plugin-charts/src/AdvancedChartImpl.tsxcomparisonStyle()
gives the dash to line/area only (scatter gets none), and the muted opacity differs
per family (line/scatter stroke 0.5, area fill 0.2, bar fill 0.4). The doc had the two
families crossed. The replacement is true and shorter, so this correction helps pay
for the others.

Payment for the additions (SKILL.md headroom was 0)

The ratchet requires new text to be paid for by genuine deletion in the same file.
Two redundant passages in the timeSegments block paid for items 4–7; no fact was
dropped — both were restatements of rows already in the field table directly above them:

落点beforeafter
L573 — "Calendar-midnight cue" bullet3 lines restating the showMidnight table rowdeleted; its one unique clause ("the 排班日 cell itself stays unbroken") folded into that row
L576 — "Default off = zero regression"2 lines; the tint half restates the bands[].color row"Default off. Omit timeSegments and the gantt renders unsegmented."

Evidence — executed probes

Non-vacuity control satisfied several times over; each probe carries positive and
negative controls.

  • Date macrosDATE_MACRO_TOKENS.length === 36; isDateMacroToken returns
    true for all four next_*_end, false for the control next_fortnight_end,
    true for the control today. {0_days_ago} is accepted, settling item 7.
  • type: 'page'ListViewSchema.safeParse ACCEPTS type:'page' + pageName;
    the control type:'carousel' is REJECTED and its own message enumerates all ten
    members including page.
  • comboChartTypeSchema enumerates 20 members including combo; the
    generated contracts/react-blocks.contract.json already carries it, so the SKILL.md
    table contradicted its own package.
  • tabs rejected, not droppedObjectListViewSchema REJECTS
    userFilters:{element:'tabs'} ("expected one of dropdown|toggle"); controls:
    dropdown ACCEPTED, and page-list ListViewSchema still ACCEPTS tabs. The spec's
    own pin (packages/spec/src/ui/object-list-view.test.ts) says "rejected at parse"
    and records the flip from "drops".
  • position / inline keys rejectedDashboardSchema returns
    unrecognized_keys naming position, and separately object, categoryField,
    valueField, aggregate; controls: a clean dataset+values widget ACCEPTED, a
    widget missing dataset REJECTED for that reason alone.

A vacuity trap caught by a control (worth recording)

GanttConfigSchema.safeParse ACCEPTS timeSegments — but it also accepts a bogus
__zz__ key identically, because that schema is passthrough. The acceptance
measured nothing. Settled instead on the declaration: GanttConfigSchema has 19
declared members and timeSegments is not one (zero hits in packages/spec/src/),
which confirms the doc's existing claim that timeSegments is an ObjectUI display
extension and not upstream spec. VERIFIED, no change.

Gates — union run at ec46764f, this PR's head commit

All 14 families derived from the REAL diff via
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (exit 0; change
set derived by the script from the merge base, not hand-supplied):

gateexit
node scripts/check-ci-filter-parity.mjs0
node scripts/check-cross-package-test-inputs.mjs0
node scripts/check-shard-attestation.mjs0
node scripts/check-skills-token-ratchet.mjs0
node scripts/check-test-completeness.mjs3 — NOT MEASURED by its own verdict text (needs a turbo run test log it cannot produce; "not a red, nothing here to fix")
pnpm --filter @objectstack/lint run check:doc-formula-expressions0 (after building its two prerequisites)
pnpm check:agent-test-spelling0
pnpm check:corpus-claim-drift0
pnpm check:cross-package-test-inputs0
pnpm check:doc-authoring0
pnpm check:pm-governed-merges0
pnpm check:role-word0
pnpm check:skill-compatibility0
pnpm check:skill-frame-sync0

Plus, as the diff implicates them:

  • pnpm --filter @objectstack/spec check:skill-examplesexit 0, fully measured
    after building @objectstack/client-react with declarations. Verdict line: "260
    prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran
    the SEMANTIC pass on all of them". Population check: NON-emptyobjectstack-ui
    carries 11 os:check markers (contrast flight ③'s objectstack-query, which had 0
    and recorded an empty population). Marker count is 11 before and after this diff, and
    a line-level check shows 0 of the 22 changed lines falls inside any fence — the
    marked-example population is byte-identical across this change.
  • pnpm --filter @objectstack/spec check:skill-refs — exit 0, "9 generated files in
    sync with packages/spec".
  • pnpm --filter @objectstack/spec check:react-blocks — exit 0, "2 generated files in
    sync with packages/spec".
  • node scripts/check-nul-bytes.mjs — exit 0, 7578 files scanned. Plus a direct
    control-byte scan of the edited file: clean.

Ratchet, before and after:

before skills/objectstack-ui/SKILL.md 25125 / 25125 (+0, headroom 0)
after skills/objectstack-ui/SKILL.md 25113 / 25125 (-12, headroom 12)

Generated files: measured, not touched

contracts/react-blocks.contract.json and references/react-blocks.md are both
emitted by packages/spec/scripts/build-react-blocks-contract.ts (gen:react-blocks),
and references/_index.md by build-skill-references.ts — all three are
generator-owned and excluded from the ratchet by name. Both sync gates report them
already in sync with packages/spec, so no regeneration was due and nothing was
hand-edited
. Their content is a function of the spec source, so a correction there
would have to land in packages/spec/src/ui/** — outside this flight's fence, and
reported rather than made.

PR #13372 (the page view-type member) is the reason item 4 exists: its diff on this
package regenerated only those two generated files and never touched SKILL.md, so
the authored table went stale while the generated contract moved. Read before flagging,
as instructed.

Scope

Generated by Claude Code


Generated by Claude Code

…s corrected
Flight ⑤ of the published-skills factual sweep. Every correction is settled
against the implementation (spec Zod schemas in this repo; @object-ui renderer
sources probed read-only in objectui), never against another document.
Three of the seven are one class: "silently dropped" claims that outlived the
protocol-17 strict-unknown-keys cutover, where the schema now REJECTS by name.
Net -12 tokens / -2 lines; no ratchet ceiling touched.
Part of #13658
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
@github-actionsgithub-actionsBot added size/s documentation Improvements or additions to documentation labels Aug 31, 2026
@huangyiirenehuangyiirene added skip-changeset PR has no user-facing published change; bypasses the changeset gate needs:contract-review labels Aug 31, 2026 — with Claude
@huangyiireneClaude

Copy link
Copy Markdown
CollaboratorAuthor

Contract review — PASS at head ec46764f

Applicability: clause-② CONTENT limb (批 #12) — falsifiable operator/contract semantic claims in published skills/**. Both carriers attached in the same stroke the PR existed (PR + card #13772), per 载体纪律 — the deviation flagged on flight ④ did not repeat.

Reviewer qualification, machine-read this sitting: get_sessionexternal_metadata.last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER. Dispatching-seat review permitted per the 2026-08-21 relaxation.

Review: report + diff read; five anchors independently re-measured on origin/main this hour, all corroborating —

  • packages/spec/src/data/date-macros.zod.ts:98–99, 255–257: the four next_*_end tokens are real members with prose descriptions — the 32-token table under a 36-count heading was under-enumerating;
  • packages/spec/src/ui/view.zod.ts:1326: 'page' is a live list-view type member (with the [feature] Give runtime-published custom pages an end-user entry point: a page view type on objects, or nav registration at publish time #13216 mount refusals in both directions);
  • packages/spec/src/ui/chart.zod.ts:115 + chart.test.ts:65: 'combo' is a ChartTypeSchema member with a parse pin;
  • packages/spec/src/ui/object-list-view.test.ts:7–26: the object-view tabs element is "untypable at author time and rejected at [parse]" — the "silently dropped" prose was teaching a no-op where the platform fails loudly;
  • packages/spec/src/ui/dashboard.zod.ts:524–562: the widget grid box is spelled layout (strictObject {x,y,w,h} with alias/guidance walls); a bare position key is not a member — consistent with the probe's unrecognized_keys reading.

The vacuity-trap catch deserves its line: the GanttConfigSchema passthrough acceptance was correctly DISCARDED as measuring nothing, and the claim settled on the declaration instead — confirming, not overturning, the doc. That is the instrument discipline this program exists to exercise. Generated files (contracts/react-blocks.contract.json, references/*) untouched with both sync gates quoted green; objectui probe-read only from a detached worktree, zero edits, no branch pushed.

Budget: net −2 lines / −12 tokens; SKILL.md's zero headroom paid by deleting two genuinely redundant passages — no ceiling touched.

needs:contract-review cleared on BOTH carriers in this stroke. Governed .md content: PR remains DRAFT for the maintainer's merge (os-zhuang / hotlong requested); the review chain never enqueues a governed surface.


Generated by Claude Code

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

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@huangyiirene@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤) by huangyiirene · Pull Request #13777 · objectstack-ai/objectstack · GitHub
Skip to content

docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤) - #13777

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-13772-skills-sweep-ui
Aug 31, 2026
Merged

docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤)#13777
os-zhuang merged 1 commit into
mainfrom
claude/issue-13772-skills-sweep-ui

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes#13772
Part of #13658

Flight ⑤ of the published-skills factual sweep: skills/objectstack-ui/**. Every
behavioral claim was settled against the implementation — the Zod schemas in
packages/spec/src/ui/** and packages/lint/src/** in this repo, and the
@object-ui/* renderer sources probed read-only in a detached objectui worktree —
never against another document.

8 distinct false facts / 8 landing sites, all in SKILL.md.
Net -12 tokens / -2 lines; no ratchet ceiling touched.

The dominant class: three retired "silently dropped" claims

Three of the eight are one defect: the doc teaches that a bad key is silently
dropped
, when the protocol-17 strict-unknown-keys cutover closed those schemas and
they now reject by name. This is the most expensive direction for an AI author —
"silently dropped" says your build succeeds and the key is inert, so the author goes
hunting for a rendering bug; the truth is a loud os validate failure with a
prescription attached.

Per-item: 落点 | before | after

#落点beforeafter
1L328 — object-view userFilters"a tabs element is untypable at author time and dropped at parse""…and rejected at parse, not dropped"
2L689 — legacy inline widget query"the inline fields are dropped and a widget lacking dataset fails os validate""the closed schema REJECTS the inline keys by name, and one lacking dataset fails os validate"
3L2055 — widget position pitfall"there is no position key on a widget, so a position object is silently dropped""position is not a widget key and the closed schema REJECTS it by name (it was silently dropped before protocol 17)"
4L63 — List Views table9 rows; page absentadded page row (pageName; no rows of its own)
5L669 — Widget Types table19 of 20 ChartTypeSchema members; combo absentadded Mixed row for combo
6L1664 — Date macro table, Next period4 tokens (_start only) — table enumerated 32 while the heading says 36next_*_start / _end ×4, matching the sibling rows; table now enumerates all 36
7L1669 — parameterised token grammar"N is any positive integer""N is any non-negative integer"
8L1524 — comparison-overlay stylingdash + opacity: 0.5 claimed "for line/area/scatter"; opacity: 0.4 for bars"muted per family (dashed '4 4' on line/area only; reduced opacity on all)"

Items 4–6 are the hidden-shipped-capability direction flight ② named as the
majority: the surface is live and authorable, and the skill's own table says it is not
there. Item 6 is self-contradicting in place — the heading counts 36, the table lists
32.

Item 8 in detail: packages/plugin-charts/src/AdvancedChartImpl.tsxcomparisonStyle()
gives the dash to line/area only (scatter gets none), and the muted opacity differs
per family (line/scatter stroke 0.5, area fill 0.2, bar fill 0.4). The doc had the two
families crossed. The replacement is true and shorter, so this correction helps pay
for the others.

Payment for the additions (SKILL.md headroom was 0)

The ratchet requires new text to be paid for by genuine deletion in the same file.
Two redundant passages in the timeSegments block paid for items 4–7; no fact was
dropped — both were restatements of rows already in the field table directly above them:

落点beforeafter
L573 — "Calendar-midnight cue" bullet3 lines restating the showMidnight table rowdeleted; its one unique clause ("the 排班日 cell itself stays unbroken") folded into that row
L576 — "Default off = zero regression"2 lines; the tint half restates the bands[].color row"Default off. Omit timeSegments and the gantt renders unsegmented."

Evidence — executed probes

Non-vacuity control satisfied several times over; each probe carries positive and
negative controls.

  • Date macrosDATE_MACRO_TOKENS.length === 36; isDateMacroToken returns
    true for all four next_*_end, false for the control next_fortnight_end,
    true for the control today. {0_days_ago} is accepted, settling item 7.
  • type: 'page'ListViewSchema.safeParse ACCEPTS type:'page' + pageName;
    the control type:'carousel' is REJECTED and its own message enumerates all ten
    members including page.
  • comboChartTypeSchema enumerates 20 members including combo; the
    generated contracts/react-blocks.contract.json already carries it, so the SKILL.md
    table contradicted its own package.
  • tabs rejected, not droppedObjectListViewSchema REJECTS
    userFilters:{element:'tabs'} ("expected one of dropdown|toggle"); controls:
    dropdown ACCEPTED, and page-list ListViewSchema still ACCEPTS tabs. The spec's
    own pin (packages/spec/src/ui/object-list-view.test.ts) says "rejected at parse"
    and records the flip from "drops".
  • position / inline keys rejectedDashboardSchema returns
    unrecognized_keys naming position, and separately object, categoryField,
    valueField, aggregate; controls: a clean dataset+values widget ACCEPTED, a
    widget missing dataset REJECTED for that reason alone.

A vacuity trap caught by a control (worth recording)

GanttConfigSchema.safeParse ACCEPTS timeSegments — but it also accepts a bogus
__zz__ key identically, because that schema is passthrough. The acceptance
measured nothing. Settled instead on the declaration: GanttConfigSchema has 19
declared members and timeSegments is not one (zero hits in packages/spec/src/),
which confirms the doc's existing claim that timeSegments is an ObjectUI display
extension and not upstream spec. VERIFIED, no change.

Gates — union run at ec46764f, this PR's head commit

All 14 families derived from the REAL diff via
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (exit 0; change
set derived by the script from the merge base, not hand-supplied):

gateexit
node scripts/check-ci-filter-parity.mjs0
node scripts/check-cross-package-test-inputs.mjs0
node scripts/check-shard-attestation.mjs0
node scripts/check-skills-token-ratchet.mjs0
node scripts/check-test-completeness.mjs3 — NOT MEASURED by its own verdict text (needs a turbo run test log it cannot produce; "not a red, nothing here to fix")
pnpm --filter @objectstack/lint run check:doc-formula-expressions0 (after building its two prerequisites)
pnpm check:agent-test-spelling0
pnpm check:corpus-claim-drift0
pnpm check:cross-package-test-inputs0
pnpm check:doc-authoring0
pnpm check:pm-governed-merges0
pnpm check:role-word0
pnpm check:skill-compatibility0
pnpm check:skill-frame-sync0

Plus, as the diff implicates them:

  • pnpm --filter @objectstack/spec check:skill-examplesexit 0, fully measured
    after building @objectstack/client-react with declarations. Verdict line: "260
    prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran
    the SEMANTIC pass on all of them". Population check: NON-emptyobjectstack-ui
    carries 11 os:check markers (contrast flight ③'s objectstack-query, which had 0
    and recorded an empty population). Marker count is 11 before and after this diff, and
    a line-level check shows 0 of the 22 changed lines falls inside any fence — the
    marked-example population is byte-identical across this change.
  • pnpm --filter @objectstack/spec check:skill-refs — exit 0, "9 generated files in
    sync with packages/spec".
  • pnpm --filter @objectstack/spec check:react-blocks — exit 0, "2 generated files in
    sync with packages/spec".
  • node scripts/check-nul-bytes.mjs — exit 0, 7578 files scanned. Plus a direct
    control-byte scan of the edited file: clean.

Ratchet, before and after:

before skills/objectstack-ui/SKILL.md 25125 / 25125 (+0, headroom 0)
after skills/objectstack-ui/SKILL.md 25113 / 25125 (-12, headroom 12)

Generated files: measured, not touched

contracts/react-blocks.contract.json and references/react-blocks.md are both
emitted by packages/spec/scripts/build-react-blocks-contract.ts (gen:react-blocks),
and references/_index.md by build-skill-references.ts — all three are
generator-owned and excluded from the ratchet by name. Both sync gates report them
already in sync with packages/spec, so no regeneration was due and nothing was
hand-edited
. Their content is a function of the spec source, so a correction there
would have to land in packages/spec/src/ui/** — outside this flight's fence, and
reported rather than made.

PR #13372 (the page view-type member) is the reason item 4 exists: its diff on this
package regenerated only those two generated files and never touched SKILL.md, so
the authored table went stale while the generated contract moved. Read before flagging,
as instructed.

Scope

Generated by Claude Code


Generated by Claude Code

…s corrected
Flight ⑤ of the published-skills factual sweep. Every correction is settled
against the implementation (spec Zod schemas in this repo; @object-ui renderer
sources probed read-only in objectui), never against another document.
Three of the seven are one class: "silently dropped" claims that outlived the
protocol-17 strict-unknown-keys cutover, where the schema now REJECTS by name.
Net -12 tokens / -2 lines; no ratchet ceiling touched.
Part of #13658
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
@github-actionsgithub-actionsBot added size/s documentation Improvements or additions to documentation labels Aug 31, 2026
@huangyiirenehuangyiirene added skip-changeset PR has no user-facing published change; bypasses the changeset gate needs:contract-review labels Aug 31, 2026 — with Claude
@huangyiireneClaude

Copy link
Copy Markdown
CollaboratorAuthor

Contract review — PASS at head ec46764f

Applicability: clause-② CONTENT limb (批 #12) — falsifiable operator/contract semantic claims in published skills/**. Both carriers attached in the same stroke the PR existed (PR + card #13772), per 载体纪律 — the deviation flagged on flight ④ did not repeat.

Reviewer qualification, machine-read this sitting: get_sessionexternal_metadata.last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER. Dispatching-seat review permitted per the 2026-08-21 relaxation.

Review: report + diff read; five anchors independently re-measured on origin/main this hour, all corroborating —

  • packages/spec/src/data/date-macros.zod.ts:98–99, 255–257: the four next_*_end tokens are real members with prose descriptions — the 32-token table under a 36-count heading was under-enumerating;
  • packages/spec/src/ui/view.zod.ts:1326: 'page' is a live list-view type member (with the [feature] Give runtime-published custom pages an end-user entry point: a page view type on objects, or nav registration at publish time #13216 mount refusals in both directions);
  • packages/spec/src/ui/chart.zod.ts:115 + chart.test.ts:65: 'combo' is a ChartTypeSchema member with a parse pin;
  • packages/spec/src/ui/object-list-view.test.ts:7–26: the object-view tabs element is "untypable at author time and rejected at [parse]" — the "silently dropped" prose was teaching a no-op where the platform fails loudly;
  • packages/spec/src/ui/dashboard.zod.ts:524–562: the widget grid box is spelled layout (strictObject {x,y,w,h} with alias/guidance walls); a bare position key is not a member — consistent with the probe's unrecognized_keys reading.

The vacuity-trap catch deserves its line: the GanttConfigSchema passthrough acceptance was correctly DISCARDED as measuring nothing, and the claim settled on the declaration instead — confirming, not overturning, the doc. That is the instrument discipline this program exists to exercise. Generated files (contracts/react-blocks.contract.json, references/*) untouched with both sync gates quoted green; objectui probe-read only from a detached worktree, zero edits, no branch pushed.

Budget: net −2 lines / −12 tokens; SKILL.md's zero headroom paid by deleting two genuinely redundant passages — no ceiling touched.

needs:contract-review cleared on BOTH carriers in this stroke. Governed .md content: PR remains DRAFT for the maintainer's merge (os-zhuang / hotlong requested); the review chain never enqueues a governed surface.


Generated by Claude Code

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

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@huangyiirene@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤) by huangyiirene · Pull Request #13777 · objectstack-ai/objectstack · GitHub
Skip to content

docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤) - #13777

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-13772-skills-sweep-ui
Aug 31, 2026
Merged

docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤)#13777
os-zhuang merged 1 commit into
mainfrom
claude/issue-13772-skills-sweep-ui

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes#13772
Part of #13658

Flight ⑤ of the published-skills factual sweep: skills/objectstack-ui/**. Every
behavioral claim was settled against the implementation — the Zod schemas in
packages/spec/src/ui/** and packages/lint/src/** in this repo, and the
@object-ui/* renderer sources probed read-only in a detached objectui worktree —
never against another document.

8 distinct false facts / 8 landing sites, all in SKILL.md.
Net -12 tokens / -2 lines; no ratchet ceiling touched.

The dominant class: three retired "silently dropped" claims

Three of the eight are one defect: the doc teaches that a bad key is silently
dropped
, when the protocol-17 strict-unknown-keys cutover closed those schemas and
they now reject by name. This is the most expensive direction for an AI author —
"silently dropped" says your build succeeds and the key is inert, so the author goes
hunting for a rendering bug; the truth is a loud os validate failure with a
prescription attached.

Per-item: 落点 | before | after

#落点beforeafter
1L328 — object-view userFilters"a tabs element is untypable at author time and dropped at parse""…and rejected at parse, not dropped"
2L689 — legacy inline widget query"the inline fields are dropped and a widget lacking dataset fails os validate""the closed schema REJECTS the inline keys by name, and one lacking dataset fails os validate"
3L2055 — widget position pitfall"there is no position key on a widget, so a position object is silently dropped""position is not a widget key and the closed schema REJECTS it by name (it was silently dropped before protocol 17)"
4L63 — List Views table9 rows; page absentadded page row (pageName; no rows of its own)
5L669 — Widget Types table19 of 20 ChartTypeSchema members; combo absentadded Mixed row for combo
6L1664 — Date macro table, Next period4 tokens (_start only) — table enumerated 32 while the heading says 36next_*_start / _end ×4, matching the sibling rows; table now enumerates all 36
7L1669 — parameterised token grammar"N is any positive integer""N is any non-negative integer"
8L1524 — comparison-overlay stylingdash + opacity: 0.5 claimed "for line/area/scatter"; opacity: 0.4 for bars"muted per family (dashed '4 4' on line/area only; reduced opacity on all)"

Items 4–6 are the hidden-shipped-capability direction flight ② named as the
majority: the surface is live and authorable, and the skill's own table says it is not
there. Item 6 is self-contradicting in place — the heading counts 36, the table lists
32.

Item 8 in detail: packages/plugin-charts/src/AdvancedChartImpl.tsxcomparisonStyle()
gives the dash to line/area only (scatter gets none), and the muted opacity differs
per family (line/scatter stroke 0.5, area fill 0.2, bar fill 0.4). The doc had the two
families crossed. The replacement is true and shorter, so this correction helps pay
for the others.

Payment for the additions (SKILL.md headroom was 0)

The ratchet requires new text to be paid for by genuine deletion in the same file.
Two redundant passages in the timeSegments block paid for items 4–7; no fact was
dropped — both were restatements of rows already in the field table directly above them:

落点beforeafter
L573 — "Calendar-midnight cue" bullet3 lines restating the showMidnight table rowdeleted; its one unique clause ("the 排班日 cell itself stays unbroken") folded into that row
L576 — "Default off = zero regression"2 lines; the tint half restates the bands[].color row"Default off. Omit timeSegments and the gantt renders unsegmented."

Evidence — executed probes

Non-vacuity control satisfied several times over; each probe carries positive and
negative controls.

  • Date macrosDATE_MACRO_TOKENS.length === 36; isDateMacroToken returns
    true for all four next_*_end, false for the control next_fortnight_end,
    true for the control today. {0_days_ago} is accepted, settling item 7.
  • type: 'page'ListViewSchema.safeParse ACCEPTS type:'page' + pageName;
    the control type:'carousel' is REJECTED and its own message enumerates all ten
    members including page.
  • comboChartTypeSchema enumerates 20 members including combo; the
    generated contracts/react-blocks.contract.json already carries it, so the SKILL.md
    table contradicted its own package.
  • tabs rejected, not droppedObjectListViewSchema REJECTS
    userFilters:{element:'tabs'} ("expected one of dropdown|toggle"); controls:
    dropdown ACCEPTED, and page-list ListViewSchema still ACCEPTS tabs. The spec's
    own pin (packages/spec/src/ui/object-list-view.test.ts) says "rejected at parse"
    and records the flip from "drops".
  • position / inline keys rejectedDashboardSchema returns
    unrecognized_keys naming position, and separately object, categoryField,
    valueField, aggregate; controls: a clean dataset+values widget ACCEPTED, a
    widget missing dataset REJECTED for that reason alone.

A vacuity trap caught by a control (worth recording)

GanttConfigSchema.safeParse ACCEPTS timeSegments — but it also accepts a bogus
__zz__ key identically, because that schema is passthrough. The acceptance
measured nothing. Settled instead on the declaration: GanttConfigSchema has 19
declared members and timeSegments is not one (zero hits in packages/spec/src/),
which confirms the doc's existing claim that timeSegments is an ObjectUI display
extension and not upstream spec. VERIFIED, no change.

Gates — union run at ec46764f, this PR's head commit

All 14 families derived from the REAL diff via
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (exit 0; change
set derived by the script from the merge base, not hand-supplied):

gateexit
node scripts/check-ci-filter-parity.mjs0
node scripts/check-cross-package-test-inputs.mjs0
node scripts/check-shard-attestation.mjs0
node scripts/check-skills-token-ratchet.mjs0
node scripts/check-test-completeness.mjs3 — NOT MEASURED by its own verdict text (needs a turbo run test log it cannot produce; "not a red, nothing here to fix")
pnpm --filter @objectstack/lint run check:doc-formula-expressions0 (after building its two prerequisites)
pnpm check:agent-test-spelling0
pnpm check:corpus-claim-drift0
pnpm check:cross-package-test-inputs0
pnpm check:doc-authoring0
pnpm check:pm-governed-merges0
pnpm check:role-word0
pnpm check:skill-compatibility0
pnpm check:skill-frame-sync0

Plus, as the diff implicates them:

  • pnpm --filter @objectstack/spec check:skill-examplesexit 0, fully measured
    after building @objectstack/client-react with declarations. Verdict line: "260
    prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran
    the SEMANTIC pass on all of them". Population check: NON-emptyobjectstack-ui
    carries 11 os:check markers (contrast flight ③'s objectstack-query, which had 0
    and recorded an empty population). Marker count is 11 before and after this diff, and
    a line-level check shows 0 of the 22 changed lines falls inside any fence — the
    marked-example population is byte-identical across this change.
  • pnpm --filter @objectstack/spec check:skill-refs — exit 0, "9 generated files in
    sync with packages/spec".
  • pnpm --filter @objectstack/spec check:react-blocks — exit 0, "2 generated files in
    sync with packages/spec".
  • node scripts/check-nul-bytes.mjs — exit 0, 7578 files scanned. Plus a direct
    control-byte scan of the edited file: clean.

Ratchet, before and after:

before skills/objectstack-ui/SKILL.md 25125 / 25125 (+0, headroom 0)
after skills/objectstack-ui/SKILL.md 25113 / 25125 (-12, headroom 12)

Generated files: measured, not touched

contracts/react-blocks.contract.json and references/react-blocks.md are both
emitted by packages/spec/scripts/build-react-blocks-contract.ts (gen:react-blocks),
and references/_index.md by build-skill-references.ts — all three are
generator-owned and excluded from the ratchet by name. Both sync gates report them
already in sync with packages/spec, so no regeneration was due and nothing was
hand-edited
. Their content is a function of the spec source, so a correction there
would have to land in packages/spec/src/ui/** — outside this flight's fence, and
reported rather than made.

PR #13372 (the page view-type member) is the reason item 4 exists: its diff on this
package regenerated only those two generated files and never touched SKILL.md, so
the authored table went stale while the generated contract moved. Read before flagging,
as instructed.

Scope

Generated by Claude Code


Generated by Claude Code

…s corrected
Flight ⑤ of the published-skills factual sweep. Every correction is settled
against the implementation (spec Zod schemas in this repo; @object-ui renderer
sources probed read-only in objectui), never against another document.
Three of the seven are one class: "silently dropped" claims that outlived the
protocol-17 strict-unknown-keys cutover, where the schema now REJECTS by name.
Net -12 tokens / -2 lines; no ratchet ceiling touched.
Part of #13658
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
@github-actionsgithub-actionsBot added size/s documentation Improvements or additions to documentation labels Aug 31, 2026
@huangyiirenehuangyiirene added skip-changeset PR has no user-facing published change; bypasses the changeset gate needs:contract-review labels Aug 31, 2026 — with Claude
@huangyiireneClaude

Copy link
Copy Markdown
CollaboratorAuthor

Contract review — PASS at head ec46764f

Applicability: clause-② CONTENT limb (批 #12) — falsifiable operator/contract semantic claims in published skills/**. Both carriers attached in the same stroke the PR existed (PR + card #13772), per 载体纪律 — the deviation flagged on flight ④ did not repeat.

Reviewer qualification, machine-read this sitting: get_sessionexternal_metadata.last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER. Dispatching-seat review permitted per the 2026-08-21 relaxation.

Review: report + diff read; five anchors independently re-measured on origin/main this hour, all corroborating —

  • packages/spec/src/data/date-macros.zod.ts:98–99, 255–257: the four next_*_end tokens are real members with prose descriptions — the 32-token table under a 36-count heading was under-enumerating;
  • packages/spec/src/ui/view.zod.ts:1326: 'page' is a live list-view type member (with the [feature] Give runtime-published custom pages an end-user entry point: a page view type on objects, or nav registration at publish time #13216 mount refusals in both directions);
  • packages/spec/src/ui/chart.zod.ts:115 + chart.test.ts:65: 'combo' is a ChartTypeSchema member with a parse pin;
  • packages/spec/src/ui/object-list-view.test.ts:7–26: the object-view tabs element is "untypable at author time and rejected at [parse]" — the "silently dropped" prose was teaching a no-op where the platform fails loudly;
  • packages/spec/src/ui/dashboard.zod.ts:524–562: the widget grid box is spelled layout (strictObject {x,y,w,h} with alias/guidance walls); a bare position key is not a member — consistent with the probe's unrecognized_keys reading.

The vacuity-trap catch deserves its line: the GanttConfigSchema passthrough acceptance was correctly DISCARDED as measuring nothing, and the claim settled on the declaration instead — confirming, not overturning, the doc. That is the instrument discipline this program exists to exercise. Generated files (contracts/react-blocks.contract.json, references/*) untouched with both sync gates quoted green; objectui probe-read only from a detached worktree, zero edits, no branch pushed.

Budget: net −2 lines / −12 tokens; SKILL.md's zero headroom paid by deleting two genuinely redundant passages — no ceiling touched.

needs:contract-review cleared on BOTH carriers in this stroke. Governed .md content: PR remains DRAFT for the maintainer's merge (os-zhuang / hotlong requested); the review chain never enqueues a governed surface.


Generated by Claude Code

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

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@huangyiirene@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤) by huangyiirene · Pull Request #13777 · objectstack-ai/objectstack · GitHub
Skip to content

docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤) - #13777

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-13772-skills-sweep-ui
Aug 31, 2026
Merged

docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤)#13777
os-zhuang merged 1 commit into
mainfrom
claude/issue-13772-skills-sweep-ui

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes#13772
Part of #13658

Flight ⑤ of the published-skills factual sweep: skills/objectstack-ui/**. Every
behavioral claim was settled against the implementation — the Zod schemas in
packages/spec/src/ui/** and packages/lint/src/** in this repo, and the
@object-ui/* renderer sources probed read-only in a detached objectui worktree —
never against another document.

8 distinct false facts / 8 landing sites, all in SKILL.md.
Net -12 tokens / -2 lines; no ratchet ceiling touched.

The dominant class: three retired "silently dropped" claims

Three of the eight are one defect: the doc teaches that a bad key is silently
dropped
, when the protocol-17 strict-unknown-keys cutover closed those schemas and
they now reject by name. This is the most expensive direction for an AI author —
"silently dropped" says your build succeeds and the key is inert, so the author goes
hunting for a rendering bug; the truth is a loud os validate failure with a
prescription attached.

Per-item: 落点 | before | after

#落点beforeafter
1L328 — object-view userFilters"a tabs element is untypable at author time and dropped at parse""…and rejected at parse, not dropped"
2L689 — legacy inline widget query"the inline fields are dropped and a widget lacking dataset fails os validate""the closed schema REJECTS the inline keys by name, and one lacking dataset fails os validate"
3L2055 — widget position pitfall"there is no position key on a widget, so a position object is silently dropped""position is not a widget key and the closed schema REJECTS it by name (it was silently dropped before protocol 17)"
4L63 — List Views table9 rows; page absentadded page row (pageName; no rows of its own)
5L669 — Widget Types table19 of 20 ChartTypeSchema members; combo absentadded Mixed row for combo
6L1664 — Date macro table, Next period4 tokens (_start only) — table enumerated 32 while the heading says 36next_*_start / _end ×4, matching the sibling rows; table now enumerates all 36
7L1669 — parameterised token grammar"N is any positive integer""N is any non-negative integer"
8L1524 — comparison-overlay stylingdash + opacity: 0.5 claimed "for line/area/scatter"; opacity: 0.4 for bars"muted per family (dashed '4 4' on line/area only; reduced opacity on all)"

Items 4–6 are the hidden-shipped-capability direction flight ② named as the
majority: the surface is live and authorable, and the skill's own table says it is not
there. Item 6 is self-contradicting in place — the heading counts 36, the table lists
32.

Item 8 in detail: packages/plugin-charts/src/AdvancedChartImpl.tsxcomparisonStyle()
gives the dash to line/area only (scatter gets none), and the muted opacity differs
per family (line/scatter stroke 0.5, area fill 0.2, bar fill 0.4). The doc had the two
families crossed. The replacement is true and shorter, so this correction helps pay
for the others.

Payment for the additions (SKILL.md headroom was 0)

The ratchet requires new text to be paid for by genuine deletion in the same file.
Two redundant passages in the timeSegments block paid for items 4–7; no fact was
dropped — both were restatements of rows already in the field table directly above them:

落点beforeafter
L573 — "Calendar-midnight cue" bullet3 lines restating the showMidnight table rowdeleted; its one unique clause ("the 排班日 cell itself stays unbroken") folded into that row
L576 — "Default off = zero regression"2 lines; the tint half restates the bands[].color row"Default off. Omit timeSegments and the gantt renders unsegmented."

Evidence — executed probes

Non-vacuity control satisfied several times over; each probe carries positive and
negative controls.

  • Date macrosDATE_MACRO_TOKENS.length === 36; isDateMacroToken returns
    true for all four next_*_end, false for the control next_fortnight_end,
    true for the control today. {0_days_ago} is accepted, settling item 7.
  • type: 'page'ListViewSchema.safeParse ACCEPTS type:'page' + pageName;
    the control type:'carousel' is REJECTED and its own message enumerates all ten
    members including page.
  • comboChartTypeSchema enumerates 20 members including combo; the
    generated contracts/react-blocks.contract.json already carries it, so the SKILL.md
    table contradicted its own package.
  • tabs rejected, not droppedObjectListViewSchema REJECTS
    userFilters:{element:'tabs'} ("expected one of dropdown|toggle"); controls:
    dropdown ACCEPTED, and page-list ListViewSchema still ACCEPTS tabs. The spec's
    own pin (packages/spec/src/ui/object-list-view.test.ts) says "rejected at parse"
    and records the flip from "drops".
  • position / inline keys rejectedDashboardSchema returns
    unrecognized_keys naming position, and separately object, categoryField,
    valueField, aggregate; controls: a clean dataset+values widget ACCEPTED, a
    widget missing dataset REJECTED for that reason alone.

A vacuity trap caught by a control (worth recording)

GanttConfigSchema.safeParse ACCEPTS timeSegments — but it also accepts a bogus
__zz__ key identically, because that schema is passthrough. The acceptance
measured nothing. Settled instead on the declaration: GanttConfigSchema has 19
declared members and timeSegments is not one (zero hits in packages/spec/src/),
which confirms the doc's existing claim that timeSegments is an ObjectUI display
extension and not upstream spec. VERIFIED, no change.

Gates — union run at ec46764f, this PR's head commit

All 14 families derived from the REAL diff via
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (exit 0; change
set derived by the script from the merge base, not hand-supplied):

gateexit
node scripts/check-ci-filter-parity.mjs0
node scripts/check-cross-package-test-inputs.mjs0
node scripts/check-shard-attestation.mjs0
node scripts/check-skills-token-ratchet.mjs0
node scripts/check-test-completeness.mjs3 — NOT MEASURED by its own verdict text (needs a turbo run test log it cannot produce; "not a red, nothing here to fix")
pnpm --filter @objectstack/lint run check:doc-formula-expressions0 (after building its two prerequisites)
pnpm check:agent-test-spelling0
pnpm check:corpus-claim-drift0
pnpm check:cross-package-test-inputs0
pnpm check:doc-authoring0
pnpm check:pm-governed-merges0
pnpm check:role-word0
pnpm check:skill-compatibility0
pnpm check:skill-frame-sync0

Plus, as the diff implicates them:

  • pnpm --filter @objectstack/spec check:skill-examplesexit 0, fully measured
    after building @objectstack/client-react with declarations. Verdict line: "260
    prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran
    the SEMANTIC pass on all of them". Population check: NON-emptyobjectstack-ui
    carries 11 os:check markers (contrast flight ③'s objectstack-query, which had 0
    and recorded an empty population). Marker count is 11 before and after this diff, and
    a line-level check shows 0 of the 22 changed lines falls inside any fence — the
    marked-example population is byte-identical across this change.
  • pnpm --filter @objectstack/spec check:skill-refs — exit 0, "9 generated files in
    sync with packages/spec".
  • pnpm --filter @objectstack/spec check:react-blocks — exit 0, "2 generated files in
    sync with packages/spec".
  • node scripts/check-nul-bytes.mjs — exit 0, 7578 files scanned. Plus a direct
    control-byte scan of the edited file: clean.

Ratchet, before and after:

before skills/objectstack-ui/SKILL.md 25125 / 25125 (+0, headroom 0)
after skills/objectstack-ui/SKILL.md 25113 / 25125 (-12, headroom 12)

Generated files: measured, not touched

contracts/react-blocks.contract.json and references/react-blocks.md are both
emitted by packages/spec/scripts/build-react-blocks-contract.ts (gen:react-blocks),
and references/_index.md by build-skill-references.ts — all three are
generator-owned and excluded from the ratchet by name. Both sync gates report them
already in sync with packages/spec, so no regeneration was due and nothing was
hand-edited
. Their content is a function of the spec source, so a correction there
would have to land in packages/spec/src/ui/** — outside this flight's fence, and
reported rather than made.

PR #13372 (the page view-type member) is the reason item 4 exists: its diff on this
package regenerated only those two generated files and never touched SKILL.md, so
the authored table went stale while the generated contract moved. Read before flagging,
as instructed.

Scope

Generated by Claude Code


Generated by Claude Code

…s corrected
Flight ⑤ of the published-skills factual sweep. Every correction is settled
against the implementation (spec Zod schemas in this repo; @object-ui renderer
sources probed read-only in objectui), never against another document.
Three of the seven are one class: "silently dropped" claims that outlived the
protocol-17 strict-unknown-keys cutover, where the schema now REJECTS by name.
Net -12 tokens / -2 lines; no ratchet ceiling touched.
Part of #13658
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
@github-actionsgithub-actionsBot added size/s documentation Improvements or additions to documentation labels Aug 31, 2026
@huangyiirenehuangyiirene added skip-changeset PR has no user-facing published change; bypasses the changeset gate needs:contract-review labels Aug 31, 2026 — with Claude
@huangyiireneClaude

Copy link
Copy Markdown
CollaboratorAuthor

Contract review — PASS at head ec46764f

Applicability: clause-② CONTENT limb (批 #12) — falsifiable operator/contract semantic claims in published skills/**. Both carriers attached in the same stroke the PR existed (PR + card #13772), per 载体纪律 — the deviation flagged on flight ④ did not repeat.

Reviewer qualification, machine-read this sitting: get_sessionexternal_metadata.last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER. Dispatching-seat review permitted per the 2026-08-21 relaxation.

Review: report + diff read; five anchors independently re-measured on origin/main this hour, all corroborating —

  • packages/spec/src/data/date-macros.zod.ts:98–99, 255–257: the four next_*_end tokens are real members with prose descriptions — the 32-token table under a 36-count heading was under-enumerating;
  • packages/spec/src/ui/view.zod.ts:1326: 'page' is a live list-view type member (with the [feature] Give runtime-published custom pages an end-user entry point: a page view type on objects, or nav registration at publish time #13216 mount refusals in both directions);
  • packages/spec/src/ui/chart.zod.ts:115 + chart.test.ts:65: 'combo' is a ChartTypeSchema member with a parse pin;
  • packages/spec/src/ui/object-list-view.test.ts:7–26: the object-view tabs element is "untypable at author time and rejected at [parse]" — the "silently dropped" prose was teaching a no-op where the platform fails loudly;
  • packages/spec/src/ui/dashboard.zod.ts:524–562: the widget grid box is spelled layout (strictObject {x,y,w,h} with alias/guidance walls); a bare position key is not a member — consistent with the probe's unrecognized_keys reading.

The vacuity-trap catch deserves its line: the GanttConfigSchema passthrough acceptance was correctly DISCARDED as measuring nothing, and the claim settled on the declaration instead — confirming, not overturning, the doc. That is the instrument discipline this program exists to exercise. Generated files (contracts/react-blocks.contract.json, references/*) untouched with both sync gates quoted green; objectui probe-read only from a detached worktree, zero edits, no branch pushed.

Budget: net −2 lines / −12 tokens; SKILL.md's zero headroom paid by deleting two genuinely redundant passages — no ceiling touched.

needs:contract-review cleared on BOTH carriers in this stroke. Governed .md content: PR remains DRAFT for the maintainer's merge (os-zhuang / hotlong requested); the review chain never enqueues a governed surface.


Generated by Claude Code

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

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@huangyiirene@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤) by huangyiirene · Pull Request #13777 · objectstack-ai/objectstack · GitHub
Skip to content

docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤) - #13777

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-13772-skills-sweep-ui
Aug 31, 2026
Merged

docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤)#13777
os-zhuang merged 1 commit into
mainfrom
claude/issue-13772-skills-sweep-ui

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes#13772
Part of #13658

Flight ⑤ of the published-skills factual sweep: skills/objectstack-ui/**. Every
behavioral claim was settled against the implementation — the Zod schemas in
packages/spec/src/ui/** and packages/lint/src/** in this repo, and the
@object-ui/* renderer sources probed read-only in a detached objectui worktree —
never against another document.

8 distinct false facts / 8 landing sites, all in SKILL.md.
Net -12 tokens / -2 lines; no ratchet ceiling touched.

The dominant class: three retired "silently dropped" claims

Three of the eight are one defect: the doc teaches that a bad key is silently
dropped
, when the protocol-17 strict-unknown-keys cutover closed those schemas and
they now reject by name. This is the most expensive direction for an AI author —
"silently dropped" says your build succeeds and the key is inert, so the author goes
hunting for a rendering bug; the truth is a loud os validate failure with a
prescription attached.

Per-item: 落点 | before | after

#落点beforeafter
1L328 — object-view userFilters"a tabs element is untypable at author time and dropped at parse""…and rejected at parse, not dropped"
2L689 — legacy inline widget query"the inline fields are dropped and a widget lacking dataset fails os validate""the closed schema REJECTS the inline keys by name, and one lacking dataset fails os validate"
3L2055 — widget position pitfall"there is no position key on a widget, so a position object is silently dropped""position is not a widget key and the closed schema REJECTS it by name (it was silently dropped before protocol 17)"
4L63 — List Views table9 rows; page absentadded page row (pageName; no rows of its own)
5L669 — Widget Types table19 of 20 ChartTypeSchema members; combo absentadded Mixed row for combo
6L1664 — Date macro table, Next period4 tokens (_start only) — table enumerated 32 while the heading says 36next_*_start / _end ×4, matching the sibling rows; table now enumerates all 36
7L1669 — parameterised token grammar"N is any positive integer""N is any non-negative integer"
8L1524 — comparison-overlay stylingdash + opacity: 0.5 claimed "for line/area/scatter"; opacity: 0.4 for bars"muted per family (dashed '4 4' on line/area only; reduced opacity on all)"

Items 4–6 are the hidden-shipped-capability direction flight ② named as the
majority: the surface is live and authorable, and the skill's own table says it is not
there. Item 6 is self-contradicting in place — the heading counts 36, the table lists
32.

Item 8 in detail: packages/plugin-charts/src/AdvancedChartImpl.tsxcomparisonStyle()
gives the dash to line/area only (scatter gets none), and the muted opacity differs
per family (line/scatter stroke 0.5, area fill 0.2, bar fill 0.4). The doc had the two
families crossed. The replacement is true and shorter, so this correction helps pay
for the others.

Payment for the additions (SKILL.md headroom was 0)

The ratchet requires new text to be paid for by genuine deletion in the same file.
Two redundant passages in the timeSegments block paid for items 4–7; no fact was
dropped — both were restatements of rows already in the field table directly above them:

落点beforeafter
L573 — "Calendar-midnight cue" bullet3 lines restating the showMidnight table rowdeleted; its one unique clause ("the 排班日 cell itself stays unbroken") folded into that row
L576 — "Default off = zero regression"2 lines; the tint half restates the bands[].color row"Default off. Omit timeSegments and the gantt renders unsegmented."

Evidence — executed probes

Non-vacuity control satisfied several times over; each probe carries positive and
negative controls.

  • Date macrosDATE_MACRO_TOKENS.length === 36; isDateMacroToken returns
    true for all four next_*_end, false for the control next_fortnight_end,
    true for the control today. {0_days_ago} is accepted, settling item 7.
  • type: 'page'ListViewSchema.safeParse ACCEPTS type:'page' + pageName;
    the control type:'carousel' is REJECTED and its own message enumerates all ten
    members including page.
  • comboChartTypeSchema enumerates 20 members including combo; the
    generated contracts/react-blocks.contract.json already carries it, so the SKILL.md
    table contradicted its own package.
  • tabs rejected, not droppedObjectListViewSchema REJECTS
    userFilters:{element:'tabs'} ("expected one of dropdown|toggle"); controls:
    dropdown ACCEPTED, and page-list ListViewSchema still ACCEPTS tabs. The spec's
    own pin (packages/spec/src/ui/object-list-view.test.ts) says "rejected at parse"
    and records the flip from "drops".
  • position / inline keys rejectedDashboardSchema returns
    unrecognized_keys naming position, and separately object, categoryField,
    valueField, aggregate; controls: a clean dataset+values widget ACCEPTED, a
    widget missing dataset REJECTED for that reason alone.

A vacuity trap caught by a control (worth recording)

GanttConfigSchema.safeParse ACCEPTS timeSegments — but it also accepts a bogus
__zz__ key identically, because that schema is passthrough. The acceptance
measured nothing. Settled instead on the declaration: GanttConfigSchema has 19
declared members and timeSegments is not one (zero hits in packages/spec/src/),
which confirms the doc's existing claim that timeSegments is an ObjectUI display
extension and not upstream spec. VERIFIED, no change.

Gates — union run at ec46764f, this PR's head commit

All 14 families derived from the REAL diff via
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (exit 0; change
set derived by the script from the merge base, not hand-supplied):

gateexit
node scripts/check-ci-filter-parity.mjs0
node scripts/check-cross-package-test-inputs.mjs0
node scripts/check-shard-attestation.mjs0
node scripts/check-skills-token-ratchet.mjs0
node scripts/check-test-completeness.mjs3 — NOT MEASURED by its own verdict text (needs a turbo run test log it cannot produce; "not a red, nothing here to fix")
pnpm --filter @objectstack/lint run check:doc-formula-expressions0 (after building its two prerequisites)
pnpm check:agent-test-spelling0
pnpm check:corpus-claim-drift0
pnpm check:cross-package-test-inputs0
pnpm check:doc-authoring0
pnpm check:pm-governed-merges0
pnpm check:role-word0
pnpm check:skill-compatibility0
pnpm check:skill-frame-sync0

Plus, as the diff implicates them:

  • pnpm --filter @objectstack/spec check:skill-examplesexit 0, fully measured
    after building @objectstack/client-react with declarations. Verdict line: "260
    prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran
    the SEMANTIC pass on all of them". Population check: NON-emptyobjectstack-ui
    carries 11 os:check markers (contrast flight ③'s objectstack-query, which had 0
    and recorded an empty population). Marker count is 11 before and after this diff, and
    a line-level check shows 0 of the 22 changed lines falls inside any fence — the
    marked-example population is byte-identical across this change.
  • pnpm --filter @objectstack/spec check:skill-refs — exit 0, "9 generated files in
    sync with packages/spec".
  • pnpm --filter @objectstack/spec check:react-blocks — exit 0, "2 generated files in
    sync with packages/spec".
  • node scripts/check-nul-bytes.mjs — exit 0, 7578 files scanned. Plus a direct
    control-byte scan of the edited file: clean.

Ratchet, before and after:

before skills/objectstack-ui/SKILL.md 25125 / 25125 (+0, headroom 0)
after skills/objectstack-ui/SKILL.md 25113 / 25125 (-12, headroom 12)

Generated files: measured, not touched

contracts/react-blocks.contract.json and references/react-blocks.md are both
emitted by packages/spec/scripts/build-react-blocks-contract.ts (gen:react-blocks),
and references/_index.md by build-skill-references.ts — all three are
generator-owned and excluded from the ratchet by name. Both sync gates report them
already in sync with packages/spec, so no regeneration was due and nothing was
hand-edited
. Their content is a function of the spec source, so a correction there
would have to land in packages/spec/src/ui/** — outside this flight's fence, and
reported rather than made.

PR #13372 (the page view-type member) is the reason item 4 exists: its diff on this
package regenerated only those two generated files and never touched SKILL.md, so
the authored table went stale while the generated contract moved. Read before flagging,
as instructed.

Scope

Generated by Claude Code


Generated by Claude Code

…s corrected
Flight ⑤ of the published-skills factual sweep. Every correction is settled
against the implementation (spec Zod schemas in this repo; @object-ui renderer
sources probed read-only in objectui), never against another document.
Three of the seven are one class: "silently dropped" claims that outlived the
protocol-17 strict-unknown-keys cutover, where the schema now REJECTS by name.
Net -12 tokens / -2 lines; no ratchet ceiling touched.
Part of #13658
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
@github-actionsgithub-actionsBot added size/s documentation Improvements or additions to documentation labels Aug 31, 2026
@huangyiirenehuangyiirene added skip-changeset PR has no user-facing published change; bypasses the changeset gate needs:contract-review labels Aug 31, 2026 — with Claude
@huangyiireneClaude

Copy link
Copy Markdown
CollaboratorAuthor

Contract review — PASS at head ec46764f

Applicability: clause-② CONTENT limb (批 #12) — falsifiable operator/contract semantic claims in published skills/**. Both carriers attached in the same stroke the PR existed (PR + card #13772), per 载体纪律 — the deviation flagged on flight ④ did not repeat.

Reviewer qualification, machine-read this sitting: get_sessionexternal_metadata.last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER. Dispatching-seat review permitted per the 2026-08-21 relaxation.

Review: report + diff read; five anchors independently re-measured on origin/main this hour, all corroborating —

  • packages/spec/src/data/date-macros.zod.ts:98–99, 255–257: the four next_*_end tokens are real members with prose descriptions — the 32-token table under a 36-count heading was under-enumerating;
  • packages/spec/src/ui/view.zod.ts:1326: 'page' is a live list-view type member (with the [feature] Give runtime-published custom pages an end-user entry point: a page view type on objects, or nav registration at publish time #13216 mount refusals in both directions);
  • packages/spec/src/ui/chart.zod.ts:115 + chart.test.ts:65: 'combo' is a ChartTypeSchema member with a parse pin;
  • packages/spec/src/ui/object-list-view.test.ts:7–26: the object-view tabs element is "untypable at author time and rejected at [parse]" — the "silently dropped" prose was teaching a no-op where the platform fails loudly;
  • packages/spec/src/ui/dashboard.zod.ts:524–562: the widget grid box is spelled layout (strictObject {x,y,w,h} with alias/guidance walls); a bare position key is not a member — consistent with the probe's unrecognized_keys reading.

The vacuity-trap catch deserves its line: the GanttConfigSchema passthrough acceptance was correctly DISCARDED as measuring nothing, and the claim settled on the declaration instead — confirming, not overturning, the doc. That is the instrument discipline this program exists to exercise. Generated files (contracts/react-blocks.contract.json, references/*) untouched with both sync gates quoted green; objectui probe-read only from a detached worktree, zero edits, no branch pushed.

Budget: net −2 lines / −12 tokens; SKILL.md's zero headroom paid by deleting two genuinely redundant passages — no ceiling touched.

needs:contract-review cleared on BOTH carriers in this stroke. Governed .md content: PR remains DRAFT for the maintainer's merge (os-zhuang / hotlong requested); the review chain never enqueues a governed surface.


Generated by Claude Code

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

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@huangyiirene@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤) by huangyiirene · Pull Request #13777 · objectstack-ai/objectstack · GitHub
Skip to content

docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤) - #13777

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-13772-skills-sweep-ui
Aug 31, 2026
Merged

docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤)#13777
os-zhuang merged 1 commit into
mainfrom
claude/issue-13772-skills-sweep-ui

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes#13772
Part of #13658

Flight ⑤ of the published-skills factual sweep: skills/objectstack-ui/**. Every
behavioral claim was settled against the implementation — the Zod schemas in
packages/spec/src/ui/** and packages/lint/src/** in this repo, and the
@object-ui/* renderer sources probed read-only in a detached objectui worktree —
never against another document.

8 distinct false facts / 8 landing sites, all in SKILL.md.
Net -12 tokens / -2 lines; no ratchet ceiling touched.

The dominant class: three retired "silently dropped" claims

Three of the eight are one defect: the doc teaches that a bad key is silently
dropped
, when the protocol-17 strict-unknown-keys cutover closed those schemas and
they now reject by name. This is the most expensive direction for an AI author —
"silently dropped" says your build succeeds and the key is inert, so the author goes
hunting for a rendering bug; the truth is a loud os validate failure with a
prescription attached.

Per-item: 落点 | before | after

#落点beforeafter
1L328 — object-view userFilters"a tabs element is untypable at author time and dropped at parse""…and rejected at parse, not dropped"
2L689 — legacy inline widget query"the inline fields are dropped and a widget lacking dataset fails os validate""the closed schema REJECTS the inline keys by name, and one lacking dataset fails os validate"
3L2055 — widget position pitfall"there is no position key on a widget, so a position object is silently dropped""position is not a widget key and the closed schema REJECTS it by name (it was silently dropped before protocol 17)"
4L63 — List Views table9 rows; page absentadded page row (pageName; no rows of its own)
5L669 — Widget Types table19 of 20 ChartTypeSchema members; combo absentadded Mixed row for combo
6L1664 — Date macro table, Next period4 tokens (_start only) — table enumerated 32 while the heading says 36next_*_start / _end ×4, matching the sibling rows; table now enumerates all 36
7L1669 — parameterised token grammar"N is any positive integer""N is any non-negative integer"
8L1524 — comparison-overlay stylingdash + opacity: 0.5 claimed "for line/area/scatter"; opacity: 0.4 for bars"muted per family (dashed '4 4' on line/area only; reduced opacity on all)"

Items 4–6 are the hidden-shipped-capability direction flight ② named as the
majority: the surface is live and authorable, and the skill's own table says it is not
there. Item 6 is self-contradicting in place — the heading counts 36, the table lists
32.

Item 8 in detail: packages/plugin-charts/src/AdvancedChartImpl.tsxcomparisonStyle()
gives the dash to line/area only (scatter gets none), and the muted opacity differs
per family (line/scatter stroke 0.5, area fill 0.2, bar fill 0.4). The doc had the two
families crossed. The replacement is true and shorter, so this correction helps pay
for the others.

Payment for the additions (SKILL.md headroom was 0)

The ratchet requires new text to be paid for by genuine deletion in the same file.
Two redundant passages in the timeSegments block paid for items 4–7; no fact was
dropped — both were restatements of rows already in the field table directly above them:

落点beforeafter
L573 — "Calendar-midnight cue" bullet3 lines restating the showMidnight table rowdeleted; its one unique clause ("the 排班日 cell itself stays unbroken") folded into that row
L576 — "Default off = zero regression"2 lines; the tint half restates the bands[].color row"Default off. Omit timeSegments and the gantt renders unsegmented."

Evidence — executed probes

Non-vacuity control satisfied several times over; each probe carries positive and
negative controls.

  • Date macrosDATE_MACRO_TOKENS.length === 36; isDateMacroToken returns
    true for all four next_*_end, false for the control next_fortnight_end,
    true for the control today. {0_days_ago} is accepted, settling item 7.
  • type: 'page'ListViewSchema.safeParse ACCEPTS type:'page' + pageName;
    the control type:'carousel' is REJECTED and its own message enumerates all ten
    members including page.
  • comboChartTypeSchema enumerates 20 members including combo; the
    generated contracts/react-blocks.contract.json already carries it, so the SKILL.md
    table contradicted its own package.
  • tabs rejected, not droppedObjectListViewSchema REJECTS
    userFilters:{element:'tabs'} ("expected one of dropdown|toggle"); controls:
    dropdown ACCEPTED, and page-list ListViewSchema still ACCEPTS tabs. The spec's
    own pin (packages/spec/src/ui/object-list-view.test.ts) says "rejected at parse"
    and records the flip from "drops".
  • position / inline keys rejectedDashboardSchema returns
    unrecognized_keys naming position, and separately object, categoryField,
    valueField, aggregate; controls: a clean dataset+values widget ACCEPTED, a
    widget missing dataset REJECTED for that reason alone.

A vacuity trap caught by a control (worth recording)

GanttConfigSchema.safeParse ACCEPTS timeSegments — but it also accepts a bogus
__zz__ key identically, because that schema is passthrough. The acceptance
measured nothing. Settled instead on the declaration: GanttConfigSchema has 19
declared members and timeSegments is not one (zero hits in packages/spec/src/),
which confirms the doc's existing claim that timeSegments is an ObjectUI display
extension and not upstream spec. VERIFIED, no change.

Gates — union run at ec46764f, this PR's head commit

All 14 families derived from the REAL diff via
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (exit 0; change
set derived by the script from the merge base, not hand-supplied):

gateexit
node scripts/check-ci-filter-parity.mjs0
node scripts/check-cross-package-test-inputs.mjs0
node scripts/check-shard-attestation.mjs0
node scripts/check-skills-token-ratchet.mjs0
node scripts/check-test-completeness.mjs3 — NOT MEASURED by its own verdict text (needs a turbo run test log it cannot produce; "not a red, nothing here to fix")
pnpm --filter @objectstack/lint run check:doc-formula-expressions0 (after building its two prerequisites)
pnpm check:agent-test-spelling0
pnpm check:corpus-claim-drift0
pnpm check:cross-package-test-inputs0
pnpm check:doc-authoring0
pnpm check:pm-governed-merges0
pnpm check:role-word0
pnpm check:skill-compatibility0
pnpm check:skill-frame-sync0

Plus, as the diff implicates them:

  • pnpm --filter @objectstack/spec check:skill-examplesexit 0, fully measured
    after building @objectstack/client-react with declarations. Verdict line: "260
    prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran
    the SEMANTIC pass on all of them". Population check: NON-emptyobjectstack-ui
    carries 11 os:check markers (contrast flight ③'s objectstack-query, which had 0
    and recorded an empty population). Marker count is 11 before and after this diff, and
    a line-level check shows 0 of the 22 changed lines falls inside any fence — the
    marked-example population is byte-identical across this change.
  • pnpm --filter @objectstack/spec check:skill-refs — exit 0, "9 generated files in
    sync with packages/spec".
  • pnpm --filter @objectstack/spec check:react-blocks — exit 0, "2 generated files in
    sync with packages/spec".
  • node scripts/check-nul-bytes.mjs — exit 0, 7578 files scanned. Plus a direct
    control-byte scan of the edited file: clean.

Ratchet, before and after:

before skills/objectstack-ui/SKILL.md 25125 / 25125 (+0, headroom 0)
after skills/objectstack-ui/SKILL.md 25113 / 25125 (-12, headroom 12)

Generated files: measured, not touched

contracts/react-blocks.contract.json and references/react-blocks.md are both
emitted by packages/spec/scripts/build-react-blocks-contract.ts (gen:react-blocks),
and references/_index.md by build-skill-references.ts — all three are
generator-owned and excluded from the ratchet by name. Both sync gates report them
already in sync with packages/spec, so no regeneration was due and nothing was
hand-edited
. Their content is a function of the spec source, so a correction there
would have to land in packages/spec/src/ui/** — outside this flight's fence, and
reported rather than made.

PR #13372 (the page view-type member) is the reason item 4 exists: its diff on this
package regenerated only those two generated files and never touched SKILL.md, so
the authored table went stale while the generated contract moved. Read before flagging,
as instructed.

Scope

Generated by Claude Code


Generated by Claude Code

…s corrected
Flight ⑤ of the published-skills factual sweep. Every correction is settled
against the implementation (spec Zod schemas in this repo; @object-ui renderer
sources probed read-only in objectui), never against another document.
Three of the seven are one class: "silently dropped" claims that outlived the
protocol-17 strict-unknown-keys cutover, where the schema now REJECTS by name.
Net -12 tokens / -2 lines; no ratchet ceiling touched.
Part of #13658
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
@github-actionsgithub-actionsBot added size/s documentation Improvements or additions to documentation labels Aug 31, 2026
@huangyiirenehuangyiirene added skip-changeset PR has no user-facing published change; bypasses the changeset gate needs:contract-review labels Aug 31, 2026 — with Claude
@huangyiireneClaude

Copy link
Copy Markdown
CollaboratorAuthor

Contract review — PASS at head ec46764f

Applicability: clause-② CONTENT limb (批 #12) — falsifiable operator/contract semantic claims in published skills/**. Both carriers attached in the same stroke the PR existed (PR + card #13772), per 载体纪律 — the deviation flagged on flight ④ did not repeat.

Reviewer qualification, machine-read this sitting: get_sessionexternal_metadata.last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER. Dispatching-seat review permitted per the 2026-08-21 relaxation.

Review: report + diff read; five anchors independently re-measured on origin/main this hour, all corroborating —

  • packages/spec/src/data/date-macros.zod.ts:98–99, 255–257: the four next_*_end tokens are real members with prose descriptions — the 32-token table under a 36-count heading was under-enumerating;
  • packages/spec/src/ui/view.zod.ts:1326: 'page' is a live list-view type member (with the [feature] Give runtime-published custom pages an end-user entry point: a page view type on objects, or nav registration at publish time #13216 mount refusals in both directions);
  • packages/spec/src/ui/chart.zod.ts:115 + chart.test.ts:65: 'combo' is a ChartTypeSchema member with a parse pin;
  • packages/spec/src/ui/object-list-view.test.ts:7–26: the object-view tabs element is "untypable at author time and rejected at [parse]" — the "silently dropped" prose was teaching a no-op where the platform fails loudly;
  • packages/spec/src/ui/dashboard.zod.ts:524–562: the widget grid box is spelled layout (strictObject {x,y,w,h} with alias/guidance walls); a bare position key is not a member — consistent with the probe's unrecognized_keys reading.

The vacuity-trap catch deserves its line: the GanttConfigSchema passthrough acceptance was correctly DISCARDED as measuring nothing, and the claim settled on the declaration instead — confirming, not overturning, the doc. That is the instrument discipline this program exists to exercise. Generated files (contracts/react-blocks.contract.json, references/*) untouched with both sync gates quoted green; objectui probe-read only from a detached worktree, zero edits, no branch pushed.

Budget: net −2 lines / −12 tokens; SKILL.md's zero headroom paid by deleting two genuinely redundant passages — no ceiling touched.

needs:contract-review cleared on BOTH carriers in this stroke. Governed .md content: PR remains DRAFT for the maintainer's merge (os-zhuang / hotlong requested); the review chain never enqueues a governed surface.


Generated by Claude Code

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

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@huangyiirene@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤) by huangyiirene · Pull Request #13777 · objectstack-ai/objectstack · GitHub
Skip to content

docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤) - #13777

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-13772-skills-sweep-ui
Aug 31, 2026
Merged

docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤)#13777
os-zhuang merged 1 commit into
mainfrom
claude/issue-13772-skills-sweep-ui

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes#13772
Part of #13658

Flight ⑤ of the published-skills factual sweep: skills/objectstack-ui/**. Every
behavioral claim was settled against the implementation — the Zod schemas in
packages/spec/src/ui/** and packages/lint/src/** in this repo, and the
@object-ui/* renderer sources probed read-only in a detached objectui worktree —
never against another document.

8 distinct false facts / 8 landing sites, all in SKILL.md.
Net -12 tokens / -2 lines; no ratchet ceiling touched.

The dominant class: three retired "silently dropped" claims

Three of the eight are one defect: the doc teaches that a bad key is silently
dropped
, when the protocol-17 strict-unknown-keys cutover closed those schemas and
they now reject by name. This is the most expensive direction for an AI author —
"silently dropped" says your build succeeds and the key is inert, so the author goes
hunting for a rendering bug; the truth is a loud os validate failure with a
prescription attached.

Per-item: 落点 | before | after

#落点beforeafter
1L328 — object-view userFilters"a tabs element is untypable at author time and dropped at parse""…and rejected at parse, not dropped"
2L689 — legacy inline widget query"the inline fields are dropped and a widget lacking dataset fails os validate""the closed schema REJECTS the inline keys by name, and one lacking dataset fails os validate"
3L2055 — widget position pitfall"there is no position key on a widget, so a position object is silently dropped""position is not a widget key and the closed schema REJECTS it by name (it was silently dropped before protocol 17)"
4L63 — List Views table9 rows; page absentadded page row (pageName; no rows of its own)
5L669 — Widget Types table19 of 20 ChartTypeSchema members; combo absentadded Mixed row for combo
6L1664 — Date macro table, Next period4 tokens (_start only) — table enumerated 32 while the heading says 36next_*_start / _end ×4, matching the sibling rows; table now enumerates all 36
7L1669 — parameterised token grammar"N is any positive integer""N is any non-negative integer"
8L1524 — comparison-overlay stylingdash + opacity: 0.5 claimed "for line/area/scatter"; opacity: 0.4 for bars"muted per family (dashed '4 4' on line/area only; reduced opacity on all)"

Items 4–6 are the hidden-shipped-capability direction flight ② named as the
majority: the surface is live and authorable, and the skill's own table says it is not
there. Item 6 is self-contradicting in place — the heading counts 36, the table lists
32.

Item 8 in detail: packages/plugin-charts/src/AdvancedChartImpl.tsxcomparisonStyle()
gives the dash to line/area only (scatter gets none), and the muted opacity differs
per family (line/scatter stroke 0.5, area fill 0.2, bar fill 0.4). The doc had the two
families crossed. The replacement is true and shorter, so this correction helps pay
for the others.

Payment for the additions (SKILL.md headroom was 0)

The ratchet requires new text to be paid for by genuine deletion in the same file.
Two redundant passages in the timeSegments block paid for items 4–7; no fact was
dropped — both were restatements of rows already in the field table directly above them:

落点beforeafter
L573 — "Calendar-midnight cue" bullet3 lines restating the showMidnight table rowdeleted; its one unique clause ("the 排班日 cell itself stays unbroken") folded into that row
L576 — "Default off = zero regression"2 lines; the tint half restates the bands[].color row"Default off. Omit timeSegments and the gantt renders unsegmented."

Evidence — executed probes

Non-vacuity control satisfied several times over; each probe carries positive and
negative controls.

  • Date macrosDATE_MACRO_TOKENS.length === 36; isDateMacroToken returns
    true for all four next_*_end, false for the control next_fortnight_end,
    true for the control today. {0_days_ago} is accepted, settling item 7.
  • type: 'page'ListViewSchema.safeParse ACCEPTS type:'page' + pageName;
    the control type:'carousel' is REJECTED and its own message enumerates all ten
    members including page.
  • comboChartTypeSchema enumerates 20 members including combo; the
    generated contracts/react-blocks.contract.json already carries it, so the SKILL.md
    table contradicted its own package.
  • tabs rejected, not droppedObjectListViewSchema REJECTS
    userFilters:{element:'tabs'} ("expected one of dropdown|toggle"); controls:
    dropdown ACCEPTED, and page-list ListViewSchema still ACCEPTS tabs. The spec's
    own pin (packages/spec/src/ui/object-list-view.test.ts) says "rejected at parse"
    and records the flip from "drops".
  • position / inline keys rejectedDashboardSchema returns
    unrecognized_keys naming position, and separately object, categoryField,
    valueField, aggregate; controls: a clean dataset+values widget ACCEPTED, a
    widget missing dataset REJECTED for that reason alone.

A vacuity trap caught by a control (worth recording)

GanttConfigSchema.safeParse ACCEPTS timeSegments — but it also accepts a bogus
__zz__ key identically, because that schema is passthrough. The acceptance
measured nothing. Settled instead on the declaration: GanttConfigSchema has 19
declared members and timeSegments is not one (zero hits in packages/spec/src/),
which confirms the doc's existing claim that timeSegments is an ObjectUI display
extension and not upstream spec. VERIFIED, no change.

Gates — union run at ec46764f, this PR's head commit

All 14 families derived from the REAL diff via
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (exit 0; change
set derived by the script from the merge base, not hand-supplied):

gateexit
node scripts/check-ci-filter-parity.mjs0
node scripts/check-cross-package-test-inputs.mjs0
node scripts/check-shard-attestation.mjs0
node scripts/check-skills-token-ratchet.mjs0
node scripts/check-test-completeness.mjs3 — NOT MEASURED by its own verdict text (needs a turbo run test log it cannot produce; "not a red, nothing here to fix")
pnpm --filter @objectstack/lint run check:doc-formula-expressions0 (after building its two prerequisites)
pnpm check:agent-test-spelling0
pnpm check:corpus-claim-drift0
pnpm check:cross-package-test-inputs0
pnpm check:doc-authoring0
pnpm check:pm-governed-merges0
pnpm check:role-word0
pnpm check:skill-compatibility0
pnpm check:skill-frame-sync0

Plus, as the diff implicates them:

  • pnpm --filter @objectstack/spec check:skill-examplesexit 0, fully measured
    after building @objectstack/client-react with declarations. Verdict line: "260
    prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran
    the SEMANTIC pass on all of them". Population check: NON-emptyobjectstack-ui
    carries 11 os:check markers (contrast flight ③'s objectstack-query, which had 0
    and recorded an empty population). Marker count is 11 before and after this diff, and
    a line-level check shows 0 of the 22 changed lines falls inside any fence — the
    marked-example population is byte-identical across this change.
  • pnpm --filter @objectstack/spec check:skill-refs — exit 0, "9 generated files in
    sync with packages/spec".
  • pnpm --filter @objectstack/spec check:react-blocks — exit 0, "2 generated files in
    sync with packages/spec".
  • node scripts/check-nul-bytes.mjs — exit 0, 7578 files scanned. Plus a direct
    control-byte scan of the edited file: clean.

Ratchet, before and after:

before skills/objectstack-ui/SKILL.md 25125 / 25125 (+0, headroom 0)
after skills/objectstack-ui/SKILL.md 25113 / 25125 (-12, headroom 12)

Generated files: measured, not touched

contracts/react-blocks.contract.json and references/react-blocks.md are both
emitted by packages/spec/scripts/build-react-blocks-contract.ts (gen:react-blocks),
and references/_index.md by build-skill-references.ts — all three are
generator-owned and excluded from the ratchet by name. Both sync gates report them
already in sync with packages/spec, so no regeneration was due and nothing was
hand-edited
. Their content is a function of the spec source, so a correction there
would have to land in packages/spec/src/ui/** — outside this flight's fence, and
reported rather than made.

PR #13372 (the page view-type member) is the reason item 4 exists: its diff on this
package regenerated only those two generated files and never touched SKILL.md, so
the authored table went stale while the generated contract moved. Read before flagging,
as instructed.

Scope

Generated by Claude Code


Generated by Claude Code

…s corrected
Flight ⑤ of the published-skills factual sweep. Every correction is settled
against the implementation (spec Zod schemas in this repo; @object-ui renderer
sources probed read-only in objectui), never against another document.
Three of the seven are one class: "silently dropped" claims that outlived the
protocol-17 strict-unknown-keys cutover, where the schema now REJECTS by name.
Net -12 tokens / -2 lines; no ratchet ceiling touched.
Part of #13658
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
@github-actionsgithub-actionsBot added size/s documentation Improvements or additions to documentation labels Aug 31, 2026
@huangyiirenehuangyiirene added skip-changeset PR has no user-facing published change; bypasses the changeset gate needs:contract-review labels Aug 31, 2026 — with Claude
@huangyiireneClaude

Copy link
Copy Markdown
CollaboratorAuthor

Contract review — PASS at head ec46764f

Applicability: clause-② CONTENT limb (批 #12) — falsifiable operator/contract semantic claims in published skills/**. Both carriers attached in the same stroke the PR existed (PR + card #13772), per 载体纪律 — the deviation flagged on flight ④ did not repeat.

Reviewer qualification, machine-read this sitting: get_sessionexternal_metadata.last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER. Dispatching-seat review permitted per the 2026-08-21 relaxation.

Review: report + diff read; five anchors independently re-measured on origin/main this hour, all corroborating —

  • packages/spec/src/data/date-macros.zod.ts:98–99, 255–257: the four next_*_end tokens are real members with prose descriptions — the 32-token table under a 36-count heading was under-enumerating;
  • packages/spec/src/ui/view.zod.ts:1326: 'page' is a live list-view type member (with the [feature] Give runtime-published custom pages an end-user entry point: a page view type on objects, or nav registration at publish time #13216 mount refusals in both directions);
  • packages/spec/src/ui/chart.zod.ts:115 + chart.test.ts:65: 'combo' is a ChartTypeSchema member with a parse pin;
  • packages/spec/src/ui/object-list-view.test.ts:7–26: the object-view tabs element is "untypable at author time and rejected at [parse]" — the "silently dropped" prose was teaching a no-op where the platform fails loudly;
  • packages/spec/src/ui/dashboard.zod.ts:524–562: the widget grid box is spelled layout (strictObject {x,y,w,h} with alias/guidance walls); a bare position key is not a member — consistent with the probe's unrecognized_keys reading.

The vacuity-trap catch deserves its line: the GanttConfigSchema passthrough acceptance was correctly DISCARDED as measuring nothing, and the claim settled on the declaration instead — confirming, not overturning, the doc. That is the instrument discipline this program exists to exercise. Generated files (contracts/react-blocks.contract.json, references/*) untouched with both sync gates quoted green; objectui probe-read only from a detached worktree, zero edits, no branch pushed.

Budget: net −2 lines / −12 tokens; SKILL.md's zero headroom paid by deleting two genuinely redundant passages — no ceiling touched.

needs:contract-review cleared on BOTH carriers in this stroke. Governed .md content: PR remains DRAFT for the maintainer's merge (os-zhuang / hotlong requested); the review chain never enqueues a governed surface.


Generated by Claude Code

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

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@huangyiirene@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤) by huangyiirene · Pull Request #13777 · objectstack-ai/objectstack · GitHub
Skip to content

docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤) - #13777

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-13772-skills-sweep-ui
Aug 31, 2026
Merged

docs(skills): objectstack-ui factual sweep — 8 false behavioral claims corrected (flight ⑤)#13777
os-zhuang merged 1 commit into
mainfrom
claude/issue-13772-skills-sweep-ui

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes#13772
Part of #13658

Flight ⑤ of the published-skills factual sweep: skills/objectstack-ui/**. Every
behavioral claim was settled against the implementation — the Zod schemas in
packages/spec/src/ui/** and packages/lint/src/** in this repo, and the
@object-ui/* renderer sources probed read-only in a detached objectui worktree —
never against another document.

8 distinct false facts / 8 landing sites, all in SKILL.md.
Net -12 tokens / -2 lines; no ratchet ceiling touched.

The dominant class: three retired "silently dropped" claims

Three of the eight are one defect: the doc teaches that a bad key is silently
dropped
, when the protocol-17 strict-unknown-keys cutover closed those schemas and
they now reject by name. This is the most expensive direction for an AI author —
"silently dropped" says your build succeeds and the key is inert, so the author goes
hunting for a rendering bug; the truth is a loud os validate failure with a
prescription attached.

Per-item: 落点 | before | after

#落点beforeafter
1L328 — object-view userFilters"a tabs element is untypable at author time and dropped at parse""…and rejected at parse, not dropped"
2L689 — legacy inline widget query"the inline fields are dropped and a widget lacking dataset fails os validate""the closed schema REJECTS the inline keys by name, and one lacking dataset fails os validate"
3L2055 — widget position pitfall"there is no position key on a widget, so a position object is silently dropped""position is not a widget key and the closed schema REJECTS it by name (it was silently dropped before protocol 17)"
4L63 — List Views table9 rows; page absentadded page row (pageName; no rows of its own)
5L669 — Widget Types table19 of 20 ChartTypeSchema members; combo absentadded Mixed row for combo
6L1664 — Date macro table, Next period4 tokens (_start only) — table enumerated 32 while the heading says 36next_*_start / _end ×4, matching the sibling rows; table now enumerates all 36
7L1669 — parameterised token grammar"N is any positive integer""N is any non-negative integer"
8L1524 — comparison-overlay stylingdash + opacity: 0.5 claimed "for line/area/scatter"; opacity: 0.4 for bars"muted per family (dashed '4 4' on line/area only; reduced opacity on all)"

Items 4–6 are the hidden-shipped-capability direction flight ② named as the
majority: the surface is live and authorable, and the skill's own table says it is not
there. Item 6 is self-contradicting in place — the heading counts 36, the table lists
32.

Item 8 in detail: packages/plugin-charts/src/AdvancedChartImpl.tsxcomparisonStyle()
gives the dash to line/area only (scatter gets none), and the muted opacity differs
per family (line/scatter stroke 0.5, area fill 0.2, bar fill 0.4). The doc had the two
families crossed. The replacement is true and shorter, so this correction helps pay
for the others.

Payment for the additions (SKILL.md headroom was 0)

The ratchet requires new text to be paid for by genuine deletion in the same file.
Two redundant passages in the timeSegments block paid for items 4–7; no fact was
dropped — both were restatements of rows already in the field table directly above them:

落点beforeafter
L573 — "Calendar-midnight cue" bullet3 lines restating the showMidnight table rowdeleted; its one unique clause ("the 排班日 cell itself stays unbroken") folded into that row
L576 — "Default off = zero regression"2 lines; the tint half restates the bands[].color row"Default off. Omit timeSegments and the gantt renders unsegmented."

Evidence — executed probes

Non-vacuity control satisfied several times over; each probe carries positive and
negative controls.

  • Date macrosDATE_MACRO_TOKENS.length === 36; isDateMacroToken returns
    true for all four next_*_end, false for the control next_fortnight_end,
    true for the control today. {0_days_ago} is accepted, settling item 7.
  • type: 'page'ListViewSchema.safeParse ACCEPTS type:'page' + pageName;
    the control type:'carousel' is REJECTED and its own message enumerates all ten
    members including page.
  • comboChartTypeSchema enumerates 20 members including combo; the
    generated contracts/react-blocks.contract.json already carries it, so the SKILL.md
    table contradicted its own package.
  • tabs rejected, not droppedObjectListViewSchema REJECTS
    userFilters:{element:'tabs'} ("expected one of dropdown|toggle"); controls:
    dropdown ACCEPTED, and page-list ListViewSchema still ACCEPTS tabs. The spec's
    own pin (packages/spec/src/ui/object-list-view.test.ts) says "rejected at parse"
    and records the flip from "drops".
  • position / inline keys rejectedDashboardSchema returns
    unrecognized_keys naming position, and separately object, categoryField,
    valueField, aggregate; controls: a clean dataset+values widget ACCEPTED, a
    widget missing dataset REJECTED for that reason alone.

A vacuity trap caught by a control (worth recording)

GanttConfigSchema.safeParse ACCEPTS timeSegments — but it also accepts a bogus
__zz__ key identically, because that schema is passthrough. The acceptance
measured nothing. Settled instead on the declaration: GanttConfigSchema has 19
declared members and timeSegments is not one (zero hits in packages/spec/src/),
which confirms the doc's existing claim that timeSegments is an ObjectUI display
extension and not upstream spec. VERIFIED, no change.

Gates — union run at ec46764f, this PR's head commit

All 14 families derived from the REAL diff via
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (exit 0; change
set derived by the script from the merge base, not hand-supplied):

gateexit
node scripts/check-ci-filter-parity.mjs0
node scripts/check-cross-package-test-inputs.mjs0
node scripts/check-shard-attestation.mjs0
node scripts/check-skills-token-ratchet.mjs0
node scripts/check-test-completeness.mjs3 — NOT MEASURED by its own verdict text (needs a turbo run test log it cannot produce; "not a red, nothing here to fix")
pnpm --filter @objectstack/lint run check:doc-formula-expressions0 (after building its two prerequisites)
pnpm check:agent-test-spelling0
pnpm check:corpus-claim-drift0
pnpm check:cross-package-test-inputs0
pnpm check:doc-authoring0
pnpm check:pm-governed-merges0
pnpm check:role-word0
pnpm check:skill-compatibility0
pnpm check:skill-frame-sync0

Plus, as the diff implicates them:

  • pnpm --filter @objectstack/spec check:skill-examplesexit 0, fully measured
    after building @objectstack/client-react with declarations. Verdict line: "260
    prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran
    the SEMANTIC pass on all of them". Population check: NON-emptyobjectstack-ui
    carries 11 os:check markers (contrast flight ③'s objectstack-query, which had 0
    and recorded an empty population). Marker count is 11 before and after this diff, and
    a line-level check shows 0 of the 22 changed lines falls inside any fence — the
    marked-example population is byte-identical across this change.
  • pnpm --filter @objectstack/spec check:skill-refs — exit 0, "9 generated files in
    sync with packages/spec".
  • pnpm --filter @objectstack/spec check:react-blocks — exit 0, "2 generated files in
    sync with packages/spec".
  • node scripts/check-nul-bytes.mjs — exit 0, 7578 files scanned. Plus a direct
    control-byte scan of the edited file: clean.

Ratchet, before and after:

before skills/objectstack-ui/SKILL.md 25125 / 25125 (+0, headroom 0)
after skills/objectstack-ui/SKILL.md 25113 / 25125 (-12, headroom 12)

Generated files: measured, not touched

contracts/react-blocks.contract.json and references/react-blocks.md are both
emitted by packages/spec/scripts/build-react-blocks-contract.ts (gen:react-blocks),
and references/_index.md by build-skill-references.ts — all three are
generator-owned and excluded from the ratchet by name. Both sync gates report them
already in sync with packages/spec, so no regeneration was due and nothing was
hand-edited
. Their content is a function of the spec source, so a correction there
would have to land in packages/spec/src/ui/** — outside this flight's fence, and
reported rather than made.

PR #13372 (the page view-type member) is the reason item 4 exists: its diff on this
package regenerated only those two generated files and never touched SKILL.md, so
the authored table went stale while the generated contract moved. Read before flagging,
as instructed.

Scope

Generated by Claude Code


Generated by Claude Code

…s corrected
Flight ⑤ of the published-skills factual sweep. Every correction is settled
against the implementation (spec Zod schemas in this repo; @object-ui renderer
sources probed read-only in objectui), never against another document.
Three of the seven are one class: "silently dropped" claims that outlived the
protocol-17 strict-unknown-keys cutover, where the schema now REJECTS by name.
Net -12 tokens / -2 lines; no ratchet ceiling touched.
Part of #13658
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
@github-actionsgithub-actionsBot added size/s documentation Improvements or additions to documentation labels Aug 31, 2026
@huangyiirenehuangyiirene added skip-changeset PR has no user-facing published change; bypasses the changeset gate needs:contract-review labels Aug 31, 2026 — with Claude
@huangyiireneClaude

Copy link
Copy Markdown
CollaboratorAuthor

Contract review — PASS at head ec46764f

Applicability: clause-② CONTENT limb (批 #12) — falsifiable operator/contract semantic claims in published skills/**. Both carriers attached in the same stroke the PR existed (PR + card #13772), per 载体纪律 — the deviation flagged on flight ④ did not repeat.

Reviewer qualification, machine-read this sitting: get_sessionexternal_metadata.last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER. Dispatching-seat review permitted per the 2026-08-21 relaxation.

Review: report + diff read; five anchors independently re-measured on origin/main this hour, all corroborating —

  • packages/spec/src/data/date-macros.zod.ts:98–99, 255–257: the four next_*_end tokens are real members with prose descriptions — the 32-token table under a 36-count heading was under-enumerating;
  • packages/spec/src/ui/view.zod.ts:1326: 'page' is a live list-view type member (with the [feature] Give runtime-published custom pages an end-user entry point: a page view type on objects, or nav registration at publish time #13216 mount refusals in both directions);
  • packages/spec/src/ui/chart.zod.ts:115 + chart.test.ts:65: 'combo' is a ChartTypeSchema member with a parse pin;
  • packages/spec/src/ui/object-list-view.test.ts:7–26: the object-view tabs element is "untypable at author time and rejected at [parse]" — the "silently dropped" prose was teaching a no-op where the platform fails loudly;
  • packages/spec/src/ui/dashboard.zod.ts:524–562: the widget grid box is spelled layout (strictObject {x,y,w,h} with alias/guidance walls); a bare position key is not a member — consistent with the probe's unrecognized_keys reading.

The vacuity-trap catch deserves its line: the GanttConfigSchema passthrough acceptance was correctly DISCARDED as measuring nothing, and the claim settled on the declaration instead — confirming, not overturning, the doc. That is the instrument discipline this program exists to exercise. Generated files (contracts/react-blocks.contract.json, references/*) untouched with both sync gates quoted green; objectui probe-read only from a detached worktree, zero edits, no branch pushed.

Budget: net −2 lines / −12 tokens; SKILL.md's zero headroom paid by deleting two genuinely redundant passages — no ceiling touched.

needs:contract-review cleared on BOTH carriers in this stroke. Governed .md content: PR remains DRAFT for the maintainer's merge (os-zhuang / hotlong requested); the review chain never enqueues a governed surface.


Generated by Claude Code

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

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@huangyiirene@os-zhuang@claude