Repository navigation
fix(objectql): a federated object whose datasource the connect policy denied is reported at info, not in the wrong-table ERROR - #25117
Conversation
Claude-Session: https://claude.ai/code/session_016cxs5HWHRyhQhA9EaXmnWy Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016cxs5HWHRyhQhA9EaXmnWy Co-authored-by: Claude <noreply@anthropic.com>
…derated-report-migrate-run
…derated-report-migrate-run
Claude-Session: https://claude.ai/code/session_016cxs5HWHRyhQhA9EaXmnWy Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 6 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 18 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 659686d5cae79f8ae768a95135b528a3942c05a7 && git checkout 659686d5cae79f8ae768a95135b528a3942c05a7
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin f2b6cf230b4cddd795b854b044bbcd95e37b6f55 b9f2cfec12f2bb83a85549c313557c95bade8887 && git checkout -B drift-repro f2b6cf230b4cddd795b854b044bbcd95e37b6f55 && git merge --no-ff b9f2cfec12f2bb83a85549c313557c95bade8887
node scripts/docs-audit/affected-docs.mjs --json f2b6cf230b4cddd795b854b044bbcd95e37b6f55
|
Contract reviewServed-tier: Scope: the net diff against the merge base (3 files, +258/−1):
Read with them:
① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
席位核对 ·
|
| Item | Reading |
|---|---|
| Shape | Draft PR → main. The body opens Fixes #25079. 3 files, +258/−1. Not governed: check-governed-merges matched 0 of 3 paths. |
| Scope | An unbound federated object whose datasource the connect policy denied (listUnavailableDatasources() kind blocked) is reported, on every composition, in one info line. The line names the objects and the datasource, and says reads are refused with DatasourceUnavailableError. It is no longer in the ERROR that claimed its reads resolve to the wrong table. |
| Seat's own read | The ERROR is word for word what it was, for an undeclared datasource, a failed connect, an unsupported driver and a registration that threw, and its counts exclude the denied objects. The info line's claim is what the engine does (getDriver refuses with DatasourceUnavailableError). No composition signal is read, so a serving boot and a migrate run are judged alike. |
| Review | TIER_DEFAULT. Record 6317969425 is PASS on this head. |
| Declaration | One changeset, @objectstack/objectql patch, with Clause-②: no (log text and level only: …) and Metadata-protocol: none (…) at line starts, as on the PR body. |
| Cross-lane | None. packages/runtime's federated-boot-binding.test.ts (domain:cli) did not move and stays green. |
| Objections | None from domain:devx (the filer) or the maintainer on #25079 to the re-declaration, at this read. |
| Gates | Dev at b9f2cfec1: 67 derived, 67 run, all exit 0. The new pins pass 11/11. In the ablation the 3 blocked and mixed cases went red and the 8 controls stayed green; restored to HEAD. objectql passed 8631 tests after the last main merge; runtime 6794 passed; core test:repo 82; full turbo build 77/77. Live os migrate apply --yes on the stock showcase: before, the denial line and then the ERROR; after, the denial line and the info line, 0 ERROR lines, exit 0. |
| CI | At this read on b9f2cfec12: ci-failure GREEN, all 41 check-runs completed, none failed. git merge-tree against today's origin/main (edcc8ceae6) is clean. |
Disposition:
open_questions: none. The one fork was settled by the seat's re-declaration (C).deviations: all accepted:- the
Metadata-protocol: noneline (feat(gates): the changeset level follows the metadata protocol —Metadata-protocol:line, level axis, console refresh at patch, release notes by reader action (ruling A) #25114's new rule); - no cross-lane file;
- the runtime suite measured before the last two
mainmerges, with objectql re-run after the one that moved its closure; - the session-URL PR footer and the seat-held subscription;
- Check Changeset's PR-body half left to CI.
- the
out_of_scope_findings: thecreateHonoApp({ kernel })/ no-http.serverobservation is why option A was refused. Nothing reads it today, so it is noted, not filed.
Landing: ordinary queue (pr_ready + automerge_enable through the relay). Fixes #25079 then closes the card.
Generated by Claude Code
Fixes #25079
Clause-②: no (log text and level only: no response, status, outcome, boot verdict or export moves)
Metadata-protocol: none (a boot log line's level and text; nothing a metadata author writes changes)
What changed
ObjectQLPlugin.reconcileFederatedBindings(packages/objectql/src/plugin.ts, the report only) reads the datasource layer's recorded verdict back through the engine (this.ql.listUnavailableDatasources()). An unbound federated object whose datasource is recorded askind: 'blocked', meaning the connect policy denied it on purpose, is now reported in ONEinfoline. The line names the objects and their datasource, and says every read against them is refused withDatasourceUnavailableErroruntil the policy allows that datasource. Those objects are no longer counted in the ERROR.Unchanged, at
error, word for word, on every composition:kind: 'failed');registerExternalObject;On a boot with both, the info line covers the denied objects and the ERROR covers the rest, with its counts excluding the denied ones. No binding, connect policy, read result or export changes. The #9285 registry-read seam is untouched.
Why
On the stock showcase,
os migrate apply --yesdeniesshowcase_external(schemaMode: 'external') on purpose, under the CLI's managed-only policy. The reconciliation then printed an ERROR saying the federated objects "keep their REST routes and keep rendering in the UI, while every read … resolves to a table named after the OBJECT". For a policy-denied datasource that consequence is false on EVERY composition, because the engine refuses those reads withDatasourceUnavailableError(engine.ts, theunavailableDatasourcesbranch ofgetDriver). Under the AGENTS.md degradation-log-level rule, a deliberate denial whose reads refuse loudly is a functional degradation:info, and named rather than silent, which keeps #7737's ruling.The scope is the seat's re-declaration 6315166970, option C of the dev's
needs_decision6314587078. The composition clause of claim 6314457843 is dropped, because no faithful "serves nothing" signal exists: "nohttp.server" misreads the documentedcreateHonoApp({ kernel })embed. The condition is the recorded verdict alone, so no new signal is read and nothing outsidepackages/objectqlchanges.Pins
New file
packages/objectql/src/federated-binding-policy-denied-report.test.ts, 11 cases:blocked: exactly one info line naming the denial, the datasource and both objects, and zero ERROR, on a serving-shaped and a migrate-shaped context alike;failed, unsupported driver, registration threw;2 federated …covering the undeclared and failed ones, excluding the denied one.packages/runtime/src/federated-boot-binding.test.ts(domain:cli) is NOT moved and stays green: its datasource is undeclared.Verification record
Base
2e242bb0a9for the census; built onba244f1b4, then mergedorigin/maintwice. The final head isb9f2cfec1(merge basef2b6cf230).scripts/ablation-replace.mjs,(blocked.has(datasource) ? denied : unbound).push(replaced byunbound.push(): anchor 1 → 0, blobaea19b4003ed→45e012d1ed12. Result: 3 failed | 8 passed (11). The twoblockedcases and the mixed case went red; all 8 controls stayed green. Restored: blob == HEAD (aea19b4003ed) andgit diff HEADempty. The test imports./plugin.jsfrom source, so no dist leg is involved.tsconfig.test.jsonprogram lists the new file;check:test-typecheckOK, no new debt). Full suite at55a4c8b9f, after the merge that brought fix(objectql)!: under strictReadonlyWrites, a write whose value a stored expression replaces is refused, and nothing is written #25086's objectql change: 459/459 files, 8631/8631 tests. The earlier run at5cf4a4529was 459/459, 8621/8621.5cf4a4529against anobjectql/distcarrying this change. The diff touches no runtime file. Of the two merges, only fix(objectql)!: under strictReadonlyWrites, a write whose value a stored expression replaces is refused, and nothing is written #25086 (objectqlengine.ts, strict read-only writes) moved a package in runtime's closure, and objectql's own suite was rerun after it.test:repo: 6/6 files, 82/82 tests.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(no paths) derived 67 lines. Every line ran, each exit code captured before any pipe. At the final headb9f2cfec1: 67/67 exit 0, and--ranreported67 derived famil(ies) accounted for — 67 run, 0 NOT-MEASURED (a DERIVED zero — all 67 recorded an exit code and none of them is 3). The same held at55a4c8b9f. An earlier pass at5cf4a4529had three non-zero lines, none a gate verdict:check:dual-build-cjs-loadsexit 3 (no full build yet), andcheck:query-options-erasure/check:type-check-debtexit 124 (my own 240 s per-command cap). All three exit 0 after the full build. Full buildpnpm exec turbo run build --concurrency=2: 77/77 at both merged heads.examples/app-showcase, fresh file DB, same tree:os migrate apply --yesexit 0, thenINFO datasource 'showcase_external': connect denied by policy (…), thenERROR 2 federated (external) object(s) are NOT bound to their remote table, yet stay registered and served: they keep their REST routes and keep rendering in the UI, …;INFO 2 federated (external) object(s) left unbound because the connect policy denied their datasource: showcase_ext_customer -> datasource 'showcase_external', showcase_ext_order -> datasource 'showcase_external'. Every read against them is refused (DatasourceUnavailableError) …, and 0ERRORlines; 70 tables created. The after-run was repeated once objectql's dist was rebuilt from the restored source: same result.Acceptance notes
Metadata-protocol:line follows feat(gates): the changeset level follows the metadata protocol —Metadata-protocol:line, level axis, console refresh at patch, release notes by reader action (ruling A) #25114, which landed after the claim; its value isnone, so the level stayspatch.os migrate plan/applyoffer--allow-destructivefor a unique index that duplicates BLOCK, and the re-run ends PARTIAL — the driver's apply-limit declaration does not cover a blockedcreate_index#25031, Boot drift lines on a 17.x database before the ownership ceremony prescribeos migrate apply --allow-destructivefor eachorganization_idcolumn, a run the drop gate refuses #24956.Generated by Claude Code