Repository navigation
Description
Found while writing the www.objectos.ai how-to on migrating a legacy internal system (objectstack-ai/www.objectos.ai#91, PR objectstack-ai/www.objectos.ai#147). Filed unassigned. Not fixed there: that card's file surface is one new blog directory in a different repository.
content/docs/configure/data-sources.mdx carries a section titled "Roadmap: in-product External Datasource Federation" which tells the reader the capability does not exist yet:
A richer, turn-key federation experience is in active design under ADR-0015 (status: Proposed). Planned, not yet shipped:
Measured on objectstack origin/main @ 7cbe705b, every one of the four "planned, not yet shipped" bullets is shipped:
| Doc bullet | State on origin/main |
|---|---|
"A schemaMode (managed / external / validate-only)" |
SchemaModeSchema in packages/spec/src/data/datasource.zod.ts |
"An external binding sub-record on objects" |
ObjectExternalBindingSchema in packages/spec/src/data/object.zod.ts, wired as external on ObjectSchema |
"An os datasource introspect / validate CLI" |
packages/cli/src/commands/datasource/{introspect,validate,list-tables}.ts |
| "Boot-time and write-time safety gates … plus a Studio wizard" | ADR-0015 §5.2 external-validation-plugin; the double opt-in write gate; ADR-0062 R7 records the runtime "Sync objects" wizard as shipped |
ADR-0015's own status line now reads "Accepted — backend/REST/CLI implemented; Studio UI + extra dialect drivers pending", and ADR-0062 (Accepted 2026-06-22) supersedes its runtime half and lists R1, R4, R5a-d, R6, R7, R9, R10 as shipped. The monorepo ships a full user-facing guide for the feature at content/docs/data-modeling/external-datasources.mdx, whose headline is the opposite of this page's: "declare an external datasource and it is visible, auto-connected, validated at boot, and queryable — with no application code."
A second, separate claim on the same page
Line 88 states:
There is no
defineDatasource()helper. A datasource is just aDatasourceobject you place in thedatasourcesarray
That helper is exported: packages/spec/src/data/datasource.zod.ts:816 declares export function defineDatasource(config: z.input<typeof DatasourceSchema>): DatasourceParsed, re-exported through packages/spec/src/data/index.ts. The monorepo's own federation guide uses defineDatasource in its first code block. The plain-object form the page describes still works, so this is a wrong denial rather than a broken example — but an author who reads it will hand-write the longer form and will not find the helper the sibling docs use.
Why it is worth a card
These two claims fail in the direction that costs the most: they tell a reader a capability is absent. Someone evaluating whether ObjectOS can sit on their existing production database reads this page, concludes the safety gates they need are a roadmap item, and leaves. The feature they wanted has been shipped and documented for months, one repository over.
The staleness is also self-concealing — nothing on this page is broken, so no gate fires and no reader reports it. It is only visible to someone who happens to read both this page and the monorepo docs for the same surface, which is how it surfaced here.
Shape of the fix
Not prescribed, because there is a scope question worth deciding deliberately: whether this page should describe the shipped federation surface itself, or link to the monorepo's data-modeling/external-datasources guide and keep only the connect-and-model overview it does well. The second is smaller and avoids two pages drifting apart again. Either way the "Roadmap" heading and the defineDatasource denial go.
Re-check
git -C objectstack show origin/main:docs/adr/0015-external-datasource-federation.md | head -3
git -C objectstack grep -n 'export function defineDatasource' origin/main -- packages/spec/src
git show origin/main:content/docs/configure/data-sources.mdx | sed -n '85,95p;230,250p'
Related: the sibling claim in the extend-existing-systems-with-ai blog post is filed separately in the www.objectos.ai tracker.
Generated by Claude Code
Activity
os-bill commentedon Sep 2, 2026
Triage — first touch. Graded
Bug, promoted topm:queue.Session
session_01ChPQM8jamxLUfUAxwFpJ8S,repo:objectosseat, round 1. This is a single-lane repo, so under the 2026-08-26 ruling first-touch grading andtypeare this seat's own to produce, not central triage's. This seat still does not producedomain:*.Type
Bug, by the mechanical boundary test: the change restoresdeclared = actualon a published page. It does not widen an accept set or a public surface, so it is not a Feature; it is not neutral housekeeping, so it is not a Task. A page telling a reader that a shipped capability is a roadmap item is a defect in published material, and the finder's measurement — all four "planned, not yet shipped" bullets located onorigin/main, plusexport function defineDatasourceatdatasource.zod.ts:816— makes it a defect with a named landing site rather than an observation. That is what separatespm:queuefromfindinghere.Severity note, not a priority label: this one fails in the expensive direction. It does not mislead someone already committed; it tells someone still evaluating that the safety gates they need for their production database do not exist yet. That reader leaves and never files a bug, which is also why the staleness is self-concealing — nothing on the page is broken, so no gate fires.
Direction adjudicated — link, do not duplicate
The card leaves the scope question open ("describe the shipped federation surface here, or link to the monorepo guide"). Adjudicated in favour of linking, so the dispatch carries a decided direction rather than handing the fork to a dev. This is a docs-structure call, not a product-semantics one, and it is settled by a convention this lane already holds in writing: the mirror follows, it does not lead — the rule this seat used to block #142 rather than let objectos become the de-facto author of platform release notes.
data-modeling/external-datasources.mdxin the monorepo owns this surface and ships the full guide; re-describing it here creates the second copy that drifted into existence in the first place. It is also the smaller change, which is the right default at this stage.So, in scope:
data-modeling/external-datasources.mdx, not a re-description ofschemaMode,externalbindings, the CLI or the wizard.defineDatasource()denial on line 88 is corrected. Note the shape: the plain-object form the page describes still works, so this is a wrong denial, not a broken example — the fix names the helper as available, and must not imply the existing form stopped working.⛔ Out of scope: any change to
data-modeling/external-datasources.mdx(different repo, and it is the source of truth this page will point at), and any claim about which dialect drivers or Studio surfaces are pending — that is exactly the forecasting this lane keeps having to delete.Premise re-check is the dispatch's first task, not this comment's. The measurements above were taken at
objectstackorigin/main@7cbe705b; they get re-run againstorigin/mainat dispatch time, using the re-check block the finder helpfully left on the card. A premise verified at grading and quoted forward at dispatch is the exact failure this lane has recorded three times.Generated by Claude Code
os-bill commentedon Sep 2, 2026
Claim: PM loop round 1⚠️ Tier stated by PM judgment, not quoted from
Session:
session_01ChPQM8jamxLUfUAxwFpJ8SBranch:
claude/issue-250-federation-shipped-not-roadmapWorktree:
objectos-issue-250Domain:
repo:objectos(single-lane repo — this seat does not producedomain:*)File surface:
content/docs/configure/data-sources.mdx(stop on breach; explain in the report)Container & model:
M,mode:subagent,model: opus.scripts/pm/dispatch-gates.mjs --tier— absent in this repo.Clause-②: no
Serial constraints cleared: none — no open PR, no in-flight card and no hot-file queue entry touches
configure/data-sources.mdx. The two siblings dispatched in this batch (#246configure/notifications.mdx, #251reference/environment-variables.mdx) are disjoint by construction. ⛔ No read coupling either: this card asserts nothing about behaviour a sibling is changing, so there is no pin to flip when they land.Dispatch-time premise re-check — all four legs hold. Card measured at
objectstackorigin/main@7cbe705b; upstream is now90ff957, so every leg was re-run rather than carried:data-sources.mdx:238is stale at the source.export function defineDatasourceis live atpackages/spec/src/data/datasource.zod.ts:816. Control-probed: the same pathspec returns otherexport function define…hits acrosspackages/spec/src, so the match is a real reading and not a lucky grep.data-sources.mdx:232still carries## Roadmap: in-product External Datasource Federation, and:238still saysPlanned, **not yet shipped**.data-sources.mdx:88still carries the denial> There is **no**defineDatasource()helper.Nothing is half-done: the page is exactly as the finder measured it, four days on.
Generated by Claude Code
os-bill commentedon Sep 2, 2026
Claim: dev agent, round 1 (in addition to the PM's claim above).
Session:
session_01ChPQM8jamxLUfUAxwFpJ8S— note this is the same session id the PM comment carries; this seat runs as a subagent under that session, so the id does not distinguish us. The distinguishing identity bit is the branch below.Branch:
claude/issue-250-federation-shipped-not-roadmap(pushed empty at8e665c7before the first edit — write path probed green).Worktree:
objectos-issue-250, cut--no-trackfromorigin/main@8e665c7.File surface:
content/docs/configure/data-sources.mdxonly.Assignee: untouched (
os-bill, set by PM).Premise re-check is my first task; upstream
objectstackhas moved again since dispatch (90ff957→2514d49), so all four legs get re-run against the current tip rather than carried forward.Generated by Claude Code
os-bill commentedon Sep 2, 2026
os-dev-report
{ "issue": 250, "status": "done", "branch": "claude/issue-250-federation-shipped-not-roadmap", "pr": "https://github.com/objectstack-ai/objectos/pull/252", "premise_still_valid": true, "premise_recheck": { "measured_at": "objectstack origin/main @ 2514d49 (card measured @ 7cbe705b, PM @ 90ff957 — upstream moved again, so all legs re-run, none carried)", "adr_0015_status": "HOLDS — 'Status: Accepted — backend/REST/CLI implemented; Studio UI + extra dialect drivers pending'; the page's 'status: Proposed' gloss is stale at the source", "defineDatasource": "HOLDS — packages/spec/src/data/datasource.zod.ts:816; re-exported at packages/spec/src/index.ts:171 and through ./data. Control probe: same pathspec returns 20 other 'export function define' hits, so the match is a real reading, not a lucky grep", "page_lines": "HOLDS — :232 Roadmap heading, :238 'Planned, not yet shipped', :88 the defineDatasource denial, all present before editing", "bullet_1_schemaMode": "SHIPPED — SchemaModeSchema at datasource.zod.ts:238, wired at :651 as schemaMode: SchemaModeSchema.default('managed')", "bullet_2_external_binding": "SHIPPED — ObjectExternalBindingSchema wired at object.zod.ts:1919 as external: ObjectExternalBindingSchema.optional()", "bullet_3_cli": "SHIPPED — packages/cli/src/commands/datasource/introspect.ts, validate.ts, list-tables.ts all present", "bullet_4_gates_and_wizard": "SHIPPED — ADR-0062 R6 boot validation gate (packages/runtime/src/external-validation-plugin.ts), R5c write gate (double opt-in), R7 introspection + runtime Sync wizard, each marked shipped in the ADR-0062 requirement table", "split_needed": false }, "files_changed": ["content/docs/configure/data-sources.mdx"], "gates": [ { "gate": "pnpm turbo run type-check build --filter=@objectos/docs (under scripts/pm/os-verify-lock.sh)", "conclusion": "PASS — 'Tasks: 2 successful, 2 total' / 'Cached: 0 cached, 2 total' (real work, not a replayed green: the content edit moved the turbo hash). Lock line: 'VERDICT command-exit 0 · held the lock 77s · waited 0s'" }, { "gate": "pnpm turbo run test (under the same lock)", "conclusion": "PASS — 'Tasks: 1 successful, 1 total'; ci-scripts prints 'self-test: 18 case(s) over 10 rule(s) and 3 artifact(s) — every rule demonstrated able to fail' and '✓ 4 self-test(s) passed'. Lock line: 'VERDICT command-exit 0 · held the lock 3s · waited 55s'" }, { "gate": "union re-run at final HEAD feeeec8 (type-check build test)", "conclusion": "PASS, DECLARED REPLAY — 'Tasks: 3 successful, 3 total · Cached: 3 cached · FULL TURBO'. Not an independent measurement; the uncached run above ran minutes earlier in this same worktree on a byte-identical tree (git status empty at feeeec8), and the rendered HTML inspected below came out of that build" }, { "gate": "node apps/docs/scripts/gen-zh-hant.mjs --check", "conclusion": "PASS — '✓ zh-Hant: 73 generated file(s) match the zh-Hans sources byte for byte.'" }, { "gate": "node .github/scripts/check-translations.mjs", "conclusion": "PASS — '✓ translations gate passed' (this page's 7 locale siblings are now stale; reported, not blocking, by design)" }, { "gate": "node .github/scripts/check-translation-ownership.mjs --actor os-bill --files (diff list)", "conclusion": "PASS with notice — '⚠ TRANSLATION_BOT_LOGIN is not set — ownership is not enforced yet.' / 'This PR touches 0 translation artifact(s) and 1 other file(s).'" }, { "gate": "node .github/scripts/check-locale-surface.mjs (reads the built sitemap)", "conclusion": "PASS — '✓ every advertised URL has a source file and every source file is advertised; both llms bodies carry every en-only page title and none from the other locales; and no page slug in the content tree contains a dot'. sitemap.xml row: read 409 / expected 409 / unexpected 0 / missing 0" }, { "gate": "node .github/scripts/check-node-floor.mjs --self-test, then the real scan", "conclusion": "PASS — self-test: '17 rule case(s), 24 satisfies case(s) and 18 range case(s) — every rule demonstrated able to fail'; scan: '✅ Every declared floor clears what the dependency tree requires, and the declarations agree.'" }, { "gate": "control-byte self-scan: grep -naP over the edited file and the PR body", "conclusion": "CLEAN — grep exit 1 (no match) on both" }, { "gate": "rendered-artifact check on apps/docs/.next/server/app/en/docs/configure/data-sources.html", "conclusion": "PASS — new heading present (4 hits: heading + TOC + anchors), pointer href present (2 hits), new defineDatasource callout present; 'Roadmap: in-product' 0, 'not yet shipped' 0, 'status: Proposed' 0, 'There is no' 0" }, { "gate": "node scripts/pm/check-half-states.mjs", "conclusion": "NOT MEASURED — exit 3, 'PREREQUISITE NOT MET — the token in the environment is not a valid GitHub credential'. Read as not-measured, not as red; it is the scheduled half-state-patrol job, not a PR gate on this diff" } ], "gates_derivation_note": "objectstack's scripts/pm/dispatch-gates.mjs is NOT used here — it only ever answers about its own tree, and this repo is objectos. The list above is derived by hand from this repo's .github/workflows/ci.yml (node-floor, gen-zh-hant --check, type-check, build, check-locale-surface, test) and translations.yml (ownership, freshness).", "summary": "Removed the 'Roadmap: in-product External Datasource Federation' section (heading, the 'Planned, not yet shipped' framing, its four bullets and the 'until those land' closer) and replaced it with a short pointer to the framework guide that owns the surface, per the adjudicated link-do-not-duplicate direction. Corrected the line-88 denial to name defineDatasource() as available while keeping the plain-object Datasource literal explicitly valid — it was a wrong denial, not a broken example. The ADR-0015 link survives with its stale 'status: Proposed' gloss replaced by 'Accepted'. No changeset (this repo has no changeset flow) and no locale siblings touched.", "tests": "Gate union re-run at final HEAD feeeec8 (see the replay declaration in the gates list); heavy runs went through scripts/pm/os-verify-lock.sh and are quoted by their own VERDICT lines, never a bare $?.", "mcp_calls": "8 — issue_read get, issue_read get_comments, add_issue_comment (claim), create_pull_request, pull_request_read (full body read-back), search_issues (one targeted dedup query), issue_write (filed #254), add_issue_comment (this report). Repo-scoped REST probed first and returned HTTP 403 ('GitHub access is not enabled for this session') and gh is absent, so MCP was the declared channel for the dedup search.", "deviations": [ "Gate union at final HEAD is a turbo cache replay (3 cached, FULL TURBO), declared rather than quoted as a fresh measurement. The uncached run happened minutes earlier in this same worktree on a byte-identical tree.", "Scope held: a sibling page carries the same defect and was NOT fixed here. content/docs/extend-existing-systems.mdx:83 repeats the identical claim ('turn-key federation ... in active design under ADR-0015 (status: Proposed). Until it lands ...'). The bounded in-place-fix exemption was not taken because this dispatch pins the file surface to data-sources.mdx and says stop on breach. Filed unassigned as #254 instead.", "No changeset and no skip-changeset label: this repo runs no changeset flow (workflows are ci.yml, deploy-docs.yml, half-state-patrol.yml, translations.yml) and has no such label mechanism.", "No browser dogfood pass. AGENTS.md rule 2 targets UI changes in apps/docs; this is a content-only MDX edit rendered by unchanged components, so verification was taken off the real prerendered build artifact instead (listed as a gate above).", "CI convergence not awaited, per the standing dispatch contract; PR check state at report time is whatever CI has reached.", "Assignee untouched, as instructed." ], "open_questions": [], "out_of_scope_findings": [ "filed as #254: content/docs/extend-existing-systems.mdx 'Where this is headed' repeats the same stale ADR-0015 'status: Proposed' / 'until it lands' federation forecast that #250 removes from data-sources.mdx" ] }Generated by Claude Code
os-bill commentedon Sep 2, 2026
ACCEPT — PR #252
Reviewer of record:
session_01ChPQM8jamxLUfUAxwFpJ8S,repo:objectosseat, round 1. Checked against GitHub, not against the report's account of itself.main, first body lineFixes #250✓content/docs/configure/data-sources.mdx. Matches the pinned surface exactlyget_files, not the report)docs/adr/**,.claude/**,skills/**,AGENTS.md,CLAUDE.md. Clears for the queuebuild(required)successon headfeeeec8Node floorsuccessOwnership & freshnesssuccessDiff read, not skimmed. It is the adjudicated direction and nothing else: the Roadmap section becomes a pointer rather than a second description; the ADR-0015 gloss goes
Proposed→Accepted; thedefineDatasource()denial becomes an availability statement that explicitly keeps the plainDatasourceliteral valid — which was the specific trap on this card (a wrong denial, not a broken example), and it was not fallen into. The cross-site absolute URL todocs.objectstack.aiis right for a link leaving this site.The part of the report that earns the most credit is the part that could have gone wrong quietly. The dispatch asked for each of the four "planned" bullets to be verified individually, because one still-unshipped bullet would have split the edit rather than being deleted along with three false ones. All four were checked separately and named with their wiring sites (
SchemaModeSchemaat:238wired at:651;ObjectExternalBindingSchemaatobject.zod.ts:1919; the three CLI command files; ADR-0062 R6/R5c/R7).split_needed: falseis therefore a measured answer, not an assumption.Upstream had moved again —
90ff957→2514d49— between my dispatch-time re-check and the dev's run, and every leg was re-run there rather than carried. That is the discipline this lane keeps paying for; here it cost nothing because the readings held.Two declarations I want on the record because they were volunteered rather than extracted:
feeeec8is a turbo cache replay (3 cached · FULL TURBO), declared as such instead of quoted as a fresh measurement, with the uncached run that actually moved the hash quoted separately. This lane has a standing note that the turbo cache is shared across worktrees and has replayed a sibling's green here; a dev distinguishing its own replay from its own measurement is exactly the behaviour that note asks for.check-half-states.mjsreturned exit 3,PREREQUISITE NOT METand was reported as not measured rather than as red or as passed. Correct on both counts: it is the scheduled patrol, not a gate on this diff. It also independently corroborates what I hit earlier this round — the API credential in this container is not usable for direct GitHub calls.Scope held under pressure, and the finding is the valuable part.⚠️ The instruction was mine and it was the weaker choice: had I known at dispatch time that the defect had a twin, fold gate ① (same defect shape, same fix) and ② (same region) were both satisfied and this should have gone out as one folded dispatch. I did not sweep for siblings before writing the file surface — the same "answer absence by diffing, not by enumerating" failure this seat post has carried since 08-20. #254 now costs a second full dispatch cycle for what one PR could have carried.
content/docs/extend-existing-systems.mdx:83carries the identical stale claim. The dev did not ride it in — the dispatch pinned the file surface and said stop on breach — and filed #254 instead. That is the right call against the instruction it was given.⛔ No deviations requiring rework. Landing.
Generated by Claude Code