Skip to content

docs(automation): every sender-facing text for an inbound api hook teaches the timestamped x-objectstack-signature form only - #22846

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-22825-inbound-hook-timestamped-guidance
Oct 11, 2026
Merged

os-zhuang merged 2 commits into
mainfrom
claude/issue-22825-inbound-hook-timestamped-guidance

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #22825

Clause-②: no

Ruling B on #22805 (maintainer 「同意」, comment 6108492902), step 1: every text that teaches a sender of an inbound api hook teaches the timestamped x-objectstack-signature form only. The form is the one signHttpBodyAt in packages/core/src/security/http-signature.ts writes — t=UNIX_SECONDS,v1=HEX, where HEX is the HMAC-SHA256 of UNIX_SECONDS.RAW_BODY under the flow's secret, and the door refuses a t more than HTTP_SIGNATURE_TOLERANCE_SECONDS (300) from its clock. The inbound verifier, packages/core/**, packages/triggers/**, packages/services/** and the outbound contract (content/docs/automation/webhooks.mdx §6.2, the messaging outbox, the flow http node, body-only signHttpBody) are not touched. The door's refusal of the body-only form is #22826, which is Blocked-by: this card and unblocks on merge.

The five positions and the changeset

position before after
skills/objectstack-automation/SKILL.md, Inbound webhook section, Signature line (Tier H) the body-only form, "(GitHub/Stripe style)" t=UNIX_SECONDS,v1=HEX; v1 = HMAC-SHA256 of UNIX_SECONDS.RAW_BODY under secret; refused when t is over 300 s from the server clock
packages/lint/src/rule-explanations.ts, flow-api-trigger-secret-missing explanation (os explain) "carries 'sha256=' and the hex HMAC-SHA256 of the raw body" the timestamped form, its material, the 300-second window, and why (a captured post stops verifying); ADR-0041 and HMAC kept, which the explanation pin reads
packages/lint/src/validate-flow-trigger-readiness.ts, the rule's hint same sentence the same form; the verdict message, rule id, severity, path and judgement are unchanged
examples/app-showcase/src/automation/flows/index.ts, the InboundTaskWebhookFlow doc comment header line with the body-only form header line with the timestamped form, signHttpBodyAt(rawBody, secret, Math.floor(Date.now() / 1000)) named as the writer, the 300 s refusal named
docs/qa/platform-checklist/areas/automation.json, item automation.trigger-type-matrix, the api step signs the raw body only signs with signHttpBodyAt(rawBody, 'showcase-webhook-secret', Math.floor(Date.now() / 1000)); revision 2 → 3 with a history entry
.changeset/22825-inbound-hook-timestamped-guidance.md — @objectstack/lint patch + @objectstack/skills patch (@objectstack/example-showcase is private; docs/qa is not a package)

