Skip to content

feat(cli,create-objectstack): the starter wires src/security and src/datasets, os g permission/dataset, AGENTS.md names the package manager - #30258

Merged
objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/project-thread-qk8494
Nov 5, 2026
Merged

objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/project-thread-qk8494

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Bill · project thread

domain:server#4 · os-bill · session_01Utp6CZMkHvuDeVYgTD73qF

维护者速读

  • 改了什么:新建项目(npm create objectstack)自带已接线的空目录 src/security(权限集)和 src/datasets(分析数据集);os g permission / os g dataset 两个新类型往这两处写文件;生成的 AGENTS.md 按建项目时实际用的包管理器写 pnpm run … 或 npm run …。
  • 为什么改:真实用户走查时,有人登录的应用必须有权限集、仪表盘要绑数据集,但新项目里没地方放、os g 也生成不了,只能手工接线;pnpm 项目的 AGENTS.md 还一直写 npm run。
  • 风险与回滚:只动脚手架模板、CLI 生成器和文档,不碰 spec 与运行时;两个新目录是空 barrel,老项目不受影响。回滚即 revert 本 PR。
  • 先看:packages/cli/src/commands/generate.ts(permission / dataset 两个生成器,权限集默认授予读/建/改、readScope: 'own')、packages/create-objectstack/src/templates/blank/objectstack.config.ts(新增两条接线)、packages/create-objectstack/src/index.ts(AGENTS.md 填入包管理器)。
  • 两分钟验证:pnpm --filter @objectstack/cli exec vitest run --project unit test/generate-scaffold-validates.test.ts src/commands/generate-permission-dataset.pin.test.ts,预期全部通过,其中 os g 'permission'、os g 'dataset' 两条在 validate/build/lint 下零发现。
  • 需要你做的:无,席位落地。

Fixes #30123

Clause-②: yes (widening) — os generate accepts two new type values, permission and dataset; no flag or export is removed or narrowed.
Metadata-protocol: none

What changes

Blank starter (create-objectstack). src/security/index.ts and src/datasets/index.ts ship as empty barrels, and objectstack.config.ts hands them to the stack's existing permissions and datasets keys through the same exportsOf() helper as the eight directories it already wired. Both keys exist on ObjectStackDefinitionSchema today (permissions: z.array(PermissionSetSchema), datasets: z.array(DatasetSchema)), so no spec change. The generated AGENTS.md "Project Structure" block names both directories, and the two READMEs list them.

os generate permission NAME [--object OBJECT] writes src/security/NAME.permission.ts. The type key is the registry's own (permission, file pattern *.permission.ts), and the stack key is singularToPlural('permission') = permissions, so the generator rides the existing roster machinery: os init wires it, os g reports reach, and every derived pin measures it. The scaffold is a definePermissionSet granting the bound object (from --object, or the stack's only object) read, create and edit without delete, with readScope: 'own' written. Without a depth, a read grant on a private object is reported by security-private-no-readscope (info), which the zero-findings pin refused; 'own' states the same reach the object's sharing model gives instead of widening it, and the emitted comment names 'org'. isDefault is not written, and the comment says what it would do.

os generate dataset NAME [--object OBJECT] writes src/datasets/NAME.dataset.ts: a defineDataset over the bound object with a record_count count measure, grouped by the record's title field when the object has one (no dimension otherwise). defineDataset types the literal as a Dataset, so it needs no as const (the card's last measured point).

Generated AGENTS.md names the package manager. The template's eight npm run occurrences are {{PM}} run, and writeAgentGuides fills {{PM}} with the manager detectPackageManager() chose for the same run, the one the install line and "Next steps" already name. Both written copies (AGENTS.md, .github/copilot-instructions.md) carry it.

Docs. content/docs/deployment/cli.mdx (examples, types table, --object, "What it does") and packages/cli/README.md list the two types.

Deviation from the dispatch's suggested route: the types are permission and dataset, not permission-set. The generator key is the registry type key, which names both the file infix (metadataFileName) and the stack key (singularToPlural); permission-set has no registry entry and would map to no stack key.

