You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit d0ebb8f
Browse filesBrowse the repository at this point in the historyBrowse files
docs(skills): the platform skill's operations reference says the official image refuses to start without its database and secrets (#30875)
<!-- claude-projects-attribution: {"github_login":"os-tesla"} -->
_Requested by **Tesla** · [project
thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6JaoUSHs2PSwPeZKjinKYi84Wn)_Fixes#30857
Clause-②: no
Metadata-protocol: none
Refs #30120 · PR #30720 (the `Skills-docs:` follow-up it named as owed).
## 维护者速读
- **改了什么**:平台技能的运维参考页。部署目标表的 Docker / Kubernetes 行写明官方镜像必须在运行时给出
`OS_DATABASE_URL`、`OS_AUTH_SECRET`、`OS_SECRET_KEY` 三项,否则拒绝启动,显式指向挂载卷的
`file:` 地址可以过;「Common ops pitfalls」新增一行:镜像启动即退出并点名这三项时怎么办,升级时沿用旧容器
`/home/node/.objectstack`
下已生成的值(`auth-secret`、`dev-crypto-key`、`data/objectstack.db`),不要换新。另加评测用例
16 和 changeset。
- **为什么改**:PR #30720 之后镜像的行为变了,技能还按旧文写,AI 照抄会写出镜像拒启的 `docker
run`;更糟的是升级时换上新密钥,所有已保存的凭据都读不出来、所有人被登出。
- **风险与回滚**:只改技能文字与一个评测用例,不动 SKILL.md;token 额度靠删同文件里在别处有家的重复文字支付(3116 →
3108,上限 3119 → 3108 下调,不抬);回滚即撤这个 PR。
- **先看**:`skills/objectstack-platform/references/operations.md` 的 Docker
/ Kubernetes 行与「Common ops pitfalls」最后一行;其次被删的 Testing pattern 代码块(改为指向
plugin-development.md 的两节)。
- **两分钟验证**:`node scripts/check-skills-token-ratchet.mjs | grep
operations.md` 应打印 `3108 / 3108`;对照 `docker/README.md`「What the image
presets」与 `packages/cli/src/commands/start.ts` 的
`formatDurabilityRefusal`,三个变量名与三个文件名应一致。
- **需要你做的**:批准这个 Tier H PR(`skills/**` 需受管审批人 os-zhuang 或 hotlong
批准),之后席位落地。
## What changes
`skills/objectstack-platform/references/operations.md` (212 → 181 lines,
3116 → 3108 tokens, ceiling 3119 → 3108):
- **Deployment targets, Docker / Kubernetes row:** the official image
(`ghcr.io/objectstack-ai/objectstack`) refuses to start unless
`OS_DATABASE_URL`, `OS_AUTH_SECRET` and `OS_SECRET_KEY` are set at
runtime, never baked in; an explicit
`OS_DATABASE_URL=file:/path/on/a/mounted/volume/app.db` passes, so
SQLite on a volume still works.
- **Common ops pitfalls, new last row:** symptom "the official image
exits at start naming the three"; cause: the image presets
`OS_DEPLOYMENT_DURABILITY_CHECK_ENABLED=true`, under which `os start`
exits 1 before it writes a database file or a secret when any of the
three is unset; fix: set them on the run command, and on an upgrade
**keep the generated values** from the old container's
`/home/node/.objectstack` (`docker exec CONTAINER cat FILE`, or its
volume): `OS_AUTH_SECRET` is the contents of `auth-secret`,
`OS_SECRET_KEY` the contents of `dev-crypto-key`, the data is
`data/objectstack.db` (`OS_DATABASE_URL=file:…` on the kept volume, or
migrate it); fresh values leave every saved credential unreadable and
sign everyone out.
Every sentence is read off `main`: `docker/README.md` ("What the image
presets"), `content/docs/deployment/self-hosting.mdx` ("When the three
are not set"), and the check itself in
`packages/cli/src/commands/start.ts` (`readDurabilityCheckSignal`,
`missingDurableVariables` — an explicit `file:` URL counts as chosen,
`isDefaultedDatabase`; `formatDurabilityRefusal` prints the three file
paths and exits 1 before `readOrCreateAuthSecret` runs).
**Paid inside the file (the headroom was 3 tokens).** Each deletion, and
where the content lives:
1. The intro sentence ("Every project gets the same `os` command surface
— `npm install` does not need to be re-run when commands are added"): no
rule and no author action; the command tables under it are the content.
2. "In a scaffolded project these are `npm run validate` / `npm run
build`" in Verify your work: the Verify section of every domain skill
carries the scaffolded spelling (objectstack-ai, -api, -automation,
-data, -formula, -query, -ui `SKILL.md`).
3. The cloud-connection blockquote's plugin roster
(`CloudConnectionPlugin`/`createCloudConnectionPlugin`,
`MarketplaceProxyPlugin`, `RuntimeConfigPlugin`, "ship the Installed
Apps page and marketplace Setup nav"): no author action; kept are the
package, the ADRs and the one fact `os package install` needs —
`MarketplaceInstallLocalPlugin` serves the install-local endpoint (also
on the docs page `deployment/cli`, under `os package install`);
`createCloudConnectionPlugin` stays in `plugin-development.md` §
Well-Known Plugin Names.
4. The Testing pattern vitest block: the LiteKernel + vitest shape
(`describe`/`it`, silent logger, `bootstrap()`, `getService`,
`shutdown()`) is `plugin-development.md` § Testing Plugins, and the
`ObjectQLPlugin` / `DriverPlugin` / `InMemoryDriver` imports are § Using
Plugins. What was unique stays as prose: which three plugins a stack
boot assembles, that `AppPlugin` is in `@objectstack/runtime` and
`stack` is the config's default export, with links to both sections.
5. The "Seed in tests" bullet: the `os data` row already says the
`data:` collection loads at boot, and objectstack-data
`references/seeds.md` carries the `env: ['dev', 'test']` scoping.
No line was re-wrapped to win room. The section headings are unchanged,
so `SKILL.md` L402's section list still holds and no `SKILL.md` edit is
needed.
**`skills/objectstack-platform/evals/config-plugins-ops.json`:** case 16
(the platform evals cover deployment: case 6), spliced before the
closing bracket so the file's formatting is untouched. Prompt: the
official image on a kept volume, nothing set, exits after pulling the
new tag; expected: set the three on the run command, carry
`auth-secret`, `dev-crypto-key` and `data/objectstack.db` over from
`/home/node/.objectstack`, never fresh secrets. `must_contain` the three
file names and the home path; `must_not_contain` `OS_DEV_CRYPTO_KEY` (it
does not count for `OS_SECRET_KEY`, PR #30720 acceptance notes).
**`scripts/check-skills-token-ratchet.mjs`:** the operations.md row 3119
→ 3108, pinned at the landed count (down only).
**`.changeset/30857-image-secrets-refuse-start.md`:**
`'@objectstack/skills': patch`, both declaration lines.
## Why
Since PR #30720 (ruling A3 on #30120) an agent that follows the skill as
written produces a `docker run` the image refuses, and on an existing
deployment may set fresh secrets, which makes every encrypted saved
credential unreadable. The triage audit (6679092587) asks for the text
to say **keep** the existing secrets on an upgrade; the pitfall row says
it in bold.
## Tests
- `node scripts/check-skills-token-ratchet.mjs`: exit 0;
`skills/objectstack-platform/references/operations.md 3108 / 3108 (+0)`;
`--self-test` 97 cases pass.
- `skills/objectstack-platform/evals/config-plugins-ops.json` parses; 16
cases, ids unique.
- The derived gate battery and its `--ran` reconciliation: see
Verification.
## Acceptance notes
- The `os start` row ("It does **not** validate env or apply
migrations") is unchanged: outside the image's preset that is still what
`os start` does; the Docker row and the pitfall carry the preset's
refusal. Left as is, scope.
- Verify your work still says a bare field ref in a predicate "evaluates
to `null` and silently hides an action/validation", while the formula
skill's Verify section says the engine throws at runtime and the rule
fails loudly. One of the two is stale; not this card's surface, noted
for the skills seat.
- `/home/node/.objectstack` is the image's home for the `node` user; the
refusal prints the actual paths (and marks the ones present), so a
custom `OS_HOME` is covered by reading the refusal.
- The `OS_DEPLOYMENT_DURABILITY_CHECK_ENABLED=false` escape is not
taught; neither `docker/README.md` nor `self-hosting.mdx` teaches it.
- Whole-package readings (`skills/**`): the sum of every `SKILL.md` is
4523 lines before and after (no `SKILL.md` touched); the ratchet's
shipped-bundle total is 227058 → 227374 tokens (+316: the eval fixture
+324, operations.md −8).
- Relay writes only: `git push`, `pr_create`, the `os-dev-report`
comment. The harness's assignee / reviewer step is skipped (no MCP
writes); the seat sets them at hand-over.
## Verification
Head `bc38b673` (9db88a2 plus the merge of `main` cf478ea). Exit codes
captured before any pipe, one `COMMAND :: exit CODE` line per command,
then reconciled:
- `bash scripts/pm/os-verify-lock.sh -c "pnpm build
--filter='./packages/**' --concurrency=2"`: `VERDICT command-exit 0`,
held the lock 402 s.
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` (no paths; the change set from the merge
base): 62 commands, all 62 `:: exit 0` — among them
`check:skills-token-ratchet` and its `--self-test` (97 cases),
`check:skill-identifier-liveness`, `check:skill-frame-sync`,
`check:skill-compatibility`, `check:skill-refs`,
`check:pm-skill-id-lint`, `check:doc-authoring`,
`check:empty-changeset`, `check:changeset-no-major`,
`check:adr-0087-registration`, `check:doc-formula-expressions` (after
the packages build), `check:comment-mask-corpus`,
`check:pm-dispatch-gates`, `check:pm-governed-merges`.
- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--ran LIST`: "62 derived famil(ies) accounted for — 62 run, 0
NOT-MEASURED"; changed lines 78 (+36 / −42) against the 3000 threshold.
- `pnpm lint`, `test:repo` and the artifact-roster families are CI's
run: the PR's check-runs.
- `main` moved by four commits after the push (to 18870c9); none
touches the four files and a `git merge-tree` of the two is clean.
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(`packages/spec` untouched.)
- [x] 2. Every name I added uses the casing for its kind.
- [x] 3. No formatter ran; `pnpm lint` is CI's run.
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. A change that publishes carries a changeset, and both
declaration lines are filled in here and in the changeset.
- [x] 6. `packages/spec` touched: its generated artifacts are
regenerated and committed. (Not touched.)
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English.
- [x] The *Before Submitting* list in CONTRIBUTING.md is done.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01L9qibyPEPCmwvSgLKLnUeg)_
Co-authored-by: Claude <noreply@anthropic.com>
The platform skill's operations reference now says what the official image does on `main`: it refuses to start unless `OS_DATABASE_URL`, `OS_AUTH_SECRET` and `OS_SECRET_KEY` are set at runtime (an explicit `file:` URL on a mounted volume passes), and a Common ops pitfalls row tells an upgrade to keep the values an old container generated (`auth-secret`, `dev-crypto-key`, `data/objectstack.db` under `/home/node/.objectstack`) rather than set fresh ones, which would leave every saved credential unreadable.
Copy file name to clipboardExpand all lines: skills/objectstack-platform/evals/config-plugins-ops.json
+17Lines changed: 17 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -270,6 +270,23 @@
270
270
"PUT /api/v1/meta/action/crm_close_deal"
271
271
]
272
272
}
273
+
},
274
+
{
275
+
"id": 16,
276
+
"prompt": "We run the official image on one host with a volume at /home/node/.objectstack and never set any OS_* variable. After pulling the new tag the container exits at once: OS_DATABASE_URL, OS_AUTH_SECRET and OS_SECRET_KEY are not set. Get us back up without losing the logins and the stored credentials.",
277
+
"expected_output": "The image presets `OS_DEPLOYMENT_DURABILITY_CHECK_ENABLED=true`, so `os start` exits before it writes a database file or a secret while any of the three is unset; set all three on the run command, never in the image. Keep the values the old container generated, read from its `/home/node/.objectstack` (`docker exec` or the volume): `OS_AUTH_SECRET` is the contents of `auth-secret`, `OS_SECRET_KEY` the contents of `dev-crypto-key`, and `OS_DATABASE_URL=file:/home/node/.objectstack/data/objectstack.db` on the kept volume (or migrate that file to a database). Fresh secrets would leave every saved credential unreadable and sign everyone out.",
Copy file name to clipboardExpand all lines: skills/objectstack-platform/references/operations.md
+10-41Lines changed: 10 additions & 41 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,8 +1,5 @@
1
1
# Part 3 — Operations: CLI, Testing, Deployment
2
2
3
-
Every project gets the same `os` command surface — `npm install` does not need
4
-
to be re-run when commands are added.
5
-
6
3
## Daily-loop commands
7
4
8
5
| Command | What it does |
@@ -49,8 +46,7 @@ Both run the same gates:
49
46
3.**Widget-binding integrity (ADR-0021)** — every dashboard widget's
50
47
`dataset` / `dimensions` / `values` resolves to a declared dataset/field.
51
48
52
-
Both exit non-zero with a located, corrective message. In a scaffolded project
53
-
these are `npm run validate` / `npm run build`.
49
+
Both exit non-zero with a located, corrective message.
54
50
55
51
**Rule of thumb: never report a metadata change as done until `os validate`
56
52
passes.** (`os lint` is a *separate* style/convention pass and does not
@@ -104,12 +100,9 @@ Port resolution is the same for `os dev` and `os start` (both spawn `os serve`):
104
100
|`os package publish [dist/objectstack.json] [--env … --install --visibility org]`| Upload the compiled artifact as a versioned package to the cloud catalog (ADR-0008 P3). Listing file, README, review and every screen the customer's administrator meets: [Marketplace handbook](https://objectstack.ai/docs/deployment/marketplace-handbook)|
105
101
|`os package install <manifest-id │ ./dist/objectstack.json> [--version │ -u/--url http://localhost:3000]`| Install a package into a **running** runtime. Catalog mode (by manifest id) or air-gapped local-artifact mode. Auths as a **target runtime** user (`-t/--token` or `--email/--password`; env `OS_RUNTIME_TOKEN` or `OS_RUNTIME_EMAIL`/`OS_RUNTIME_PASSWORD`), not the cloud login |
| Docker / Kubernetes | any | any | Use `os start` as the entrypoint; pin `PORT` and `EXPOSE` it (see [Ports & networking](#ports--networking)) |
157
+
| Docker / Kubernetes | any | any | Use `os start` as the entrypoint; pin `PORT` and `EXPOSE` it (see [Ports & networking](#ports--networking)). The official image (`ghcr.io/objectstack-ai/objectstack`) refuses to start unless `OS_DATABASE_URL`, `OS_AUTH_SECRET` and `OS_SECRET_KEY` are set at runtime, never baked in; an explicit `OS_DATABASE_URL=file:/path/on/a/mounted/volume/app.db` passes, so SQLite on a volume still works|
| Hot reload misses new objects | Barrel `src/objects/index.ts` not re-exporting — check the file |
211
179
| Login works but **Setup / Studio missing**| The logged-in user isn't a platform admin. Setup/Studio are gated by `setup.access` / `studio.access` on `admin_full_access`, auto-granted only to the first registered **human** (`bootstrapPlatformAdmin`). The `usr_system` seed identity is skipped, so it can't steal the grant. Either sign up first (`--seed-admin`/`--fresh` does this) or check `sys_user_permission_set` for a cross-tenant (`organization_id = NULL`) `admin_full_access` link on your user. Don't edit nav code first. |
212
180
| A permission set is declared but grants nobody anything | Declaring a set is not assigning it — see "Assigning a permission set to a user" in **objectstack-data**. |
181
+
| The official image exits at start naming `OS_DATABASE_URL` / `OS_AUTH_SECRET` / `OS_SECRET_KEY`| The image presets `OS_DEPLOYMENT_DURABILITY_CHECK_ENABLED=true`: with any of the three unset, `os start` exits 1 before it writes a database file or a secret. Set the named ones on the run command. Upgrading a container that ran on the image's defaults? **Keep its generated values**, read from the old container's `/home/node/.objectstack` (`docker exec <container> cat <file>`, or its volume): `OS_AUTH_SECRET` is the contents of `auth-secret`, `OS_SECRET_KEY` the contents of `dev-crypto-key`, and the data is `data/objectstack.db` (`OS_DATABASE_URL=file:…` on the kept volume, or migrate it). Fresh values leave every saved credential unreadable and sign everyone out. |
0 commit comments