Repository navigation
[finding] docs(getting-started): the Build-with-Claude-Code tutorial's resolve_ticket action names a target handler nothing registers — the "Resolve" button it tells you to verify in the Console is the dead-button trap the Actions page warns about #22152
Description
Activity
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsPath: the road — start: the tutorial builds a working app | 缺项 | P2
Triage: first grade,
bug·priority:p2·domain:devx·area:devpath·pm:queue(findingremoved). Direction: the tutorial's action does what it says, and the page tells the reader how to checkTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-08T05:00Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in
content/docs/getting-started/build-with-claude-code.mdx(steps 3 and 5) and the mirrored example onquick-start.mdx⇒domain:devx; rationale:content/docs/**is that lane's. Read onmainec8f37c890.- Why p2: a newcomer who copies the tutorial gets a Resolve button that does nothing;
os devwarns about it, but the page tells them to verify it (measured). - Direction:
- give
resolve_ticketa handler the tutorial also writes, or make it a declarative action that needs none - step 5's check exercises the button and names what to expect
- give
- Not this card: an authoring-time refusal of a script action with no handler (a
packages/lintrule) would be a new gate, so it defaults to no. Clause-②: no. No changeset (docs).
- Why p2: a newcomer who copies the tutorial gets a Resolve button that does nothing;
- addedarea:devpathThe road — create, dev, verify, publish/install, connect an agent, iterateThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingSomething isn't workingpriority:p2Medium: important, M3Medium: important, M3and removed
on Oct 8, 2026 objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsClaim: PM loop round 8 · anchor of a two-card bundle (#22152 + #22165): both edit the getting-started pages, so they are carried by one PR
Session:session_01VF48aw8RPG6wzDnMgp6rtw
Account:os-justin(the seat's linked user asGET /useranswers it; the cards' assignee)
Branch:claude/issue-22152-getting-started-on-ramp(new, cut fromorigin/main6ed0c0f3e5)
Worktree:objectstack-issue-22152
Domain:domain:devx
Seat:domain:devx#2
Cards closed by the one PR: #22152 (p2, this anchor) and #22165 (p3, the maintainer's ③; a pointer claim is on that card).
File surface:content/docs/getting-started/build-with-claude-code.mdx(steps 3 and 5) and the mirrored example onquick-start.mdx([finding] docs(getting-started): the Build-with-Claude-Code tutorial'sresolve_ticketaction names atargethandler nothing registers — the "Resolve" button it tells you to verify in the Console is the dead-button trap the Actions page warns about #22152): the tutorial'sresolve_ticketaction does what it says, and step 5's check names what to expect.content/docs/getting-started/index.mdx, one routing line at the top ([maintainer] docs(getting-started): four overlapping entry pages (How AI development works / Build with Claude Code / Your First Project / Anatomy) — add one routing line at the top of the index so a newcomer does not have to choose #22165), with the four entry pages' opening callouts following it:how-ai-development-works.mdx,build-with-claude-code.mdx,your-first-project.mdx,quick-start.mdx.- ⛔ No new lint rule (triage: a new gate defaults to no). ⛔ Not here: [finding] docs on-ramp drift a first-time reader hits in sequence: stale CONTRIBUTING.md (retired
specrepo), README's firstcurlgets 401, three pnpm floors, "three examples" vs five,os dev --help/os initstrings, tutorial transcript #22156's items onindex.mdx,examples.mdxandbuild-with-claude-code.mdx; [finding] docs on-ramp drift a first-time reader hits in sequence: stale CONTRIBUTING.md (retiredspecrepo), README's firstcurlgets 401, three pnpm floors, "three examples" vs five,os dev --help/os initstrings, tutorial transcript #22156 is serial after this PR. - Stop on a breach and explain it in the report.
Container & model:M,mode:subagent,model: opus(dispatch-gates --tier: no path-derived mandate; default tier; a tutorial must be run, not read)
Clause-②: no
Responsibility: the getting-started tutorial and entry pages (this repo'scontent/docs/**) | none | every newcomer who copies the tutorial
Thread-read: 6052646397
Serial constraints cleared: - No open PR touches
content/docs/getting-started/**(all open PRs' file lists read this round). - The [finding] README's
pnpm install && pnpm build && pnpm devserves no Console on a fresh clone:/_console/and/answer 404, and the boot warning names a remedy that does not exist in this repo #22155 bundle holdsREADME.mdandserve.ts; no shared file.
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 22152,
"status": "done",
"branch": "claude/issue-22152-getting-started-on-ramp",
"pr": "#22204",
"session": "session_01VF48aw8RPG6wzDnMgp6rtw (subagent run: the parent PM session id, as the Claude-Session trailer on both commits records)",
"premise_still_valid": true,
"summary": "Bundle #22152 + #22165 in one draft PR (#22204, docs only, 5 files under content/docs/getting-started/, +64/-25, BASE c6fe02d, head 9bfd965). #22152: the tutorial's resolve_ticket is now the declarative single-record write (operation: 'update' + patch: { status: 'resolved' }, type left at its default) instead of type: 'script' + an unregistered target; a paragraph under step 3 says what it does and what a target handler would need; step 5 asks the reader to click Resolve and names the toast, the status change, the button disappearing and the ticket leaving Support → Open. #22165: index.mdx opens with the maintainer's routing line (agent writes the app → Build with Claude Code; by hand, every file → Your First Project) and the four entry pages' opening callouts follow it in one shape (agent path / by-hand path / the map, not a starting point / the why, not a starting point), each linking back to it. Route choice, measured in a project scaffolded from the published create-objectstack@17.7.0: the declarative route is a 4-line change with no new file and no config edit; the handler route needs a handler file plus an onEnable export in objectstack.config.ts, which contradicts the page's own 'the config is not edited' paragraph, and its ctx.engine runs elevated. The handler route was costed from the scaffolded config, not booted. Mechanism assumption 3 partly falsified: quick-start.mdx carries no action code (no defineAction, no target, no type: 'script'); the mirror is its Actions reading bullet, which now tells a reviewer to check what a click does and that an unregistered target passes os validate and is named only by the os dev boot warning. Assumptions 1, 2 and 4 held as written. No new lint rule; #22156's items untouched. Deviation to note: os dev on this host generated /root/.objectstack/dev-crypto-key (a dev-only key the CLI persists for every later os dev on the host); left in place because a dev server started after mine may have loaded it. The scaffolded scratch project and the worktree are removed after this report.",
"tests": "Scaffold: npx create-objectstack@17.7.0 support-desk --template blank --skip-skills (exit 0); step 3's four files extracted VERBATIM from the page by script, plus the four barrel export lines; extraction from head 9bfd965 is byte-identical to the measured files (diff -r clean). BEFORE (main page): os validate → 'Validation passed', 'Data: 2 Objects 6 Fields', 'UI: 1 Apps 1 Views 1 Actions'; os dev --ui boot diagnostics 4 warnings incl. 'WARN [action-governance] declared script actions with NO handler ... {"count":1,"actions":["support_desk_ticket:resolve_ticket"]}'; POST /api/v1/actions/support_desk_ticket/resolve_ticket {recordId} → HTTP 404 RESOURCE_NOT_FOUND 'Action resolve_ticket on object support_desk_ticket not found', status stays open. AFTER (this branch): os validate → 'Validation passed (211ms)', same counts; tsc --noEmit in the project exit 0; os dev --ui boot diagnostics 3 warnings, grep -c action-governance = 0; same POST → HTTP 200 {"success":true,"data":{"operation":"update",...,"status":"resolved"}}, GET reads status resolved. Console (headless Chromium /opt/pw-browsers/chromium, the console shipped in @objectstack/cli 17.7.0): create a ticket via the Create Ticket form, the record opens; Resolve buttons before = 1; click Resolve → toast 'Ticket resolved.' seen; STATUS reads Resolved; Resolve buttons after = 0; the Console POSTed /api/v1/actions/support_desk_ticket/resolve_ticket → 200; after reload the ticket is absent from Support → Open (rows matching subject = 0). MCP run_action via an API key (tools/call run_action resolve_ticket) → "ok": true, "operation": "update"; GET reads status resolved. Step 4 still holds: a bare visible: 'status != "resolved"' on the declarative action → os validate exit 1 with the page's message (bare reference status ... Write record.status; rule: expression-invalid); restored and re-checked by grep count. Gates: node scripts/pm/dispatch-gates.mjs --commands at head derived the same 40 commands as at dispatch; all 40 run after the final commit at 9bfd965, all exit 0; dispatch-gates --ran: '40 derived, 40 run, 0 NOT-MEASURED, 0 UNRUN' (derived zero, every line carries its exit code). First pass: check:docs-transcript-drift and check:skill-examples exited 3 PREREQUISITE NOT MET (lint / client-react unbuilt) → built pnpm --filter '@objectstack/lint...' and '@objectstack/client-react...' through os-verify-lock.sh (VERDICT command-exit 0 both) and re-ran green. check:doc-anchors: 460 fragment links all resolve (incl. the new /docs/ui/actions#give-it-server-behavior--two-paths). check:nul-bytes green; control-byte grep over the 5 pages: no hits. @mdx-js/mdx 3.1.1 compiles all 5 pages. No package touched, so no build/test/typecheck owed; no changeset (docs only, skip-changeset). Reverse verification = the BEFORE column: the only difference between the two runs is the page's action block.",
"mcp_calls": "0",
"api_writes": "3 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]) carrying 4 writes: POST /repos/objectstack-ai/objectstack/pulls (pr_create, draft, #22204, body read back identical); POST /repos//issues/22204/labels (skip-changeset); POST /repos//issues/22204/assignees (os-justin); POST /repos//issues/22152/comments (this os-dev-report). Plus 2 git pushes (not REST). Local-only: POST /api/v1/keys on the scratch dev server (localhost, not GitHub).",
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: public door, measured once - the Console Create Ticket form (console shipped in @objectstack/cli 17.7.0) renders Priority and Status as "Select an option", both required, although each declares an option with default: true; REST POST /api/v1/data/support_desk_ticket without status stores open (the declared default), so only the form ignores it · evidence: the tutorial's verbatim ticket object in a fresh create-objectstack@17.7.0 project, headless Chromium, New → Create Ticket; objectui-side reader, not re-measured against the current pin · dedupe words: console create form select option default true not preselected; picklist default value form required; Field.select options default",
"class: a · reach: public door, measured twice - os dev --ui on a freshly scaffolded create-objectstack@17.7.0 blank project (empty .objectstack/data, 2 of 2 fresh boots) lists in its boot diagnostics WARN Insert operation failed {"object":"sys_migration","error":{"message":"UNIQUE constraint failed: sys_migration.id ..."}} with a full knex stack; not re-measured on main, cause not investigated · dedupe words: sys_migration UNIQUE constraint failed boot warning; Insert operation failed sys_migration fresh database; migration recovery duplicate insert os dev",
"carrier: #22156 item 6 (serial after this PR, devx seat) · noted, not filed - the field-no-consumers verdict on the tutorial's description field reads "nothing in this stack reads or displays it ... inert", yet the Console Create Ticket form renders a Description textarea (measured); recorded in PR #22204 Acceptance notes so whoever takes item 6 picks between placing description on a view and showing the warning with this measurement in hand"
]
}objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsACCEPT — PR #22204 (bundle #22152 + #22165) ·
domain:devx#2· 2026-10-08T06:44ZSeat review of PR #22204 against GitHub, at head
9bfd965329. Report: theos-dev-reporton this card. Claims:6053072940(this card) and the member claim on #22165.Checklist conclusions
- Shape: draft PR to
main. Body line 1 isFixes #22152and line 2 isFixes #22165, with no other closing keyword; [finding] docs on-ramp drift a first-time reader hits in sequence: stale CONTRIBUTING.md (retiredspecrepo), README's firstcurlgets 401, three pnpm floors, "three examples" vs five,os dev --help/os initstrings, tutorial transcript #22156 is untouched.Clause-②: nois at line start. Both closed cards carry aClaim:naming the head branch, so the closing-target claim guard is satisfied. - Files: five pages under
content/docs/getting-started/(+64 −25):build-with-claude-code.mdx,how-ai-development-works.mdx,index.mdx,quick-start.mdxandyour-first-project.mdx, the claim's surface.- No lint rule was added.
skip-changesetis correct (docs only).
- No lint rule was added.
- [finding] docs(getting-started): the Build-with-Claude-Code tutorial's
resolve_ticketaction names atargethandler nothing registers — the "Resolve" button it tells you to verify in the Console is the dead-button trap the Actions page warns about #22152, read in the diff:ResolveTicketActiondropstype: 'script'+target: 'resolveTicket'and becomes the declarative single-record writeoperation: 'update'+patch: { status: 'resolved' }. A new paragraph says what the click does, and what atargethandler would need.- Checked against
main's spec (packages/spec/src/ui/action.zod.ts:1136,:1155):patchis "written on the data plane as the caller: object permissions, hooks and validations fire as for a user edit". So the page's "runs as the signed-in user" sentence is the spec's own. - Step 5 now has the reader click Resolve, and names the toast, the status change, the button hiding and the ticket leaving Support → Open.
- Checked against
- Route choice, measured in a project scaffolded from
create-objectstack@17.7.0: the declarative route is a 4-line change with no new file. The handler route needs a handler file plus anonEnableexport inobjectstack.config.ts, which contradicts the page's own "the config is not edited". It was costed from the config, not booted. - Before and after, on the verbatim page files:
- Before:
os validatepasses; the boot log warns[action-governance] … NO handler;POST /api/v1/actions/support_desk_ticket/resolve_ticketreturns 404 "not found". - After:
os validatepasses with the same counts; the boot log has 0action-governancelines; the same POST returns 200 withstatus: resolved. - In the Console (headless Chromium): clicking Resolve shows the "Ticket resolved." toast; Status reads Resolved; the Resolve buttons go from 1 to 0; after a reload the ticket is gone from Support → Open.
- The step-4 predicate trap still refuses at
os validate.
- Before:
- Zone 2 assumption 3, partly falsified and accepted:
quick-start.mdxcarries no action code. Its mirror is the Actions reading bullet, which now tells a reviewer to check what a click does. - [maintainer] docs(getting-started): four overlapping entry pages (How AI development works / Build with Claude Code / Your First Project / Anatomy) — add one routing line at the top of the index so a newcomer does not have to choose #22165:
index.mdxopens with the maintainer's routing line (agent writes the app → Build with Claude Code; by hand, every file → Your First Project). The four entry pages' opening callouts follow one shape and link back to it. - Gates: 40 derived, 40 run, all exit 0.
check:docs-transcript-driftandcheck:skill-examplesfirst exited 3 (prerequisite not met);lintandclient-reactwere built under the verify lock and both re-ran green.check:doc-anchorsresolves 460 fragment links, including the new/docs/ui/actions#give-it-server-behavior--two-paths. - CI at head
9bfd965329: 26 success, 10 skipped (path-filtered: Build Core, Temporal and the dogfood matrix; Check Changeset underskip-changeset), 0 red. Every required context is green:Lint & Repo Gates,TypeScript Type Check,Test Core,Dogfood Regression GateandGoverned Surface Queue Guard. The only non-green item is Vercel's preview status, which is not required.check-governed-merges --pr 22204: NOT governed, 89 changed lines.
Deviation, accepted:
os devon this host created/root/.objectstack/dev-crypto-key, a dev-only key the CLI persists. It was left in place, since another dev server may have loaded it, and it touches no repo state.Out-of-scope findings:
- Console create form ignores an option's
default: trueon a required select (measured on the Console shipped in@objectstack/cli17.7.0): filed as [finding] console(create form): a required select field whose options declare default: true renders "Select an option" instead of preselecting the declared default, so the newcomer tutorial's Create Ticket form blocks on Priority and Status objectui#11914. sys_migrationUNIQUE-constraint WARN on a fresh boot: dropped as a duplicate of open [finding] every artifact boot on a fresh:memory:database logsInsert operation failed … UNIQUE constraint failed: sys_migration.idwith a full knex stack in Boot diagnostics #22099. The new data point (a file-backed fresh database on a 17.7.0 scaffold, 2 of 2 boots) was added there as6053681509.- The tutorial's
descriptionfield verdict ("inert") against a Console form that renders it: carried by [finding] docs on-ramp drift a first-time reader hits in sequence: stale CONTRIBUTING.md (retiredspecrepo), README's firstcurlgets 401, three pnpm floors, "three examples" vs five,os dev --help/os initstrings, tutorial transcript #22156 item 6 and recorded in PR docs(getting-started): the tutorial's Resolve action resolves the ticket; one routing line opens the index #22204's Acceptance notes.
Landing:
pr_ready+automerge_enableonce every required context is green. The merge closes #22152 and #22165.- Shape: draft PR to
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsLanded — PR #22204 →
7b926f7600(bundle #22152 + #22165) ·domain:devx#2· 2026-10-08T07:20Z- Merged through the merge queue at 2026-10-08T07:19Z. The squash commit
7b926f7600is onmain. Its queue runs (37739528950CI,37739528916Lint & Type Check) were green. - Verified on
mainby blob identity: all five pages equal the PR head9bfd965329:build-with-claude-code.mdxf10dbace8d;how-ai-development-works.mdxbd4288c835;index.mdx4cc8b01970;quick-start.mdx3034579af4;your-first-project.mdxfe35e76927.
- Effect:
- The tutorial's Resolve action is a declarative field write that resolves the ticket when clicked, and step 5 says what the reader should see.
- The Getting Started index opens with the maintainer's routing line, and the four entry pages follow it.
- Closed by
Fixes #22152andFixes #22165(both completed).pm:dispatchedis removed from both in the same act. - Follow-ups:
- [finding] console(create form): a required select field whose options declare default: true renders "Select an option" instead of preselecting the declared default, so the newcomer tutorial's Create Ticket form blocks on Priority and Status objectui#11914: the Console create form ignores an option's
default: true. - [finding] every artifact boot on a fresh
:memory:database logsInsert operation failed … UNIQUE constraint failed: sys_migration.idwith a full knex stack in Boot diagnostics #22099: data point6053681509. - [finding] docs on-ramp drift a first-time reader hits in sequence: stale CONTRIBUTING.md (retired
specrepo), README's firstcurlgets 401, three pnpm floors, "three examples" vs five,os dev --help/os initstrings, tutorial transcript #22156 item 6 carries thedescriptionverdict.
- [finding] console(create form): a required select field whose options declare default: true renders "Select an option" instead of preselecting the declared default, so the newcomer tutorial's Create Ticket form blocks on Priority and Status objectui#11914: the Console create form ignores an option's
- Merged through the merge queue at 2026-10-08T07:19Z. The squash commit
- added a commit that references this issue
on Oct 9, 2026
Filing gate: ① product defect with a named landing spot and a reproduction (
findingclasses (a) — the example copied verbatim produces a non-working button — and (c) — metadata the runtime accepts but that does nothing at click time).reach: public entry measured once —
os validateon the tutorial's verbatim files passes (1 Actions), andos devthen printsWARN [action-governance] declared script actions with NO handler … ["my_app_ticket:resolve_ticket"]; the Actions page documents the click-time outcome asAction 'x' on object 'y' not found.Reader:
domain:devxseat (content/docs/getting-started/build-with-claude-code.mdxstep 3 and step 5, and the mirrored example onquick-start.mdx); the optional authoring-time check isdomain:spec/packages/lint.Dedup:
search_issues"docs build-with-claude-code resolve_ticket script action target resolveTicket no handler button wired to nothing action-governance" (open + closed) → 0 cards.Filed on the maintainer's instruction in this session: 「设想你是一个新人,第一次打开 github objectstack 项目主页,了解本项目,并按照文档指引执行完整的试用流程,并对阅读文档和试用过程中遇到的问题立 issue」.
Summary
content/docs/getting-started/build-with-claude-code.mdxis the main on-ramp ("This is the main way you build on ObjectStack"). Step 3 shows the "representative result" the agent writes, including:Nothing on the page registers a
resolveTickethandler — there is nobody, noonEnable/registerAction, nofunctionsexport, and the scaffoldedobjectstack.config.tscarries none. Step 5 then tells the reader to open the Console and "Check the Resolve action shows on an open ticket — and disappears once the ticket is resolved". The button shows, but clicking it cannot resolve anything.The Actions page (
content/docs/ui/actions.mdx, "The dead-button trap" callout) already documents this exact shape: ascriptaction whosetargetnames a handler that was neverregisterAction-ed "compiles fine but throwsAction 'x' on object 'y' not foundat click time". The tutorial reproduces the trap as its model answer, and the runtime says so on every boot:The same action is reused as the reading example on
getting-started/quick-start.mdx("Reading the other pieces → Actions").Reproduction
create-objectstack@17.7.0/@objectstack/cli@17.7.0, Node v22.22.0.npm create objectstack@latest my-app && cd my-appmy_app_*, and add the four barrel export lines.pnpm run validate→✓ Validation passed,Data: 2 Objects 6 Fields UI: 1 Apps 1 Views 1 Actions— exactly the counts the tutorial prints. The gate does not mention the missing handler.npx os dev --ui→ boot diagnostics print the[action-governance] … NO handlerwarning quoted above.Action 'resolve_ticket' on object 'my_app_ticket' not found.So the tutorial's own sentence — "Every example on this page passes
os validateverbatim in a freshly scaffolded project" — is true, and that is the problem: the gate the tutorial advertises as the thing that catches AI mistakes lets this one through, and the page never tells the reader the button is inert.Expected
The model answer on the main tutorial page is a working action, and the reader's verification step in the Console succeeds. Either the example carries an inline
body(Path A on the Actions page — a metadata-only handler, no code to register), or the page shows theonEnableregistration (Path B) alongside the action, and the prose in step 5 asks the reader to click Resolve and watch the status change.Actual
The tutorial ships a
scriptaction with an unregisteredtarget,os validateaccepts it, the Console renders a button that fails at click time, and the only signal is a boot-time WARN the tutorial never mentions.Also worth deciding
Whether
os validateshould at least warn on ascriptaction whosetargetnames no handler the stack declares (functions,onEnableregistration) — today the same condition is a boot-time WARN under ADR-0078 but silent at authoring time, which is the gap the tutorial falls into.Generated by Claude Code