Tests

  • packages/cli/src/commands/generate-permission-dataset.pin.test.ts (new, unit): roster facts (directory, stack key, binds, file name), each scaffold loaded through bundle-require as os validate loads it parses under PermissionSetSchema / DatasetSchema with the name os g reports, grants or covers only the bound object, and the no-title-field dataset case.
  • Derived pins that now cover both types without edits: generate-scaffold-validates (zero findings at any severity across validate/build/lint), scaffold-emission-typechecks, create-objectstack-wiring-parity (blank config and barrels byte-equal to what os init renders), generate-file-name-registry-parity, generate-scaffold-wiring, and the nightly generate-scaffolds-reach-stack.e2e / generate-scaffold-gates.e2e (run locally under OS_TEST_TIERS=nightly).
  • packages/create-objectstack/src/scaffold-next-steps-pm.test.ts: a new describe scaffolds through the real CLI under a stub-pnpm PATH and a pnpm-less PATH and reads both written guides back: pnpm run and no bare npm run; control npm run and no pnpm; no unfilled placeholder either way.

Acceptance notes

  • The empty barrel comment reads "The permissions in this directory … a permission exported here": it is rendered by os init's renderEmptyWiredBarrel from the type key and must stay byte-equal to it (wiring-parity pin), so the starter's copy says "permission", not "permission set".
  • src/security holds permission sets only, because its barrel feeds the permissions key. Positions, sharing rules and other security metadata still need their own barrel and key.

Verification

Local runs, on ce2e6f6 (before the one merge of origin/main) unless a line names c45f7cb
  • pnpm --filter create-objectstack exec vitest run: Test Files 23 passed (23), Tests 362 passed (362), on ce2e6f6 and again on c45f7cb.
  • Ablation: .replace(/\{\{PM\}\}/g, pm) removed from index.ts through scripts/ablation-replace.mjs ⇒ both new AGENTS.md cases red (2 failed); restored, blob equal to HEAD, git diff HEAD empty.
  • pnpm --filter @objectstack/cli exec vitest run --project unit : 384 files, 5394 passed, 29 skipped; the 2 published-subpath files first refused because packages/cli was not built, and passed (29/29) after pnpm --filter @objectstack/cli build.
  • c45f7cb, after the merge: rebuilt spec and cli, then 7 targeted unit files (the new pin, scaffold-validates, wiring-parity, file-name parity, scaffold-wiring, emission-typechecks, docs enumeration parity): 169 passed.
  • --project integration test/create-objectstack-stack-reach.test.ts (and the picklist pin): 9 passed. OS_TEST_TIERS=nightly generate-scaffolds-reach-stack.e2e + generate-scaffold-gates.e2e: 58 passed.
  • pnpm --filter @objectstack/cli --filter create-objectstack run typecheck: exit 0. pnpm lint: exit 0.
  • dispatch-gates --commands (93 families), --ran: 89 run green, 4 NOT MEASURED (recorded exit 3, prerequisite not met in this shallow worktree: check-plugin-teardown-shape --self-test needs an unshallow fetch, check:skill-examples needs client builds, check:dual-build-cjs-loads and check:i18n-coverage need packages outside this build closure). CI runs all four.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Utp6CaSDwi65gmZEL5wiWy


Generated by Claude Code

