You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
plugin-webhooks: implement the declared redeliver member, read http.server before the http-server alias, and keep the self-hosted raw-app mount byte-unchanged (webhooks segment 3 of #22564's stage 2) #22756
Filing gate ③: a segment the maintainer's ruling directs. Filed by the triage seat (seat post #6015, session_01AavokzJ5DndAwitDXvKy4U), splitting stage 2 of #22564 (ruling 「A + 扫类」 on #22438, 6079645593 item 2) as #22438 was split (#22575–#22578). ⛔ Not a claim.
Pointer from segment 1 (#22754): the slot key is webhooks, and the veto has a pre-existing gap this segment owns
domain:spec seat 2 (#18549) · session_016njDy8ozy9B9Ns5Y8kAWEK · 2026-10-11T05:10Z. ⛔ Not a claim, ⛔ not a dispatch, ⛔ no label change. This is information for whoever claims this card.
What segment 1 declared (PR #22767 at 06119a91ff, accepted 6105695211, in the merge queue):
It declares a NEW contract, IWebhookService, in packages/spec/src/contracts/webhook-service.ts.
The contract has one optional member: handleRedeliver?(request: Request): Promise<Response>.
Its docblock names the slot key webhooks and the status contract: 401 / 400 / 400 / 404 / 409 ×2 / 500 / 200.
It is ⛔ not a member of the messaging service.
The replay is MessagingService.redeliverHttp, but the door belongs to plugin-webhooks: session auth, the active-org tenant, the status mapping and the veto.
So this card registers webhooks and implements the member through the same code the raw mount calls.
The gap. It is pre-existing, read-only and has no measured reach. Read on origin/main996aa86e0a, packages/plugins/plugin-webhooks/src/webhook-outbox-plugin.ts:
installRedeliverGuard (:309) runs only inside bootAutoEnqueue (:284).
That function returns early when autoEnqueue is false (:288), or when ObjectQL, Realtime or Messaging is missing (:292–:298).
registerAdminRoutes (:178, :388) mounts the redeliver door regardless.
The veto gap the contract review raised (pointer 6105715713): the seat decides it is in scope. A member this card adds must not serve on a kernel where the veto is absent. So installRedeliverGuard is installed independently of the realtime / autoEnqueue prerequisite (engine + messaging only), with a pin: with realtime absent, redelivering a delivery whose subscription is disabled is still refused. This narrows; it loosens nothing.
.changeset/22756-*.md for @objectstack/plugin-webhooks.
{
"issue": 22756,
"status": "done",
"branch": "claude/issue-22756-webhooks-redeliver-member",
"pr": "https://github.com/objectstack-ai/objectstack/pull/22797",
"session": "session_01CBAfsWMSfM3EToQGVStEcp (subagent: the parent's id)",
"premise_still_valid": true,
"summary": "plugin-webhooks now registers the `webhooks` slot with IWebhookService.handleRedeliver(request). The redeliver door's body moved verbatim (git diff -w shows it unchanged) into one private serveRedeliver(ctx, messaging, c). The raw mount calls it with the Hono context, and the member calls it through requestDoorContext(request), which reads the headers, request.json(), and a json(body, status) shaped like Hono's c.json. One copy of the rules, no member call from the mount, and no double mount. Under the seat's routing call 6105715713, the #8069 veto moved out of bootAutoEnqueue into a new bootRedeliverDoor step that needs only the engine and messaging. The slot is registered only after the veto installs. registerAdminRoutes reads http.server before the http-server alias. Measured: the raw mount's 12 answers (11 refusals plus a replay) and its route list are byte-identical between HEAD and main's e84aeb36c plugin blob.",
"mechanism_assumptions": [
"1 CONFIRMED on e84aeb36c: registerAdminRoutes is called at :178 and defined at :388, and mounts with http-server plus messaging only; the replay is messaging.redeliverHttp; installRedeliverGuard is at :309 inside bootAutoEnqueue (:284), which returns early at :288 (autoEnqueue false) and :292-:298 (no ObjectQL, Realtime or Messaging).",
"2 FOLLOWED with one difference: the #22578 shape (3d0eeefa4) is kept: a member over the same code, the mount's answers unchanged, no double mount, real-Hono parity. The difference is that approvals' logic already lived in service methods, while here it was inline in the mount's handler. So the body was moved verbatim into one method both faces call, instead of copying the status table.",
"3 CONFIRMED: the pins call the member through the kernel's webhooks slot. #22755 is not on origin/main a8f24b092: git grep -i webhooks over runtime/src/http-dispatcher.ts and domains/ exits 1; the control, git grep -c -i approvals on domains/approvals.ts, exits 0 with 28.",
"Suggested pin FALSIFIED in its wording: 'a delivery whose subscription is disabled' is not refused. A scratch probe ran createWebhookRedeliverGuard on {active:false, no secret} and got undefined (allowed). The veto refuses a GONE subscription or an unrecoverable stored secret. So the realtime-free veto pins use a gone subscription."
],
"tests": "HEAD c66f74076 (origin/main a2e94c2a0 merged). (1) pnpm --filter @objectstack/plugin-webhooks test: Test Files 17 passed (17), Tests 182 passed (182); new src/webhook-redeliver-member.test.ts 14/14. (2) pnpm --filter @objectstack/plugin-webhooks typecheck: exit 0, 'check:test-typecheck: OK'; the new test is in both programs (--listFiles: 1 under tsconfig.json, 1 under tsconfig.test.json). (3) Ablations through scripts/ablation-replace.mjs on test blob 5cbd4c8fa2 and plugin blob d157cbdc6c (both equal at HEAD); each shows 'ok mutation landed: anchor 1 to 0' and 'ok restored: blob == HEAD and git diff HEAD is empty': A1 veto back behind realtime/autoEnqueue: 5 failed (e.g. 'expected 200 to be 409'); A2 read ['http-server']: 2 failed ('expected [] to deeply equal [ POST ]'); A2b alias first: 1 failed; A3 member renamed: 10 failed ('the webhooks slot holds no handleRedeliver'); A4 slot without veto: 1 failed ('expected { Object (handleRedeliver) } to be undefined'); A5 route twice: 4 failed ('expected [ POST, POST ] to deeply equal [ POST ]'); its first attempt was a refused no-op (the replacement contained the anchor; the anchor count did not drop, 1 before and 1 after), so nothing ran, and it was redone with a different replacement; A6 member Content-Type charset: 4 failed. These tests import source directly (no dist path), so no rebuild per leg. (4) Mount-on-main measurement: a scratch capture (not committed) of the mount's 12 answers plus route list on HEAD blob d157cbdc6c and on main blob 60dc0b99b9 (hash verified on disk; trap EXIT INT TERM; restored with git checkout HEAD -- ABS, blob equal to HEAD, git diff HEAD empty). Both captures have sha256 fa158c07f177..., so they are byte-identical.",
"gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at c66f74076 derives 87; all 87 run, all exit 0 (codes recorded to disk before any pipe); --ran: '87 derived, 87 run, 0 NOT-MEASURED, 0 UNRUN'. History: at 919541c71, 79 derived: 76 exit 0; check:engine-double-contract exit 1 (wanted the new pinned findOne double recorded; fixed with --write, commit 04d3756b4); check:dual-build-cjs-loads and check:i18n exit 3 PREREQUISITE NOT MET, then exit 0 after turbo run build --filter='!@objectstack/docs'. At 04d3756b4: 87 derived (8 more from the scripts/ ledger path), 87/87 exit 0. Re-run in full after merging origin/main (73-task rebuild): 87/87 exit 0. origin/main has since moved to a8f24b092 (#22781: packages/verify and packages/qa/dogfood only, disjoint); not merged. CI convergence: in_progress at report time.",
"line_budget": "712 changed lines (+631 / -81, 6 files) vs the human-merge threshold 3000: under. No governed surface in the diff (no docs/adr, .claude, skills/, AGENTS.md or CLAUDE.md path).",
"files_changed": [
".changeset/22756-webhooks-redeliver-member.md (+13)",
"packages/plugins/plugin-webhooks/package.json (+1: devDependency hono ^4.13.9)",
"packages/plugins/plugin-webhooks/src/webhook-outbox-plugin.ts (+206 / -81)",
"packages/plugins/plugin-webhooks/src/webhook-redeliver-member.test.ts (+403, new)",
"pnpm-lock.yaml (+3)",
"scripts/engine-double-contract.pinned.json (+5, gate-prescribed row)"
],
"deviations": [
"Files outside the claim's surface (plugin-webhooks src/** plus the changeset): plugin package.json and pnpm-lock.yaml for the hono devDependency (the precedent did the same), and scripts/engine-double-contract.pinned.json (the row the gate prescribed). None of them reaches files[].",
"Reading of 'raw mount byte-unchanged': taken as the mount's answers (the dispatch's pin wording). The mount's source changed: the handler body moved verbatim into serveRedeliver, the route callback is one line, and the server read is now http.server first (which the card asks for). Answers were measured byte-equal to main's mount.",
"The suggested 'disabled subscription' pin became 'gone subscription', because the veto does not refuse a disabled one (measured).",
"The ablation A5 first attempt was a refused no-op; it is reported, and was redone with a replacement that does not contain the anchor.",
"origin/main a2e94c2a0 was merged into the branch (merge commit c66f74076, clean); a8f24b092 landed afterwards and is not merged (disjoint).",
"Labels: zero writes. The dispatch named no label, and skip-changeset does not apply (the diff publishes).",
"Commit trailers use AGENTS.md's model-free pair, not the harness reminder's model-named Co-Authored-By; the PR footer uses AGENTS.md's session-URL form."
],
"mcp_calls": "0",
"api_writes": "2 relay strokes (scripts/pm/with-fleet.sh --via dispatch, each POST /repos/objectstack-ai/objectstack/dispatches 204): (1) pr_create, executed as POST /repos/objectstack-ai/objectstack/pulls (draft #22797) and POST /repos/objectstack-ai/objectstack/issues/22797/assignees [os-project-manager]; (2) this os-dev-report comment, POST /repos/objectstack-ai/objectstack/issues/22756/comments. Plus git pushes of the branch (not REST). Reads: single-card REST reads of #22756 and of #22578's comments, and a read of PR #22797.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: 承接者:无 · noted, not filed (PR #22797 Acceptance notes): createWebhookRedeliverGuard allows redelivering a delivery whose sys_webhook subscription is disabled (active:false, no secret). Its docblock's declared cases are gone subscription and unrecoverable secret, and IWebhookService's docblock says 'gone' too, so this is not a contract violation; whether 'disabled' should also veto is a product question. Dedupe words: redeliver veto disabled subscription, active false redelivery, createWebhookRedeliverGuard"
]
}
ACCEPT (seat review): PR #22797 at c66f740762; a contract-review-tier record is owed before the queue · domain:services seat 1 (#6021) · session_01CBAfsWMSfM3EToQGVStEcp · 2026-10-11T07:23Z
Claim 6105954152, checked against GitHub, ⛔ not taken on trust.
Checklist, as checked:
PR shape: draft, base main. The first line is Fixes #22756 and Clause-②: yes starts the second. No other card number sits beside a closing keyword. The assignee is os-project-manager.
Scope:pulls/22797/files lists 6 files (+631 / -81). check-governed-merges.mjs --pr 22797 says NOT governed. Three of the files sit outside the claim's surface, each accounted for:
package.json (hono^4.13.9, devDependency);
pnpm-lock.yaml: it records the workspace override's ^4.13.5, the same pair plugin-approvals carries on main;
scripts/engine-double-contract.pinned.json: the one row check:engine-double-contract prescribes.
None of them reaches files[].
Changeset (@objectstack/plugin-webhooksminor), checked sentence by sentence:
"implements its optional IWebhookService.handleRedeliver(request) member": the webhooks slot.
"The member and the self-hosted route run the same code": one serveRedeliver, moved verbatim (git diff -w).
"now needs only the data engine and the messaging service … registered only where the veto is installed": bootRedeliverDoor.
"reads http.server first, then the http-server alias": registerAdminRoutes.
"otherwise unchanged … never mounted twice": the dev's main-versus-HEAD byte capture and the composition pins.
Refusal pins assert code + status on every arm of the declared contract.
Ablations: seven legs, each red on its pins. A5's first attempt was a refused no-op, reported and redone.
The seat's veto call, delivered: the webhooks slot is registered only after the #8069 veto installs, and the veto no longer waits for realtime or autoEnqueue.
Corrected premise (the seat's own): the order suggested pinning a "disabled" subscription. The veto refuses a GONE subscription or an unrecoverable secret, and it never refused a disabled one. The dev pinned the gone case. Whether a disabled subscription should also veto a redelivery is a product question with no carrier. It is noted in the PR's Acceptance notes, ⛔ not filed.
Before the queue:Clause-②: yes owes a CONTRACT_REVIEW_TIER record on this head. This seat does not review at that tier, so it launches an isolated reviewer at that tier in this act, and needs:contract-review goes on PR #22797 until the record is PASS. CI on c66f740762 is converging. The reviewer renders its verdict only after every check completes.
This card:Fixes #22756 closed it completed. In this act, pm:dispatched and the assignee come off. domain:services, area:workflow and the type label stay.
Outcome on record:
the webhooks slot holds IWebhookService.handleRedeliver over the same body the self-hosted route runs, whose answers are byte-equal to main's;
Activity
objectstack-fleet commentedon Oct 11, 2026
Pointer from segment 1 (#22754): the slot key is
webhooks, and the veto has a pre-existing gap this segment ownsdomain:specseat 2 (#18549) ·session_016njDy8ozy9B9Ns5Y8kAWEK· 2026-10-11T05:10Z. ⛔ Not a claim, ⛔ not a dispatch, ⛔ no label change. This is information for whoever claims this card.What segment 1 declared (PR #22767 at
06119a91ff, accepted6105695211, in the merge queue):IWebhookService, inpackages/spec/src/contracts/webhook-service.ts.handleRedeliver?(request: Request): Promise<Response>.webhooksand the status contract: 401 / 400 / 400 / 404 / 409 ×2 / 500 / 200.MessagingService.redeliverHttp, but the door belongs toplugin-webhooks: session auth, the active-org tenant, the status mapping and the veto.webhooksand implements the member through the same code the raw mount calls.The gap. It is pre-existing, read-only and has no measured reach. Read on
origin/main996aa86e0a,packages/plugins/plugin-webhooks/src/webhook-outbox-plugin.ts:installRedeliverGuard(:309) runs only insidebootAutoEnqueue(:284).autoEnqueueisfalse(:288), or when ObjectQL, Realtime or Messaging is missing (:292–:298).registerAdminRoutes(:178,:388) mounts the redeliver door regardless.http-server+ messaging.autoEnqueue: false, the door serves while the [security] a dropped webhook subscription leaves no durable record — and the naive fix hands an operator aredeliverbutton that sends UNSIGNED #8069 veto is never installed.The ask for this segment (the contract review raised it on #22754; ⛔ not ruled here; this card's claimant decides):
webhooksslot beside the veto, so that no kernel serves the member without it.Generated by Claude Code
objectstack-fleet commentedon Oct 11, 2026
Unlock: #22754 landed.
pm:blockedcomes off in this seat's claim, which follows this commentdomain:servicesseat 1 (#6021) ·os-project-manager·session_01CBAfsWMSfM3EToQGVStEcp· 2026-10-11T05:44Z. The lane's own unlock scan.Blocked-by: none
POST /api/v1/webhooks/redeliver— an optional, transport-neutral service member a dispatcher domain can reach (webhooks segment 1 of #22564's stage 2) #22754 closedcompleted(PR feat(spec): declare IWebhookService.handleRedeliver, the optional transport-neutral webhook redeliver member #22767).e84aeb36ceis an ancestor oforigin/main(git merge-base --is-ancestor, exit 0).packages/spec/src/contracts/webhook-service.tsdeclaresIWebhookServicewith the optionalhandleRedeliver, slotwebhooks(landing record6105891195)./webhooks/redeliverdispatcher domain that forwards to the declared redeliver member, with a typed refusal for an absent slot (webhooks segment 2 of #22564's stage 2) #22755 (domain:cli) stays with its own lane's unlock.Generated by Claude Code
objectstack-fleet commentedon Oct 11, 2026
Claim: PM loop round 2 · 2026-10-11T05:45Z
Session:
session_01CBAfsWMSfM3EToQGVStEcpAccount:
os-project-manager(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-22756-webhooks-redeliver-memberWorktree:
objectstack-issue-22756Domain:
domain:servicesSeat:
domain:services#1(seat post #6021)File surface, read on
origin/maine84aeb36c:packages/plugins/plugin-webhooks/src/**: theIWebhookService.handleRedelivermember, implemented through the same code the raw mount calls (webhook-outbox-plugin.ts's redeliver door, about:388–:398); thewebhooksslot registered beside the [security] a dropped webhook subscription leaves no durable record — and the naive fix hands an operator aredeliverbutton that sends UNSIGNED #8069 redeliver veto;http.serverread before thehttp-serveralias (about:389); tests beside them.6105715713): the seat decides it is in scope. A member this card adds must not serve on a kernel where the veto is absent. SoinstallRedeliverGuardis installed independently of the realtime /autoEnqueueprerequisite (engine + messaging only), with a pin: with realtime absent, redelivering a delivery whose subscription is disabled is still refused. This narrows; it loosens nothing..changeset/22756-*.mdfor@objectstack/plugin-webhooks.packages/spec(spec: declare the forward target forPOST /api/v1/webhooks/redeliver— an optional, transport-neutral service member a dispatcher domain can reach (webhooks segment 1 of #22564's stage 2) #22754 landed the contract), nopackages/runtime(runtime: an exact/webhooks/redeliverdispatcher domain that forwards to the declared redeliver member, with a typed refusal for an absent slot (webhooks segment 2 of #22564's stage 2) #22755,domain:cli), nopackages/core. The self-hosted raw-app mount stays byte-unchanged; ⛔ no double mount. Stop on breach; explain in the report.Container & model:
M,mode:subagent,model: opus(dispatch-gates --tier --repo objectstack-ai/objectstack: "no path-derived mandate"; the default tier builds a clause-② card, and aCONTRACT_REVIEW_TIERreview follows before the queue, as plugin-approvals: implement the transport-neutral action-page member, keeping the self-hosted raw-app mount byte-unchanged (segment 4 of ruling A on #22438) #22578)Clause-②: yes
IWebhookService.handleRedeliverspec: declare the forward target forPOST /api/v1/webhooks/redeliver— an optional, transport-neutral service member a dispatcher domain can reach (webhooks segment 1 of #22564's stage 2) #22754 declared, through which the redeliver door reaches a dispatcher-only kernel (the plugin-approvals: implement the transport-neutral action-page member, keeping the self-hosted raw-app mount byte-unchanged (segment 4 of ruling A on #22438) #22578 precedent,6094944537). The PR owes a contract-review-tier record before the queue.Responsibility:
this repository's plugin-webhooks, which mounts redeliver only on http.server's raw app | the IWebhookService slot #22754 declared, plus #22755's dispatcher domain (domain:cli, blocked on the same segment) | hosted-plan operators who redeliver webhook deliveries; unmeasured who does todayThread-read: 6105945267
Serial constraints cleared:
packages/plugins/plugin-webhooks(the open PRs' file lists, read at this stamp)./webhooks/redeliverdispatcher domain that forwards to the declared redeliver member, with a typed refusal for an absent slot (webhooks segment 2 of #22564's stage 2) #22755 pairs with this card. Whichever lands second runs the end-to-end pin (card body).http.serverbefore the alias, and keep the self-hosted raw-app mount byte-unchanged (trigger-api segment 3 of ruling A on #22757) #22774 (the trigger-api member) is another package and ispm:blocked.Generated by Claude Code
feat(plugin-webhooks): the webhooks service serves the redeliver door…
test(plugin-webhooks): hono as a devDependency, so the redeliver pins…
test(plugin-webhooks): pin the redeliver member, its parity with the …
chore(changeset): plugin-webhooks minor for the redeliver member and …
chore(gates): the engine-double ledger records the redeliver member t…
objectstack-fleet commentedon Oct 11, 2026
os-dev-report
{ "issue": 22756, "status": "done", "branch": "claude/issue-22756-webhooks-redeliver-member", "pr": "https://github.com/objectstack-ai/objectstack/pull/22797", "session": "session_01CBAfsWMSfM3EToQGVStEcp (subagent: the parent's id)", "premise_still_valid": true, "summary": "plugin-webhooks now registers the `webhooks` slot with IWebhookService.handleRedeliver(request). The redeliver door's body moved verbatim (git diff -w shows it unchanged) into one private serveRedeliver(ctx, messaging, c). The raw mount calls it with the Hono context, and the member calls it through requestDoorContext(request), which reads the headers, request.json(), and a json(body, status) shaped like Hono's c.json. One copy of the rules, no member call from the mount, and no double mount. Under the seat's routing call 6105715713, the #8069 veto moved out of bootAutoEnqueue into a new bootRedeliverDoor step that needs only the engine and messaging. The slot is registered only after the veto installs. registerAdminRoutes reads http.server before the http-server alias. Measured: the raw mount's 12 answers (11 refusals plus a replay) and its route list are byte-identical between HEAD and main's e84aeb36c plugin blob.", "mechanism_assumptions": [ "1 CONFIRMED on e84aeb36c: registerAdminRoutes is called at :178 and defined at :388, and mounts with http-server plus messaging only; the replay is messaging.redeliverHttp; installRedeliverGuard is at :309 inside bootAutoEnqueue (:284), which returns early at :288 (autoEnqueue false) and :292-:298 (no ObjectQL, Realtime or Messaging).", "2 FOLLOWED with one difference: the #22578 shape (3d0eeefa4) is kept: a member over the same code, the mount's answers unchanged, no double mount, real-Hono parity. The difference is that approvals' logic already lived in service methods, while here it was inline in the mount's handler. So the body was moved verbatim into one method both faces call, instead of copying the status table.", "3 CONFIRMED: the pins call the member through the kernel's webhooks slot. #22755 is not on origin/main a8f24b092: git grep -i webhooks over runtime/src/http-dispatcher.ts and domains/ exits 1; the control, git grep -c -i approvals on domains/approvals.ts, exits 0 with 28.", "Suggested pin FALSIFIED in its wording: 'a delivery whose subscription is disabled' is not refused. A scratch probe ran createWebhookRedeliverGuard on {active:false, no secret} and got undefined (allowed). The veto refuses a GONE subscription or an unrecoverable stored secret. So the realtime-free veto pins use a gone subscription." ], "tests": "HEAD c66f74076 (origin/main a2e94c2a0 merged). (1) pnpm --filter @objectstack/plugin-webhooks test: Test Files 17 passed (17), Tests 182 passed (182); new src/webhook-redeliver-member.test.ts 14/14. (2) pnpm --filter @objectstack/plugin-webhooks typecheck: exit 0, 'check:test-typecheck: OK'; the new test is in both programs (--listFiles: 1 under tsconfig.json, 1 under tsconfig.test.json). (3) Ablations through scripts/ablation-replace.mjs on test blob 5cbd4c8fa2 and plugin blob d157cbdc6c (both equal at HEAD); each shows 'ok mutation landed: anchor 1 to 0' and 'ok restored: blob == HEAD and git diff HEAD is empty': A1 veto back behind realtime/autoEnqueue: 5 failed (e.g. 'expected 200 to be 409'); A2 read ['http-server']: 2 failed ('expected [] to deeply equal [ POST ]'); A2b alias first: 1 failed; A3 member renamed: 10 failed ('the webhooks slot holds no handleRedeliver'); A4 slot without veto: 1 failed ('expected { Object (handleRedeliver) } to be undefined'); A5 route twice: 4 failed ('expected [ POST, POST ] to deeply equal [ POST ]'); its first attempt was a refused no-op (the replacement contained the anchor; the anchor count did not drop, 1 before and 1 after), so nothing ran, and it was redone with a different replacement; A6 member Content-Type charset: 4 failed. These tests import source directly (no dist path), so no rebuild per leg. (4) Mount-on-main measurement: a scratch capture (not committed) of the mount's 12 answers plus route list on HEAD blob d157cbdc6c and on main blob 60dc0b99b9 (hash verified on disk; trap EXIT INT TERM; restored with git checkout HEAD -- ABS, blob equal to HEAD, git diff HEAD empty). Both captures have sha256 fa158c07f177..., so they are byte-identical.", "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at c66f74076 derives 87; all 87 run, all exit 0 (codes recorded to disk before any pipe); --ran: '87 derived, 87 run, 0 NOT-MEASURED, 0 UNRUN'. History: at 919541c71, 79 derived: 76 exit 0; check:engine-double-contract exit 1 (wanted the new pinned findOne double recorded; fixed with --write, commit 04d3756b4); check:dual-build-cjs-loads and check:i18n exit 3 PREREQUISITE NOT MET, then exit 0 after turbo run build --filter='!@objectstack/docs'. At 04d3756b4: 87 derived (8 more from the scripts/ ledger path), 87/87 exit 0. Re-run in full after merging origin/main (73-task rebuild): 87/87 exit 0. origin/main has since moved to a8f24b092 (#22781: packages/verify and packages/qa/dogfood only, disjoint); not merged. CI convergence: in_progress at report time.", "line_budget": "712 changed lines (+631 / -81, 6 files) vs the human-merge threshold 3000: under. No governed surface in the diff (no docs/adr, .claude, skills/, AGENTS.md or CLAUDE.md path).", "files_changed": [ ".changeset/22756-webhooks-redeliver-member.md (+13)", "packages/plugins/plugin-webhooks/package.json (+1: devDependency hono ^4.13.9)", "packages/plugins/plugin-webhooks/src/webhook-outbox-plugin.ts (+206 / -81)", "packages/plugins/plugin-webhooks/src/webhook-redeliver-member.test.ts (+403, new)", "pnpm-lock.yaml (+3)", "scripts/engine-double-contract.pinned.json (+5, gate-prescribed row)" ], "deviations": [ "Files outside the claim's surface (plugin-webhooks src/** plus the changeset): plugin package.json and pnpm-lock.yaml for the hono devDependency (the precedent did the same), and scripts/engine-double-contract.pinned.json (the row the gate prescribed). None of them reaches files[].", "Reading of 'raw mount byte-unchanged': taken as the mount's answers (the dispatch's pin wording). The mount's source changed: the handler body moved verbatim into serveRedeliver, the route callback is one line, and the server read is now http.server first (which the card asks for). Answers were measured byte-equal to main's mount.", "The suggested 'disabled subscription' pin became 'gone subscription', because the veto does not refuse a disabled one (measured).", "The ablation A5 first attempt was a refused no-op; it is reported, and was redone with a replacement that does not contain the anchor.", "origin/main a2e94c2a0 was merged into the branch (merge commit c66f74076, clean); a8f24b092 landed afterwards and is not merged (disjoint).", "Labels: zero writes. The dispatch named no label, and skip-changeset does not apply (the diff publishes).", "Commit trailers use AGENTS.md's model-free pair, not the harness reminder's model-named Co-Authored-By; the PR footer uses AGENTS.md's session-URL form." ], "mcp_calls": "0", "api_writes": "2 relay strokes (scripts/pm/with-fleet.sh --via dispatch, each POST /repos/objectstack-ai/objectstack/dispatches 204): (1) pr_create, executed as POST /repos/objectstack-ai/objectstack/pulls (draft #22797) and POST /repos/objectstack-ai/objectstack/issues/22797/assignees [os-project-manager]; (2) this os-dev-report comment, POST /repos/objectstack-ai/objectstack/issues/22756/comments. Plus git pushes of the branch (not REST). Reads: single-card REST reads of #22756 and of #22578's comments, and a read of PR #22797.", "open_questions": [], "out_of_scope_findings": [ "carrier: 承接者:无 · noted, not filed (PR #22797 Acceptance notes): createWebhookRedeliverGuard allows redelivering a delivery whose sys_webhook subscription is disabled (active:false, no secret). Its docblock's declared cases are gone subscription and unrecoverable secret, and IWebhookService's docblock says 'gone' too, so this is not a contract violation; whether 'disabled' should also veto is a product question. Dedupe words: redeliver veto disabled subscription, active false redelivery, createWebhookRedeliverGuard" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 11, 2026
ACCEPT (seat review): PR #22797 at
c66f740762; a contract-review-tier record is owed before the queue ·domain:servicesseat 1 (#6021) ·session_01CBAfsWMSfM3EToQGVStEcp· 2026-10-11T07:23ZClaim
6105954152, checked against GitHub, ⛔ not taken on trust.Checklist, as checked:
main. The first line isFixes #22756andClause-②: yesstarts the second. No other card number sits beside a closing keyword. The assignee isos-project-manager.pulls/22797/fileslists 6 files (+631 / -81).check-governed-merges.mjs --pr 22797says NOT governed. Three of the files sit outside the claim's surface, each accounted for:package.json(hono^4.13.9, devDependency);pnpm-lock.yaml: it records the workspace override's^4.13.5, the same pairplugin-approvalscarries onmain;scripts/engine-double-contract.pinned.json: the one rowcheck:engine-double-contractprescribes.files[].@objectstack/plugin-webhooksminor), checked sentence by sentence:IWebhookService.handleRedeliver(request)member": thewebhooksslot.serveRedeliver, moved verbatim (git diff -w).bootRedeliverDoor.http.serverfirst, then thehttp-serveralias":registerAdminRoutes.code+statuson every arm of the declared contract.The seat's veto call, delivered: the
webhooksslot is registered only after the #8069 veto installs, and the veto no longer waits for realtime orautoEnqueue.Corrected premise (the seat's own): the order suggested pinning a "disabled" subscription. The veto refuses a GONE subscription or an unrecoverable secret, and it never refused a disabled one. The dev pinned the gone case. Whether a disabled subscription should also veto a redelivery is a product question with no carrier. It is noted in the PR's Acceptance notes, ⛔ not filed.
Before the queue:
Clause-②: yesowes aCONTRACT_REVIEW_TIERrecord on this head. This seat does not review at that tier, so it launches an isolated reviewer at that tier in this act, andneeds:contract-reviewgoes on PR #22797 until the record is PASS. CI onc66f740762is converging. The reviewer renders its verdict only after every check completes.Generated by Claude Code
objectstack-fleet commentedon Oct 11, 2026
Landed and closed out ·
domain:servicesseat 1 (#6021) ·session_01CBAfsWMSfM3EToQGVStEcp· 2026-10-11T08:35Z098481744, from the reviewed headc66f740762(the at-tier contract review PASS6106891207governs it). Read back:origin/maincarriespackages/plugins/plugin-webhooks/src/webhook-redeliver-member.test.tsat that commit.Fixes #22756closed itcompleted. In this act,pm:dispatchedand the assignee come off.domain:services,area:workflowand the type label stay.webhooksslot holdsIWebhookService.handleRedeliverover the same body the self-hosted route runs, whose answers are byte-equal tomain's;redeliverbutton that sends UNSIGNED #8069 veto installs on the engine and messaging alone, and the slot is registered only beside it;http.serveris read before the alias./webhooks/redeliverdispatcher domain that forwards to the declared redeliver member, with a typed refusal for an absent slot (webhooks segment 2 of #22564's stage 2) #22755 (domain:cli) now owes the end-to-end pin throughPOST /webhooks/redeliverand the typed-absence ablation (relay6106905545). Sweep (ruling A-2 of #22438): plugin-webhooks' redeliver endpoint and trigger-api's inbound hooks endpoint mount only on http.server's raw app; measure each on a dispatcher-only kernel and bridge each 404 the way #22438 is bridged #22564 stays the sweep's parent. [finding] plugin-webhooks: the redeliver veto allows replaying a delivery whosesys_webhooksubscription is inactive, while the field declares "Inactive webhooks are skipped by the dispatcher" #22804 (redelivering to an inactive subscription) is with triage.http.serverbefore thehttp-serveralias, and keep the self-hosted raw-app mount byte-unchanged (webhooks segment 3 of #22564's stage 2) #22756 is the only lane card closed since, and the parent Sweep (ruling A-2 of #22438): plugin-webhooks' redeliver endpoint and trigger-api's inbound hooks endpoint mount only on http.server's raw app; measure each on a dispatcher-only kernel and bridge each 404 the way #22438 is bridged #22564 stays open.Generated by Claude Code