Skip to content

fix(create-objectstack,cli,docs): make the third-party onboarding path actually work on the current release - #2907

Merged
os-zhuang merged 7 commits into
mainfrom
claude/third-party-dev-docs-0t5256
Jul 14, 2026
Merged

os-zhuang merged 7 commits into
mainfrom
claude/third-party-dev-docs-0t5256

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

背景

#2899 合并后,按建议对 npm 入门路径做了真实的端到端验证(以外部用户身份:npx create-objectstack@latest → install → validate → dev → REST → build → os start),发现入门路径在当前发布版上实际是坏的,并顺藤摸瓜修复了一个 CLI 门禁缺口。

验证发现的问题与修复

create-objectstack(核心问题)

  1. 脚手架装到落后 8 个大版本的框架:bundled blank 模板锁 ^6.0.0,而 npm 上所有包已发布到 14.7.0 —— 实测新项目装到 6.9.0。
  2. 模板代码与 14.x 不兼容(直接升级依赖后):
    • Field.longText 已移除 → 改为 Field.textarea;
    • api: { rest: ... } 不再是 defineStack 的合法键(REST 已默认开启)→ 移除;
    • 缺 sharingModel 被 ADR-0090 安全姿态门禁拦截 → 显式声明 'private'。

修复策略(双保险):模板字面量更新到 ^14.0.0 + 当前 API;同时脚手架在生成时把 package.json 里所有 @objectstack/* 区间改写为 ^<自身版本>(全家桶 lockstep 发版,恒可解析)——即使模板字面量再次漂移,生成的项目也跟随当前发布版。新增一致性测试棘轮:模板依赖 major 必须等于包自身 major;README 模板表必须与 TEMPLATES 注册表一致(正是 #2899 发现的两类腐化)。

修复后全流程在 14.7.0 上实测跑通:scaffold → tsc/validate ✓ → dev 启动 → 登录 seeded admin → REST 增查 ✓ → os build → os start + health/ready ✓。

@objectstack/cli

os validate 缺 ADR-0090 D7 安全姿态检查:同一份 stack validate 放行、os build 拒绝(例如缺 sharingModel 的自定义对象),违背 cli.mdx 声明的 "validate 与 compile/build 同门禁(只是不产出物)" 契约。已把 validateSecurityPosture 对齐进 validate(error 拦截、advisory 警告、--json 一致)。CLI 全部 489 个测试通过;补丁后实测:缺 sharingModel 时 validate 拦截,声明后通过。

文档

  • quick-start / build-with-claude-code / your-first-project 的示例更新到当前字段 API,并补上显式 sharingModel(含"读对象要看什么"清单项)。
  • your-first-project 的 curl 流程加入 seeded dev-admin 登录步骤(14.x 数据 API 默认要求会话)——原裸 curl 实测返回 unauthenticated。
  • cli.mdx 收敛双脚手架口径:npm create objectstack@latest 为推荐入口,os init 定位 plugin 骨架 / 裸配置场景。

部署板块补齐

  • 新增 Backup & Restore 指南:部署状态清单(含 OS_SECRET_KEY 托管陷阱——没有它的数据库备份是不完整备份)、按驱动的备份方法、恢复演练步骤(对应 production-readiness 清单要求)。
  • self-hosting 新增 Kubernetes 参考 manifests(探针接已验证的 /api/v1/health、/api/v1/ready)。
  • 新增 examples/docker/:可直接复制进脚手架项目的 Dockerfile / compose / .dockerignore,与 self-hosting 文档互链。

验证

  • npm create objectstack(本地构建的 dist)冒烟:生成项目依赖为 ^14.7.0、textarea、sharingModel、无 api 块 ✓
  • pnpm --filter create-objectstack test(4 个新测试)✓;--filter @objectstack/cli test(489)✓
  • check-role-word / check-doc-authoring ✓;docs 站完整构建 ✓;ESLint ✓
  • 两个 changeset(create-objectstack patch、@objectstack/cli patch)
  • 说明:examples/docker 的镜像构建未在本会话执行(容器内无 docker daemon);Dockerfile 内容与已在裸机验证的 npm ci → os build → os start 流程一一对应。

分支说明:claude/third-party-dev-docs-0t5256 按规范从最新 main 重建;一个 -s ours 合并结点用于接续被 GitHub 删除前的旧分支引用,不影响 diff。

🤖 Generated with Claude Code

https://claude.ai/code/session_01Em3ky9uu6zw2cYzVhqCij2


Generated by Claude Code

claude added 5 commits July 14, 2026 06:23
… guides

Evaluated the docs from an external (npm-consumer) developer's perspective:
the getting-started section had no hands-on scaffold-to-API tutorial that
doesn't assume an AI agent or the monorepo, and the deployment section had
no self-hosting guide (only Vercel as a concrete target).

- getting-started/your-first-project: scaffold via create-objectstack,
  generated layout and package surface, dev server, REST calls, manual
  model edits, validate gate, artifact build
- deployment/self-hosting: systemd, Docker (multi-stage), Docker Compose
  with Postgres, required secrets (OS_AUTH_SECRET/OS_SECRET_KEY), health
  and readiness probes, reverse-proxy wiring, multi-node notes
- create-objectstack README: replace stale template list
  (minimal-api/full-stack/plugin) with the real registry (blank + remote
  todo/compliance/content/contracts/procurement) and document
  --skip-skills and the identity-rewrite behavior
- nav meta.json + cross-links from section indexes

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Em3ky9uu6zw2cYzVhqCij2
…le grammar)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Em3ky9uu6zw2cYzVhqCij2
…h actually work on the current release

Verified the published npm onboarding flow end-to-end as an external user
(npx create-objectstack@latest → install → validate → dev → REST → build →
os start) and fixed everything that broke:

- create-objectstack: the bundled blank template pinned ^6.0.0 while the
  registry publishes 14.x, so fresh projects installed a framework eight
  majors behind the docs. Template bumped to the current API
  (Field.longText → Field.textarea, drop the removed api.rest config key,
  declare sharingModel per ADR-0090) and the scaffolder now rewrites every
  @objectstack/* range in the generated package.json to its own release
  version, so generated projects track the registry even if the committed
  template drifts. Consistency tests ratchet the template major and the
  README template table against the TEMPLATES registry.
- cli: os validate now runs the ADR-0090 D7 security posture check —
  previously a stack passed validate and then failed the identical gate in
  os build, breaking validate's documented same-gates contract.
- docs: quick-start / build-with-claude-code / your-first-project examples
  updated to the current field API + explicit sharingModel; the tutorial's
  curl flow now includes the seeded dev-admin sign-in that the data API
  requires; cli.mdx names npm create objectstack as the recommended
  scaffolder with os init for plugin/bare-config cases.
- deployment: new Backup & Restore guide (state inventory incl. the
  OS_SECRET_KEY escrow trap, per-driver recipes, restore drill); Kubernetes
  reference manifests in self-hosting; ready-to-copy Docker packaging in
  examples/docker linked from the guide.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Em3ky9uu6zw2cYzVhqCij2
@vercel

vercel Bot commented Jul 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 14, 2026 9:39am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file tests tooling size/l labels Jul 14, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/cli, create-objectstack.

19 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/skills-reference.mdx (via packages/cli, create-objectstack)
  • content/docs/ai/skills.mdx (via create-objectstack)
  • content/docs/api/client-sdk.mdx (via @objectstack/cli)
  • content/docs/api/data-flow.mdx (via @objectstack/cli)
  • content/docs/api/environment-routing.mdx (via @objectstack/cli)
  • content/docs/api/error-catalog.mdx (via @objectstack/cli)
  • content/docs/automation/hook-bodies.mdx (via packages/cli)
  • content/docs/deployment/backup-restore.mdx (via @objectstack/cli)
  • content/docs/deployment/self-hosting.mdx (via @objectstack/cli)
  • content/docs/getting-started/cli.mdx (via @objectstack/cli)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/cli, create-objectstack)
  • content/docs/kernel/runtime-services/data-service.mdx (via packages/cli)
  • content/docs/kernel/runtime-services/index.mdx (via packages/cli)
  • content/docs/permissions/authentication.mdx (via @objectstack/cli)
  • content/docs/plugins/packages.mdx (via @objectstack/cli, create-objectstack)
  • content/docs/protocol/objectos/plugin-spec.mdx (via @objectstack/cli)
  • content/docs/protocol/objectos/realtime-protocol.mdx (via @objectstack/cli)
  • content/docs/releases/implementation-status.mdx (via @objectstack/cli)
  • content/docs/releases/v9.mdx (via create-objectstack)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang marked this pull request as ready for review July 14, 2026 09:21
…on warnings alongside conversion notices

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Em3ky9uu6zw2cYzVhqCij2
@os-zhuang
os-zhuang merged commit eaff014 into main Jul 14, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/third-party-dev-docs-0t5256 branch July 14, 2026 09:51
os-zhuang added a commit that referenced this pull request Jul 14, 2026
…-time template dep sync (#2912)

Close the remaining template-staleness gaps behind #2907 (fixes #2908):
a scaffold-local PR job that scaffolds with the repo-built dist and runs
the generated project end-to-end (install → validate → build → boot →
health probes → docker build/run of examples/docker), a nightly registry
canary running npx create-objectstack@latest across every template as a
real first-run user, and scripts/sync-template-versions.mjs chained into
the root version script so a release can never ship the blank template
pinning a stale @objectstack/* range.
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 17, 2026
…ge-tag cannot misfire (objectstack-ai#9102)

* feat(scripts): sync docs image tags at version time so the gate cannot misfire

`check:docs-image-tag` (objectstack-ai#9018) pins the docs' concrete image/CLI tags to
`packages/cli`'s version, so a bump reddens it until the doc surfaces move.
The red could not land on the change that caused it: `changeset version`
bumps the version on a release PR that gets no CI (changesets/action opens
it with the default GITHUB_TOKEN, per sync-template-versions.mjs's own
header), so the bump merged green and the gate reddened on the next
ordinary PR, naming files that author never touched.

Adds scripts/sync-docs-image-tags.mjs to the root `version` chain, beside
the two sync scripts already there -- the shape this repo chose for the
identical drift class in objectstack-ai#2907. It imports SURFACES, PATTERNS,
VERSION_SOURCE, extractOccurrences and checkSurfaces from the gate, so the
rewriter and the gate read one list and its verdict IS the gate's.

Version-time sync only: no publish, no tag, no Version Packages PR (objectstack-ai#6170).

check-docs-image-tag.mjs gains an entry-point guard and exports
VERSION_SOURCE. Both additive: importing it previously ran main() and
exited the process, which made its exports unusable by the one consumer
they were added for.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011RB4waLuNbdruCo6X9oobm

* test(scripts): name the inert-rewriter failure instead of crashing on it

An ablation that made rewriteText inert died of a TypeError indexing an
empty `changed` array, two limbs before the byte-identity control ran.
Optional chaining so the self-test REPORTS the inert case by name.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011RB4waLuNbdruCo6X9oobm

---------

Co-authored-by: Claude <noreply@anthropic.com>
hotlong pushed a commit that referenced this pull request Sep 4, 2026
…#15332)

`content/docs/releases/index.mdx` ends each major's entry with a status
parenthetical — "(current series: 17.2.0, released 2026-08-23)". That sentence
is derived data: the newest GA of a major is already readable from
`packages/spec/CHANGELOG.md`, which is where check-release-section-coverage
reads it from to produce its finding. Kept by hand, it went stale on three
consecutive minors (#10232, #11649, and this one), each caught after the fact.

The gate that names it cannot fire on the change that causes it: the version
commit is opened by changesets/action with the default GITHUB_TOKEN and gets no
CI, and lint.yml runs the gate without `--strict`, where a finding is advisory
and the job is green by design. Only release-coverage-patrol.yml passes
`--strict`, and a standing patrol is an after-the-fact reader by construction.

Adds scripts/sync-release-index-currency.mjs to the root `version` chain, beside
the three sync scripts already there — the shape this repo chose for the
identical drift class in #2907 and #9064 (e569cac). It imports INDEX_PATH,
SPEC_CHANGELOG, the scope predicate, the entry and status lookups and the
verdict from check-release-section-coverage.mjs, so the rewriter and the gate
read one contract and the rewriter's verdict IS the gate's.

It rewrites exactly one shape, `current series: <x.y.z>, released <date>`, and
refuses the ones that need a human sentence — a "final release:" claim a newer
minor contradicts, an entry with no status field — which then reach the gate's
own words and stop the run. Assertion 1 (a published minor has a section) is
never consulted here: a rewriter cannot write curated prose, and hard-failing
the version lane on unwritten prose would wedge it for a debt the release did
not create.

release.yml's post-version shape assertion and cut-rc.yml's staging allowlist
both resolve the surface from `syncedPaths()` at run time, joining the two lists
they already resolve on the same terms — a fourth literal would be a fourth
contract. Measured: without that third list the post-version validation rejects
content/docs/releases/index.mdx as "outside the reviewed surface", which is the
treadmill guard doing its job.

The index line itself was fixed by running the stamper, not by hand.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHvF5hyiZjnCyExFnfQB8m
os-litant added a commit that referenced this pull request Sep 5, 2026
…w declarations in the CI filter-parity pin

Two review findings from PR #15974.

1. The head reddened `check-ci-filter-parity --self-test`: the pre-#10015
   rollback now uncovers 21 globs, not 19. Measured, the delta is exactly the
   two `content/docs` pages this branch declared for `@objectstack/cli`
   (troubleshooting.mdx, getting-started/index.mdx) — an origin/main control
   yields 19 with an empty symmetric difference otherwise. Both are recorded by
   name, the way the pin's own comment prescribes for #14824's three, rather
   than the count merely being bumped.

2. The shipped history claim was wrong. `dbb54e12f0c` (2026-05-25) added the
   bundled template at `^5.3.0`, not `^6.0.0`; `eaff01425b7` (#2907,
   2026-07-14) moved it to `^6.0.0` and recorded no reasoning about TypeScript
   — in that same one-file diff the five `@objectstack/*` ranges move
   `^6.0.0` to `^14.0.0` while the `typescript` line moves onto the `^6.0.0`
   they are vacating. So the three-value split is 53 days old, not 102, and
   the two-value split is 210 (the changeset said 211). Corrected in init.ts,
   create.ts, the pin's header and the changeset, which now agree.

A dated provenance claim written into source comments is exactly the restated
fact nothing checks that this card exists to close; shipping a wrong one inside
the fix would have been self-refuting.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D47qPfEWVPmhguWgBZCi5N
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 9, 2026
…d os create stop restating the tsconfig and the devtool ranges (objectstack-ai#15974)

* refactor(cli): extract the restated scaffold emission policy into one module

`os init` and `os create` each restated the third-party ranges and the
`tsconfig.json` an emitted project carries. Measured on the tree, the
TypeScript range was written in six places across three scaffolders and had
split into three values (`^5.3.0` / `^5.8.0` / `^6.0.0`); vitest into two.

Both CLI scaffolders now read one definition per value. Surviving values:
`^5.3.0` for TypeScript (the floor two live doc pages already state) and
`^4.0.0` for vitest (no recorded decision for either; `^4.0.18` claimed a
patch-level floor nothing justifies). Neither changes what an emitted project
installs — `^5.3.0` and `^5.8.0` both resolve to typescript 5.9.3, `^4.0.0`
and `^4.0.18` both to vitest 4.1.11.

`create-objectstack`'s `^6.0.0` is deliberately untouched: it cannot import
from `@objectstack/cli` (the dependency edge runs the other way), and unifying
it would change what a scaffolded project installs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D47qPfEWVPmhguWgBZCi5N

* test(cli): pin the shared scaffold emission policy across all five emissions

Both ends of every expectation are derived — from the renderers, from the
other scaffolder, or from the doc pages that already state the TypeScript
floor — so a transcription cannot go green on a half-edited tree.

`os init` writes its `tsconfig.json` inside `run()`, so that half is measured
by driving the real command into a throwaway directory and reading the bytes
off disk; an exported renderer nobody calls would pass every in-process
assertion. The two doc pages the floor case reads are declared in
`scripts/cross-package-test-inputs.mjs` and mirrored into `turbo.json`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D47qPfEWVPmhguWgBZCi5N

* chore(changeset): record the scaffold emission policy extraction

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D47qPfEWVPmhguWgBZCi5N

* fix(cli): correct the shipped provenance claim, and record the two new declarations in the CI filter-parity pin

Two review findings from PR objectstack-ai#15974.

1. The head reddened `check-ci-filter-parity --self-test`: the pre-objectstack-ai#10015
   rollback now uncovers 21 globs, not 19. Measured, the delta is exactly the
   two `content/docs` pages this branch declared for `@objectstack/cli`
   (troubleshooting.mdx, getting-started/index.mdx) — an origin/main control
   yields 19 with an empty symmetric difference otherwise. Both are recorded by
   name, the way the pin's own comment prescribes for objectstack-ai#14824's three, rather
   than the count merely being bumped.

2. The shipped history claim was wrong. `dbb54e12f0c` (2026-05-25) added the
   bundled template at `^5.3.0`, not `^6.0.0`; `eaff01425b7` (objectstack-ai#2907,
   2026-07-14) moved it to `^6.0.0` and recorded no reasoning about TypeScript
   — in that same one-file diff the five `@objectstack/*` ranges move
   `^6.0.0` to `^14.0.0` while the `typescript` line moves onto the `^6.0.0`
   they are vacating. So the three-value split is 53 days old, not 102, and
   the two-value split is 210 (the changeset said 211). Corrected in init.ts,
   create.ts, the pin's header and the changeset, which now agree.

A dated provenance claim written into source comments is exactly the restated
fact nothing checks that this card exists to close; shipping a wrong one inside
the fix would have been self-refuting.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D47qPfEWVPmhguWgBZCi5N

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 9, 2026
…objectstack-ai#15332) (objectstack-ai#15392)

* fix(docs): stamp the release index's "current series" at version time (objectstack-ai#15332)

`content/docs/releases/index.mdx` ends each major's entry with a status
parenthetical — "(current series: 17.2.0, released 2026-08-23)". That sentence
is derived data: the newest GA of a major is already readable from
`packages/spec/CHANGELOG.md`, which is where check-release-section-coverage
reads it from to produce its finding. Kept by hand, it went stale on three
consecutive minors (objectstack-ai#10232, objectstack-ai#11649, and this one), each caught after the fact.

The gate that names it cannot fire on the change that causes it: the version
commit is opened by changesets/action with the default GITHUB_TOKEN and gets no
CI, and lint.yml runs the gate without `--strict`, where a finding is advisory
and the job is green by design. Only release-coverage-patrol.yml passes
`--strict`, and a standing patrol is an after-the-fact reader by construction.

Adds scripts/sync-release-index-currency.mjs to the root `version` chain, beside
the three sync scripts already there — the shape this repo chose for the
identical drift class in objectstack-ai#2907 and objectstack-ai#9064 (e569cac). It imports INDEX_PATH,
SPEC_CHANGELOG, the scope predicate, the entry and status lookups and the
verdict from check-release-section-coverage.mjs, so the rewriter and the gate
read one contract and the rewriter's verdict IS the gate's.

It rewrites exactly one shape, `current series: <x.y.z>, released <date>`, and
refuses the ones that need a human sentence — a "final release:" claim a newer
minor contradicts, an entry with no status field — which then reach the gate's
own words and stop the run. Assertion 1 (a published minor has a section) is
never consulted here: a rewriter cannot write curated prose, and hard-failing
the version lane on unwritten prose would wedge it for a debt the release did
not create.

release.yml's post-version shape assertion and cut-rc.yml's staging allowlist
both resolve the surface from `syncedPaths()` at run time, joining the two lists
they already resolve on the same terms — a fourth literal would be a fourth
contract. Measured: without that third list the post-version validation rejects
content/docs/releases/index.mdx as "outside the reviewed surface", which is the
treadmill guard doing its job.

The index line itself was fixed by running the stamper, not by hand.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHvF5hyiZjnCyExFnfQB8m

* ci(lint): run the release-index rewriter's self-test at PR time (objectstack-ai#15332)

Third version-time rewriter, third self-test step, beside the two already in
this job (check:docs-image-tag-sync, check:template-version-sync).

Two gates require a PR-time caller, and both name this family:
check-self-test-wired ("a script CI runs that ships a --self-test must have that
self-test run by CI"), and dispatch-gates' "a deferred pair defers the LEAD, not
the load break" — a family no every-PR workflow runs leaves its import edges
unwatched at PR time, so a change breaking the module load of
check-release-section-coverage.mjs would not redden the PR that made it. With
release.yml as the only caller that self-test was 2-of-1382 RED naming
check:release-index-currency-sync.

⚠️ Not the --strict promotion, and it cannot become one: this step runs only
--self-test, whose cases are string fixtures. It never reads the live index for
currency and never reads a release page, so no corpus state can red it. The
advisory, non-strict `Release section-coverage guard` step is untouched — this
diff is 44 insertions and 0 deletions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHvF5hyiZjnCyExFnfQB8m

---------

Co-authored-by: Claude <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — 9307c98d Deployed Jul 14, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants