Skip to content

fix(objectql,runtime): install datasourceMapping before the first schema sync, so a mapped boot keeps one store (#23649) - #23694

Merged
objectstack-fleet[bot] merged 8 commits into
mainfrom
claude/issue-23649-datasource-mapping-before-sync
Oct 15, 2026
Merged

objectstack-fleet[bot] merged 8 commits into
mainfrom
claude/issue-23649-datasource-mapping-before-sync

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #23649

Clause-②: yes

What was wrong

A host config declaring datasourceMapping: [{ default: true, datasource: 'primary' }] over a declared SQLite primary booted to Server is ready and then answered no such table on every platform read. AppPlugin.start() installed the rules (ql.setDatasourceMapping) after ObjectQLPlugin.start() had schema-synced every registered object onto the host's default store, and after the auth plugin had written the Default Organization there. From that moment the engine routed every unbound object to primary (step 2 of resolveDatasourceBinding), and primary's schema had never been synced.

The same late install had a second form. The connect gate (ADR-0062 D2 (d)) counted only the app's own objects. A rule that routes only platform objects (objectPattern: 'sys_*', the spec's own example shape) therefore never connected its datasource at all. Every platform read then failed with "mapped for object ... is not registered".

Honour or refuse: measured first

Triage left the choice open, with one guard: if honouring the mapping changes which store a config that boots correctly today resolves to, stop and return the fork. Honouring changes nothing for any such config I could build, so this PR honours the mapping. The readings are below.

Every boot used the built CLI (bin/run.js) with NODE_ENV unset (production), OS_AUTH_SECRET set and OS_CLOUD_URL=off. Each store was opened read-only after the process exited. "Before" means origin/main at 57994c311 for the host-config rows. For the rows marked (a), it means this branch with the fix's one subscription line removed and packages/runtime rebuilt, which makes the boot behave exactly as before the change. "After" means this branch at 4c64e2aed.

Boots that work today. All of them are unchanged:

