Skip to content

feat(webhook): pin local-webhook 0.10.0 — standing watches stop duplicating owned work - #171

Merged
defangdevs merged 1 commit into
masterfrom
feat/webhook-0.10.0-pin
Aug 3, 2026
Merged

feat(webhook): pin local-webhook 0.10.0 — standing watches stop duplicating owned work#171
defangdevs merged 1 commit into
masterfrom
feat/webhook-0.10.0-pin

Conversation

@defangdevs

Copy link
Copy Markdown
Owner

Companion to defangdevs/local-channels#11 (merged as efa2531), which closes defangdevs/local-channels#10.

Motivation

This box hit the same failure twice on 2026-08-02: five hook-* sessions spawned for CI on PRs a session was already driving — two while #168 went through CI, three more when merging #168 and #169 put CI on master. Three of the four hook slots went with them, from two documentation merges. Nothing was misconfigured: CI-outcome events bypass ignoreSenders by design, and dispatch_event() never asked whether a session peer had just taken the same delivery.

Changes

  • services.agent-box.webhook.rev/sha256 → local-channels efa2531 (local-webhook 0.10.0). Two brakes, dispatch path only: a CI event overrides ignoreSenders only when it reports a failure, and no CI event spawns while a live session peer's own filter already claims the topic. Session delivery is untouched, so "merge on green" still works. Non-CI events (new issue, someone else's PR) still spawn regardless of who is subscribed — topics are repo-granular while ownership is object-granular.
  • Docs in the two places an agent actually looks: the guide's standing-watch section and agent-box-webhook --help both now state that a watch will not double up on work you own.
  • tests/webhook.nix covers the new behaviour end-to-end.

0.10.0 renames peer IPC sockets to <filter key>.<pid>.sock so the ingress owner can resolve a live peer to its subscriptions. That is internal to webhook.py's own state dir; nothing in this module reads those names.

Why the VM test had to change

Its dispatch delivery is a workflow_run failure on defangdevs/agent-box while the peer session is subscribed to that repo (pinned) — exactly the case 0.10.0 now suppresses, so the old assertions would have failed. The test now proves both directions on a real box:

  1. Delivery accepted (200), the daemon logs not spawning for workflow_run on defangdevs/agent-box — session agent-main is subscribed to it, and no hook-* session appears.
  2. The peer unsubscribes, the same signed delivery is re-sent, and the hook-* session appears with the framed prompt + trusted preamble as before.

The socket-name assertion moved to instances/agent-main.*.sock, which also pins the new naming contract.

User-visible / security effects

Fewer spawned sessions, none of them for work a live session owns. No change to the ingress, HMAC verification, the 401 fail2ban key, socket ownership, or the settings surface. No AWS, IAM, networking, or migration impact.

Operational note: this box's github:defangdevs/* standing watch is currently unsubscribed as a stop-gap. It gets restored after this lands and the box rebuilds onto the new pin.

Checks run

nix build -L .#checks.aarch64-linux.{module-generated-up-to-date,module-single-file,webhook-route,multi-user} — pass. nix eval .#checks.x86_64-linux.webhook.drvPath evaluates.

The webhook VM test is x86_64-only, so the new assertions are unverified locally — CI is their first real run.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PsqGhkpjsb4kKAdVz25xKN

…cating owned work

Bumps services.agent-box.webhook.rev/sha256 to local-channels efa2531
(local-webhook 0.10.0, defangdevs/local-channels#11), which fixes the
self-spawning this box hit twice on 2026-08-02: five hook-* sessions for CI on
PRs a session was already driving, three of the four hook slots gone, all from
two docs merges. Nothing was misconfigured — CI-outcome events bypass
ignoreSenders by design, and dispatch never asked whether a session peer had
just taken the same delivery.

0.10.0 adds two brakes on the dispatch path only (session delivery is
untouched, so "merge on green" still works): a CI event overrides
ignoreSenders only when it reports a FAILURE, and no CI event spawns while a
live session peer's own filter already claims the topic. Non-CI events — a new
issue, someone else's PR — still spawn regardless of who is subscribed,
because topics are repo-granular while ownership is object-granular.

Peer IPC sockets are now named "<filter key>.<pid>.sock" so the ingress owner
can resolve a live peer to its subscriptions; that is internal to webhook.py's
own state dir, and nothing in this module reads those names.

Also documented in the two places an agent actually looks: the guide's standing
watch section and `agent-box-webhook --help` both now say a watch will not
double up on work you own.

tests/webhook.nix asserts the new behaviour end-to-end, and had to change to
keep passing — its dispatch delivery is a workflow_run FAILURE on the repo the
peer session is subscribed to, which is now precisely the suppressed case. It
therefore proves both directions on a real box: the delivery is accepted, the
daemon logs "not spawning ... session agent-main is subscribed to it" and no
hook-* session appears; after the peer unsubscribes, the same delivery spawns
the session with the framed prompt as before. The socket-name assertion moved
to instances/agent-main.*.sock.

Checks run (aarch64-linux): module-generated-up-to-date, module-single-file,
webhook-route, multi-user. The webhook VM test is x86_64-only and runs in CI —
the assertions above are unverified locally.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PsqGhkpjsb4kKAdVz25xKN
@defangdevs
defangdevs merged commit a48da1d into master Aug 3, 2026
1 check passed
@defangdevs
defangdevs deleted the feat/webhook-0.10.0-pin branch August 3, 2026 09:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dispatch: a session that owns a topic should exclude its events from everyone else (self-spawn on your own PR's CI)

2 participants