Skip to content

Commit 813fd9b

Browse files
docs(adr): ADR-0015 §8 binds its example credential with a sys_secret: handle, the only form the shipped binder resolves (#27906)
<!-- claude-projects-attribution: {"github_login":"os-elon-musk"} --> _Requested by **Elon** · [project thread](https://claude.ai/code/project/chan_01WedDzV26nniwxv7jC88B9D?thread=cmsg_01WedDzV26nniwxv7jC88B9D64Su8iVExEyoqzjz95AbBX)_ Fixes #27688 Clause-②: no Metadata-protocol: none ## 维护者速读 - 改了什么:ADR-0015 第 8 节端到端示例的凭据引用,从 `secret:warehouse/readonly` 改为 `sys_secret:9f2c…` 句柄形态;示例下加一条带日期的修订注,原句照录,不是静默改写;文件头 `Amended by` 行指向这条注。 - 为什么改:平台只认密钥库铸出的 `sys_secret:` 句柄(Setup → 数据源连接表单的密钥栏写入)。照抄旧示例写出的引用能通过校验,但启动时解析不到,数据源一直连不上。PR #27656 已改好 schema 提示和 drivers 文档,这个 ADR 是最后一处还在教旧写法的地方。 - 风险与回滚:只改一个 ADR 文件(+22/−2),不发布任何包,不动代码、门禁和 §10 正文;回滚即 revert 这一个提交。 - 先看:`docs/adr/0015-external-datasource-federation.md` 第 8 节第一个代码块和紧随其后的修订注,再看文件头第 7 行。 - 两分钟验证:`grep -n "credentialsRef: '" docs/adr/0015-external-datasource-federation.md`,预期两行:示例里的 `sys_secret:9f2c…`,和修订注里照录的旧句。 - 需要你做的:暂无。contract review owed(契约复审未完成,席位复审后再求批);本 PR 改 ADR,落地为 Tier H,由维护者批准。 ## What changes One file, `docs/adr/0015-external-datasource-federation.md` (+22 / −2). - **§8 example.** `credentialsRef: 'secret:warehouse/readonly'` becomes `credentialsRef: 'sys_secret:9f2c…'`, with a three-line comment that says where the handle comes from. The comment mirrors the one PR #27656 put in `examples/app-showcase/src/system/datasources/showcase-external.datasource.ts`. - **A dated amendment note right under that code block**, in the house form of ADR-0099's 2026-10-23 note and ADR-0097's notes: the text is corrected in place and the note records what it replaced. The note quotes the original line, says why it fails (it parses, but nothing shipped resolves it), names what the binder resolves and where (`packages/services/service-datasource/src/datasource-secret-binder.ts#parseCredentialsRef`), and points at the schema refusals and `content/docs/data-modeling/drivers.mdx`, which teach the same form after PR #27656. - **The header's `Amended by` line** gains one entry pointing at the note. Not edited: §10's body, §4.1, and the example's other keys. D7 (`external.connector`) is not taught here. ## Why — measured at `04740b7c` - The whole ADR has one `secret:` example, `:657`. No other prose spells the form. - The binder accepts a ref only with the `sys_secret:` prefix: `parseCredentialsRef` returns the id after it, else `undefined`. `resolve()` then returns `undefined` with no read, and `DatasourceConnectionService` leaves the datasource unconnected with `failed-credentials` ("could not be resolved or decrypted"). `os serve` wires `createDatasourceSecretBinder` as that resolver (`packages/cli/src/commands/serve.ts`). - PR #27656 teaches `sys_secret:9f2c…` in `drivers.mdx` and the showcase example, and `sys_secret:9f2c` in the two `password` refusals in `datasource.zod.ts`. - `DatasourceSchema.safeParse`, run with `tsx` against `packages/spec/src`: | Variant of the §8 datasource | Result | |:--|:--| | As written on `main` | refused, one issue: `external.label` (removed in 17.0.0, ADR-0049) | | Only the `secret:` ref; every other key in its current spelling | **parses** — the silent defect this card is about | | `external.label` moved to top level, `config.connectionString` kept | refused: `connectionString` → `url` | | `label` top level, `config.url` or discrete fields, `sys_secret:` ref | parses | So the `secret:` form is the one stale key in the example that fails silently. The other two are refused by name, each with its fix. ## Deviations from the dispatch order The first two were reported to the seat before the push and accepted (seat note, 2026-10-30T03:05Z): - **One sentence beyond the credential fix.** The note says the rest of the example is kept as written, as the surface this record was taken on, and that today's parse refuses `external.label` and `config.connectionString` by name. Neither key is edited. - **One clause on §10.** §10 says `credentialsRef` "points at `service-secrets`"; no package of that name exists. The note says the binder is the component that resolves the reference and that what it yields is the password, injected at connect. §10's body is not edited. - The full test suite was not run before opening. The diff touches no package; every gate family `dispatch-gates` derives was run instead (Verification). ## Acceptance notes - §10 still names `service-secrets` in its body; the §8 note now says what it is. A body edit is for the maintainer if wanted. - §8 still shows `external.label` and `config.connectionString`. Both are refused loudly at the parse, each naming its fix. ## Verification <details><summary>dispatch-gates</summary> `node scripts/pm/dispatch-gates.mjs --commands` (no paths, from the committed diff against merge base `04740b7c`) derives 21 families. All 21 were run with exit codes captured before any pipe. `pnpm --filter @objectstack/lint run check:doc-formula-expressions` first exited 3 (`@objectstack/formula` and `@objectstack/lint` not built in a fresh worktree); after `pnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lint` it exited 0. `--ran`: `21 derived famil(ies) accounted for — 21 run, 0 NOT-MEASURED`. Re-derived after the commit: identical list. The ADR gates among them: `check:adr-index`, `check:adr-anchors`, `check:adr-symbol-anchors`, `check-adr-links.mjs` (+ `--self-test`), all exit 0. Changed lines 24 (+22 / −2), under the 3000 threshold. `--tier` answers MANDATORY `CONTRACT_REVIEW_TIER` for `docs/adr/**`. `git merge-tree` against `origin/main` `e320e366` is clean, and no commit since the base touched this file. `scripts/check-nul-bytes.mjs` exit 0. </details> Contract review owed: governed `docs/adr/**`, at `CONTRACT_REVIEW_TIER`. Landing is Tier H (triage 6505597349: "Tier H: the maintainer merges"). ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. (not touched) - [x] 2. Every name I added uses the casing for its kind. (no names added) - [x] 3. No formatter ran; `pnpm lint` passes (prose only; the full run is CI's). - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. A change that publishes carries a changeset. `docs/adr/**` publishes nothing, so `skip-changeset`. - [x] 6. `packages/spec` touched: n/a. - [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 (the 维护者速读 is the sanctioned Chinese channel). - [x] The *Before Submitting* list in CONTRIBUTING.md is done. --- _Generated by [Claude Code](https://claude.ai/code/session_016WV4cwBHtvCZyayQ8RFyUN)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 9122271 commit 813fd9b

1 file changed

Lines changed: 22 additions & 2 deletions

File tree

‎docs/adr/0015-external-datasource-federation.md‎

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
**Deciders**: ObjectStack Protocol Architects
55
**Builds on**: [ADR-0005](./0005-metadata-customization-overlay.md) (one Zod source of truth per metadata type)
66
**Consumers**: `@objectstack/spec`, `@objectstack/runtime`, `@objectstack/objectql`, `@objectstack/plugins/driver-sql`, `@objectstack/services/service-ai`, `@objectstack/cli`, `../objectui`
7-
**Amended by**: [ADR-0143](./0143-outbound-connector-auth-is-open-tier.md) (2026-10-27), attribution only — see the note below. D7 (2026-10-29, ruling 6486136301 on #27298) — an API-backed datasource may borrow a declared connector instance's credential through `external.connector`; see the D7 note below.
7+
**Amended by**: [ADR-0143](./0143-outbound-connector-auth-is-open-tier.md) (2026-10-27), attribution only — see the note below. D7 (2026-10-29, ruling 6486136301 on #27298) — an API-backed datasource may borrow a declared connector instance's credential through `external.connector`; see the D7 note below. #27688 (2026-10-30), example only — §8's `credentialsRef` is a `sys_secret:` handle, the only form the shipped secret binder resolves; see the note under §8.
88

99
> **Amendment note D7 (2026-10-29, ruling 6486136301, letter A) — a second credential channel.**
1010
> §10 says credentials reach a datasource only through `credentialsRef`. That stays true for a
@@ -654,11 +654,31 @@ export default defineDatasource({
654654
allowWrites: false,
655655
validation: { onMismatch: 'fail', checkOnBoot: true },
656656
queryTimeoutMs: 15_000,
657-
credentialsRef: 'secret:warehouse/readonly',
657+
// The opaque handle the secret store minted (Setup → Datasources binds
658+
// the password and writes it here); the shipped binder resolves only
659+
// `sys_secret:` handles.
660+
credentialsRef: 'sys_secret:9f2c…',
658661
},
659662
});
660663
```
661664

665+
> **Amendment note (2026-10-30, #27688) — the example's credential handle; no decision changes.**
666+
> The `credentialsRef` above is the amended one; the original read
667+
> `credentialsRef: 'secret:warehouse/readonly'`. That form parses, but nothing shipped resolves it.
668+
> The datasource secret binder dereferences only a `sys_secret:<id>` handle, `<id>` being the
669+
> `sys_secret` row the secret store minted when the credential was bound
670+
> (`packages/services/service-datasource/src/datasource-secret-binder.ts#parseCredentialsRef`).
671+
> A hand-written path resolves to nothing, and the connection service leaves the datasource
672+
> unconnected (`failed-credentials`). The Setup → Datasources connection form's secret field
673+
> encrypts the password into `sys_secret` and writes the handle here; the datasource schema's
674+
> refusals and `content/docs/data-modeling/drivers.mdx` teach the same form (PR #27656). §10's
675+
> `service-secrets` names no shipped package: this binder is the component that resolves the
676+
> reference, and what it yields is the password, injected beside a credential-free `config` at
677+
> connect. The rest of the example is kept as written, as the surface this record was taken on.
678+
> Today's parse refuses two of its keys by name, each with its fix: `external.label` (removed in
679+
> `@objectstack/spec` 17.0.0 under ADR-0049; the label is the datasource's top-level one) and
680+
> `config.connectionString` (spelled `url`).
681+
662682
```bash
663683
os datasource list-tables warehouse --schema mart
664684
# mart.fact_orders (14 cols, ~12.4M rows)

0 commit comments

Comments
 (0)