[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CBNERY2HACPC6HMZKN213B":3,"skill-same:01M6CBNERY2HACPC6HMZKN213B":85},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":55,"linkOnly":56,"markdownContent":57,"markdownBody":58,"frontMatter":59,"refName":62,"commitSha":63,"skillDirectory":64,"forksCount":65,"repositoryHtmlUrl":66,"repositoryHomepageUrl":6,"ownerHtmlUrl":67,"ownerBlogUrl":68,"ownerDescription":69,"updatedAt":70,"install":71,"resources":84},"01M6CBNERY2HACPC6HMZKN213B","pilot-watch-alert-response",null,"Use when Pilot is RESPONDING TO REAL-TIME CLUSTER EVENTS surfaced by `cub-scout watch` or `cub-scout bot`. Natural phrasings: \"Pilot subscribes to the watch stream\", \"render verdicts on each drift event as they fire\", \"real-time acceptance kernel for cluster changes\", \"Pilot, decide on this drift.detected event\", \"what does Pilot say about the ownership.changed alert\", \"stream PASS\u002FWATCH\u002FASK\u002FBLOCK per event from cub-scout watch\". Pilot consumes the `cub-scout watch` \u002F `cub-scout bot` event stream (webhook or file sink, optionally with inline receipts via `--emit-receipt-on`) and renders a verdict per event, calling back into cub-scout (`explain`, `compare three-way`, `trace`) for context when needed. This is the ONLY event-driven skill in the pilot-* batch — others are query-driven. Do NOT load for: a single-resource pre-deploy gate (use pilot-cd-gate), a periodic fleet roll-up (use pilot-fleet-conformance), a drift-classification deep-dive (use pilot-patch-and-drift), a postmortem evidence pack (use pilot-incident-evidence), or any mutating action.","confighub\u002Fcub-scout","confighub","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F206140369?v=4","01M6CBJBWD33AFNG4VXMJHSRXD","ConfigHub Inc","01M6CBJC0K0F8CJVFWGRSR0KYC",14,"MIT","https:\u002F\u002Fgithub.com\u002Fconfighub\u002Fcub-scout\u002Fblob\u002Fmain\u002Fskills\u002Fpilot-watch-alert-response\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54],"alert","pilot watch alert response","watch","flux","up","periodic","patch","cub scout","scout compare","show","time","describe","deep","webhook","app","events","unit","inline","kernel","postmortem","release","doctor","acceptance","batch","kubectl","real-time","classification","Bash","evidence","changeset","decide","ask","list","view","use","only","2026-11-10 10:12:30",false,"---\nname: pilot-watch-alert-response\ndescription: 'Use when Pilot is RESPONDING TO REAL-TIME CLUSTER EVENTS surfaced by `cub-scout watch` or `cub-scout bot`. Natural phrasings: \"Pilot subscribes to the watch stream\", \"render verdicts on each drift event as they fire\", \"real-time acceptance kernel for cluster changes\", \"Pilot, decide on this drift.detected event\", \"what does Pilot say about the ownership.changed alert\", \"stream PASS\u002FWATCH\u002FASK\u002FBLOCK per event from cub-scout watch\". Pilot consumes the `cub-scout watch` \u002F `cub-scout bot` event stream (webhook or file sink, optionally with inline receipts via `--emit-receipt-on`) and renders a verdict per event, calling back into cub-scout (`explain`, `compare three-way`, `trace`) for context when needed. This is the ONLY event-driven skill in the pilot-* batch — others are query-driven. Do NOT load for: a single-resource pre-deploy gate (use pilot-cd-gate), a periodic fleet roll-up (use pilot-fleet-conformance), a drift-classification deep-dive (use pilot-patch-and-drift), a postmortem evidence pack (use pilot-incident-evidence), or any mutating action.'\nphase: cross-cutting\nallowed-tools: Bash(.\u002Fcub-scout explain *) Bash(cub-scout explain *) Bash(cub scout explain *) Bash(.\u002Fcub-scout compare three-way *) Bash(cub-scout compare three-way *) Bash(cub scout compare three-way *) Bash(.\u002Fcub-scout compare drift *) Bash(cub-scout compare drift *) Bash(cub scout compare drift *) Bash(.\u002Fcub-scout compare source-truth *) Bash(cub-scout compare source-truth *) Bash(cub scout compare source-truth *) Bash(.\u002Fcub-scout trace *) Bash(cub-scout trace *) Bash(cub scout trace *) Bash(.\u002Fcub-scout receipt verify *) Bash(cub-scout receipt verify *) Bash(cub scout receipt verify *) Bash(.\u002Fcub-scout receipt show *) Bash(cub-scout receipt show *) Bash(cub scout receipt show *) Bash(.\u002Fcub-scout receipt validate *) Bash(cub-scout receipt validate *) Bash(cub scout receipt validate *) Bash(.\u002Fcub-scout receipt list *) Bash(cub-scout receipt list *) Bash(cub scout receipt list *) Bash(.\u002Fcub-scout doctor *) Bash(cub-scout doctor *) Bash(cub scout doctor *) Bash(.\u002Fcub-scout map list *) Bash(.\u002Fcub-scout map workloads *) Bash(.\u002Fcub-scout map orphans *) Bash(cub-scout map list *) Bash(cub-scout map workloads *) Bash(cub-scout map orphans *) Bash(cub scout map list *) Bash(cub scout map workloads *) Bash(cub scout map orphans *) Bash(kubectl get *) Bash(kubectl describe *) Bash(cub space list *) Bash(cub unit get *) Bash(cub unit list *) Bash(cub link get *) Bash(cub link list *) Bash(cub view get *) Bash(cub view list *) Bash(cub unit-event list *) Bash(cub resource list *) Bash(cub release list *) Bash(cub changeset list *) Bash(argocd app get *) Bash(flux get *)\n\n---\n\n# pilot-watch-alert-response\n\nThe real-time event-driven scenario from **Pilot's** side. Pilot subscribes to `cub-scout watch` or `cub-scout bot` (which expose the same webhook \u002F file event sinks) and, for each event, decides PASS \u002F WATCH \u002F ASK \u002F BLOCK — calling back into cub-scout for context as needed. This is the **only event-driven skill in the pilot-* batch**; the other four are query-driven.\n\nWith the receipts v2 surface shipped (#463), Pilot can ask `cub-scout watch` or `cub-scout bot` to **inline a receipt** with each matching event via `--emit-receipt-on drift.detected,ownership.changed` or `--emit-receipt-on all`. That delivers a fingerprinted in-toto Statement v1 per event in the same JSONL line — Pilot reads the verdict + receipt in one shot, no synchronous call-back required for the common case.\n\n## When to use\n\nExplicit phrasings:\n\n- \"Pilot subscribes to the watch stream\"\n- \"Render verdicts on each drift event as they fire\"\n- \"Real-time acceptance kernel for cluster changes\"\n- \"Pilot, decide on this `drift.detected` event\"\n- \"What does Pilot say about the `ownership.changed` alert\"\n- \"Stream PASS\u002FWATCH\u002FASK\u002FBLOCK per event from cub-scout watch\"\n- \"Run the same stream from cub-scout bot in the cluster\"\n- \"Pilot reads receipts inline from the watch event stream\"\n- \"Trigger Pilot on any cub-scout drift event\"\n\nImplicit intents:\n\n- The flow is **event-driven**, not query-driven (Pilot reacts to a stream, not a polling job)\n- The decision needs to **fire fast** — a Pilot verdict per event, ideally inline\n- The receipt-attached path (v2 `--emit-receipt-on`) is preferred when audit durability matters\n- Backpressure is a real concern when events fire fast (e.g., ApplicationSet expansion)\n\n## Do not load for\n\n- A **single-resource pre-deploy gate** — [`pilot-cd-gate`](..\u002Fpilot-cd-gate\u002FSKILL.md)\n- A **periodic fleet roll-up verdict** — [`pilot-fleet-conformance`](..\u002Fpilot-fleet-conformance\u002FSKILL.md)\n- A **drift-classification deep-dive** for one resource — [`pilot-patch-and-drift`](..\u002Fpilot-patch-and-drift\u002FSKILL.md)\n- A **postmortem evidence pack** — [`pilot-incident-evidence`](..\u002Fpilot-incident-evidence\u002FSKILL.md)\n- Pure **observation** without a Pilot policy decision — [`scout-observe`](..\u002Fscout-observe\u002FSKILL.md) covers the `watch` surface from the operator side\n- Any **mutating action**. Pilot's mutation path is `cub` \u002F Argo \u002F Flux \u002F kubectl — never cub-scout.\n\n## The Pilot ↔ cub-scout watch \u002F bot loop\n\n```\n   cub-scout watch -n prod \\\n     --webhook https:\u002F\u002Fpilot.acme\u002Fcub-scout-events \\\n     --emit-receipt-on drift.detected,ownership.changed \\\n     --output-file \u002Fvar\u002Flog\u002Fcub-scout-watch.jsonl\n        │\n        │  ▼ JSONL event stream (one event per line)\n        │  {\n        │    \"type\": \"drift.detected\",\n        │    \"timestamp\": \"2026-05-22T11:00:00Z\",\n        │    \"resource\": {\"kind\": \"Deployment\", \"name\": \"api\", \"namespace\": \"prod\"},\n        │    \"owner\": {\"type\": \"argo\", \"name\": \"payments-api\"},\n        │    \"severity\": \"warning\",\n        │    \"details\": {\"category\": \"DRIFT\"},\n        │    \"receipt\": { in-toto Statement v1 with applied-matches-spec verdict }\n        │  }\n        ▼\n   Pilot's event handler\n        │  fast path: the event already carries a receipt\n        │    │\n        │    └► Pilot reads receipt.predicate.verdict → render verdict\n        │\n        │  slow path: the event doesn't carry a receipt\n        │    │  (event type isn't in --emit-receipt-on, OR receipt-build failed)\n        │    │\n        │    ├──► cub-scout compare three-way \u003Cr> -n \u003Cns> --format json\n        │    ├──► cub-scout explain \u003Cr> -n \u003Cns> --presentation ai\n        │    └──► cub-scout receipt verify \u003Cr> -n \u003Cns> --strategy \u003Cs> --out event-receipt.json\n        │\n        ▼\n   Pilot's per-event verdict\n        │  PASS  → log + continue\n        │  WATCH → alert + log + (optional) attach receipt to a ticket\n        │  ASK   → page on-call; the proof gap is structured in the receipt\n        │  BLOCK → halt promotion \u002F trigger Pilot's escalation policy\n        └────────────────────────────────────────────────────\n```\n\n## Event types (`cub-scout watch` \u002F `cub-scout bot` + receipts v2)\n\n`cub-scout watch` and `cub-scout bot` emit four event types today; `--emit-receipt-on` can attach receipts to any of them, with `--emit-receipt-batch-cap` bounding first-poll bursts:\n\n| Event type | When it fires | Receipt-built in v1? | Pilot's typical reaction |\n|------------|---------------|----------------------|--------------------------|\n| `resource.discovered` | First poll sees a resource cub-scout hadn't seen before | **Yes** — bounded by `--emit-receipt-batch-cap` to avoid initial burst floods. | Log; no verdict needed. |\n| `ownership.changed` | A resource's ownership controller changed (Argo → Flux, Flux → kubectl, etc.) | **Yes** — `applied-matches-spec` auto-detected. Receipt verdict reflects whether the new owner has a resolved git anchor. | WATCH (often a transient state during migration); ASK if `applied-matches-spec` returns INCONCLUSIVE. |\n| `drift.detected` | `compare three-way` finds a divergence on a resource cub-scout watched into | **Yes** — `applied-matches-spec` auto-detected. Receipt verdict reflects whether the drift is controller-drift (PASS \u002F reconciling) or manual-edit (BLOCK). | Drives [`pilot-patch-and-drift`](..\u002Fpilot-patch-and-drift\u002FSKILL.md) shape: PASS = ACCEPT; WATCH = INVESTIGATE; BLOCK = REVERT\u002FQUARANTINE. |\n| `scan.finding` | A risk pattern matched on a resource (CVE, expiring cert, etc.) | **Yes** — bounded by `--emit-receipt-batch-cap` to avoid initial scan floods. | Severity-driven; route to security\u002FSRE escalation policy. |\n\nThe `--emit-receipt-on all` sugar accepts every known event type for forward-compat. Receipt-build failures are non-fatal — the underlying event still emits, just without the `receipt` key (uses `omitempty`; consumers should check key presence, not null-ness).\n\n```python\n# Idiomatic Python consumer\nfor line in stream:\n    event = json.loads(line)\n    if \"receipt\" in event:        # key-present check, NOT `is not None`\n        verdict = pilot.decide_from_receipt(event[\"receipt\"])\n    else:\n        verdict = pilot.fallback_decide(event)  # slow path\n    handle(verdict)\n```\n\n## Wire shape\n\nA `drift.detected` event with an attached receipt (one JSONL line, pretty-printed here):\n\n```json\n{\n  \"type\": \"drift.detected\",\n  \"timestamp\": \"2026-05-22T11:00:00Z\",\n  \"resource\": {\n    \"kind\": \"Deployment\",\n    \"name\": \"payments-api\",\n    \"namespace\": \"prod\"\n  },\n  \"owner\": {\n    \"type\": \"argo\",\n    \"name\": \"payments-api\"\n  },\n  \"severity\": \"warning\",\n  \"details\": {\n    \"category\": \"DRIFT\"\n  },\n  \"receipt\": {\n    \"_type\": \"https:\u002F\u002Fin-toto.io\u002FStatement\u002Fv1\",\n    \"subject\": [\n      {\n        \"name\": \"k8s-live:\u002F\u002Fapps\u002Fv1\u002FDeployment\u002Fprod\u002Fpayments-api\",\n        \"digest\": {\"sha256\": \"abc...\"}\n      }\n    ],\n    \"predicateType\": \"https:\u002F\u002Fcub-scout.dev\u002Freceipt\u002Fv1\",\n    \"predicate\": {\n      \"version\": \"v1\",\n      \"predicateName\": \"applied-matches-spec\",\n      \"verdict\": \"BLOCK\",\n      \"claim\": \"applied matches spec at apps\u002Fprod\u002Fpayments-api\",\n      \"scope\": {\"kind\": \"Deployment\", \"name\": \"payments-api\", \"namespace\": \"prod\"},\n      \"evidence\": {\n        \"attribution\": {\"cause\": \"manual-edit\", \"managerHint\": \"kubectl-edit\"},\n        \"gitSource\": {\"repoUrl\": \"https:\u002F\u002Fgithub.com\u002Forg\u002Fpayments\", \"revision\": \"abc123\", \"path\": \"apps\u002Fprod\u002Fpayments-api\"}\n      },\n      \"omissions\": [],\n      \"inputAttestations\": [],\n      \"nextSteps\": [\n        {\n          \"actionType\": \"read-only\",\n          \"reason\": \"live state was last written by a kubectl-* tool; the GitOps loop was bypassed since the controller's last apply\",\n          \"nextCommand\": \"kubectl get --show-managed-fields\",\n          \"nextSurface\": \"kubectl\"\n        }\n      ],\n      \"verifier\": {\"tool\": \"cub-scout\", \"version\": \"v2.2.1\"},\n      \"verifiedAt\": \"2026-05-22T11:00:00Z\",\n      \"fingerprint\": \"sha256:1a2b3c...\"\n    }\n  }\n}\n```\n\nNotes on the wire shape (verified against `pkg\u002Fagent\u002Freceipt.go`):\n- `predicate.version` is the literal string `\"v1\"` (`PredicateVersion`), not `\"1\"`.\n- The `nextSteps` array is populated for the manual-edit BLOCK branch — `EvaluateAppliedMatchesSpec` appends one `read-only` next step pointing at `kubectl get --show-managed-fields`. (`nextSteps` uses `omitempty` so other branches that produce zero next steps omit the key entirely.)\n- `omissions: []` and `inputAttestations: []` are explicit arrays (never null). The full receipt's fingerprint covers both.\n\nPilot reads `receipt.predicate.verdict` directly: `BLOCK` → halt; `WATCH` → alert; `PASS` → log + continue; `INCONCLUSIVE` → ASK. Receipt verdicts are restricted to those four — `ASK` is a source-truth `status` value (and maps to receipt `WATCH` when wrapped, per `pkg\u002Fagent\u002Freceipt_predicates.go:396-407`), not a receipt verdict.\n\n## Step-by-step\n\n### Step 1 — confirm the watch stream is shaped for Pilot\n\n```bash\n# Pre-flight: doctor + status\n$ cub-scout doctor\n$ cub-scout status\n\n# Confirm the event taxonomy Pilot expects\n$ cub-scout watch --help | grep -A 3 '\\-\\-emit-receipt-on'\n```\n\nIf standalone (no ConfigHub auth), the receipts in the stream omit the `confighub-unit:\u002F\u002F` subject and record an `OmissionConfigHubUnitSubject` entry — structural honesty about what's missing, not a verdict downgrade. The verdict follows the predicate's normal rules; `applied-matches-spec` can still PASS in standalone mode. Pilot's policy may choose to treat standalone receipts more conservatively, but that's Pilot-side; cub-scout doesn't impose a ceiling.\n\n### Step 2 — start the watch stream or bot\n\n```bash\n$ cub-scout watch -n prod \\\n    --webhook https:\u002F\u002Fpilot.acme\u002Fcub-scout-events \\\n    --emit-receipt-on all \\\n    --output-file \u002Fvar\u002Flog\u002Fcub-scout-watch.jsonl \\\n    --severity warning,critical\n```\n\n- `--webhook` is Pilot's listener (POST per event).\n- `--output-file` keeps a local JSONL log (useful for replay during postmortems; see [`pilot-incident-evidence`](..\u002Fpilot-incident-evidence\u002FSKILL.md)).\n- `--emit-receipt-on` attaches receipts to matching event types; use `all` with the default batch cap when first-poll bursts are possible.\n- `--severity` filters scan-finding events to the actionable subset.\n\nThe watch loop is **read-only by design**. cub-scout's only cluster operations are `Get` \u002F `List` \u002F `Watch`; `--emit-receipt-on` adds an in-process `BuildReceipt` per matching event, which is also pure (the receipts code path is statically guarded by `TestReceiptPackageReadOnlyClient`).\n\n### Step 3 — Pilot's per-event handler\n\nPilot's logic, per event:\n\n```python\ndef handle_event(event: dict) -> Verdict:\n    # Fast path: event carries an inline receipt\n    if \"receipt\" in event:\n        receipt = event[\"receipt\"]\n        verdict_str = receipt[\"predicate\"][\"verdict\"]  # PASS|WATCH|BLOCK|INCONCLUSIVE\n        # The receipt also carries omissions[], attribution, gitSource — Pilot can drill in\n        if verdict_str == \"PASS\":\n            return Verdict.PASS\n        elif verdict_str == \"WATCH\":\n            attach_receipt_to_ticket(receipt)\n            return Verdict.WATCH\n        elif verdict_str == \"BLOCK\":\n            escalate(event, receipt)\n            return Verdict.BLOCK\n        elif verdict_str == \"INCONCLUSIVE\":\n            return Verdict.ASK\n\n    # Slow path: no inline receipt (event type not in --emit-receipt-on, OR receipt-build failed)\n    return synchronous_evidence_gathering(event)\n```\n\nThe slow path calls back into cub-scout synchronously:\n\n```bash\n$ cub-scout compare three-way deploy\u002Fpayments-api -n prod --format json > evidence.json\n$ cub-scout receipt verify deploy\u002Fpayments-api -n prod --save --out event.receipt.json\n```\n\n### Step 4 — verify the receipt fingerprint (optional but recommended)\n\nPilot may want to verify that the inline receipt's fingerprint is intact — particularly when the event arrived via a webhook that traversed network boundaries. cub-scout's receipt validate path is exit-coded:\n\n```bash\n$ echo \"$event\" | jq '.receipt' > event-receipt.json\n$ cub-scout receipt validate event-receipt.json\n# exit 0 = fingerprint matches; 1 = mismatch (refuse to act on it); 2 = I\u002FO\n```\n\n## Operational defaults Pilot should know\n\n- **Receipt-build failures are non-fatal**: the event still emits, the `receipt` key is omitted (omitempty), and cub-scout logs a stderr warning. Pilot's handler must check for key presence, not null-ness.\n- **Warnings are rate-limited** (Codex round-6 P2 fix in #463): the first 10 receipt-build warnings pass through verbatim; afterwards, a summary line fires every 100 suppressed warnings. A long-running watch with transient cluster-read failures won't spam stderr.\n- **Unsupported event types pass through silently**: `resource.discovered` and `scan.finding` accept the flag (so `--emit-receipt-on all` works) but cub-scout skips receipt-build for them in v1. A startup warning lists them.\n- **Backpressure is not yet handled** (open in `#449`): if events fire faster than the consumer drains, the watch can queue up to `--max-queued-events` and then drops oldest. ApplicationSet expansion is the canonical \"events fire fast\" scenario.\n- **Connected vs standalone**: receipts attached to events include the `confighub-unit:\u002F\u002F` subject only when connected. Standalone-mode receipts omit it and carry an `OmissionConfigHubUnitSubject` entry — that's structural honesty about missing evidence. The verdict itself follows the predicate's normal rules (PASS is possible in standalone mode). Pilot may apply its own conservative policy; cub-scout doesn't impose a ceiling.\n\n## Worked example: drift event triggers Pilot\n\nA `drift.detected` event fires for `deploy\u002Fpayments-api` in prod. Pilot's webhook receives:\n\n```json\n{\n  \"type\": \"drift.detected\",\n  \"timestamp\": \"2026-05-22T11:00:00Z\",\n  \"resource\": {\"kind\": \"Deployment\", \"name\": \"payments-api\", \"namespace\": \"prod\"},\n  \"owner\": {\"type\": \"argo\", \"name\": \"payments-api\"},\n  \"severity\": \"warning\",\n  \"details\": {\"category\": \"DRIFT\"},\n  \"receipt\": {\n    \"_type\": \"https:\u002F\u002Fin-toto.io\u002FStatement\u002Fv1\",\n    \"predicateType\": \"https:\u002F\u002Fcub-scout.dev\u002Freceipt\u002Fv1\",\n    \"predicate\": {\n      \"predicateName\": \"applied-matches-spec\",\n      \"verdict\": \"BLOCK\",\n      \"evidence\": {\n        \"attribution\": {\"cause\": \"manual-edit\", \"managerHint\": \"kubectl-edit\"}\n      },\n      \"fingerprint\": \"sha256:1a2b3c...\"\n    }\n  }\n}\n```\n\nPilot's handler:\n1. Sees `\"receipt\" in event` → fast path.\n2. Reads `receipt.predicate.verdict: \"BLOCK\"`.\n3. Reads `receipt.predicate.evidence.attribution: {cause: manual-edit, managerHint: kubectl-edit}` → confirms human kubectl-edited an Argo-owned resource.\n4. Renders Pilot verdict: **BLOCK**.\n5. Escalates: opens a ticket, attaches the receipt, pages the on-call.\n\nTotal round-trip: one webhook POST, zero synchronous cub-scout calls. The receipt is fingerprint-verifiable later if the ticket is audited.\n\nIf the same event had arrived without an inline receipt (e.g., `--emit-receipt-on` wasn't set), Pilot would call `cub-scout compare three-way deploy\u002Fpayments-api -n prod --format json` to get the same evidence on the slow path.\n\n## Open scope on the cub-scout side (issue `#449`)\n\nThis skill calls out gaps that may surface during real deployment. They live in the open scope of `#449`, not this skill:\n\n- **More event types**: `attribution.cause-flipped` (a resource's `cause` changes from `controller-drift` → `manual-edit`); `source-truth.verdict-changed` (a `compare source-truth` verdict flips PASS → WATCH); `bindingSource.changed` (a Link now resolves to a different upstream). All v2+ scope.\n- **Backpressure \u002F batching**: high-frequency events from ApplicationSet expansion need a documented drop \u002F batch policy. Currently `--max-queued-events` controls in-process queue depth; downstream filtering is Pilot's call.\n- **Pilot-shaped emit format**: a `--format pilot` or `--shape acceptance-event` that bundles enough context per event for Pilot to verdict-render without any synchronous call-back. Receipts inline already cover the common case, but a fuller shape could include `compareThreeWay` per event.\n- **`resource.discovered` \u002F `scan.finding` receipt support**: gated on the backpressure design (would flood on initial poll burst). Open in `#449`.\n\nFiling these is a non-goal of this skill; surfacing them during real-deployment authoring is a goal.\n\n## Tool boundary\n\n- **Allowed (cub-scout):** `watch` (not auto-approved: its `--webhook` flag sends events to any URL, so the host asks each time), Compare verbs, `explain`, `trace`, `doctor`, `map`, `receipt verify \u002F show \u002F validate \u002F list`. All read-only.\n- **Allowed (cluster):** `kubectl get\u002Fdescribe`. NOT `kubectl apply \u002F edit \u002F patch \u002F delete`.\n- **Allowed (ConfigHub):** `cub \u003Centity> get \u002F list` for the entities named in allowed-tools. NOT `cub * create \u002F update \u002F delete`.\n- **Allowed (controllers):** `argocd app get`, `flux get`. NOT `argocd app sync`, `flux reconcile`.\n- **Pilot's mutation path** (REVERT, QUARANTINE, escalation) is out-of-scope for this skill.\n\n## References\n\n- [`scout-observe`](..\u002Fscout-observe\u002FSKILL.md) — the `watch` surface from the operator side\n- [`scout-verify`](..\u002Fscout-verify\u002FSKILL.md) — receipt-emit (the `--emit-receipt-on` flag wiring)\n- [`scout-compare`](..\u002Fscout-compare\u002FSKILL.md) — Compare verbs Pilot falls back to on the slow path\n- [`pilot-cd-gate`](..\u002Fpilot-cd-gate\u002FSKILL.md) — pre-deploy companion (query-driven)\n- [`pilot-fleet-conformance`](..\u002Fpilot-fleet-conformance\u002FSKILL.md) — periodic fleet companion (query-driven)\n- [`pilot-patch-and-drift`](..\u002Fpilot-patch-and-drift\u002FSKILL.md) — drill-down for BLOCK \u002F WATCH events\n- [`pilot-incident-evidence`](..\u002Fpilot-incident-evidence\u002FSKILL.md) — replay watch logs during postmortems\n- Wire format: [`docs\u002Freference\u002Fjson-contracts.md`](..\u002F..\u002Fdocs\u002Freference\u002Fjson-contracts.md) § Receipt Contract — Watch event emission (v2.2)\n- Receipts v1+v2: `#446` (v1), `#449` (this flag), `#463` (the shipping merge)\n- Read-only triad: [`scout-observe`](..\u002Fscout-observe\u002FSKILL.md), [`scout-attribute`](..\u002Fscout-attribute\u002FSKILL.md), [`scout-compare`](..\u002Fscout-compare\u002FSKILL.md), [`scout-verify`](..\u002Fscout-verify\u002FSKILL.md)\n\n## Constraints\n\n- As of `v2.3.0` (PR #470), all four known event types build receipts: `drift.detected`, `ownership.changed`, `resource.discovered`, `scan.finding`. The per-poll cap `--emit-receipt-batch-cap N` (default 10) bounds first-poll bursts that would otherwise flood — the first N events get receipts and the rest emit with the `receipt` key omitted plus a single stderr summary line.\n- The `receipt` key uses `omitempty` — consumers MUST check key presence, not null-ness. `event[\"receipt\"]` raising `KeyError` is the correct empty signal; `if event[\"receipt\"] is None` is the wrong pattern.\n- The wire format is the **in-toto Statement v1 envelope** wrapping `https:\u002F\u002Fcub-scout.dev\u002Freceipt\u002Fv1`. Pilot's receipt parser should be schema-aware to handle future envelope additions (e.g., signing layer).\n- `--emit-receipt-on` requires the v2.2+ cub-scout binary (the flag shipped in `#463`); the per-poll cap requires v2.3+ (`#470`). Older binaries don't have the flag and the watch event payload won't include a `receipt` field.\n- **Per-poll backpressure semantics**: the cap resets every call to `attachReceiptsIfRequested` (one watch poll = one call), so a long-running watch with quiet polls between bursts doesn't accumulate suppression state. `--emit-receipt-batch-cap 0` disables receipt-build entirely while keeping the flag explicit; large values (e.g., 1000) effectively disable the cap. See [`docs\u002Freference\u002Fwatch-events.md`](..\u002F..\u002Fdocs\u002Freference\u002Fwatch-events.md) for the full specification.\n","# pilot-watch-alert-response\n\nThe real-time event-driven scenario from **Pilot's** side. Pilot subscribes to `cub-scout watch` or `cub-scout bot` (which expose the same webhook \u002F file event sinks) and, for each event, decides PASS \u002F WATCH \u002F ASK \u002F BLOCK — calling back into cub-scout for context as needed. This is the **only event-driven skill in the pilot-* batch**; the other four are query-driven.\n\nWith the receipts v2 surface shipped (#463), Pilot can ask `cub-scout watch` or `cub-scout bot` to **inline a receipt** with each matching event via `--emit-receipt-on drift.detected,ownership.changed` or `--emit-receipt-on all`. That delivers a fingerprinted in-toto Statement v1 per event in the same JSONL line — Pilot reads the verdict + receipt in one shot, no synchronous call-back required for the common case.\n\n## When to use\n\nExplicit phrasings:\n\n- \"Pilot subscribes to the watch stream\"\n- \"Render verdicts on each drift event as they fire\"\n- \"Real-time acceptance kernel for cluster changes\"\n- \"Pilot, decide on this `drift.detected` event\"\n- \"What does Pilot say about the `ownership.changed` alert\"\n- \"Stream PASS\u002FWATCH\u002FASK\u002FBLOCK per event from cub-scout watch\"\n- \"Run the same stream from cub-scout bot in the cluster\"\n- \"Pilot reads receipts inline from the watch event stream\"\n- \"Trigger Pilot on any cub-scout drift event\"\n\nImplicit intents:\n\n- The flow is **event-driven**, not query-driven (Pilot reacts to a stream, not a polling job)\n- The decision needs to **fire fast** — a Pilot verdict per event, ideally inline\n- The receipt-attached path (v2 `--emit-receipt-on`) is preferred when audit durability matters\n- Backpressure is a real concern when events fire fast (e.g., ApplicationSet expansion)\n\n## Do not load for\n\n- A **single-resource pre-deploy gate** — [`pilot-cd-gate`](..\u002Fpilot-cd-gate\u002FSKILL.md)\n- A **periodic fleet roll-up verdict** — [`pilot-fleet-conformance`](..\u002Fpilot-fleet-conformance\u002FSKILL.md)\n- A **drift-classification deep-dive** for one resource — [`pilot-patch-and-drift`](..\u002Fpilot-patch-and-drift\u002FSKILL.md)\n- A **postmortem evidence pack** — [`pilot-incident-evidence`](..\u002Fpilot-incident-evidence\u002FSKILL.md)\n- Pure **observation** without a Pilot policy decision — [`scout-observe`](..\u002Fscout-observe\u002FSKILL.md) covers the `watch` surface from the operator side\n- Any **mutating action**. Pilot's mutation path is `cub` \u002F Argo \u002F Flux \u002F kubectl — never cub-scout.\n\n## The Pilot ↔ cub-scout watch \u002F bot loop\n\n```\n   cub-scout watch -n prod \\\n     --webhook https:\u002F\u002Fpilot.acme\u002Fcub-scout-events \\\n     --emit-receipt-on drift.detected,ownership.changed \\\n     --output-file \u002Fvar\u002Flog\u002Fcub-scout-watch.jsonl\n        │\n        │  ▼ JSONL event stream (one event per line)\n        │  {\n        │    \"type\": \"drift.detected\",\n        │    \"timestamp\": \"2026-05-22T11:00:00Z\",\n        │    \"resource\": {\"kind\": \"Deployment\", \"name\": \"api\", \"namespace\": \"prod\"},\n        │    \"owner\": {\"type\": \"argo\", \"name\": \"payments-api\"},\n        │    \"severity\": \"warning\",\n        │    \"details\": {\"category\": \"DRIFT\"},\n        │    \"receipt\": { in-toto Statement v1 with applied-matches-spec verdict }\n        │  }\n        ▼\n   Pilot's event handler\n        │  fast path: the event already carries a receipt\n        │    │\n        │    └► Pilot reads receipt.predicate.verdict → render verdict\n        │\n        │  slow path: the event doesn't carry a receipt\n        │    │  (event type isn't in --emit-receipt-on, OR receipt-build failed)\n        │    │\n        │    ├──► cub-scout compare three-way \u003Cr> -n \u003Cns> --format json\n        │    ├──► cub-scout explain \u003Cr> -n \u003Cns> --presentation ai\n        │    └──► cub-scout receipt verify \u003Cr> -n \u003Cns> --strategy \u003Cs> --out event-receipt.json\n        │\n        ▼\n   Pilot's per-event verdict\n        │  PASS  → log + continue\n        │  WATCH → alert + log + (optional) attach receipt to a ticket\n        │  ASK   → page on-call; the proof gap is structured in the receipt\n        │  BLOCK → halt promotion \u002F trigger Pilot's escalation policy\n        └────────────────────────────────────────────────────\n```\n\n## Event types (`cub-scout watch` \u002F `cub-scout bot` + receipts v2)\n\n`cub-scout watch` and `cub-scout bot` emit four event types today; `--emit-receipt-on` can attach receipts to any of them, with `--emit-receipt-batch-cap` bounding first-poll bursts:\n\n| Event type | When it fires | Receipt-built in v1? | Pilot's typical reaction |\n|------------|---------------|----------------------|--------------------------|\n| `resource.discovered` | First poll sees a resource cub-scout hadn't seen before | **Yes** — bounded by `--emit-receipt-batch-cap` to avoid initial burst floods. | Log; no verdict needed. |\n| `ownership.changed` | A resource's ownership controller changed (Argo → Flux, Flux → kubectl, etc.) | **Yes** — `applied-matches-spec` auto-detected. Receipt verdict reflects whether the new owner has a resolved git anchor. | WATCH (often a transient state during migration); ASK if `applied-matches-spec` returns INCONCLUSIVE. |\n| `drift.detected` | `compare three-way` finds a divergence on a resource cub-scout watched into | **Yes** — `applied-matches-spec` auto-detected. Receipt verdict reflects whether the drift is controller-drift (PASS \u002F reconciling) or manual-edit (BLOCK). | Drives [`pilot-patch-and-drift`](..\u002Fpilot-patch-and-drift\u002FSKILL.md) shape: PASS = ACCEPT; WATCH = INVESTIGATE; BLOCK = REVERT\u002FQUARANTINE. |\n| `scan.finding` | A risk pattern matched on a resource (CVE, expiring cert, etc.) | **Yes** — bounded by `--emit-receipt-batch-cap` to avoid initial scan floods. | Severity-driven; route to security\u002FSRE escalation policy. |\n\nThe `--emit-receipt-on all` sugar accepts every known event type for forward-compat. Receipt-build failures are non-fatal — the underlying event still emits, just without the `receipt` key (uses `omitempty`; consumers should check key presence, not null-ness).\n\n```python\n# Idiomatic Python consumer\nfor line in stream:\n    event = json.loads(line)\n    if \"receipt\" in event:        # key-present check, NOT `is not None`\n        verdict = pilot.decide_from_receipt(event[\"receipt\"])\n    else:\n        verdict = pilot.fallback_decide(event)  # slow path\n    handle(verdict)\n```\n\n## Wire shape\n\nA `drift.detected` event with an attached receipt (one JSONL line, pretty-printed here):\n\n```json\n{\n  \"type\": \"drift.detected\",\n  \"timestamp\": \"2026-05-22T11:00:00Z\",\n  \"resource\": {\n    \"kind\": \"Deployment\",\n    \"name\": \"payments-api\",\n    \"namespace\": \"prod\"\n  },\n  \"owner\": {\n    \"type\": \"argo\",\n    \"name\": \"payments-api\"\n  },\n  \"severity\": \"warning\",\n  \"details\": {\n    \"category\": \"DRIFT\"\n  },\n  \"receipt\": {\n    \"_type\": \"https:\u002F\u002Fin-toto.io\u002FStatement\u002Fv1\",\n    \"subject\": [\n      {\n        \"name\": \"k8s-live:\u002F\u002Fapps\u002Fv1\u002FDeployment\u002Fprod\u002Fpayments-api\",\n        \"digest\": {\"sha256\": \"abc...\"}\n      }\n    ],\n    \"predicateType\": \"https:\u002F\u002Fcub-scout.dev\u002Freceipt\u002Fv1\",\n    \"predicate\": {\n      \"version\": \"v1\",\n      \"predicateName\": \"applied-matches-spec\",\n      \"verdict\": \"BLOCK\",\n      \"claim\": \"applied matches spec at apps\u002Fprod\u002Fpayments-api\",\n      \"scope\": {\"kind\": \"Deployment\", \"name\": \"payments-api\", \"namespace\": \"prod\"},\n      \"evidence\": {\n        \"attribution\": {\"cause\": \"manual-edit\", \"managerHint\": \"kubectl-edit\"},\n        \"gitSource\": {\"repoUrl\": \"https:\u002F\u002Fgithub.com\u002Forg\u002Fpayments\", \"revision\": \"abc123\", \"path\": \"apps\u002Fprod\u002Fpayments-api\"}\n      },\n      \"omissions\": [],\n      \"inputAttestations\": [],\n      \"nextSteps\": [\n        {\n          \"actionType\": \"read-only\",\n          \"reason\": \"live state was last written by a kubectl-* tool; the GitOps loop was bypassed since the controller's last apply\",\n          \"nextCommand\": \"kubectl get --show-managed-fields\",\n          \"nextSurface\": \"kubectl\"\n        }\n      ],\n      \"verifier\": {\"tool\": \"cub-scout\", \"version\": \"v2.2.1\"},\n      \"verifiedAt\": \"2026-05-22T11:00:00Z\",\n      \"fingerprint\": \"sha256:1a2b3c...\"\n    }\n  }\n}\n```\n\nNotes on the wire shape (verified against `pkg\u002Fagent\u002Freceipt.go`):\n- `predicate.version` is the literal string `\"v1\"` (`PredicateVersion`), not `\"1\"`.\n- The `nextSteps` array is populated for the manual-edit BLOCK branch — `EvaluateAppliedMatchesSpec` appends one `read-only` next step pointing at `kubectl get --show-managed-fields`. (`nextSteps` uses `omitempty` so other branches that produce zero next steps omit the key entirely.)\n- `omissions: []` and `inputAttestations: []` are explicit arrays (never null). The full receipt's fingerprint covers both.\n\nPilot reads `receipt.predicate.verdict` directly: `BLOCK` → halt; `WATCH` → alert; `PASS` → log + continue; `INCONCLUSIVE` → ASK. Receipt verdicts are restricted to those four — `ASK` is a source-truth `status` value (and maps to receipt `WATCH` when wrapped, per `pkg\u002Fagent\u002Freceipt_predicates.go:396-407`), not a receipt verdict.\n\n## Step-by-step\n\n### Step 1 — confirm the watch stream is shaped for Pilot\n\n```bash\n# Pre-flight: doctor + status\n$ cub-scout doctor\n$ cub-scout status\n\n# Confirm the event taxonomy Pilot expects\n$ cub-scout watch --help | grep -A 3 '\\-\\-emit-receipt-on'\n```\n\nIf standalone (no ConfigHub auth), the receipts in the stream omit the `confighub-unit:\u002F\u002F` subject and record an `OmissionConfigHubUnitSubject` entry — structural honesty about what's missing, not a verdict downgrade. The verdict follows the predicate's normal rules; `applied-matches-spec` can still PASS in standalone mode. Pilot's policy may choose to treat standalone receipts more conservatively, but that's Pilot-side; cub-scout doesn't impose a ceiling.\n\n### Step 2 — start the watch stream or bot\n\n```bash\n$ cub-scout watch -n prod \\\n    --webhook https:\u002F\u002Fpilot.acme\u002Fcub-scout-events \\\n    --emit-receipt-on all \\\n    --output-file \u002Fvar\u002Flog\u002Fcub-scout-watch.jsonl \\\n    --severity warning,critical\n```\n\n- `--webhook` is Pilot's listener (POST per event).\n- `--output-file` keeps a local JSONL log (useful for replay during postmortems; see [`pilot-incident-evidence`](..\u002Fpilot-incident-evidence\u002FSKILL.md)).\n- `--emit-receipt-on` attaches receipts to matching event types; use `all` with the default batch cap when first-poll bursts are possible.\n- `--severity` filters scan-finding events to the actionable subset.\n\nThe watch loop is **read-only by design**. cub-scout's only cluster operations are `Get` \u002F `List` \u002F `Watch`; `--emit-receipt-on` adds an in-process `BuildReceipt` per matching event, which is also pure (the receipts code path is statically guarded by `TestReceiptPackageReadOnlyClient`).\n\n### Step 3 — Pilot's per-event handler\n\nPilot's logic, per event:\n\n```python\ndef handle_event(event: dict) -> Verdict:\n    # Fast path: event carries an inline receipt\n    if \"receipt\" in event:\n        receipt = event[\"receipt\"]\n        verdict_str = receipt[\"predicate\"][\"verdict\"]  # PASS|WATCH|BLOCK|INCONCLUSIVE\n        # The receipt also carries omissions[], attribution, gitSource — Pilot can drill in\n        if verdict_str == \"PASS\":\n            return Verdict.PASS\n        elif verdict_str == \"WATCH\":\n            attach_receipt_to_ticket(receipt)\n            return Verdict.WATCH\n        elif verdict_str == \"BLOCK\":\n            escalate(event, receipt)\n            return Verdict.BLOCK\n        elif verdict_str == \"INCONCLUSIVE\":\n            return Verdict.ASK\n\n    # Slow path: no inline receipt (event type not in --emit-receipt-on, OR receipt-build failed)\n    return synchronous_evidence_gathering(event)\n```\n\nThe slow path calls back into cub-scout synchronously:\n\n```bash\n$ cub-scout compare three-way deploy\u002Fpayments-api -n prod --format json > evidence.json\n$ cub-scout receipt verify deploy\u002Fpayments-api -n prod --save --out event.receipt.json\n```\n\n### Step 4 — verify the receipt fingerprint (optional but recommended)\n\nPilot may want to verify that the inline receipt's fingerprint is intact — particularly when the event arrived via a webhook that traversed network boundaries. cub-scout's receipt validate path is exit-coded:\n\n```bash\n$ echo \"$event\" | jq '.receipt' > event-receipt.json\n$ cub-scout receipt validate event-receipt.json\n# exit 0 = fingerprint matches; 1 = mismatch (refuse to act on it); 2 = I\u002FO\n```\n\n## Operational defaults Pilot should know\n\n- **Receipt-build failures are non-fatal**: the event still emits, the `receipt` key is omitted (omitempty), and cub-scout logs a stderr warning. Pilot's handler must check for key presence, not null-ness.\n- **Warnings are rate-limited** (Codex round-6 P2 fix in #463): the first 10 receipt-build warnings pass through verbatim; afterwards, a summary line fires every 100 suppressed warnings. A long-running watch with transient cluster-read failures won't spam stderr.\n- **Unsupported event types pass through silently**: `resource.discovered` and `scan.finding` accept the flag (so `--emit-receipt-on all` works) but cub-scout skips receipt-build for them in v1. A startup warning lists them.\n- **Backpressure is not yet handled** (open in `#449`): if events fire faster than the consumer drains, the watch can queue up to `--max-queued-events` and then drops oldest. ApplicationSet expansion is the canonical \"events fire fast\" scenario.\n- **Connected vs standalone**: receipts attached to events include the `confighub-unit:\u002F\u002F` subject only when connected. Standalone-mode receipts omit it and carry an `OmissionConfigHubUnitSubject` entry — that's structural honesty about missing evidence. The verdict itself follows the predicate's normal rules (PASS is possible in standalone mode). Pilot may apply its own conservative policy; cub-scout doesn't impose a ceiling.\n\n## Worked example: drift event triggers Pilot\n\nA `drift.detected` event fires for `deploy\u002Fpayments-api` in prod. Pilot's webhook receives:\n\n```json\n{\n  \"type\": \"drift.detected\",\n  \"timestamp\": \"2026-05-22T11:00:00Z\",\n  \"resource\": {\"kind\": \"Deployment\", \"name\": \"payments-api\", \"namespace\": \"prod\"},\n  \"owner\": {\"type\": \"argo\", \"name\": \"payments-api\"},\n  \"severity\": \"warning\",\n  \"details\": {\"category\": \"DRIFT\"},\n  \"receipt\": {\n    \"_type\": \"https:\u002F\u002Fin-toto.io\u002FStatement\u002Fv1\",\n    \"predicateType\": \"https:\u002F\u002Fcub-scout.dev\u002Freceipt\u002Fv1\",\n    \"predicate\": {\n      \"predicateName\": \"applied-matches-spec\",\n      \"verdict\": \"BLOCK\",\n      \"evidence\": {\n        \"attribution\": {\"cause\": \"manual-edit\", \"managerHint\": \"kubectl-edit\"}\n      },\n      \"fingerprint\": \"sha256:1a2b3c...\"\n    }\n  }\n}\n```\n\nPilot's handler:\n1. Sees `\"receipt\" in event` → fast path.\n2. Reads `receipt.predicate.verdict: \"BLOCK\"`.\n3. Reads `receipt.predicate.evidence.attribution: {cause: manual-edit, managerHint: kubectl-edit}` → confirms human kubectl-edited an Argo-owned resource.\n4. Renders Pilot verdict: **BLOCK**.\n5. Escalates: opens a ticket, attaches the receipt, pages the on-call.\n\nTotal round-trip: one webhook POST, zero synchronous cub-scout calls. The receipt is fingerprint-verifiable later if the ticket is audited.\n\nIf the same event had arrived without an inline receipt (e.g., `--emit-receipt-on` wasn't set), Pilot would call `cub-scout compare three-way deploy\u002Fpayments-api -n prod --format json` to get the same evidence on the slow path.\n\n## Open scope on the cub-scout side (issue `#449`)\n\nThis skill calls out gaps that may surface during real deployment. They live in the open scope of `#449`, not this skill:\n\n- **More event types**: `attribution.cause-flipped` (a resource's `cause` changes from `controller-drift` → `manual-edit`); `source-truth.verdict-changed` (a `compare source-truth` verdict flips PASS → WATCH); `bindingSource.changed` (a Link now resolves to a different upstream). All v2+ scope.\n- **Backpressure \u002F batching**: high-frequency events from ApplicationSet expansion need a documented drop \u002F batch policy. Currently `--max-queued-events` controls in-process queue depth; downstream filtering is Pilot's call.\n- **Pilot-shaped emit format**: a `--format pilot` or `--shape acceptance-event` that bundles enough context per event for Pilot to verdict-render without any synchronous call-back. Receipts inline already cover the common case, but a fuller shape could include `compareThreeWay` per event.\n- **`resource.discovered` \u002F `scan.finding` receipt support**: gated on the backpressure design (would flood on initial poll burst). Open in `#449`.\n\nFiling these is a non-goal of this skill; surfacing them during real-deployment authoring is a goal.\n\n## Tool boundary\n\n- **Allowed (cub-scout):** `watch` (not auto-approved: its `--webhook` flag sends events to any URL, so the host asks each time), Compare verbs, `explain`, `trace`, `doctor`, `map`, `receipt verify \u002F show \u002F validate \u002F list`. All read-only.\n- **Allowed (cluster):** `kubectl get\u002Fdescribe`. NOT `kubectl apply \u002F edit \u002F patch \u002F delete`.\n- **Allowed (ConfigHub):** `cub \u003Centity> get \u002F list` for the entities named in allowed-tools. NOT `cub * create \u002F update \u002F delete`.\n- **Allowed (controllers):** `argocd app get`, `flux get`. NOT `argocd app sync`, `flux reconcile`.\n- **Pilot's mutation path** (REVERT, QUARANTINE, escalation) is out-of-scope for this skill.\n\n## References\n\n- [`scout-observe`](..\u002Fscout-observe\u002FSKILL.md) — the `watch` surface from the operator side\n- [`scout-verify`](..\u002Fscout-verify\u002FSKILL.md) — receipt-emit (the `--emit-receipt-on` flag wiring)\n- [`scout-compare`](..\u002Fscout-compare\u002FSKILL.md) — Compare verbs Pilot falls back to on the slow path\n- [`pilot-cd-gate`](..\u002Fpilot-cd-gate\u002FSKILL.md) — pre-deploy companion (query-driven)\n- [`pilot-fleet-conformance`](..\u002Fpilot-fleet-conformance\u002FSKILL.md) — periodic fleet companion (query-driven)\n- [`pilot-patch-and-drift`](..\u002Fpilot-patch-and-drift\u002FSKILL.md) — drill-down for BLOCK \u002F WATCH events\n- [`pilot-incident-evidence`](..\u002Fpilot-incident-evidence\u002FSKILL.md) — replay watch logs during postmortems\n- Wire format: [`docs\u002Freference\u002Fjson-contracts.md`](..\u002F..\u002Fdocs\u002Freference\u002Fjson-contracts.md) § Receipt Contract — Watch event emission (v2.2)\n- Receipts v1+v2: `#446` (v1), `#449` (this flag), `#463` (the shipping merge)\n- Read-only triad: [`scout-observe`](..\u002Fscout-observe\u002FSKILL.md), [`scout-attribute`](..\u002Fscout-attribute\u002FSKILL.md), [`scout-compare`](..\u002Fscout-compare\u002FSKILL.md), [`scout-verify`](..\u002Fscout-verify\u002FSKILL.md)\n\n## Constraints\n\n- As of `v2.3.0` (PR #470), all four known event types build receipts: `drift.detected`, `ownership.changed`, `resource.discovered`, `scan.finding`. The per-poll cap `--emit-receipt-batch-cap N` (default 10) bounds first-poll bursts that would otherwise flood — the first N events get receipts and the rest emit with the `receipt` key omitted plus a single stderr summary line.\n- The `receipt` key uses `omitempty` — consumers MUST check key presence, not null-ness. `event[\"receipt\"]` raising `KeyError` is the correct empty signal; `if event[\"receipt\"] is None` is the wrong pattern.\n- The wire format is the **in-toto Statement v1 envelope** wrapping `https:\u002F\u002Fcub-scout.dev\u002Freceipt\u002Fv1`. Pilot's receipt parser should be schema-aware to handle future envelope additions (e.g., signing layer).\n- `--emit-receipt-on` requires the v2.2+ cub-scout binary (the flag shipped in `#463`); the per-poll cap requires v2.3+ (`#470`). Older binaries don't have the flag and the watch event payload won't include a `receipt` field.\n- **Per-poll backpressure semantics**: the cap resets every call to `attachReceiptsIfRequested` (one watch poll = one call), so a long-running watch with quiet polls between bursts doesn't accumulate suppression state. `--emit-receipt-batch-cap 0` disables receipt-build entirely while keeping the flag explicit; large values (e.g., 1000) effectively disable the cap. See [`docs\u002Freference\u002Fwatch-events.md`](..\u002F..\u002Fdocs\u002Freference\u002Fwatch-events.md) for the full specification.\n",{"name":5,"phase":60,"description":7,"allowed-tools":61},"cross-cutting","Bash(.\u002Fcub-scout explain *) Bash(cub-scout explain *) Bash(cub scout explain *) Bash(.\u002Fcub-scout compare three-way *) Bash(cub-scout compare three-way *) Bash(cub scout compare three-way *) Bash(.\u002Fcub-scout compare drift *) Bash(cub-scout compare drift *) Bash(cub scout compare drift *) Bash(.\u002Fcub-scout compare source-truth *) Bash(cub-scout compare source-truth *) Bash(cub scout compare source-truth *) Bash(.\u002Fcub-scout trace *) Bash(cub-scout trace *) Bash(cub scout trace *) Bash(.\u002Fcub-scout receipt verify *) Bash(cub-scout receipt verify *) Bash(cub scout receipt verify *) Bash(.\u002Fcub-scout receipt show *) Bash(cub-scout receipt show *) Bash(cub scout receipt show *) Bash(.\u002Fcub-scout receipt validate *) Bash(cub-scout receipt validate *) Bash(cub scout receipt validate *) Bash(.\u002Fcub-scout receipt list *) Bash(cub-scout receipt list *) Bash(cub scout receipt list *) Bash(.\u002Fcub-scout doctor *) Bash(cub-scout doctor *) Bash(cub scout doctor *) Bash(.\u002Fcub-scout map list *) Bash(.\u002Fcub-scout map workloads *) Bash(.\u002Fcub-scout map orphans *) Bash(cub-scout map list *) Bash(cub-scout map workloads *) Bash(cub-scout map orphans *) Bash(cub scout map list *) Bash(cub scout map workloads *) Bash(cub scout map orphans *) Bash(kubectl get *) Bash(kubectl describe *) Bash(cub space list *) Bash(cub unit get *) Bash(cub unit list *) Bash(cub link get *) Bash(cub link list *) Bash(cub view get *) Bash(cub view list *) Bash(cub unit-event list *) Bash(cub resource list *) Bash(cub release list *) Bash(cub changeset list *) Bash(argocd app get *) Bash(flux get *)","main","261862e7ec5e5c93ce377ccfd6b583f5ac03c95c","skills\u002Fpilot-watch-alert-response",1,"https:\u002F\u002Fgithub.com\u002Fconfighub\u002Fcub-scout","https:\u002F\u002Fgithub.com\u002Fconfighub","http:\u002F\u002Fwww.confighub.com","Public repo for ConfigHub","2026-11-11 04:47:05",{"source":8,"skillName":5,"commands":72,"prompt":82,"zipAvailable":83},[73,76,79],{"tool":74,"command":75},"npx","npx skills add confighub\u002Fcub-scout --skill pilot-watch-alert-response",{"tool":77,"command":78},"bunx","bunx skills add confighub\u002Fcub-scout --skill pilot-watch-alert-response",{"tool":80,"command":81},"pnpm","pnpm dlx skills add confighub\u002Fcub-scout --skill pilot-watch-alert-response","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fconfighub\u002Fcub-scout\u002Fblob\u002Fmain\u002Fskills\u002Fpilot-watch-alert-response\u002FSKILL.md",true,[],[86,120,139,158,182,204],{"skillNo":87,"name":88,"nameZh":6,"description":89,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":90,"categories":91,"keywords":97,"publishedAt":55},"01M6CBPQHTK7YGVZD3MMH1328H","triage-unhealthy-workload","Use when the user is responding to a broken Kubernetes workload UNDER TIME PRESSURE — pager-going-off, CI-red, \"prod is down\" framing. Natural phrasing: \"deploy\u002Fapi is CrashLoopBackOff, what now?\", \"the rollout is stuck, help\", \"this pod won't start\", \"pager fired on payments\", \"everything is red in argocd\", \"what should I check first?\", \"give me a triage plan for this workload\". Composes doctor → explain → trace into a tight ~30-second loop the operator can run in a pager-acknowledged context. Do NOT load for: a planned investigation without urgency (use scout-diagnose directly), a drift question (use investigate-drift), or anything mutating (cub-scout never mutates — route to kubectl with the user driving).","https:\u002F\u002Fgithub.com\u002Fconfighub\u002Fcub-scout\u002Fblob\u002Fmain\u002Fskills\u002Ftriage-unhealthy-workload\u002FSKILL.md",[92],{"categoryNo":93,"categoryName":94,"taxonomyType":95,"taxonomyTypeDesc":96},"01JBSEEDCAT000000000000011","运维与部署","SCENARIO","使用场景",[98,99,100,101,102,40,103,104,105,106,46,107,108,109,110,111,53,112,113,26,114,115,116,29,117,118,119],"triage","workload","triage unhealthy workload","kubernetes","diagnose","logs","ci","payments","api","loop","explain","check","broken","question","rollout","never","route","drift","map","get","now","when",{"skillNo":121,"name":122,"nameZh":6,"description":123,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":124,"categories":125,"keywords":127,"publishedAt":55},"01M6CBPKYVREY83CQYNFW6BVD0","scout-verify","Use when the user wants a TYPED, FINGERPRINTED, IMMUTABLE evidence artifact about a Kubernetes resource — the Verify verb group of cub-scout (the receipt capability shipped in #446). Natural phrasing: \"produce a receipt that this is in compliance\", \"give me an attestation that the cluster matches Git\", \"I need a verifiable record for the audit trail\", \"build a receipt verifying no manual edits since deploy\", \"verify deploy\u002Fapi against source-truth and save the artifact\", \"validate this receipt has not been tampered with\", \"show me what receipts we have\", \"is this receipt tampered with?\", \"attach evidence to my CI gate\". Load whenever intent is receipt \u002F attestation \u002F evidence-artifact \u002F tamper-evident-record \u002F verified-record \u002F audit-trail \u002F postmortem-evidence \u002F acceptance-judge-input. Do NOT load for: a live comparison without a persisted artifact (use scout-compare), interpreting a single field's provenance (use scout-attribute), or actually applying a fix (cub-scout never mutates — route to cub \u002F argocd \u002F kubectl with the user driving).","https:\u002F\u002Fgithub.com\u002Fconfighub\u002Fcub-scout\u002Fblob\u002Fmain\u002Fskills\u002Fscout-verify\u002FSKILL.md",[126],{"categoryNo":93,"categoryName":94,"taxonomyType":95,"taxonomyTypeDesc":96},[128,129,130,101,41,131,104,132,133,106,134,46,38,48,135,52,136,53,113,47,26,28,114,137,117,33,35,138,119],"verify","scout verify","scout","produce","attestation","provenance","show me","argocd","fix","me","managed",{"skillNo":140,"name":141,"nameZh":6,"description":142,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":143,"categories":144,"keywords":145,"publishedAt":55},"01M6CBPF8WZBM7F9X096WT8PJD","scout-observe","Use when the user wants to SEE what is running in a Kubernetes cluster, who owns it, and how it is structured — the read-only Observe verb group of cub-scout. Natural phrasing: \"what is running in my cluster?\", \"give me a map of resources\", \"who owns this Deployment?\", \"trace this back to its source\", \"show me the ownership tree\", \"scan this cluster for risk\", \"dump the cluster as JSON\", \"stream cluster events\", \"run cub-scout as a bot\", \"what is the connection status?\", \"is this cluster healthy?\". Load when intent is observe \u002F inventory \u002F map \u002F show \u002F list \u002F trace \u002F scan \u002F dump \u002F stream \u002F bot \u002F health-check over a Kubernetes cluster. Do NOT load for: explaining WHY something is broken (use scout-diagnose), comparing cluster state to intended state (use scout-compare), provenance of individual field values (use scout-attribute), or any action that mutates the cluster (cub-scout never mutates — route to cub or kubectl with the user driving).","https:\u002F\u002Fgithub.com\u002Fconfighub\u002Fcub-scout\u002Fblob\u002Fmain\u002Fskills\u002Fscout-observe\u002FSKILL.md",[],[146,147,130,148,101,102,149,40,103,150,133,151,134,46,110,53,152,113,54,153,26,28,154,155,116,117,156,157,119],"observe","scout observe","bot","deployment","risk","inventory","version","hooks","back","health-check","resources","meaning",{"skillNo":159,"name":160,"nameZh":6,"description":161,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":162,"categories":163,"keywords":167,"publishedAt":55},"01M6CBPBM5J9PX4H8CE628AY5X","scout-mcp","Use when the user wants to expose cub-scout to an AI agent over MCP, wants a deterministic AI-ready snapshot of cluster context, or wants cub-scout running as a read-only event bot — the Integrate verb group. Natural phrasing: \"start the MCP server\", \"expose cub-scout to Claude \u002F Codex \u002F my agent\", \"give me an AI-ready context pack of this cluster\", \"set up the MCP gateway\", \"what MCP tools does cub-scout expose?\", \"run cub-scout as a bot\", \"produce JSON context for an LLM to reason about this cluster\". Load whenever intent is mcp \u002F mcp-gateway \u002F mcp-serve \u002F context-pack \u002F bot \u002F agent-context \u002F ai-snapshot \u002F llm-context \u002F model-context-protocol. Do NOT load for: actually running a non-integrate verb (those are scout-observe \u002F scout-diagnose \u002F scout-compare \u002F scout-attribute \u002F scout-ingest \u002F scout-govern \u002F scout-verify), or `cub` MCP integration (that's a separate tool surface).","https:\u002F\u002Fgithub.com\u002Fconfighub\u002Fcub-scout\u002Fblob\u002Fmain\u002Fskills\u002Fscout-mcp\u002FSKILL.md",[164],{"categoryNo":165,"categoryName":166,"taxonomyType":95,"taxonomyTypeDesc":96},"01JBSEEDCAT000000000000023","Skill与智能体开发",[168,169,130,148,170,171,172,173,174,39,175,176,46,177,48,178,179,54,180,23,146,117,35,181,119],"MCP","scout mcp","mcp server","ai agent","auth","config","run","server","SET","model","read","snapshot","ready","agent-context",{"skillNo":183,"name":184,"nameZh":6,"description":185,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":186,"categories":187,"keywords":188,"publishedAt":55},"01M6CBP7D72G704FWGRXNB6F9T","scout-ingest","Use when the user wants to ADOPT existing Kubernetes \u002F GitOps workload structure into ConfigHub after observing the live cluster — the adoption\u002Fimport verb group of cub-scout. Natural phrasing: \"discover workloads in this cluster and propose ConfigHub units\", \"show me the import proposal before I apply\", \"import this Argo Application set\", \"bring my Flux Kustomizations into ConfigHub\", \"preview what would land in ConfigHub if I imported this repo\", \"parse my git repo as a ConfigHub import bundle\", \"import a cluster aggregator\", \"what would --git-path produce for this repo?\". Load whenever intent is adopt \u002F import \u002F ingest \u002F preview \u002F propose \u002F parse-repo \u002F discovery \u002F aggregator \u002F bring-into-confighub \u002F what-would-confighub-see. Do NOT load for: questions about who changed a resource, whether it was edited by hand or drifted (use scout-attribute or investigate-drift); reading an exported `kubectl get -o yaml` dump to answer a question about the cluster (that is not an import); basic live-cluster inventory (use scout-observe), troubleshooting (use scout-diagnose), comparing live state to ConfigHub (use scout-compare), or the actual write to ConfigHub via `cub variant upload` (that is `cub`, not cub-scout — route to cub skills). Important: `cub-scout import apply` IS the mutating write into ConfigHub — this skill teaches the read-only preview path and explicitly refuses to invoke `import apply` itself.","https:\u002F\u002Fgithub.com\u002Fconfighub\u002Fcub-scout\u002Fblob\u002Fmain\u002Fskills\u002Fscout-ingest\u002FSKILL.md",[],[189,190,130,101,102,39,191,131,192,176,151,193,134,46,48,194,111,178,195,52,53,54,146,26,28,196,197,198,199,33,35,200,201,202,203],"ingest","scout ingest","state","adoption","discovery","repo","write","structure","aggregator","adopt","argo","reading","exported","invoke","parse",{"skillNo":205,"name":206,"nameZh":6,"description":207,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":208,"categories":209,"keywords":210,"publishedAt":55},"01M6CBP32CYJT8DJSGNCRWXQTM","scout-govern","Use when the user wants to consume CONNECTED ConfigHub governance signals from cub-scout — the Govern verb group. Natural phrasing: \"show me the ChangeSet history for this unit\", \"what is the blast radius if I change this unit?\", \"which clusters in my fleet are outliers?\", \"show me yesterday's connected summary\", \"render this view across the fleet\", \"audit who changed this\", \"where did the last apply come from?\", \"list ConfigHub bundles I have\", \"show me the catalog of past snapshots\". Load whenever intent is history \u002F impact \u002F blast-radius \u002F fleet-outliers \u002F summary \u002F view \u002F audit \u002F bundle \u002F catalog \u002F connected-context. Do NOT load for: live cluster comparison (use scout-compare), receipts (use scout-verify), inventory of running pods (use scout-observe), or any mutation via cub. Most of this skill requires `cub auth login` — say so upfront.","https:\u002F\u002Fgithub.com\u002Fconfighub\u002Fcub-scout\u002Fblob\u002Fmain\u002Fskills\u002Fscout-govern\u002FSKILL.md",[],[211,130,212,172,213,214,215,151,128,134,46,216,48,52,217,53,218,219,220,146,26,28,221,117,222,223,35,224,225,226,227,119],"scout govern","change","governance","blast radius","audit","history","catalog","diff","say","snapshots","project","mutation","impact","render","blast-radius","which","inspect"]