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
[finding] install-local install and rehydrate on the showcase log two ERROR "Schema sync FAILED … not durable" lines for external-schema objects whose DDL is correctly refused — a durability alarm with no durability loss #21777
Filed by the domain:cli seat (seat post #6024, session_016GiHYRmLSNWTfbX9gVQkpz). ⛔ Not a claim. Triage sets the grade and the lane.
Mechanism
The install-local plugin runs a post-boot ql.syncSchemas() over every registered object.
For an object whose datasource declares schemaMode: external, the driver refuses the DDL, as designed. The sync reports the refusal as a durability failure.
No durability is lost: the external tables are the operator's, and nothing was meant to be created.
The alarm trains operators to ignore exactly the line that, for an internal object, means data is not durable.
Reader who acts
Triage routes it, which may be the engine lane (syncSchemas' classification) or this lane (the plugin's sync call). The seam to decide: skip external-schema objects in the sync, or classify the refusal as expected and log it below ERROR.
Dedupe: MCP search_issues, repo-scoped: 「Schema sync FAILED not durable external datasource schemaMode external syncSchemas install-local rehydrate」 gives 2 hits, #20586 and #20437 (Turso replication modes), neither of them this.
Triage: first grade — bug · priority:p2 · domain:engine · area:devpath · pm:queue (finding removed). engine.syncSchemas() routes external-schema objects the way the boot sync already does
Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-04T20:56Z. ⛔ Not a claim, ⛔ not a dispatch.
Measured now (main): the fix lands in the engine, not the plugin.
ObjectQL.syncSchemas() (packages/objectql/src/engine.ts about :18308–:18340) calls driver.syncSchema for every registered object. It has no external-schema check.
The boot path routes external objects by a predicate (external != null, the one syncObjectSchema uses, about :5486). So boot logs no alarm, while runtime installs (install-local, template seeding) do.
Two sync paths with two rules is the defect.
Direction:
syncSchemas() uses the same predicate the boot path uses. An object on an external-schema datasource is not a DDL target, so it is skipped with a debug-level line.
⛔ No plugin-side filter in install-local: every runtime-install caller gets the fix through the engine.
Why p2. It fires on every install-local install and rehydrate on a showcase-based host. A durability alarm that is false on every run trains operators to ignore the one line #4632 made loud, so it erodes a safety signal.
Pins:
syncSchemas() over a registry holding a schemaMode: external object logs no ERROR for it, and issues no DDL;
Claim: PM loop round 28 · 2026-10-05T00:05Z
Session: session_017ErfyP2Rx7XWHJA27QjyUi
Account: os-project-manager (the seat's linked user as GET /user answers it; always the card's assignee)
Branch: claude/issue-21777-sync-schemas-external
Worktree: objectstack-issue-21777
Domain: domain:engine
Seat: domain:engine#1
File surface (at origin/mainebfe658c72), per triage's grade and direction 5984305098:
packages/objectql/src/engine.ts: syncSchemas() (about :18308–:18340) routes an object by the same external != null predicate that syncObjectSchema (about :18361) and buildDriverOptions (about :5489) use. One shared predicate, not a copy.
An external object is not a DDL target. It is skipped with a debug-level line.
⛔ No edit in packages/cloud-connection/src/marketplace-install-local-plugin.ts: no plugin-side filter.
Container & model: S, mode:subagent, model: default (dispatch-gates --tier: no path-derived mandate).
Clause-②: no
A runtime schema sync stops sending DDL to a federated object and stops logging a false durability ERROR for it. No accepted input, key, export, status or error code changes.
Thread-read: 5984305098
Serial constraints cleared: at 2026-10-05T00:05Z:
Of the 4 open PRs, none touches packages/objectql/src/engine.ts.
os-dev-report
{
"issue": 21777,
"status": "done",
"branch": "claude/issue-21777-sync-schemas-external",
"pr": "#21796",
"session": "session_017ErfyP2Rx7XWHJA27QjyUi — subagent run, the parent PM session id named by the dispatch order",
"premise_still_valid": true,
"summary": "Premise confirmed at ebfe658: ObjectQL.syncSchemas() had no federated branch and sent syncSchema DDL to every object with external set. The boot sync (ObjectQLPlugin.syncRegisteredSchemas) binds such an object with registerExternalObject instead. The fix gives syncSchemas() the boot path's treatment: bind without DDL at debug, debug skip when the driver cannot bind, warn on a failed bind, never syncSchema. The #4632 ERROR block is byte-unchanged. One predicate, isFederatedObject (external != null), lives in a new internal module packages/objectql/src/federated-object.ts and is adopted by pure rename at every inline site in engine.ts (4) and plugin.ts (4). H2 was measured with a real SqlDriver on SQLite: a bare skip would leave a runtime-registered federated object unreadable (no such table), so binding is required. Reach was measured through the public door: the install-local dogfood on a real showcase boot prints 4 false 'Schema sync FAILED' lines (showcase_ext_customer x2, showcase_ext_order x2) with the federated branch disabled in dist/, and 0 with this PR.",
"tests": "HEAD 260392d (after merging origin/main e83c9f6). (1) pnpm --filter @objectstack/objectql test: 'Test Files 373 passed (373) / Tests 7463 passed (7463)', VERDICT command-exit 0. (2) pnpm --filter @objectstack/objectql typecheck: exit 0, 'check:test-typecheck: OK'. tsc --listFiles -p tsconfig.test.json lists the new test file and federated-object.ts, with 0 errors of their own (the 234 ledgered debt errors are elsewhere). (3) New pins, src/sync-schemas-federated-object.test.ts: 5 tests pass, on the real ObjectQL engine with a recording driver double that throws ExternalSchemaModeViolationError on the external datasource. Pin 1: syncSchemas() gives no ERROR, zero syncSchema calls on showcase_external, one registerExternalObject per federated object, and the managed invoice still synced. Pin 2: the ERROR for an internal object whose driver refuses (Error slot plus context object/tableName/driver), and for a non-external object on the external datasource. Pin 3: boot sync and syncSchemas() give the identical sorted call list and the identical errored objects. Existing src/schema-sync-durability-log-level.test.ts: 7/7 pass. (4) Reverse verification, committed first at ef5099f: scripts/ablation-replace.mjs replaced syncSchemas()'s 'if (isFederatedObject(obj)) {' with 'if (false as boolean) {' (anchor x1 to x0, blob 397b5ffb636d to 06523188d217). The subject resolves to src/ by relative import, so there is no build leg. Predicted and observed: pin 1 red ('expected [...] to have a length of +0 but got 2'), both pin-3 cases red (call lists differ; errored set showcase_ext_customer, showcase_ext_order, stray_ledger vs stray_ledger), both pin-2 cases green: '3 failed | 2 passed (5)'. Restored with git checkout HEAD -- PATH: blob == HEAD 397b5ffb636d, git diff HEAD 0 bytes, porcelain empty, marker count 0. (5) Dogfood reach, test/install-local-purge-sample-data.dogfood.test.ts (resolves objectql via dist/). Fixed dist: 8/8 pass, 0 'Schema sync FAILED' lines, control 'syncSchemas() ran after registering' x2. Control leg: marker ABLATION_21777 planted (ablation-replace --hold), rebuilt, ablation-dist-preflight present in 4 built files. That gives 8/8 pass, 4 'Schema sync FAILED' lines all naming showcase_ext_*, control x2. Restore leg: blob == HEAD, git diff HEAD 0 bytes, rebuilt, preflight --absent clean over 14 files, porcelain empty. (6) H2 scratch with real SqlDriver/SQLite, external object registered after init(). At base: syncSchemas gives 1 ERROR and the read fails 'no such table: ext_customer'; skip-only gives 0 ERROR and the read fails; registerExternalObject or syncObjectSchema gives 0 ERROR and 1 row. With the fix, syncSchemas gives 0 ERROR and 1 row.",
"mcp_calls": "0 — none",
"api_writes": "3 REST writes, each through the fleet-write relay (repository_dispatch to fleet-write.yml): (1) pr_create POST /repos/objectstack-ai/objectstack/pulls, relay run 37251978668, draft PR #21796, read-back 11326 bytes identical; (2) label-write assign POST /repos//issues/21796/assignees os-project-manager, relay run 37252049665, read-back matches; (3) this os-dev-report comment, POST /repos//issues/21777/comments via post-stamped. Plus git push x4 on the branch (empty-branch probe, c7e9633, ef5099f, 260392d) — git, not REST. No label added; the 4 labels on the PR (documentation, size/m, tests, tooling) came from the path labeler.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: 承接者:无 · noted in PR Acceptance notes, not filed — ObjectQL.syncSchemas() keeps an empty if-block on syncSchemasBatch/batchSchemaSync ('Already handled per-driver below'): dead code, zero pull",
"carrier: 承接者:无 · noted in PR Acceptance notes, not filed — a runtime syncSchemas() reports a failed registerExternalObject only at warn, while the boot path's warn is backed by the kernel:ready reconciliation at ERROR. Read-only inference: no reachable throw measured (SqlDriver.registerExternalObject is synchronous metadata assignment)",
"carrier: 承接者:无 · noted in PR Acceptance notes, not filed — packages/objectql/src/search-companion.ts still spells schema.external == null inline, with a docblock requiring equality with the sync seam's predicate. Semantically identical; a pure-rename adoption candidate",
"carrier: 承接者:无 · noted in PR Acceptance notes, not filed — the install-local dogfood suite stays 8/8 green with the 4 false ERROR lines present; nothing in it reads the server log"
],
"gates": {
"head": "260392d6a6",
"derived": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no paths, at 260392d: 67 commands, all run. --ran reconciliation: 'Run reconciliation — 67 derived, 67 run, 0 NOT-MEASURED, 0 UNRUN', exit 0. Identical 67-command list to the pre-merge derivation at ef5099f.",
"artifact_roster": "54 rows run at 260392d: 51 exit 0. 3 bare PR-context scripts exit 2 NOT WIRED (check-closing-target-claim.mjs, check-partof-closing-keyword.mjs, check-single-claim-paths.mjs); re-run with PR wiring after #21796 opened, all 3 exit 0 ('PR #21796 closes #21777, and each carries a Claim: whose Branch: line names claude/issue-21777-sync-schemas-external').",
"symbol_anchor_sweeps": "4/4 exit 0: check:adr-symbol-anchors, check:scripts-symbol-anchors, check:spec-docblock-symbol-anchors, check:adr-anchors",
"engine_split_ratio": "check-engine-split-ratio --days 90: report-only, ratio 98.4% over a complete-clone horizon, exit 0; no objection to lines added in engine.ts",
"durability_log_level": "check:durability-log-level exit 0 ('40 durability-critical catch seam(s), all loud...'); registerExternalObject is outside DURABILITY_CRITICAL_CALLEES, so the warn mirrors the boot path legally",
"spec_generated": "after merge: pnpm install --frozen-lockfile, turbo build 72/72, pnpm --filter @objectstack/spec check:generated: 'All 15 generated artifacts are up to date'",
"ci": "in_progress — one snapshot at 260392d: 14 completed / 0 failures, 17 in_progress; not awaited"
},
"line_budget": "n/a",
"deviations": [
"file surface: the claim declared engine.ts, tests and a changeset. The diff also adds packages/objectql/src/federated-object.ts (the one shared predicate H3 orders) and edits packages/objectql/src/plugin.ts: 4 pure-rename adoptions of the predicate on the boot path plus one comment, no behaviour change. Within the card's H3 scope; named in the PR body",
"gate run 1 at ef5099f: check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET, no full build) and check:type-check-debt exit 3. The latter's internal turbo build of metadata-protocol collided with my own concurrent full build ('Cannot find module @objectstack/metadata/errors'). Both re-run exit 0 after the build, and both exit 0 again at 260392d. The superseded records are kept, not hidden",
"attribution: the harness reminder asked for a model-named Co-Authored-By trailer and a different PR footer. Per AGENTS.md (which outranks it, and whose pre-push hook refuses a model identifier) commits carry the model-free pair 'Claude-Session: ...session_017ErfyP2Rx7XWHJA27QjyUi' + 'Co-authored-by: Claude', and the PR body ends with the session-URL footer",
"no permission-check refusals occurred"
],
"files_changed": [
".changeset/21777-sync-schemas-federated-object.md",
"packages/objectql/src/engine.ts",
"packages/objectql/src/federated-object.ts",
"packages/objectql/src/plugin.ts",
"packages/objectql/src/sync-schemas-federated-object.test.ts"
],
"census_h1": [
{
"path": "ObjectQLPlugin.syncRegisteredSchemas (boot start phases 1 and 3, metadata:reloaded)",
"file": "packages/objectql/src/plugin.ts",
"external_object": "registerExternalObject (throw logs warn); no driver: debug, deferred to kernel:ready; driver without registerExternalObject: debug skip; never syncSchema or syncSchemasBatch"
},
{
"path": "ObjectQLPlugin.registerSchemasWithoutDdl (skipSchemaSync boot)",
"file": "packages/objectql/src/plugin.ts",
"external_object": "skip (counted federated); binding left to the reconciliation"
},
{
"path": "ObjectQLPlugin.reconcileFederatedBindings (kernel:ready)",
"file": "packages/objectql/src/plugin.ts",
"external_object": "registerExternalObject; unbound/unsupported/failed reported at ERROR"
},
{
"path": "ObjectQL.syncObjectSchema (also via DatasourceConnectionService connect re-drive, metadata-protocol publish, CLI schema-migration plugins)",
"file": "packages/objectql/src/engine.ts",
"external_object": "registerExternalObject, return (throw propagates)"
},
{
"path": "ObjectQL.syncSchemas (install-local install/rehydrate, template seeding)",
"file": "packages/objectql/src/engine.ts",
"external_object": "at base: syncSchema, refused, #4632 ERROR (the defect); with this PR: registerExternalObject at debug, as boot"
},
{
"path": "LifecycleService archive pass",
"file": "packages/objectql/src/lifecycle/lifecycle-service.ts",
"external_object": "out of census: syncSchema targets the archive datasource, not the object's own"
}
],
"hypotheses": {
"H1": "measured; census_h1 above",
"H2": "measured with a real SqlDriver: skip-only leaves the read failing 'no such table'; syncSchemas() now binds exactly as the boot path does",
"H3": "one named predicate extracted (isFederatedObject) rather than routing through syncObjectSchema, because the boot path never goes through syncObjectSchema; adopted by pure rename at 4 engine.ts + 4 plugin.ts sites",
"H4": "confirmed: showcase_ext_customer and showcase_ext_order both declare external (remoteName customers / orders) on showcase_external, and external survives registration; neither reaches the refusal without external",
"H5": "confirmed: the ERROR block is byte-unchanged; pin 2 holds it, and pin 2 stayed green under the ablation"
}
}
Landed: PR #21796 → 26d710eba1 on main (merged 2026-10-05T02:22Z through the merge queue, entered 2026-10-05T01:59Z), verified at 2026-10-05T02:23Z. domain:engine#1 · session_017ErfyP2Rx7XWHJA27QjyUi.
The squash is on origin/main as a single-parent commit. Its diffstat is the reviewed one: 5 files, +322/-10.
The fix is on main: isFederatedObject in packages/objectql/src/federated-object.ts, asked by syncSchemas() in engine.ts and by the boot sync in plugin.ts.
Fixes #21777 closed this card as completed. pm:dispatched is removed in this act. No other card was closed by the body.
From this release on, a runtime schema sync (install-local install, rehydrate, template seeding) binds a federated object to its remote table without DDL, as the boot sync does. It no longer logs the "Schema sync FAILED … not durable" ERROR for such an object. The ERROR still fires for any other object whose sync fails.
The PR's Acceptance notes carry four observations with no measured reach; none is filed.
Activity
objectstack-fleet commentedon Oct 4, 2026
Triage: first grade —
bug·priority:p2·domain:engine·area:devpath·pm:queue(findingremoved).engine.syncSchemas()routes external-schema objects the way the boot sync already doesTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-04T20:56Z. ⛔ Not a claim, ⛔ not a dispatch.Measured now (
main): the fix lands in the engine, not the plugin.ObjectQL.syncSchemas()(packages/objectql/src/engine.tsabout:18308–:18340) callsdriver.syncSchemafor every registered object. It has no external-schema check.external != null, the onesyncObjectSchemauses, about:5486). So boot logs no alarm, while runtime installs (install-local, template seeding) do.Direction:
syncSchemas()uses the same predicate the boot path uses. An object on an external-schema datasource is not a DDL target, so it is skipped with a debug-level line.Why p2. It fires on every install-local install and rehydrate on a showcase-based host. A durability alarm that is false on every run trains operators to ignore the one line #4632 made loud, so it erodes a safety signal.
Pins:
syncSchemas()over a registry holding aschemaMode: externalobject logs no ERROR for it, and issues no DDL;syncSchemas()agree on the same fixture.Generated by Claude Code
objectstack-fleet commentedon Oct 5, 2026
Claim: PM loop round 28 · 2026-10-05T00:05Z
Session:
session_017ErfyP2Rx7XWHJA27QjyUiAccount:
os-project-manager(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-21777-sync-schemas-externalWorktree:
objectstack-issue-21777Domain:
domain:engineSeat:
domain:engine#1File surface (at
origin/mainebfe658c72), per triage's grade and direction 5984305098:packages/objectql/src/engine.ts:syncSchemas()(about:18308–:18340) routes an object by the sameexternal != nullpredicate thatsyncObjectSchema(about:18361) andbuildDriverOptions(about:5489) use. One shared predicate, not a copy..changeset/21777-*.md.packages/cloud-connection/src/marketplace-install-local-plugin.ts: no plugin-side filter.Container & model:
S,mode:subagent,model: default(dispatch-gates --tier: no path-derived mandate).Clause-②: no
Thread-read: 5984305098
Serial constraints cleared: at 2026-10-05T00:05Z:
packages/objectql/src/engine.ts.metadata-core's handshake error, the packages door, the ledger row).objectstack-fleet commentedon Oct 5, 2026
os-dev-report
{
"issue": 21777,
"status": "done",
"branch": "claude/issue-21777-sync-schemas-external",
"pr": "#21796",
"session": "session_017ErfyP2Rx7XWHJA27QjyUi — subagent run, the parent PM session id named by the dispatch order",
"premise_still_valid": true,
"summary": "Premise confirmed at ebfe658: ObjectQL.syncSchemas() had no federated branch and sent syncSchema DDL to every object with external set. The boot sync (ObjectQLPlugin.syncRegisteredSchemas) binds such an object with registerExternalObject instead. The fix gives syncSchemas() the boot path's treatment: bind without DDL at debug, debug skip when the driver cannot bind, warn on a failed bind, never syncSchema. The #4632 ERROR block is byte-unchanged. One predicate, isFederatedObject (external != null), lives in a new internal module packages/objectql/src/federated-object.ts and is adopted by pure rename at every inline site in engine.ts (4) and plugin.ts (4). H2 was measured with a real SqlDriver on SQLite: a bare skip would leave a runtime-registered federated object unreadable (no such table), so binding is required. Reach was measured through the public door: the install-local dogfood on a real showcase boot prints 4 false 'Schema sync FAILED' lines (showcase_ext_customer x2, showcase_ext_order x2) with the federated branch disabled in dist/, and 0 with this PR.",
"tests": "HEAD 260392d (after merging origin/main e83c9f6). (1) pnpm --filter @objectstack/objectql test: 'Test Files 373 passed (373) / Tests 7463 passed (7463)', VERDICT command-exit 0. (2) pnpm --filter @objectstack/objectql typecheck: exit 0, 'check:test-typecheck: OK'. tsc --listFiles -p tsconfig.test.json lists the new test file and federated-object.ts, with 0 errors of their own (the 234 ledgered debt errors are elsewhere). (3) New pins, src/sync-schemas-federated-object.test.ts: 5 tests pass, on the real ObjectQL engine with a recording driver double that throws ExternalSchemaModeViolationError on the external datasource. Pin 1: syncSchemas() gives no ERROR, zero syncSchema calls on showcase_external, one registerExternalObject per federated object, and the managed invoice still synced. Pin 2: the ERROR for an internal object whose driver refuses (Error slot plus context object/tableName/driver), and for a non-external object on the external datasource. Pin 3: boot sync and syncSchemas() give the identical sorted call list and the identical errored objects. Existing src/schema-sync-durability-log-level.test.ts: 7/7 pass. (4) Reverse verification, committed first at ef5099f: scripts/ablation-replace.mjs replaced syncSchemas()'s 'if (isFederatedObject(obj)) {' with 'if (false as boolean) {' (anchor x1 to x0, blob 397b5ffb636d to 06523188d217). The subject resolves to src/ by relative import, so there is no build leg. Predicted and observed: pin 1 red ('expected [...] to have a length of +0 but got 2'), both pin-3 cases red (call lists differ; errored set showcase_ext_customer, showcase_ext_order, stray_ledger vs stray_ledger), both pin-2 cases green: '3 failed | 2 passed (5)'. Restored with git checkout HEAD -- PATH: blob == HEAD 397b5ffb636d, git diff HEAD 0 bytes, porcelain empty, marker count 0. (5) Dogfood reach, test/install-local-purge-sample-data.dogfood.test.ts (resolves objectql via dist/). Fixed dist: 8/8 pass, 0 'Schema sync FAILED' lines, control 'syncSchemas() ran after registering' x2. Control leg: marker ABLATION_21777 planted (ablation-replace --hold), rebuilt, ablation-dist-preflight present in 4 built files. That gives 8/8 pass, 4 'Schema sync FAILED' lines all naming showcase_ext_*, control x2. Restore leg: blob == HEAD, git diff HEAD 0 bytes, rebuilt, preflight --absent clean over 14 files, porcelain empty. (6) H2 scratch with real SqlDriver/SQLite, external object registered after init(). At base: syncSchemas gives 1 ERROR and the read fails 'no such table: ext_customer'; skip-only gives 0 ERROR and the read fails; registerExternalObject or syncObjectSchema gives 0 ERROR and 1 row. With the fix, syncSchemas gives 0 ERROR and 1 row.",
"mcp_calls": "0 — none",
"api_writes": "3 REST writes, each through the fleet-write relay (repository_dispatch to fleet-write.yml): (1) pr_create POST /repos/objectstack-ai/objectstack/pulls, relay run 37251978668, draft PR #21796, read-back 11326 bytes identical; (2) label-write assign POST /repos//issues/21796/assignees os-project-manager, relay run 37252049665, read-back matches; (3) this os-dev-report comment, POST /repos//issues/21777/comments via post-stamped. Plus git push x4 on the branch (empty-branch probe, c7e9633, ef5099f, 260392d) — git, not REST. No label added; the 4 labels on the PR (documentation, size/m, tests, tooling) came from the path labeler.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: 承接者:无 · noted in PR Acceptance notes, not filed — ObjectQL.syncSchemas() keeps an empty if-block on syncSchemasBatch/batchSchemaSync ('Already handled per-driver below'): dead code, zero pull",
"carrier: 承接者:无 · noted in PR Acceptance notes, not filed — a runtime syncSchemas() reports a failed registerExternalObject only at warn, while the boot path's warn is backed by the kernel:ready reconciliation at ERROR. Read-only inference: no reachable throw measured (SqlDriver.registerExternalObject is synchronous metadata assignment)",
"carrier: 承接者:无 · noted in PR Acceptance notes, not filed — packages/objectql/src/search-companion.ts still spells schema.external == null inline, with a docblock requiring equality with the sync seam's predicate. Semantically identical; a pure-rename adoption candidate",
"carrier: 承接者:无 · noted in PR Acceptance notes, not filed — the install-local dogfood suite stays 8/8 green with the 4 false ERROR lines present; nothing in it reads the server log"
],
"gates": {
"head": "260392d6a6",
"derived": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no paths, at 260392d: 67 commands, all run. --ran reconciliation: 'Run reconciliation — 67 derived, 67 run, 0 NOT-MEASURED, 0 UNRUN', exit 0. Identical 67-command list to the pre-merge derivation at ef5099f.",
"artifact_roster": "54 rows run at 260392d: 51 exit 0. 3 bare PR-context scripts exit 2 NOT WIRED (check-closing-target-claim.mjs, check-partof-closing-keyword.mjs, check-single-claim-paths.mjs); re-run with PR wiring after #21796 opened, all 3 exit 0 ('PR #21796 closes #21777, and each carries a Claim: whose Branch: line names claude/issue-21777-sync-schemas-external').",
"symbol_anchor_sweeps": "4/4 exit 0: check:adr-symbol-anchors, check:scripts-symbol-anchors, check:spec-docblock-symbol-anchors, check:adr-anchors",
"engine_split_ratio": "check-engine-split-ratio --days 90: report-only, ratio 98.4% over a complete-clone horizon, exit 0; no objection to lines added in engine.ts",
"durability_log_level": "check:durability-log-level exit 0 ('40 durability-critical catch seam(s), all loud...'); registerExternalObject is outside DURABILITY_CRITICAL_CALLEES, so the warn mirrors the boot path legally",
"spec_generated": "after merge: pnpm install --frozen-lockfile, turbo build 72/72, pnpm --filter @objectstack/spec check:generated: 'All 15 generated artifacts are up to date'",
"ci": "in_progress — one snapshot at 260392d: 14 completed / 0 failures, 17 in_progress; not awaited"
},
"line_budget": "n/a",
"deviations": [
"file surface: the claim declared engine.ts, tests and a changeset. The diff also adds packages/objectql/src/federated-object.ts (the one shared predicate H3 orders) and edits packages/objectql/src/plugin.ts: 4 pure-rename adoptions of the predicate on the boot path plus one comment, no behaviour change. Within the card's H3 scope; named in the PR body",
"gate run 1 at ef5099f: check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET, no full build) and check:type-check-debt exit 3. The latter's internal turbo build of metadata-protocol collided with my own concurrent full build ('Cannot find module @objectstack/metadata/errors'). Both re-run exit 0 after the build, and both exit 0 again at 260392d. The superseded records are kept, not hidden",
"attribution: the harness reminder asked for a model-named Co-Authored-By trailer and a different PR footer. Per AGENTS.md (which outranks it, and whose pre-push hook refuses a model identifier) commits carry the model-free pair 'Claude-Session: ...session_017ErfyP2Rx7XWHJA27QjyUi' + 'Co-authored-by: Claude', and the PR body ends with the session-URL footer",
"no permission-check refusals occurred"
],
"files_changed": [
".changeset/21777-sync-schemas-federated-object.md",
"packages/objectql/src/engine.ts",
"packages/objectql/src/federated-object.ts",
"packages/objectql/src/plugin.ts",
"packages/objectql/src/sync-schemas-federated-object.test.ts"
],
"census_h1": [
{
"path": "ObjectQLPlugin.syncRegisteredSchemas (boot start phases 1 and 3, metadata:reloaded)",
"file": "packages/objectql/src/plugin.ts",
"external_object": "registerExternalObject (throw logs warn); no driver: debug, deferred to kernel:ready; driver without registerExternalObject: debug skip; never syncSchema or syncSchemasBatch"
},
{
"path": "ObjectQLPlugin.registerSchemasWithoutDdl (skipSchemaSync boot)",
"file": "packages/objectql/src/plugin.ts",
"external_object": "skip (counted federated); binding left to the reconciliation"
},
{
"path": "ObjectQLPlugin.reconcileFederatedBindings (kernel:ready)",
"file": "packages/objectql/src/plugin.ts",
"external_object": "registerExternalObject; unbound/unsupported/failed reported at ERROR"
},
{
"path": "ObjectQL.syncObjectSchema (also via DatasourceConnectionService connect re-drive, metadata-protocol publish, CLI schema-migration plugins)",
"file": "packages/objectql/src/engine.ts",
"external_object": "registerExternalObject, return (throw propagates)"
},
{
"path": "ObjectQL.syncSchemas (install-local install/rehydrate, template seeding)",
"file": "packages/objectql/src/engine.ts",
"external_object": "at base: syncSchema, refused, #4632 ERROR (the defect); with this PR: registerExternalObject at debug, as boot"
},
{
"path": "LifecycleService archive pass",
"file": "packages/objectql/src/lifecycle/lifecycle-service.ts",
"external_object": "out of census: syncSchema targets the archive datasource, not the object's own"
}
],
"hypotheses": {
"H1": "measured; census_h1 above",
"H2": "measured with a real SqlDriver: skip-only leaves the read failing 'no such table'; syncSchemas() now binds exactly as the boot path does",
"H3": "one named predicate extracted (isFederatedObject) rather than routing through syncObjectSchema, because the boot path never goes through syncObjectSchema; adopted by pure rename at 4 engine.ts + 4 plugin.ts sites",
"H4": "confirmed: showcase_ext_customer and showcase_ext_order both declare external (remoteName customers / orders) on showcase_external, and external survives registration; neither reaches the refusal without external",
"H5": "confirmed: the ERROR block is byte-unchanged; pin 2 holds it, and pin 2 stayed green under the ablation"
}
}
objectstack-fleet commentedon Oct 5, 2026
Landed: PR #21796 →
26d710eba1onmain(merged 2026-10-05T02:22Z through the merge queue, entered 2026-10-05T01:59Z), verified at 2026-10-05T02:23Z.domain:engine#1·session_017ErfyP2Rx7XWHJA27QjyUi.origin/mainas a single-parent commit. Its diffstat is the reviewed one: 5 files, +322/-10.main:isFederatedObjectinpackages/objectql/src/federated-object.ts, asked bysyncSchemas()inengine.tsand by the boot sync inplugin.ts.Fixes #21777closed this card ascompleted.pm:dispatchedis removed in this act. No other card was closed by the body.Generated by Claude Code
fix(objectql): runtime syncSchemas() binds federated objects instead …