references/completeness-and-root-cause.md·Markdown·9 KB·View on GitHub
Use this to decide whether a finding is complete and whether a root cause holds: confirming
whether a failure belongs to one entity or the whole fleet, reporting counts, totals or “no
evidence of X”, and performing and reporting root cause analysis. It applies to any source
(logs, API listings, data stores); the pagination rules below name the CloudWatch Logs calls.
Commands use AWS CLI syntax. The AWS MCP server is recommended for sandboxed execution and
audit logging; the same calls work through the CLI without it.
Before concluding that an event, request, or record doesn’t exist, make sure you searched
everywhere it could be:
AWS resources are regional. If resource names include a region or marketplace marker,
or the data could be served by more than one regional deployment, list and query the
matching resources in every plausible region, not just the default one.
Never report “no evidence of X” as a finding until you have checked every scope. If
searches across all scopes still find nothing, say exactly which scopes you checked.
For identity or authorization failures, find and compare the actual values on both
sides, such as the identity the invitation or grant was issued to and the identity that
authenticated. Base the root cause and fix on that comparison, not on guesses about
infrastructure.
When you read logs or list resources through AWS APIs, paginate until the data is exhausted
before you count, aggregate, or state a scope:
For CloudWatch GetLogEvents, keep following nextForwardToken until it returns the
same token twice.
For FilterLogEvents and List/Describe calls, keep following nextToken until none is
returned.
Treat any pagination or truncation warning as proof that the data is incomplete.
If one call returns too much output, process the pages and return only summaries. Do
not shrink the read to a single page.
Before you report counts, totals, or “every X” claims, check that the last event’s
timestamp matches the stream’s lastEventTimestamp. Also look for entities whose results
look partial, since that often means a page was cut off.
If you can’t confirm the data is complete, say the figures are partial.
When you compute a metric over a range (dates, hours, partitions, regions):
Check which values in the range have data, separately for each entity being compared.
In the answer, state for each entity whether its data covers the whole range, or name the
missing values.
Never present an aggregate as covering the full range when part of it has no data.
If the entities cover different subsets, say so, because it affects whether the comparison is
fair, and consider also giving the metric over the overlap they share.
When asked to confirm from logs whether a failure belongs to a particular entity (store,
account, tenant, resource), do not filter only on that entity. Get the wider context too:
Run an aggregated query, such as stats count by entity, sub-ID, and outcome, across
the same operation and time window. This shows whether the same error also hits other
entities, so you can say whether it is specific to this entity or happening everywhere.
For the target entity, list every unit of work in the relevant run, both successes and
failures, so you can see the full scope of the batch. Pay particular attention to the
operation that matters for the root cause.
If a query returns too much output, narrow it with aggregation, fields/parse, or
smaller time windows. Do not add filters that would hide the comparison you need.
In the final answer, state whether the failure is unique to the entity or shared, and
roughly how widely it is shared. Say which related operations succeeded. Explicitly correct
any earlier claims in the thread that the logs contradict.
When asked why one record is failed or in an exception state, widen the analysis to the
whole population the root cause touches: every category or rule pairing involved, every
entity, account or ID the user listed, exact totals per category and per side, how many of the
listed entities are affected and which are not, and the largest entity in each category.
Before reporting a root cause, check that it fits every fact you have already found,
especially your own conclusions about how the system is designed (for example, whether work
is pushed or pulled):
If something expected seems to be missing (such as a poller, loop, handler or log
entry), do not treat the gap as proof of a defect. First ask whether the design you already
found explains why it is absent.
Label any mechanism you could not confirm from data, configuration or logs as an
unverified hypothesis, never as the root cause. In particular, never claim how a processing
engine behaves (“rule X is being applied”) unless you have read the rule definition.
If the evidence points elsewhere (such as a resource whose state changed or a reference
that now points to a newer record), build the diagnosis on that.
Treat a missing feature as a root cause only after you confirm the component was meant to
have it:
A missing feature can be a missing handler, polling loop, subscriber, or log line.
Before calling its absence a defect, work out from the evidence which component owns that
responsibility.
In distributed or cross-region systems, check the data’s target or destination fields
(such as target region, account, or consumer) to see whether a different service or region
does that work.
If you can’t confirm who owns it, report the absence as an open question and name the
next system to check. Don’t present it as the root cause.
When investigating a bug report against code and logs, make sure your final verdict follows
from your evidence:
If your trace shows that a computation gives a wrong or self-inconsistent result (for
example, the same quantity is counted twice, or a valid request is rejected even though the
resource is available), classify it as a code defect.
Do not call it “working as designed”, and do not offer only workarounds such as process
changes, extra user steps, or better error messages.
Name the specific faulty expression or line and propose a concrete code correction that
would have made the reported case succeed. Workarounds can be listed as extra suggestions
after that.
Take the intended behavior from the code and from the user’s stated expectations, not
from your own view of what the system should do. If a code path exists to handle a case
(such as a fallback, retry, or alternate branch), treat that case as supported unless you
have clear evidence otherwise.
Do not say the case should be rejected, or call the failure “working as designed,” when
your own diagnosis shows a defect.
Recommend only the minimal fix that follows from the evidence, and do not add extra
policy changes on top of it.
Remove or correct anything that contradicts your main finding, the user’s stated
expectation, or the purpose of the code.
If the user points to a runbook or playbook, go through every remediation it lists
(retry, rollback, scaling, backfill, escalation) and say for each whether it addresses the
confirmed cause and why, including the ones you reject. Name the options that only treat the
symptom, such as a retry for a deterministic limit or a code defect. Recommend the change that
fixes the cause.
When a user asks a specific question or names a suspected cause (for example, “why isn’t X
being applied?” or “is it enforced per A or per B?”):
Answer that question, and back the answer with evidence from the
system.
Check the actual configuration or enforcement records, such as limit or quota
settings, throttle or decision logs, and the keys or dimensions they record.
Say plainly whether the configuration was in effect during the incident window, what
scope it applied to, and what value was enforced.
Rule out each competing explanation the user or other stakeholders raised, using
evidence rather than assumption.
Don’t hedge or offer speculative alternatives your evidence doesn’t support (such as
limits reverting to defaults or being split across hosts or partitions).
If you can’t confirm something, label it as unverified instead of implying it.