diff --git a/README.md b/README.md index 3e139f5..6bc7cf6 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,16 @@ defaults to `external` and does NOT include tailnet addresses gitea classifies it). `services/dev/gitea.nix` sets it accordingly; without that, deliveries fail with `webhook can only call allowed HTTP servers`. +Gitea names webhook events twice, and the two namespaces collide. The hook's +`events` array takes the *subscription* name; `X-GitHub-Event`, which is what +Hermes matches `--events` against, carries a lossy *wire* name from +`HookEventType.Event()`. A comment on a PR subscribes as +`pull_request_comment` but arrives as `issue_comment`, while +`pull_request_comment` on the wire means a review submission. So +`services/dev/gitea.nix` and `hosts/mars/hermes-agent.nix` deliberately name +the same event differently; `X-GitHub-Event-Type` carries the subscription +name, but Hermes does not read it. + The route's prompt and its filter script live in `hosts/mars/`, bind-mounted read-only from the nix store so the agent cannot edit its own loop guard out, and are re-subscribed by `hermes-agent-webhook-route` on every start. Run diff --git a/hosts/mars/hermes-agent.nix b/hosts/mars/hermes-agent.nix index 731beb2..19a2bed 100644 --- a/hosts/mars/hermes-agent.nix +++ b/hosts/mars/hermes-agent.nix @@ -311,11 +311,30 @@ in # exact format AND X-GitHub-Event, unconditionally, for every webhook type, # which is precisely what Hermes validates and reads the event name from. # - # --events pull_request_comment narrows the route to the one event the prompt - # handles; Gitea sends that value distinctly from issue_comment, so plain - # issue comments never reach the agent. A route carries exactly one prompt, - # so another event means either branching on {action} in the prompt or a - # second subscription plus a second Gitea hook at /webhooks/. + # --events issue_comment, NOT pull_request_comment. Gitea uses the same + # strings in two different namespaces and they collide: + # + # subscription name wire name (X-GitHub-Event) what it is + # ----------------------- -------------------------- ---------------- + # pull_request_comment issue_comment comment on a PR + # issue_comment issue_comment comment on an issue + # pull_request_review_comment pull_request_comment review on a PR + # + # The hook's `events` array (services/dev/gitea.nix) takes the SUBSCRIPTION + # name; Hermes matches --events against X-GitHub-Event, i.e. the WIRE name, + # which comes from HookEventType.Event() in modules/webhook/type.go. So + # "pull_request_comment" here would match review submissions and never a + # comment -- the exact inversion of what it reads like. X-GitHub-Event-Type + # carries the subscription name, but Hermes does not look at it. + # + # issue_comment on the wire covers comments on plain issues too; the hook + # does not subscribe those, and the filter's is_pull check drops them anyway + # if the hook is ever widened. + # + # A route carries exactly one prompt, so another event means either branching + # on {action} in the prompt or a second subscription plus a second Gitea hook + # at /webhooks/. Review comments would need that: they arrive as a + # PullRequestPayload with action "reviewed" and no comment object at all. # # No --deliver: it defaults to `log`. The prompt tells her to answer in the # pull request, so the PR comment IS the delivery. @@ -380,7 +399,7 @@ in hermes webhook subscribe gitea-pr-comments \ --secret "$GITEA_HERMES_WEBHOOK_SECRET" \ --description "Gitea PR comments -> L.U.N.A." \ - --events pull_request_comment \ + --events issue_comment \ --script gitea-pr-comment-filter.py \ --prompt "$prompt" ' diff --git a/services/dev/gitea.nix b/services/dev/gitea.nix index c2fdc84..c5bb551 100644 --- a/services/dev/gitea.nix +++ b/services/dev/gitea.nix @@ -21,9 +21,17 @@ let # nothing she does lands without darman clicking merge. lunaRepos = [ "darman/homelab" ]; - # Only the event Hermes's gitea-pr-comments route actually handles. Gitea - # sends pull_request_comment distinctly from issue_comment, so this covers - # comments on PRs and nothing else — no issue comments, no pushes. + # Only the event Hermes's gitea-pr-comments route actually handles. + # + # This is a SUBSCRIPTION name, and gitea reuses these strings in a second, + # colliding namespace on the wire — see the long comment on --events in + # hosts/mars/hermes-agent.nix. "pull_request_comment" HERE means a timeline + # comment on a pull request; the same string in X-GitHub-Event means a + # review submission. The two files therefore name the same event + # differently on purpose, and neither is a typo: + # + # here (subscription): pull_request_comment + # there (--events): issue_comment # # Hermes would drop the rest anyway (its route filters on X-GitHub-Event # before any LLM call), so this is defence in depth rather than the only