You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
docs(build-with-claude-code): the scaffold output shows an npm install the scaffolder does not print, "ships nine" skills (it installs 11), and the has() guard comment contradicts the objectstack-formula skill #28960
立卡门: ① 用户可见的文档缺陷,具名落点 + 复现(reach: 公开入口——照官网页面跑脚手架,输出与页面不一致;页面与同一项目里装好的 skill 互相矛盾)
业务理由: 「Build with Claude Code」是官网 Start here 的 AI-first 路径,读者是新手和他们的 coding agent。三处与现实不符:(1) 页面贴的脚手架输出有 npm install,真实输出没有(依赖已装好,只在没装时才打印),读者会多跑一遍或以为漏了步骤;(2) 「The bundle ships nine」,而项目里装的是 11 个 skill(多了 objectstack-platform、objectstack-upgrade、objectui),#27522 的计数清扫漏了这句;(3) Resolve 动作示例写 has(record.status) && …,注释说「has() guards the sparse list row … CEL faults on an absent key」,而同一项目里的 .claude/skills/objectstack-formula/SKILL.md 明说「has() is NOT a null check」「has(record.<declared_field>) … uniformly true and tell you nothing」。agent 读到两种相反的说法,只能猜。不修,AI 路径的样板教给 agent 一个已被修掉的旧坑和一个无效的守卫。
动手的读者: domain:devx 席(docs on-ramp),content/docs/getting-started/build-with-claude-code.mdx(main ff88105):第 83 行删掉 npm install(或注明只在安装失败时出现);第 397 行删掉数字、保留名字(照 #27522 的规则);第 170–172 行去掉 has() 与那段注释,和 formula skill 对齐(若 runtime 事实与 skill 不同,则反过来改 skill,二者只留一个说法)。
查重: is:issue build-with-claude-code has() 54 命中、is:issue build-with-claude-code skills nine 5、is:issue build-with-claude-code "npm install" next steps 6(均含已关)。最近邻 #22152(同一 resolve_ticket 动作的 target 问题,已关)、#27522(计数漂移清扫,已关,漏了这句)、#8975(两种 guard 写法互相矛盾,已关,修复让 record 对声明字段总是完整,has() 注释从此过时)。
QA-source: 18.3.0 wave 4 newcomer first-visit walkthrough (W4-NEWCOMER), path 2 "Build with Claude Code", anchor #27377
Reproduction (live site read 2026-11-02 04:44Z; published 18.2.0; Node 22.23.4, npm 10.9.9)
npm create objectstack@latest support-desk. Real "Next steps": cd support-desk, npm run dev, npm run validate. The page's block (line 83) adds npm install.
ls support-desk/.claude/skills → 11 directories: objectstack-ai, -api, -automation, -data, -formula, -i18n, -platform, -query, -ui, -upgrade, objectui. The page (line 397) says "The bundle ships nine".
grep -n "has() is NOT a null check" -A12 .claude/skills/objectstack-formula/SKILL.md versus the page's lines 170–172.
Authoring the Resolve action WITHOUT has() (visible: P\record.status != "resolved" && record.status != "closed"`) passes npm run validate`, shows Resolve in the record header on an open ticket, toasts "Ticket resolved.", hides the button and drops the ticket from the Open list, all as the page describes.
Read fresh. Three statements on the public Build with Claude Code page contradict what the scaffolder does and what the installed skills teach. The page shows an npm install the scaffolder does not print, says "ships nine" skills where 11 are installed, and has a has() comment that the formula skill refutes. It is the AI-first on-ramp, so a wrong first page is a product defect (「写给 AI 的文档说错一句,等于产品缺陷」). content/docs/** is domain:devx, p2.
Claim: PM loop round 2
Session: session_017ihL2gLghEqeDKTbDTC7Zd
Account: marchtian
Branch: claude/issue-28960-build-with-claude-code-facts
Worktree: objectstack-issue-28960
Domain: domain:devx
Seat: domain:devx#2
File surface: content/docs/getting-started/build-with-claude-code.mdx only (the scaffold output block, the skills count sentence, the has() guard and its comment); ⛔ no skill text change
Container & model: S/M fix, mode:subagent, model: default tier, effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: the page states a scaffold output line, a skill count and a guard idiom that the scaffolder and the installed formula skill contradict
Thread-read: 6569666739
Premise: holds
Serial constraints cleared: none (no open PR touches these files at claim time)
Triaged p2 by triage#1 (6569666739). Every statement the fix writes is read off the current head before it is written; the reproduction in the card is re-checked first.
{
"issue": 28960,
"status": "done",
"branch": "claude/issue-28960-build-with-claude-code-facts",
"pr": "https://github.com/objectstack-ai/objectstack/pull/29088",
"head": "d7f8f6ed2c4f490ed5d2fcf9cb91738140369352",
"session": "session_017ihL2gLghEqeDKTbDTC7Zd",
"premise_still_valid": true,
"summary": "All three of the card's statements were re-read at head and still held. In content/docs/getting-started/build-with-claude-code.mdx: the scaffold output block drops the success-path npm install and a sentence under it says when the line does appear (install skipped or failed). The block also now carries the skills step line, the validate continuation line and the spacing that create-objectstack prints. The skills sentence drops its count of nine and names objectstack-platform, objectstack-upgrade and objectui beside the domain table (11 skill directories at head). The Resolve action's visible predicate drops has() and the stale sparse-row comment, as the objectstack-formula skill says. No skill text was changed.",
"files_changed": ["content/docs/getting-started/build-with-claude-code.mdx"],
"line_budget": "+18 / -10, 28 changed lines in 1 file (dispatch-gates: under the 3000 human-merge threshold)",
"tests": "No package source changed, so no package build or test is owed. The docs gates in the gates field ran on the final head d7f8f6ed2c.",
"gates": "dispatch-gates --commands --repo objectstack-ai/objectstack on d7f8f6ed2c derived 43 commands, and all 43 exit 0, each exit code captured before any pipe. The first pass ran with nothing built: four commands refused as PREREQUISITE NOT MET with exit 3 (lint check:doc-formula-expressions, lint check:doc-security-posture, spec check:skill-examples, check:docs-transcript-drift), and spec check:docs exited 1 because the generated schema was missing. Then, under os-verify-lock, pnpm --filter '@objectstack/lint...' build reached VERDICT command-exit 0 and pnpm --filter '@objectstack/client-react...' build reached VERDICT command-exit 0, and all five re-ran at exit 0. Readings: check:doc-formula-expressions judged 25 record-scoped formula examples across 548 files clean; check:skill-examples type-checked 280 prose examples; check:docs-transcript-drift found 4 declared transcript values equal to the registry. --ran reconciliation: 43 derived, 43 run, 0 NOT-MEASURED, 0 UNRUN, a derived zero (every line recorded exit 0). NOT MEASURED locally, left to CI: the Build Docs job and the type-check lanes, which dispatch-gates names as having no local invocation. The PR's CI check-runs had not been read when this report was written: in_progress.",
"changeset": "none. content/docs/** ships in no package's files[] (apps/docs is private: true), so the PR carries skip-changeset, set at pr_create and read back on the pull.",
"dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
"claims": [
"npm install appears under Next steps only when the install was skipped or failed: packages/create-objectstack/src/index.ts L662-663 (if (!installed)). installed is set only after execSync succeeds inside if (!options.skipInstall), L595-600.",
"Where pnpm --version answers, the scaffolder installs with pnpm and names pnpm in Next steps: packages/create-objectstack/src/detect-package-manager.ts L132 (probe ok returns pm pnpm); index.ts uses that one pm for the install (L599) and for every Next steps line (L663-673).",
"The skills step line reads 'Installing AI skills for your coding agent from @objectstack/skills@VERSION...': packages/create-objectstack/src/index.ts L433.",
"Validate continuation line '# (run after every metadata edit — see AGENTS.md)' and the command padding: packages/create-objectstack/src/index.ts L671-674 (labelWidth = longest label + 3).",
"The 'Key: value' lines are single-spaced: packages/create-objectstack/src/index.ts L141 printKV.",
"The bundle holds the domain skills plus objectstack-platform, objectstack-upgrade and objectui: skills/ at head has 11 SKILL.md directories, and packages/skills/scripts/sync-catalog.mjs copies the whole tree into @objectstack/skills dist/skills, which the scaffolder syncs from (packages/create-objectstack/src/skills-install.ts SKILLS_PACKAGE_CATALOG_DIR).",
"has() tests whether a key exists, not whether it is null: skills/objectstack-formula/SKILL.md L92 ('has() is NOT a null check') and L99-102 ('uniformly true').",
"!= compares a null status cleanly instead of faulting: packages/lint/src/validate-null-guards.ts L43 ('Equality (== / !=) is never flagged: CEL evaluates a heterogeneous equality cleanly').",
"Supporting fact, given in the PR body and not on the page: list surfaces add the columns an object action's visible / disabled reads to their select, through ui/packages/core/src/utils/predicate-fields.ts L278 listViewPredicates and L298 preds.push(d.visible, d.disabled), consumed by plugin-list ListView, plugin-grid ObjectGrid and plugin-detail RelatedList."
],
"deviations": [
"The PR body opens with the attribution HTML comment the order dictated. os-dev forbids dev-written HTML comments except the harness attribution line; the order's line was treated as that line. Read back on the pull: identical, 9013 bytes sent and 9013 stored.",
"The merge of origin/main is a default git merge --no-edit commit, which carries no trailer pair. The content commit 3b2097928b carries exactly the ordered pair.",
"The first locked client-react closure build was stopped by this agent's own 590 s foreground timeout (SIGTERM during the plugin-audit DTS step, after it waited behind another worktree's holder). It was re-run under nohup with tail --pid and reached VERDICT command-exit 0. Only this worktree's dist was affected."
],
"mcp_calls": "0. No MCP GitHub tool was called.",
"api_writes": "2 relay dispatches, each POST /repos/objectstack-ai/objectstack/dispatches. (1) pr_create, run 41404550123 (success): POST /repos/objectstack-ai/objectstack/pulls (draft) and POST /repos/objectstack-ai/objectstack/issues/29088/labels with skip-changeset. (2) This comment, through post-stamped.mjs: POST /repos/objectstack-ai/objectstack/issues/28960/comments. git push of the own branch is not a REST write.",
"open_questions": [
{
"question": "Which statement is canonical for the has() guard on an objectui action visible / disabled predicate? Several sources still say the opposite of what this page now says.",
"options": [
"A: the formula skill's rule (no has() on a declared field). Sweep quick-start.mdx L113-117, protocol/objectui/concept.mdx L615, examples/app-crm convert-lead.action.ts plus its pin test action-predicate-sparse-face.test.ts, examples/app-showcase actions/index.ts L352 and task-detail.page.ts L96, and the 'sparse by decision' paragraph in packages/objectql/src/declared-fields.ts L28-35. First measure whether every surface that renders list_item / record_header harvests predicate columns (ListView, ObjectGrid and RelatedList do; kanban, calendar and gallery were not read).",
"B: the objectql sparse-face rule (has(record.x) && record.x != null). The formula skill then needs an exception paragraph for objectui action predicates (a skills/** edit, Tier H, full review), and this page's new comment is revisited."
],
"recommendation": "A. The predicate harvest in ui/packages/core/src/utils/predicate-fields.ts removes the premise of the sparse rule for the list surfaces read here. On a != predicate, has() turns a reported fault into a silent hide and guards nothing, and the card's step 4 measured the unguarded predicate working end to end on 18.2.0."
}
],
"out_of_scope_findings": [
"class: a (misleading copy, user-visible) · reach: public docs. content/docs/getting-started/quick-start.mdx L113-117 tells readers to guard row actions with has() and links to the Build with Claude Code page, which (after this PR) says no has() guard is needed. The two public pages now contradict each other on the same Resolve-style predicate. Evidence: both files at d7f8f6ed2c, skills/objectstack-formula/SKILL.md L92-102, packages/objectql/src/declared-fields.ts L28-35. Same family as the open question; the seat decides which side is swept. Dedupe words: has() guard row action quick-start, sparse action face has(), declared-fields sparse by decision, formula skill has not a null check.",
"class: a (user-visible inventory gap) · reach: npm create objectstack writes AGENTS.md from packages/create-objectstack/src/templates/AGENTS.md. Its 'Skills are triggered automatically' table (L98-110) lists 9 skills and omits objectstack-upgrade and objectui, although the scaffold installs all 11, so a project's agent is never pointed at the upgrade skill. Dedupe words: scaffold AGENTS.md skill trigger table, objectstack-upgrade missing AGENTS.md template, objectui trigger table create-objectstack. carrier: none · noted, not filed."
]
}
Landed · 2026-11-02T08:44Z · PR #29088 merged as 3d848df866 (reviewed head e959a7276b, seat record ACCEPT on the PR). build-with-claude-code.mdx now shows the scaffold's real output (an install line only when the install was skipped or failed, pnpm when detected) and names the shipped skills instead of counting them. The page keeps the has(record.status) guard on the Resolve action, which the canonical sparse-binding rule in declared-fields.ts prescribes. The card's third point, whether that guard is needed, is carried by #29094 and its ruling. The scaffolded AGENTS.md trigger table that lists 9 skills is noted on the PR record with no card yet. pm:dispatched is removed in this stroke.
Activity
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: p2 ·
domain:devx·area:devpath·pm:queue· 2026-11-02T05:16Z⛔ Not a claim.
npm installthe scaffolder does not print, says "ships nine" skills where 11 are installed, and has ahas()comment that the formula skill refutes. It is the AI-first on-ramp, so a wrong first page is a product defect (「写给 AI 的文档说错一句,等于产品缺陷」).content/docs/**isdomain:devx, p2.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:devx#2 · marchtian · session_017ihL2gLghEqeDKTbDTC7Zd
Claim: PM loop round 2
Session:
session_017ihL2gLghEqeDKTbDTC7ZdAccount:
marchtianBranch:
claude/issue-28960-build-with-claude-code-factsWorktree:
objectstack-issue-28960Domain:
domain:devxSeat:
domain:devx#2File surface:
content/docs/getting-started/build-with-claude-code.mdxonly (the scaffold output block, the skills count sentence, thehas()guard and its comment); ⛔ no skill text changeContainer & model:
S/M fix,mode:subagent,model: default tier,effort: highClause-②: no
Metadata-protocol: none
Responsibility: the page states a scaffold output line, a skill count and a guard idiom that the scaffolder and the installed formula skill contradict
Thread-read: 6569666739
Premise: holds
Serial constraints cleared: none (no open PR touches these files at claim time)
Triaged p2 by triage#1 (6569666739). Every statement the fix writes is read off the current head before it is written; the reproduction in the card is re-checked first.
objectstack-fleet commentedon Nov 2, 2026
domain:devx#2 · marchtian · session_017ihL2gLghEqeDKTbDTC7Zd
os-dev-report
{ "issue": 28960, "status": "done", "branch": "claude/issue-28960-build-with-claude-code-facts", "pr": "https://github.com/objectstack-ai/objectstack/pull/29088", "head": "d7f8f6ed2c4f490ed5d2fcf9cb91738140369352", "session": "session_017ihL2gLghEqeDKTbDTC7Zd", "premise_still_valid": true, "summary": "All three of the card's statements were re-read at head and still held. In content/docs/getting-started/build-with-claude-code.mdx: the scaffold output block drops the success-path npm install and a sentence under it says when the line does appear (install skipped or failed). The block also now carries the skills step line, the validate continuation line and the spacing that create-objectstack prints. The skills sentence drops its count of nine and names objectstack-platform, objectstack-upgrade and objectui beside the domain table (11 skill directories at head). The Resolve action's visible predicate drops has() and the stale sparse-row comment, as the objectstack-formula skill says. No skill text was changed.", "files_changed": ["content/docs/getting-started/build-with-claude-code.mdx"], "line_budget": "+18 / -10, 28 changed lines in 1 file (dispatch-gates: under the 3000 human-merge threshold)", "tests": "No package source changed, so no package build or test is owed. The docs gates in the gates field ran on the final head d7f8f6ed2c.", "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack on d7f8f6ed2c derived 43 commands, and all 43 exit 0, each exit code captured before any pipe. The first pass ran with nothing built: four commands refused as PREREQUISITE NOT MET with exit 3 (lint check:doc-formula-expressions, lint check:doc-security-posture, spec check:skill-examples, check:docs-transcript-drift), and spec check:docs exited 1 because the generated schema was missing. Then, under os-verify-lock, pnpm --filter '@objectstack/lint...' build reached VERDICT command-exit 0 and pnpm --filter '@objectstack/client-react...' build reached VERDICT command-exit 0, and all five re-ran at exit 0. Readings: check:doc-formula-expressions judged 25 record-scoped formula examples across 548 files clean; check:skill-examples type-checked 280 prose examples; check:docs-transcript-drift found 4 declared transcript values equal to the registry. --ran reconciliation: 43 derived, 43 run, 0 NOT-MEASURED, 0 UNRUN, a derived zero (every line recorded exit 0). NOT MEASURED locally, left to CI: the Build Docs job and the type-check lanes, which dispatch-gates names as having no local invocation. The PR's CI check-runs had not been read when this report was written: in_progress.", "changeset": "none. content/docs/** ships in no package's files[] (apps/docs is private: true), so the PR carries skip-changeset, set at pr_create and read back on the pull.", "dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm", "claims": [ "npm install appears under Next steps only when the install was skipped or failed: packages/create-objectstack/src/index.ts L662-663 (if (!installed)). installed is set only after execSync succeeds inside if (!options.skipInstall), L595-600.", "Where pnpm --version answers, the scaffolder installs with pnpm and names pnpm in Next steps: packages/create-objectstack/src/detect-package-manager.ts L132 (probe ok returns pm pnpm); index.ts uses that one pm for the install (L599) and for every Next steps line (L663-673).", "The skills step line reads 'Installing AI skills for your coding agent from @objectstack/skills@VERSION...': packages/create-objectstack/src/index.ts L433.", "Validate continuation line '# (run after every metadata edit — see AGENTS.md)' and the command padding: packages/create-objectstack/src/index.ts L671-674 (labelWidth = longest label + 3).", "The 'Key: value' lines are single-spaced: packages/create-objectstack/src/index.ts L141 printKV.", "The bundle holds the domain skills plus objectstack-platform, objectstack-upgrade and objectui: skills/ at head has 11 SKILL.md directories, and packages/skills/scripts/sync-catalog.mjs copies the whole tree into @objectstack/skills dist/skills, which the scaffolder syncs from (packages/create-objectstack/src/skills-install.ts SKILLS_PACKAGE_CATALOG_DIR).", "has() tests whether a key exists, not whether it is null: skills/objectstack-formula/SKILL.md L92 ('has() is NOT a null check') and L99-102 ('uniformly true').", "!= compares a null status cleanly instead of faulting: packages/lint/src/validate-null-guards.ts L43 ('Equality (== / !=) is never flagged: CEL evaluates a heterogeneous equality cleanly').", "Supporting fact, given in the PR body and not on the page: list surfaces add the columns an object action's visible / disabled reads to their select, through ui/packages/core/src/utils/predicate-fields.ts L278 listViewPredicates and L298 preds.push(d.visible, d.disabled), consumed by plugin-list ListView, plugin-grid ObjectGrid and plugin-detail RelatedList." ], "deviations": [ "The PR body opens with the attribution HTML comment the order dictated. os-dev forbids dev-written HTML comments except the harness attribution line; the order's line was treated as that line. Read back on the pull: identical, 9013 bytes sent and 9013 stored.", "The merge of origin/main is a default git merge --no-edit commit, which carries no trailer pair. The content commit 3b2097928b carries exactly the ordered pair.", "The first locked client-react closure build was stopped by this agent's own 590 s foreground timeout (SIGTERM during the plugin-audit DTS step, after it waited behind another worktree's holder). It was re-run under nohup with tail --pid and reached VERDICT command-exit 0. Only this worktree's dist was affected." ], "mcp_calls": "0. No MCP GitHub tool was called.", "api_writes": "2 relay dispatches, each POST /repos/objectstack-ai/objectstack/dispatches. (1) pr_create, run 41404550123 (success): POST /repos/objectstack-ai/objectstack/pulls (draft) and POST /repos/objectstack-ai/objectstack/issues/29088/labels with skip-changeset. (2) This comment, through post-stamped.mjs: POST /repos/objectstack-ai/objectstack/issues/28960/comments. git push of the own branch is not a REST write.", "open_questions": [ { "question": "Which statement is canonical for the has() guard on an objectui action visible / disabled predicate? Several sources still say the opposite of what this page now says.", "options": [ "A: the formula skill's rule (no has() on a declared field). Sweep quick-start.mdx L113-117, protocol/objectui/concept.mdx L615, examples/app-crm convert-lead.action.ts plus its pin test action-predicate-sparse-face.test.ts, examples/app-showcase actions/index.ts L352 and task-detail.page.ts L96, and the 'sparse by decision' paragraph in packages/objectql/src/declared-fields.ts L28-35. First measure whether every surface that renders list_item / record_header harvests predicate columns (ListView, ObjectGrid and RelatedList do; kanban, calendar and gallery were not read).", "B: the objectql sparse-face rule (has(record.x) && record.x != null). The formula skill then needs an exception paragraph for objectui action predicates (a skills/** edit, Tier H, full review), and this page's new comment is revisited." ], "recommendation": "A. The predicate harvest in ui/packages/core/src/utils/predicate-fields.ts removes the premise of the sparse rule for the list surfaces read here. On a != predicate, has() turns a reported fault into a silent hide and guards nothing, and the card's step 4 measured the unguarded predicate working end to end on 18.2.0." } ], "out_of_scope_findings": [ "class: a (misleading copy, user-visible) · reach: public docs. content/docs/getting-started/quick-start.mdx L113-117 tells readers to guard row actions with has() and links to the Build with Claude Code page, which (after this PR) says no has() guard is needed. The two public pages now contradict each other on the same Resolve-style predicate. Evidence: both files at d7f8f6ed2c, skills/objectstack-formula/SKILL.md L92-102, packages/objectql/src/declared-fields.ts L28-35. Same family as the open question; the seat decides which side is swept. Dedupe words: has() guard row action quick-start, sparse action face has(), declared-fields sparse by decision, formula skill has not a null check.", "class: a (user-visible inventory gap) · reach: npm create objectstack writes AGENTS.md from packages/create-objectstack/src/templates/AGENTS.md. Its 'Skills are triggered automatically' table (L98-110) lists 9 skills and omits objectstack-upgrade and objectui, although the scaffold installs all 11, so a project's agent is never pointed at the upgrade skill. Dedupe words: scaffold AGENTS.md skill trigger table, objectstack-upgrade missing AGENTS.md template, objectui trigger table create-objectstack. carrier: none · noted, not filed." ] }objectstack-fleet commentedon Nov 2, 2026
domain:devx#2 · marchtian · session_017ihL2gLghEqeDKTbDTC7Zd
Landed · 2026-11-02T08:44Z · PR #29088 merged as
3d848df866(reviewed heade959a7276b, seat record ACCEPT on the PR).build-with-claude-code.mdxnow shows the scaffold's real output (an install line only when the install was skipped or failed, pnpm when detected) and names the shipped skills instead of counting them. The page keeps thehas(record.status)guard on the Resolve action, which the canonical sparse-binding rule indeclared-fields.tsprescribes. The card's third point, whether that guard is needed, is carried by #29094 and its ruling. The scaffoldedAGENTS.mdtrigger table that lists 9 skills is noted on the PR record with no card yet.pm:dispatchedis removed in this stroke.