docs(autopilots): expand "where event name and action come from" with curl examples

Add concrete curl request/inference pairs under each derivation step
(body envelope, headers, body fallback, default) and a "common gotcha"
explaining why filter `event=trigger, action=true` does not match
`{"trigger": true}`. Mirrors the explanation that resolved the
on-call confusion about Event filter semantics.

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
J
2026-05-27 16:05:30 +08:00
parent 00226afa0f
commit b2e3f3809b
2 changed files with 136 additions and 30 deletions

View File

@@ -125,25 +125,79 @@ Examples:
#### Where the event name and action come from
Multica derives `event` and `action` from the inbound request in this
order — the first match wins:
Multica derives the `event` name and `action` from the inbound request
in this order — **the first match wins**.
1. **Body envelope** — if the body is a JSON object with an `event`
string field, that value is the event name. An optional
`eventPayload` object then provides `action` / `state` /
`conclusion` / `status` candidates.
2. **Headers** — `X-GitHub-Event: <event>` combined with body
`action`; `X-Gitlab-Event: <event>`; `X-Event-Type: <event>` (passed
through verbatim).
3. **Body fallback** — top-level string `event` / `type` / `action`.
4. **Default** — `webhook.received` if nothing above matches.
**1. Body envelope.** If the body is a JSON object with a string
`event` field, that value is the event name directly. An optional
`eventPayload` object then supplies action candidates from its
`action` / `state` / `conclusion` / `status` fields.
Action candidates come from the event-name suffix (`provider.event.<action>`)
plus the body string fields `action`, `state`, `conclusion`, and
`status`. **Non-string values don't qualify** — `{"action": true}` does
not produce an action candidate. Trim values before saving; entries
like `" workflow_run "` with surrounding whitespace are stored
verbatim and will never match.
```bash
curl -X POST "$MULTICA_WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d '{"event":"trigger","eventPayload":{"action":"true"}}'
# inferred: event = trigger, action candidate = true
```
**2. Headers.** When no body envelope is present, Multica reads the
following well-known provider headers:
- `X-GitHub-Event: <event>` — combined with the top-level body
`action` field (when present) to form `github.<event>.<action>`.
- `X-Gitlab-Event: <event>` — becomes `gitlab.<event>`.
- `X-Event-Type: <event>` — passed through verbatim.
```bash
# GitHub-style: header gives the event name, body gives the action.
curl -X POST "$MULTICA_WEBHOOK_URL" \
-H 'X-GitHub-Event: workflow_run' \
-H 'Content-Type: application/json' \
-d '{"action":"completed"}'
# inferred: event = github.workflow_run.completed
# → matches a filter row of workflow_run / completed
# Generic event-type header — no body fields needed.
curl -X POST "$MULTICA_WEBHOOK_URL" \
-H 'X-Event-Type: trigger.true' \
-H 'Content-Type: application/json' \
-d '{}'
# inferred: event = trigger.true → matches trigger / true
```
**3. Body fallback.** If neither a body envelope nor a known header is
present, Multica falls back to top-level body string fields in this
order: `event` → `type` → `action`.
```bash
curl -X POST "$MULTICA_WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d '{"type":"trigger","action":"true"}'
# inferred: event = trigger (from `type`), action candidate = true
```
**4. Default.** If nothing above matches, the event is
`webhook.received` and there are no action candidates.
**Action candidates, in full.** Once the event is determined, Multica
considers every value below as a possible action match:
- The event-name suffix, when the event has the form
`provider.event.<action>` (e.g. `github.workflow_run.completed` →
`completed`).
- The body fields `action`, `state`, `conclusion`, and `status` —
**only when they are JSON strings**. A boolean (`{"action": true}`)
or a number does not qualify, so a filter expecting
`event=trigger, action=true` will never match a body of
`{"trigger": true}` because `true` is a bool, not a string.
**Common gotcha.** A filter row like `Event name: trigger` /
`Actions: true` does **not** mean "fire when the body has
`trigger: true`" — Event filters match the *inferred event and
action*, not arbitrary body fields. Send `trigger.true` via
`X-Event-Type` (or use the body envelope shown above) to hit it.
Surrounding whitespace in saved filter rows (`" workflow_run "`) is
stored verbatim and will never match — trim before saving.
#### Quick test

