[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CBNQNGTKE138SFG3VBD2PY":3,"skill-same:01M6CBNQNGTKE138SFG3VBD2PY":93},{"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":56,"linkOnly":57,"markdownContent":58,"markdownBody":59,"frontMatter":60,"refName":63,"commitSha":64,"skillDirectory":65,"forksCount":66,"repositoryHtmlUrl":67,"repositoryHomepageUrl":68,"ownerHtmlUrl":69,"ownerBlogUrl":70,"ownerDescription":71,"updatedAt":72,"install":73,"resources":86},"01M6CBNQNGTKE138SFG3VBD2PY","scout-attribute",null,"Use when the user wants manager evidence for a field value on a running Kubernetes resource — which recognized controller or interactive manager is recorded for a path, which git file or ConfigHub Link supplies desired state, or whether resource-level managedFields contains an interactive manager. Natural phrasing: \"why is replicas: 1 in prod?\", \"does this resource show a kubectl manager?\", \"is Argo still reconciling or is an interactive manager recorded?\", \"what git commit set this image tag?\", \"which upstream unit feeds this field?\", \"where does this value come from?\", \"show me the provenance of this Deployment\", \"is this controller-drift or manual-edit?\", \"has an interactive manager changed this Deployment?\", \"which manager is recorded for this field?\". Load whenever attribution \u002F provenance \u002F lineage \u002F git-blame-for-runtime intent appears, especially on `compare` and `explain` output. For a known resource and exact canonical field path, `explain --field-path` can return only that path’s manager evidence; `explain` without the selector has a resource-level summary. Do NOT promise the latest writer or a human identity from manager evidence: exact-path and compare results do not order managers by time. Do NOT load for: pure ownership classification at the resource level (use scout-observe — that gives Owner=Argo\u002FFlux\u002Fetc., not per-field), source-truth strategy verdicts (use scout-compare), or live-cluster mutation (cub-scout cannot mutate — that is `cub` or `kubectl` with user driving).","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\u002Fscout-attribute\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,55],"scout attribute","scout","show","strategy","use","only","evidence","observe","cub scout","scout compare","list","writer","time","human","mutation","argo","unit","which","at","feeds","kubernetes","git commit","deployment","git","lineage","file","attribution","kubectl","image","controller","SET","provenance","classification","show me","why","Bash","edit","2026-11-10 10:12:30",false,"---\nname: scout-attribute\ndescription: 'Use when the user wants manager evidence for a field value on a running Kubernetes resource — which recognized controller or interactive manager is recorded for a path, which git file or ConfigHub Link supplies desired state, or whether resource-level managedFields contains an interactive manager. Natural phrasing: \"why is replicas: 1 in prod?\", \"does this resource show a kubectl manager?\", \"is Argo still reconciling or is an interactive manager recorded?\", \"what git commit set this image tag?\", \"which upstream unit feeds this field?\", \"where does this value come from?\", \"show me the provenance of this Deployment\", \"is this controller-drift or manual-edit?\", \"has an interactive manager changed this Deployment?\", \"which manager is recorded for this field?\". Load whenever attribution \u002F provenance \u002F lineage \u002F git-blame-for-runtime intent appears, especially on `compare` and `explain` output. For a known resource and exact canonical field path, `explain --field-path` can return only that path’s manager evidence; `explain` without the selector has a resource-level summary. Do NOT promise the latest writer or a human identity from manager evidence: exact-path and compare results do not order managers by time. Do NOT load for: pure ownership classification at the resource level (use scout-observe — that gives Owner=Argo\u002FFlux\u002Fetc., not per-field), source-truth strategy verdicts (use scout-compare), or live-cluster mutation (cub-scout cannot mutate — that is `cub` or `kubectl` with user driving).'\nphase: verify\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 link list *) Bash(cub link get *) Bash(cub unit get *) Bash(cub unit list *)\n---\n\n# scout-attribute\n\nThe Attribute layer of cub-scout (#435). Reads `metadata.managedFields` + label-based owner detection + Argo\u002FFlux tracer + ConfigHub Link bindings. It reports recognized manager evidence for a field path when decodable `FieldsV1` is available, otherwise a resource-level manager summary, alongside the field's desired-state source where available. These manager classifications do not form a time-ordered mutation history.\n\n## When to use\n\nExplicit phrasings:\n\n- \"Why is `replicas: 1` in prod when ConfigHub says `replicas: 3`?\"\n- \"Did someone `kubectl edit` this?\" \u002F \"is this manual or controller drift?\"\n- \"Is Argo still reconciling, or has the GitOps loop been bypassed?\"\n- \"What git commit set this image tag?\" \u002F \"trace this field back to its source\"\n- \"Which upstream unit feeds the `image` field on this Deployment?\"\n- \"Show me the provenance of this resource\" \u002F \"git-blame this Deployment\"\n- \"Is this `controller-drift` or `manual-edit`?\"\n- \"What does the `cause` \u002F `managerHint` field mean in this JSON?\"\n\nImplicit intents:\n\n- The user is *already looking at a divergence* from [`scout-compare`](..\u002Fscout-compare\u002FSKILL.md) and wants to know who caused it\n- The user wants per-field detail, not resource-level rollup\n- The user is investigating an audit \u002F postmortem and needs evidence with citations\n\n## Do not load for\n\n- Resource-level ownership classification (Owner = Argo \u002F Flux \u002F Sveltos \u002F Modelplane \u002F Helm \u002F Crossplane \u002F kro \u002F ConfigHub \u002F Native) — [`scout-observe`](..\u002Fscout-observe\u002FSKILL.md) covers that via `cub-scout map` \u002F `cub-scout trace`\n- \"Did the deploy land?\" verdicts at the resource level — [`scout-compare`](..\u002Fscout-compare\u002FSKILL.md)\n- Diagnosing the *symptom* (CrashLoop, OOM, etc.) — [`scout-diagnose`](..\u002Fscout-diagnose\u002FSKILL.md)\n- Live-cluster mutation — cub-scout never mutates. Route to `cub` or `kubectl` (user driving)\n\n## Standalone vs connected\n\n- **Standalone (cluster only):** `cause` + `managerHint` (from managedFields), `gitSource.{repoUrl, revision, path}` (from controller tracer). Per-field attribution via `FieldsV1` decoding (A1.5) works standalone.\n- **Standalone with local checkout (cluster + `--source-path \u003Cdir>`):** Stage B back-resolution adds `gitSource.file` + `gitSource.line` for raw-YAML manifests (#440).\n- **Connected (cluster + `cub auth login`):** adds `incomingBindings[]` (the ConfigHub Links influencing this unit) and per-field `bindingSource` (which upstream unit + path feeds each field).\n\nThe attribution layer **always emits something honest** — if managedFields was stripped, `cause: unknown` and `managerHint` is omitted. If ConfigHub is unavailable in standalone mode, `bindingSource` is omitted from the JSON. The current JSON contract expresses missing evidence via `cause: unknown` + field omission; structured `omissions[]` entries are a forthcoming receipt-layer surface (in #446 batch 1, not today's attribution output). See [`references\u002Fkubernetes-managedfields.md`](..\u002Freferences\u002Fkubernetes-managedfields.md) § \"What happens when evidence is missing\" for the today-vs-future distinction.\n\n## Tool boundary\n\n- **Allowed (read-only):** `cub-scout compare *`, `cub-scout explain *`, `cub-scout trace *`, `kubectl get\u002Fdescribe`, `kubectl get --show-managed-fields`, `cub link list\u002Fget`, `cub unit get\u002Flist`.\n- **Not allowed:** any path that writes — `kubectl edit\u002Fpatch\u002Fapply\u002Fdelete`, `argocd app sync`, `cub * create\u002Fupdate\u002Fdelete`. Attribution reads the writer; it never becomes one.\n\n## The output shape\n\nAttribution evidence is **not its own verb** — it's *enrichment* on the output of [`scout-compare`](..\u002Fscout-compare\u002FSKILL.md)'s `compare three-way` and [`scout-diagnose`](..\u002Fscout-diagnose\u002FSKILL.md)'s `explain`. The fields:\n\n| Field | Means | Source |\n|---|---|---|\n| `cause` | One of `controller-drift`, `manual-edit`, `unknown`. A classification of recognized manager evidence for the mapped path, or a resource-level rollup when path attribution is unavailable. It does not say who wrote last. | `metadata.managedFields` + owner co-signal |\n| `managerHint` | A representative recognized manager string (e.g., `argocd-controller`, `kubectl-edit`) for transparency. Resource-level explain output aggregates manager strings across the object. | `metadata.managedFields[].manager` |\n| `gitSource` | `{repoUrl, revision, path, file?, line?}` — where the field's desired value lives in git | Controller spec (Argo Application \u002F Flux GitRepository) + optional `--source-path` back-resolution (#440) |\n| `bindingSource` | `{linkId, linkSlug, upstreamUnitId, upstreamPath, transformExpr}` — the ConfigHub Link that supplies this field's value | `cub link list` for the owning unit |\n| `incomingBindings[]` | All Links whose downstream is this resource's unit | `cub link list --where \"FromUnitID = ...\"` |\n\nSee [`references\u002Fverified-manager-strings.md`](..\u002Freferences\u002Fverified-manager-strings.md) for the full enumeration of recognized manager strings and [`references\u002Fkubernetes-managedfields.md`](..\u002Freferences\u002Fkubernetes-managedfields.md) for the data substrate.\n\n## The loop\n\n1. **Identify the divergence.** The user is asking about a specific field value (`replicas: 1`, `image: ghcr.io\u002F...\u002Fv1.4`, `env[LOG_LEVEL]`) — figure out which resource and which field.\n2. **Pick the surface:**\n   - If the resource and exact canonical field path are known and the user asks which managers are recorded for that path, call `.\u002Fcub-scout explain \u003Ckind>\u002F\u003Cname> -n \u003Cns> --field-path '\u003Cpath>' --format json` directly (MCP: `explain` with `field_path`). Do not run `doctor`, `map`, `trace`, or a broad compare first just to rediscover manager evidence. The `fieldAttribution` block is scoped to the requested path; the normal resource summary remains. Absent, malformed, unrecognized-only, or ambiguous evidence remains `unknown` and never falls back to resource-level evidence. Do not guess a canonical path; if the path is not known, use the comparison\u002Fread needed to identify it or ask the user.\n   - For a *resource-level first read*, use `.\u002Fcub-scout explain \u003Ckind>\u002F\u003Cname> -n \u003Cns>`. Its `mutationCause` and representative `mutationManager` aggregate manager evidence across the resource; they do not identify a field or latest writer.\n   - Use `.\u002Fcub-scout compare three-way --scope resource:\u003Ckind>\u002F\u003Cname>` or `--scope namespace\u002F\u003Cns>` when the user also needs intended\u002Flive values or a divergence identified. A mismatch can use the mapped path's `cause` and `managerHint` when decodable `FieldsV1` is available; otherwise it may fall back to the resource-level summary, which must not be stated as evidence for that field. This classification does not order managers by time.\n3. **Read the `cause`:**\n   - `controller-drift` → a recognized expected-controller manager claims the resource or mapped path; this does not establish that reconciliation is happening now\n   - `manual-edit` → a recognized interactive manager is present in the resource-level rollup or on the mapped compare path; this does not establish that it wrote last or identify a person. On an exact `fieldAttribution` query, shared controller and interactive claims or any unrecognized co-claimant make the field cause `unknown`, while all observed managers remain visible.\n   - `unknown` → manager evidence is missing, unrecognized, or cannot be mapped; never guess\n4. **Read the `gitSource`:** when present, this is the git origin of the desired value. Add `--source-path \u003Clocal-checkout>` to populate `file` + `line` (stage B back-resolution, raw YAML only — #440).\n5. **Read the `bindingSource`** (connected only): which upstream ConfigHub unit + path supplies this field. `incomingBindings[]` shows the full Link graph for the unit.\n6. **Hand off.** Treat `cause: manual-edit` as manager evidence, not proof of a person or latest write. If the user separately needs raw entry details or timestamps, inspect that field's `managedFields` path; timestamps still do not identify a person and may not establish the latest writer. If the record is incomplete or ambiguous, say unknown. Any correction remains user-driven; cub-scout does not mutate.\n\n## Worked examples\n\n### A: standalone attribution with file:line\n\nThe primary v1 path. No ConfigHub auth required.\n\n```bash\n$ cub-scout compare three-way Deployment\u002Fapi -n prod --source-path \u002Fhome\u002Fme\u002Fplatform-config\nDrift cause: controller-drift (manager: argocd-controller)\nGit source: https:\u002F\u002Fgithub.com\u002Forg\u002Fplatform-config @abc123 path=apps\u002Fprod\u002Fapi file=deployment.yaml:9\n\nDiff Highlights\n  - replicas: DRY=3 | WET=3 | LIVE=1\n```\n\nStandalone — no ConfigHub. Argo is the controller; the `gitSource.file:line` points at the exact line in the local checkout where `replicas` is set. Stage B (#440) — raw YAML only; Helm\u002FKustomize templated sources fall back to resource-level `gitSource` (no `file:line`).\n\nWithout `--source-path`, the resource-level `gitSource` still applies — `repoUrl`, `revision`, `path` from the controller's spec.\n\n### B: classifying divergence as controller-drift vs manual-edit *(connected enrichment)*\n\n```bash\n$ cub-scout compare three-way Deployment\u002Fapi -n prod\nCompare Resource: Deployment\u002Fapi (namespace: prod)\nMode: dry-live    Connection: connected\n\nDRY (unit intent)\n  replicas: 3\nLIVE (cluster)\n  replicas: 1\n\nDrift cause: manual-edit (manager: kubectl-edit)\n\nDiff Highlights\n  - replicas: DRY=3 | WET=- | LIVE=1\n      \u003C- bound from unit:01HFK...XY path:.spec.scale.value via link:replicas-from-scale\n```\n\nThere is no WET side: ConfigHub no longer exposes a unit's live data, so a connected compare shows DRY against LIVE (`Mode: dry-live`) and says so in its notes.\n\nFor this `.spec.replicas` mismatch, a path-specific `manual-edit` classification means a recognized interactive manager is recorded for that path (when decodable `FieldsV1` is available); a controller manager may also be recorded. It does not prove which manager wrote the value last or identify who ran a command. A resource-level fallback must not be stated as evidence about `replicas`. The `bound from` line tells the user the upstream ConfigHub unit + path that *should* be feeding `replicas` — that's the C2 connected enrichment on top of standalone's cause + gitSource.\n\nNext read-only step (don't apply!): inspect the exact path's managed-field entries; use audit logs if the user needs write history or identity.\n\n```bash\n$ kubectl get deploy\u002Fapi -n prod -o yaml --show-managed-fields | grep -A 3 \"manager: kubectl-edit\"\n- manager: kubectl-edit\n  operation: Update\n  time: \"2026-05-21T13:42:00Z\"\n  fieldsV1: { f:spec: { f:replicas: {} } }\n```\n\nSo `replicas` was overwritten by `kubectl edit` at 13:42 UTC. The user can now decide: port back to ConfigHub (governed) or revert (also governed). The skill does not act.\n\n### C: per-field binding (connected, C2)\n\n```bash\n$ cub-scout compare three-way Deployment\u002Fapi -n prod --format json | \\\n    jq '.mismatches[] | {field, cause, managerHint, bindingSource}'\n{\n  \"field\": \"replicas\",\n  \"cause\": \"manual-edit\",\n  \"managerHint\": \"kubectl-edit\",\n  \"bindingSource\": {\n    \"linkId\": \"01HFK...A1\",\n    \"linkSlug\": \"replicas-from-scale\",\n    \"upstreamUnitId\": \"01HFK...XY\",\n    \"upstreamPath\": \".spec.scale.value\",\n    \"transformExpr\": \"to_int\"\n  }\n}\n```\n\nThe agent can say that the live `replicas` path is associated with the `kubectl-edit` manager while the intended value comes from upstream unit `01HFK...XY` at path `.spec.scale.value` via link `replicas-from-scale`. The manager string does not identify a human or prove it was the latest write.\n\n## Output evidence\n\n- Embedded in `compare three-way` JSON and `explain` JSON — there is no `cub-scout attribute` command. The Attribute layer is *enrichment*, not its own verb.\n- See `docs\u002Freference\u002Fjson-contracts.md` § \"Field Mutation Attribution Contract\" for the full schema.\n- Example fixtures: `examples\u002Fdrift\u002Fmutation-cause-attribution\u002F`.\n\n## References\n\n- Capability map: [`README.md`](..\u002F..\u002FREADME.md#capability-map) § Attribute\n- Parent attribution issue: #435 (closed) — shipped via #437 \u002F #438 \u002F #439 \u002F #440\n- Manager-string enumeration: [`references\u002Fverified-manager-strings.md`](..\u002Freferences\u002Fverified-manager-strings.md)\n- managedFields substrate + caveats: [`references\u002Fkubernetes-managedfields.md`](..\u002Freferences\u002Fkubernetes-managedfields.md)\n- Receipt (forthcoming): the attribution evidence will be embedded in `cub-scout receipt verify` output once #446 batch 1 lands\n\n## Constraints\n\n- `cause: manual-edit` is a *manager-presence signal*, not proof of a person or the latest writer. managedFields records a manager string, not the human identity behind it. To attribute to a specific user or order writes, cross-reference cluster audit logs (out of scope for cub-scout).\n- managedFields is **field-manager evidence, not complete or time-ordered mutation-history proof**. The classifier does not order managers by their timestamps. A controller that was overwritten and then re-reconciled may not leave a manual-edit trace if the controller subsequently wins. For stronger history, pair with a K8s admission audit log.\n- The `kubectl-client-side-apply` manager string is *ambiguous* — Argo CD's CSA migration uses it as the default, and so does `kubectl apply` (client-side). The classifier disambiguates via the `argocd.argoproj.io\u002Ftracking-id` annotation (label co-signal). See [`references\u002Fverified-manager-strings.md`](..\u002Freferences\u002Fverified-manager-strings.md).\n- Crossplane composed-resource manager strings carry a per-XR hash suffix (`apiextensions.crossplane.io\u002Fcomposed-\u003Chash>`). The classifier matches by **prefix**, not exact string.\n- For *templated sources* (Helm \u002F Kustomize), `gitSource.file:line` is not populated (stage B handles raw YAML only). Resource-level `gitSource` (`repoUrl`, `revision`, `path`) still applies.\n- Attribution evidence is read-only enrichment. The triad lock (#410 \u002F #428) means no `cub-scout` path can act on the evidence. Always hand off mutation to the appropriate `cub` \u002F `kubectl` skill with the user driving.\n","# scout-attribute\n\nThe Attribute layer of cub-scout (#435). Reads `metadata.managedFields` + label-based owner detection + Argo\u002FFlux tracer + ConfigHub Link bindings. It reports recognized manager evidence for a field path when decodable `FieldsV1` is available, otherwise a resource-level manager summary, alongside the field's desired-state source where available. These manager classifications do not form a time-ordered mutation history.\n\n## When to use\n\nExplicit phrasings:\n\n- \"Why is `replicas: 1` in prod when ConfigHub says `replicas: 3`?\"\n- \"Did someone `kubectl edit` this?\" \u002F \"is this manual or controller drift?\"\n- \"Is Argo still reconciling, or has the GitOps loop been bypassed?\"\n- \"What git commit set this image tag?\" \u002F \"trace this field back to its source\"\n- \"Which upstream unit feeds the `image` field on this Deployment?\"\n- \"Show me the provenance of this resource\" \u002F \"git-blame this Deployment\"\n- \"Is this `controller-drift` or `manual-edit`?\"\n- \"What does the `cause` \u002F `managerHint` field mean in this JSON?\"\n\nImplicit intents:\n\n- The user is *already looking at a divergence* from [`scout-compare`](..\u002Fscout-compare\u002FSKILL.md) and wants to know who caused it\n- The user wants per-field detail, not resource-level rollup\n- The user is investigating an audit \u002F postmortem and needs evidence with citations\n\n## Do not load for\n\n- Resource-level ownership classification (Owner = Argo \u002F Flux \u002F Sveltos \u002F Modelplane \u002F Helm \u002F Crossplane \u002F kro \u002F ConfigHub \u002F Native) — [`scout-observe`](..\u002Fscout-observe\u002FSKILL.md) covers that via `cub-scout map` \u002F `cub-scout trace`\n- \"Did the deploy land?\" verdicts at the resource level — [`scout-compare`](..\u002Fscout-compare\u002FSKILL.md)\n- Diagnosing the *symptom* (CrashLoop, OOM, etc.) — [`scout-diagnose`](..\u002Fscout-diagnose\u002FSKILL.md)\n- Live-cluster mutation — cub-scout never mutates. Route to `cub` or `kubectl` (user driving)\n\n## Standalone vs connected\n\n- **Standalone (cluster only):** `cause` + `managerHint` (from managedFields), `gitSource.{repoUrl, revision, path}` (from controller tracer). Per-field attribution via `FieldsV1` decoding (A1.5) works standalone.\n- **Standalone with local checkout (cluster + `--source-path \u003Cdir>`):** Stage B back-resolution adds `gitSource.file` + `gitSource.line` for raw-YAML manifests (#440).\n- **Connected (cluster + `cub auth login`):** adds `incomingBindings[]` (the ConfigHub Links influencing this unit) and per-field `bindingSource` (which upstream unit + path feeds each field).\n\nThe attribution layer **always emits something honest** — if managedFields was stripped, `cause: unknown` and `managerHint` is omitted. If ConfigHub is unavailable in standalone mode, `bindingSource` is omitted from the JSON. The current JSON contract expresses missing evidence via `cause: unknown` + field omission; structured `omissions[]` entries are a forthcoming receipt-layer surface (in #446 batch 1, not today's attribution output). See [`references\u002Fkubernetes-managedfields.md`](..\u002Freferences\u002Fkubernetes-managedfields.md) § \"What happens when evidence is missing\" for the today-vs-future distinction.\n\n## Tool boundary\n\n- **Allowed (read-only):** `cub-scout compare *`, `cub-scout explain *`, `cub-scout trace *`, `kubectl get\u002Fdescribe`, `kubectl get --show-managed-fields`, `cub link list\u002Fget`, `cub unit get\u002Flist`.\n- **Not allowed:** any path that writes — `kubectl edit\u002Fpatch\u002Fapply\u002Fdelete`, `argocd app sync`, `cub * create\u002Fupdate\u002Fdelete`. Attribution reads the writer; it never becomes one.\n\n## The output shape\n\nAttribution evidence is **not its own verb** — it's *enrichment* on the output of [`scout-compare`](..\u002Fscout-compare\u002FSKILL.md)'s `compare three-way` and [`scout-diagnose`](..\u002Fscout-diagnose\u002FSKILL.md)'s `explain`. The fields:\n\n| Field | Means | Source |\n|---|---|---|\n| `cause` | One of `controller-drift`, `manual-edit`, `unknown`. A classification of recognized manager evidence for the mapped path, or a resource-level rollup when path attribution is unavailable. It does not say who wrote last. | `metadata.managedFields` + owner co-signal |\n| `managerHint` | A representative recognized manager string (e.g., `argocd-controller`, `kubectl-edit`) for transparency. Resource-level explain output aggregates manager strings across the object. | `metadata.managedFields[].manager` |\n| `gitSource` | `{repoUrl, revision, path, file?, line?}` — where the field's desired value lives in git | Controller spec (Argo Application \u002F Flux GitRepository) + optional `--source-path` back-resolution (#440) |\n| `bindingSource` | `{linkId, linkSlug, upstreamUnitId, upstreamPath, transformExpr}` — the ConfigHub Link that supplies this field's value | `cub link list` for the owning unit |\n| `incomingBindings[]` | All Links whose downstream is this resource's unit | `cub link list --where \"FromUnitID = ...\"` |\n\nSee [`references\u002Fverified-manager-strings.md`](..\u002Freferences\u002Fverified-manager-strings.md) for the full enumeration of recognized manager strings and [`references\u002Fkubernetes-managedfields.md`](..\u002Freferences\u002Fkubernetes-managedfields.md) for the data substrate.\n\n## The loop\n\n1. **Identify the divergence.** The user is asking about a specific field value (`replicas: 1`, `image: ghcr.io\u002F...\u002Fv1.4`, `env[LOG_LEVEL]`) — figure out which resource and which field.\n2. **Pick the surface:**\n   - If the resource and exact canonical field path are known and the user asks which managers are recorded for that path, call `.\u002Fcub-scout explain \u003Ckind>\u002F\u003Cname> -n \u003Cns> --field-path '\u003Cpath>' --format json` directly (MCP: `explain` with `field_path`). Do not run `doctor`, `map`, `trace`, or a broad compare first just to rediscover manager evidence. The `fieldAttribution` block is scoped to the requested path; the normal resource summary remains. Absent, malformed, unrecognized-only, or ambiguous evidence remains `unknown` and never falls back to resource-level evidence. Do not guess a canonical path; if the path is not known, use the comparison\u002Fread needed to identify it or ask the user.\n   - For a *resource-level first read*, use `.\u002Fcub-scout explain \u003Ckind>\u002F\u003Cname> -n \u003Cns>`. Its `mutationCause` and representative `mutationManager` aggregate manager evidence across the resource; they do not identify a field or latest writer.\n   - Use `.\u002Fcub-scout compare three-way --scope resource:\u003Ckind>\u002F\u003Cname>` or `--scope namespace\u002F\u003Cns>` when the user also needs intended\u002Flive values or a divergence identified. A mismatch can use the mapped path's `cause` and `managerHint` when decodable `FieldsV1` is available; otherwise it may fall back to the resource-level summary, which must not be stated as evidence for that field. This classification does not order managers by time.\n3. **Read the `cause`:**\n   - `controller-drift` → a recognized expected-controller manager claims the resource or mapped path; this does not establish that reconciliation is happening now\n   - `manual-edit` → a recognized interactive manager is present in the resource-level rollup or on the mapped compare path; this does not establish that it wrote last or identify a person. On an exact `fieldAttribution` query, shared controller and interactive claims or any unrecognized co-claimant make the field cause `unknown`, while all observed managers remain visible.\n   - `unknown` → manager evidence is missing, unrecognized, or cannot be mapped; never guess\n4. **Read the `gitSource`:** when present, this is the git origin of the desired value. Add `--source-path \u003Clocal-checkout>` to populate `file` + `line` (stage B back-resolution, raw YAML only — #440).\n5. **Read the `bindingSource`** (connected only): which upstream ConfigHub unit + path supplies this field. `incomingBindings[]` shows the full Link graph for the unit.\n6. **Hand off.** Treat `cause: manual-edit` as manager evidence, not proof of a person or latest write. If the user separately needs raw entry details or timestamps, inspect that field's `managedFields` path; timestamps still do not identify a person and may not establish the latest writer. If the record is incomplete or ambiguous, say unknown. Any correction remains user-driven; cub-scout does not mutate.\n\n## Worked examples\n\n### A: standalone attribution with file:line\n\nThe primary v1 path. No ConfigHub auth required.\n\n```bash\n$ cub-scout compare three-way Deployment\u002Fapi -n prod --source-path \u002Fhome\u002Fme\u002Fplatform-config\nDrift cause: controller-drift (manager: argocd-controller)\nGit source: https:\u002F\u002Fgithub.com\u002Forg\u002Fplatform-config @abc123 path=apps\u002Fprod\u002Fapi file=deployment.yaml:9\n\nDiff Highlights\n  - replicas: DRY=3 | WET=3 | LIVE=1\n```\n\nStandalone — no ConfigHub. Argo is the controller; the `gitSource.file:line` points at the exact line in the local checkout where `replicas` is set. Stage B (#440) — raw YAML only; Helm\u002FKustomize templated sources fall back to resource-level `gitSource` (no `file:line`).\n\nWithout `--source-path`, the resource-level `gitSource` still applies — `repoUrl`, `revision`, `path` from the controller's spec.\n\n### B: classifying divergence as controller-drift vs manual-edit *(connected enrichment)*\n\n```bash\n$ cub-scout compare three-way Deployment\u002Fapi -n prod\nCompare Resource: Deployment\u002Fapi (namespace: prod)\nMode: dry-live    Connection: connected\n\nDRY (unit intent)\n  replicas: 3\nLIVE (cluster)\n  replicas: 1\n\nDrift cause: manual-edit (manager: kubectl-edit)\n\nDiff Highlights\n  - replicas: DRY=3 | WET=- | LIVE=1\n      \u003C- bound from unit:01HFK...XY path:.spec.scale.value via link:replicas-from-scale\n```\n\nThere is no WET side: ConfigHub no longer exposes a unit's live data, so a connected compare shows DRY against LIVE (`Mode: dry-live`) and says so in its notes.\n\nFor this `.spec.replicas` mismatch, a path-specific `manual-edit` classification means a recognized interactive manager is recorded for that path (when decodable `FieldsV1` is available); a controller manager may also be recorded. It does not prove which manager wrote the value last or identify who ran a command. A resource-level fallback must not be stated as evidence about `replicas`. The `bound from` line tells the user the upstream ConfigHub unit + path that *should* be feeding `replicas` — that's the C2 connected enrichment on top of standalone's cause + gitSource.\n\nNext read-only step (don't apply!): inspect the exact path's managed-field entries; use audit logs if the user needs write history or identity.\n\n```bash\n$ kubectl get deploy\u002Fapi -n prod -o yaml --show-managed-fields | grep -A 3 \"manager: kubectl-edit\"\n- manager: kubectl-edit\n  operation: Update\n  time: \"2026-05-21T13:42:00Z\"\n  fieldsV1: { f:spec: { f:replicas: {} } }\n```\n\nSo `replicas` was overwritten by `kubectl edit` at 13:42 UTC. The user can now decide: port back to ConfigHub (governed) or revert (also governed). The skill does not act.\n\n### C: per-field binding (connected, C2)\n\n```bash\n$ cub-scout compare three-way Deployment\u002Fapi -n prod --format json | \\\n    jq '.mismatches[] | {field, cause, managerHint, bindingSource}'\n{\n  \"field\": \"replicas\",\n  \"cause\": \"manual-edit\",\n  \"managerHint\": \"kubectl-edit\",\n  \"bindingSource\": {\n    \"linkId\": \"01HFK...A1\",\n    \"linkSlug\": \"replicas-from-scale\",\n    \"upstreamUnitId\": \"01HFK...XY\",\n    \"upstreamPath\": \".spec.scale.value\",\n    \"transformExpr\": \"to_int\"\n  }\n}\n```\n\nThe agent can say that the live `replicas` path is associated with the `kubectl-edit` manager while the intended value comes from upstream unit `01HFK...XY` at path `.spec.scale.value` via link `replicas-from-scale`. The manager string does not identify a human or prove it was the latest write.\n\n## Output evidence\n\n- Embedded in `compare three-way` JSON and `explain` JSON — there is no `cub-scout attribute` command. The Attribute layer is *enrichment*, not its own verb.\n- See `docs\u002Freference\u002Fjson-contracts.md` § \"Field Mutation Attribution Contract\" for the full schema.\n- Example fixtures: `examples\u002Fdrift\u002Fmutation-cause-attribution\u002F`.\n\n## References\n\n- Capability map: [`README.md`](..\u002F..\u002FREADME.md#capability-map) § Attribute\n- Parent attribution issue: #435 (closed) — shipped via #437 \u002F #438 \u002F #439 \u002F #440\n- Manager-string enumeration: [`references\u002Fverified-manager-strings.md`](..\u002Freferences\u002Fverified-manager-strings.md)\n- managedFields substrate + caveats: [`references\u002Fkubernetes-managedfields.md`](..\u002Freferences\u002Fkubernetes-managedfields.md)\n- Receipt (forthcoming): the attribution evidence will be embedded in `cub-scout receipt verify` output once #446 batch 1 lands\n\n## Constraints\n\n- `cause: manual-edit` is a *manager-presence signal*, not proof of a person or the latest writer. managedFields records a manager string, not the human identity behind it. To attribute to a specific user or order writes, cross-reference cluster audit logs (out of scope for cub-scout).\n- managedFields is **field-manager evidence, not complete or time-ordered mutation-history proof**. The classifier does not order managers by their timestamps. A controller that was overwritten and then re-reconciled may not leave a manual-edit trace if the controller subsequently wins. For stronger history, pair with a K8s admission audit log.\n- The `kubectl-client-side-apply` manager string is *ambiguous* — Argo CD's CSA migration uses it as the default, and so does `kubectl apply` (client-side). The classifier disambiguates via the `argocd.argoproj.io\u002Ftracking-id` annotation (label co-signal). See [`references\u002Fverified-manager-strings.md`](..\u002Freferences\u002Fverified-manager-strings.md).\n- Crossplane composed-resource manager strings carry a per-XR hash suffix (`apiextensions.crossplane.io\u002Fcomposed-\u003Chash>`). The classifier matches by **prefix**, not exact string.\n- For *templated sources* (Helm \u002F Kustomize), `gitSource.file:line` is not populated (stage B handles raw YAML only). Resource-level `gitSource` (`repoUrl`, `revision`, `path`) still applies.\n- Attribution evidence is read-only enrichment. The triad lock (#410 \u002F #428) means no `cub-scout` path can act on the evidence. Always hand off mutation to the appropriate `cub` \u002F `kubectl` skill with the user driving.\n",{"name":5,"phase":61,"description":7,"allowed-tools":62},"verify","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 link list *) Bash(cub link get *) Bash(cub unit get *) Bash(cub unit list *)","main","261862e7ec5e5c93ce377ccfd6b583f5ac03c95c","skills\u002Fscout-attribute",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":74,"prompt":84,"zipAvailable":85},[75,78,81],{"tool":76,"command":77},"npx","npx skills add confighub\u002Fcub-scout --skill scout-attribute",{"tool":79,"command":80},"bunx","bunx skills add confighub\u002Fcub-scout --skill scout-attribute",{"tool":82,"command":83},"pnpm","pnpm dlx skills add confighub\u002Fcub-scout --skill scout-attribute","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fconfighub\u002Fcub-scout\u002Fblob\u002Fmain\u002Fskills\u002Fscout-attribute\u002FSKILL.md",true,[87],{"path":88,"resourceType":89,"resourceTypeDesc":90,"sizeBytes":91,"sourceHtmlUrl":92},"agents\u002Fopenai.yaml","REFERENCE","参考文档",127,"https:\u002F\u002Fgithub.com\u002Fmalinskibeniamin\u002Fskills\u002Fblob\u002Fmain\u002Fcodex-skills\u002Fefficient-frontier\u002Fagents\u002Fopenai.yaml",[94,128,148,165,190,211],{"skillNo":95,"name":96,"nameZh":6,"description":97,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":98,"categories":99,"keywords":105,"publishedAt":56},"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",[100],{"categoryNo":101,"categoryName":102,"taxonomyType":103,"taxonomyTypeDesc":104},"01JBSEEDCAT000000000000011","运维与部署","SCENARIO","使用场景",[106,107,108,39,109,110,111,112,113,114,54,115,116,117,118,119,23,120,121,27,122,123,124,31,125,126,127],"triage","workload","triage unhealthy workload","diagnose","doctor","logs","ci","payments","api","loop","explain","check","broken","question","rollout","never","route","drift","map","get","now","when",{"skillNo":129,"name":130,"nameZh":6,"description":131,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":132,"categories":133,"keywords":135,"publishedAt":56},"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",[134],{"categoryNo":101,"categoryName":102,"taxonomyType":103,"taxonomyTypeDesc":104},[61,136,20,39,137,138,112,139,50,114,52,54,140,141,142,143,144,23,121,25,27,21,122,145,125,146,35,147,127],"scout verify","acceptance","produce","attestation","postmortem","changeset","argocd","view","fix","me","app","managed",{"skillNo":149,"name":150,"nameZh":6,"description":151,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":152,"categories":153,"keywords":154,"publishedAt":56},"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",[],[26,155,20,156,39,109,41,110,111,157,50,158,52,54,118,23,159,121,24,160,27,21,161,162,124,125,163,164,127],"scout observe","bot","risk","inventory","version","hooks","back","health-check","resources","meaning",{"skillNo":166,"name":167,"nameZh":6,"description":168,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":169,"categories":170,"keywords":174,"publishedAt":56},"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",[171],{"categoryNo":172,"categoryName":173,"taxonomyType":103,"taxonomyTypeDesc":104},"01JBSEEDCAT000000000000023","Skill与智能体开发",[175,176,20,156,177,178,179,180,181,182,183,49,54,184,141,185,186,24,187,188,26,125,35,189,127],"MCP","scout mcp","mcp server","ai agent","auth","config","run","release","server","model","read","snapshot","ready","up","agent-context",{"skillNo":191,"name":192,"nameZh":6,"description":193,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":194,"categories":195,"keywords":196,"publishedAt":56},"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",[],[197,198,20,39,109,182,199,138,200,49,158,201,52,54,141,202,119,185,203,143,23,24,26,27,21,204,205,206,34,146,35,207,208,209,210],"ingest","scout ingest","state","adoption","discovery","repo","write","structure","aggregator","adopt","reading","exported","invoke","parse",{"skillNo":212,"name":213,"nameZh":6,"description":214,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":215,"categories":216,"keywords":217,"publishedAt":56},"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",[],[218,20,219,179,220,221,222,158,61,52,54,223,141,143,224,23,225,226,227,26,27,21,228,125,33,229,35,230,231,36,232,127],"scout govern","change","governance","blast radius","audit","history","catalog","diff","say","snapshots","project","impact","render","blast-radius","inspect"]