Skip to content

feat(spec,objectql): transaction 契约收紧第一批 —— opts.require fail-closed 与 owned 信号 (#5696) - #6165

Merged
baozhoutao merged 6 commits into
mainfrom
claude/issue-5696-transaction-contract
Aug 7, 2026
Merged

feat(spec,objectql): transaction 契约收紧第一批 —— opts.require fail-closed 与 owned 信号 (#5696)#6165
baozhoutao merged 6 commits into
mainfrom
claude/issue-5696-transaction-contract

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Fixes #5696

本 PR 是 #5696「契约收紧半边」的第一批,也是 #5351 裁 A 引擎行为 PR 的前序(PR 序:契约先行)。落地 #5696 三点中的第 1 点与第 3 点,并把 transaction 契约 TSDoc 里被实测证伪的那句改写。

第 2 点(跨驱动业务写响亮拒绝)不在本 PR —— 2026-08-06 维护者裁决把它与 #5351 的系统写 carve-out 绑成同批同 PR:单独先落拒绝会「响亮化但不修复」(审计 hook 的 try/catch 把拒绝吃成日志,合规行照丢)。它随 #5351 的引擎行为 PR 一起落。


契约 diff 逐条(给 spec 席确认单用)

packages/spec/src/contracts/objectql-engine.ts:

  1. 新增导出 EngineTransactionOptions(interface,1 个可选成员 require?: boolean)。语义:驱动无 beginTransaction 时,require: true 抛错而非静默降级;undefined/false 保持 ADR-0119 D1 已声明的降级行为,一字未改。刻意只放一个成员 —— 按本文件 header 的 evidence bar,消费者证明需要才扩。
  2. 新增导出 EngineTransactionInfo(interface,1 个必选成员 owned: boolean)。true = 本次调用开启了事务并拥有提交/回滚;false = join 了外层 ambient 事务(ADR-0067 D2),处在降级路径上(那里没有事务可拥有)。
  3. 成员签名变更 —— transaction
    transaction< T >(callback: (trxCtx: any) => Promise< T >, baseContext?: any): Promise< T >
    变为
    transaction< T >(callback: (trxCtx: any, info: EngineTransactionInfo) => Promise< T >, baseContext?: any, opts?: EngineTransactionOptions): Promise< T >
    两处新增都是追加:既有单参数回调、两参数调用点全部不受影响。
    ⚠️ 选型说明(留给 spec 席否决):owned回调第二参数,而不是挂在 trxCtx 上。理由是 trxCtx 会被调用方原样透传成 { context: trxCtx } 一路进 buildDriverOptions,往里塞一个纯诊断字段等于把它送进执行上下文与 driver options;第二参数是纯附加、零污染。
  4. TSDoc 事实性改写。原文:「objects routed elsewhere by setDatasourceMapping are written outside it」。实测不成立 —— 引擎无条件把 ambient 事务句柄穿给目标驱动,语句在错误的连接上执行(ambient 事务句柄跨数据源泄漏:凡在事务中执行的被审计写入,合规审计行全部静默丢失(#5226 的真实根因) #5351 实测真 SQL driver 报 no such table;PR fix(objectql): make transaction() 的两条既声明 caveat 可被观测 (#4619) #5724 用纯 in-memory 双数据源独立复现,收到的是 { __trx: 'primary' })。新文案按实测陈述,并声明随后落地的两条语义:业务写跨驱动响亮拒绝;lifecycle.classaudit/telemetry/event 的系统账本 carve-out(移出事务、在自己的连接上执行、承担孤儿行语义,ambient 事务句柄跨数据源泄漏:凡在事务中执行的被审计写入,合规审计行全部静默丢失(#5226 的真实根因) #5351)。
  5. 段落头注释 ── Transactions (ADR-0119 D1) ──── Transactions (ADR-0119 D1, revised by #5696/#5351) ──

为什么本 PR 不是纯 spec 改动

派发令原定 PR 1 只动 packages/spec。实测下来那样不可交付,两个原因,都指向仓规:

  1. 纯声明会让 @objectstack/objectql typecheck 转红。 实测报错:
    src/engine.ts(6671,9): error TS2416: Property 'transaction' in type 'ObjectQL' is not assignable
      to the same property in base type 'IObjectQLEngine'.
        Target signature provides too few arguments. Expected 2 or more, but got 1.
    
    (ObjectQL implements IObjectQLEngineThe service-lookup any rule misses getService<any>(...) — 80 sites erase the slot contract, 3 of them inside the rule's own scope #4251 B3 刻意留的验证步。)
  2. 声明了不兑现,正是 PD#10 明令禁止的形状。 只声明 opts.require/owned 而引擎不实现,就是「advertise a capability the runtime doesn't deliver」。哪怕只存在到下一个 PR 合入,也不该进 main

所以本 PR 同时带上第 1、3 点的引擎实现(纯追加、默认行为不变),把耦合裁决真正约束的那一点(第 2 点拒绝)完整留给 #5351 的 PR。维护者裁决的硬约束由此完全保持

实现要点

  • packages/objectql/src/transaction-errors.ts(新)—— TransactionUnsupportedError,code: 'ERR_TRANSACTION_UNSUPPORTED'(按 DriverConnectError 的既有惯例用 code 而非 instanceof 跨包识别),已从包根导出。
  • ObjectQL.transaction:join 分支给 { owned: false };降级分支先判 require 再 warn;开启分支给 { owned: true }
  • ScopedContext.transaction(ctx.api.transaction,沙箱 hook/action 体)同步支持 optsowned —— 同一原语的第二份实现不该变成第二种方言。
  • @objectstack/coreEngineWithTransaction 从手抄签名改为 transaction: IObjectQLEngine['transaction']。它自称「Mirrors IObjectQLEngine['transaction']」而实际已开始漂移;ADR-0119 D1 早就为窄宿主接口定了这个写法(窄可以,漂移不行)。

测试

新增 packages/objectql/src/engine-transaction-contract.test.ts(15 例):require 拒绝(抛型/code/datasource/消息含两半修法/回调未运行/一行未写/不再多打 warn)、require 在可事务驱动上无副作用、不传 require 仍降级 + warn-once 的回归钉require: false 不等于 true、owned 三态(开启 true / join false / 降级 false)、单参数回调不受影响、第三参数在场时 baseContext 仍正常穿透、沙箱面三例。

真实输出:

 ✓ src/engine-transaction-contract.test.ts (15 tests)
 Test Files  1 passed (1)
      Tests  15 passed (15)

受影响包全跑(合入 origin/main 36fc938 之后):

packages/spec test:               Test Files  329 passed (329)   Tests  8399 passed (8399)
packages/core test:               Test Files   27 passed (27)    Tests   498 passed (498)
packages/metadata-protocol test:  Test Files   49 passed (49)    Tests   502 passed (502)
packages/objectql test:           Test Files  133 passed (133)   Tests  2195 passed (2195)
packages/runtime test:            Test Files  105 passed (105)   Tests  1506 passed (1506)

typecheck:

packages/spec typecheck: Done
packages/objectql typecheck: Done
packages/runtime typecheck: Done

生成物(AGENTS §10 / .gitattributes os-regen 四步序:build → check:generated → --fix → commit),十道门全绿:

  ✓ check:spec-changes         ✓ check:upgrade-guide     ✓ check:skill-docs
  ✓ check:skill-refs           ✓ check:react-blocks      ✓ check:authorable-surface
  ✓ check:api-surface          ✓ check:docs              ✓ check:strictness-ledger
  ✓ check:test-typecheck

api-surface/contracts.json 的 delta 恰为本 PR 意图的两条(+ EngineTransactionInfo+ EngineTransactionOptions)。合入 main 时 os-regen 驱动把该文件记为 pending,已按规程重生成并由 pre-commit 复核清账。

其它门:

check-nul-bytes: OK (scanned 5900 tracked text file(s); ... no raw ASCII control bytes)
check-engine-double-contract: OK — 73 pinned, 133 in the DEBT ledger, 2 exempt.

反向验证(方向先写死,再运行)

肢 C —— 去掉 require 判定(引擎面与沙箱面各删一处 if (opts?.require === true) throw)。

  • 预测:4 条引擎面拒绝断言 + 1 条沙箱面拒绝断言转红,共 5 红;owned 三例、降级默认回归钉、baseContext 穿透等 10 例保持绿(它们不经过被删的分支)。
  • 实测:完全一致 ——
    × throws TransactionUnsupportedError instead of running the callback
       AssertionError: promise resolved "undefined" instead of rejecting
    × carries the boundary-crossing code, the datasource, and the fix
       AssertionError: expected undefined to be 'ERR_TRANSACTION_UNSUPPORTED'
    × writes nothing — the refusal is not a rollback, it is a non-start
       AssertionError: expected [ { object: 'thing', …(2) } ] to have a length of +0 but got 1
    × is silent about the degrade it refused — the throw IS the report
       AssertionError: expected [ { level: 'warn', …(2) } ] to have a length of +0 but got 1
    × refuses under require: true, with the same error
       AssertionError: promise resolved "undefined" instead of rejecting
     Tests  5 failed | 10 passed (15)
    
  • 匹配:是(红,常规方向)。已还原,还原后 15/15 绿。

其余两肢(去掉同源校验、关掉系统写 carve-out)作用于 #5351 的引擎行为 PR,在那边做。

依据

ADR-0119 D1(transaction 契约与两条 caveat;旧文里的「ADR-0118 D1/D4」按该 ADR 自己的改号说明即本记录)、ADR-0119 D4(batchData fail-closed 先例)、ADR-0067 D2(join 语义)、ADR-0057 §3.6(lifecycle 分流)、#4619(母单)、#5724(可发现性半边)、#5351(2026-08-06 裁 A 与耦合硬约束)。

⚠️ 本 PR 不含 ADR 修订文案 —— 孤儿行语义与 P1 边界决定属于 #5351 引擎行为 PR 的落点,一份修订一处写,避免两个 PR 各改同一段 ADR 撞车。


Generated by Claude Code

claude added 3 commits August 7, 2026 04:11
…losed and an `owned` signal (#5696)

`IObjectQLEngine.transaction` declared two degradations as part of its meaning
(ADR-0119 D1): default-driver-only routing, and a silent fallback to "no
transaction, no rollback" on a driver without `beginTransaction`. #4619 made
both audible (PR #5724). This lands the first two of #5696's three tightenings,
each opt-in, with every existing caller's behaviour unchanged:

- `opts.require: true` throws `TransactionUnsupportedError` instead of
  degrading — refused BEFORE the callback runs, so nothing is written when the
  caller finds out. Generalizes `batchData`'s atomic gate (ADR-0119 D4).
- the callback's second argument carries `owned`: true when this call opened
  the transaction, false when it JOINED an outer one (ADR-0067 D2) or ran on
  the degrade path where there is no transaction to own.

Both are honoured on `ScopedContext.transaction` (`ctx.api.transaction`) too —
a second implementation of one primitive must not become a second dialect.

The contract TSDoc is corrected on a point measurement disproved: writes routed
off the transaction's datasource were NOT "written outside it", they were handed
the owner's transaction handle and executed on the wrong connection (#5351). The
TSDoc now states that, plus the two decided semantics landing next: business
writes refused across drivers, and system ledgers (`lifecycle.class` of
audit/telemetry/event) carved out to execute outside the transaction.

`@objectstack/core`'s `EngineWithTransaction` is typed FROM the contract rather
than transcribed from it — the hand-copy had already started to drift.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Q7oc7ASjh8yxyS3Yz78We
…rred artifact)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Q7oc7ASjh8yxyS3Yz78We
@vercel

vercel Bot commented Aug 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 7, 2026 7:14am

Request Review

@github-actions github-actions Bot added the size/l label Aug 7, 2026
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/core, @objectstack/objectql, @objectstack/spec.

120 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/actions-as-tools.mdx (via @objectstack/core)
  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/knowledge-rag.mdx (via @objectstack/core)
  • content/docs/ai/natural-language-queries.mdx (via @objectstack/core)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/core, @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/objectql, packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/core, @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via packages/objectql, @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/migration-from-objectql.mdx (via @objectstack/core, @objectstack/objectql)
  • content/docs/deployment/tenancy-modes.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/deployment/vercel.mdx (via @objectstack/objectql)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/core, @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx (via @objectstack/core, packages/objectql, @objectstack/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/core, @objectstack/objectql, @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/core, @objectstack/objectql, @objectstack/spec)
  • content/docs/permissions/authentication.mdx (via @objectstack/core, @objectstack/objectql)
  • content/docs/permissions/authorization.mdx (via packages/core, @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/anatomy.mdx (via @objectstack/core)
  • content/docs/plugins/development.mdx (via @objectstack/core, @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/core, @objectstack/objectql, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/core, @objectstack/objectql, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/core, @objectstack/objectql, @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/core, @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/core, @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via packages/objectql, @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/objectql, @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/core, @objectstack/objectql, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/core, @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v15.mdx (via @objectstack/core)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/core, @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/apps.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/field-grouping-and-order.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

…ransaction signature with the contract (#5696)

CI's `TypeScript Type Check` went red where a scoped `pnpm --filter …
typecheck` could not: @objectstack/metadata-protocol has no `typecheck`
script, so its errors are only ever seen by the DEBT ledger's `--re-measure`,
which reported 63 -> 70 (+7).

All seven were one shape. Six test doubles stand in for `SysMetadataEngine`,
whose `transaction?` member is typed FROM the contract
(`IObjectQLEngine['transaction']`), and each declared its callback as
`(ctx: any) => Promise<T>` — one parameter, from before the callback gained
its `info` argument. A double may be narrower than the producer; it may not
contradict it.

Each now declares `(ctx: any, info: { owned: boolean })` and passes
`{ owned: true }` at the call — the honest value, since every one of these
doubles OPENS the transaction it stands in for, which is exactly what
`ObjectQL.transaction` reports on its own open branch.

Re-measured: 63 raw errors, the frozen count, with zero transaction-related
errors remaining. `check-type-check-coverage --re-measure` reports no upward
drift. metadata-protocol: 49 files / 502 tests pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Q7oc7ASjh8yxyS3Yz78We
…e TEST_DEBT re-measure (#5696)

objectql's test layer is excluded from its own `tsconfig.json`, so
`pnpm --filter @objectstack/objectql typecheck` never reads these files —
only the ledger's `--re-measure` does, by synthesizing a config with the test
globs unexcluded. The new file arrived with 7 errors nothing local reported.

Two shapes, both fixed rather than absorbed:

- `registry.registerObject(x as any)` — `packageId` is not optional (TS2554).
- `promise.catch((e) => e as E)` types the result `E | <resolved type>`, so
  every property read on it is TS2339. Replaced by a `rejection<E>()` helper
  that narrows to the rejection AND throws if the call did not reject at all —
  which the bare `.catch()` would have let pass silently as a green test.

Re-measured: zero errors in this file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Q7oc7ASjh8yxyS3Yz78We
…nsaction-contract

Conflict: packages/objectql/src/engine.ts import block — both sides added an
import next to the same line (#5696's transaction-errors, main's
summary-aggregate). Both kept; no logic overlap.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Q7oc7ASjh8yxyS3Yz78We

Copy link
Copy Markdown
Contributor Author

ACCEPT(执行席 PM 验收,同批 PR 序第一落)

核过:① 契约三点齐(require fail-closed / owned 信号 / 签名向后兼容追加),TSDoc 把被实测证伪的旧 caveat 改写为事实陈述 —— 契约文档从「描述缺陷」变回「描述行为」;② 偏离 1 裁定:采纳 —— 纯 spec 声明会让 ObjectQL implements IObjectQLEngine 的验证步转红(TS2416 实测),且「声明了不兑现」哪怕存在一个 PR 的间隙也是 PD#10 禁止的形状;把第 1、3 点的引擎实现(纯追加、默认行为不变)带进本 PR、把耦合裁决真正约束的第 2 点完整留给 PR #6171 与 carve-out 同批 —— 维护者硬约束保持,肢 B 实测(审计写拒绝顶掉业务错误)正是其证据;③ owned 走第二参数的选型已单列进 spec 席确认单;④ 首轮 CI 真红(metadata-protocol 无 typecheck 脚本的 DEBT 盲区 +7)修复而非抬台账,6 个测试替身签名对齐;⑤ 最新 SHA 24 项全绿;changeset 在。

spec 席确认单:#6172(可选面,事后收窄不破坏)。翻 ready + auto-merge,进队列(rc.5)。PR #6171 待其 CI 跑满 + 本 PR 合入(base 自动转 main)后按序落。


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

更正:spec 席确认单为 #6184(上条 ACCEPT 评论误写为 #6172,以本条为准)。


Generated by Claude Code

@baozhoutao
baozhoutao marked this pull request as ready for review August 7, 2026 07:41
@baozhoutao
baozhoutao added this pull request to the merge queue Aug 7, 2026
Merged via the queue into main with commit 1363084 Aug 7, 2026
25 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-5696-transaction-contract branch August 7, 2026 07:56
baozhoutao pushed a commit that referenced this pull request Aug 7, 2026
…-audit-same-origin

main squash-merged #6165 (the contract half) as 1363084, so this branch's
original #6165 commits and main's squashed version are two sources for the same
content — the known stacked-PR shape. Resolved semantically, not textually.

Three conflicted files, all one pattern: the #6165 content is identical on both
sides (it auto-merged wherever only #6165 touched it), and every conflict hunk
is #5351's own work sitting ON TOP of that identical base. HEAD taken in each:

- packages/objectql/src/transaction-errors.ts (add/add) — main has
  TransactionUnsupportedError; this branch has it verbatim PLUS
  CrossDatasourceTransactionWriteError (#5696 point 2). Superset kept.
- packages/objectql/src/index.ts — same shape: the second error's export.
- packages/objectql/src/engine.ts, two hunks — the transaction-errors import
  (superset), and the transaction() TSDoc bullet that #5351 rewrote from
  "routed elsewhere runs OUTSIDE it, reported at error" to the decided
  behaviour (refuse business writes / carve out system ledgers). main's side is
  the pre-#5351 text and still names reportWriteOutsideTransaction, which this
  branch renamed to enforceTransactionOrigin.

Verified after resolving: no conflict markers, and the only surviving mention
of reportWriteOutsideTransaction is the TSDoc line that deliberately records
the rename.

Changesets: both survive intact. main's `chore: version packages (rc)`
(bd19133) landed BEFORE the #6165 squash, so it consumed neither — #6165's
changeset is still on main and this branch's own
transaction-same-origin-audit-carve-out.md is untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Q7oc7ASjh8yxyS3Yz78We
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

Development

Successfully merging this pull request may close these issues.

[spec] engine.transaction 契约收紧:opts.require fail-closed、跨驱动拒绝、owned-vs-joined 信号(#4619 的契约半边,维护者已批 P2)

2 participants