View File

@@ -120,21 +120,73 @@ curl -X POST "$MULTICA_WEBHOOK_URL" \
#### 事件名和 action 从哪来
Multica 按下面的顺序从入站请求里推断 `event` 和 `action`**先命中先用**
Multica 按下面的顺序从入站请求里推断 `event` 和 `action`**先命中先用**
1. **Body envelope** —— 如果 body 是一个 JSON 对象、且带
`event: "<字符串>"` 字段,就用它。可选的 `eventPayload` 对象再
提供 `action` / `state` / `conclusion` / `status` 候选。
2. **请求头** —— `X-GitHub-Event: <event>` 配合 body `action`
`X-Gitlab-Event: <event>``X-Event-Type: <event>`(原样使用)。
3. **Body 兜底** —— 顶层字符串 `event` / `type` / `action`。
4. **默认值** —— 以上都没命中时取 `webhook.received`。
**1. Body envelope** 如果 body 是一个 JSON 对象、且带字符串字段
`event`,就直接用它作为事件名。可选的 `eventPayload` 对象再
从自己的 `action` / `state` / `conclusion` / `status` 字段里提供
action 候选。
action 候选来自事件名后缀(`provider.event.<action>`)以及 body 里
`action`、`state`、`conclusion`、`status` 这四个字符串字段。
**非字符串值不算候选**——`{"action": true}` 不会被识别为 action。
保存前请先 trim 掉首尾空格;`" workflow_run "` 这种带空白的值
会被原样保存,但永远命中不了。
```bash
curl -X POST "$MULTICA_WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d '{"event":"trigger","eventPayload":{"action":"true"}}'
# 推断结果event = triggeraction 候选 = true
```
**2. 请求头。** 没有 body envelope 时按以下头部识别:
- `X-GitHub-Event: <event>` —— 结合 body 顶层的 `action` 字段
(如果有),拼成 `github.<event>.<action>`。
- `X-Gitlab-Event: <event>` —— 拼成 `gitlab.<event>`。
- `X-Event-Type: <event>` —— 原样使用。
```bash
# GitHub 风格:事件名来自 headeraction 来自 body。
curl -X POST "$MULTICA_WEBHOOK_URL" \
-H 'X-GitHub-Event: workflow_run' \
-H 'Content-Type: application/json' \
-d '{"action":"completed"}'
# 推断结果event = github.workflow_run.completed
# → 命中 workflow_run / completed 的过滤规则
# 通用 event-type 头部 —— 不需要任何 body 字段。
curl -X POST "$MULTICA_WEBHOOK_URL" \
-H 'X-Event-Type: trigger.true' \
-H 'Content-Type: application/json' \
-d '{}'
# 推断结果event = trigger.true → 命中 trigger / true
```
**3. Body 兜底。** Body envelope 和上面的 header 都没有时,
从 body 顶层字符串字段里依次找:`event` → `type` → `action`。
```bash
curl -X POST "$MULTICA_WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d '{"type":"trigger","action":"true"}'
# 推断结果event = trigger取自 `type`action 候选 = true
```
**4. 默认值。** 以上都没命中时,事件名取 `webhook.received`
没有 action 候选。
**action 候选的完整清单。** 事件名确定后,下面这些值都会被列为
可能的 action
- 事件名后缀,当事件形如 `provider.event.<action>` 时
(例如 `github.workflow_run.completed` → `completed`)。
- body 里 `action`、`state`、`conclusion`、`status` 这四个字段——
**必须是 JSON 字符串**。布尔(`{"action": true}`)或数字都不算
候选,所以 `event=trigger, action=true` 的过滤规则**永远命中不了**
`{"trigger": true}` 这种 body因为 `true` 是 bool 不是字符串。
**常见误区。** 一条 `Event name: trigger` / `Actions: true` 的规则
**不是**「body 里出现 `trigger: true` 就放行」的意思——事件过滤匹配的是
**推断出来的事件和 action**,不是任意 body 字段。要命中它,请用
`X-Event-Type` 头发送 `trigger.true`,或者用上面的 body envelope。
保存时带空格的值(例如 `" workflow_run "`)会被原样保存,但永远命中
不了——保存前请先 trim。
#### 快速验证