Skip to content

docs(skills): name the ctx.email.send and ctx.activity.append body doors in the data-hooks reference - #33078

Merged
os-zhuang merged 2 commits into
mainfrom
claude/project-thread-i5ra51
Nov 13, 2026
Merged

os-zhuang merged 2 commits into
mainfrom
claude/project-thread-i5ra51

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Tesla · project thread

Fixes #33033

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:objectstack-data 技能的 data-hooks.md 现在点名 feat(runtime): a script body sends mail and adds a timeline entry through platform doors that stamp who sent it #32966 发布的两个脚本体入口:沙箱 ctx 表加 ctx.email / ctx.activity 两行,「Capabilities — the complete list」加 email.send / activity.append 两行,并把过时的「exactly five」改为「exactly seven」(HookBodyCapability 在 main 上是七个值)。
  • 为什么改:按原文写钩子的 agent 找不到这两个入口,还可能在钩子体里发邮件——这在解析时就被拒(裁决 [PM seat] security · seat 2 — 🟢 os-tesla #32004 6843314411)。规则只陈述一次:钩子体不能持有 email.send(解析与绑定时拒收),记录变更时的邮件走 action、job 或 flow;activity.append 随运行脚本体的那次写入一起提交或回滚;type 只能用应用自己的值(平台类型 403 拒收),且不得在 ctx.api.transaction 内调用(409)。另把「async 钩子用于发邮件」改为「发通知」,免得与新规则矛盾。
  • 风险与回滚:只改已发布技能文字,无代码改动;token 10007 / 10011(同文件删复述付账,不抬上限)。回滚即 revert。
  • 先看:skills/objectstack-data/references/data-hooks.md 第 355–356 行(ctx 表两行)、第 426–436 行(能力表两行 + seven),第 197 行(async 用途)。
  • 两分钟验证:node scripts/check-skills-token-ratchet.mjs | grep data-hooks,预期 10007 / 10011 且退出 0。
  • 需要你做的:本 PR 触及 skills/**(Tier H)。契约复审在现 head 已 PASS(r1 评论 6849613993,r2 增量 6849985798,Head-sha dc05d1b0a91dd4c9d89f6fe6b558114e54f03818),请以 os-zhuang 批准。⛔ 18.4.0 合并冻结中([sweep] v18.4.0 release test sweep #32908 6848983225):本 PR 带 changeset,批准后请勿入队,席位在解冻后落地。
  • 席位意见:同意落地。两个钩子体入口、解析/绑定两处拒收、两个入参 schema 逐一对过;r1 的两个 should-fix(activity.append 的 type 与事务内调用会被拒;async 段落仍教「发邮件」)已在 r2 修掉;余两个 nit 作为接受的偏差。

What changes

  • ctx table: ctx.email ({ send }, gated by email.send, not in a hook body) and ctx.activity ({ append }, gated by activity.append).
  • Capabilities — the complete list: "exactly five" → "exactly seven" (it was stale: HookBodyCapability on main b232220 lists api.read, api.write, api.transaction, crypto.uuid, log, email.send, activity.append), plus two rows:
    • email.send: ctx.email.send({ to, subject, text }), mail via the mail service with sender, user and organization stamped (BodyMailSendInputSchema); not in a hook body, refused at parse and at bind, because a message cannot be taken back if the hook's write rolls back; mail on a record change goes through an action, a job or a flow.
    • activity.append: ctx.activity.append({ object, recordId, type, summary }), one record-timeline entry with actor and origin stamped (BodyActivityAppendInputSchema); commits or rolls back with the write that runs the body. type is the app's own, never a SYS_ACTIVITY_PLATFORM_TYPES value (403 PERMISSION_DENIED, aborting the write under onError: 'abort'), and the call is never made inside ctx.api.transaction (409 RESOURCE_CONFLICT).
  • async section: "Sending emails/notifications" → "Sending notifications", so no line sends an author to mail from a hook.
  • Truth sources read on main b232220: packages/spec/src/data/hook-body-doors.zod.ts (both input schemas and their descriptions), packages/spec/src/data/hook-body.zod.ts (HookBodyCapability JSDoc), packages/spec/src/data/hook.zod.ts refuseHookBodyMailGrant (parse-side refusal; its block comment names the bind-side refusal in hookBodyRunnerFactory), content/docs/automation/hook-bodies.mdx rows for both doors, content/docs/kernel/runtime-services/email-service.mdx. The skill text claims nothing those do not say; the required input keys named are the schema's required keys (text stands for "text or html").
  • Budget paid by same-file restatement cuts, no ratchet raise:
    • the body vs handler table's "Ships as" row and the paragraph after the table ("Because a body is pure metadata …") — both restate the Shape/Status rows and the section intro;
    • the Hook Context API callout's tail "including the where query shape and the update({ id, … }) pattern" — the linked section already titles both;
    • the "What Are Hooks?" four-bullet list, which restates the Before vs After table (now linked) and the ctx table;
    • the Cross-Object API paragraph's second link to the sandbox section and its "additionally require api.read / api.write" sentence — the callout at the top of the same ## Hook Context API section links the sandbox section, and the capability table states the tokens.

Tests

Teaching text only; no tested behaviour changed, so no ablation.

Acceptance notes

  • Readings (published skills/**): skills/objectstack-data/references/data-hooks.md lines 953 → 943, tokens 9987 → 10007 (ceiling 10011) at head dc05d1b.
  • No out-of-scope findings.

Verification

Gates: CI on dc05d1b 44 check-runs, 28 success, 16 skipped, 0 failed; local derived list at e7336ef, skill-text gates re-run on dc05d1b
  • Derivation: node scripts/pm/dispatch-gates.mjs --commands (45 commands) plus pnpm check:changeset-fixed (roster under .changeset, flagged by the derivation). @objectstack/lint... built first for check:doc-formula-expressions.
  • main b232220 merged before opening: no-op. Skill-text gates re-run on e7336ef, each exit 0: check-skills-token-ratchet (10007 / 10011), spec check:skill-refs, spec check:skill-docs, check:skill-identifier-liveness, check:skill-links.
  • Re-run on dc05d1b, 16 commands, each exit 0 (token ratchet 10007 / 10011, spec check:skill-refs / check:skill-docs, skill identifier liveness, skill links, doc authoring, changeset gates, closing-keyword parity, …).
  • NOT MEASURED locally (exit 3, prerequisite: whole-workspace dists): check:dual-build-cjs-loads, check:lean-entry-closure. The diff is one markdown file and a changeset, which cannot move built dists; CI's Build Core ran both on dc05d1b: success.

Generated by Claude Code

🤖 Generated with Claude Code

https://claude.ai/code/session_01L9qibzqxVnBg8FjZXM1fQu

…ors in the data-hooks reference

The sandbox ctx table and the capability list name both doors; a hook
body cannot be granted email.send, and an activity entry commits or rolls
back with the write that runs the body. Growth paid by same-file
restatement cuts.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qibzqxVnBg8FjZXM1fQu
@github-actions github-actions Bot added documentation Improvements or additions to documentation tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Nov 13, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-tesla · session_01L9qibvXzthnUYrxzphgFgW

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: e7336ef1fc634913fc713d7e4aaf55c4e96f42a7
Local-runs: none
Scope: skills/objectstack-data/references/data-hooks.md + none

PR #33078 for card #33033, rules face (skills/** is a governed path). Net diff against main at b2322209, the head's merge base: two files, 12 lines added and 12 deleted. No file in the diff implements or enforces the hits file. .changeset/hooks-skill-body-doors.md is the remainder: the lane seat's ACCEPT at TIER_DEFAULT.

① Derived judgments

  • Accept set: nothing moves. Right. The diff holds no schema, validator, lint rule or runtime file. Both doors and the hook-body refusal of email.send are already on main (refuseHookBodyMailGrant on HookSchema, hookBodyRunnerFactory, buildBodyDoors); the skill text follows them.
  • Public surface: one published reference changes its teaching. Right. No skill, file, heading or anchor is added, removed or renamed, so the inbound link from rules/validation.md to #capabilities--the-complete-list still resolves, and no generated references/_index.md moves.
  • "exactly five" becomes "exactly seven". Right. HookBodyCapability on main lists seven values: api.read, api.write, api.transaction, crypto.uuid, log, email.send, activity.append.
  • Governed surface. skills/** is a Tier H row of GOVERNED_SURFACES. This record is the contract review, not the landing word: landing waits for an authorized APPROVED review, or the maintainer's own merge or enqueue.
  • Gates the diff derives, as the head's check-runs concluded them (read shortly before this record, 2026-11-13T09:50Z):
    • Type Check · source gates: success. Its steps include the published-skills token ratchet, skill docs, generated skill references, and skill links and anchors.
    • Lint · docs & code guards: success (published-skills identifier liveness). Lint · repo & tooling gates: success (doc and skill authoring guard). Type Check · consumer gates: success (skills TypeScript examples compile).
    • Check Changeset, Governed Surface Queue Guard, Check PR Size, PR-body guards: success.
    • Build Core: success. It carries the two gates the dev reported NOT MEASURED locally (check:dual-build-cjs-loads, check:lean-entry-closure); both steps concluded success.
    • Lint & Repo Gates, TypeScript Type Check, Test Core, Dogfood Regression Gate, Live E2E UI, Test UI: success.
    • All 44 check-runs on this head have concluded: 28 success, 16 skipped, none failed, none still running.

② Semver level

  • The changeset is '@objectstack/skills': patch. The diff publishes skill text from that one package and changes nothing an author may write, so patch matches.
  • The PR body declares Clause-②: no and Metadata-protocol: none, and the card's claim comment declares the same pair. Both are right (①).
  • N1, nit (a prose face; the lane seat's ACCEPT). The changeset body carries neither declaration line. AGENTS.md, Post-Task Checklist step 3, asks for both lines in the PR body and in the changeset body, and the other @objectstack/skills changesets on main carry them. No gate reads them at no and none, and the level does not depend on them. A changeset-only edit adds them and keeps this record.

③ Boundary flags

  • open_questions is empty, and the report lists no out-of-scope finding.
  • Model tier (report deviations). The card thread drafted on its configured model, not on the tier the claim line names as MANDATORY for published skills/**. Answered in part: the at-tier read of the whole hits diff is this record, rendered by an isolated sub-agent that did not draft it and adopted by seat domain:skills#2. Escalated in part: whether a draft made below the mandatory tier is accepted is the dispatching seat's ACCEPT. This record does not decide it.
  • Refused first push (check:commit-card-trailers). Answered. The head is the PR's only commit. Its message carries the model-free trailer pair and no closing keyword, and the PR timeline shows no force-push.
  • Two gates NOT MEASURED locally. Answered by Build Core on this head (①).
  • Acceptance note: activity.append inside ctx.api.transaction left out for budget. Answered in ④, finding S1.
  • The PR's user.login is objectstack-fleet[bot]; no off-relay author to name.

④ Design judgment

skills/objectstack-data/references/data-hooks.md, each changed sentence read against the live tree on main:

  • ctx table, ctx.email and ctx.activity rows: hold. installDoor (quickjs-runner.ts) puts both members on every body and checks each call against its own token first. In a hook body ctx.email.send is also refused at the call (buildBodyDoors, 403 PERMISSION_DENIED).
  • "exactly seven": holds (①).
  • email.send row: holds. to, subject and one of text or html are the required keys of BodyMailSendInputSchema. "Sender, user and organization are stamped" is the HookBodyCapability JSDoc. "Refused at parse" is refuseHookBodyMailGrant, a refinement on HookSchema, so defineHook, os validate, the save door, compile and an artifact's parse all meet it. "Refused at bind" is the throw in hookBodyRunnerFactory. The route for mail on a record change is ruling 6843314411's own sentence, and hook-bodies.mdx and email-service.mdx say the same.
  • activity.append row: holds. object, recordId, type and summary are the required keys of BodyActivityAppendInputSchema. The door stamps actor, organization, time and origin. "Commits or rolls back with the write that runs the body" is the schema's description, and buildBodyDoors does it: the engine's ambient transaction joins by itself, and a threaded handle is passed to appendAppActivity. body-doors-transaction.integration.test.ts pins both directions. The door reads the record host-side, so no api.read grant is owed beside activity.append.
  • Hook Context API callout and Cross-Object API paragraph, as cut: hold.

Deleted lines:

  • Callout tail, and the Cross-Object API paragraph's second link and capability sentence: true restatements. The linked section still titles "Query shape" and "Update by id". The capability per method stays in the ctx.api.object(name) table, the ctx table and the capability list, and the section's opening callout keeps the link.
  • "Because a body is pure metadata" paragraph: restates the section's first sentence and the Shape row.
  • "Ships as" row: the body cell restates the Shape row. The handler cell does not (N2).

Tried to break it:

  • Mail from a hook body: the text stops it twice (the ctx row and the capability row), and the parse stops what the text misses.
  • A missed grant: none. Each door needs its own token only, and both rows name it.
  • A hook body that is refused: yes, by two routes. They are S1 and S2.

Findings:

  • S1, should-fix. The activity.append row leaves out the call-time refusals its docs row carries (hook-bodies.mdx), and an author following the row walks into one of them. The row names type as a bare required key. The values an author reaches for first on a record-change hook (created, updated, deleted, commented, assigned, system) are platform-only (SYS_ACTIVITY_PLATFORM_TYPES): the activity writer refuses each with 403 PERMISSION_DENIED at every call, and under the default onError: 'abort' that fails the write the hook is attached to. A call inside the body's own ctx.api.transaction is refused with 409 RESOURCE_CONFLICT (installDoor); this is the omission the PR's acceptance notes name. Neither is caught at parse or at build. Fix: the row says that type is the app's own value and never a platform one, and that the call stays outside ctx.api.transaction. Pay for it in this file; S2 gives some back.
  • S2, should-fix. Under "async — Background Execution" the file still lists "Sending emails/notifications" as a reason to set async: true (line 202 at this head). With the rule this PR adds, the file teaches both that an async after-hook is where mail is sent and that a hook body cannot send mail. The card's scenario is an author who tries mail from a hook, and this is the one line that sends them there. It is unchanged text, but it sits in the hits file and contradicts the sentence under review, so it is graded here. Fix: take mail out of that bullet. The cut lowers the token count.
  • N2, nit. The "Ships as" row's handler cell was not a restatement: nothing else in the file says a handler is lowered at build to a string ref and a sibling .mjs module (Sandbox restrictions keeps only "a bundled (deprecated) handler"). The loss changes nothing an author writes: the form is deprecated, the file sends authors to body, and on main the build lowers an extractable handler into a body (extract-hook-body.ts), so the cell was not exact either.
  • N3, nit. The Hook Context API callout still calls the body's ctx a "subset" of the handler context. ctx.email and ctx.activity now join ctx.log, ctx.crypto and ctx.title as members that context does not declare (HookContextSchema). The word predates this PR, and the sentence's pointer to the sandbox section is what an author follows.
  • Read, no finding. The row's transaction sentence describes a body that runs inside its write. An async: true after-hook runs fire-and-forget (hook-wrappers.ts), detached from the write, and the sentence does not cover it. The sentence is the published schema's, and the file's own Before vs After table states the async case.

No must-fix. S1 and S2 each earn a delta review of their fix by this reviewer. N1 to N3 need none.

Implemented-by: claude/project-thread-i5ra51
Reviewed-by: session_01L9qibvXzthnUYrxzphgFgW

VERDICT: PASS

…tion refusals; async bullet drops mail

Review r1 S1/S2 and N1: the activity.append row says type is the app's
own value (a SYS_ACTIVITY_PLATFORM_TYPES value is 403 and aborts the
write under onError abort) and that the call stays outside
ctx.api.transaction (409). The async bullet no longer suggests mail from
a hook. The changeset carries the two declaration lines. Growth paid by
cutting the What Are Hooks bullet list, which restates the Before vs
After table.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qibzqxVnBg8FjZXM1fQu
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-tesla · session_01L9qibvXzthnUYrxzphgFgW

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: dc05d1b0a91dd4c9d89f6fe6b558114e54f03818
Local-runs: none
Scope: skills/objectstack-data/references/data-hooks.md + none

Delta review, round 2, of PR #33078 for card #33033. This head is one commit on top of e7336ef1, whose record is comment 6849613993 on the PR thread. This record judges the hunks that moved between the two heads. Every hunk that did not move keeps that record's judgment. .changeset/hooks-skill-body-doors.md is still the remainder: the lane seat's ACCEPT at TIER_DEFAULT.

① Derived judgments

  • Accept set: nothing moves. Right. The delta is skill text and changeset prose. No schema, validator, lint rule or runtime file is in the diff.
  • Public surface: unchanged in shape. Right. No heading or anchor is added, removed or renamed. The delta adds one in-file link, #before-vs-after-hooks; the "Before vs After Hooks" heading carries that anchor, and the file's own contents list already uses it.
  • Tree. Net diff against main: two files, 17 lines added and 19 deleted, merge base still b2322209. main has since moved one commit, to c4196099. That commit touches nothing under skills/** and none of the files read for ④.
  • Governed surface. skills/** stays a Tier H row. This record is the contract review, not the landing word.
  • Gates the diff derives, as this head's check-runs concluded them (read shortly before this record, 2026-11-13T10:10Z):
    • Type Check · source gates: success. The published-skills token ratchet step passed and its log prints 10007 / 10011 for this file, the same count as round 1. Skill docs, generated skill references, and skill links and anchors passed too, so the new in-file link resolves.
    • Lint · docs & code guards: success (published-skills identifier liveness). Lint · repo & tooling gates: success (doc and skill authoring guard). Type Check · consumer gates: success (skills TypeScript examples compile).
    • Check Changeset, Governed Surface Queue Guard, Check PR Size, PR-body guards, Build Core: success.
    • Lint & Repo Gates, TypeScript Type Check, Test Core, Dogfood Regression Gate, Live E2E UI, Test UI: success.
    • All 44 check-runs on this head have concluded: 28 success, 16 skipped, none failed, none still running.

② Semver level

  • The changeset is still '@objectstack/skills': patch, and the delta publishes skill text only. patch matches.
  • N1 is closed. The changeset body now carries both declaration lines, no and none, the same pair the PR body declares. Its added sentence on type and ctx.api.transaction agrees with the row (④).

③ Boundary flags

  • No card comment is newer than the os-dev report, and the PR thread holds only the round 1 record. The dev's account of this commit is its commit message.
  • Count of SYS_ACTIVITY_PLATFORM_TYPES. Ten on main: created, updated, deleted, commented, mentioned, shared, assigned, login, logout, system. The dev's count is right. Round 1 named six of the ten as the values an author reaches for first and gave no count; read as a count, six is wrong and ten stands.
  • The PR body describes e7336ef1, not this head. Escalated to the seat. It gives the file as 948 lines (943 at this head) and points the reader at lines 360 to 361 and 431 to 441 (now 355 to 356 and 426 to 436). Its activity.append bullet names neither refusal, its budget list omits the "What Are Hooks?" cut, its acceptance note still says the ctx.api.transaction refusal was left out of the row, and its local-gate list is for e7336ef1. Its token reading still holds: the token ratchet's log on this head prints 10007 / 10011. A body edit moves no head and keeps this record. The maintainer reads that body for the Tier H approval, so it is owed before the approval is asked.
  • Model tier. Unchanged from round 1: the drafting tier is the dispatching seat's ACCEPT, and this record does not decide it.
  • Commit. The fix is a second commit on top; the PR timeline shows no force-push. Its message carries the model-free trailer pair and no closing keyword.

④ Design judgment

skills/objectstack-data/references/data-hooks.md, the three hunks that moved, each read against the live tree on main:

  • activity.append row (line 436): holds, and S1 is closed.

    • "type is the app's own, never a SYS_ACTIVITY_PLATFORM_TYPES value": appActivityEntryRefusal (app-activity-door.ts) refuses a type in that set. The constant is a published export of @objectstack/spec/data (feed.zod.ts, listed in api-surface/data.json), read here and not by a gate: identifier liveness judges a row's first cell only. An author resolves it in the package, as with the two schemas the row already names.
    • "403 PERMISSION_DENIED, aborting the write under onError: 'abort'": the refusal carries that code and status. The bound hook handler rethrows a body's throw (hookBodyRunnerFactory), and the hook wrapper rethrows it unless the hook declares onError: 'log'. An async: true after-hook is the one case that does not abort, and the file's Before vs After table already limits the abort to a sync hook.
    • "never inside ctx.api.transaction (409 RESOURCE_CONFLICT)": installDoor (quickjs-runner.ts) throws that code and status while the body's own transaction is open.
    • The row now says both things S1 asked for, and the sentence on commit and rollback is kept.
  • async bullet (line 197): holds, and S2 is closed. "Sending emails/notifications" is now "Sending notifications". The file no longer names mail as a reason to set async: true, so no line in it sends an author to mail from a hook.

  • "What Are Hooks?" (line 23): the cut list was a restatement. Its content survives in this file:

    • "Modify input parameters or operation results": the Before vs After table's "Can modify" row.
    • "Validate data and throw errors to abort operations": that table's "Purpose" and "Can abort" rows.
    • "Trigger side effects (notifications, integrations, logging)": that table's "Purpose" row for after* hooks. "Integrations" is not in the row; the lifecycle table keeps it as "sync external systems".
    • "Read the operation context (user, session, input data)": not in that table. The ctx table and the Hook Context API section carry it.

    So the table restates three of the four bullets and the ctx table the fourth. Nothing an author needs is lost, and the new link resolves.

Tried to break the moved text:

  • An author who follows the row picks a type of the app's own and keeps the call outside ctx.api.transaction. Both round 1 routes to a refused body are closed.
  • Call-time refusals the row still leaves to the docs row: a record the caller cannot read (404), the metadata rules, and an object the timeline does not show. Round 1 did not ask for them, and none is a value an author is steered into.

Round 1 nits N2 and N3 are unchanged text and stay as recorded. No new finding.

No must-fix and no should-fix. The round ends here.

Implemented-by: claude/project-thread-i5ra51
Reviewed-by: session_01L9qibvXzthnUYrxzphgFgW

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-tesla · session_01L9qibvXzthnUYrxzphgFgW

席位核对 · ACCEPT · 2026-11-13T10:11Z

Head-sha: dc05d1b0a91dd4c9d89f6fe6b558114e54f03818

  1. Shape. Draft PR to main, Fixes #33033, 2 files, +17/−19 ≤ 3000. GOVERNED via skills/** ⇒ Tier H, a human approval. Changeset '@objectstack/skills': patch, carrying both declaration lines. Clause-②: no, Metadata-protocol: none. Files are within claim 6849100308.
  2. Premise. Holds: feat(runtime): a script body sends mail and adds a timeline entry through platform doors that stamp who sent it #32966 merged. Both doors and the hook-body refusal of email.send (refuseHookBodyMailGrant, hookBodyRunnerFactory, buildBodyDoors) are on main as the row teaches.
  3. Review. Contract review at CONTRACT_REVIEW_TIER by an isolated sub-agent. Round 1 (6849613993, head e7336ef) was PASS with two should-fix: S1, the activity.append row omitted the platform-type 403 and the in-transaction 409; S2, the async section still named mail. Delta round 2 on this head (6849985798) is PASS with both closed, 0 must-fix, 0 should-fix. Prose I read against the diff: the changeset body and the PR body, which I re-patched to describe this head.
  4. Gates. Check-runs on this head: 44 concluded, 28 success, 16 skipped, 0 failure. Token ratchet 10007 / 10011 for data-hooks.md, no ceiling moved. K = 1.
  5. Accepted deviations.
    • D1, drafting tier: the card thread drafted on its configured model, not on CONTRACT_REVIEW_TIER. Accepted: both review rounds are an at-tier read of the whole hits diff by an isolated reviewer that did not draft it.
    • N2: the "Ships as" row's handler cell carried a fact found nowhere else (the build lowers a handler to a string ref and a sibling module). The form is deprecated and the file sends authors to body, so nothing an author writes changes.
    • N3: the Hook Context API callout still calls the body's ctx a "subset", although ctx.email and ctx.activity now join members the handler context does not declare. The wording predates this PR.
    • N1 (changeset declaration lines) was fixed in round 2.
  6. Out of scope / landing.

@objectstack-fleet objectstack-fleet Bot added the pm:awaiting-merge PR only: landing waits on the maintainer's own review and merge (SKILL.md 复核 ②); never on an issue label Nov 13, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review November 13, 2026 10:14
@os-zhuang
os-zhuang requested a review from hotlong as a code owner November 13, 2026 10:14
@os-zhuang
os-zhuang added this pull request to the merge queue Nov 13, 2026
Merged via the queue into main with commit b440ffb Nov 13, 2026
54 checks passed
@os-zhuang
os-zhuang deleted the claude/project-thread-i5ra51 branch November 13, 2026 14:41
@objectstack-fleet objectstack-fleet Bot removed the pm:awaiting-merge PR only: landing waits on the maintainer's own review and merge (SKILL.md 复核 ②); never on an issue label Nov 13, 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/s tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs(skills): name the ctx.email.send and ctx.activity.append body doors in the data-hooks reference

3 participants