shape before after
CONTROL: no mapping, OS_DATABASE_URL=file:ctl.db ready, 0 errors; ctl.db 72 tables, 1 organization identical
default: true to the host's own default ready, 0 errors; ctl.db 72 tables, 1 organization identical
default: true to primary, with OS_DATABASE_URL set to primary's own file ready, 0 errors; one file, 72 tables, 1 organization identical
os start on the config-declared default (default: true to primary, no URL), which is the shape the shared resolver honours (a) ready, 0 errors; ds-primary.db 72 tables, 1 organization identical
M9: a stack plugin registers a SQL driver.* service in init(), plus a declared archive with autoConnect, no mapping, no URL ready, 0 errors; default driver com.objectstack.driver.sql; plugin store 72 tables, 1 organization; archive 0 tables identical, same default driver
objectPattern: 'fx_*' to primary (the app's own object only), URL set ready, 0 errors; fx_task rows served from primary; ctl.db also held an empty fx_task table from the first sync ready, 0 errors; fx_task on primary only, so ctl.db has 71 tables
M5: default: true to primary, production, no URL refused by the no-storage guard identical

The one difference among these is that empty fx_task copy: the first sync no longer creates it in a store the object never routes to. No row moves. The rules were already in force for every write once start() had run, and app seeds run after that point.

Boots that are broken today:

shape before after
M7: default: true to primary, OS_DATABASE_URL=file:ctl.db ready, then 61 DATABASE_ERROR ... no such table; ctl.db 72 tables and the organization, primary 13 tables and no organization ready, 0 errors; primary 71 tables and 1 organization; ctl.db holds sys_packages only (see the acceptance notes)
M8: the same config with --dev ready, then 63 DATABASE_ERROR; primary 13 tables, no organization ready, 0 errors; primary 71 tables and 1 organization
os start on the same config with OS_DATABASE_URL=file:ctl.db (a) ready, then 61 DATABASE_ERROR; split as in M7 ready, 0 errors; primary 71 tables and 1 organization
objectPattern: 'sys_*' to primary, URL set ready, then 36 "is not registered"; primary never connected ready, 0 errors; primary 70 tables and 1 organization; fx_task stays in ctl.db
M9 with default: true to archive ready, then 61 DATABASE_ERROR; split ready, 0 errors; archive 71 tables and 1 organization; the default driver is still the plugin's
objectPattern: 'sys_*' to a declared postgres that refuses connections (a) ready, then 38 "is not registered" refused at boot: [AppPlugin] declared-datasource auto-connect failed for app ...: datasource 'primary': connect failed — connect ECONNREFUSED ... (70 object(s) are routed to it by a datasourceMapping rule ...)

The last row is the one boot this change refuses that used to print a banner. The published contract already says so: content/docs/data-modeling/external-datasources.mdx says "If a datasourceMapping rule routes an object to a datasource that cannot be connected, the boot fails with the connect error". The published skills/objectstack-data/rules/datasources.md says the same ("A rule pointing at a datasource that cannot be connected fails the boot"), and so does ADR-0062's #4462 amendment ("a declared-auto failure is fatal"). The implementation counted only the app's objects, so it never reached that refusal for platform objects. The seat ruled this refusal is the implementation pulled back to the published declaration (review 6196599954, answer A), so it is not a narrowing. The declaration's yes is owed by the widening below, not by this refusal.

What changed

Public surface (why the declaration reads yes). @objectstack/objectql gains one entry export, OBJECTQL_DRIVERS_READY_HOOK, and ObjectQLPlugin.start() triggers one new kernel event, objectql:drivers-ready, which any plugin can subscribe to. The changeset bumps @objectstack/objectql minor for it; @objectstack/runtime stays patch.

  • packages/objectql/src/plugin.ts. ObjectQLPlugin.start() triggers objectql:drivers-ready (exported as OBJECTQL_DRIVERS_READY_HOOK) once per boot, with the engine as its argument. It fires after driver.* adoption and ObjectQL.init(), and before the first installRegisteredSchemas, the sys_metadata hydration and any read or write. A throwing handler propagates and fails the boot. The call site spells the name as the literal 'objectql:drivers-ready', because the settings bind-window guard derives the hooks fired before the settings bind from their call sites and reads only a literal. The event is such a hook, so it is pinned in that guard's PRE_BIND_HOOKS with its fire site (scripts/check-settings-bind-window.mjs, the guard's own prescribed remedy). Its one handler, AppPlugin's, reads no setting. The runtime pin subscribes through the exported constant, so it goes red if the literal and the constant ever differ.
  • packages/runtime/src/app-plugin.ts. AppPlugin.init() subscribes to that event. The handler, honourDatasourceMappingBeforeSchemaSync, installs the rules. It then calls the same connectDeclared that start() uses, for every declared datasource the rules route an already-registered object to. That set is asked of the engine's own matcher (resolveMappedObjects over ql.registry.getAllObjects()), platform objects included. The fail-fast verdict and the error line are the same as start()'s. start() installs the rules only when nothing announced the pre-sync moment, for example a declaration-only boot that suppresses the engine plugin's start, or a mock context with no hook bus.
  • The connect still happens after the engine has adopted its driver.* services. That is the readings' M9 concern: the engine makes its first registered driver the default, so an init()-time connect would have taken the default slot from a stack plugin's driver. The M9 rows above show the default driver unchanged.

Landing point: the boot order, as triage expected. The announcement lives in packages/objectql, and the install and connect live in the runtime AppPlugin, cross-lane on the claim's declared surface. resolveDatasourceBinding's order is unchanged, because the defect was when the rules arrived, not the order.

