Skip to content

fix(create-objectstack): the blank starter wires every generator barrel, so os g scaffolds reach the stack (#20333) - #20363

Merged
objectstack-fleet[bot] merged 7 commits into
mainfrom
claude/issue-20333-create-objectstack-wire-barrels
Sep 28, 2026
Merged

objectstack-fleet[bot] merged 7 commits into
mainfrom
claude/issue-20333-create-objectstack-wire-barrels

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #20333
Clause-②: no

Summary

npm create objectstack's blank starter imported ./src/objects alone, so everything os g view|action|flow|dashboard|app|skill wrote was never loaded and os validate counted 0 of it. The starter now wires the seven generator barrels os init wires since PR #20329, in the lines os init renders: exportsOf over export {}; barrels, and requires: ['automation', 'triggers']. The copy is bound to the CLI's single source (SCAFFOLD_WIRED_BARRELS / SCAFFOLD_WIRED_REQUIRES, derived from GENERATOR_SCAFFOLD_TARGETS) by a parity pin, so it is not a second wiring rule. A per-PR pin drives npm create objectstack → os g object (control) → os g flow → os validate and reads Logic: 1 Flows.

What changed

  • packages/create-objectstack/src/templates/blank/objectstack.config.ts: imports every wired barrel, declares the exportsOf helper, and hands each barrel to its stack key. The objects import changes from './src/objects/index.js' to './src/objects', the extensionless form os init renders, which the parity pin compares verbatim; the template's moduleResolution: bundler resolves the directory index, and a fresh scaffold type-checks. It carries requires: ['automation', 'triggers']. automation was already there for the three connector plugins, and its comment keeps that reason.
  • Six new src/{views,actions,flows,dashboards,apps,skills}/index.ts barrels, byte-identical to what os init writes.
  • Two pins in packages/cli/test/ (below). The CLI is the only package that can call the renderer, and it already depends on create-objectstack.
  • packages/cli/package.json gains @objectstack/connector-{rest,openapi,mcp} as devDependencies (lockfile +9 lines, one importer block). They exist only so the scaffolded project the chain pin builds under the CLI's node_modules can resolve the blank config's connector imports, and so CI builds them in @objectstack/cli#test's closure.
  • scripts/cross-package-test-inputs.mjs and turbo.json declare the blank config and src/** as inputs of @objectstack/cli#test, with a witness for the barrel glob the scan cannot name.
  • Docs this change made false (see below), and a create-objectstack patch changeset.

Why a static copy, and what binds it

create-objectstack cannot import the roster. The dependency edge runs the other way, and the npx entry must not pull the CLI's closure: the boundary scripts/sync-scaffold-emission-policy.mjs already documents. Measured options:

  • Generate at build time. The roster is computed from the GENERATORS literal in generate.ts. Reading it at create-objectstack's build would need either text-parsing that literal, or evaluating the CLI's source before the CLI's own dependencies are built, which is a build-order cycle.
  • Parity pin over a static copy. Chosen as the least machinery. create-objectstack-wiring-parity.test.ts reads every expected line off the CLI: the barrel import lines, the exportsOf line and the stack-key lines of TEMPLATES.app.configContent, the requires tokens as a superset of SCAFFOLD_WIRED_REQUIRES, and each empty barrel byte for byte from TEMPLATES.app.srcFiles. A generator added to the roster, a renderer change or a hand edit of the template reddens it (ablations A1 to A3).

Measured before and after, through the real commands

The on-ramp's real bin/ scaffolded my-app --skip-install --skip-skills into a directory where the config's imports resolve, then this repo's CLI ran.

step origin/main c74de10a9 this branch
os g object order_line (control) exit 0, reaches the stack exit 0, reaches the stack
os g flow order_line exit 0, Not wired exit 0, reaches the stack
os validate exit 0, Data: 2 Objects, Logic: 0 Flows exit 0, Data: 2 Objects, Logic: 1 Flows
  • exportsOf is required here too. A fresh starter type-checks (tsc --noEmit, 6.0.3, exit 0). The same starter with Object.values on the empty barrels fails with 4 x TS2322 (actions, flows, dashboards, apps). After generating the object and the flow it still type-checks.
  • requires boots. os dev --fresh on a random port: the flow-less fresh starter was healthy after about 22s, /api/v1/ready answered 200, and AutomationServicePlugin and the record-change, schedule, time-relative and api trigger plugins loaded, resolved through the CLI's own dependencies. With the generated flow it was healthy after about 24s and reported Flows: 1 flow(s) 1 bound to triggers. Neither boot printed "not enabled" or "NOT installed".
  • Census. src/templates/ holds one starter, blank, which is also the registry's only entry.

Pins

  • packages/cli/test/create-objectstack-wiring-parity.test.ts (unit, per-PR): 20 cases, described above.
  • packages/cli/test/create-objectstack-stack-reach.test.ts (integration, per-PR, not .e2e): the chain above, with item names read off the generator roster. It asserts the exit codes, the named subjects, the absence of the wiring lines and of a requires line from os g flow, and the Data: 2 Objects / Logic: 1 Flows counts. No prose is pinned.

Ablations

Each ran after the fix was committed. Mutations went through scripts/ablation-replace.mjs in wrap mode, which verified the anchor count and the blob change and restored with blob equal to HEAD and an empty git diff HEAD.

  • A1, the wiring reverted (the flows: exportsOf(flows), line deleted, then create-objectstack rebuilt). ablation-dist-preflight --absent confirmed the line was gone from dist/. Chain pin: 2 failed, 2 passed. The control and the scaffold stayed green, and os g flow printed the wiring lines while validate read no Logic: 1 Flows. Parity pin: 1 failed, 19 passed, on the stack-key comparison. Direction: red.
  • A1 restore. Rebuilt; ablation-dist-preflight found the marker present in dist/templates/blank/objectstack.config.ts, and the whole tree was clean. Chain pin 4/4, parity pin 20/20.
  • A2, a barrel dropped from the template (the skills key deleted): parity 1 failed, 19 passed. Red.
  • A3, one barrel's bytes drifted from what os init writes (views/index.ts reworded): parity 1 failed, 19 passed. Red.
  • After A2 and A3 the whole tree was clean, and parity was 20/20.

Verification

Patch round 1, at HEAD 702a27775 (origin/main a88a1bb39 merged at df0c0c846): the 124 derived gates, check-issue-citations --base origin/main and check:scaffold-emission-policy all exited 0 on the first pass (--ran: 124 derived, 124 run, 0 NOT-MEASURED, 0 UNRUN), including check:doc-anchors, check:docs-audit-scope and check-affected-docs; pnpm lint exited 0; the parity pin 20/20, the chain pin 4/4, and create-objectstack 16 files, 232 passed.

Round 0: all of the following ran at HEAD d50d46fe0 (origin/main 26daf0b03 merged).

  • pnpm --filter create-objectstack test: 16 files, 232 passed. typecheck: exit 0.
  • pnpm --filter @objectstack/cli typecheck: exit 0, including check:test-typecheck, whose ledger is unchanged.
  • CLI unit project: 231 files, 3316 passed.
  • CLI integration: this chain pin plus generate-stack-reach.test.ts, 2 files, 11 passed.
  • pnpm lint: exit 0 over the whole repo, not narrowed.
  • node scripts/check-issue-citations.mjs --base origin/main: exit 0.
  • node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran: 124 derived, 124 run, 0 NOT-MEASURED, 0 UNRUN. Three gates first exited 3 with PREREQUISITE NOT MET (check:skill-examples, check:dual-build-cjs-loads, check:i18n-coverage) and exited 0 after a full build.
  • pnpm check:scaffold-emission-policy: exit 0.

Docs this change made false, and a surface note

These published lines described an objects-only starter and are corrected in place:

  • the blank starter's README.md Layout, plus its app remedy, which now says to export the file from src/apps/index.ts;
  • the shipped AGENTS.md rule 3, which prescribed Object.values() (measured TS2322 on the now-empty barrels);
  • the package README.md tree;
  • content/docs/getting-started/your-first-project.mdx: its section-2 tree and config block;
  • content/docs/getting-started/build-with-claude-code.mdx (patch round 1): step 3 said the agent wires the action, view and app through actions: / views: / apps: keys in defineStack(). It now says each file is exported from its directory's barrel (src/actions/index.ts, src/views/index.ts, src/apps/index.ts), which the starter's config already hands to defineStack(), matching the shipped AGENTS.md rule 3. A sweep of content/docs/ found no other sentence telling a starter author to add a collection key;
  • content/docs/deployment/cli.mdx.

In cli.mdx, the os generate section's "Not wired" example named "the npm create objectstack starter", and its first-app walkthrough ran os generate action approve. On the wired starter that action is refused with exit 1: "Action 'approve' references object 'my_app_approve' which is not defined in objects". The walkthrough now runs object customer, then flow customer, then action customer, measured UI: 1 Actions and Logic: 1 Flows. Its fixture callout now names the extra action.

content/docs/** and packages/create-objectstack/README.md were outside the claim's first file surface; the seat amended the claim in place to name them. They are edited under the agent contract's rule that a published line this change makes false is repaired in the same PR. PR #20341 edits cli.mdx around lines 1619 to 1690, disjoint from these hunks; PR #20258 edited lines 1 to 7 of your-first-project.mdx and build-with-claude-code.mdx, has since landed, and merged into this branch without conflict.

skills/objectstack-platform/SKILL.md line 192 says the template declares requires: ['automation']. That is now stale, but skills/** is a governed Tier H surface, so it is not edited here; the seat files it for the skills lane once this PR lands.

Acceptance notes


Generated by Claude Code

`npm create objectstack`'s blank config imported ./src/objects alone, so
every `os g view|action|flow|dashboard|app|skill` scaffold was written and
never loaded, and `os validate` counted 0 of them. The config now wires
the seven barrels `os init` wires, in the lines `os init` renders
(`exportsOf` over `export {};` barrels), and `requires` gains `triggers`
beside the `automation` its connectors already needed.

Claude-Session: https://claude.ai/code/session_01UYBdGBzWSrAMzpW8ah3GbP
Co-authored-by: Claude <noreply@anthropic.com>
A unit parity pin reads every expected line off the CLI's own render
(TEMPLATES.app, SCAFFOLD_WIRED_BARRELS, SCAFFOLD_WIRED_REQUIRES) and holds
create-objectstack's blank config and barrels to it. A per-PR integration
pin drives `npm create objectstack` -> `os g object` (control) ->
`os g flow` -> `os validate` and reads `Logic: 1 Flows`.

The blank config imports three connector packages; they become CLI
devDependencies so the scaffolded project resolves them and CI builds them
in this suite's closure.

Claude-Session: https://claude.ai/code/session_01UYBdGBzWSrAMzpW8ah3GbP
Co-authored-by: Claude <noreply@anthropic.com>
Both new pins measure create-objectstack's blank config and src/ tree, so
@objectstack/cli#test declares them (with a witness for the barrel glob the
scan cannot name) and turbo.json hashes them.

Claude-Session: https://claude.ai/code/session_01UYBdGBzWSrAMzpW8ah3GbP
Co-authored-by: Claude <noreply@anthropic.com>
…a chain that composes

The starter's tree, config and agent guide, the package README, the Your
First Project page and the CLI page described an objects-only starter.
They now name the seven wired barrels, `exportsOf` and the `triggers`
requirement. The CLI page's first-app walkthrough generated an action bound
to an object nobody declared; on the wired starter that is refused, so the
walkthrough now binds the flow and the action to the object it creates.

Claude-Session: https://claude.ai/code/session_01UYBdGBzWSrAMzpW8ah3GbP
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/l dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation tests tooling labels Sep 28, 2026
@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

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

  • content/docs/getting-started/build-with-claude-code.mdx (via exportsOf (symbol, a top-level const))
  • content/docs/getting-started/your-first-project.mdx (via exportsOf (symbol, a top-level const))
What this run could not see
  • 9 changed file(s) yielded no anchor (packages/create-objectstack/README.md, packages/create-objectstack/src/templates/AGENTS.md, packages/create-objectstack/src/templates/blank/README.md, …) — pages documenting those are invisible to this run
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 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; 97 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 — 10 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 5a6267f4862556fd7422cd161cd931b03aa17b72 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from eff30fa2412644f9cd7e917ccd8f34c2d92223b0 — the merge of head 702a27775dfda9c4bd3dc96f2fb775ba026c8de1 into base 5a6267f4862556fd7422cd161cd931b03aa17b72, 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 eff30fa2412644f9cd7e917ccd8f34c2d92223b0 && git checkout eff30fa2412644f9cd7e917ccd8f34c2d92223b0
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 5a6267f4862556fd7422cd161cd931b03aa17b72 702a27775dfda9c4bd3dc96f2fb775ba026c8de1 && git checkout -B drift-repro 5a6267f4862556fd7422cd161cd931b03aa17b72 && git merge --no-ff 702a27775dfda9c4bd3dc96f2fb775ba026c8de1

node scripts/docs-audit/affected-docs.mjs --json 5a6267f4862556fd7422cd161cd931b03aa17b72

⚠️ 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 5a6267f4862556fd7422cd161cd931b03aa17b72 → 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

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: d50d46fe0da3a3192183393f6a4c824d93c9a940

① Derived judgments

  • The static copy is bound to the single source. Correct.
    • packages/cli/test/create-objectstack-wiring-parity.test.ts reads SCAFFOLD_WIRED_BARRELS, SCAFFOLD_WIRED_REQUIRES and TEMPLATES.app.configContent/srcFiles from packages/cli/src/commands/init.ts:602-703.
    • It compares the sorted BARREL_IMPORT, HELPER and STACK_KEY lines with toEqual, checks requires as a superset, compares each empty barrel byte-for-byte, and adds vacuity guards.
    • Each kind of drift reddens it:
      • a generator added to GENERATORS (generate.ts:559-577) grows the roster, which reddens toEqual and the %s exists case;
      • a new token in FLOW_SCAFFOLD_REQUIRES reddens the superset check;
      • a reworded renderEmptyWiredBarrel reddens the byte compare;
      • a changed import style in renderWiredImports reddens the vacuity guard.
    • So it is not a silent second rule. The only designed slack: if a token is removed from the roster, the starter keeps its extra token (the superset check). That is acceptable, since the connectors need automation.
  • The six barrels are byte-identical. Correct. Each file equals renderEmptyWiredBarrel(stackKey, type)'s output, article slip included ("a action", "a app").
  • The starter's other files are consistent.
    • blank/package.json needs no new dependency, because the new imports are relative barrels.
    • tsconfig.json includes src/**/* and uses moduleResolution: bundler.
    • objectstack.manifest.json carries no requires.
    • _gitignore, Dockerfile and ci.yml are unaffected.
    • blank-template-console-disclosure.test.ts only asserts there is no .app.ts, so the empty barrels pass.
  • The providers resolve outside the monorepo. Correct by reading.
    • Serve.CAPABILITY_PROVIDERS (serve.ts:1863-1937) maps automation/triggers to @objectstack/service-automation, trigger-record-change, trigger-schedule and trigger-api.
    • They are loaded via await import(pkg) inside the CLI module, so they resolve from @objectstack/cli's own dependencies, where all four are present in packages/cli/package.json.
    • A real starter installs @objectstack/cli as a devDependency, and its Dockerfile runtime image ships the CLI: the same path automation already used.
    • Not re-booted here. The dev's boot ran inside the monorepo, but the mechanism is location-independent.
  • The './src/objects' import is safe.
    • moduleResolution: bundler resolves the directory index.
    • Every starter script goes through objectstack * (an esbuild-loaded config) or tsc --noEmit. No script runs Node ESM on the config, and the starter ships no bundler.
    • The form is the one os init renders, and the parity pin requires it.
  • The packages/cli devDependencies are justified, and nothing published changes.
    • files is ['dist','README.md','CHANGELOG.md'], and dependencies is unchanged.

    • Why the devDeps are needed: the chain pin scaffolds under packages/cli/node_modules/.create-objectstack-reach-*, so Node resolves @objectstack/connector-* from packages/cli/node_modules. The devDeps put those packages in @objectstack/cli#test's ^build closure; temp-dir symlinks would not.

    • There is no cycle: no connector depends on @objectstack/cli.

    • The lockfile changes only the packages/cli importer block:

      • the keys are in pnpm sort order;
      • the link:../connectors/connector-* paths exist;
      • the header is unchanged.

      That is consistent with regeneration by tooling.

  • The scripts/cross-package-test-inputs.mjs + turbo.json edits are minimal and correct. They add two globs on the existing @objectstack/cli entry, plus a heldBy witness in the shape the file documents (:87-95, ten prior uses). turbo.json mirrors exactly those two globs. Nothing else under scripts/ changed.
  • The cli.mdx walkthrough is true.
    • os generate object customer yields my_app_customer.
    • flow customer writes customer_flow, bound to my_app_customer (generate.ts:319-406).
    • action customer writes type: 'flow', objectName: 'my_app_customer' and target: 'customer_flow' (generate.ts:277-317), so "runs the flow" and the object-first ordering hold.
    • The fixture callout's "a second action and a Logic: row" is consistent.
    • The os info/os compile fixture blocks print Runtime: 3 plugins and no capability line, so triggers leaves them true.
  • your-first-project.mdx §2 is true. The tree and the config code lines match the head template.
  • Overlap with open PRs: clear.
  • Docs made false: one was missed. Wrong.
    • content/docs/getting-started/build-with-claude-code.mdx:226-228 says that, in the npm create objectstack project of its step 1, the agent wires a new action, view and app "via the actions: / views: / apps: arrays in defineStack()".
    • On the wired starter, those keys are already exportsOf(...). Following the line means writing a duplicate property or replacing the barrel wiring. The shipped AGENTS.md rule 3, rewritten in this PR, now says the opposite.
    • The PR body names this duplicate-key hazard as "inference, not measured" and leaves the page.
    • The cli.mdx fixture callout links to that section. docs(content,spec): search-ready page descriptions — 52 authored rewrites and derived reference descriptions #20258's hunk on the page is lines 1-7, so a fix is disjoint.

② Semver level

create-objectstack: patch is right: it is a bug fix to generated starter content.

  • create-objectstack is in the changeset fixed group with @objectstack/cli (.changeset/config.json:77), so the group bumps together.
  • @objectstack/cli gains tests and devDependencies only, with no published API change.

Clause-②: no is right: no accept set changes. Check Changeset is green.

③ Boundary flags

  • Files outside the amended claim: none, strictly. Claim 5861507334 (amended at 03:04Z, after the 03:02Z report) names every file in the 20-file diff. One soft stretch: the parity unit pin lives in packages/cli/test/, while the claim words the tests as "packages/create-objectstack tests, and one per-PR pin". It is declared in the PR body.

  • PR body vs diff:

    • These match: the 20 parity cases (2+4+7+1+6), the 4 chain cases, the lockfile +9, the devDeps +3, and the scripts and turbo edits.
    • "Docs this change made false are corrected in place" is incomplete (see the bullet above).
    • The './src/objects' import change appears in the report's deviation (2), but not in the body's "What changed".
  • SKILL.md:192: confirmed stale on head (requires: ['automation']). It is governed and declared out. skills/objectstack-platform/references/bootstrap.md:161-180 is a generic bootstrap, not the starter.

  • Not re-measured: install, typecheck and boot of a fresh starter. The review relied on reading, plus CI's Scaffold with repo dist and the Test Core shards.

  • CI on head (read last): 36 check runs.

    • 27 success and 0 failure.
    • 3 skipped: Console Pin Gate, Packed-tarball smoke (opt-in) and Registry canary.
    • 6 in progress: Lint & Repo Gates, Test Core (1/6), Test Core (3/6), Test Core (5/6), Test Core (6/6), and Type Check · workspace.

    Both new pins run in Test Core shards that are still in progress.

Implemented-by: claude/issue-20333-create-objectstack-wire-barrels
Reviewed-by: session_01UYBdGBzWSrAMzpW8ah3GbP

Independence: INDEPENDENT AGENT (fed the card, the triage direction and the PR only; not the dispatch order or the seat's conclusions)

VERDICT: FAIL

…t by stack keys

Build with Claude Code said the agent wires the action, view and app through
`actions:` / `views:` / `apps:` arrays in defineStack(). On the wired
starter those keys already read the barrels through exportsOf(), so a
second key duplicates it (tsc TS1117) and replaces the barrel's wiring (a
later `os g view` reports Not wired). The page now says each file is
exported from its directory's index.ts, which is the whole wiring.

Claude-Session: https://claude.ai/code/session_01UYBdGBzWSrAMzpW8ah3GbP
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review (delta, patch round 1)

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 702a27775dfda9c4bd3dc96f2fb775ba026c8de1

① Derived judgments

  • Delta is exactly one PR file. Correct. git diff origin/main...702a277 --stat lists 21 files; the previous head's list (vs its merge-base 26daf0b03) lists 20; the only addition is content/docs/getting-started/build-with-claude-code.mdx. Per-file hunk hashes of the other 20 PR files are identical at both heads. Commit 702a277 touches that one page only (+10 -6). The raw .changeset/ noise in the d50d46fe0..702a277 range is merged-main content (19886-rls-...), not PR content.
  • Merge df0c0c846 carries no manual resolution. Correct. git merge-tree --write-tree d50d46fe0 a88a1bb39 yields tree 502b0687f, equal to df0c0c846^{tree}. The merge's only diff to parent 1 in PR files is docs(content,spec): search-ready page descriptions — 52 authored rewrites and derived reference descriptions #20258's frontmatter line on the two getting-started pages. Head also auto-merges clean with current origin/main 5049a3cf4.
  • The new paragraph (:226-:235) is true on the head. Correct, one wording note.
    • blank/objectstack.config.ts :5-:11 imports all seven barrels, :15 declares exportsOf, :73-:79 hands objects, views, actions, flows, dashboards, apps, skills to defineStack() through it. src/objects/index.ts exports Note; the six others are export {}; barrels. So "every barrel" and "the config is not edited" hold for the four kinds step 3 names.
    • exportsOf is Object.values(barrel), so a named export from src/actions/index.ts, src/views/index.ts, src/apps/index.ts lands in the matching key. Wording matches the shipped templates/AGENTS.md rule 3 (:49-:53) and blank/README.md :40-:46, :71-:76.
    • "would duplicate the key and replace that barrel's wiring": a duplicate literal key is TS1117 in every placement; at runtime the later key wins (confirmed with node: {views: Object.values(a), views: [b]} gives [b]). "Replace" is precise for the natural append placement; a key added before the exportsOf line would instead be dropped. Not a required change. measureStackReach (packages/cli/src/utils/scaffold-wiring.ts :108-:130) loads the real config and asks stackCarries, so the body's "a later os g view customer reports Not wired" follows from the same mechanism.
    • Step 4 still agrees: Data: 2 Objects 6 Fields is note (2) plus ticket (4), UI: 1 Apps 1 Views 1 Actions is SupportApp, the one defineView container, ResolveTicketAction; :237-:241 and :100 ("wire barrel exports") are consistent with the new step 3. Not re-measured (no node_modules in the shared checkout); the counts were unchanged by the delta.
  • Sweep of content/docs/ (excluding references/, releases/). Complete. Swept for objectstack.config plus edit verbs, starter/blank/npm create mentions, KEY: [ arrays, backticked keys in prose, "register/add/import ... into the config", "scaffold" prose, and a stale requires: ['automation'] line (none). The five dismissals are right: connectors.mdx:332 is defineConnector.actions, not a stack key; flows.mdx:1767 is the generic com.example.crm config; flows.mdx:2328 is a fragment; cli.mdx:2117-2136 is the generic ## Configuration example; examples.mdx:179-204 is examples/app-todo (com.example.todo). Extra hits I judged, none addressed to the starter: ui/views.mdx:59-66 ("Register the container in your stack config", file src/ui/views/task.view.ts), troubleshooting.mdx:243-255, common-patterns.mdx:517-532, quick-start.mdx:170-173 (describes barrels imported into the config, consistent).
  • PR body vs diff. Correct. "What changed" now carries the objects-import change ('./src/objects/index.js' to './src/objects', verified main vs head). The docs list matches the six doc files in the diff. The claim-surface paragraph matches claim 5861507334 as amended 03:18:44Z, which names content/docs/**, the package README and the page. skills/objectstack-platform/SKILL.md:192 reads requires: ['automation'] on head, stale and declared out. The Verification header (702a27775, a88a1bb39 merged at df0c0c846) matches git log. Gate counts not re-run; see CI. One tense nit: feat(qa): os test prints suite and scenario names and selects scenarios by --tags #20341 has since landed (5a6267f48, 03:57Z, after the merged a88a1bb39); its cli.mdx hunks (1651, 1677, 1685) stay disjoint from this PR's (33, 739, 1410, 1421).

② Semver level

create-objectstack: patch stays right: the delta is prose on a docs page; the package change is a bug fix to generated starter content, and create-objectstack sits in fixed group 0 (69 packages) with @objectstack/cli, which gains only tests and devDependencies. Clause-②: no stays right: no accept set changes in the delta or the PR. Check Changeset is green.

③ Boundary flags

  • Files outside the amended claim: none. The delta touches only build-with-claude-code.mdx, named in the amended claim for patch round 1.
  • Conflict resolution in the merge: none (tree equals the automatic merge).
  • Not re-measured: the fresh-starter os validate counts and the 3 x TS1117; the shared checkout has no installed dependencies. Runtime last-key-wins confirmed with node.
  • PR state: still Draft, mergeable_state: clean.
  • CI on head 702a277 (read last, 04:48Z): 45 check runs, 40 success, 5 skipped (Auto Label, Check PR Size, Console Pin Gate, Packed-tarball smoke (opt-in), Registry canary), 0 failure, 0 in progress. Green includes Test Core 1/6 to 6/6, Lint & Repo Gates, Type Check · workspace, Scaffold with repo dist, Check Changeset, Build Docs, Check Documentation Links, Flag docs affected by code changes. Combined status: success.

Implemented-by: claude/issue-20333-create-objectstack-wire-barrels
Reviewed-by: session_01UYBdGBzWSrAMzpW8ah3GbP

Independence: INDEPENDENT AGENT (fed the card, the triage direction and the PR only; not the dispatch order or the seat's conclusions)

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 28, 2026 04:52
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 28, 2026
Merged via the queue into main with commit c577e66 Sep 28, 2026
47 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-20333-create-objectstack-wire-barrels branch September 28, 2026 05:17
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 28, 2026
… requires automation+triggers, seven barrels via exportsOf (objectstack-ai#20410)

Fixes objectstack-ai#20385
Clause-②: no

## What was false, and what the skill now says

`skills/objectstack-platform/SKILL.md` 〈The Template〉 said the blank
starter declares `requires: ['automation']` and said nothing about the
barrel wiring. Read on the branch base `df3ba164` (`origin/main` at
claim time),
`packages/create-objectstack/src/templates/blank/objectstack.config.ts`
declares `requires: ['automation', 'triggers']` (line 51), keeps the
three generic connector executors in `plugins:` (lines 61–65:
`ConnectorRestPlugin`, `ConnectorOpenApiPlugin`, `ConnectorMcpPlugin`),
and hands all seven generator barrels (`objects`, `views`, `actions`,
`flows`, `dashboards`, `apps`, `skills`) to the stack key of the same
name through `exportsOf` (lines 73–79; six of the barrels are `export
{};`). objectstack-ai#20363 landed the template change; the card behind it, objectstack-ai#20333, is
not addressed here.

The bullet now states those facts and points at the scaffolded
`AGENTS.md` for how to add to the barrels — one pointer, not a second
spelling of its rule (the claim's judgement). The pointer names the file
without a rule number so a later renumbering of that list cannot make
the skill stale again.

## Sentence-by-sentence audit of the starter's description (the
execution note)

| Where (line on the base) | Sentence | Verdict |
|:--|:--|:--|
| 192–194, 〈The Template〉 | `requires: ['automation']` plus the three
connector executors | FALSE on `requires` (no `triggers`) and SILENT on
the seven barrels → rewritten |
| same bullet | "the three generic connector executors in `plugins:`" |
TRUE (lines 61–65 of the template) → kept |
| same bullet | "The memory driver and the Hono server are NOT in the
file — the CLI auto-registers both at boot" | TRUE (no driver or server
plugin in the file) → kept |
| 357–366, `requires:` table | `triggers` row | already present
(`@objectstack/trigger-record-change`, plus `trigger-schedule` and
`trigger-api`) → no row added; its bold "Pair it with `job`" clause
restated rule 5 under the same table → dropped from the row, rule 5
keeps it in full |
| 399, the five rules | "Keep `automation` whenever `plugins:` lists a
connector" | TRUE for the starter → unchanged |
| 401, the five rules | "Pair `triggers` with `job`" | TRUE → unchanged,
now the one spelling |
| 225, the directory tree | `flows/ # Optional: automation flows` | a
project convention, not the starter → unchanged |
| 245, naming table | `Object.values(imported)` | still true —
`exportsOf` is a typed `Object.values` → unchanged |
| `references/bootstrap.md` § Scaffolding Command | "blank is the
default, and the only, template" | TRUE → unchanged |

## Paying the skills token ratchet (headroom 2 → 4)

Net content added by the rewritten bullet is paid by deleting redundancy
in the same file, nothing moved elsewhere and the ceiling untouched:

- The retired-templates paragraph (four lines) is one sentence. The CLI
already prints `Template "NAME" has been retired and is no longer
available.` when one is asked for by name
(`packages/create-objectstack/src/index.ts`, line 414), so the skill
needs the fact, not the marketplace history.
- The `triggers` table row drops the "Pair it with `job` — schedule and
time-relative triggers run on the job service" clause; rule 5 directly
under the table says the same thing with its consequence, and every
other row in that table lists providers only.
- "works offline, no network fetch" → "no network fetch" (one claim,
said once).

## Readings

### line_budget

| Scope | before | after |
|:--|--:|--:|
| file lines (`skills/objectstack-platform/SKILL.md`) | 487 | 489 |
| file bytes | 23321 | 23313 |
| file tokens (ratchet, ceil bytes/4) — ceiling 5833 | 5831 (headroom 2)
| 5829 (headroom 4) |
| package: lines over every `skills/**/SKILL.md` (10 files) | 4402 |
4404 |
| package: authored bundle tokens (ratchet total / ceiling) | 143456 /
154938 | 143454 / 154938 |
| package: bundle total tokens (whole shipped tree) | 153970 | 153968 |

### gates

Derived with `node scripts/pm/dispatch-gates.mjs --repo
objectstack-ai/objectstack --commands` at `7ac5e9f4` (1 path vs merge
base `df3ba164`; 25 commands). Every exit code captured before any pipe
(`cmd > log 2>&1; EXIT=$?`). `--ran` reconciliation with exit codes: 25
derived, 25 run, 0 NOT-MEASURED, 0 UNRUN.

| Command | exit | verdict line |
|:--|--:|:--|
| `node scripts/check-ci-filter-parity.mjs` | 0 | pass |
| `node scripts/check-closing-keyword-parity.mjs` | 0 | pass |
| `node scripts/check-closing-keyword-parity.mjs --self-test` | 0 | pass
|
| `node scripts/check-comment-mask-corpus.mjs` | 0 | pass |
| `node scripts/check-doc-route-spelling.mjs --advisory` | 0 | pass |
| `node scripts/check-doc-route-spelling.mjs --self-test` | 0 | pass |
| `node scripts/check-skills-token-ratchet.mjs` | 0 |
`skills/objectstack-platform/SKILL.md is 5829 tokens (ceiling 5833;
headroom 4)` · `54 authored bundle file(s) within their ceilings` |
| `node scripts/check-skills-token-ratchet.mjs --self-test` | 0 | pass |
| `pnpm --filter @objectstack/lint run check:doc-formula-expressions` |
3 then 0 | first run: PREREQUISITE NOT MET (`@objectstack/formula` and
`@objectstack/lint` not built — nothing measured); built both under the
verify lock (`turbo run build --filter=@objectstack/formula
--filter=@objectstack/lint --concurrency=2`, VERDICT command-exit 0);
re-run: `22 record-scoped formula example(s) across 456 files / 1383 TS
blocks judged clean` |
| `pnpm --filter @objectstack/spec run check:skill-docs` | 0 | `Skill
docs in sync` |
| `pnpm check:agent-test-spelling` | 0 | pass |
| `pnpm check:corpus-claim-drift` | 0 | pass |
| `pnpm check:cross-package-test-inputs` | 0 | pass |
| `pnpm check:doc-authoring` | 0 | `53 published skill files clean — no
internal issue-id references` |
| `pnpm check:driver-memory-census` | 0 | pass |
| `pnpm check:gitlink-declared` | 0 | pass |
| `pnpm check:nul-bytes` | 0 | `OK (scanned 9892 text file(s) … no raw
ASCII control bytes)` |
| `pnpm check:pm-governed-merges` | 0 | self-test, 454 assertions (what
CI runs for this family) |
| `pnpm check:refd-timer-probe` | 0 | pass |
| `pnpm check:role-word` | 0 | pass |
| `pnpm check:skill-compatibility` | 0 | pass |
| `pnpm check:skill-frame-sync` | 0 | pass |
| `pnpm check:skill-identifier-liveness` | 0 | pass |
| `pnpm check:skill-top-level-keys` | 0 | pass |
| `pnpm check:watch-hint-literal` | 0 | pass |

Also run outside the derivation: `grep -naP
'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]' skills/objectstack-platform/SKILL.md`
→ no match.

### tests

`Test Core` is path-scheduled by `skills/**`. The diff touches no
package, so no dependency closure (①) and no package suite (②) is owed;
run locally instead are the test files whose code reads the `skills/`
root (the only tests a prose change here can move), under the verify
lock (VERDICT command-exit 0, held 33s, waited 0s), each invocation
checked for a non-zero file count:

| Command | exit | result |
|:--|--:|:--|
| `pnpm --filter create-objectstack exec vitest run --maxWorkers=2
src/template-consistency.test.ts` | 0 | 1 file, 37 tests passed |
| `pnpm --filter @objectstack/formula exec vitest run --maxWorkers=2
src/skill-catalog-sync.test.ts` | 0 | 1 file, 1 test passed |
| `pnpm --filter @objectstack/rest exec vitest run --maxWorkers=2
src/meta-state-route-doc-spelling.test.ts` | 0 | 1 file, 8 tests passed
|
| `pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2
scripts/dist-freshness-adoption.test.ts scripts/export-list.test.ts
scripts/query-pointer-row.test.ts
scripts/solution-blueprint-header-row.test.ts` | 0 | 4 files, 26 tests
passed |

NOT MEASURED, declared to CI: the full `Test Core` shards;
`packages/cli/test/generate-skill.e2e.test.ts` (integration tier — it
spawns the CLI; the diff touches no spawn entry); the four type-check
lanes (no TypeScript touched); shard attestation and test-completeness
(values exist only in a CI run); the 55 artifact-roster, 11
wide-population and 14 pending-changeset families the derivation lists
outside its runnable total.

### changeset

`skip-changeset`. No published package's `files[]` names `skills/**`
(read over every `packages/**/package.json`: zero); the catalog reaches
customers by `npx skills add objectstack-ai/objectstack/skills` from
this repository (`packages/create-objectstack/src/skills-install.ts`,
line 62), not from an npm tarball. Measured after building
`create-objectstack` (the only package that names the catalog at all):
the edited sentence's phrase `generic connector executors in` hits 0
files across its `files[]` paths (`dist`, `README.md`, `CHANGELOG.md`)
and 0 files across the 5 `dist/` trees present on disk; positive control
`exportsOf` hits 2 files in that same `dist`.

### deviations

- None of the derived families was narrowed or skipped. The one exit 3
(`check:doc-formula-expressions`) was a declared prerequisite, cleared
by building and re-running; recorded above as 3 then 0.
- The commit's attribution trailer is the model-free pair AGENTS.md
prescribes (`Claude-Session:` + `Co-authored-by: Claude`), not the
harness-suggested model-named form.

### files_changed

- `skills/objectstack-platform/SKILL.md` (+11 / −9)

## Acceptance notes (observed, not filed)

- `## Project Structure Conventions` (lines 209–232) lists no
`src/skills/` directory, while the starter now ships one with its own
barrel. That section describes a project convention, not the starter;
class: none of a/b/c; carrier: none.
- Line 245's naming row spells the barrel hand-off as
`Object.values(imported)`; the starter spells it `exportsOf(barrel)`, a
typed `Object.values`. Both true; carrier: none.
- "Bundled with `create-objectstack` — no network fetch" describes the
template itself; the scaffold's separate skills-install step (`npx -y
skills add …`) does fetch. Pre-existing claim, shortened here without
changing its substance; carrier: none.

## 维护者速读(草稿)

**改了什么**:平台技能(`skills/objectstack-platform/SKILL.md`)里描述 `blank`
起步模板的那一段,改成与实际发出的模板一致:`requires` 现在是 `['automation',
'triggers']`,并说明七个目录
barrel(objects/views/actions/flows/dashboards/apps/skills)都已经通过
`exportsOf` 接到同名 stack 键,加一句指向脚手架生成的 `AGENTS.md` 说明怎么往里加东西。为了不超过技能包的
token 上限,同一文件里删了三处重复表述(退役模板段落压成一句、`triggers` 表格行不再重复规则 5、"works offline
/ no network fetch" 只说一次)。

**为什么改**:技能是 AI 写应用时读的说明书;这句话过时后,AI 按它描述起步项目会漏掉 `triggers`(`objectstack
generate flow` 生成的 flow 装不上),也不知道 barrel 已经接好,可能手加 stack 键而不是从 barrel
导出。

**风险与代价(含回滚)**:纯文档改动,不动代码、不动发布包(`skills/**` 不在任何已发布包的 `files[]`
里,已实测);风险只在措辞被误读,已逐句对照模板文件核过并列在上表。回滚:revert 本 PR 的一个 commit 即可,无其它依赖。

**席位意见**:

**你要做的**:审阅并 APPROVE 本 PR(`skills/**` 属 Tier H,需要维护者的批准),之后由席位落地。

---
_Generated by [Claude
Code](https://claude.ai/code/session_01MjvgiFAmjHqsxy1XLiVYfH)_

Co-authored-by: os-steve <steve@objectstack.ai>
Co-authored-by: Claude <noreply@anthropic.com>
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

2 participants