Repository navigation
Description
Environment fingerprint
| key | value |
|---|---|
| subject | the PUBLISHED npm packages, not a checkout: create-objectstack@17.6.0 and every @objectstack/* resolved at 17.6.0 from https://registry.npmjs.org/ (dist-tag latest); 56 @objectstack/* entries in the scaffold's node_modules/.pnpm, all @17.6.0, zero link: entries in its pnpm-lock.yaml |
| framework sha | 617f25f8 (the 17.6.0 version commit, per the release session) |
| bundled Console | @objectstack/console@17.6.0 (objectui pin 31971ff1e28f, per the release session) |
| runtime | Node v22.22.0, npm 10.9.4, Ubuntu 24.04.4 LTS (linux x86_64), Chromium via Playwright executablePath=/opt/pw-browsers/chromium |
| workspace | scratch dirs under /tmp/ns/ outside the repository, no workspace links |
| boots | tasks-app dev runtime os dev -p 4310 (sqlite file:<project>/.objectstack/data/objectstack.db, seeded dev admin); environment runtimes os start with OS_CLOUD_URL=off: ops-env :4320 (catalog-less install target), empty kernel :4340 (hot-install repro), artifact-pinned :4350 |
| date | 2026-10-02, 04:05–04:25 UTC |
| runner | Claude Code cloud session, release verification lane "north-star path on published 17.6.0"; executed sequentially (one runner) |
Scope
Selector: the path in docs/NORTH-STAR.md (「唯一的度量,那条路」), walked end to end as a new developer reading only the published docs (content/docs/**) and CLI output, against the published 17.6.0 train. The items scored are the 「路上的功能点」 checklist items each step exercised, at these revisions:
cli.scaffold-first-run r2 · cli.scaffold-console-first-paint r2 · cli.build-own-contract r3 · cli.dev-boot-contract r3 · platform-core.console-login r4 · cli.lint-severity-exit-contract r1 · cli.verify-verdict-exit-mapping r1 · platform-core.marketplace-install-local-lifecycle r1 · ai.mcp-http-surface r2 · ai.mcp-run-action-exposure-gate r2 · identity-auth.api-key-ui-lifecycle r1 · studio-authoring.first-run-loop r3 · cli.dev-automigrate-policy r1
Planned items: none in this selection.
The app built for the walk (tasks-app, namespace tasks_app): a shared picklist tasks_app_work_status used by two objects; objects tasks_app_project and tasks_app_task (text, lookup → project, picklist select, date, number, boolean, textarea); a list view + a two-section form view; a script action complete_task with an inline body, visible: 'record.done != true', ai.exposed: true; an active record_change flow task_completed_note (task after-update, record.status == 'done' → create_record on the starter note object); a permission set tasks_app_task_user (CRUD + readScope: 'org', no delete on project); an app tasks_app with three nav entries.
The path — per-step verdicts
| step | verdict | first failing clause / note |
|---|---|---|
① npm create objectstack → write metadata |
pass | scaffold → install → validate → build all exit 0; only the blank template exists (the others are documented as retired). Generator defects noted below (they do not block a hand-written app). |
| ② run locally and see it | pass | health/ready 200, Console paints, seeded admin signs in, the app's list/form/lookup/picklist render, a record is created through the form, the Complete Task button runs, hides itself after completion (the visible predicate), and the flow writes its note. Permission set proven both sides with a member persona. |
| ③ verification refuses wrong, admits right | pass, with two findings | four planted mistakes are refused by os validate / os build / os lint, each located and with a prescription; fixed → all green incl. objectstack verify --rls. But objectstack verify itself prints ✓ verify passed (exit 0) on the broken stack, and verify --json stdout is not parseable JSON. |
| ④ publish and install into an environment | FAIL — current P0 | ai.mcp-run-action-exposure-gate clause 2 / NEG1: the documented community install (os package install ./dist/objectstack.json, no control plane) reports success, but the installed app's script action is not dispatchable from ANY door (REST 404, MCP "No handler registered"), while list_actions advertises it; hot install also leaves the flow trigger unbound and the permission set unprojected until a restart. Workaround used: the documented artifact-pinned boot (os start --artifact), on which every later step passes. |
| ⑤ connect an Agent over MCP, one real business operation | pass on the workaround environment; fail on the installed one | API key minted show-once from Account → Connect an Agent; MCP Streamable HTTP client: tools/list = 12 tools, list_actions lists complete_task, create_record + run_action complete_task complete a task, the flow fires, and the Console list shows it Done. Anonymous / bogus / revoked key → 401, restored key → 200. |
| ⑥ iterate once on a one-sentence request | pass (metadata path) | 「给任务加一个优先级字段,并在列表里显示」: one select field + one column + one form row; validate/lint green; os dev rebuilt and restarted itself; the Console list shows Priority; existing rows, the action and the flow still work. Studio path not exercised. |
Per-clause verdicts
| item | clause | verdict | evidence (text oracle) |
|---|---|---|---|
| cli.scaffold-first-run | 0 | pass | npm create objectstack@17.6.0 tasks-app exit 0 (installs + skills); os validate exit 0, os build exit 0 (dist/objectstack.json 2.2 KB); a second scaffold booted with os start (artifact auto-detected) → /api/v1/health 200, /api/v1/ready {"status":"ready","state":"running"} |
| cli.scaffold-first-run | 1 | pass | --help offers blank only; docs say the remote templates are retired; blank validates and builds |
| cli.scaffold-first-run | 2 | pass | healthy boot of a coherent scaffold (engines: { protocol: '^17' }), no protocol refusal |
| cli.scaffold-first-run | 3 | pass | installed set in .claude/skills/ = the 10 directories of the curated skills/ catalog exactly; no dogfood-verification or other internal skill present |
| cli.scaffold-first-run | 4 | skipped | no unhealthy boot occurred |
| cli.scaffold-console-first-paint | 0 | pass | pristine scaffold npx os validate exit 0 |
| cli.scaffold-console-first-paint | 1 | pass | /_console/ 200 text/html; screenshot (live, not attached): login form at /_console/login, then the home shell ("Build an app", "Your apps", Setup tile) |
| cli.scaffold-console-first-paint | 2 | pass | npm run dev -- -p 4310 → /_console/ 200; npx os dev --ui -p 4311 → /_console/ 200; both text/html |
| cli.scaffold-console-first-paint | 3 | pass | boot banner prints Dev admin: admin@objectos.ai / admin123; sign-in via the form lands on /_console/home; record created, action show/hide observed |
| cli.build-own-contract | 0 | not-run | human success path captured (exit 0, stats, Artifact: dist/objectstack.json (14.8 KB)); the --json success payload was not captured |
| cli.build-own-contract | 1 | not-run | no schema-shape break planted (the planted breaks were author-time rules) |
| cli.build-own-contract | 2 | pass | os build exit 1, ✗ Author-time rules failed (3 issues), each with rule: + at path (expression-invalid, object-reference-unknown, list-view-field-unknown), all three reported at once |
| cli.build-own-contract | 3 | pass | os build --json failure payload keys success, error, issues, warnings, conversions, success:false, 3 issues |
| cli.build-own-contract | 4 | pass | every observed exit was 0 or 1 across repeated runs |
| cli.build-own-contract | 5 | pass | the field-no-consumers warning prints and the build exits 0 with the artifact written |
| cli.dev-boot-contract | 0 | pass | health 200 within ~10 s, ready 200, /_console/ serves the login page |
| cli.dev-boot-contract | 1 | not-run | sign-in with the seeded credentials succeeded; the changed-password restart (idempotency) was not exercised |
| cli.dev-boot-contract | 2 | pass | nothing chosen → Database: file:/tmp/ns/tasks-app/.objectstack/data/objectstack.db, persistent across the session's restarts |
| cli.dev-boot-contract | 3–5 | not-run | --fresh, port shift and staleness block not exercised |
| cli.dev-boot-contract | 6 | pass | in a dir with no config: ✗ Config file not found … + Run in a directory with objectstack.config.ts, pass --artifact <path|url>, or run from the monorepo root., exit 1 |
| platform-core.console-login | 0 | pass | form sign-in → /_console/home, header + launcher, no sidebar |
| platform-core.console-login | 1–4 | not-run | reload / server-side expiry / wrong-password legs not exercised |
| cli.lint-severity-exit-contract | 0 | pass | human report groups Errors (3) ✗ / Warnings ⚠, each with rule id + path |
| cli.lint-severity-exit-contract | 1 | pass | 3 errors → exit 1; warnings-only (green app) → exit 0 |
| cli.lint-severity-exit-contract | 3 | pass | the same three registry rule ids appear in os build and os lint on the same stack |
| cli.lint-severity-exit-contract | 2, 4–6 | not-run | --json, i18n fold, --fix, throwing config not exercised |
| cli.verify-verdict-exit-mapping | 0 | pass | statuses observed: verified, needs-fixture — both in the closed six (read from the JSON after stripping the log prefix, see finding below) |
| cli.verify-verdict-exit-mapping | 1 | not-run | only the zero side observed (hardFailures: 0, exit 0); no hard failure staged |
| cli.verify-verdict-exit-mapping | 2 | pass | a validation rule rejecting every insert → ~ tasks_app_project needs-fixture (app validation rejected the auto-record), summary 2 verified … 1 needs-fixture, exit 0 |
| cli.verify-verdict-exit-mapping | 3–4 | not-run | --rls ran green (3 PROVEN (3 consistent, 0 HOLES), per-persona line) but no hole was staged; posture leg not run |
| platform-core.marketplace-install-local-lifecycle | 0–1 | not-run | boot B (OS_CLOUD_URL=off) half only: runtime/config → installLocal:true, marketplace:false, GET /marketplace/install-local 200; boot A not run |
| platform-core.marketplace-install-local-lifecycle | 2 | pass | os package install ./dist/objectstack.json --runtime http://localhost:4320 → ✓ Package installed into the running kernel; GET /meta/app names tasks_app; POST /data/tasks_app_project 201 and read back. (What the install does NOT bring along is scored under the action gate item below and in the findings.) |
| platform-core.marketplace-install-local-lifecycle | 3 | pass | admin listing carries installedBy + storageDir; member listing 200 with the entry and without both; anonymous 401 |
| platform-core.marketplace-install-local-lifecycle | 4–6 | not-run | purge/reseed, full 4×3 door matrix, DELETE not exercised (member POST 403 / DELETE 403, anonymous POST 401 observed) |
| ai.mcp-http-surface | 3 | pass | anonymous POST /api/v1/mcp initialize → 401; bogus osk_ key → 401 |
| ai.mcp-http-surface | 4 | pass | keyed Streamable HTTP session: list_objects, describe_object, validate_expression, query_records, aggregate_records, get_record, create_record, update_record, delete_record, list_actions, run_action, resume_run |
| ai.mcp-http-surface | 0–2, 5 | not-run | opt-out boot, /mcp/skill, OAuth scope legs not exercised |
| ai.mcp-run-action-exposure-gate | 1 | pass | list_actions → exactly complete_task (the one ai.exposed action), with its ai.description |
| ai.mcp-run-action-exposure-gate | 2 | fail | on the runtime the app was INSTALLED into: run_action {actionName:'complete_task', recordId} → isError: true, No handler registered for action 'complete_task' on 'tasks_app_task'; record unchanged. Same call on the dev runtime and on the artifact-pinned runtime → {ok:true, …} and the record reads status: done, done: true. Reproduction below. |
| ai.mcp-run-action-exposure-gate | 3 | pass | [action-audit] MCP run_action 'complete_task' on 'tasks_app_task' — body executes TRUSTED (system-elevated context, RLS/FLS-bypassing) for user '…' |
| ai.mcp-run-action-exposure-gate | 0, 4 | not-run | the app declares no unexposed action; no sys_* action probed |
| identity-auth.api-key-ui-lifecycle | 0 | pass | Account → Connect an Agent → Create key → POST /api/v1/keys 201 with the raw key once; the panel says "copy it now, it will not be shown again"; GET /data/sys_api_key rows carry prefix and no key field |
| identity-auth.api-key-ui-lifecycle | 1 | pass | x-api-key on GET /data/tasks_app_task → 200 as the owner; MCP calls ran as the key's user (created_by = that user) |
| identity-auth.api-key-ui-lifecycle | 2 | pass | PATCH /data/sys_api_key/:id {revoked:true} 200 → next data call 401, MCP initialize 401 |
| identity-auth.api-key-ui-lifecycle | 3 | pass | {revoked:false} 200 → data call 200 |
| identity-auth.api-key-ui-lifecycle | 4–5 | not-run | mine-view scoping and the list screenshot not exercised |
| studio-authoring.first-run-loop | all | not-run | step ⑥ was walked through metadata (allowed by the lane), not Studio |
| cli.dev-automigrate-policy | all | not-run | path-level only: after adding priority, os dev printed ↻ recompiling … ✓ server restarted — the new build is live, the column was served and the five existing rows read back intact; the [schema-drift] auto-reconciled info line was not captured at the default log level |
Derived item verdicts
| item | verdict |
|---|---|
| cli.scaffold-first-run | pass |
| cli.scaffold-console-first-paint | pass |
| cli.build-own-contract | partial |
| cli.dev-boot-contract | partial |
| platform-core.console-login | partial |
| cli.lint-severity-exit-contract | partial |
| cli.verify-verdict-exit-mapping | partial |
| platform-core.marketplace-install-local-lifecycle | partial |
| ai.mcp-http-surface | partial |
| ai.mcp-run-action-exposure-gate | fail |
| identity-auth.api-key-ui-lifecycle | partial |
| studio-authoring.first-run-loop | not-run |
| cli.dev-automigrate-policy | not-run |
Hand-off (not reached this run): studio-authoring.first-run-loop (all clauses), cli.dev-automigrate-policy (all clauses), and the not-run clauses listed above.
Reproduction rule for the fail
ai.mcp-run-action-exposure-gate clause 2, on an installed package (no authentication or authorization element; full recipe published):
npm create objectstack@17.6.0 tasks-app; add ascriptaction with an inlinebodyandai: { exposed: true, description }on an app object (anybodythat updates the record — the docs' Path A example shape);npx os build.- In a second directory boot an empty runtime:
OS_CLOUD_URL=off npx os start -p 4340 --home ./home --auth-secret <32+ chars>;POST /api/v1/auth/sign-up/email(headerOrigin: http://localhost:4340) for the first owner. npx os package install ./dist/objectstack.json --runtime http://localhost:4340 --email … --password …→✓ Package installed into the running kernel.POST /api/v1/data/tasks_app_task {"name":"probe"}→ 201.POST /api/v1/actions/tasks_app_task/complete_task {"recordId":"<id>"}→ expected 200{success:true, data:{ok:true}}; actual404 {"code":"RESOURCE_NOT_FOUND","message":"Action 'complete_task' on object 'tasks_app_task' not found"}.- Mint
POST /api/v1/keys; MCPlist_actions→ listscomplete_task; MCPrun_action {actionName:'complete_task', recordId}→ actualisError: true,No handler registered for action 'complete_task' on 'tasks_app_task'. - Restart the runtime: same result (reproduced on :4320 after restart and on :4340 hot, i.e. twice on fresh loads).
- Control:
npx os start -p 4350 --artifact <path>/dist/objectstack.json …→ step 5 answers{"success":true,"data":{"ok":true,…}}and the record readsstatus: done.
Verify pass (RUNNER rule 7): a second, independent agent re-derived this verdict on fresh runtimes (:4461 install-local, :4462 artifact-pinned) from the steps above alone — CONFIRMED: REST 404 RESOURCE_NOT_FOUND and MCP No handler registered … on the installed runtime while list_actions lists the action; REST 200 and MCP {ok:true} on the artifact-pinned one.
Findings outside the scored clauses (each extracted to its own card)
- Install-local drops the app's
scriptaction bodies — the fail above (P0 of the path). - Hot install leaves record-change flows unbound and permission sets unprojected until a restart — on :4340 a task updated to
doneright after install wrote no note (flow did not fire); after a restart (:4320) the same update writes it.sys_permission_setliststasks_app_task_useronly after a restart (/meta/permissionalready lists it), so an admin cannot grant the installed app's set until then. The CLI says nothing about a restart. objectstack verifypasses a stack the authoring gates refuse — with a dangling lookup target, a bare-referencevisiblepredicate and an unknown list column planted (validate/build/lint all exit 1),objectstack verifyprints3 verified … ✓ verify passed — no runtime failures, exit 0. NORTH-STAR defines done as "objectstack verifyis green"; the published docs (content/docs/deployment/cli.mdx) do not documentverifyat all.objectstack verify --jsonstdout is not a JSON document — ~329 lines ofINFOkernel log precede the payload on stdout, soverify --json > report.json(the item's own step 0) yields an unparseable file.os generatescaffolds fail the project's own gates —os g flow task_donewrites a start node ontasks_app_task_done(an object that does not exist) and reports✓ Reaches the stack; validate only warns.os g view taskwrites a view thatos lintrefuses (View "tasks_app_task" is missing a labelatviews[0].list.label, exit 1) and whosename/labelvalidate calls dead properties.os g action complete_task/os g app tasksderive the object from the NAME and refuse; there is no flag to target an existing object.
Observations recorded, not extracted: the Console requests GET /api/v1/usage/storage on every page and gets 404 ENDPOINT_NOT_FOUND on a community runtime; a plain member's Console requests GET /data/sys_activity and gets 403 on home; the create form does not pre-select the picklist's default: true option (the server applies it on insert); your-first-project.mdx says the default template "runs on an in-memory driver" while os dev resolves a persistent SQLite file (the same page says so two sections later); runtime/config reports aiStudio: true on a community os start boot (not followed up).
Fixture gaps: none.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 2, 2026
Close-out — product defects extracted from this run:
Current P0 of the path: step ④ (install into an environment) — #21321. Workaround that keeps the path walkable: the artifact-pinned boot.
Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
Close-out completed: closed
completedTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-06T16:07Z. The maintainer approved clearing the openqa-runrecords' close-out debt: 「同意,动手」. This was audited row by row (read-only) against checklist-test §5 before this write.Superseded-by: #21722 · cli.build-own-contract
Superseded-by: #21721 · cli.dev-boot-contract
Superseded-by: #21782 · platform-core.console-login
Superseded-by: #21721 · cli.lint-severity-exit-contract
Superseded-by: #21721 · cli.verify-verdict-exit-mapping
Superseded-by: #21720 · platform-core.marketplace-install-local-lifecycle
Superseded-by: #21720 · ai.mcp-http-surface
Superseded-by: #21784 · identity-auth.api-key-ui-lifecycle
Superseded-by: #21784 · studio-authoring.first-run-loop
Superseded-by: #21721 · cli.dev-automigrate-policy
ai.mcp-run-action-exposure-gateclause 2 was extracted as os package install (install-local) drops an app's script action bodies: REST 404 and MCP run_action "No handler registered" while list_actions advertises the action #21321 (closedcompleted).cli.dev-boot-contract's remaining console half is open on QA run · surface:cli (18/18) · 251a7dd4 · 2026-10-04 · 10 PASS / 2 PARTIAL / 6 FAIL / 0 BLOCKED / 0 NOT-RUN #21721, and stays there.marketplace-install-local-lifecycle's newer FAIL is disposed on QA run · surface:api (89/89) · 251a7dd4 · 2026-10-04 · 68 PASS / 7 PARTIAL / 14 FAIL / 0 BLOCKED / 0 NOT-RUN #21720 (marketplace: install-local purge-sample-data always answers 500 DRIVER_UNAVAILABLE (looks up a bare "driver" service nothing registers) — and seed records carry no id to purge by #21728, qa(checklist): re-point 17 clauses on 16 items that the 17.7 pre-release runs (#21720 / #21721 / #21722) proved stale or mis-asserted #21735).dev-automigrate-policy's newer FAIL is disposed on QA run · surface:cli (18/18) · 251a7dd4 · 2026-10-04 · 10 PASS / 2 PARTIAL / 6 FAIL / 0 BLOCKED / 0 NOT-RUN #21721 (cli: a plain os dev (standalone stack) never runs autoMigrate 'safe' — the documented dev self-heal applies only to host configs, while plan and drift lines say "auto-applied at boot" #21733).Generated by Claude Code
docs(releases): finalize the 17.6.0 notes after publish (objectstack-…