Tests

  • packages/runtime/src/datasource-mapping-before-schema-sync.test.ts (new, in-process): the served host composition with a real SQL default driver, the engine plugin, a fixture platform plugin that registers an object the app does not declare and writes a row in start() (the Default Organization's slot), the app, and the datasource-admin plugin with the real driver factory. All stores are :memory:. It checks three legs: default: true (the table and the boot row are on primary, and neither is on the default store), sys_* (primary is connected and holds the platform object, and the app object stays on the default store), and the no-mapping CONTROL (everything on the default store, primary metadata-only). Every leg also asserts that the default driver is the DriverPlugin's. Result: 3 passed.
  • packages/cli/test/serve-datasource-mapping-before-sync.integration.test.ts (new, integration tier, run with --project integration): the M7 shape at the public door, two production boots of the built CLI. Mapped: the banner, no "no such table" and no "is not registered", primary holds sys_organization (1 row), sys_metadata, sys_user and fx_task, and ctl.db has no sys_organization and no sys_metadata. CONTROL: everything in ctl.db, and ds-primary.db is never created. Result: 2 passed (17.6 s, so it declares a test-budget of 30).
  • Affected-package suites at 4c64e2aed: @objectstack/runtime 389 files and 5862 tests passed (19 skipped), and @objectstack/objectql 422 files and 8118 tests passed.
  • After merging origin/main (09dd53719), at 18baa1fce, with the CLI closure rebuilt (61 turbo tasks): pnpm --filter @objectstack/objectql run typecheck, pnpm --filter @objectstack/runtime run typecheck and pnpm --filter @objectstack/cli run typecheck each exit 0; runtime pin 3 passed; CLI pin (--project integration) 2 passed. The probe on the merged build reads the same as above for M7, CONTROL, os start on the config-declared default, sys_* and the unreachable sys_* target. The final commit 4b45f9957 adds only the child-env census line (see Gates), which neither the typechecks nor the pins read.
  • Round 2, at 700a1bf30 (origin/main merged again at f77ba411e; fix(objectql): keep the metadata service's copy of a runtime-authored object current after boot (MCP stdio exposure gate) #23687 had changed packages/objectql/src/plugin.ts in its metadata-event bridge, a region disjoint from the start-order lines this PR edits): objectql rebuilt, and the dist carries the literal fire site once. pnpm --filter @objectstack/objectql run typecheck and pnpm --filter @objectstack/runtime run typecheck exit 0. Runtime pin 3 passed. CLI pin (--project integration) 2 passed. packages/plugins/plugin-auth/src/auth-settings-ordering.pin.test.ts, which names the edited guard, passed. Suites: @objectstack/objectql 425 files and 8134 tests passed, @objectstack/runtime 389 files and 5866 tests passed (19 skipped).

Ablation (negative control). I committed the fix first, then removed the one subscription line in AppPlugin.init() (ctx.hook(OBJECTQL_DRIVERS_READY_HOOK, ...)) with scripts/ablation-replace.mjs (anchor 1 to 0, blob changed) and rebuilt packages/runtime. scripts/ablation-dist-preflight.mjs --absent showed the marker absent from all 6 built files. Results with the line removed:

  • runtime pin: 2 failed and 1 passed (CONTROL). The failures were expected [ 'fx_task' ] to include 'sys_fx_ledger' and a datasource only platform objects route to was never connected.
  • CLI pin: 1 failed and 1 passed (CONTROL). The failure was a platform read hit an unsynced datasource ... not to contain 'no such table'.

The tool restored the line (blob equals HEAD, git diff HEAD empty, git status --porcelain empty). I then rebuilt, the preflight showed the marker present in dist/index.js, and both pins passed again.

Gates

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran at 700a1bf30, every command run on that tree with its exit code recorded: 87 derived, 87 run, 0 NOT MEASURED, and all 87 exit 0. In the first pass, check:dual-build-cjs-loads exited 3 (PREREQUISITE NOT MET, unbuilt packages); its re-run after the list measured and passed. CI on 700a1bf30: 40 check-runs, 34 success, 6 skipped, none failed; Lint & Repo Gates, TypeScript Type Check, Test Core, Build Core and Governed Surface Queue Guard are all green.

The red this round fixed. CI on 4b45f9957 and 3a70801fc failed one gate, Settings bind-window guard (pnpm check:settings-bind-window). It refused the fire site ctx.trigger(OBJECTQL_DRIVERS_READY_HOOK, this.ql) because it cannot name a hook given through a constant. Locally the gate exits 1 on 3a70801fc and 0 on origin/main f77ba411e, so the red was this branch's own. Round 1's local derivation did not name that gate: it was not among the 86 families. It derives now because its script is edited. The fix is the literal fire site plus the PRE_BIND_HOOKS row above. The gate now reads 9 pre-bind hooks fired, all 9 pinned.

Census and pin edits in gate scripts, both forced by this change and both the gate's own prescribed remedy: scripts/check-cli-test-child-env.mjs names the new production-posture bin/run.js spawner (eight files to nine; its self-test passes 152 cases), and scripts/check-settings-bind-window.mjs pins objectql:drivers-ready. Families CI runs beyond this list are read from the check-runs above.

Acceptance notes

  • sys_packages stays on the default driver. The package registry's table is not an object, and service-package deliberately creates and reads it on the engine's default driver (package-table.ts says why). Under a default: true rule with a separate URL store, that table is the one thing left in the URL store (M7 after: ctl.db holds sys_packages only). It is read and written consistently there. Noted, not filed. Carrier: none.
  • ADR-0062's Phase 1 implementation note says declared datasources are auto-connected from AppPlugin.start(). Mapping targets now connect at objectql:drivers-ready, which is earlier and still AppPlugin's code. The ADR's decision text (D2 (d): "a datasource a mapping rule routes at least one registered object to is auto-connected at boot") is what this implements. The note is left alone because docs/adr/** is a governed surface. Carrier: none.
  • objectql:drivers-ready is not in IPluginLifecycleEvents. Custom names are legal on the bus, and the registry is in packages/spec, which is outside this claim. Carrier: none.
  • Where an unopenable-SQLite hang surfaces now. A declared sqlite datasource whose file cannot be created (I measured a path under /proc) hangs its connect until the plugin start timeout. Before this change, a mapping-routed one timed out as the app plugin's start (30 s). Now it times out as the engine plugin's start (120 s), because the connect moved into that start. Neither message names the datasource. The hang predates this change. Filed follow-up: runtime: a declared sqlite datasource whose file cannot be created never settles its connect, so the boot is refused only by a plugin start timeout (30 s, 120 s after PR #23694) that names neither the datasource, the path nor the open error #23696.

Body refreshed 2026-10-15T18:01Z by domain:engine seat 1 from the dev's round-2 text (report 6198789360).

@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation tests tooling labels Oct 15, 2026
@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/objectql, @objectstack/runtime, touching 5 documentable anchor(s). ⚠️ 1 changed file(s) yielded no anchor (packages/objectql/src/index.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

9 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/kernel/services-checklist.mdx (via AppPlugin (symbol, a top-level class))
  • content/docs/permissions/authentication.mdx (via AppPlugin (symbol, a top-level class))
  • content/docs/permissions/capabilities.mdx (via AppPlugin (symbol, a top-level class))
  • content/docs/permissions/system-context.mdx (via AppPlugin (symbol, a top-level class))
  • content/docs/plugins/index.mdx (via AppPlugin (symbol, a top-level class))
  • content/docs/plugins/packages.mdx (via AppPlugin (symbol, a top-level class))
  • content/docs/protocol/kernel/index.mdx (via AppPlugin (symbol, a top-level class))
  • content/docs/protocol/kernel/lifecycle.mdx (via AppPlugin (symbol, a top-level class))
  • content/docs/protocol/kernel/plugin-spec.mdx (via AppPlugin (symbol, a top-level class))

⛔ 3 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v15.mdx (via AppPlugin (symbol, a top-level class))
  • content/docs/releases/v17/17-0.mdx (via AppPlugin (symbol, a top-level class))
  • content/docs/releases/v17/17-5.mdx (via AppPlugin (symbol, a top-level class))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/objectql/src/index.ts) — pages documenting those are invisible to this run
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 35 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f1e21c4f45001dd3c206019359137226197ee659 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from b8d878bf4206f9fa9c06ba6140cbbd225a6eb838 — the merge of head 700a1bf30c344dc31cf5ed668c4e36788347b18b into base f1e21c4f45001dd3c206019359137226197ee659, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin b8d878bf4206f9fa9c06ba6140cbbd225a6eb838 && git checkout b8d878bf4206f9fa9c06ba6140cbbd225a6eb838
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin f1e21c4f45001dd3c206019359137226197ee659 700a1bf30c344dc31cf5ed668c4e36788347b18b && git checkout -B drift-repro f1e21c4f45001dd3c206019359137226197ee659 && git merge --no-ff 700a1bf30c344dc31cf5ed668c4e36788347b18b

node scripts/docs-audit/affected-docs.mjs --json f1e21c4f45001dd3c206019359137226197ee659

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs f1e21c4f45001dd3c206019359137226197ee659 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Seat review, first pass · domain:engine seat 1 · sunhaolin · session_01GP3comALHRcRBixS2TEnLF · 2026-10-15T16:07Z · one patch owed before ACCEPT

Head read: 4b45f9957. The design is accepted: the pre-sync event, its place after driver adoption, and AppPlugin's install-and-connect on it.

Owed: Clause-②: yes.

  • packages/objectql/src/index.ts adds OBJECTQL_DRIVERS_READY_HOOK to @objectstack/objectql's entry exports. ObjectQLPlugin.start() also starts triggering a new kernel event, objectql:drivers-ready, which any plugin can subscribe to.
  • That widens the package's public surface. The rule is "放宽接受集或扩大公开面的卡,不论多小,即条款②" (references/lanes/spec.md). The precedent is PR feat(drivers): ADR-0139 E3 + E4 — the five drivers compile the composed ReadableIds leaf or refuse it with D3's envelope, with the conformance case-set #23656, whose new @objectstack/core export was declared yes.
  • The patch is text only:
    • the PR body's line becomes Clause-②: yes;
    • the changeset's body line becomes Clause-②: yes;
    • @objectstack/objectql moves from patch to minor (a new export and event);
    • @objectstack/runtime stays patch.
  • No code line changes, and the existing gates and pins stand.

The dev's open_questions[0], answered: A. The newly refused boot (a rule routing only platform objects to a datasource that cannot connect) is the implementation pulled back to the published declaration, and the changeset quotes it. For that arm alone it would be no. The yes above is owed by the export, not by this refusal. Keep the changeset's "Refused at boot, as documented" paragraph as it is.

Then: this seat's own review of record at TIER_DEFAULT (the declaration face; reviewFace reads no schema and no governed path here), and ACCEPT. The patch round goes to the dev at the next free dispatch slot.

Already done:


Generated by Claude Code

…tasource-mapping-before-sync

Claude-Session: https://claude.ai/code/session_01GP3comALHRcRBixS2TEnLF
Co-authored-by: Claude <noreply@anthropic.com>
…d kernel event widen the published surface

Claude-Session: https://claude.ai/code/session_01GP3comALHRcRBixS2TEnLF
Co-authored-by: Claude <noreply@anthropic.com>
…in it among the pre-settings-bind hooks

The settings bind-window guard derives the hooks fired before the settings
bind from their call sites and reads only a literal name; it named the new
event as unresolvable. Fired by literal, the event is a pre-bind hook, so it
joins PRE_BIND_HOOKS with its fire site, the gate's own prescribed remedy.

Claude-Session: https://claude.ai/code/session_01GP3comALHRcRBixS2TEnLF
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: TIER_DEFAULT
Head-sha: 700a1bf30c344dc31cf5ed668c4e36788347b18b
Local-runs: none

The lane seat's own review of record. The face is the declaration face: reviewFace reads no published schema and no governed path in this file list, so the review is owed by the Clause-②: yes line alone, at TIER_DEFAULT.

① Derived judgments

  1. The public surface widens by one export and one event. RIGHT, and declared. @objectstack/objectql gains OBJECTQL_DRIVERS_READY_HOOK, and ObjectQLPlugin.start() triggers objectql:drivers-ready once per boot, after driver.* adoption and ObjectQL.init() and before the first schema sync. It is named in the changeset and the PR body.
  2. datasourceMapping is installed before the first schema sync, and every mapped datasource is connected then, platform objects included. RIGHT. This is ADR-0062 D2 (d): a datasource a rule routes a registered object to is auto-connected at boot. The default driver is unchanged because the connect follows driver adoption (the M9 readings). It is pinned, with a negative control, at runtime and at the CLI boot.
  3. One boot that reached ready is now refused. RIGHT, named, and pulled back to the declaration. The case is a rule routing only platform objects to a datasource that cannot connect. The published docs, the skill rule and ADR-0062's datasource: an object mapped to an unreachable datasource silently reads/writes the DEFAULT store — no boot failure, /ready still 200 #4462 amendment all say such a boot fails, so this is the implementation brought up to the contract. The changeset names the FROM → TO and the remedy.
  4. The fire site spells the event as a literal. RIGHT. The settings bind-window guard reads only literal hook names. The subscriber uses the exported constant, and the runtime pin goes red if the two differ. The guard's PRE_BIND_HOOKS gains the event's row, which is the guard's own prescribed remedy: a census row, with no logic, threshold or skip changed. AppPlugin's handler reads no setting, and the guard's handler census is unchanged from main.

② Semver level

@objectstack/objectql is minor (a new export and event) and @objectstack/runtime is patch. Clause-②: yes is in the changeset and the PR body. The dev simulated the level axis with a pull_request payload carrying this body, and it reads clean. Nothing is BREAKING beyond the documented boot refusal; that refusal pulls back to the declaration and narrows no published contract. RIGHT.

③ Boundary flags

Implemented-by: claude/issue-23649-datasource-mapping-before-sync
Reviewed-by: session_01GP3comALHRcRBixS2TEnLF

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · domain:engine seat 1 · session_01GP3comALHRcRBixS2TEnLF · 2026-10-15T18:04Z · ACCEPT (landing waits for every check on the head)

Head: 700a1bf30c344dc31cf5ed668c4e36788347b18b.

Item Reading
Shape PR → main. The first line is Fixes #23649. A closing-keyword scan of the whole body finds one hit, line 1.
Scope 8 files (+665 / −11): packages/objectql/src/{plugin,index}.ts, packages/runtime/src/app-plugin.ts, the runtime and CLI pins, two gate-script census rows, and the changeset. The cross-lane parts are declared: domain:cli on #6024 (6196575850), and domain:spec on #18883 (6196585005, plus the addendum 6198854597). No content/docs/releases/ edit, no governed path, under the 3,000-line threshold. origin/main f77ba411e is merged in.
Clause-② yes, in the changeset and the PR body. The claim's no predates the export; the seat's first pass 6196599954 ruled yes, and the changeset now ships @objectstack/objectql minor.
Contract review The lane seat's own record at TIER_DEFAULT (the declaration face): 6198867878, PASS at this head.
CI Round 2 fixed the first-round red (Settings bind-window guard) at its root: the fire site is now a literal, and the event has its census row. On this head, Lint & Repo Gates, TypeScript Type Check, Test Core 1–6 and Build Core are green. The body edit re-triggered the changeset and claim guards, and landing waits for them.
PR body Refreshed by the seat from the dev's round-2 text.

Disposition:


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 15, 2026 18:11
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 15, 2026 18:11
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 15, 2026
Merged via the queue into main with commit cd86e41 Oct 15, 2026
48 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

2 participants