Skip to content

[finding] configure/data-sources.mdx describes external datasource federation as unshipped — all four planned bullets have shipped, and defineDatasource() does exist #250

Closed

Description

@hotlong

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 a Datasource object you place in the datasources array

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

  1. added theissue type on Sep 2, 2026
  2. os-bill commented on Sep 2, 2026

    @os-bill
    Collaborator

    Triage — first touch. Graded Bug, promoted to pm:queue.

    Session session_01ChPQM8jamxLUfUAxwFpJ8S, repo:objectos seat, round 1. This is a single-lane repo, so under the 2026-08-26 ruling first-touch grading and type are this seat's own to produce, not central triage's. This seat still does not produce domain:*.

    Type Bug, by the mechanical boundary test: the change restores declared = actual on 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 on origin/main, plus export function defineDatasource at datasource.zod.ts:816 — makes it a defect with a named landing site rather than an observation. That is what separates pm:queue from finding here.

    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.mdx in 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:

    1. The "Roadmap: in-product External Datasource Federation" section goes — heading, the "planned, not yet shipped" framing and its four bullets. What replaces it is a short pointer to data-modeling/external-datasources.mdx, not a re-description of schemaMode, external bindings, the CLI or the wizard.
    2. The 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.
    3. The ADR-0015 link stays useful but its "status: Proposed" gloss does not survive: the ADR's own status line now reads "Accepted — backend/REST/CLI implemented; Studio UI + extra dialect drivers pending."

    ⛔ 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 objectstack origin/main @ 7cbe705b; they get re-run against origin/main at 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

  3. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Sep 2, 2026
  4. self-assigned this
    on Sep 2, 2026
  5. os-bill commented on Sep 2, 2026

    @os-bill
    Collaborator

    Claim: PM loop round 1
    Session: session_01ChPQM8jamxLUfUAxwFpJ8S
    Branch: claude/issue-250-federation-shipped-not-roadmap
    Worktree: objectos-issue-250
    Domain: repo:objectos (single-lane repo — this seat does not produce domain:*)
    File surface: content/docs/configure/data-sources.mdx (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus. ⚠️ Tier stated by PM judgment, not quoted from 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 (#246 configure/notifications.mdx, #251 reference/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 objectstack origin/main @ 7cbe705b; upstream is now 90ff957, so every leg was re-run rather than carried:

    • ADR-0015's status line reads "Accepted — backend/REST/CLI implemented; Studio UI + extra dialect drivers pending" — so the page's "status: Proposed" gloss at data-sources.mdx:238 is stale at the source.
    • export function defineDatasource is live at packages/spec/src/data/datasource.zod.ts:816. Control-probed: the same pathspec returns other export function define… hits across packages/spec/src, so the match is a real reading and not a lucky grep.
    • data-sources.mdx:232 still carries ## Roadmap: in-product External Datasource Federation, and :238 still says Planned, **not yet shipped**.
    • data-sources.mdx:88 still 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

  6. os-bill commented on Sep 2, 2026

    @os-bill
    Collaborator

    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 at 8e665c7 before the first edit — write path probed green).
    Worktree: objectos-issue-250, cut --no-track from origin/main @ 8e665c7.
    File surface: content/docs/configure/data-sources.mdx only.
    Assignee: untouched (os-bill, set by PM).

    Premise re-check is my first task; upstream objectstack has 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

  7. os-bill commented on Sep 2, 2026

    @os-bill
    Collaborator

    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

  8. os-bill commented on Sep 2, 2026

    @os-bill
    Collaborator

    ACCEPT — PR #252

    Reviewer of record: session_01ChPQM8jamxLUfUAxwFpJ8S, repo:objectos seat, round 1. Checked against GitHub, not against the report's account of itself.

    Check Reading
    PR shape draft, base main, first body line Fixes #250 ✓
    Changed files 1 — content/docs/configure/data-sources.mdx. Matches the pinned surface exactly
    Path surface (get_files, not the report) no governed path — no docs/adr/**, .claude/**, skills/**, AGENTS.md, CLAUDE.md. Clears for the queue
    build (required) success on head feeeec8
    Node floor success
    Ownership & freshness success
    Changeset correctly none — this repo runs no changeset flow

    Diff 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; the defineDatasource() denial becomes an availability statement that explicitly keeps the plain Datasource literal 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 to docs.objectstack.ai is 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 (SchemaModeSchema at :238 wired at :651; ObjectExternalBindingSchema at object.zod.ts:1919; the three CLI command files; ADR-0062 R6/R5c/R7). split_needed: false is 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:

    • The final gate union at feeeec8 is 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.mjs returned exit 3, PREREQUISITE NOT MET and 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. content/docs/extend-existing-systems.mdx:83 carries 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. ⚠️ 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.

    ⛔ No deviations requiring rework. Landing.


    Generated by Claude Code

  9. removed
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions