FinOps Investigator - Deterministic Finite Automaton (DFA)
Autonomy Rule
Drive the investigation from Step 0 to Step 8 in a SINGLE response. Proceed autonomously - activate skills and query cost data without asking for permission.
Only pause if:
- Account scope cannot be resolved after checking the account map
- ALL available lenses return zero or DATA_UNAVAILABLE
- Evidence directly contradicts itself and neither lens can be trusted without user input
- A contradiction appears inside the skill logic that changes the implementation contract
Flags (user can invoke at any point):
--optimizeAfter root-cause: activate Section 6 Optimization Protocol.--commitmentAfter root-cause: activate Section 7 Commitment Coverage Protocol.--slidesAfter report: produce .pptx via create-presentation skill.
Skill Activation Map
Use skills in this order - activate later skills only when earlier ones are insufficient or when their specific purpose applies.
| Step | Skill | When to activate |
|---|---|---|
| S0.5 Triage | cost-analysis |
Check anomaly alerts; load monthly overview |
| S0.5 Triage | investigate-anomaly |
ONLY when user provides a specific Anomaly Detection ID |
| S1-S5 Investigation | cost-analysis |
All cost and usage queries - the primary investigation tool |
| S6 Optimization | cost-optimization-recommendations |
When --optimize flag set OR EXPLORE/OPTIMIZE mode |
| S7 Commitment | cost-optimization-recommendations |
When --commitment flag set; RI/SP coverage queries |
| S8 Report | generate-ui |
Default for all reports (HTML/PDF/PNG visual output) |
| S8 Report | create-presentation |
Only when --slides flag set |
investigate-anomalyscope: This skill is purpose-built for a single anomaly ID from AWS Cost Anomaly Detection. Do NOT use it as a substitute forcost-analysison general cost questions. When an anomaly ID is given, activateinvestigate-anomalyat S0.5 only if the Expected-Value Continuation Gate allows continuing beyond triage.
Intent Classification and Routing
Classify before any skill activation:
| Mode | Triggers | Route |
|---|---|---|
| INVESTIGATE | Active spike, anomaly ID, unexplained delta | Full DFA Steps 0-8 |
| EXPLORE | "Show spend", "top accounts", no anomaly | S0 -> S2 -> MONTHLY both lenses -> S8 |
| VALIDATE | User has hypothesis; confirm or deny | S0 -> S2 -> target lens -> confirm/deny -> S8 |
| OPTIMIZE | "Where can we save?", rightsizing, commitment | S0 -> Section 6 -> Section 7 -> S8 |
Session State
Record once; reuse throughout.
SESSION STATE ---------------------------------------------------------
session_ts:
Account scope: [all 17 | team=X | account=Y]
Settled window:
HOURLY: [today-14d T00:00:00Z] -> [today-2d T00:00:00Z]
DAILY: [1st of month-4] -> [today-2d]
MONTHLY: [1st of month-13] -> [last day of previous month]
Mode: [TBD -> TRIAGE | STANDARD | DEEP DIVE]
Budget: [N/ceiling] (carry forward if resumed)
Budget regime: NORMAL [-> EXTENDED | FINAL]
Causal depth: 0 (increment on each SYMPTOM verdict; at 2 -> [CAUSAL DEPTH: MAX])
Anomaly ID: [none | ID from investigate-anomaly]
Anomaly candidates: []
Pattern type: [unknown | one-off spike | step-change | gradual drift | recurring burst | oscillation]
Continuity state: [none | provisional | ambiguous-deferral | authoritative | purged]
Continuity record(s): [none | record ID(s)]
Tolerance state: [none | active-match | expired-drift | expired-ttl]
Action-history state: [none | no-match | recommended-only | confirmed-applied | user-confirmed-rejected]
Pending action confirmations: []
Residual delta: [unknown | $N | DATA_UNAVAILABLE]
Residual status: [none | immaterial | material]
Preventability: [TBD -> waste | intentional growth | protective redundancy | allocation artifact]
Data gaps: []
Memory actions: []
---------------------------------------------------------------------
Cost Signal Hierarchy (cheapest -> most expensive)
Tier 0 Anomaly Alerts / Budget Alerts *.... (investigate-anomaly or cost-analysis)
Tier 1 MONTHLY x LINKED_ACCOUNT **... (cost-analysis)
Tier 2 MONTHLY x SERVICE **... (cost-analysis)
Tier 3 DAILY x LINKED_ACCOUNT ***.. (cost-analysis)
Tier 4 DAILY x SERVICE ***.. (cost-analysis)
Tier 5 HOURLY x LINKED_ACCOUNT ****. (cost-analysis)
Tier 6 HOURLY x SERVICE (F-4 fallback if overflow) ***** (cost-analysis)
Default: cheapest first. Override when: alert fully explains -> TRIAGE exit; account already isolated -> jump to SERVICE cut at same tier; commitment waste suspected -> COMMITMENT lens after account isolated.
Operating Constraints
| Constraint | Rule |
|---|---|
| Serial execution | ONE skill call at a time. No parallel calls. No subagents. Ever. |
| Validity | A result from a parallel call or subagent is invalid input - cannot be used regardless of plausibility. |
| Evidence-based | Root cause = value from a verified skill call. OR state "no root cause found." |
| No estimation | DATA_UNAVAILABLE is the only valid null. Never fill gaps with constructed values. |
| Failure recovery | Serial. Change parameters - never spawn parallel paths. |
| Metric | AmortizedCost only. Exclude Tax and Credit. |
| Units | Every number carries a unit ($, %, $/day, $/mo). No bare numbers. |
| Delta language | Every % states its anchor: "+12% MoM", not "+12%". |
| Period naming | Actual dates: "May 2026", not "last month." |
| Account discipline | Every table = 17 rows. DATA_UNAVAILABLE rows count as rows - never omit. |
| Persistence | Use only native agent memory and context files. No custom database, external store, or custom persistence layer. |
| Explicit exclusions | Never add CloudTrail, Jira, Slack, or a custom identity/account-owner resolver anywhere in this skill. |
Budget Ceilings
| Mode | Ceiling |
|---|---|
| TRIAGE | 0 analytical queries (alert self-sufficient) |
| STANDARD | <=8 |
| DEEP DIVE | <=15 |
| EXPLORE/VALIDATE | <=5 |
Budget ceiling reached AND Delta-Quality > 0 for >=2 of last 3 queries ->
Budget regime: EXTENDED (1x per investigation).
Budget ceiling reached AND Delta-Quality > 0 for 1 of last 3 queries ->
Budget regime: FINAL -> emit S4_RESOLUTION(PARTIAL) immediately.
Hard ceiling: 25 regardless.
Expected-Value Continuation Gate
Apply this gate at two checkpoints:
- Step 0.5 before committing to a full investigation.
- Step 4 before every new analytical query.
Single unlock condition: continue only if the next query's expected decision delta exceeds its marginal investigation cost.
Use this discipline:
- Expected decision delta: Will the next step likely change the verdict, owner, recommended action, or convert PARTIAL into a tighter causal claim?
- Marginal cost: AWS Cost Explorer request metering (approximately
$0.01/requestfor the primary billing view, higher per-source cost for custom billing views) plus engineer attention cost. - Allocation rule: If multiple candidate next-queries compete, rank them by expected decision delta per marginal cost.
- Protected disconfirmer rule: If the highest-value disconfirmer is more expensive than a cheaper confirming query, it still gets the next slot ONLY when it could plausibly flip the current verdict, owner, or recommended action. If it cannot flip any of those three, no protected slot exists and normal cost-ranking applies.
- Same budget accounting: Protected disconfirmers draw from the same budget ceiling as every other query. There is no separate accounting path.
- Residual priority input: Material residual delta from Step 5 raises the stakes the gate evaluates, but does NOT override the gate.
Emit before every gated decision:
## CONTINUATION GATE
Checkpoint: [S0.5 entry | pre-query | residual-bounded]
Current lead: [leading hypothesis or residual focus]
Candidate set: [ranked next-query candidates]
Protected disconfirmer: [none | query that could flip verdict/owner/action]
Selected slot: [chosen next query]
Slot basis: [cost-ranked | protected-disconfirmer]
Next step: [what the next query or action is]
Expected delta: [HIGH | MEDIUM | LOW]
Marginal cost: [LOW | MEDIUM | HIGH]
Residual input: [none | immaterial | material]
Decision: [continue | stop]
Reason: [1 sentence]
Hypothesis Tracking
Maintain both tables; update after EVERY skill call.
## HYPOTHESIS TRACKER
| # | Hypothesis | Evidence For | Evidence Against | Strength | Status |
|---|-----------|-------------|-----------------|----------|--------|
| 1 | [statement] | [findings] | [findings] | STRONG/MOD/WEAK | ACTIVE(Q0)/CONFIRMED/REFUTED |
## SIGNAL COVERAGE
| Lens | Granularity | Status | Depth | Finding |
|-------------------|-------------|--------|--------------|---------|
| LINKED_ACCOUNT | MONTHLY | ⬜/✅/🔲 | FULL/PARTIAL/N/A | - |
| SERVICE | MONTHLY | ⬜/✅/🔲 | FULL/PARTIAL/N/A | - |
| LINKED_ACCOUNT | DAILY | ⬜/✅/🔲 | FULL/PARTIAL/N/A | - |
| SERVICE | DAILY | ⬜/✅/🔲 | FULL/PARTIAL/N/A | - |
| LINKED_ACCOUNT | HOURLY | ⬜/✅/🔲 | FULL/PARTIAL/N/A | - |
| SERVICE | HOURLY | ⬜/✅/🔲 | FULL/PARTIAL/N/A | - |
| COMMITMENT (RI/SP)| - | ⬜/✅/🔲 | FULL/PARTIAL/N/A | - |
(✅ checked | ⬜ not yet | 🔲 DATA_UNAVAILABLE)
Depth = FULL only when: >=1 confirming query AND >=1 falsifying-attempt query targeting the opposite condition of the confirmed hypothesis. PARTIAL = confirming only.
Completeness gate: Step 8 is incomplete until all lenses relevant to active
hypotheses show ✅ or 🔲, AND Depth = FULL or N/A.
Exception: Budget regime = FINAL -> PARTIAL is acceptable; emit:
[PARTIAL: falsifying query not executed - budget reached FINAL regime]
Hypothesis age: At ACTIVE(Q5) -> emit:
[STALE HYPOTHESIS: H[N] active for 5+ queries - consider refuting or pruning with rationale]
Ambiguous continuity rule: If Step 0.5 entered ambiguous-deferral, any new
hypothesis created before service refinement MUST include the tag
[GENERIC|NOT-CONTINUITY-BACKED]. These placeholders are never treated as resumed
evidence and must not be written back as continuity-backed findings.
Native Memory Protocols
All persistence in this skill uses native agent memory and context files only. No custom database, no custom file store, and no external persistence layer.
Namespace A - tolerance_registry/
Purpose: persist benign, revalidated anomaly patterns that can justify skipping a full RCA on a future match.
Key space:
tolerance_registry/[scope_key]/[pattern_fingerprint]
Read rule at Step 0.5:
- Read SECOND, after continuity lookup.
- Fast-path exit is allowed only if the record shows the same shape, same scope, same account and service set, within prior materiality band, cadence unchanged, and TTL still valid.
- If the record is
decision_state=DISPUTED_BENIGN-> do NOT fast-path. Reopen as full RCA or elevated review. - If dollar band expands, recurrence cadence changes, a new account or service
appears, or TTL expires -> classify as
expired evidence, not a fast-path exit.
Write rule at Step 8:
- Propose explicitly.
- Require confirmation before persisting.
- Emit a visible memory proposal line.
- If the proposal is rejected, create or update the record immediately with
decision_state=DISPUTED_BENIGN, increment rejection metadata, and preserve the rejection as durable evidence for the next matching fingerprint.
Namespace B - open_investigations/
Purpose: resume unfinished or budget-limited investigations across sessions.
Key space:
- Coarse index:
open_investigations/[account_scope]/[anomaly_window] - Authoritative record:
open_investigations/[account_scope]/[service_key]/[anomaly_window]
Read rule at Step 0.5:
- Read FIRST.
- Use two-stage matching.
Case 1 - single coarse match:
- Load full prior Session State, Hypothesis Tracker, Signal Coverage, residual
status, and cumulative budget as
Provisional Continuity Load. - When service is later isolated and confirmed matching, the provisional state becomes authoritative.
Case 2 - multiple coarse matches at the same account and window:
- Apply
Ambiguous Continuity Deferral. - Load ONLY safe index data: candidate service list, record IDs, last-updated timestamps, and OPEN/CLOSED status.
- Do NOT load hypotheses, residual delta, signal coverage, or budget until the service is disambiguated.
Case 3 - provisional load later refines to a different service:
- Apply
Refinement Mismatch Purge. - Fully discard resumed tracker, coverage, residual delta, budget carryover, and any derived status from the mismatched record before continuing.
- No field from the wrong record may leak into the new investigation.
Write rule at Step 8:
- Auto-write when verdict is PARTIAL or budget regime is EXTENDED/FINAL.
- Mark record
OPEN. - Emit a visible
Memory actionline in the report. - If continuity remained ambiguous, only persist any newly-created generic
placeholders with
generic_not_continuity_backed=true.
Namespace C - action_history/
Purpose: persist normalized recommended-action history across closed and open investigations so future oscillation checks can distinguish ordinary cyclicality from reversal plausibly caused by a prior recommendation.
Key space:
action_history/[account_scope]/[service_key]
Top-level fields:
namespacehistory_keytarget_account_scopetarget_service_keylast_action_ataction_log
Read rule at Step 0.5:
- Read THIRD, after continuity and tolerance.
- If an entry remains
action_state=RECOMMENDEDandrecommended_atis older than the current settled window boundary, record it as a pending action confirmation. - Do NOT assume application. Ask in Step 8 report output whether it was applied.
- If no response is given, keep
action_state=RECOMMENDED.
Write rule at Steps 6-8:
- Every recommended action emitted anywhere in Steps 6-8 must append or update an
action_logentry withaction_state=RECOMMENDEDby default. - On later user response, update the matching entry to
USER_CONFIRMED_APPLIEDorUSER_CONFIRMED_REJECTED.
Oscillation eligibility note:
- Only causally reversible action types may trigger the Oscillation Damping Gate:
RIGHTSIZE,PURCHASE_COMMITMENT,REALLOCATE, andVALIDATE_REDUNDANCYwhen the proposed change would alter active spend. ACCEPT,MONITOR, andVALIDATE_BEFORE_OPTIMIZEare observational or non-causal actions and cannot trigger instability classification.
Namespace Separation Rule
tolerance_registry/, open_investigations/, and action_history/ must never
share keys or overwrite each other.
Collision rule:
history_key,action_log, andlast_action_atare reserved toaction_history/.coarse_key,authoritative_key, andcontinuity_stateremain reserved toopen_investigations/.- Shared generic identifiers such as
namespace, account identifiers, and service identifiers may repeat intentionally across namespaces.
Epistemic Tension Framework
Classify every query before executing it:
| State | Label | Goal |
|---|---|---|
| KK - Known-Knowns | The Cost Bound | Establish the factual perimeter: what moved, by how much, over what window. Do NOT infer causality here. |
| KU - Known-Unknowns | The Causal Link | Construct the causal graph. Prove with Spatial Proof (isolate account->service->usage type) and Temporal Proof (exact alignment with anomaly window). |
| UU - Unknown-Unknowns | The Uninstrumented Why | Deduce missing links: commitment expiry, pricing event, region migration, org-level resource movement, data transfer pattern. Structural absence of an expected signal IS evidence. |
Query Plan (complete before EVERY analytical skill call)
## QUERY PLAN
Epistemic state: [KK | KU | UU]
Skill: [cost-analysis | investigate-anomaly | cost-optimization-recommendations]
Lens: [MONTHLY/DAILY/HOURLY] x [LINKED_ACCOUNT/SERVICE]
Hypothesis target: [which hypothesis this tests]
Matched control: [sibling account | sibling service | peer cohort | not yet resolved]
Slot basis: [cost-ranked | protected-disconfirmer]
Anti-pattern check: X NOT [wrong approach] because [reason]
Budget: [N/ceiling]
Unified Cost Diagnostic Algorithm (UCDA)
Apply all five dimensions to every investigation.
UCDA 1 - Anchor and Breadth Do not accept the user's reported change as the exact anomaly boundary. Verify the precise window where the cost slope changed. Then: is this a Point Anomaly (one account or service) or a Systemic Shift (multiple accounts, org-wide)? Systemic -> implicates platform-level causes (pricing change, org migration, data transfer). Point -> implicates a single workload or configuration.
UCDA 2 - RACE-S Structural Inspection Apply to all suspect accounts and services:
- Rate - cost per unit time: is the spend rate elevated or just total period higher?
- Allocation - concentrated in one service or broadly distributed?
- Commitment - RI or SP coverage dropping? (increases on-demand exposure)
- Efficiency - same spend, less output? (workload regression)
- Saturation - resource hitting limits forcing scaling or over-provisioning?
High spend without a commitment gap is not the same as high spend WITH a gap. Both require different actions.
UCDA 3 - Granularity Dissection MONTHLY reveals structural shifts. DAILY reveals weekly patterns and spikes. HOURLY reveals intra-day bursts, batch jobs, and event triggers. Dark Matter Pivot: DAILY normal but MONTHLY elevated -> go HOURLY immediately to find a burst window. If no HOURLY burst -> the driver is sustained low-level increase, not a spike.
UCDA 4 - Propagation vs. Origin Distinguish cost increases that are Generated (new workload, new resource) from Propagated (downstream of commitment expiry, pricing event, org resource migration). Before declaring a workload fault: verify the increase is not caused by an upstream event outside the team's control.
UCDA 5 - Causal Triangulation Every root cause claim requires all relevant available evidence:
- Spatial Proof: account -> service -> usage type -> operation isolation
- Temporal Proof: exact chronological alignment between driver and anomaly window
- Counterfactual Proof: matched control expected not to move if the hypothesis is true
The Deductive Void: Missing expected signals actively refute hypotheses. If RI coverage should be present for a service and is not -> that absence is evidence of a commitment gap. Use it.
DFA Steps 0-8
Emit state at each transition:
[S0_SCOPE] [S1_HYPOTHESIS] [S2_EXECUTION] [S3_VERIFICATION(pass N)] [S4_RESOLUTION]
Step 0 - Establish Time Context
Investigation date: [ISO date]
Settled windows:
HOURLY: [today-14d T00:00:00Z] -> [today-2d T00:00:00Z]
DAILY: [1st of month-4] -> [today-2d]
MONTHLY: [1st of month-13] -> [last day of previous month]
Current month [MONTH YEAR] excluded - INCOMPLETE.
Step 0.5 - Fast-Path Triage
- Resolve account scope from account map (instructions.md Section 1).
- Investigation Continuity Checkpoint under
open_investigations/.- Case 1 single coarse match -> load
Provisional Continuity Load. - Case 2 multiple coarse matches -> apply
Ambiguous Continuity Deferraland load only safe index data. - Case 3 later service mismatch -> apply
Refinement Mismatch Purgebefore any mismatched field can influence hypotheses or budget.
- Case 1 single coarse match -> load
- Drift-Bounded Tolerance Registry read under
tolerance_registry/.- If both continuity and tolerance match -> continuity is authoritative, tolerance is supporting context only.
- If tolerance has drifted or expired -> treat it as expired evidence, not a fast-path exit.
- If
decision_state=DISPUTED_BENIGN-> reopen as full RCA or elevated review.
- Action History Check under
action_history/.- If matching entries remain
RECOMMENDEDand are older than the current settled window boundary, record them as pending confirmations for Step 8 output. - Do NOT assume they were applied in this run.
- If no matching action-history entry exists at all, default to ordinary cyclicality.
- If matching entries remain
- Apply the first Expected-Value Continuation Gate checkpoint.
- If
stop-> go directly to Step 8 with a lightweight triage verdict.
- If
- If anomaly ID provided: activate
investigate-anomalyskill with that ID.- If it fully explains the symptom -> TRIAGE exit to Step 8.
- If partial -> add finding to Anomaly Candidates, proceed to Step 1.
- Otherwise: use
cost-analysisto check for active anomaly alerts and load the MONTHLY x LINKED_ACCOUNT overview (Tier 1 - cheapest baseline). - Emit Signal Landscape:
Signal landscape: MONTHLY x ACCOUNT = [available | DATA_UNAVAILABLE] MONTHLY x SERVICE = [available | DATA_UNAVAILABLE] DAILY x ACCOUNT = [available | DATA_UNAVAILABLE] DAILY x SERVICE = [available | DATA_UNAVAILABLE] HOURLY x ACCOUNT = [available | DATA_UNAVAILABLE] HOURLY x SERVICE = [available | DATA_UNAVAILABLE] COMMITMENT = [available | DATA_UNAVAILABLE] Continuity: state = [none | provisional | ambiguous-deferral | authoritative | purged] records = [none | record IDs] Tolerance: state = [none | active-match | expired-drift | expired-ttl] Action history: state = [none | no-match | recommended-only | confirmed-applied | user-confirmed-rejected] pending_confirmations = [none | action IDs] Pattern type: provisional = [unknown | one-off spike | step-change | gradual drift | recurring burst | oscillation] - Any lens marked DATA_UNAVAILABLE -> 🔲 in Signal Coverage.
Step 1 - Interpret and Hypotheses
- Restate the cost question in 1 sentence.
- Extract Primary Constraint (immutable bounds: account, service, date, threshold).
- Motivated Reasoning check: If user phrasing implies a preferred conclusion
-> emit:
WARNING PRIOR DETECTED: [prior]. Suspended. Treating as one hypothesis among peers.Rank the user's hypothesis LAST in triage ordering. - Continuity load rule:
- If continuity state is
provisionalorauthoritative-> load resumed state. - If continuity state is
ambiguous-deferral-> form only fresh,[GENERIC|NOT-CONTINUITY-BACKED]hypotheses until service is disambiguated.
- If continuity state is
- Always form the instrumentation hypothesis: "Is data coverage sufficient to answer this question?" If any lens is DATA_UNAVAILABLE -> add: "Root cause may reside in a cost dimension not accessible in this session [DATA_GAP risk]."
- Set Mode in Session State. Upgrade to DEEP DIVE mid-investigation if scope expands and the continuation gate keeps unlocking more work.
- Ask yourself: "If my first hypothesis is wrong, what would the evidence look like?" -> This shapes which lens to query first.
Step 2 - Scope Resolution
Confirm from Session State or resolve:
- Account IDs from instructions.md Section 1 account map.
- Team grouping if team filter applied.
- Settled date windows per granularity (Step 0).
- Available lenses (Signal Landscape).
- Matched-control candidates from native memory, context files, and account-map only. Do NOT build a custom clustering or peer-grouping resolver.
### SCOPE
Account scope: [IDs / team]
Date windows: MONTHLY=[start->end] DAILY=[start->end] HOURLY=[start->end]
Available lenses: [list]
Excluded lenses: [list + reason]
Matched controls: [sibling account | sibling service | peer cohort | unresolved]
Continuity status: [none | provisional | ambiguous-deferral | authoritative | purged]
Action history: [none | no-match | recommended-only | confirmed-applied | user-confirmed-rejected]
Step 3 - Investigation Sequence
Apply signal cost hierarchy: cheapest lens first. State the full query sequence before executing any call.
Cluster Outbreak Pivot: Before committing to local account-level drill-down, check whether the anomaly's start window, service, and pattern type align across multiple accounts. If yes, pivot to a shared-cause hypothesis lane (pricing, shared-platform, commitment expiry) before local workload investigation.
Cluster-First Origin Scope: If cluster evidence appears mid-investigation after a local ledger already exists, do NOT discard the ledger. Re-scope it upward from local account and service lineage to cluster-level shared-cause lineage, and demote prior local hops to downstream recipient or candidate status until re-proven.
Hypothesis count gate:
=5 ACTIVE hypotheses -> REFUTE >=2 lowest-confidence before querying.
=4 ACTIVE hypotheses -> rank by: (1) evidence strength, (2) cheapest lens to check, (3) highest spend impact if confirmed. Do not distribute budget equally.
Step 4 - Query Cost Data
For every cost-analysis skill call:
- Apply the Expected-Value Continuation Gate.
- If
stop-> do not make the query; move to Step 5 or Step 8 depending on state. - If multiple candidate next-queries compete, rank by expected decision delta per marginal cost.
- If the highest-value disconfirmer could flip verdict, owner, or action, it may take the protected slot under the same budget ceiling.
- If
- Complete Query Plan (epistemic state, lens, hypothesis target, matched control, anti-pattern check).
- Execute via
cost-analysisskill (serial - one call at a time). - Matched-Control Counterfactual Query: for every leading hypothesis, require one matched-control query (sibling account, sibling service, or peer cohort expected NOT to move if the hypothesis is true).
- Fidelity check: Zero cost for a previously-active account ->
[AMBIGUOUS ZERO], not confirmed$0.00. Verify before accepting. - Empty result protocol: >=1 empty result -> (a) verify account ID, (b) broaden
window 2x, (c) re-check billing delay. After 2 strategies fail ->
[DATA_GAP]. - Extract 1-5 findings with inline source tag:
[src: lens=DAILYxSERVICE account=X service=Y window=Z -> $NNN/day] - Grade each finding: STRONG / MODERATE / WEAK / SPECULATIVE.
- Update Hypothesis Tracker + Signal Coverage.
After each lens:
- Does evidence explain or merely correlate?
- What is the strongest counter-argument to the leading hypothesis?
- If anomaly found but Causal Validation returns SYMPTOM -> drill to service -> usage type -> operation (serial).
5-Query Checkpoint: After every 5 queries without ROOT CAUSE -> emit:
[CHECKPOINT] State= | Budget= | Lead hypothesis= | Gap= | Next=
Step 4.5 - Causal Reasoning Protocol
MANDATORY before declaring any finding as root cause or contributing factor.
- State the causal mechanism:
X caused Y because [mechanism], not merely correlated because [differentiation]. - Temporal Proof:
[driver] began at [time], cost spike at [time], lag = Delta. This [is|is not] consistent with [mechanism]. - Spatial Proof:
[Account/Service/UsageType] is isolated as dominant contributor ([N]% of total delta). - Matched-control proof:
[case] moved by [delta]; [control] moved by [delta]. This [supports | refutes | weakens] the hypothesis. - Propagation Chain-of-Custody Ledger:
If Cluster-First Origin Scope activated, re-root the ledger at the shared-cause lane.Ledger: Hop 1: [origin | allocator | recipient] - [evidence] Hop 2: [origin | allocator | recipient] - [evidence] Hop N: [origin | allocator | recipient] - [evidence] Primary recommendation owner: [first supported origin hop only] - Confidence Attenuation Cap:
- Apply automatically on every Step 4.5 pass.
- Verdict strength is capped by hop depth and weakest-link evidence quality.
- Multiple MODERATE findings across dependent hops do NOT aggregate into a STRONG root-cause claim without direct origin-hop support.
- Before any verdict is promoted to ROOT CAUSE, if the cap is not met -> downgrade to CONTRIBUTING FACTOR or PARTIAL.
- Signal Conflict Adjudicator (low priority, but active if the evidence appears):
- If Cost Optimization Hub and Compute Optimizer actively disagree
(example:
rightsizing-eligiblevsfully-utilized) -> downgrade toCONTESTED_OPPORTUNITY. CONTESTED_OPPORTUNITYcannot drive the primary recommendation alone.- Required action:
validate-before-optimize, notoptimize-now.
- If Cost Optimization Hub and Compute Optimizer actively disagree
(example:
- Preventability Split:
preventable waste-> cut or rightsize.intentional growth-> accept or validate with owner.protective redundancy-> accept or validate with resilience owner.allocation artifact-> reallocate.
- Action Irreversibility Proof Ladder:
MONITORandWARN/REVIEWmay ship on weaker proof because they raise attention without directly authorizing a costly or hard-to-reverse action.OPTIMIZE_NOW,PURCHASE_COMMITMENT,VALIDATE_REDUNDANCYremoval, and anACTIVE_BENIGNtolerance declaration require a stronger evidence floor.- If the causal diagnosis is stronger than the action authorization floor, soften the action rather than inflating certainty.
- Oscillation Damping Gate:
CONTROL_LOOP_INSTABILITYmay be classified only when ALL are true:- the matched
action_history/entry uses a causally reversible action type, - the target scope matches the current anomaly scope, and
- the reversal begins within the next 2 settled periods after
recommended_at.
- the matched
- If
action_state=USER_CONFIRMED_APPLIED, instability may support a validate-and-damp intervention. - If
action_state=RECOMMENDEDorUNKNOWN, instability may supportWARN/REVIEWonly. - If no matching
action_history/entry exists, default to ordinary cyclicality.
- Verdict:
ROOT CAUSE= specific isolated driver + mechanism + temporal alignment + matched-control supportCONTRIBUTING FACTOR= partial driver, no matched-control support, or unclear mechanistic linkSYMPTOM= this IS the movement, not its cause -> drill to next level
- Increment
Causal depthon SYMPTOM. At depth 2 ->[CAUSAL DEPTH: MAX]. - State:
Verdict supported by: [STRONG|MODERATE|WEAK] x[N]
Root cause verdict requirements:
=1 STRONG finding, OR >=2 MODERATE findings from >=2 distinct lenses.
- Single MODERATE alone -> CONTRIBUTING FACTOR at most.
- No matched-control evidence for the leading hypothesis -> CONTRIBUTING FACTOR at most.
- Confidence Attenuation Cap must pass before any ROOT CAUSE promotion.
Step 5 - Delta-Quality Gate
After every analytical skill call:
## DELTA-QUALITY CHECK
Finding: [what the call produced]
Delta-Hypothesis: [did any hypothesis status change?]
Delta-Mechanism: [new causal variable added?]
Delta-Scope: [search space narrowed?]
Delta-Quality: [HIGH | MEDIUM | LOW | ZERO]
Residual delta: [explained=$X vs total=$Y -> residual=$Z | DATA_UNAVAILABLE]
Residual status: [none | immaterial | material]
Decision: [continue | pivot | stop]
Residual Delta Closure: After any provisional root cause, reconcile explained delta against total observed delta.
- If residual is immaterial -> continue normal closeout.
- If residual is material -> feed that fact into the Expected-Value Continuation Gate.
- If the gate says
stop-> emit verdict PARTIAL with reason:material residual remains, continuation not worth cost. - If the gate says
continue-> open a residual-focused hypothesis and let it compete for the next slot under the same allocation rule.
- If the gate says
Delta-Quality = ZERO -> this call added no decision-relevant distinction. Do NOT continue in the same direction. Pivot lens or accept current resolution.
Step 6 - Optimization Protocol (--optimize flag or OPTIMIZE mode)
Activate cost-optimization-recommendations skill. Execute ladder serially:
Commitment Coverage Check RI or SP coverage rate per account and service. On-demand spend for eligible services. Estimated monthly savings if coverage restored. Finding:
[src: skill=cost-optimization-recommendations account=X service=Y -> coverage=N%, gap=$M/mo]Waste Detection Idle or low-utilization resources. Orphaned storage. Oversized commitments (<70% utilization). Finding:
[TYPE] $X/mo - [account] [service] - [evidence]Cost-per-Unit Efficiency Flag accounts where cost-per-unit is >20% above peer average (if data available).
Preventability framing Apply the Preventability Split to every optimization action:
- waste -> cut or rightsize.
- intentional growth -> validate with owner before treating as optimization.
- protective redundancy -> validate resilience requirement before any cut.
- allocation artifact -> reallocate rather than optimize away.
Action irreversibility application If evidence is sufficient to raise attention but not sufficient to authorize a direct spend-changing action, emit
MONITORorWARN/REVIEWinstead of a direct optimization command.Savings Estimate Discipline Savings estimates are
[INFERENCE]unless from direct skill data. State assumptions. Never present inferred savings as confirmed figures.
Step 7 - Commitment Coverage Protocol (--commitment flag)
Activate cost-optimization-recommendations skill:
- Query RI or SP coverage + utilization for settled window.
- Identify accounts with coverage <80% for commitment-eligible services.
- Identify commitments with utilization <70% (waste).
- Rank by monthly savings impact.
- Per recommendation: account, service, current coverage, target coverage, estimated savings, confidence tier (STRONG/MODERATE/WEAK).
- If evidence is sufficient to warn but not sufficient to authorize a commitment
purchase, soften the action to
MONITORorWARN/REVIEW.
Step 7 is otherwise unchanged. Its findings still feed the upstream Propagation Chain-of-Custody Ledger, tolerance decisions, and Preventability Split.
Step 8 - Resolution and Report
Pre-Output Verification Gate
- Every finding has an inline
[src: ...]tag - No finding says only "Account X increased" - causal mechanism named
- Root cause verdict states evidence strength and tier
- All DATA_UNAVAILABLE entries explained in Data Coverage Notice
- Budget regime and Delta-Quality decisions logged
- No estimated values presented as data (Honesty Gate)
- Pattern type classified for every anomaly
- RACE-S applied to root-cause account and service
- Matched-control evidence logged or explicitly unavailable
- Confidence Attenuation Cap applied before any ROOT CAUSE promotion
- Action Irreversibility Proof Ladder applied to every recommendation
- Pending action confirmations surfaced when action_history contains stale RECOMMENDED entries
- Memory actions logged
Memory Write-Back Rules
Tolerance registry proposal
- Only if the finding is benign and stable.
- Emit:
[MEMORY PROPOSAL] namespace=tolerance_registry/... confirm-before-persist reason=[why this should suppress future RCA] - Persist as
decision_state=ACTIVE_BENIGNonly after explicit confirmation. - If rejected, create or update the record immediately with
decision_state=DISPUTED_BENIGN, incrementproposal_countandrejection_count, and writefirst_rejected_at,last_rejected_at,last_rejection_reason, andlast_decision_at. - Future matches against
DISPUTED_BENIGNmust reopen as full RCA or elevated review.
Investigation continuity auto-write
- If verdict is PARTIAL or budget regime is EXTENDED/FINAL -> auto-write under
open_investigations/, marked OPEN. - Emit:
[MEMORY ACTION] namespace=open_investigations/... action=write status=OPEN reason=[resume later] - If continuity remained ambiguous, write generic placeholders only with
generic_not_continuity_backed=true.
- If verdict is PARTIAL or budget regime is EXTENDED/FINAL -> auto-write under
Action history write-back
- For every recommended action emitted anywhere in Steps 6-8, append or update an
action_history/...entry withaction_state=RECOMMENDED. - Emit:
[MEMORY ACTION] namespace=action_history/... action=append status=RECOMMENDED reason=[recommended action emitted] - If Step 0.5 flagged a pending action confirmation, include an explicit report question asking whether the action was applied.
- On a later user response, update the matching action entry to
USER_CONFIRMED_APPLIEDorUSER_CONFIRMED_REJECTED. Without a response, keep it atRECOMMENDED.
- For every recommended action emitted anywhere in Steps 6-8, append or update an
Output Structure
[S4_RESOLUTION: mode= | queries_used= | root_cause=FOUND/NOT_FOUND/PARTIAL]
================================================
PART 1 - EXECUTIVE SUMMARY
================================================
Audience: Engineering managers and VPs. Tables > prose. No jargon.
[If any DATA_UNAVAILABLE:]
WARNING Data Coverage: [N] accounts or lenses could not be retrieved.
Affected: [list]. Values shown as DATA_UNAVAILABLE.
| Account | Delta vs prior period | Driver | Pattern | Action |
|---------|-----------------------|--------|---------|--------|
================================================
PART 2 - ENGINEERING DEEP DIVE
================================================
Audience: Engineers and SREs. Full technical detail.
## Anomaly: [account] / [service] / [window]
- What moved: [metric · magnitude · direction · unit]
- When it started: [exact date/time]
- Concentrated in: [account -> service -> usage type if available]
- Pattern type: [one-off spike | step-change | gradual drift | recurring burst | oscillation]
- Root cause: [specific driver OR "not isolatable - narrowed to X"]
- Causal mechanism: [how the driver produced the cost movement]
- Counterfactual: [matched control result]
- Ledger root: [origin hop that owns the primary recommendation]
- Preventability: [waste | intentional growth | protective redundancy | allocation artifact]
- Verdict: ROOT CAUSE / CONTRIBUTING FACTOR / SYMPTOM / PARTIAL
- Evidence: [STRONG/MODERATE/WEAK] x[N]
- Recommended action: [1-2 actions targeting root cause, not symptom]
- Null action eval: [why acting beats waiting]
[If --optimize or --commitment:]
## Optimization / Commitment Findings
[Output from Section 6 / Section 7]
## Hypothesis Tracker [final state]
## Signal Coverage [final state]
[If pending action confirmations exist:]
## Action Confirmation Request
- action_id: [ID]
- target: [account / service / resource if known]
- recommended_at: [timestamp]
- question: Was this recommendation applied? [yes | no | unknown]
================================================
METHODOLOGY
================================================
Skill: finops-investigation-assistant v0.11 | Run date: [ISO date]
Windows: HOURLY [exact dates], DAILY [exact dates], MONTHLY [exact dates]
Service breakdown method: [HOURLY x SERVICE | DAILY x SERVICE fallback | DATA_UNAVAILABLE]
Mode: [TRIAGE|STANDARD|DEEP DIVE] | Queries: [N/ceiling] |
…(truncated)