Skip to content

Commit 658d84f

Browse files
docs(skills): mark the always-on tokens in the platform skill's requires: table (#31181)
<!-- claude-projects-attribution: {"github_login":"huangyiirene"} --> _Requested by **Irene** · [project thread](https://claude.ai/code/project/chan_01TJXtQ1tVD26ecLDZxFS67x?thread=cmsg_01TJXtQ1tVD26ecLDZxFS67xVLaZCHfVovNCieVsJ1xWP3)_ Fixes #31130 Clause-②: no Metadata-protocol: none `dispatch-gates --tier` reads a MANDATORY model tier for `skills/**` (clause ① of the model-tiering ruling); it is waived by the standing order of the maintainer in this project (2026-11-03), and this card ran on the project's default model. The dispatching seat runs the contract review. ## 维护者速读 - 改了什么:`objectstack-platform` 的 `### requires:` 表用 ° 标出全部常驻 token(`PLATFORM_ALWAYS_ON_CAPABILITIES`),导语改为「标 ° 的每次启动都挂载,列不列都一样;`--preset minimal` 恰好去掉这些」;`auth`→`email` 规则注明 minimal 下也成立,`triggers`+`job` 配对限定到 `--preset minimal`;`queues`/`assignmentRules` 一段删去「(`sharing` in `requires`)」;eval 第 3、9 例不再要求在 `requires` 里写 `job`/`messaging`/`sharing`,新增第 20 例(常驻服务要不要列进 `requires:`)。 - 为什么改:导语原文「其余服务插件都是 opt-in」与代码相反:`resolveServedCapabilities` 在非 minimal 预设下把常驻清单追加到每个应用的 `requires`(#31130)。作者会误以为未列出的服务不存在。 - 风险与回滚:只改技能文字与 eval;SKILL.md 6007 → 6004 / 6011(净减 3 token),无上限上调;发 `@objectstack/skills` patch;回滚即 revert。 - 先看:`skills/objectstack-platform/SKILL.md` § `### requires:` 的导语和表,以及 L55 的 `sharing` 一句(下方 diff)。 - 两分钟验证:`node scripts/check-skills-token-ratchet.mjs`,预期退出 0,`objectstack-platform/SKILL.md 6004 / 6011`。 - 需要你做的:`skills/**` 属 Tier H(人合),需要 `os-zhuang` 或 `hotlong` 的一次 approval,之后席位落地。 ## Code sites read (on `main` `8ef4d309`, re-checked after merging `21c1f748`) - `packages/spec/src/kernel/platform-capabilities.ts` `PLATFORM_ALWAYS_ON_CAPABILITIES`: `queue`, `job`, `cache`, `settings`, `email`, `storage`, `sms`, `sharing`, `messaging`, `analytics`, `package-registry`. These, and only these, carry ° in the table. - `packages/core/src/capability-composition.ts` `resolveServedCapabilities`, in order: the declared tokens (deduplicated); `email` when `auth` is declared; `hostDefaults`; the slate unless `preset === 'minimal'`; then `job` and `queue` moved to the front when `email` / `approvals` / `auth` is present. So `--preset minimal` drops the slate and nothing else. - `packages/cli/src/commands/serve.ts` L3006–3009: `hostDefaults` = `mcp` unless `OS_MCP_SERVER_ENABLED` is `0`/`false`/`off`/`no` (`packages/types/src/env.ts` `isMcpServerEnabled`), plus `pinyin-search` when `stampSearchPinyinEnabled(config.i18n)` (the env var, else any `zh-*` locale). They are appended under every preset, `minimal` included. Not taught here (see Other sites). - `packages/core/src/capability-providers.ts`: every slate token has a provider row (`package-registry` → `@objectstack/service-package`, L174), and `packages/cli/package.json` depends on all eleven provider packages, so a stock `os serve` mounts each one. Every existing table row was checked against `PLATFORM_CAPABILITY_TOKENS` and core's `CAPABILITY_PROVIDERS`: every service token has a row and every row names its registry package. No phantom row, no missing row. ## What changes ```diff @@ -52,8 +52,8 @@ objectstack-data): named sets of people a new record of an `ownership: 'user'` object sits in until a member claims it. `assignmentRules` (`defineAssignmentRule`, `@objectstack/spec/automation`; objectstack-automation) routes each inserted ownerless row into a queue — parked, `round_robin` or `least_loaded` — or to one -user. Both need the ownership-queue service `@objectstack/plugin-sharing` registers -(`sharing` in `requires`): a stack declaring either without it is refused at boot. +user. Both need the ownership-queue service `@objectstack/plugin-sharing` registers: +a stack declaring either without it is refused at boot. Undeclared keys are handled per surface, in two postures: @@ -294,18 +294,19 @@ production fails loudly): [Ports & networking](./references/operations.md#ports- ### `requires:` — which service plugins boot -Step 4's list is the fixed core. Every other service plugin is opt-in, and -`requires: [...]` on the stack root is what turns it on. The CLI expands each +Step 4's list is the fixed core. Tokens marked ° are always-on: every boot +mounts them, listed or not, and `--preset minimal` drops exactly those. Every +other service plugin is opt-in: `requires: [...]` on the stack root turns it on. The CLI expands each token through the `CAPABILITY_PROVIDERS` registry in `@objectstack/core`: | Token | Provider package | |:--|:--| | `automation` | `@objectstack/service-automation` — flows, and any declarative `connectors:` entry | -| `analytics` `cache` `storage` `queue` `job` `messaging` `realtime` `settings` `sms` `push` | `@objectstack/service-` + the token ([the `push` block](./references/operations.md#mobile-push)) | +| `analytics`° `cache`° `storage`° `queue`° `job`° `messaging`° `realtime` `settings`° `sms`° `push` | `@objectstack/service-` + the token ([the `push` block](./references/operations.md#mobile-push)) | | `mailbox` | `@objectstack/service-mailbox` — inbound mail | -| `marketplace` `package-registry` | `@objectstack/service-package` | -| `audit` `email` `sharing` `approvals` `webhooks` | `@objectstack/plugin-` + the token | +| `marketplace` `package-registry`° | `@objectstack/service-package` | +| `audit` `email`° `sharing`° `approvals` `webhooks` | `@objectstack/plugin-` + the token | | `pinyin-search` | `@objectstack/plugin-pinyin-search` | | `mcp` | `@objectstack/mcp` | | `triggers` | `@objectstack/trigger-record-change`, plus `trigger-schedule` and `trigger-api` | @@ -315,8 +316,7 @@ through it: - **Tier-gated** — `ai`, `ai-studio`, `i18n`, `ui`, `auth` have no provider entry; dedicated blocks in `serve.ts` `run()` open their tier instead - (`ai`/`ai-studio` through the intent-driven AI block, the other three through - their tier blocks). + (`ai`/`ai-studio` through the intent-driven AI block). - **Enterprise / cloud** — `hierarchy-security` has no open-edition provider and ships in `@objectstack/security-enterprise`, loaded through `plugins[]`; `ai-seat` and `governance` are resolved only by cloud's objectos-runtime. @@ -332,14 +332,14 @@ Five rules that change what you write: - **Declaring is a demand.** A capability YOU declared whose provider package is absent is a hard boot error; one the platform auto-injects for you stays best-effort (warn and continue). -- **`auth` implies `email`.** Auth callbacks need the mail service, so the CLI - appends `email` whenever `auth` is required. +- **`auth` implies `email`**, even under `--preset minimal`: auth callbacks + need the mail service. - **Keep `automation` whenever `plugins:` lists a connector** — connector - executors register their provider factories with it, and without it they have - nowhere to register and boot fails. -- **Pair `triggers` with `job`.** `triggers` alone arms record-change triggers; - schedule and time-relative triggers run on the job service, so autolaunched - scheduled flows stay silent without `job`. + executors register their provider factories with it, and without it boot + fails. +- **Under `--preset minimal`, pair `triggers` with `job`:** `triggers` alone + arms record-change triggers; schedule and time-relative ones run on the job + service, so scheduled flows stay silent. ### `onEnable` — where an app binds runtime code ``` ## Token readings and the deletions that pay them `node scripts/check-skills-token-ratchet.mjs` (`ceil((bytes − 20) / 4)`): `skills/objectstack-platform/SKILL.md` **6007 / 6011 on `main`** (24045 bytes) → **6004 / 6011 at this head** (24035 bytes): a net change of −3 tokens. No ceiling raised; `scripts/check-skills-token-ratchet.mjs` is untouched; standing ruling 6513306068 is not used. The growth (lead sentence + eleven ° markers) is paid by the deletions below, all in the same file. Facts each cut text held, and where each survives: | Cut | Facts it held | Surviving home | |:--|:--|:--| | Tier-gated bullet: ", the other three through their tier blocks" | `i18n` / `ui` / `auth` open a tier | Same bullet: "dedicated blocks in `serve.ts` `run()` open their tier instead", which names all five tokens | | `auth` bullet: "so the CLI appends `email` whenever `auth` is required" | the CLI appends `email` when `auth` is declared | The bullet's own head "`auth` implies `email`", which now also says it holds under `--preset minimal` | | `automation` bullet: "they have nowhere to register and" | connector executors register with the automation service | Same sentence: "connector executors register their provider factories with it" | | `triggers` bullet: "autolaunched", "without `job`" | scheduled flows are autolaunched; they need `job` | The bullet's head now names the pairing ("pair `triggers` with `job`"); "scheduled flows" stays | | Lead: "and … is what" | none (wording) | n/a | | § Full Configuration Reference L55–56: " (`sharing` in `requires`)" (contract review M1) | the ownership-queue service comes from the `sharing` token | The `### requires:` table (`sharing`° → `@objectstack/plugin-sharing`, always-on) and its lead (`--preset minimal` drops it). The remaining sentence ("Both need the ownership-queue service `@objectstack/plugin-sharing` registers: a stack declaring either without it is refused at boot") is true under every preset. | No deleted text is pinned: `grep` of `scripts/**` and `packages/**` for each cut phrase finds only files that never read this skill ("nowhere to register" is matched in `create-objectstack`'s starter-comment test, which reads the scaffold's own comments, and the test's regex also accepts "boot fails", which stays). ## Eval cases (`skills/objectstack-platform/evals/config-plugins-ops.json`) - **Case 3 corrected** (seat ruling Q1). It expected `requires: ['automation', 'triggers', 'job', 'messaging']` and said notify is skipped without `messaging`. Both are always-on on a default boot. It now expects `requires: ['automation', 'triggers']`, says `job` and `messaging` are always-on, and gives the `--preset minimal` caveat. `must_contain` drops `job` / `messaging` for `--preset minimal`. No new `must_not_contain` entry: a careful answer writes the minimal-preset line as `requires: ['automation', 'triggers', 'job', 'messaging']` (contract review S1). - **Case 9 corrected** (contract review M1; claim widened in 6709825690). It expected "plus `'sharing'` in `requires` … else the boot is refused". The refusal (`describeMissingOwnershipQueueService`, `packages/objectql/src/assignment-rules.ts`) tests only that the `ownership-queue` service is registered, and `sharing` is always-on. It now says no `requires` change is needed on a default boot and gives the `--preset minimal` caveat; `must_contain` takes `sharing` instead of `'sharing'` and adds `--preset minimal`, as cases 3 and 20 have, so the old unconditional answer no longer passes (delta review should-fix); `'sharing'` is not banned, since the minimal-preset line spells it. - **Case 20 added**: "Do I have to list `storage` and `settings` in `requires:`?" Expected: no, both are always-on, listing is harmless, only `--preset minimal` drops them. `must_contain` is `--preset minimal` only; neither case 3 nor case 20 requires the hyphenated "always-on" (contract review N2). Eval fixtures are measured, not ratcheted. ## Interplay #31115 item 2 (open, unclaimed) would register this table as a liveness-exhaustive section against `PLATFORM_CAPABILITY_TOKENS` ∩ `CAPABILITY_PROVIDERS`. The ° marker sits outside the backticks, so the token spans it would parse are unchanged; whichever of the two lands second re-reads the first. ## Other sites found (reported, not fixed) Filed as #31184 by the seat: it covers items 1–3 below (the automation rows, the host defaults and the jsdoc). 1. `skills/objectstack-automation/SKILL.md` § Prerequisite table: the `job`, `queue` and `messaging` rows give an "Absent ⇒" outcome, but all three are always-on, so those outcomes happen only under `--preset minimal`. Even there, `email`, `approvals` or `auth` pulls `job` and `queue` back in (`NEEDS_JOB_AND_QUEUE`, `packages/core/src/capability-composition.ts`). Same teaching in `references/examples-flows.md` L132 and `references/integration-recipes.md` L62 (`'job'` added to `requires`). 2. The lead's "Every other service plugin is opt-in" is still false for `mcp` and `pinyin-search`: `os serve` adds `mcp` (unless `OS_MCP_SERVER_ENABLED` is off) and `pinyin-search` (for a `zh-*` locale) as host defaults under every preset, `minimal` included. Left out: the clause naming both costs more than the 7 tokens the `sharing` deletion freed. 3. `packages/spec/src/kernel/platform-capabilities.ts`, the jsdoc on `'package-registry'` in `PLATFORM_ALWAYS_ON_CAPABILITIES` ("⚠️ SCOPE … inert under `objectstack serve` … that registry keys `marketplace`, not this token") is stale: `packages/core/src/capability-providers.ts` L174 keys `package-registry` now. ## Gates On `221a7ff2` (the content commit), after a full `pnpm build`, under `NODE_OPTIONS=--max-old-space-size=8192`: `pnpm build` and all 46 commands from `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` exited 0, plus `pnpm --filter @objectstack/spec run check:skill-refs`, `pnpm check:skill-identifier-liveness`, `pnpm check:skill-compatibility` and `node scripts/check-skills-token-ratchet.mjs`, all exit 0. Not measured locally: the CI-only steps dispatch-gates lists as NOT MEASURED (shard attestation, dogfood, Build Core, type-check lanes). ``` pnpm build :: exit 0 node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0 node scripts/check-adr-0087-registration.mjs --self-test :: exit 0 node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0 node scripts/check-closing-keyword-parity.mjs :: exit 0 node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0 node scripts/check-comment-mask-corpus.mjs :: exit 0 node scripts/check-doc-route-spelling.mjs --advisory :: exit 0 node scripts/check-doc-route-spelling.mjs --self-test :: exit 0 node scripts/check-dts-emitted.mjs --self-test :: exit 0 node scripts/check-empty-changeset.mjs --base origin/main :: exit 0 node scripts/check-empty-changeset.mjs --self-test :: exit 0 node scripts/check-skills-token-ratchet.mjs :: exit 0 node scripts/check-skills-token-ratchet.mjs --self-test :: exit 0 node scripts/ci/assert-turbo-remote-cache.mjs --self-test :: exit 0 node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0 node scripts/ci/prune-turbo-cache.mjs --self-test :: exit 0 node scripts/ci/snapshot-next.mjs --self-test :: exit 0 node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0 node scripts/release-pending-publish.mjs --self-test :: exit 0 pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0 pnpm --filter @objectstack/spec run check:skill-docs :: exit 0 pnpm check:agent-test-spelling :: exit 0 pnpm check:changeset-gate-self-tests :: exit 0 pnpm check:ci-filter-parity :: exit 0 pnpm check:closed-ceremony-text :: exit 0 pnpm check:corpus-claim-drift :: exit 0 pnpm check:cross-package-test-inputs :: exit 0 pnpm check:doc-authoring :: exit 0 pnpm check:driver-memory-census :: exit 0 pnpm check:dts-closure :: exit 0 pnpm check:dual-build-cjs-loads :: exit 0 pnpm check:gitlink-declared :: exit 0 pnpm check:lean-entry-closure :: exit 0 pnpm check:merge-driver :: exit 0 pnpm check:nul-bytes :: exit 0 pnpm check:pm-governed-merges :: exit 0 pnpm check:pm-skill-id-lint :: exit 0 pnpm check:published-files :: exit 0 pnpm check:refd-timer-probe :: exit 0 pnpm check:role-word :: exit 0 pnpm check:skill-compatibility :: exit 0 pnpm check:skill-frame-sync :: exit 0 pnpm check:skill-identifier-liveness :: exit 0 pnpm check:skill-top-level-keys :: exit 0 pnpm check:sourcemap-no-sources-content :: exit 0 pnpm check:watch-hint-literal :: exit 0 EXTRA pnpm --filter @objectstack/spec run check:skill-refs :: exit 0 EXTRA pnpm check:skill-identifier-liveness :: exit 0 EXTRA pnpm check:skill-compatibility :: exit 0 EXTRA node scripts/check-skills-token-ratchet.mjs :: exit 0 ``` On `e3ce4aa7` (after merging `origin/main` `21c1f748`, which touches no skill, ratchet or capability file), re-run: ``` node scripts/check-skills-token-ratchet.mjs :: exit 0 pnpm check:skill-identifier-liveness :: exit 0 pnpm check:skill-compatibility :: exit 0 pnpm check:skill-top-level-keys :: exit 0 pnpm check:skill-frame-sync :: exit 0 pnpm --filter @objectstack/spec run check:skill-docs :: exit 0 pnpm --filter @objectstack/spec run check:skill-refs :: exit 0 node scripts/check-empty-changeset.mjs --base origin/main :: exit 0 node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0 node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0 pnpm check:doc-authoring :: exit 0 pnpm check:published-files :: exit 0 ``` Delta after the contract review (`6a12d8ad`: M1, S1, N2; files SKILL.md, the eval fixture and the changeset): ``` node scripts/check-skills-token-ratchet.mjs :: exit 0 pnpm --filter @objectstack/spec run check:skill-refs :: exit 0 pnpm check:skill-identifier-liveness :: exit 0 pnpm check:skill-compatibility :: exit 0 pnpm check:skill-top-level-keys :: exit 0 python3 -c "import json;json.load(open('skills/objectstack-platform/evals/config-plugins-ops.json'))" :: exit 0 node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD :: exit 0 node scripts/check-empty-changeset.mjs --base origin/main :: exit 0 node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0 ``` Delta at `1fedb7c3` (eval case 9 `must_contain` only): ``` python3 -c "import json;json.load(open('skills/objectstack-platform/evals/config-plugins-ops.json'))" :: exit 0 node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD :: exit 0 ``` `node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD`: exit 0 before each push. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01J8VVAkYSWQ13zHBd9mH4Bt <!-- signed: domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7 --> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 150f740 commit 658d84f

3 files changed

Lines changed: 46 additions & 22 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/skills': patch
3+
---
4+
5+
docs(skills): the platform skill's `requires:` table marks the always-on tokens
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
`objectstack-platform`'s `### requires:` no longer calls every listed service opt-in. The table marks each token of `PLATFORM_ALWAYS_ON_CAPABILITIES` (`queue`, `job`, `cache`, `settings`, `email`, `storage`, `sms`, `sharing`, `messaging`, `analytics`, `package-registry`) with °, and the lead says every boot mounts them, listed or not, while `--preset minimal` drops exactly those. The `auth` → `email` rule now says it holds under `--preset minimal` too, and the `triggers` + `job` pairing is scoped to `--preset minimal`. The `queues` / `assignmentRules` paragraph no longer says `sharing` must be in `requires:`. The skill's evals for silent scheduled flows and notifications, and for an ownership queue, no longer expect `job`, `messaging` or `sharing` in `requires:`, and a new eval case asks whether an always-on service must be listed. The platform behaviour already shipped; this release only teaches it.

‎skills/objectstack-platform/SKILL.md‎

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ objectstack-data): named sets of people a new record of an `ownership: 'user'`
5252
object sits in until a member claims it. `assignmentRules` (`defineAssignmentRule`,
5353
`@objectstack/spec/automation`; objectstack-automation) routes each inserted
5454
ownerless row into a queue — parked, `round_robin` or `least_loaded` — or to one
55-
user. Both need the ownership-queue service `@objectstack/plugin-sharing` registers
56-
(`sharing` in `requires`): a stack declaring either without it is refused at boot.
55+
user. Both need the ownership-queue service `@objectstack/plugin-sharing` registers:
56+
a stack declaring either without it is refused at boot.
5757

