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
docs(drivers): the plugin-driver paragraph says config is "served to administrators as written", but the read path still withholds the canonical credential keys and URL credentials for every driver #21950
Path: an API a customer can call — external data; secrets can be neither written in nor read out | integration-system.datasource-credential-refusal-matrix | P2
Filed by the triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U, from domain:devx seat 1's "noted, not filed" on #21932 (6008901276). A foreseen follow-up is a card. ⛔ Not a claim, ⛔ not a dispatch.
Triage: lands in content/docs/data-modeling/drivers.mdx (about :155–:160) ⇒ domain:devx; rationale: it is a docs disconnect, and those enter the queue. The code is more protective than the sentence, so only the sentence changes.
The code: the read path still redacts through the shared list, redactableConfigKeys (@objectstack/spec/datadatasource-credential-redaction.ts, re-exported by service-datasource's datasource-config-redaction.ts). Its header names an "unknown-driver posture": the canonical credential keys and URL userinfo are withheld for every driver, contracted or not.
Done when
The paragraph says what the code does. The platform does not guess beyond the canonical keys and URL credentials it withholds for every driver. Anything else in a plugin driver's config is served as written and is the plugin author's to keep free of secrets.
The text is read against the code by the dev, not paraphrased from this card.
Claim: PM loop round 1
Session: session_01VF48aw8RPG6wzDnMgp6rtw
Account: os-justin (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-21950-plugin-driver-config-redaction-docs (cut from origin/main at dispatch)
Worktree: objectstack-issue-21950
Domain: domain:devx
Seat: domain:devx#2
File surface: content/docs/data-modeling/drivers.mdx, the plugin-contributed-driver paragraph (about :155–:160 at origin/main3c7785d4). No code change, per the card and #21921's ruling. Stop on a breach and explain it in the report.
Container & model: S (one paragraph, but the wording is judged against the code, so it gets M treatment), mode:subagent, model: opus (dispatch-gates --tier --repo objectstack-ai/objectstack: no path-derived mandate; default tier)
Clause-②: no
Thread-read: none
Serial constraints cleared: board read at 2026-10-06T05:20Z. No open PR touches content/docs/data-modeling/drivers.mdx, each open PR's file list read by filename. Its last move is PR #21927 (9dce6353), which landed the sentence this card corrects. This seat's in-flight PRs #21951 and #21952 touch only the lockfile, pnpm-workspace.yaml and osv-scanner.toml, which is disjoint.
Premise, read at origin/main3c7785d4:
drivers.mdx:158 reads "config is stored and served to administrators as written".
packages/spec/src/data/datasource-credential-redaction.ts:67 reads "canonical spellings are therefore redacted by NAME for unknown drivers too".
:91 reads "strips it for EVERY driver".
redactableConfigKeys (:370) is applied on read at :520.
So the page still says less than the code does. Priority rule 3: no P0/P1 is open and undispatched in this lane, and this is a docs disconnect, not a tooling card.
{
"issue": 21950,
"status": "done",
"branch": "claude/issue-21950-plugin-driver-config-redaction-docs",
"pr": "https://github.com/objectstack-ai/objectstack/pull/21953",
"session": "session_01VF48aw8RPG6wzDnMgp6rtw — subagent run; the parent's harness-stamped id (relay route read it from CLAUDE_CODE_REMOTE_SESSION_ID)",
"premise_still_valid": true,
"summary": "Docs only: rewrote the plugin-contributed-driver paragraph in content/docs/data-modeling/drivers.mdx (lines 155-168 after the edit). The page said config is stored AND served as written. The code shows the stored half is true and the served half is false. No code change, so #21921's ruling stands. No link was added and no new page was made. BEFORE (drivers.mdx:157-160 at 3c7785d4), verbatim: \"The platform also does not guess which of its keys hold credentials: `config` is stored and served to administrators as written. Keeping secrets out of it is the plugin author's responsibility; put the credential in the bound secret (`external.credentialsRef`) instead.\" AFTER, verbatim: \"... so its `config` is left unvalidated rather than judged against a shape the platform does not have, and is stored as written. The platform also does not guess which of its keys hold credentials. On read it withholds only what it withholds for every driver: a key named exactly `password` or `authToken`, or one of their former aliases (`FORMER_CREDENTIAL_ALIASES`), and, in a URL-shaped string value, the password in its userinfo and its credential query parameters (`CREDENTIAL_URL_QUERY_PARAM_NAMES`, such as `?password=`). Both apply at every depth of nested objects, but not inside arrays. Everything else in `config` is served to administrators as written (`redactDatasourceConfig` in `datasource-credential-redaction.ts`), and a withheld value still sits in the stored row. Keeping secrets out of `config` is the plugin author's responsibility; put the credential in the bound secret (`external.credentialsRef`) instead.\" CODE LINES the new text rests on (base 3c7785d4). (1) Stored as written: config-registry.zod.ts:435 `return id ? DRIVER_CONFIG_SCHEMAS[id] : undefined;` and :522 `if (!schema) return { known: false };`. datasource.zod.ts:693 `reportDriverConfigIssues(ctx, ds.driver, ds.config, ['config']);` returns at :485 `if (!result.known) return;`. The admin write doors use the same judges: datasource-admin-service.ts:1031 `validateDriverConfig(driver, config)` and :1061 `DatasourceSchema.safeParse(record)`. (2) Names withheld: datasource-credential-redaction.ts:372 `const canonical = derived.length > 0 ? derived : [...CANONICAL_CREDENTIAL_KEYS];` and :374 `return [...new Set([...canonical, ...FORMER_CREDENTIAL_ALIASES, ...stillWritable])];`. common.zod.ts:437 `export const CANONICAL_CREDENTIAL_KEYS = ['password', 'authToken'] as const;`, and the aliases start at :448. (3) Exact-case match at every object depth, not inside arrays: :520 `const hidden = new Set(redactableConfigKeys(driver));`, :527 `if (hidden.has(key)) {`, :546 `if (value && typeof value === 'object' && !Array.isArray(value)) {`, :550 `out[key] = value;`. (4) URL credentials: :537 `const redacted = redactUrlCredentials(value);` runs on every string. :451 composes :405 `value.replace(URL_USERINFO_RE, ...)`, which keeps the username, with :436 `credentialQueryParamOf(pair, CREDENTIAL_URL_QUERY_PARAM_NAMES)`. common.zod.ts:311-312 is the union of :299-300, matched case-insensitively at :621. This is premise 3, which the PM had not located; the module header states it at :88-94. (5) Nothing positional for an unknown driver: :227 `return id ? (PASSTHROUGH_SECRET_PATHS[id] ?? []) : [];`. (6) Read exits: datasource-admin-service.ts:554 and metadata-type-redaction.ts:93 both call redactDatasourceConfig. All four Zone-2 readings held at the exact lines: drivers.mdx:158, redaction :67, :91, :370 and :520. A scratch probe (not committed) ran the src code at 3c7785d4 for driver com.vendor.snowflake. DatasourceSchema.safeParse succeeded and stored the config byte-equal. The read withheld password, authToken, pwd, token, a nested token, a nested URL's userinfo password, and the ?password= and ?AuthToken= query pairs. The read served Password (case variant), privateKey, apiKey, clientSecret, a nested secret and an array-member password as written.",
"tests": "Docs-only diff; no package touched, so the diff needs no dependency-closure build and owes no package test. The gate list was derived on the real diff at 809a8641 with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (no path argument, merge-base 3c7785d4). It gave the same 40 commands the dispatch named. All 40 exit 0 at 809a8641, and each exit code was written to disk before any pipe. Reconciliation via `--ran`: '✓ dispatch-gates --ran: 40 derived famil(ies) accounted for — 40 run, 0 NOT-MEASURED (a DERIVED zero — all 40 recorded an exit code and none of them is 3)'. check:skill-examples first exited 3 with 'PREREQUISITE NOT MET — packages/client-react/dist holds no .d.ts'. That run is not a measurement. After building @objectstack/client-react... and @objectstack/client... under os-verify-lock (VERDICT command-exit 0) it exited 0: '✅ 262 prose examples type-check across 3 surface(s)'. @objectstack/lint... was built first under the lock (VERDICT command-exit 0) because the lint and spec docs gates read built output. check:docs: '✅ 226 generated files in sync with packages/spec'. check:doc-authoring: '✓ doc authoring guard: 17798 customer-facing string(s) across 1280 spec sources clean'. Not run locally, left to CI: the artifact-roster, wide-population, path-scheduled (Test Core, Build Docs) and type-check lanes that dispatch-gates prints outside its 40. Ablation: not applicable (no code path changed). The measurement here is the probe described in summary.",
"gates": [
"node scripts/check-ci-filter-parity.mjs :: 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-frontmatter.mjs :: exit 0",
"node scripts/check-doc-frontmatter.mjs --self-test :: 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-docs-section-name.mjs :: exit 0",
"node scripts/check-docs-section-name.mjs --self-test :: exit 0",
"node scripts/check-section-landing-index.mjs :: exit 0",
"node scripts/check-section-landing-index.mjs --self-test :: exit 0",
"pnpm check:corpus-claim-drift :: exit 0",
"pnpm check:cross-package-test-inputs :: exit 0",
"pnpm check:doc-anchors :: exit 0",
"pnpm check:doc-authoring :: exit 0",
"pnpm check:docs-audit-scope :: exit 0",
"pnpm check:docs-redirects :: exit 0",
"pnpm check:docs-single-h1 :: exit 0",
"pnpm check:docs-spec-enumerations :: exit 0",
"pnpm check:docs-transcript-drift :: exit 0",
"pnpm check:driver-memory-census :: exit 0",
"pnpm check:gitlink-declared :: exit 0",
"pnpm check:nul-bytes :: exit 0",
"pnpm check:published-readme-links :: exit 0",
"pnpm check:react-page-adapter-contract :: exit 0",
"pnpm check:refd-timer-probe :: exit 0",
"pnpm check:role-word :: exit 0",
"pnpm check:skill-identifier-liveness :: exit 0",
"pnpm check:vendor-version-stamps :: exit 0",
"pnpm check:watch-hint-literal :: exit 0",
"pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0",
"pnpm --filter @objectstack/lint run check:doc-security-posture :: exit 0",
"pnpm --filter @objectstack/spec run check:docs :: exit 0",
"pnpm --filter @objectstack/spec run check:empty-state :: exit 0",
"pnpm --filter @objectstack/spec run check:liveness :: exit 0",
"pnpm --filter @objectstack/spec run check:skill-examples :: exit 0",
"pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0",
"pnpm --filter @objectstack/spec run check:variant-docs :: exit 0",
"pnpm --filter @objectstack/spec run check:yaml-examples :: exit 0"
],
"gates_head": "809a8641",
"line_budget": "content/docs/data-modeling/drivers.mdx +12/-4 (16 changed lines, 1 file); human-merge threshold 5000: under. No skills/** or ledger surface touched, so no line ratchet applies.",
"files_changed": [
"content/docs/data-modeling/drivers.mdx"
],
"changeset": "skip-changeset. No published package's files[] ships content/docs. A probe for the new sentence's text over every package dist/, packages/spec/llms.txt, packages/spec/prompts and skills/ found 0 hits. Positive control: redactDatasourceConfig in packages/spec/dist, 10 files. Clause-②: no is copied from the claim into the PR body.",
"deviations": [
"The commit trailer uses the AGENTS.md model-free pair (Claude-Session + Co-authored-by: Claude). The harness attribution reminder asked for a model-bearing Co-Authored-By; AGENTS.md outranks it and the pre-push hook refuses that pair.",
"The PR body footer uses the AGENTS.md session-URL form, not the harness reminder's emoji line.",
"Built @objectstack/lint, @objectstack/client and @objectstack/client-react (with their closures) although the diff touches no package. The gates read built output; check:skill-examples refused without it (exit 3, re-run to exit 0).",
"The report carries both api_writes (definition field) and rest_writes (dispatch field), with the same content.",
"The worktree was removed before this report was posted, so the comment went out through the shared checkout's scripts/pm/post-stamped.mjs. That was a read-only use of the shared tree, with no edit."
],
"mcp_calls": "0 — no MCP GitHub tool called (reads went through `gh api` GETs and the relay's own read-backs).",
"api_writes": "3 relay strokes (POST /repos/objectstack-ai/objectstack/dispatches, each executed by fleet-write.yml as objectstack-fleet[bot]): (1) pr_create → POST /repos/objectstack-ai/objectstack/pulls (draft, #21953; read-back 7736/7736 bytes identical); (2) label-write → POST /repos/objectstack-ai/objectstack/issues/21953/labels [skip-changeset] + POST /repos/objectstack-ai/objectstack/issues/21953/assignees [os-justin] (read-back MATCHES); (3) post-stamped → POST /repos/objectstack-ai/objectstack/issues/21950/comments (this os-dev-report). Plus 2 git pushes (empty branch probe, then 809a8641), which are not REST writes.",
"rest_writes": "same as api_writes: 3 relay strokes (pulls create; issues/21953 labels + assignees; issues/21950 comments) + 2 git pushes.",
"open_questions": [],
"out_of_scope_findings": [
"class: a+b · reach: exception: security (a credential-shaped stored value can be served in cleartext on a read exit) · evidence: datasource-credential-redaction.ts:373 `const stillWritable = typeof driver === 'string' ? (STILL_WRITABLE_CREDENTIAL_KEYS[driver] ?? []) : [];` indexes the table by the raw driver spelling. Its sibling passthroughSecretPaths resolves the id first (:226-227 via resolveDriverId, which is own-property guarded at config-registry.zod.ts:296). A function-level probe at 3c7785d4 shows two symptoms. First, the documented `turso` | `libsql` row of drivers.mdx:185, and the claim at :191 'every one of them is stripped before a datasource record is ever served back', hold for one spelling only. Second, a driver id naming an Object.prototype member throws 'stillWritable is not iterable' on read; this fails closed, and DatasourceSchema accepts such an id. Seam: spec:STILL_WRITABLE_CREDENTIAL_KEYS / redactableConfigKeys → runtime:DatasourceAdminService.getDatasource (datasource-admin-service.ts:554) + metadata-type-redaction.ts:93. restoreRedactedConfig and datasource-credential-migration.ts:148 read the same set. Both symptoms come from one line and one fix (resolve the id before the lookup), so this is one finding, not two. Not fixed here because the card is docs-only and forbids code. · dedupe words: STILL_WRITABLE_CREDENTIAL_KEYS; redactableConfigKeys alias; libsql encryptionKey redaction; resolveDriverId still-writable"
]
}
Seat domain:devx#2 · session_01VF48aw8RPG6wzDnMgp6rtw · reviewed against GitHub and the fetched branch at 2026-10-06T05:47Z, not against the report.
PR shape.
Draft against main, body opening Fixes #21950 and Clause-②: no at line start, assignee os-justin.
Labels: documentation · size/s · skip-changeset.
One file, content/docs/data-modeling/drivers.mdx, +12/−4.
check-governed-merges.mjs --pr 21953: 0 of 1 path governed.
Scope and changeset. Docs only, no code change, which keeps #21921's ruling. No content/docs/releases/**. skip-changeset holds: content/docs ships in no package's files[].
Sentence-by-sentence against the code at origin/main3c7785d4. Each sentence of the new paragraph was checked by this seat.
"…and is stored as written." True. For an unknown driver, datasource.zod.ts:485 returns before judging (if (!result.known) return;). The module header (datasource-credential-redaction.ts:66-71) calls the write gate's pass-through for unknown drivers deliberate.
"On read it withholds only what it withholds for every driver: a key named exactly password or authToken, or one of their former aliases (FORMER_CREDENTIAL_ALIASES)…" True. redactableConfigKeys (:370-375) falls back to CANONICAL_CREDENTIAL_KEYS when the driver has no derived set, and adds the aliases. :527 drops by exact Set.has(key).
"…in a URL-shaped string value, the password in its userinfo and its credential query parameters…" True. :537 runs redactUrlCredentials on every string. That composes redactUrlPassword (:405, which keeps the username) with the query-parameter strip (:436).
"Both apply at every depth of nested objects, but not inside arrays." True. :546 recurses into non-array objects only, and :550 passes anything else through as is.
"Everything else in config is served to administrators as written…, and a withheld value still sits in the stored row." True. The redaction is on read, and the write gate does not refuse an unknown driver's keys.
Gates. The dev ran 40 of 40, all exit 0 at 809a8641 (--ran reconciled). CI at this verdict: 21 success, 10 skipped, and 3 in progress (Lint & Repo Gates, Test Core 1/6, Type Check · workspace).
Out-of-scope finding: filed #21955 (class a+b, under the "may leak data" exception). The mechanism is withheld from public surfaces and given to the maintainer privately.
Landing: once the in-progress checks are green: pr_ready + automerge_enable, verify on main, close #21950.
Landed: PR #21953 → 01e0f71ad8, verified on origin/main by content at 2026-10-06T06:13Z.
content/docs/data-modeling/drivers.mdx on main is blob-identical to the reviewed landing head 809a8641 (2cc6444fe4). The merge commit is an ancestor of origin/main.
The card was closed completed by the PR's Fixes #21950. pm:dispatched is removed in this act; domain:devx, area:api and the type labels stay.
Activity
objectstack-fleet commentedon Oct 6, 2026
Claim: PM loop round 1
Session:
session_01VF48aw8RPG6wzDnMgp6rtwAccount:
os-justin(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-21950-plugin-driver-config-redaction-docs(cut fromorigin/mainat dispatch)Worktree:
objectstack-issue-21950Domain:
domain:devxSeat:
domain:devx#2File surface:
content/docs/data-modeling/drivers.mdx, the plugin-contributed-driver paragraph (about:155–:160atorigin/main3c7785d4). No code change, per the card and #21921's ruling. Stop on a breach and explain it in the report.Container & model:
S(one paragraph, but the wording is judged against the code, so it gets M treatment),mode:subagent,model: opus(dispatch-gates --tier --repo objectstack-ai/objectstack: no path-derived mandate; default tier)Clause-②: no
Thread-read: none
Serial constraints cleared: board read at 2026-10-06T05:20Z. No open PR touches
content/docs/data-modeling/drivers.mdx, each open PR's file list read byfilename. Its last move is PR #21927 (9dce6353), which landed the sentence this card corrects. This seat's in-flight PRs #21951 and #21952 touch only the lockfile,pnpm-workspace.yamlandosv-scanner.toml, which is disjoint.Premise, read at
origin/main3c7785d4:drivers.mdx:158reads "configis stored and served to administrators as written".packages/spec/src/data/datasource-credential-redaction.ts:67reads "canonical spellings are therefore redacted by NAME for unknown drivers too".:91reads "strips it for EVERY driver".redactableConfigKeys(:370) is applied on read at:520.So the page still says less than the code does. Priority rule 3: no P0/P1 is open and undispatched in this lane, and this is a docs disconnect, not a tooling card.
Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
os-dev-report
{ "issue": 21950, "status": "done", "branch": "claude/issue-21950-plugin-driver-config-redaction-docs", "pr": "https://github.com/objectstack-ai/objectstack/pull/21953", "session": "session_01VF48aw8RPG6wzDnMgp6rtw — subagent run; the parent's harness-stamped id (relay route read it from CLAUDE_CODE_REMOTE_SESSION_ID)", "premise_still_valid": true, "summary": "Docs only: rewrote the plugin-contributed-driver paragraph in content/docs/data-modeling/drivers.mdx (lines 155-168 after the edit). The page said config is stored AND served as written. The code shows the stored half is true and the served half is false. No code change, so #21921's ruling stands. No link was added and no new page was made. BEFORE (drivers.mdx:157-160 at 3c7785d4), verbatim: \"The platform also does not guess which of its keys hold credentials: `config` is stored and served to administrators as written. Keeping secrets out of it is the plugin author's responsibility; put the credential in the bound secret (`external.credentialsRef`) instead.\" AFTER, verbatim: \"... so its `config` is left unvalidated rather than judged against a shape the platform does not have, and is stored as written. The platform also does not guess which of its keys hold credentials. On read it withholds only what it withholds for every driver: a key named exactly `password` or `authToken`, or one of their former aliases (`FORMER_CREDENTIAL_ALIASES`), and, in a URL-shaped string value, the password in its userinfo and its credential query parameters (`CREDENTIAL_URL_QUERY_PARAM_NAMES`, such as `?password=`). Both apply at every depth of nested objects, but not inside arrays. Everything else in `config` is served to administrators as written (`redactDatasourceConfig` in `datasource-credential-redaction.ts`), and a withheld value still sits in the stored row. Keeping secrets out of `config` is the plugin author's responsibility; put the credential in the bound secret (`external.credentialsRef`) instead.\" CODE LINES the new text rests on (base 3c7785d4). (1) Stored as written: config-registry.zod.ts:435 `return id ? DRIVER_CONFIG_SCHEMAS[id] : undefined;` and :522 `if (!schema) return { known: false };`. datasource.zod.ts:693 `reportDriverConfigIssues(ctx, ds.driver, ds.config, ['config']);` returns at :485 `if (!result.known) return;`. The admin write doors use the same judges: datasource-admin-service.ts:1031 `validateDriverConfig(driver, config)` and :1061 `DatasourceSchema.safeParse(record)`. (2) Names withheld: datasource-credential-redaction.ts:372 `const canonical = derived.length > 0 ? derived : [...CANONICAL_CREDENTIAL_KEYS];` and :374 `return [...new Set([...canonical, ...FORMER_CREDENTIAL_ALIASES, ...stillWritable])];`. common.zod.ts:437 `export const CANONICAL_CREDENTIAL_KEYS = ['password', 'authToken'] as const;`, and the aliases start at :448. (3) Exact-case match at every object depth, not inside arrays: :520 `const hidden = new Set(redactableConfigKeys(driver));`, :527 `if (hidden.has(key)) {`, :546 `if (value && typeof value === 'object' && !Array.isArray(value)) {`, :550 `out[key] = value;`. (4) URL credentials: :537 `const redacted = redactUrlCredentials(value);` runs on every string. :451 composes :405 `value.replace(URL_USERINFO_RE, ...)`, which keeps the username, with :436 `credentialQueryParamOf(pair, CREDENTIAL_URL_QUERY_PARAM_NAMES)`. common.zod.ts:311-312 is the union of :299-300, matched case-insensitively at :621. This is premise 3, which the PM had not located; the module header states it at :88-94. (5) Nothing positional for an unknown driver: :227 `return id ? (PASSTHROUGH_SECRET_PATHS[id] ?? []) : [];`. (6) Read exits: datasource-admin-service.ts:554 and metadata-type-redaction.ts:93 both call redactDatasourceConfig. All four Zone-2 readings held at the exact lines: drivers.mdx:158, redaction :67, :91, :370 and :520. A scratch probe (not committed) ran the src code at 3c7785d4 for driver com.vendor.snowflake. DatasourceSchema.safeParse succeeded and stored the config byte-equal. The read withheld password, authToken, pwd, token, a nested token, a nested URL's userinfo password, and the ?password= and ?AuthToken= query pairs. The read served Password (case variant), privateKey, apiKey, clientSecret, a nested secret and an array-member password as written.", "tests": "Docs-only diff; no package touched, so the diff needs no dependency-closure build and owes no package test. The gate list was derived on the real diff at 809a8641 with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (no path argument, merge-base 3c7785d4). It gave the same 40 commands the dispatch named. All 40 exit 0 at 809a8641, and each exit code was written to disk before any pipe. Reconciliation via `--ran`: '✓ dispatch-gates --ran: 40 derived famil(ies) accounted for — 40 run, 0 NOT-MEASURED (a DERIVED zero — all 40 recorded an exit code and none of them is 3)'. check:skill-examples first exited 3 with 'PREREQUISITE NOT MET — packages/client-react/dist holds no .d.ts'. That run is not a measurement. After building @objectstack/client-react... and @objectstack/client... under os-verify-lock (VERDICT command-exit 0) it exited 0: '✅ 262 prose examples type-check across 3 surface(s)'. @objectstack/lint... was built first under the lock (VERDICT command-exit 0) because the lint and spec docs gates read built output. check:docs: '✅ 226 generated files in sync with packages/spec'. check:doc-authoring: '✓ doc authoring guard: 17798 customer-facing string(s) across 1280 spec sources clean'. Not run locally, left to CI: the artifact-roster, wide-population, path-scheduled (Test Core, Build Docs) and type-check lanes that dispatch-gates prints outside its 40. Ablation: not applicable (no code path changed). The measurement here is the probe described in summary.", "gates": [ "node scripts/check-ci-filter-parity.mjs :: 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-frontmatter.mjs :: exit 0", "node scripts/check-doc-frontmatter.mjs --self-test :: 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-docs-section-name.mjs :: exit 0", "node scripts/check-docs-section-name.mjs --self-test :: exit 0", "node scripts/check-section-landing-index.mjs :: exit 0", "node scripts/check-section-landing-index.mjs --self-test :: exit 0", "pnpm check:corpus-claim-drift :: exit 0", "pnpm check:cross-package-test-inputs :: exit 0", "pnpm check:doc-anchors :: exit 0", "pnpm check:doc-authoring :: exit 0", "pnpm check:docs-audit-scope :: exit 0", "pnpm check:docs-redirects :: exit 0", "pnpm check:docs-single-h1 :: exit 0", "pnpm check:docs-spec-enumerations :: exit 0", "pnpm check:docs-transcript-drift :: exit 0", "pnpm check:driver-memory-census :: exit 0", "pnpm check:gitlink-declared :: exit 0", "pnpm check:nul-bytes :: exit 0", "pnpm check:published-readme-links :: exit 0", "pnpm check:react-page-adapter-contract :: exit 0", "pnpm check:refd-timer-probe :: exit 0", "pnpm check:role-word :: exit 0", "pnpm check:skill-identifier-liveness :: exit 0", "pnpm check:vendor-version-stamps :: exit 0", "pnpm check:watch-hint-literal :: exit 0", "pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0", "pnpm --filter @objectstack/lint run check:doc-security-posture :: exit 0", "pnpm --filter @objectstack/spec run check:docs :: exit 0", "pnpm --filter @objectstack/spec run check:empty-state :: exit 0", "pnpm --filter @objectstack/spec run check:liveness :: exit 0", "pnpm --filter @objectstack/spec run check:skill-examples :: exit 0", "pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0", "pnpm --filter @objectstack/spec run check:variant-docs :: exit 0", "pnpm --filter @objectstack/spec run check:yaml-examples :: exit 0" ], "gates_head": "809a8641", "line_budget": "content/docs/data-modeling/drivers.mdx +12/-4 (16 changed lines, 1 file); human-merge threshold 5000: under. No skills/** or ledger surface touched, so no line ratchet applies.", "files_changed": [ "content/docs/data-modeling/drivers.mdx" ], "changeset": "skip-changeset. No published package's files[] ships content/docs. A probe for the new sentence's text over every package dist/, packages/spec/llms.txt, packages/spec/prompts and skills/ found 0 hits. Positive control: redactDatasourceConfig in packages/spec/dist, 10 files. Clause-②: no is copied from the claim into the PR body.", "deviations": [ "The commit trailer uses the AGENTS.md model-free pair (Claude-Session + Co-authored-by: Claude). The harness attribution reminder asked for a model-bearing Co-Authored-By; AGENTS.md outranks it and the pre-push hook refuses that pair.", "The PR body footer uses the AGENTS.md session-URL form, not the harness reminder's emoji line.", "Built @objectstack/lint, @objectstack/client and @objectstack/client-react (with their closures) although the diff touches no package. The gates read built output; check:skill-examples refused without it (exit 3, re-run to exit 0).", "The report carries both api_writes (definition field) and rest_writes (dispatch field), with the same content.", "The worktree was removed before this report was posted, so the comment went out through the shared checkout's scripts/pm/post-stamped.mjs. That was a read-only use of the shared tree, with no edit." ], "mcp_calls": "0 — no MCP GitHub tool called (reads went through `gh api` GETs and the relay's own read-backs).", "api_writes": "3 relay strokes (POST /repos/objectstack-ai/objectstack/dispatches, each executed by fleet-write.yml as objectstack-fleet[bot]): (1) pr_create → POST /repos/objectstack-ai/objectstack/pulls (draft, #21953; read-back 7736/7736 bytes identical); (2) label-write → POST /repos/objectstack-ai/objectstack/issues/21953/labels [skip-changeset] + POST /repos/objectstack-ai/objectstack/issues/21953/assignees [os-justin] (read-back MATCHES); (3) post-stamped → POST /repos/objectstack-ai/objectstack/issues/21950/comments (this os-dev-report). Plus 2 git pushes (empty branch probe, then 809a8641), which are not REST writes.", "rest_writes": "same as api_writes: 3 relay strokes (pulls create; issues/21953 labels + assignees; issues/21950 comments) + 2 git pushes.", "open_questions": [], "out_of_scope_findings": [ "class: a+b · reach: exception: security (a credential-shaped stored value can be served in cleartext on a read exit) · evidence: datasource-credential-redaction.ts:373 `const stillWritable = typeof driver === 'string' ? (STILL_WRITABLE_CREDENTIAL_KEYS[driver] ?? []) : [];` indexes the table by the raw driver spelling. Its sibling passthroughSecretPaths resolves the id first (:226-227 via resolveDriverId, which is own-property guarded at config-registry.zod.ts:296). A function-level probe at 3c7785d4 shows two symptoms. First, the documented `turso` | `libsql` row of drivers.mdx:185, and the claim at :191 'every one of them is stripped before a datasource record is ever served back', hold for one spelling only. Second, a driver id naming an Object.prototype member throws 'stillWritable is not iterable' on read; this fails closed, and DatasourceSchema accepts such an id. Seam: spec:STILL_WRITABLE_CREDENTIAL_KEYS / redactableConfigKeys → runtime:DatasourceAdminService.getDatasource (datasource-admin-service.ts:554) + metadata-type-redaction.ts:93. restoreRedactedConfig and datasource-credential-migration.ts:148 read the same set. Both symptoms come from one line and one fix (resolve the id before the lookup), so this is one finding, not two. Not fixed here because the card is docs-only and forbids code. · dedupe words: STILL_WRITABLE_CREDENTIAL_KEYS; redactableConfigKeys alias; libsql encryptionKey redaction; resolveDriverId still-writable" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
Review: ACCEPT — PR #21953 at
809a8641Seat
domain:devx#2·session_01VF48aw8RPG6wzDnMgp6rtw· reviewed against GitHub and the fetched branch at 2026-10-06T05:47Z, not against the report.PR shape.
main, body openingFixes #21950andClause-②: noat line start, assigneeos-justin.documentation·size/s·skip-changeset.content/docs/data-modeling/drivers.mdx, +12/−4.check-governed-merges.mjs --pr 21953: 0 of 1 path governed.Scope and changeset. Docs only, no code change, which keeps #21921's ruling. No
content/docs/releases/**.skip-changesetholds:content/docsships in no package'sfiles[].Sentence-by-sentence against the code at
origin/main3c7785d4. Each sentence of the new paragraph was checked by this seat.datasource.zod.ts:485returns before judging (if (!result.known) return;). The module header (datasource-credential-redaction.ts:66-71) calls the write gate's pass-through for unknown drivers deliberate.passwordorauthToken, or one of their former aliases (FORMER_CREDENTIAL_ALIASES)…" True.redactableConfigKeys(:370-375) falls back toCANONICAL_CREDENTIAL_KEYSwhen the driver has no derived set, and adds the aliases.:527drops by exactSet.has(key).:537runsredactUrlCredentialson every string. That composesredactUrlPassword(:405, which keeps the username) with the query-parameter strip (:436).:546recurses into non-array objects only, and:550passes anything else through as is.configis served to administrators as written…, and a withheld value still sits in the stored row." True. The redaction is on read, and the write gate does not refuse an unknown driver's keys.configis the plugin author's responsibility; put the credential in the bound secret (external.credentialsRef) instead." Unchanged from docs(drivers): a plugin driver's config is its author's to keep free of credentials #21927, per the ruling.Gates. The dev ran 40 of 40, all exit 0 at
809a8641(--ranreconciled). CI at this verdict: 21 success, 10 skipped, and 3 in progress (Lint & Repo Gates, Test Core 1/6, Type Check · workspace).Out-of-scope finding: filed #21955 (class a+b, under the "may leak data" exception). The mechanism is withheld from public surfaces and given to the maintainer privately.
Landing: once the in-progress checks are green:
pr_ready+automerge_enable, verify onmain, close #21950.Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
Landed: PR #21953 →
01e0f71ad8, verified onorigin/mainby content at 2026-10-06T06:13Z.content/docs/data-modeling/drivers.mdxonmainis blob-identical to the reviewed landing head809a8641(2cc6444fe4). The merge commit is an ancestor oforigin/main.completedby the PR'sFixes #21950.pm:dispatchedis removed in this act;domain:devx,area:apiand the type labels stay.Generated by Claude Code
docs(drivers): say what the read path withholds from a plugin driver'…