Not changed on purpose: automation.json line 429 (another item's step, "a valid x-objectstack-signature HMAC", names no form); content/docs/releases/** and packages/*/CHANGELOG.md (release-owned); the deployment docs' #sha256= artifact pin (a different thing); skills/objectstack-automation/evals/** (no eval names the signature: git grep -i "sha256|signature|x-objectstack" -- skills/objectstack-automation/evals is empty).

Done-when readings

Grep set FIVE = the five files above. Trees named by commit.

  • Before (origin/main d8c7d3864): git grep -n "sha256=" -- FIVE → 5 hits, one per file (SKILL.md:351, rule-explanations.ts:1463, validate-flow-trigger-readiness.ts:937, flows/index.ts:1581, automation.json:557).
  • After (this branch): the same grep → 0 hits.
  • Positive control (this branch): git grep -c "v1=" -- FIVE → automation.json 2, flows/index.ts 1, rule-explanations.ts 1, validate-flow-trigger-readiness.ts 1, SKILL.md 1; git grep -c "signHttpBodyAt" -- packages/core/src/security/http-signature.ts → 6.
  • What the wider grep still hits (git grep -c "sha256=" -- skills packages/lint examples docs/qa content/docs packages/triggers packages/core, this branch): webhooks.mdx 5 (outbound contract, kept by the ruling), deployment docs 10 (the #sha256= artifact pin), releases/v17/17-6.mdx 1 (history), packages/core/CHANGELOG.md 1 (release-owned), http-signature.ts 5 + its test 8 and api-trigger.ts 2 + its test 4 (the verifier and its pins — trigger-api: the inbound hook door refuses the body-only sha256= signature, so only the timestamped, replay-protected form verifies (ruling B on #22805, step 3) #22826's). None is a sender-facing inbound-hook text.

skills/** readings (token = ceil(utf8 bytes / 4), the ratchet's convention)

surface before (d8c7d3864) after
skills/objectstack-automation/SKILL.md 5783 tokens / 23132 bytes / 438 lines (ceiling 5785, headroom 2) 5784 tokens / 23135 bytes / 438 lines (ceiling 5785, headroom 1) — check-skills-token-ratchet green
package skills/objectstack-automation/**/*.md 56541 bytes / 1036 lines 56544 bytes / 1036 lines
whole catalog, every skills/**/SKILL.md 210520 bytes / 4409 lines 210523 bytes / 4409 lines

The Signature line grew by 103 bytes and is paid by two same-file deletions of text restated beside it, not by re-wrapping: the api row of the Flow Types table loses "every api flow is bound to its hook endpoint and" (the Inbound webhook section opens with that sentence), and the Queue-backed bullet loses "Requires the queue service (see prerequisite)" (the prerequisites table 25 lines above carries the queue row and its 503). The ceiling is not moved. No eval token names the retired spelling, so evals/** is untouched.

Serial state

PR #22828 (lint one-line verdicts slice 10, the other writer of rule-explanations.ts) landed as d8c7d3864, which is this branch's base. origin/main was merged at 1eff3224d before opening; the incoming commits touch packages/cli, packages/verify, packages/qa and content/docs only, none of the six files.

Verification

Measured on this worktree; the lock figures are shared-box seconds. The lint suite and typecheck ran on 435fd3b3e (the content commit); the merge of origin/main that followed touched no file under packages/lint, packages/spec, packages/formula or packages/sdui-parser, and the derived gate union (74 families, same set as before the merge) was run again on the final head caf9fa094, every exit code recorded as the tool prints it, and reconciled: dispatch-gates --ran: 74 derived famil(ies) accounted for — 72 run, 2 NOT-MEASURED (2 DERIVED from a recorded exit 3).; the only non-zero exits are the two NOT MEASURED prerequisites below and check:platform-checklist, whose red set on this head is byte-identical to the base's.

  • pnpm --filter @objectstack/lint test (vitest run --maxWorkers=2, whole package): Test Files 137 passed (137), Tests 6450 passed | 5 skipped (6455). The two directly affected files first: rule-explanations.test.ts + validate-flow-trigger-readiness.test.ts, 107 passed (107) — this is where the explanation pin (ADR-0041, HMAC, registerFlow, ...) lives.
  • pnpm --filter @objectstack/lint typecheck: tsc --noEmit clean; check:test-typecheck: OK — 2 file(s) / 6 error(s) / 2 pinned signature(s) held (the ledger as committed).
  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 74 families from the six-path change set; each was run in the foreground with its exit code recorded as the tool prints it; first-pass --ran verdict on 435fd3b3e: 74 derived famil(ies) accounted for — 68 run, 6 NOT-MEASURED (6 DERIVED from a recorded exit 3), 0 UNRUN; the final pass on caf9fa094 is quoted above (72 run, 2 NOT-MEASURED, 0 UNRUN). Green among them: check-skills-token-ratchet (+ --self-test), check:skill-docs, check:skill-compatibility, check:skill-frame-sync, check:skill-identifier-liveness, check:doc-authoring, check:nul-bytes, check:pm-governed-merges, check-empty-changeset, check-changeset-no-major, check-adr-0087-registration, check:issue-citations, check:cross-package-test-inputs, check:test-source-alias, and the rest of the list.
  • Dispatch-named gates outside the derived list: pnpm --filter @objectstack/spec run check:skill-refs → 9 generated files in sync; check:skill-examples → exit 0 once @objectstack/client-react (its client-SDK root) was built; its first run was a prerequisite refusal (exit 3, no built output to read), not a finding.
  • NOT MEASURED locally, declared to CI: pnpm check:i18n-coverage (prerequisite: the built CLI; this diff touches no label, translation or metadata form) and pnpm check:dual-build-cjs-loads (prerequisite: all 81 package dists; this diff changes string literals in @objectstack/lint only). The other four exit 3 refusals of the first pass were re-run green once their prerequisite was met: check:docs-transcript-drift (4 declared transcript value(s) across 412 page(s) … equal what the registry derives) and check:doc-formula-expressions after @objectstack/lint was built, check:lean-entry-closure (2 published condition(s) measured from a real load) after @objectstack/objectql was built, and check-plugin-teardown-shape --self-test (48 cases pass) after git fetch --deepen=4000 brought its fixture commit 621a4876… into reach.
  • pnpm check:platform-checklist exits 1 on this branch AND on the untouched base d8c7d3864 with a byte-identical set of 5 unique findings (absent symbol anchors in areas/access-security.json and areas/attachments-storage.json); none names automation.json, which parses (json.load) and carries the bumped revision 3 with its history entry. checklist-status.yml keeps that gate out of per-PR CI; it is a watchdog finding on main, not this PR's.
  • @objectstack/example-showcase: the diff is inside one /** … */ block (comment only), so its typecheck was not run.
  • check:commit-card-trailers (pre-push) is green on every pushed commit: the trailer pair is model-free and no commit carries a card relation; this body is the one carrier.

Acceptance notes

  • docs/qa/platform-checklist/areas/automation.json line 429 (item automation.flow-node-type-matrix's webhook chain step) says "a valid x-objectstack-signature HMAC (secret 'showcase-webhook-secret')" and names no form. It is not one of the five and is left as is; once trigger-api: the inbound hook door refuses the body-only sha256= signature, so only the timestamped, replay-protected form verifies (ruling B on #22805, step 3) #22826 lands, "valid" means the timestamped form by construction, and the showcase comment this step points at now teaches it.
  • The check:platform-checklist reds above are pre-existing on main (symbol anchors pointing at envWideRawViewRows, anonymousFormIntakeOrgScopeRefusal, anonymousFormIntakeReopenRefusal in packages/metadata-protocol/src/protocol.ts and canEdit in packages/services/service-storage/src/attachment-access-hooks.ts, which those files no longer declare). Carrier: the checklist watchdog / whoever renamed those symbols; noted here, not filed.
  • The ratchet's token convention under-prices nothing here: the edit is ASCII apart from one em dash and the arrows already in the file.

维护者速读(草稿)

改了什么。 五处「教发送方怎么给入站 webhook 签名」的文本,从只签请求体的旧写法改为带时间戳的 t=UNIX_SECONDS,v1=HEX 写法(v1 是对 UNIX_SECONDS.RAW_BODY 用流程 secret 做的 HMAC-SHA256,服务端只接受与自身时钟相差 300 秒以内的 t)。五处是:对外发布的 objectstack-automation 技能的 Inbound webhook 一节(Tier H,需要您的 APPROVED)、lint 规则 flow-api-trigger-secret-missing 的提示与 os explain 解释、showcase 示例的注释、平台测试清单里 api 触发的请求配方;另加一个 changeset(@objectstack/lint 与 @objectstack/skills 各 patch)。校验器、出站签名、webhooks.mdx §6.2 一字未动。

为什么改。 #22805 裁决 B(您批「同意」)第 1 步:先让所有教材只教带时间戳的形式,再让入站门拒收旧形式(#22826,被本卡阻塞)。旧形式不含时间,抓到一次请求可以永远重放;新形式是门已经在接受、@objectstack/core 的 signHttpBodyAt 已经在写的形式,教材落后于代码。

风险与代价(含回滚)。 纯文本改动,无行为变化:lint 的判定、规则 id、严重级别不变,整包 137 个测试文件 6450 用例全绿,typecheck 全绿。对外技能文件的 token 棘轮只有 2 的余量,新签名行多出 102 字节,用同文件两处与相邻表格重复的半句话抵掉(未折行、未抬上限),落地后余量 1。代价是下一位编辑该文件的人仍要先删再加。回滚即 revert 本 PR 的单个 squash 提交,无数据、无迁移。

席位意见。 (留空,席位定稿成评论。)

你要做的。 本 PR 含 skills/**,属 Tier H:只需您在 PR 上给一个 APPROVED review(任一提交上、不撤回即可),席位随后负责排队落地;不需要您合并。若您认为技能里那一行的措辞应改(例如要不要保留「Stripe style」的类比),在 review 里写一句即可,席位代改。


Generated by Claude Code

…aches the timestamped x-objectstack-signature form only

The skill's Inbound webhook section, the flow-api-trigger-secret-missing
hint and its os explain entry, the showcase example comment and the
platform checklist's intake recipe teach t=UNIX_SECONDS,v1=HEX — the
HMAC-SHA256 of UNIX_SECONDS.RAW_BODY under the flow's secret, refused
more than 300 seconds from the server clock — and no longer the
body-only form. The outbound contract and the inbound verifier are
unchanged. The skill's token ceiling is paid by two same-file
deletions of text restated beside it.

Claude-Session: https://claude.ai/code/session_011u73oxZ5X95qrARPTeoU6v
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling labels Oct 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • 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 — 4 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 31b5a5f7f51b7a7fd1131299a5b1dbe95910bc4f → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 6c8096cb6667eb61f71549f5e6d4a30e37a52172 — the merge of head caf9fa094761dea1da403431c9b05aabd89ed0c3 into base 31b5a5f7f51b7a7fd1131299a5b1dbe95910bc4f, 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 6c8096cb6667eb61f71549f5e6d4a30e37a52172 && git checkout 6c8096cb6667eb61f71549f5e6d4a30e37a52172
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 31b5a5f7f51b7a7fd1131299a5b1dbe95910bc4f caf9fa094761dea1da403431c9b05aabd89ed0c3 && git checkout -B drift-repro 31b5a5f7f51b7a7fd1131299a5b1dbe95910bc4f && git merge --no-ff caf9fa094761dea1da403431c9b05aabd89ed0c3

node scripts/docs-audit/affected-docs.mjs --json 31b5a5f7f51b7a7fd1131299a5b1dbe95910bc4f

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

维护者速读(终稿)· PR #22846 · #22825

席位 2(session_011u73oxZ5X95qrARPTeoU6v,zhuangjianguo)对照自己读的 diff(对 merge-base 1eff3224d,6 文件 +43/−16)校正 dev 草稿后定稿 · 2026-10-11T14:07Z。

改了什么:按你裁的 B(#22805「同意」)第 1 步,把五处教「入站 webhook 发送方怎么签名」的文本全部改成只教带时间戳的新形式 t=秒级时间戳,v1=HEX(HEX = 用流程 secret 对「时间戳.原始正文」做 HMAC-SHA256;门口拒绝与服务器时钟相差超过 300 秒的 t):对外发布的 objectstack-automation 技能的 Signature 行、lint 规则 flow-api-trigger-secret-missing 的解释与提示、showcase 示例注释、测试清单 automation 项的 api 步骤(修订 2→3,带历史条目)。加 @objectstack/lint、@objectstack/skills 两个 patch changeset。不碰校验器、发送方代码、出站契约 §6.2。

为什么改:旧形式只签正文,截获的请求可以无限重放;新形式已经在门口可用,但所有教发送方的文本还在教旧形式。先把写法改对,再由 #22826 关掉旧形式的入口(它 Blocked-by: 本卡,本 PR 合并即解锁)。

风险与代价(含回滚):纯文本。技能文件 token 余量从 2 降到 1,靠删掉两句与上下文重复的话付账(api 行的「每个 api 流程绑定到它的 hook 端点」由本节首句说过;Queue-backed 行的「需要 queue 服务(见前提)」由前提一节说过)。回滚 = revert 本 PR。

席位意见:ACCEPT。五处与 http-signature.ts 的常量逐字一致(300 秒、时间戳.正文);done-when 的 grep 在 head 上五处零命中旧拼写、每处命中新拼写。契约复核记录(达档、在席)已贴本 PR;CI 在本 head 全绿(34 个 check:31 个 success、3 个按条件 skipped、0 个红;读于 2026-10-11T14:06Z)。顺带一个 dev 量到的旧账(不在本卡):pnpm check:platform-checklist 在 main 上本来就红(5 个符号锚点失效,access-security、attachments-storage 两份清单),按立卡门不立卡(repo 门禁不是公开入口),记入 Acceptance notes,承接者 = devx @ objectstack 席的下一次清单巡检(座位贴 #6023,现空席)与每周清单发布;124 张 open 卡按标题查重零命中;轮报里点给你。

你要做的:同意即给一个 APPROVED review;落地由席位走队列。


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: caf9fa094761dea1da403431c9b05aabd89ed0c3
Local-runs: none

Reviewed by the skills seat 2 in seat (session_011u73oxZ5X95qrARPTeoU6v, served model equal to the constant's value at get_session, re-read for this record), on the diff of head caf9fa094 against its merge base 1eff3224d fetched from origin (six files, +43/−16), the card #22825 with its triage note and the dev report (6109634551), the ruling 6108492902 on #22805, and the head's check-runs. Written 2026-10-11T14:09Z. Read from the customer seat that installs the whole objectstack-automation skill, not from the author's.

① Derived judgments

  • Face touched: the published skill skills/objectstack-automation/SKILL.md, three lines. The Inbound webhook section's Signature line now teaches t=UNIX_SECONDS,v1=HEX, v1 the HMAC-SHA256 of UNIX_SECONDS.RAW_BODY under secret, refused when t is over 300 s from the server clock. Right: packages/core/src/security/http-signature.ts on origin/main exports HTTP_SIGNATURE_TOLERANCE_SECONDS = 300, signHttpBodyAt writes exactly that header value from timestampSeconds and the HMAC of timestampSeconds.body, and TIMESTAMPED_FORM accepts that shape; the ruling's step 1 asks for this form only. The body-only spelling is gone from the file.
  • The two same-file deletions that pay the token ratchet (the dev reads headroom 2 to 1; CI's ratchet check is the judge): the api row's clause "every api flow is bound to its hook endpoint and" restates the section opener "An api flow is bound to an inbound HTTP endpoint"; the Queue-backed bullet's "Requires the queue service (see prerequisite)" restates the Prerequisite section (its capability table carries the row queue, the inbound-webhook consumer, whose absence answers 503, and its requires example lists 'queue'). Content deletions of restated text, no re-wrap; no teaching lost. Lines 438 to 438.
  • Density, from the customer seat: the skill's one sender-facing line now matches what the door accepts and what trigger-api: the inbound hook door refuses the body-only sha256= signature, so only the timestamped, replay-protected form verifies (ruling B on #22805, step 3) #22826 will make the only accepted form; an author copying it signs a post the door verifies; nothing else in the bundle is re-taught.
  • The four positions outside skills/** (the flow-api-trigger-secret-missing explanation paragraph and hint string in packages/lint, the showcase flow's doc comment, the checklist item's api step with revision 3 and a history entry naming inbound webhook guidance: every place that teaches a sender teaches the timestamped t=…,v1=… signature only (ruling B on #22805, step 1) #22825) say the same thing as the code; the lint rule's id, severity, verdict and judgment are unchanged (the diff touches the hint string and one explanation paragraph only). Prose faces outside the review set, read sentence by sentence here and in the ACCEPT.
  • No accept set and no public surface moves: no verifier, sender, schema or gate is touched; webhooks.mdx §6.2, packages/core/**, packages/services/** and packages/triggers/** are untouched. Clause-②: no is correct. The done-when grep at the head: sha256= 0 hits over the five files; positive control v1= present in each of the five, signHttpBodyAt still in core.

② Semver level

@objectstack/lint patch and @objectstack/skills patch in .changeset/22825-inbound-hook-timestamped-guidance.md, correct: both packages publish (private: false); the lint package ships the changed strings and @objectstack/skills ships skills/**; @objectstack/example-showcase is private and docs/qa is no package. The changeset prose was read sentence by sentence against the diff: every sentence is true of the diff; "Nothing to migrate for an author" and "the inbound door's accept set is not changed by this release" state the boundary the ruling draws. Clause-②: no matches.

③ Boundary flags

Implemented-by: claude/issue-22825-inbound-hook-timestamped-guidance
Reviewed-by: session_011u73oxZ5X95qrARPTeoU6v

VERDICT: PASS


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review October 11, 2026 14:14
@os-zhuang
os-zhuang enabled auto-merge October 11, 2026 14:14
@os-zhuang
os-zhuang added this pull request to the merge queue Oct 11, 2026
Merged via the queue into main with commit eed637c Oct 11, 2026
43 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-22825-inbound-hook-timestamped-guidance branch October 11, 2026 14:40
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

inbound webhook guidance: every place that teaches a sender teaches the timestamped t=…,v1=… signature only (ruling B on #22805, step 1)

3 participants