5858
Undeclared keys are handled per surface, in two postures:
5959

@@ -294,18 +294,19 @@ production fails loudly): [Ports & networking](./references/operations.md#ports-
294294

295295
### `requires:` — which service plugins boot
296296

297-
Step 4's list is the fixed core. Every other service plugin is opt-in, and
298-
`requires: [...]` on the stack root is what turns it on. The CLI expands each
297+
Step 4's list is the fixed core. Tokens marked ° are always-on: every boot
298+
mounts them, listed or not, and `--preset minimal` drops exactly those. Every
299+
other service plugin is opt-in: `requires: [...]` on the stack root turns it on. The CLI expands each
299300
token through the `CAPABILITY_PROVIDERS` registry in
300301
`@objectstack/core`:
301302

302303
| Token | Provider package |
303304
|:--|:--|
304305
| `automation` | `@objectstack/service-automation` — flows, and any declarative `connectors:` entry |
305-
| `analytics` `cache` `storage` `queue` `job` `messaging` `realtime` `settings` `sms` `push` | `@objectstack/service-` + the token ([the `push` block](./references/operations.md#mobile-push)) |
306+
| `analytics`° `cache`° `storage`° `queue`° `job`° `messaging`° `realtime` `settings`° `sms`° `push` | `@objectstack/service-` + the token ([the `push` block](./references/operations.md#mobile-push)) |
306307
| `mailbox` | `@objectstack/service-mailbox` — inbound mail |
307-
| `marketplace` `package-registry` | `@objectstack/service-package` |
308-
| `audit` `email` `sharing` `approvals` `webhooks` | `@objectstack/plugin-` + the token |
308+
| `marketplace` `package-registry`° | `@objectstack/service-package` |
309+
| `audit` `email`° `sharing`° `approvals` `webhooks` | `@objectstack/plugin-` + the token |
309310
| `pinyin-search` | `@objectstack/plugin-pinyin-search` |
310311
| `mcp` | `@objectstack/mcp` |
311312
| `triggers` | `@objectstack/trigger-record-change`, plus `trigger-schedule` and `trigger-api` |
@@ -315,8 +316,7 @@ through it:
315316

316317
- **Tier-gated** — `ai`, `ai-studio`, `i18n`, `ui`, `auth` have no provider
317318
entry; dedicated blocks in `serve.ts` `run()` open their tier instead
318-
(`ai`/`ai-studio` through the intent-driven AI block, the other three through
319-
their tier blocks).
319+
(`ai`/`ai-studio` through the intent-driven AI block).
320320
- **Enterprise / cloud** — `hierarchy-security` has no open-edition provider and
321321
ships in `@objectstack/security-enterprise`, loaded through `plugins[]`;
322322
`ai-seat` and `governance` are resolved only by cloud's objectos-runtime.
@@ -332,14 +332,14 @@ Five rules that change what you write:
332332
- **Declaring is a demand.** A capability YOU declared whose provider package is
333333
absent is a hard boot error; one the platform auto-injects for you stays
334334
best-effort (warn and continue).
335-
- **`auth` implies `email`.** Auth callbacks need the mail service, so the CLI
336-
appends `email` whenever `auth` is required.
335+
- **`auth` implies `email`**, even under `--preset minimal`: auth callbacks
336+
need the mail service.
337337
- **Keep `automation` whenever `plugins:` lists a connector** — connector
338-
executors register their provider factories with it, and without it they have
339-
nowhere to register and boot fails.
340-
- **Pair `triggers` with `job`.** `triggers` alone arms record-change triggers;
341-
schedule and time-relative triggers run on the job service, so autolaunched
342-
scheduled flows stay silent without `job`.
338+
executors register their provider factories with it, and without it boot
339+
fails.
340+
- **Under `--preset minimal`, pair `triggers` with `job`:** `triggers` alone
341+
arms record-change triggers; schedule and time-relative ones run on the job
342+
service, so scheduled flows stay silent.
343343

344344
### `onEnable` — where an app binds runtime code
345345

‎skills/objectstack-platform/evals/config-plugins-ops.json‎

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,13 @@
4242
{
4343
"id": 3,
4444
"prompt": "Our scheduled flows never launch, and `notify` reports success but nobody receives anything.",
45-
"expected_output": "`requires: ['automation', 'triggers', 'job', 'messaging']` on the stack root: `triggers` alone arms record-change triggers, schedule and time-relative ones run on the `job` service, and without `messaging` notify returns success with `skipped: true`. Declaring is a demand (missing provider = hard boot error); `defineStack` rejects an unknown token at authoring time.",
45+
"expected_output": "`requires: ['automation', 'triggers']` on the stack root: `triggers` arms the start bindings, and schedule and time-relative ones run on the `job` service. `job` and `messaging` are always-on: a default boot mounts both, listed or not. Only a `--preset minimal` boot drops them; there, list `job` too (else scheduled flows stay silent) and `messaging` (else notify returns success with `skipped: true`). Declaring is a demand (missing provider = hard boot error); `defineStack` rejects an unknown token at authoring time.",
4646
"files": [],
4747
"assertions": {
4848
"must_contain": [
4949
"requires",
50-
"job",
51-
"messaging",
52-
"triggers"
50+
"triggers",
51+
"--preset minimal"
5352
],
5453
"must_not_contain": [
5554
"plugins: [new ServiceJobPlugin",
@@ -148,14 +147,15 @@
148147
{
149148
"id": 9,
150149
"prompt": "Add a `crm_support_intake` queue staffed by the `crm_service_agent` position and route every new `crm_case` into it (`requires: ['automation', 'triggers']`).",
151-
"expected_output": "Two stack collections: `queues: [defineQueue({ name: 'crm_support_intake', label: 'Support Intake', members: [{ type: 'position', value: 'crm_service_agent' }] })]` and `assignmentRules: [defineAssignmentRule(...)]` with one entry, `assignTo: { type: 'queue', value: 'crm_support_intake' }`; plus `'sharing'` in `requires`: the keys need `@objectstack/plugin-sharing`'s ownership-queue service (`queue` is the job queue), else the boot is refused.",
150+
"expected_output": "Two stack collections: `queues: [defineQueue({ name: 'crm_support_intake', label: 'Support Intake', members: [{ type: 'position', value: 'crm_service_agent' }] })]` and `assignmentRules: [defineAssignmentRule(...)]` with one entry, `assignTo: { type: 'queue', value: 'crm_support_intake' }`; no `requires` change: the keys need `@objectstack/plugin-sharing`'s ownership-queue service (`queue` is the job queue), and `sharing` is always-on, so a default boot mounts it unlisted. Only under `--preset minimal` must `'sharing'` be listed, else the boot is refused.",
152151
"files": [],
153152
"assertions": {
154153
"must_contain": [
155154
"queues:",
156155
"assignmentRules:",
157156
"defineQueue",
158-
"'sharing'"
157+
"sharing",
158+
"--preset minimal"
159159
],
160160
"must_not_contain": [
161161
"assigned_to",
@@ -333,6 +333,20 @@
333333
"defineAgent("
334334
]
335335
}
336+
},
337+
{
338+
"id": 20,
339+
"prompt": "Uploads and settings must work in our app. Do I have to list `storage` and `settings` in `requires:`?",
340+
"expected_output": "No. `storage` and `settings` are always-on (`PLATFORM_ALWAYS_ON_CAPABILITIES`): every boot mounts them, listed or not, and listing one is harmless. Only `--preset minimal` drops the always-on tokens, and there they must be listed. A token outside that set, such as `automation` or `mailbox`, mounts only when `requires:` lists it.",
341+
"files": [],
342+
"assertions": {
343+
"must_contain": [
344+
"--preset minimal"
345+
],
346+
"must_not_contain": [
347+
"requires: ['storage', 'settings']"
348+
]
349+
}
336350
}
337351
]
338352
}

0 commit comments

Comments
 (0)