[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CBK0XHNFKCPFTX5RQCB487":3,"skill-same:01M6CBK0XHNFKCPFTX5RQCB487":81},{"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":50,"linkOnly":51,"markdownContent":52,"markdownBody":53,"frontMatter":54,"refName":57,"commitSha":58,"skillDirectory":59,"forksCount":60,"repositoryHtmlUrl":61,"repositoryHomepageUrl":62,"ownerHtmlUrl":63,"ownerBlogUrl":64,"ownerDescription":65,"updatedAt":66,"install":67,"resources":80},"01M6CBK0XHNFKCPFTX5RQCB487","investigate-drift",null,"Use when the user wants to compare live and desired state and inspect available manager and source evidence. Natural phrasing: \"why is this Deployment different from the git manifest?\", \"which recognized manager is recorded for this path?\", \"controller-drift or interactive-manager evidence?\", \"compare three-way + attribution for deploy\u002Fapi\". Composes `compare three-way` + `compare drift` + the attribution layer (`cause` \u002F `managerHint` \u002F `gitSource` \u002F `bindingSource`). Do NOT promise who changed the value or which manager wrote last: path-level manager evidence is not time-ordered, and resource-level `explain` evidence is not field-specific. Do NOT load for: a triage where the workload won't start (use triage-unhealthy-workload), pure inventory (use scout-observe), generating a fingerprinted evidence artifact (use scout-verify and the no-manual-edits-since predicate), or any mutating fix (cub-scout never mutates).","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\u002Finvestigate-drift\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],"investigate","drift","investigate drift","use","when","managed","inspect","which","unit","app","get","time","show","scout compare","observe","evidence","never","deployment","fix","interactive","view","argocd","changeset","explain","Bash","api","inventory","manifest","controller","attribution","state","2026-11-10 10:12:30",false,"---\nname: investigate-drift\ndescription: 'Use when the user wants to compare live and desired state and inspect available manager and source evidence. Natural phrasing: \"why is this Deployment different from the git manifest?\", \"which recognized manager is recorded for this path?\", \"controller-drift or interactive-manager evidence?\", \"compare three-way + attribution for deploy\u002Fapi\". Composes `compare three-way` + `compare drift` + the attribution layer (`cause` \u002F `managerHint` \u002F `gitSource` \u002F `bindingSource`). Do NOT promise who changed the value or which manager wrote last: path-level manager evidence is not time-ordered, and resource-level `explain` evidence is not field-specific. Do NOT load for: a triage where the workload won''t start (use triage-unhealthy-workload), pure inventory (use scout-observe), generating a fingerprinted evidence artifact (use scout-verify and the no-manual-edits-since predicate), or any mutating fix (cub-scout never mutates).'\nphase: cross-cutting\nallowed-tools: 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 explain *) Bash(cub-scout explain *) Bash(cub scout explain *) Bash(.\u002Fcub-scout trace *) Bash(cub-scout trace *) Bash(cub scout trace *) Bash(kubectl get *) Bash(kubectl describe *) Bash(kubectl get --show-managed-fields *) 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# investigate-drift\n\nThe drift-investigation loop. Live state does not match desired state, so compare the values and inspect available provenance. Composes `compare three-way` (DRY\u002FWET\u002FLIVE) + `compare drift` (file\u002Fbundle vs cluster) + attribution (`cause` \u002F `managerHint` \u002F `gitSource` \u002F `bindingSource`). Manager evidence classifies recognized managers; it does not establish write order or human identity.\n\n## When to use\n\nExplicit phrasings:\n\n- \"Why is deploy\u002Fapi different from the git manifest?\"\n- \"Is a recognized interactive manager recorded for this path?\"\n- \"Which recognized controller or interactive manager is recorded?\"\n- \"controller-drift or manual-edit?\"\n- \"Find the field that diverged and show its available manager evidence\"\n- \"Compare three-way + attribution for deploy\u002Fapi in prod\"\n- \"The cluster says replicas=1, ConfigHub says 3 — what happened?\"\n\nImplicit intents:\n\n- The user knows there's a divergence; they need the **per-field** detail\n- The user wants the **cause** classified, not just the diff\n- The user is planning a *response* (revert to controller \u002F port edit to git \u002F accept manual change)\n- The user may need to attach the result to a release-gate decision\n\n## Do not load for\n\n- A pager-pressed triage where the workload is broken — [`triage-unhealthy-workload`](..\u002Ftriage-unhealthy-workload\u002FSKILL.md)\n- Pure inventory (\"what's running\") — [`scout-observe`](..\u002Fscout-observe\u002FSKILL.md)\n- Generating a fingerprinted evidence receipt — [`scout-verify`](..\u002Fscout-verify\u002FSKILL.md), specifically the `no-manual-edits-since` predicate\n- Audit-fleet-wide conformance (\"which clusters are outliers?\") — [`audit-fleet-conformance`](..\u002Faudit-fleet-conformance\u002FSKILL.md)\n- Any mutating fix — cub-scout never applies. Route to `kubectl rollout undo`, `cub` for ConfigHub updates, or a git commit.\n\n## The loop\n\n1. **Detect the diff** with `compare three-way` (connected) or `compare drift --file \u003Cyaml>` (standalone).\n2. **Inspect manager evidence** on each `compareFieldMismatch`. Path-specific classifications require decodable `FieldsV1` and a mapped canonical path; otherwise the result can be a resource-level fallback, which must not be attributed to that field:\n   - `cause`: `controller-drift` \u002F `manual-edit` \u002F `unknown`\n   - `managerHint`: a representative recognized K8s `managedFields` manager string for the path classification or fallback\n   - `gitSource`: where the desired value comes from (repo \u002F revision \u002F path \u002F file:line if stage B back-resolution is wired)\n   - `bindingSource` (connected): which ConfigHub Link supplied this field\n3. **Interpret the manager string conservatively** using [`references\u002Fverified-manager-strings.md`](..\u002Freferences\u002Fverified-manager-strings.md):\n   - `argocd-controller` \u002F `kustomize-controller` \u002F `helm-controller` → recognized controller-manager evidence; this does not show reconciliation is happening now\n   - `kubectl-edit` \u002F `kubectl-patch` \u002F `kubectl-apply` → recognized interactive-manager evidence; it does not identify the person or prove write order\n   - `kubectl-client-side-apply` + Argo owner → Argo CSA migration co-signal; manager strings alone do not identify a human\n4. **Decide the response** based on cause + the operator's policy. cub-scout doesn't pick; the user does.\n\n## Step-by-step\n\n### Step 1 — detect the diff\n\n**Connected mode (preferred):** DRY (ConfigHub intent) vs WET (rendered) vs LIVE (cluster).\n\n```bash\n$ cub-scout compare three-way deploy\u002Fapi -n prod --format json\n{\n  \"agreement\": \"diverged\",\n  \"summary\": { \"agreed\": 5, \"diverged\": 2 },\n  \"fieldMismatches\": [\n    {\n      \"path\": \".spec.replicas\",\n      \"dry\": 3, \"wet\": 3, \"live\": 1,\n      \"attribution\": {\n        \"cause\": \"manual-edit\",\n        \"managerHint\": \"kubectl-edit\",\n        \"gitSource\": { \"repoUrl\": \"https:\u002F\u002Fgithub.com\u002Forg\u002Fplatform-config\", \"revision\": \"abc123\", \"path\": \"apps\u002Fprod\u002Fapi\" }\n      }\n    }\n  ]\n}\n```\n\n**Standalone mode:** `compare drift --file desired.yaml -n prod` for a file-vs-live diff. Or `compare three-way --source-path \u003Clocal-git-checkout>` for stage B back-resolution (file:line per field).\n\n### Step 2 — read the attribution\n\nEach `compareFieldMismatch.attribution` block carries the per-field provenance. The fields:\n\n| Field | Meaning |\n|-------|---------|\n| `cause` | One of `controller-drift` \u002F `manual-edit` \u002F `unknown` (verified manager-string enumeration in `pkg\u002Fagent\u002Fmanager_strings.go`) |\n| `managerHint` | A representative recognized manager string; not proof of the latest writer or a person |\n| `gitSource.{repoUrl, revision, path}` | Resource-level git anchor from the Argo \u002F Flux tracer (A2) |\n| `gitSource.{file, line}` | Stage B back-resolution (`--source-path \u003Clocal-checkout>`) — the exact YAML file:line where the field was set |\n| `bindingSource` (connected) | `{unit, path, link}` — which ConfigHub Link supplies this field's value (C2) |\n\nThe `cause` classifies recognized manager evidence. `managerHint` is a manager string, not a person or timestamped writer identity. The git\u002Fbinding sources point to desired-state provenance.\n\n### Step 3 — interpret manager evidence\n\nRead the manager-string enumeration in [`references\u002Fverified-manager-strings.md`](..\u002Freferences\u002Fverified-manager-strings.md). These are manager classifications, not proof of a current reconciliation or human action:\n\n| Writer | Owner context | Meaning |\n|--------|--------------|---------|\n| `argocd-controller` | Argo-owned | Recognized Argo controller-manager evidence. `controller-drift`; recency is not established. |\n| `kubectl-client-side-apply` | Argo-owned | Argo CSA migration co-signal. `controller-drift`; does not establish recency. |\n| `kubectl-client-side-apply` | Native (no Argo signal) | Classified as interactive-manager evidence. `manual-edit`; the human identity is unknown. |\n| `kustomize-controller` \u002F `helm-controller` | Flux-owned | Recognized Flux controller-manager evidence. `controller-drift`; recency is not established. |\n| `kubectl-edit` \u002F `kubectl-patch` | Any | Recognized interactive-manager evidence. `manual-edit`; person and write order are unknown. |\n| `apiextensions.crossplane.io\u002Fcomposed-\u003Chash>` | Crossplane-owned | Recognized Crossplane composed-resource manager evidence. `controller-drift`; recency is not established. |\n| `helm` (bare) | Helm-direct | Helm manager evidence. `controller-drift` for OwnerHelm; it does not establish a person or write order. |\n| Unrecognized | Any | `cause=unknown`. cub-scout parses; it does not guess. |\n\nThe owner co-signal is essential for the `kubectl-client-side-apply` disambiguation. See [`observe-argocd`](..\u002Fobserve-argocd\u002FSKILL.md) for the full rule.\n\n### Step 4 — decide the response\n\ncub-scout produces the evidence; the operator picks the action.\n\n| Cause | Common operator response (mutations are user-driven) |\n|-------|----------------------------------------------------|\n| `controller-drift` + independently observed recent sync | Compare live values again and inspect controller health; manager evidence alone does not show it is reconciling or that the diff is transient. |\n| `controller-drift` + persistent | Investigate controller status (Argo `OutOfSync`, Flux `False`, kstatus failure); do not infer a broken reconciler from manager evidence alone. |\n| `manual-edit` + change should be kept | Verify the live value and desired source, then port an approved change back to git. |\n| `manual-edit` + change should be reverted | Verify policy and live value, then have the operator restore desired state; do not assume which value is newest. |\n| `manual-edit` + change should be accepted as canonical | Verify and review the live value, then update the source of truth through the operator's normal process. |\n| `unknown` | Cannot classify. Missing, incomplete, unmapped, or unrecognized evidence can all yield unknown; investigate the available metadata without guessing. |\n\n## Worked example\n\nProduction `deploy\u002Fapi` has 1 replica; ConfigHub says 3. Argo CD is in `Synced` state. The operator's question: \"did Argo do this, or did someone?\"\n\n```bash\n$ cub-scout compare three-way deploy\u002Fapi -n prod\nThree-way compare for Deployment\u002Fapi in prod\n\nAgreement: DIVERGED — 2 of 7 fields disagree\n\nField mismatches:\n  .spec.replicas\n    DRY (ConfigHub unit payments-api rev=42):    3\n    WET (rendered):                              3\n    LIVE (cluster):                              1\n    Cause:        manual-edit (manager: kubectl-edit)\n    Git source:   https:\u002F\u002Fgithub.com\u002Forg\u002Fplatform-config @abc123 path=apps\u002Fprod\u002Fapi\n  .spec.template.spec.containers[0].resources.requests.cpu\n    DRY:  500m\n    WET:  500m\n    LIVE: 250m\n    Cause:        manual-edit (manager: kubectl-patch)\n    Git source:   (same)\n```\n\n**Reading:** If these are path-specific classifications, each path has recognized interactive-manager evidence; controller-manager evidence may also be present. The strings do not prove separate commands, identify a person, or establish that Argo's last sync predates these values. Check the actual live and desired values and the controller status independently.\n\n**Response options:**\n\n- If the live values should return to desired state, have the operator restore them through the approved workflow and verify reconciliation.\n- If the live values should become canonical, have the operator review and update the source of truth through the normal workflow.\n- Manager evidence alone does not establish that somebody bypassed GitOps. For time-bounded history, use a suitable audit source or the receipt predicate with its documented timestamp evidence.\n\ncub-scout produced the evidence in one command. The decision is the operator's.\n\n## Connected-mode enrichment\n\nWith `cub auth login`, `compare three-way` adds:\n\n- **DRY column** — the ConfigHub Unit's intent (the canonical \"what we asked for\")\n- **`bindingSource` per field** — which ConfigHub Link supplies this value (e.g., `link:env-shared.replicas`). Per-field provenance into the unit graph.\n- **`confighubUrl`** — deep-link to the unit's revision in the ConfigHub GUI\n- **`incomingBindings[]`** on the unit — which upstream units feed this unit\n\nStandalone mode loses the DRY column and bindingSource; what remains is the WET (file) vs LIVE (cluster) diff. A path-specific manager classification is available only when decodable `FieldsV1` maps the mismatch; otherwise output may be resource-level or unknown. It still does not establish write order or a person.\n\n## Tool boundary\n\n- **Allowed:** the four Compare verbs; `explain`, `trace`; `kubectl get\u002Fdescribe\u002Fget --show-managed-fields`; `cub \u003Centity> get \u002F list` for the entities named in allowed-tools (connected); `argocd app get`, `flux get` (controller-side reads)\n- **Not allowed:** `kubectl rollout undo`, `kubectl edit`, `kubectl patch`, `argocd app sync`, `flux reconcile`, `cub * update\u002Fcreate\u002Fdelete`. The investigation produces evidence; the response is the operator's. cub-scout's `compare three-way --fail-on` and `--suggest` flags work for CI gating but do not write.\n\n## References\n\n- [`scout-compare`](..\u002Fscout-compare\u002FSKILL.md) — the verb group this skill composes\n- [`scout-attribute`](..\u002Fscout-attribute\u002FSKILL.md) — the attribution-layer evidence surface\n- [`references\u002Fkubernetes-managedfields.md`](..\u002Freferences\u002Fkubernetes-managedfields.md) — the data substrate\n- [`references\u002Fverified-manager-strings.md`](..\u002Freferences\u002Fverified-manager-strings.md) — the writer enumeration\n- [`observe-argocd`](..\u002Fobserve-argocd\u002FSKILL.md), [`observe-flux`](..\u002Fobserve-flux\u002FSKILL.md) — owner co-signals for disambiguation\n- [`scout-verify`](..\u002Fscout-verify\u002FSKILL.md) — the `no-manual-edits-since` predicate captures the same evidence as a fingerprinted receipt\n- Attribution layer issues: `#435` (parent), `#437` (A1+A1.5+A2), `#438` (C1), `#439` (C2), `#440` (stage B)\n- Example: [`examples\u002Fdrift\u002Fmutation-cause-attribution\u002F`](..\u002F..\u002Fexamples\u002Fdrift\u002Fmutation-cause-attribution\u002F)\n\n## Constraints\n\n- This skill is **investigation**, not remediation. cub-scout categorically never applies a fix. Every revert \u002F port \u002F accept is the operator running another tool.\n- `cause=unknown` is honest when manager evidence is missing, incomplete, unmapped, or unrecognized. Don't pressure-classify it.\n- `controller-drift` and `manual-edit` describe recognized manager presence in the resource or mapped path. The classifier does not use manager timestamps to order writers or prove a person acted; inspect audit logs for identity\u002Fhistory.\n- Stage B file:line back-resolution requires `--source-path \u003Clocal-git-checkout>` and only covers raw YAML (no Helm \u002F Kustomize templating yet — see #435 follow-ons).\n","# investigate-drift\n\nThe drift-investigation loop. Live state does not match desired state, so compare the values and inspect available provenance. Composes `compare three-way` (DRY\u002FWET\u002FLIVE) + `compare drift` (file\u002Fbundle vs cluster) + attribution (`cause` \u002F `managerHint` \u002F `gitSource` \u002F `bindingSource`). Manager evidence classifies recognized managers; it does not establish write order or human identity.\n\n## When to use\n\nExplicit phrasings:\n\n- \"Why is deploy\u002Fapi different from the git manifest?\"\n- \"Is a recognized interactive manager recorded for this path?\"\n- \"Which recognized controller or interactive manager is recorded?\"\n- \"controller-drift or manual-edit?\"\n- \"Find the field that diverged and show its available manager evidence\"\n- \"Compare three-way + attribution for deploy\u002Fapi in prod\"\n- \"The cluster says replicas=1, ConfigHub says 3 — what happened?\"\n\nImplicit intents:\n\n- The user knows there's a divergence; they need the **per-field** detail\n- The user wants the **cause** classified, not just the diff\n- The user is planning a *response* (revert to controller \u002F port edit to git \u002F accept manual change)\n- The user may need to attach the result to a release-gate decision\n\n## Do not load for\n\n- A pager-pressed triage where the workload is broken — [`triage-unhealthy-workload`](..\u002Ftriage-unhealthy-workload\u002FSKILL.md)\n- Pure inventory (\"what's running\") — [`scout-observe`](..\u002Fscout-observe\u002FSKILL.md)\n- Generating a fingerprinted evidence receipt — [`scout-verify`](..\u002Fscout-verify\u002FSKILL.md), specifically the `no-manual-edits-since` predicate\n- Audit-fleet-wide conformance (\"which clusters are outliers?\") — [`audit-fleet-conformance`](..\u002Faudit-fleet-conformance\u002FSKILL.md)\n- Any mutating fix — cub-scout never applies. Route to `kubectl rollout undo`, `cub` for ConfigHub updates, or a git commit.\n\n## The loop\n\n1. **Detect the diff** with `compare three-way` (connected) or `compare drift --file \u003Cyaml>` (standalone).\n2. **Inspect manager evidence** on each `compareFieldMismatch`. Path-specific classifications require decodable `FieldsV1` and a mapped canonical path; otherwise the result can be a resource-level fallback, which must not be attributed to that field:\n   - `cause`: `controller-drift` \u002F `manual-edit` \u002F `unknown`\n   - `managerHint`: a representative recognized K8s `managedFields` manager string for the path classification or fallback\n   - `gitSource`: where the desired value comes from (repo \u002F revision \u002F path \u002F file:line if stage B back-resolution is wired)\n   - `bindingSource` (connected): which ConfigHub Link supplied this field\n3. **Interpret the manager string conservatively** using [`references\u002Fverified-manager-strings.md`](..\u002Freferences\u002Fverified-manager-strings.md):\n   - `argocd-controller` \u002F `kustomize-controller` \u002F `helm-controller` → recognized controller-manager evidence; this does not show reconciliation is happening now\n   - `kubectl-edit` \u002F `kubectl-patch` \u002F `kubectl-apply` → recognized interactive-manager evidence; it does not identify the person or prove write order\n   - `kubectl-client-side-apply` + Argo owner → Argo CSA migration co-signal; manager strings alone do not identify a human\n4. **Decide the response** based on cause + the operator's policy. cub-scout doesn't pick; the user does.\n\n## Step-by-step\n\n### Step 1 — detect the diff\n\n**Connected mode (preferred):** DRY (ConfigHub intent) vs WET (rendered) vs LIVE (cluster).\n\n```bash\n$ cub-scout compare three-way deploy\u002Fapi -n prod --format json\n{\n  \"agreement\": \"diverged\",\n  \"summary\": { \"agreed\": 5, \"diverged\": 2 },\n  \"fieldMismatches\": [\n    {\n      \"path\": \".spec.replicas\",\n      \"dry\": 3, \"wet\": 3, \"live\": 1,\n      \"attribution\": {\n        \"cause\": \"manual-edit\",\n        \"managerHint\": \"kubectl-edit\",\n        \"gitSource\": { \"repoUrl\": \"https:\u002F\u002Fgithub.com\u002Forg\u002Fplatform-config\", \"revision\": \"abc123\", \"path\": \"apps\u002Fprod\u002Fapi\" }\n      }\n    }\n  ]\n}\n```\n\n**Standalone mode:** `compare drift --file desired.yaml -n prod` for a file-vs-live diff. Or `compare three-way --source-path \u003Clocal-git-checkout>` for stage B back-resolution (file:line per field).\n\n### Step 2 — read the attribution\n\nEach `compareFieldMismatch.attribution` block carries the per-field provenance. The fields:\n\n| Field | Meaning |\n|-------|---------|\n| `cause` | One of `controller-drift` \u002F `manual-edit` \u002F `unknown` (verified manager-string enumeration in `pkg\u002Fagent\u002Fmanager_strings.go`) |\n| `managerHint` | A representative recognized manager string; not proof of the latest writer or a person |\n| `gitSource.{repoUrl, revision, path}` | Resource-level git anchor from the Argo \u002F Flux tracer (A2) |\n| `gitSource.{file, line}` | Stage B back-resolution (`--source-path \u003Clocal-checkout>`) — the exact YAML file:line where the field was set |\n| `bindingSource` (connected) | `{unit, path, link}` — which ConfigHub Link supplies this field's value (C2) |\n\nThe `cause` classifies recognized manager evidence. `managerHint` is a manager string, not a person or timestamped writer identity. The git\u002Fbinding sources point to desired-state provenance.\n\n### Step 3 — interpret manager evidence\n\nRead the manager-string enumeration in [`references\u002Fverified-manager-strings.md`](..\u002Freferences\u002Fverified-manager-strings.md). These are manager classifications, not proof of a current reconciliation or human action:\n\n| Writer | Owner context | Meaning |\n|--------|--------------|---------|\n| `argocd-controller` | Argo-owned | Recognized Argo controller-manager evidence. `controller-drift`; recency is not established. |\n| `kubectl-client-side-apply` | Argo-owned | Argo CSA migration co-signal. `controller-drift`; does not establish recency. |\n| `kubectl-client-side-apply` | Native (no Argo signal) | Classified as interactive-manager evidence. `manual-edit`; the human identity is unknown. |\n| `kustomize-controller` \u002F `helm-controller` | Flux-owned | Recognized Flux controller-manager evidence. `controller-drift`; recency is not established. |\n| `kubectl-edit` \u002F `kubectl-patch` | Any | Recognized interactive-manager evidence. `manual-edit`; person and write order are unknown. |\n| `apiextensions.crossplane.io\u002Fcomposed-\u003Chash>` | Crossplane-owned | Recognized Crossplane composed-resource manager evidence. `controller-drift`; recency is not established. |\n| `helm` (bare) | Helm-direct | Helm manager evidence. `controller-drift` for OwnerHelm; it does not establish a person or write order. |\n| Unrecognized | Any | `cause=unknown`. cub-scout parses; it does not guess. |\n\nThe owner co-signal is essential for the `kubectl-client-side-apply` disambiguation. See [`observe-argocd`](..\u002Fobserve-argocd\u002FSKILL.md) for the full rule.\n\n### Step 4 — decide the response\n\ncub-scout produces the evidence; the operator picks the action.\n\n| Cause | Common operator response (mutations are user-driven) |\n|-------|----------------------------------------------------|\n| `controller-drift` + independently observed recent sync | Compare live values again and inspect controller health; manager evidence alone does not show it is reconciling or that the diff is transient. |\n| `controller-drift` + persistent | Investigate controller status (Argo `OutOfSync`, Flux `False`, kstatus failure); do not infer a broken reconciler from manager evidence alone. |\n| `manual-edit` + change should be kept | Verify the live value and desired source, then port an approved change back to git. |\n| `manual-edit` + change should be reverted | Verify policy and live value, then have the operator restore desired state; do not assume which value is newest. |\n| `manual-edit` + change should be accepted as canonical | Verify and review the live value, then update the source of truth through the operator's normal process. |\n| `unknown` | Cannot classify. Missing, incomplete, unmapped, or unrecognized evidence can all yield unknown; investigate the available metadata without guessing. |\n\n## Worked example\n\nProduction `deploy\u002Fapi` has 1 replica; ConfigHub says 3. Argo CD is in `Synced` state. The operator's question: \"did Argo do this, or did someone?\"\n\n```bash\n$ cub-scout compare three-way deploy\u002Fapi -n prod\nThree-way compare for Deployment\u002Fapi in prod\n\nAgreement: DIVERGED — 2 of 7 fields disagree\n\nField mismatches:\n  .spec.replicas\n    DRY (ConfigHub unit payments-api rev=42):    3\n    WET (rendered):                              3\n    LIVE (cluster):                              1\n    Cause:        manual-edit (manager: kubectl-edit)\n    Git source:   https:\u002F\u002Fgithub.com\u002Forg\u002Fplatform-config @abc123 path=apps\u002Fprod\u002Fapi\n  .spec.template.spec.containers[0].resources.requests.cpu\n    DRY:  500m\n    WET:  500m\n    LIVE: 250m\n    Cause:        manual-edit (manager: kubectl-patch)\n    Git source:   (same)\n```\n\n**Reading:** If these are path-specific classifications, each path has recognized interactive-manager evidence; controller-manager evidence may also be present. The strings do not prove separate commands, identify a person, or establish that Argo's last sync predates these values. Check the actual live and desired values and the controller status independently.\n\n**Response options:**\n\n- If the live values should return to desired state, have the operator restore them through the approved workflow and verify reconciliation.\n- If the live values should become canonical, have the operator review and update the source of truth through the normal workflow.\n- Manager evidence alone does not establish that somebody bypassed GitOps. For time-bounded history, use a suitable audit source or the receipt predicate with its documented timestamp evidence.\n\ncub-scout produced the evidence in one command. The decision is the operator's.\n\n## Connected-mode enrichment\n\nWith `cub auth login`, `compare three-way` adds:\n\n- **DRY column** — the ConfigHub Unit's intent (the canonical \"what we asked for\")\n- **`bindingSource` per field** — which ConfigHub Link supplies this value (e.g., `link:env-shared.replicas`). Per-field provenance into the unit graph.\n- **`confighubUrl`** — deep-link to the unit's revision in the ConfigHub GUI\n- **`incomingBindings[]`** on the unit — which upstream units feed this unit\n\nStandalone mode loses the DRY column and bindingSource; what remains is the WET (file) vs LIVE (cluster) diff. A path-specific manager classification is available only when decodable `FieldsV1` maps the mismatch; otherwise output may be resource-level or unknown. It still does not establish write order or a person.\n\n## Tool boundary\n\n- **Allowed:** the four Compare verbs; `explain`, `trace`; `kubectl get\u002Fdescribe\u002Fget --show-managed-fields`; `cub \u003Centity> get \u002F list` for the entities named in allowed-tools (connected); `argocd app get`, `flux get` (controller-side reads)\n- **Not allowed:** `kubectl rollout undo`, `kubectl edit`, `kubectl patch`, `argocd app sync`, `flux reconcile`, `cub * update\u002Fcreate\u002Fdelete`. The investigation produces evidence; the response is the operator's. cub-scout's `compare three-way --fail-on` and `--suggest` flags work for CI gating but do not write.\n\n## References\n\n- [`scout-compare`](..\u002Fscout-compare\u002FSKILL.md) — the verb group this skill composes\n- [`scout-attribute`](..\u002Fscout-attribute\u002FSKILL.md) — the attribution-layer evidence surface\n- [`references\u002Fkubernetes-managedfields.md`](..\u002Freferences\u002Fkubernetes-managedfields.md) — the data substrate\n- [`references\u002Fverified-manager-strings.md`](..\u002Freferences\u002Fverified-manager-strings.md) — the writer enumeration\n- [`observe-argocd`](..\u002Fobserve-argocd\u002FSKILL.md), [`observe-flux`](..\u002Fobserve-flux\u002FSKILL.md) — owner co-signals for disambiguation\n- [`scout-verify`](..\u002Fscout-verify\u002FSKILL.md) — the `no-manual-edits-since` predicate captures the same evidence as a fingerprinted receipt\n- Attribution layer issues: `#435` (parent), `#437` (A1+A1.5+A2), `#438` (C1), `#439` (C2), `#440` (stage B)\n- Example: [`examples\u002Fdrift\u002Fmutation-cause-attribution\u002F`](..\u002F..\u002Fexamples\u002Fdrift\u002Fmutation-cause-attribution\u002F)\n\n## Constraints\n\n- This skill is **investigation**, not remediation. cub-scout categorically never applies a fix. Every revert \u002F port \u002F accept is the operator running another tool.\n- `cause=unknown` is honest when manager evidence is missing, incomplete, unmapped, or unrecognized. Don't pressure-classify it.\n- `controller-drift` and `manual-edit` describe recognized manager presence in the resource or mapped path. The classifier does not use manager timestamps to order writers or prove a person acted; inspect audit logs for identity\u002Fhistory.\n- Stage B file:line back-resolution requires `--source-path \u003Clocal-git-checkout>` and only covers raw YAML (no Helm \u002F Kustomize templating yet — see #435 follow-ons).\n",{"name":5,"phase":55,"description":7,"allowed-tools":56},"cross-cutting","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 explain *) Bash(cub-scout explain *) Bash(cub scout explain *) Bash(.\u002Fcub-scout trace *) Bash(cub-scout trace *) Bash(cub scout trace *) Bash(kubectl get *) Bash(kubectl describe *) Bash(kubectl get --show-managed-fields *) 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\u002Finvestigate-drift",1,"https:\u002F\u002Fgithub.com\u002Fconfighub\u002Fcub-scout","https:\u002F\u002Fconfighub.com","https:\u002F\u002Fgithub.com\u002Fconfighub","http:\u002F\u002Fwww.confighub.com","Public repo for ConfigHub","2026-11-14 03:24:15",{"source":8,"skillName":5,"commands":68,"prompt":78,"zipAvailable":79},[69,72,75],{"tool":70,"command":71},"npx","npx skills add confighub\u002Fcub-scout --skill investigate-drift",{"tool":73,"command":74},"bunx","bunx skills add confighub\u002Fcub-scout --skill investigate-drift",{"tool":76,"command":77},"pnpm","pnpm dlx skills add confighub\u002Fcub-scout --skill investigate-drift","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fconfighub\u002Fcub-scout\u002Fblob\u002Fmain\u002Fskills\u002Finvestigate-drift\u002FSKILL.md",true,[],[82,112,130,147,173,194],{"skillNo":83,"name":84,"nameZh":6,"description":85,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":86,"categories":87,"keywords":93,"publishedAt":50},"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",[88],{"categoryNo":89,"categoryName":90,"taxonomyType":91,"taxonomyTypeDesc":92},"01JBSEEDCAT000000000000011","运维与部署","SCENARIO","使用场景",[94,95,96,97,98,99,100,101,102,44,43,103,42,104,105,106,22,107,35,108,109,20,110,30,29,111,23],"triage","workload","triage unhealthy workload","kubernetes","diagnose","doctor","logs","ci","payments","loop","check","broken","question","rollout","cub scout","route","map","now",{"skillNo":113,"name":114,"nameZh":6,"description":115,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":116,"categories":117,"keywords":119,"publishedAt":50},"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",[118],{"categoryNo":89,"categoryName":90,"taxonomyType":91,"taxonomyTypeDesc":92},[120,121,122,97,123,124,101,125,126,44,127,43,128,41,40,39,37,22,35,34,108,31,109,129,29,28,27,24,23],"verify","scout verify","scout","acceptance","produce","attestation","provenance","show me","postmortem","me",{"skillNo":131,"name":132,"nameZh":6,"description":133,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":134,"categories":135,"keywords":136,"publishedAt":50},"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",[],[33,137,122,138,97,98,36,99,100,139,126,45,127,43,105,22,140,35,141,142,108,31,143,144,110,29,145,146,23],"scout observe","bot","risk","version","only","hooks","back","health-check","resources","meaning",{"skillNo":148,"name":149,"nameZh":6,"description":150,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":151,"categories":152,"keywords":156,"publishedAt":50},"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",[153],{"categoryNo":154,"categoryName":155,"taxonomyType":91,"taxonomyTypeDesc":92},"01JBSEEDCAT000000000000023","Skill与智能体开发",[157,158,122,138,159,160,161,162,163,164,165,166,43,167,41,168,169,141,170,171,33,29,27,172,23],"MCP","scout mcp","mcp server","ai agent","auth","config","run","release","server","SET","model","read","snapshot","ready","up","agent-context",{"skillNo":174,"name":175,"nameZh":6,"description":176,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":177,"categories":178,"keywords":179,"publishedAt":50},"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",[],[180,181,122,97,98,164,49,124,182,166,45,183,127,43,41,184,106,168,185,39,22,141,33,108,31,186,187,188,189,28,27,190,191,192,193],"ingest","scout ingest","adoption","discovery","repo","write","structure","aggregator","adopt","argo","reading","exported","invoke","parse",{"skillNo":195,"name":196,"nameZh":6,"description":197,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":198,"categories":199,"keywords":200,"publishedAt":50},"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",[],[201,122,202,161,203,204,205,45,120,127,43,206,41,39,207,22,208,209,210,33,108,31,211,29,212,213,27,214,215,26,25,23],"scout govern","change","governance","blast radius","audit","history","catalog","diff","say","snapshots","project","mutation","impact","render","blast-radius"]