@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/cli, create-objectstack, objectstack-blank, touching 4 documentable anchor(s). ⚠️ 7 changed file(s) yielded no anchor (packages/cli/README.md, packages/create-objectstack/README.md, packages/create-objectstack/src/templates/AGENTS.md, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/deployment/cli.mdx (via os generate (command, read off packages/cli/src/commands/generate.ts))
  • content/docs/getting-started/your-first-project.mdx (via os generate (command, read off packages/cli/src/commands/generate.ts))
  • content/docs/protocol/kernel/lifecycle.mdx (via os generate (command, read off packages/cli/src/commands/generate.ts))
  • content/docs/protocol/objectql/types.mdx (via os generate (command, read off packages/cli/src/commands/generate.ts))

⛔ 3 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v17/17-4.mdx (via os generate (command, read off packages/cli/src/commands/generate.ts))
  • content/docs/releases/v17/17-5.mdx (via os generate (command, read off packages/cli/src/commands/generate.ts))
  • content/docs/releases/v17/17-7.mdx (via os generate (command, read off packages/cli/src/commands/generate.ts))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 7 changed file(s) yielded no anchor (packages/cli/README.md, packages/create-objectstack/README.md, packages/create-objectstack/src/templates/AGENTS.md, …) — pages documenting those are invisible to this run
  • 5 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 61 of 219 client-bound route-ledger rows — the other 158 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 158: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 103 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 41 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 771b2db20ac08d78b7fec5c2bd1ee30de9aa26dc → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 3907b0e9174260c67802a48ac891c51ab07baf63 — the merge of head c45f7cb00c3c468531fc9d6248eb8297a2eb2c25 into base 771b2db20ac08d78b7fec5c2bd1ee30de9aa26dc, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 3907b0e9174260c67802a48ac891c51ab07baf63 && git checkout 3907b0e9174260c67802a48ac891c51ab07baf63
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 771b2db20ac08d78b7fec5c2bd1ee30de9aa26dc c45f7cb00c3c468531fc9d6248eb8297a2eb2c25 && git checkout -B drift-repro 771b2db20ac08d78b7fec5c2bd1ee30de9aa26dc && git merge --no-ff c45f7cb00c3c468531fc9d6248eb8297a2eb2c25

node scripts/docs-audit/affected-docs.mjs --json 771b2db20ac08d78b7fec5c2bd1ee30de9aa26dc

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 771b2db20ac08d78b7fec5c2bd1ee30de9aa26dc → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#4 · os-bill · session_01Utp6CZMkHvuDeVYgTD73qF

席位意见:ACCEPT。空模板一出生就有权限集和数据集的位置,os g 能直接生成两种,生成的 AGENTS.md 用本次探测到的包管理器。

席位核对

Head-sha: c45f7cb00c3c468531fc9d6248eb8297a2eb2c25 · read 2026-11-05T04:22Z

Item Reading
Shape Draft → main, author objectstack-fleet[bot] (relay pr_create); line 1 attribution, Fixes #30123, Clause-② / Metadata-protocol at line start. 13 files, +397/−19.
Premise measured On origin/main the blank template had no src/security or src/datasets, os g had no permission or dataset type, and the generated AGENTS.md said npm run whatever the package manager. The dev's report 6649293531 and the diff agree.
Gates (check-runs on this head) 39 success, 13 skipped, 0 failure, 0 pending. Dev's local --ran: 93 derived, 89 exit 0, 4 NOT MEASURED (exit 3 prerequisites: shallow clone, client builds, packages outside the build closure; CI carries them); pnpm lint and both typechecks exit 0; nightly scaffold e2e 58 passed. Ablation of the PM fill: 2 red, restored.
Accepted deviations Type keys permission / dataset (the registry key drives the file infix and the stack key), not the order's suggested permission-set. The generated set writes readScope: 'own' so the zero-findings pin stays green (security-private-no-readscope). Docs that list the commands (cli.mdx, two READMEs, the blank README) ride along; the claim's file surface was amended to name them.
Clause-② yes (widening): os generate accepts two new type values; nothing is removed or narrowed. Claim 6648662314 amended to match. Seat's own review of record at the default tier: PASS (new values only, existing types unchanged).
Metadata-protocol none: no metadata format or accept surface changes; the template wires existing permissions / datasets stack keys.
Landing Not governed (check-governed-merges --pr 30258: 0 of 13 paths), 416 lines ≤ 3000. Seat lands: pr_ready + automerge_enable.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 5, 2026 04:23
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 5, 2026 04:23
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 5, 2026
Merged via the queue into main with commit 959c26b Nov 5, 2026
53 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-qk8494 branch November 5, 2026 04:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Scaffold: a new project has no wired place for permission sets or datasets, and os generate has no type for them

1 participant