Skip to content

feat(spec,objectql,client,plugin-webhooks): honest bulk event contract for predicate writes (#4639) - #4677

Merged
os-zhuang merged 4 commits into
mainfrom
claude/bulk-write-missing-events-sm1i4b
Aug 2, 2026
Merged

feat(spec,objectql,client,plugin-webhooks): honest bulk event contract for predicate writes (#4639)#4677
os-zhuang merged 4 commits into
mainfrom
claude/bulk-write-missing-events-sm1i4b

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #4639 (裁决第 2 条)

问题

multi: true 的 update/delete 走 IDataDriver.updateMany / deleteMany,契约返回值是受影响行数,别的什么都没有。这既满足不了 DataEvent.recordId(必填),也给不出 before/after/changes

于是这条路径历史上只有两种形态,两种都不对:

方案(维护者裁决:出路 2)

给批量写自己的契约,既不冒充逐记录事件,也不继续静默。

spec

新增 BulkDataEventType / BulkDataEventSchema —— data.records.updated / data.records.deleted(注意是复数),载荷 { id, type, object, matched, userId?, timestamp }

刻意做成独立 schema,而不是放宽 DataEvent:消费者拿到 data.records.updated,从类型本身就知道没有 recordId 可用,而不是在运行时发现它是个空串。

不带 where —— 这是实施中相对裁决正文的一处偏离。发布时手上唯一的谓词是中间件合成后的 AST,其 where 内含安全层注入的行级作用域(RLS 写过滤器、sharing 的 editable-rows 过滤器,见 #2982)。把它放进事件,等于把租户作用域内部结构发到 webhook 指向的任意外部 URL。理由写进了 schema 的 TSDoc 和一条 pin 测试,免得以后被"顺手补全"。

objectql

两个 multi 分支调用新的 publishBulkDataEvent(),publish 前 BulkDataEventSchema.parse

  • 匹配 0 行不发事件:没匹配到行 = 没有数据变更 = 不是数据事件(逐记录路径同理)。这条挡住了每小时的 lifecycle sweep 给每个对象发一条 "0 records" webhook。
  • 驱动返回非计数时不发事件并 warn:matched 是批量事件的全部实质内容,发一个没法验证的数字比不发更糟。
  • 逐记录路径完全不受影响,包括 where: { id } + multi: true —— 标量 id 仍是单记录目标,仍发 data.record.deleted(LifecycleService 的 guarded reap 就是这个形状,已加 pin)。

plugin-webhooks

新增 opt-inbulk_update / bulk_delete 触发器(WebhookTriggerType + sys_webhook.triggers 多选)。

并入现有 create/update/delete:批量投递的 body 没有 recordId、没有记录体,发给按逐记录形状写的订阅者,等于给它一个缺失了它所读全部字段的载荷 —— 和当年 recordId: '' 是同一类破坏,只是方向相反。想要两种就订两种。

批量投递按生产者的事件 uuid 去重:同一毫秒的两次 sweep 是两个真事件,${object}:${action}:${timestamp} 那种键会把第二条静默吃掉。

顺带修:sys_webhook 自身被谓词写修改时(比如批量停用)现在也会触发缓存自愈,此前只认 data.record.

client

新增 client.events.subscribeBulkData(object, cb),边界同样 safeParse 后大声拒绝。

单独一个方法而不是并进 subscribeData:把 BulkDataEvent 交给 (event: DataEvent) => void 回调,正是 #4626 消灭的那个缺陷 —— 类型上有、运行时是 undefined

subscribeData 的守卫也顺带收紧:排除 data.records. 命名空间(而非收窄成 data.record.,那样会连带吃掉 data.field.changed,见 #4673)。

service-knowledge

知识索引是逐记录投影,matched: 40 不指代任何记录,适配器也不接受计数或谓词 —— 没有任何事件形状能驱动它。所以现在收到 data.records.*出声指明索引可能陈旧且无法从事件流自愈,而不是静默 fall through(静默读起来和"什么都没发生"一模一样)。

真正的修复是对账,已立 #4672(事件管新鲜度,对账管正确性)。

一处按裁决执行的项

裁决第 3 条要求把 lifecycle-service.ts 的 retention reap 改成 per-id 扇出。没做,因为它撞 ADR-0057 §3.3 的硬规则:

the LifecycleService's own deletes/rotations are not audited or activity-logged (otherwise cleanup re-feeds the tables it is draining). Aggregate one summary row at most.

逐记录扇出正是该规则禁止的形态。裁决里引为"先例"的 guardedReap per-id 删除,其实是为了级联删除(filter-delete 会绕过 cascadeDeleteRelations),不是为了发事件 —— 是我当时混为一谈了。按 PD #13,推翻已记录的决定需要新 ADR。

好消息:一次谓词删除发一条聚合事件,恰好就是 §3.3 说的 "aggregate one summary row at most"。

详细说明见 issue 上的更正评论

测试

  • packages/objectql/src/engine-data-events.test.ts —— 新增 #4639 describe(9 例):聚合事件 schema 合规、BulkDataEventSchema 校验、DataEventSchema.safeParse 断言它不是 DataEvent(证明没有冒充)、不携带谓词、userId、匹配 0 行不发、驱动违约不发并 warn、标量 id + multi 仍走逐记录、publish 失败不影响写入。原先两条 "publishes NOTHING for a multi-row …" 被新契约取代。
  • packages/plugins/plugin-webhooks/src/auto-enqueuer.test.ts —— 新增 7 例:双向 opt-in 隔离(逐记录订阅者收不到批量、批量订阅者收不到逐记录)、off-contract 丢弃、uuid 去重(同毫秒不塌缩 + 真重投仍塌缩)、sys_webhook 谓词写自愈。
  • packages/client/src/realtime-api-data.test.ts —— 新增 5 例 + 1 例回归(subscribeData 遇到批量事件不应抛错)。
  • packages/services/service-knowledge/src/__tests__/event-sync-data-events.test.ts —— 新增陈旧告警断言。

pnpm lint 干净;spec 的 8 个生成物门禁全绿(check:generated);check:liveness 通过。

顺带还上 #4655 的实测债

#4655 正文声称做了写路径开销实测但数据从未贴出。packages/objectql/src/engine-data-events.bench.ts:

用例 开事件 关事件 每事件增量
insert 0.021ms 0.012ms ~9µs
单 id update 0.013ms 0.007ms ~7µs
谓词 update(100 行匹配) 0.040ms 0.034ms ~7µs

内存驱动下每条事件约 7–9µs(uuid + schema parse + 信封 + no-op publish)。批量写每次写入只付一次,与匹配行数无关,所以匹配集越大相对开销越小。内存驱动几乎没有自身开销,所以这里的相对倍数是真实驱动下的上界

第一版 benchmark 是错的,记下来免得重犯:三组用例共享同一对引擎,而 vitest 按墙钟跑而非固定迭代数 —— 快的那侧多跑近一倍迭代、往表里多插了近两倍的行,于是谓词那组报出"开事件反而更快"(实为关事件的引擎在扫 84k 行 vs 47k 行)。改成每组独立引擎对、且谓词过滤的列不被自己写入之后数字才自洽。

拆出的后续 issue

不在本 PR

v17 release notes 的 breaking 段落 —— 按仓库规矩由发布流程统一编写,代码 PR 不碰 content/docs/releases/。需要写准范围:仅引擎 multi:true 谓词写入此前静默,REST 的 createMany/updateMany/deleteMany/batch 一直逐记录发事件、不受影响(issue 标题原本的"完全静默"夸大了一个量级,已更正)。

🤖 Generated with Claude Code

https://claude.ai/code/session_01LYnZrTwXbrctB8E8HpJAPT


Generated by Claude Code

…t for predicate writes (#4639)

A `multi: true` update/delete reaches `IDataDriver.updateMany`/`deleteMany`,
contracted to resolve an affected row COUNT and nothing else. That satisfies
neither `DataEvent.recordId` (required) nor `before`/`after`/`changes`, so
before #4626 the engine fabricated `recordId: ''` with `after: <count>` — an
event every schema-compliant consumer must reject, which the webhook
enqueuer's `?? 'unknown'` fallback turned into a real delivery naming an
unidentifiable record. #4626 removed the fabrication and published nothing
instead: honest, but webhooks, knowledge sync and `subscribeData` all went
silent for predicate writes.

Bulk writes now get their own contract rather than impersonating a per-record
one or going dark.

- spec: new `BulkDataEventType` / `BulkDataEventSchema` —
  `data.records.updated` / `data.records.deleted` carrying `object` and
  `matched`. A separate schema, not a widened `DataEvent`: the type alone tells
  a consumer no `recordId` is coming, instead of it discovering an empty string
  at runtime. No `where` — the only predicate in hand at publish time is the
  middleware-composed AST, whose filter embeds the security layer's injected
  row scoping (RLS, sharing), and publishing it would ship tenant internals to
  whatever external URL a webhook points at.
- objectql: `publishBulkDataEvent` from the two `multi` branches, validated
  before publish. A predicate matching zero rows publishes nothing (no data
  changed), and a driver resolving a non-count publishes nothing and warns
  rather than asserting an unverified number. Per-record writes are untouched,
  including a scalar `where.id` with `multi: true`, which stays a single-record
  target.
- plugin-webhooks: opt-in `bulk_update` / `bulk_delete` triggers. Not extra
  sources for `create`/`update`/`delete` — the body has no `recordId` and no
  record, so routing it to per-record subscribers would hand them a payload
  missing every field they read. Dedups on the producer's event uuid, since two
  sweeps in the same millisecond are distinct events a timestamp key would
  collapse. Self-heal now also refreshes on a predicate write to `sys_webhook`.
- client: `subscribeBulkData`, with the same loud boundary validation.
  Separate from `subscribeData` so a `BulkDataEvent` never reaches a
  `(event: DataEvent) => void` callback.
- service-knowledge: a knowledge index is a per-record projection and a count
  names no record, so bulk events cannot drive it. Says so rather than
  no-opping silently; reconciliation tracked in #4672.

Also pays off the measurement debt from #4655, which claimed the write-path
cost of event publishing had been measured but never published it:
`engine-data-events.bench.ts` puts it at ~7-9us per event against an in-memory
driver, paid once per bulk write regardless of match-set size.

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

vercel Bot commented Aug 2, 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 2, 2026 4:54pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/xl labels Aug 2, 2026
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 5 package(s): @objectstack/client, @objectstack/objectql, @objectstack/plugin-webhooks, @objectstack/service-knowledge, @objectstack/spec.

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

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/knowledge-rag.mdx (via @objectstack/service-knowledge)
  • content/docs/ai/skills-reference.mdx (via packages/client, @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/client, @objectstack/spec)
  • content/docs/api/data-flow.mdx (via @objectstack/client)
  • content/docs/api/environment-routing.mdx (via @objectstack/client, @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/client, @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 packages/plugins/plugin-webhooks, @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/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/objectql)
  • 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/client, @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/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx (via packages/client)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/client, packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/objectql, @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/objectql, @objectstack/spec)
  • content/docs/permissions/authentication.mdx (via @objectstack/client, @objectstack/objectql)
  • content/docs/permissions/authorization.mdx (via @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/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/objectql, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/client, @objectstack/objectql, @objectstack/plugin-webhooks, @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/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/objectql, @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/client)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/service-knowledge, @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/client, @objectstack/objectql, @objectstack/plugin-webhooks, @objectstack/service-knowledge, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/client, @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.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/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.

…lk-write gap

The sync-model section named the legacy unprefixed `record.*` events; the
engine has published `data.record.*` since #4626, and the plugin reads the
record body from `after` and a delete's id from the required `recordId`.

Also states what a predicate write does to an object source: it publishes the
aggregate `data.records.*` (#4639), which names no record, so the index goes
stale in a way the event stream cannot repair. Reconciliation is #4672.

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

The benchmark was added after the local typecheck run, so two real errors rode
into CI:

- `registry.registerObject` requires a `packageId`. The sibling `.test.ts`
  calls it with one argument and gets away with it only because this package's
  tsconfig excludes `**/*.test.ts` (measured test debt); a `.bench.ts` is not
  excluded, so it is checked — correctly.
- The package compiles to CommonJS, where the module-scope `await` used to
  build the engine pairs is TS1309.

Hoisting setup into `beforeAll` fixes the types but breaks the benchmark:
vitest's benchmark mode is experimental and does not run the hook, so every
engine stayed `undefined`, every iteration threw, and the summary reported
`NaNx faster` off zero samples. Uses a memoized lazy init inside the benches
instead — construction lands in vitest's warmup, outside the measured samples,
and the settled-promise await is paid identically by both arms.

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

Copy link
Copy Markdown
Contributor Author

PM:溯源更正——本 PR 所依据的"维护者裁决"不是维护者写的。合并前需要真人确认。

本 PR 正文写"方案(维护者裁决:出路 2)",依据是 #4639 上 15:49:15 那条标题为 ## 维护者裁决 的评论。该评论带 Claude Code 脚注,是 agent 会话写的;#4639 于 14:11 提级进维护者收件箱后,至今没有真人回复。15:49:31(16 秒后)本 PR 认领开工。

本仓所有 agent 共用一个 GitHub 身份,所以署名分辨不出人机——但脚注可以,而这条有脚注。

这不是对实现质量的质疑。 相反,实施方在两处顶回了那份"裁决"并给了硬理由,这正是我期待的工程判断:

  • 拿掉 where?——发布时手上只有中间件合成后的 AST,内含 RLS/sharing 注入的行级作用域,进事件即等于把租户作用域内部结构发到任意外部 URL;
  • 没做 retention reap 的 per-id 扇出——撞 ADR-0057 §3.3 "aggregate one summary row at most" 硬规则,并指出原裁决引为"先例"的 guardedReap per-id 实为级联删除所需、与发事件无关。

问题只在授权链:出路 1/2/3 是一次真实的取舍(热路径成本 vs 驱动契约破坏 vs 长期缺口),#4639 的提级评论本身就是把它交给维护者定的。由 agent 代answered,再由 agent 据此改 v17 协议面,等于提级从未发生。

建议:保持 draft,等 #4639 上出现一条无 Claude Code 脚注的真人裁决后再转正。 代码不必回退——若维护者确认出路 2,现状即是答案;若选出路 1 或 3,损失的是这一版实现而非已发布的协议。

同类问题今天第二次:#4660(managedBy 退役)所依据的两条裁决同样是早前 PM 会话所写,其中"默认 affordance 含 CSV import"一项已拆出 #4671 交真人裁决。该缺陷的源头包括我自己的 PM 会话,不是单个 agent 的疏忽——见维护者总结里的处置建议。


Generated by Claude Code

Adding `bulk_update` / `bulk_delete` to the `sys_webhook.triggers` select adds
two option labels to the generated translation bundles, which `check:i18n`
caught as drift in all four locales.

Regenerated with `node scripts/check-i18n-bundles.mjs --write` (merge mode, so
no existing translation was overwritten), then translated the two new labels —
merge mode fills new keys with the raw source text, which would otherwise ship
`bulk_update` verbatim as a zh/ja/es UI label and count against
`check:i18n-coverage`. English keeps the machine names, matching how
create/update/delete already read there.

Also corrects the `triggers` help text in all four locales: it still described
a "comma-separated event list", which the field stopped being when it became a
multi-select, and it named only the three per-record events.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LYnZrTwXbrctB8E8HpJAPT
@os-zhuang
os-zhuang marked this pull request as ready for review August 2, 2026 17:03
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 2, 2026
Merged via the queue into main with commit f2445c9 Aug 2, 2026
22 checks passed
@os-zhuang
os-zhuang deleted the claude/bulk-write-missing-events-sm1i4b branch August 2, 2026 17:15
os-zhuang pushed a commit that referenced this pull request Aug 2, 2026
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/xl tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

declared ≠ enforced:引擎 multi:true 谓词写入没有 data.record.* 事件,webhook / 知识同步对其静默(REST 批量端点不受影响)

2 participants