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
extend-existing-systems-with-ai: the datasource code sample no longer parses — config.connection, user and an inlined password are all rejected now that per-driver config is enforced #175
Found while correcting the same post's ADR-0015 roadmap paragraph (#149). Filed unassigned. Not fixed under that card: its rulings scope it to the closing roadmap paragraph ("correct the paragraph, do not re-argue the post"), and this is a different defect class — a code sample, in all 8 locale files, that also has to pick between Datasource and defineDatasource.
What the post shows
content/blog/extend-existing-systems-with-ai/index.mdx (and every locale — 8 files carry the identical block):
importtype{Datasource}from'@objectstack/spec';exportconstBusinessDb: Datasource={name: 'business_primary',driver: 'postgres',config: {connection: {// ← not a PostgresConfig keyhost: process.env.BIZ_DB_HOST,user: process.env.BIZ_DB_USER,// ← the key is `username`password: process.env.BIZ_DB_PASSWORD,// ← inlining refuseddatabase: process.env.BIZ_DB_NAME,},},pool: {min: 1,max: 10},active: true,};
What the spec now enforces
Measured on objectstackorigin/main @ dbf1152:
DatasourceSchema runs reportDriverConfigIssues(ctx, ds.driver, ds.config, ['config']) — packages/spec/src/data/datasource.zod.ts — so config is parsed against the driver's own schema (ENFORCED as of #4410, per the header comment on packages/spec/src/data/driver/postgres.zod.ts).
PostgresConfigSchema is a strictObject whose keys are url / host / port / database / username / ssl / schema / applicationName / statementTimeout / autoMigrate. connection is not among them, and user is not the spelling — the nesting is exactly what the enforcement was added to stop ("a connection key written one level too high left the datasource connecting on driver defaults rather than failing").
password is typed never: "Set through the connection form's secret field or external.credentialsRef — encrypted into sys_secret, never stored in config." The datasource-level guidance is blunt: "password must never be inlined on a datasource."
The type import is not what fails: Datasource is still exported (packages/spec/src/data/datasource.zod.ts:807), and on the datasource schema config is declared as an unconstrained record — z.record(z.string(), z.unknown()) — so TypeScript accepts this literal happily. It fails at parse/boot, in the driver-config refinement. That gap between "compiles" and "parses" is precisely what defineDatasource (exported from the package root, packages/spec/src/index.ts:171) closes, and it is what the monorepo's own guide uses — content/docs/data-modeling/external-datasources.mdx.
Why it matters
This is the post the site sends readers to for the connect route, and the block is the first code a reader copies. It is also the exact shape an AI agent will reproduce from the corpus. The post's own sentence above it — "Credentials come from the environment, never inlined in source" — is the right instruction; the sample under it does the opposite.
Shape of the fix
Rewrite the block in the English original as defineDatasource with a flat config (host / port / database / username) and no password, then carry it into all seven translated files (zh-Hant regenerated with pnpm gen:zh-hant, never hand-edited). Note the FAQ and governance list say "bind to a read-only connection or DB user", which stays correct and must stay distinct from the federation write gate — see the closing section as corrected in the PR for #149. It is a live post, so it sets updated and never date.
Re-check
grep -rn "connection: {" content/blog/ # 8 files, one per locale
git -C objectstack show origin/main:packages/spec/src/data/driver/postgres.zod.ts | head -20
git -C objectstack show origin/main:content/docs/data-modeling/external-datasources.mdx | sed -n '22,50p'
Triage: lands in content/blog/extend-existing-systems-with-ai/ (all eight locale files; zh-Hant via pnpm gen:zh-hant); rationale: a published post's first copyable code sample no longer parses under the enforced per-driver datasource config, and it inlines a password right under the post's own "never inlined" sentence. That violates a declared contract, so this is a Bug, user-reachable, and it is the shape an agent will copy from the corpus.
Path: none
Type: Bug
Re-check: git grep -n "connection: {" origin/main -- content/blog/extend-existing-systems-with-ai/ returned 8 hits at 6d95393 (2026-10-29T14:22Z).
Serial note: open PR #283 (slot Wed 11-11) also edits these eight files (a back-link and its updated line). Both land; the later one resolves the conflict.
Size/model suggestion: S, not mechanical (the dev picks the current spelling on today's npm latest and measures it), default tier, effort high.
Claim: PM loop round 1, 2026-10-29T14:26Z
Session: session_01L9qibvdwLLfobyXipfCGq7
Account: os-tesla (the seat's linked user as GET /user answers it; always the card's assignee)
Branch: claude/issue-175-datasource-sample
Worktree: www.objectos.ai-issue-175
Domain: n/a (single-lane repo)
Seat: repo:www#3 (a defect-card seat; publishing stays with seat 1 per the 2026-10-21 ruling on #267, and this seat touches no queued post)
File surface: content/blog/extend-existing-systems-with-ai/index*.mdx (8 files, zh-Hant regenerated) (stop on breach; explain in the report)
Container & model: S, mode:subagent, model: TIER_DEFAULT, effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: the post's own sample (this repo's content) produces the risk; the platform path that covers it is the enforced per-driver config schema plus the secret field / external.credentialsRef; every reader who copies the connect-route sample reaches it today
Thread-read: 6499270698
Premise: holds
Serial constraints cleared: open PR #283 also edits these eight files (back-link + updated); ordinary concurrency, the later lander resolves the conflict
os-dev-report
{
"issue": 175,
"status": "done",
"branch": "claude/issue-175-datasource-sample",
"pr": "#308",
"session": "session_01L9qibvdwLLfobyXipfCGq7",
"premise_still_valid": true,
"summary": "Rewrote the step-1 datasource sample of extend-existing-systems-with-ai as defineDatasource (from @objectstack/spec/data) with a flat config (host/database/username from env), no password, and the secret bound via external.credentialsRef (the one external key a managed datasource may carry, spec #8153). The code is byte-identical in all 8 locale files. The surrounding sentence now says connection details come from env and the password lives in the secret store, so it stays true, and one sentence after the code explains load-time validation. updated set to 2026-10-29T10:00:00+08:00 in every locale, date untouched, zh-Hant regenerated. All three PM mechanism assumptions were confirmed on the published @objectstack/spec 18.2.0 (npm latest), with the code read on objectstack origin/main 4a00b2b7. defineDatasource was chosen because its own doc comment in 18.2.0 calls it preferred over a bare Datasource literal, and the objectstack external-datasources guide uses it.",
"tests": "Probe against npm @objectstack/spec@18.2.0 (cli dist-tags latest=18.2.0). OLD sample: REFUSED [config] Unrecognized key connection; flattened: [config,password] not accepted inline + [config] user to username. NEW sample (code block extracted from index.mdx, run under node with env set): PARSES {host:crm-db.internal,database:crm,username:crm_readonly} credentialsRef sys_secret:sec_123 schemaMode managed, exit 0. Control: new + config.password REFUSED. Env unset: REFUSED [config,database] needs a connection target (loud, not silent defaults). tsc --strict 5.9.3 nodenext on the sample against 18.2.0 types: exit 0. sha256 of the ts block identical across all 8 files. No ablation: content-only diff, no tested behaviour changed.",
"gates": "Head 12a9f3a, base main 6d95393; each exit captured to a file before reading output. pnpm install --frozen-lockfile: 0. pnpm content:lint: 0 (content lint passed, 383 files; no warning on this post). pnpm check (os-verify-lock): VERDICT command-exit 0, 0 errors / 0 warnings / 0 hints. pnpm build (os-verify-lock): VERDICT command-exit 0, 948 pages, content lint --dist links/CJK/quotes passed. pnpm seo:smoke: 0 (938 HTML pages checked). Browser: Playwright Chromium on built dist, en + zh-Hans + ja at 1440x750 and 390x844, screenshots viewed: renders, Updated Oct 29 2026, dateModified and article:modified_time 2026-10-29T02:00:00.000Z, no page-level horizontal overflow (code block scrolls inside pre at 390, same as before). dispatch-gates.mjs not used: www is a sister repo, list hand-derived from package.json + workflows. PR check-runs at report time: Build and deploy in_progress.",
"line_budget": "8 files, +105 / -94 (content/blog/extend-existing-systems-with-ai/index*.mdx only)",
"files_changed": [
"content/blog/extend-existing-systems-with-ai/index.mdx",
"content/blog/extend-existing-systems-with-ai/index.de.mdx",
"content/blog/extend-existing-systems-with-ai/index.es.mdx",
"content/blog/extend-existing-systems-with-ai/index.fr.mdx",
"content/blog/extend-existing-systems-with-ai/index.ja.mdx",
"content/blog/extend-existing-systems-with-ai/index.ko.mdx",
"content/blog/extend-existing-systems-with-ai/index.zh-Hans.mdx",
"content/blog/extend-existing-systems-with-ai/index.zh-Hant.mdx"
],
"deviations": [
"Commit trailer is model-free (Co-Authored-By: Claude noreply@anthropic.com + Claude-Session): the dispatch spelled a model-named Co-Authored-By and also said no model identifier in commits; the role file's model-free trailer rule decided it.",
"Browser check ran the two viewports the dispatch named (1440x750, 390x844), not all six AGENTS.md lists.",
"No PR labels: none named by the dispatch; www has no skip-changeset gate.",
"On the issue comment the os-dev-report marker is line 2, after the seat signature line: post-stamped.mjs refuses a body whose first non-empty line is not the signature (measured, dry-run exit 2)."
],
"dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "2: POST /repos/objectstack-ai/objectstack/dispatches (relay pr_create to www.objectos.ai#308, read-back 6938/6938 bytes identical, draft, no assignees); this os-dev-report comment via post-stamped.mjs. git push (2: empty-branch probe + 12a9f3a) is not a REST write.",
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: defineDatasource on @objectstack/spec 18.2.0, measured: a top-level password is refused with guidance 'Interpolate it from the environment inside config', but every driver contract refuses config.password (typed never), so following it leads to a second refusal · evidence: packages/spec/src/data/datasource.zod.ts DatasourceSchema guidance.password · dedupe words: datasource password guidance, interpolate from environment, config.password never, stale prescription",
"class: a · reach: defineDatasource on 18.2.0, measured: external.password guidance gives the example credentialsRef 'secret:warehouse/password', which content/docs/data-modeling/external-datasources.mdx says will not dereference (only the opaque sys_secret:ID form resolves) · evidence: ExternalDatasourceSettingsSchema guidance.password · dedupe words: credentialsRef example, secret:warehouse/password, sys_secret handle, guidance example",
"class: a · reach: published doc content/docs/data-modeling/drivers.mdx read-only section says 'external.credentialsRef is a federation key — the parse rejects an external block on a managed datasource — so a managed connection carries its credentials in config'; measured on 18.2.0, managed + external.credentialsRef parses, and its sample config: { url: process.env.ANALYTICS_RO_URL } is refused when the URL carries user:password · evidence: datasource.zod.ts #8153 managed allowance; probe output · dedupe words: drivers.mdx read-only, managed credentialsRef, credentials in config, url userinfo refused",
"carrier: none · the three above are one family (stale datasource credential prescriptions in spec guidance + docs); file as one card in objectstack, not three"
]
}
Activity
objectstack-fleet commentedon Oct 29, 2026
repo:www#3 · os-tesla · session_01L9qibvdwLLfobyXipfCGq7
Triage: lands in
content/blog/extend-existing-systems-with-ai/(all eight locale files; zh-Hant viapnpm gen:zh-hant); rationale: a published post's first copyable code sample no longer parses under the enforced per-driver datasource config, and it inlines a password right under the post's own "never inlined" sentence. That violates a declared contract, so this is a Bug, user-reachable, and it is the shape an agent will copy from the corpus.Path: none
Type: Bug
Re-check:
git grep -n "connection: {" origin/main -- content/blog/extend-existing-systems-with-ai/returned 8 hits at6d95393(2026-10-29T14:22Z).Serial note: open PR #283 (slot Wed 11-11) also edits these eight files (a back-link and its
updatedline). Both land; the later one resolves the conflict.Size/model suggestion: S, not mechanical (the dev picks the current spelling on today's npm
latestand measures it), default tier, efforthigh.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
repo:www#3 · os-tesla · session_01L9qibvdwLLfobyXipfCGq7
Claim: PM loop round 1, 2026-10-29T14:26Z
Session:
session_01L9qibvdwLLfobyXipfCGq7Account:
os-tesla(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-175-datasource-sampleWorktree:
www.objectos.ai-issue-175Domain: n/a (single-lane repo)
Seat:
repo:www#3(a defect-card seat; publishing stays with seat 1 per the 2026-10-21 ruling on #267, and this seat touches no queued post)File surface:
content/blog/extend-existing-systems-with-ai/index*.mdx(8 files, zh-Hant regenerated) (stop on breach; explain in the report)Container & model:
S,mode:subagent,model: TIER_DEFAULT,effort: highClause-②: no
Metadata-protocol: none
Responsibility: the post's own sample (this repo's content) produces the risk; the platform path that covers it is the enforced per-driver
configschema plus the secret field /external.credentialsRef; every reader who copies the connect-route sample reaches it todayThread-read: 6499270698
Premise: holds
Serial constraints cleared: open PR #283 also edits these eight files (back-link +
updated); ordinary concurrency, the later lander resolves the conflictGenerated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
repo:www#3 · os-tesla · session_01L9qibvdwLLfobyXipfCGq7
os-dev-report
{
"issue": 175,
"status": "done",
"branch": "claude/issue-175-datasource-sample",
"pr": "#308",
"session": "session_01L9qibvdwLLfobyXipfCGq7",
"premise_still_valid": true,
"summary": "Rewrote the step-1 datasource sample of extend-existing-systems-with-ai as defineDatasource (from @objectstack/spec/data) with a flat config (host/database/username from env), no password, and the secret bound via external.credentialsRef (the one external key a managed datasource may carry, spec #8153). The code is byte-identical in all 8 locale files. The surrounding sentence now says connection details come from env and the password lives in the secret store, so it stays true, and one sentence after the code explains load-time validation. updated set to 2026-10-29T10:00:00+08:00 in every locale, date untouched, zh-Hant regenerated. All three PM mechanism assumptions were confirmed on the published @objectstack/spec 18.2.0 (npm latest), with the code read on objectstack origin/main 4a00b2b7. defineDatasource was chosen because its own doc comment in 18.2.0 calls it preferred over a bare Datasource literal, and the objectstack external-datasources guide uses it.",
"tests": "Probe against npm @objectstack/spec@18.2.0 (cli dist-tags latest=18.2.0). OLD sample: REFUSED [config] Unrecognized key
connection; flattened: [config,password] not accepted inline + [config]usertousername. NEW sample (code block extracted from index.mdx, run under node with env set): PARSES {host:crm-db.internal,database:crm,username:crm_readonly} credentialsRef sys_secret:sec_123 schemaMode managed, exit 0. Control: new + config.password REFUSED. Env unset: REFUSED [config,database] needs a connection target (loud, not silent defaults). tsc --strict 5.9.3 nodenext on the sample against 18.2.0 types: exit 0. sha256 of the ts block identical across all 8 files. No ablation: content-only diff, no tested behaviour changed.","gates": "Head 12a9f3a, base main 6d95393; each exit captured to a file before reading output. pnpm install --frozen-lockfile: 0. pnpm content:lint: 0 (content lint passed, 383 files; no warning on this post). pnpm check (os-verify-lock): VERDICT command-exit 0, 0 errors / 0 warnings / 0 hints. pnpm build (os-verify-lock): VERDICT command-exit 0, 948 pages, content lint --dist links/CJK/quotes passed. pnpm seo:smoke: 0 (938 HTML pages checked). Browser: Playwright Chromium on built dist, en + zh-Hans + ja at 1440x750 and 390x844, screenshots viewed: renders, Updated Oct 29 2026, dateModified and article:modified_time 2026-10-29T02:00:00.000Z, no page-level horizontal overflow (code block scrolls inside pre at 390, same as before). dispatch-gates.mjs not used: www is a sister repo, list hand-derived from package.json + workflows. PR check-runs at report time: Build and deploy in_progress.",
"line_budget": "8 files, +105 / -94 (content/blog/extend-existing-systems-with-ai/index*.mdx only)",
"files_changed": [
"content/blog/extend-existing-systems-with-ai/index.mdx",
"content/blog/extend-existing-systems-with-ai/index.de.mdx",
"content/blog/extend-existing-systems-with-ai/index.es.mdx",
"content/blog/extend-existing-systems-with-ai/index.fr.mdx",
"content/blog/extend-existing-systems-with-ai/index.ja.mdx",
"content/blog/extend-existing-systems-with-ai/index.ko.mdx",
"content/blog/extend-existing-systems-with-ai/index.zh-Hans.mdx",
"content/blog/extend-existing-systems-with-ai/index.zh-Hant.mdx"
],
"deviations": [
"Commit trailer is model-free (Co-Authored-By: Claude noreply@anthropic.com + Claude-Session): the dispatch spelled a model-named Co-Authored-By and also said no model identifier in commits; the role file's model-free trailer rule decided it.",
"Browser check ran the two viewports the dispatch named (1440x750, 390x844), not all six AGENTS.md lists.",
"No PR labels: none named by the dispatch; www has no skip-changeset gate.",
"On the issue comment the os-dev-report marker is line 2, after the seat signature line: post-stamped.mjs refuses a body whose first non-empty line is not the signature (measured, dry-run exit 2)."
],
"dogfood_battery": "n/a: no
!in the PR title and no (narrowing) arm","mcp_calls": "0",
"api_writes": "2: POST /repos/objectstack-ai/objectstack/dispatches (relay pr_create to www.objectos.ai#308, read-back 6938/6938 bytes identical, draft, no assignees); this os-dev-report comment via post-stamped.mjs. git push (2: empty-branch probe + 12a9f3a) is not a REST write.",
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: defineDatasource on @objectstack/spec 18.2.0, measured: a top-level
passwordis refused with guidance 'Interpolate it from the environment insideconfig', but every driver contract refuses config.password (typed never), so following it leads to a second refusal · evidence: packages/spec/src/data/datasource.zod.ts DatasourceSchema guidance.password · dedupe words: datasource password guidance, interpolate from environment, config.password never, stale prescription","class: a · reach: defineDatasource on 18.2.0, measured: external.password guidance gives the example credentialsRef 'secret:warehouse/password', which content/docs/data-modeling/external-datasources.mdx says will not dereference (only the opaque sys_secret:ID form resolves) · evidence: ExternalDatasourceSettingsSchema guidance.password · dedupe words: credentialsRef example, secret:warehouse/password, sys_secret handle, guidance example",
"class: a · reach: published doc content/docs/data-modeling/drivers.mdx read-only section says 'external.credentialsRef is a federation key — the parse rejects an external block on a managed datasource — so a managed connection carries its credentials in config'; measured on 18.2.0, managed + external.credentialsRef parses, and its sample
config: { url: process.env.ANALYTICS_RO_URL }is refused when the URL carries user:password · evidence: datasource.zod.ts #8153 managed allowance; probe output · dedupe words: drivers.mdx read-only, managed credentialsRef, credentials in config, url userinfo refused","carrier: none · the three above are one family (stale datasource credential prescriptions in spec guidance + docs); file as one card in objectstack, not three"
]
}