@clipboard-health/ai-rules 2.38.0 โ 2.38.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/scripts/toErrorMessage.js +1 -1
- package/skills/cb-babysit/SKILL.md +4 -4
- package/skills/cb-babysit/scripts/_sentinel.sh +1 -1
- package/skills/cb-ship/references/pr-template.md +1 -1
- package/skills/flaky-critic/references/rubric.md +16 -1
- package/skills/flaky-debug/SKILL.md +26 -1
- package/skills/flaky-debug/references/datadog-apm-traces.md +135 -54
- package/skills/flaky-debug/references/plan-e2e.md +2 -0
- package/skills/flaky-debug/references/plan.md +22 -9
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.toErrorMessage = toErrorMessage;
|
|
4
|
-
// Prefer stack over message for Error instances to preserve debugging context
|
|
4
|
+
// Prefer stack over message for Error instances to preserve debugging context!
|
|
5
5
|
function toErrorMessage(error) {
|
|
6
6
|
return error instanceof Error ? (error.stack ?? error.message) : String(error);
|
|
7
7
|
}
|
|
@@ -19,9 +19,9 @@ Resolve bundled "./scripts" paths relative to SKILL.md.
|
|
|
19
19
|
|
|
20
20
|
The skill uses two sentinels with visible footer lines.
|
|
21
21
|
|
|
22
|
-
**Addressed sentinel**: `<sub>๐ค <code>cb-babysit:addressed v1 core@3.17.
|
|
22
|
+
**Addressed sentinel**: `<sub>๐ค <code>cb-babysit:addressed v1 core@3.17.1</code></sub>`. Appended on its own line at the end of every reply the skill posts so re-runs know which threads and review-body comments are already handled. Dedupe also recognizes the legacy `babysit-pr:addressed v1` prefix from before this skill was renamed.
|
|
23
23
|
|
|
24
|
-
**Follow-up sentinel**: `<sub>๐ค <code>cb-babysit:followup v1 core@3.17.
|
|
24
|
+
**Follow-up sentinel**: `<sub>๐ค <code>cb-babysit:followup v1 core@3.17.1</code></sub>`. Attached to replies that defer an out-of-scope comment as a tracked follow-up. The sentinel is additive: the post-reply scripts still append the `addressed` sentinel at the end.
|
|
25
25
|
|
|
26
26
|
**Sentinel recency rules.** The script emits a per-thread `activityState` with three values. Step 6a owns the handling rules for each state.
|
|
27
27
|
|
|
@@ -247,7 +247,7 @@ Body templates (the script appends the `addressed` sentinel if missing):
|
|
|
247
247
|
- **Agree**: `Addressed in <commit-url>. <one-line what-changed>.`
|
|
248
248
|
- **Disagree**: `Leaving current behavior. <reasoning>.`
|
|
249
249
|
- **Already fixed**: `Already handled by <commit-url-or-file:line>. <brief pointer>.`
|
|
250
|
-
- **Defer**: `Out of scope for this PR; this looks like follow-up work rather than something introduced or required by this change. <one-line rationale or pointer if useful>.\n\n<sub>๐ค <code>cb-babysit:followup v1 core@3.17.
|
|
250
|
+
- **Defer**: `Out of scope for this PR; this looks like follow-up work rather than something introduced or required by this change. <one-line rationale or pointer if useful>.\n\n<sub>๐ค <code>cb-babysit:followup v1 core@3.17.1</code></sub>`
|
|
251
251
|
|
|
252
252
|
For Defer replies, include the follow-up sentinel on its own line as shown. The script will append the `addressed` sentinel after it on its own line, so the final body ends with the follow-up sentinel followed by a blank line followed by the `addressed` sentinel. `grep cb-babysit:followup` finds the deferral and `grep cb-babysit:addressed` still marks the thread handled for dedupe.
|
|
253
253
|
|
|
@@ -263,7 +263,7 @@ The PR-level summary should:
|
|
|
263
263
|
|
|
264
264
|
- Group by source. Use `## Review-body findings` for step-7 work and `## Conversation-tab comments` for step-6b work. Omit a section if its list is empty.
|
|
265
265
|
- Inside each section, group verdicts under **Agree / Disagree / Already fixed / Deferred (out of scope)** subheadings. Omit a subheading if its list is empty.
|
|
266
|
-
- Under **Deferred (out of scope)**, list each deferred item as a bullet, followed on its own line by `<sub>๐ค <code>cb-babysit:followup v1 core@3.17.
|
|
266
|
+
- Under **Deferred (out of scope)**, list each deferred item as a bullet, followed on its own line by `<sub>๐ค <code>cb-babysit:followup v1 core@3.17.1</code></sub>` so grep catches them individually.
|
|
267
267
|
- Include the commit URL for fixes.
|
|
268
268
|
- End with a fenced fingerprint block listing every current fingerprint (addressed and deferred) one per line. Include both `reviewBodyComments[].fingerprint` (whole-body, one per automated review) and `activeIssueComments[].fingerprint` (per Conversation-tab comment). Future runs dedupe by matching these against `priorBabysitSentinels`.
|
|
269
269
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
SENTINEL_PREFIX='cb-babysit:addressed v1 '
|
|
12
12
|
LEGACY_SENTINEL_PREFIX='babysit-pr:addressed v1 '
|
|
13
|
-
SENTINEL='<sub>๐ค <code>cb-babysit:addressed v1 core@3.17.
|
|
13
|
+
SENTINEL='<sub>๐ค <code>cb-babysit:addressed v1 core@3.17.1</code></sub>'
|
|
14
14
|
|
|
15
15
|
# Bot author allowlist (JSON array literal). Used by unresolvedPrComments.sh
|
|
16
16
|
# as a fallback when GraphQL's `author.__typename == "Bot"` misses a GitHub
|
|
@@ -17,5 +17,5 @@ Concisely explain the user intent from session history and the meaningful behavi
|
|
|
17
17
|
|
|
18
18
|
Optional, don't fabricate: ticket links, rollout plan, residual risk, or specific areas for reviewers to focus.
|
|
19
19
|
|
|
20
|
-
<sub>๐ค <code>cb-ship:created v1 core@3.17.
|
|
20
|
+
<sub>๐ค <code>cb-ship:created v1 core@3.17.1</code></sub>
|
|
21
21
|
```
|
|
@@ -8,7 +8,7 @@ This rubric turns Rocky's observed review standards into checkable rules for fla
|
|
|
8
8
|
|
|
9
9
|
Findings from automated reviewers (Mendral, CodeRabbit, etc.) are **advisory inputs, not binding rules**: the critic evaluates each on rubric merits and may decline one with stated reasoning, exactly as cb-babysit's Disagree replies do.
|
|
10
10
|
|
|
11
|
-
**Statement-missing vs substance-missing (backtest amendment, 2026-06-11):** B5/B6/B7 each require an explicit statement in the plan (dedup-check results, confidence score plus observability section, current-main status). When the _statement_ is absent but the violation is not demonstrated โ no actual duplicate found, no actual low-confidence code fix, no actual staleness โ the verdict is reject with disposition **amend-and-resubmit**: one bounce asking for exactly the missing sections, never escalation. A demonstrated violation (a real duplicate, a real โค2/5 code fix) is a substantive reject. The 2026-06-11 backtest showed 6 of 7 false rejections were statement-missing on plans predating these conventions; live plans carry the sections by template, but the distinction stays load-bearing for the agreement metric.
|
|
11
|
+
**Statement-missing vs substance-missing (backtest amendment, 2026-06-11):** B5/B6/B7/B8 each require an explicit statement in the plan (dedup-check results, confidence score plus observability section, current-main status, causal-chain section). When the _statement_ is absent but the violation is not demonstrated โ no actual duplicate found, no actual low-confidence code fix, no actual staleness, no demonstrably symptom-terminated diagnosis โ the verdict is reject with disposition **amend-and-resubmit**: one bounce asking for exactly the missing sections, never escalation. A demonstrated violation (a real duplicate, a real โค2/5 code fix, a diagnosis that demonstrably stops at a symptom) is a substantive reject. The 2026-06-11 backtest showed 6 of 7 false rejections were statement-missing on plans predating these conventions; live plans carry the sections by template, but the distinction stays load-bearing for the agreement metric.
|
|
12
12
|
|
|
13
13
|
## 2. Banned patterns
|
|
14
14
|
|
|
@@ -72,6 +72,21 @@ Implementing a plan against code that has changed on `main`, or for a flake alre
|
|
|
72
72
|
|
|
73
73
|
**Staleness clause (backtest amendment, 2026-06-11):** a plan more than ~14 days old, or one whose fingerprint has new sightings since the plan was written, requires re-verification against current main before approval โ treat unverified staleness as B7. (Two backtest "rejections" were plans that sat unworked until a sweep canceled them; freshness is part of a plan being gateable.)
|
|
74
74
|
|
|
75
|
+
### B8 โ Unterminated causal chain (symptom-level diagnosis)
|
|
76
|
+
|
|
77
|
+
Proposing a code fix from a diagnosis that stops at the failure symptom โ "the request 500ed/timed out," "setup was throttled," "the element never appeared" โ without establishing _why_ at a specific cause in the owning code, config, or infrastructure.
|
|
78
|
+
|
|
79
|
+
**Why (amendment, 2026-07-07):** post-Done recurrence is the pipeline's dominant failure mode: in the Jun 2โJul 6 window, 21 fingerprint families re-flaked after a Done closure, and the fullLifecycle family (33deef731a10) was closed Done six times. Each recurrence traces to a diagnosis that dead-ended at the repo boundary or at a status code and patched the symptom locally. Local-symptom plans are the cheapest to produce, so as long as the gate accepts them, agents keep producing them; this rule makes boundary-crossing the only way to pass.
|
|
80
|
+
|
|
81
|
+
**Required structure:** the plan must contain a **Causal chain** section: failing assertion โ app/UI state โ network/trace/log evidence (trace ID, or run-window log queries when the causal event is outside the test's request path: seeding, deploys, CDC/async jobs) โ owning service and repo, resolved via the groundtruth ownership registry (`ClipboardHealth/groundtruth`, `registry/services.json` โ `registry/repos.json`) โ terminal cause cited at file/line, config key, or specific log line. The link types adapt to the failure surface: CI/setup, fixture, component, and unit failures substitute build logs, fixture state, or runner artifacts for network evidence and the owning package/repo for a deployed service โ the critic checks the terminus, not a fixed link shape. Two valid terminal states:
|
|
82
|
+
|
|
83
|
+
1. **Terminated:** the chain ends at a cause. A status code, timeout, or throttle is a link, never a terminus.
|
|
84
|
+
2. **Explicitly broken:** the chain names the link where evidence ran out and the observability that would extend it; confidence is capped at 2/5 and B6 applies โ the deliverable is the instrumentation, not a code fix.
|
|
85
|
+
|
|
86
|
+
**Confidence ceiling:** 5/5 additionally requires reproduction by inducing the blamed cause โ fault injection in the harness (delay or fail the specific response, disable the seed step) or a focused lower-level test that deterministically reproduces the race. Without reproduction, the ceiling is 4/5. One inferred _intermediate_ link with an evidenced terminus is still a terminated chain (โค4/5); an unevidenced terminus is a broken chain (cap 2/5).
|
|
87
|
+
|
|
88
|
+
**Detection heuristic:** plan lacks a Causal chain section (statement-missing โ amend-and-resubmit per ยง1); the terminal link is a symptom rather than a cause; the chain implicates another service or repo but cites no code/log evidence from it and doesn't route per C5/D5; or the plan claims 5/5 without reproduction evidence.
|
|
89
|
+
|
|
75
90
|
## 3. Allowed/safe patterns
|
|
76
91
|
|
|
77
92
|
These have strong precedent (counts from the 74 merged `flaky-test-fix` PRs; classification approximate) and are auto-merge candidates **only** when the listed evidence is present in the PR body.
|
|
@@ -3,7 +3,32 @@ name: flaky-debug
|
|
|
3
3
|
description: Debug and fix flaky tests including Playwright E2E, NestJS service/integration, React component, and unit tests.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Phases run in order. Skip a phase if you already have the information it produces. Phase 3 runs only in fix mode.
|
|
6
|
+
Phases run in order. Phase 0 is mandatory. Skip a later phase if you already have the information it produces. Phase 3 runs only in fix mode.
|
|
7
|
+
|
|
8
|
+
## Phase 0: Verify investigation access
|
|
9
|
+
|
|
10
|
+
Run these checks before classifying or diagnosing the failure. Do not silently continue with reduced evidence if a check fails.
|
|
11
|
+
|
|
12
|
+
1. Verify that `pup` can read APM spans. Do not use `pup auth status`; it can fail in sandboxes where environment-variable authentication works.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
command -v pup
|
|
16
|
+
pup traces search \
|
|
17
|
+
--query="service:cbh-backend-main env:staging" \
|
|
18
|
+
--from=15m \
|
|
19
|
+
--limit=1 \
|
|
20
|
+
--jq='.data | length'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
A successful query is sufficient even when the count is zero. If `pup` is missing, install it and rerun the check. For `401`/authentication failures, run `pup auth login` on a developer machine or provide `DD_API_KEY` and `DD_APP_KEY` in a sandbox/CI session. For `403`, obtain an application key or OAuth session with APM read access.
|
|
24
|
+
|
|
25
|
+
2. For a CI-sourced E2E failure, verify artifact access by fetching the exact run before doing any diagnosis:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
bash "<flaky-debug-skill-dir>/scripts/fetch-llm-report.sh" "<github-actions-url>"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
If GitHub authentication fails, run `gh auth login --hostname github.com` and ensure the token can read Actions artifacts in the repository. If the artifact is missing or expired, rerun the source workflow or obtain the `playwright-llm-report`/Playwright HTML report from the user. A missing run URL or inaccessible artifact blocks a CI-sourced E2E investigation; report the failed command and remediation instead of degrading the confidence score. Artifact access is not applicable to service, component, or unit failures that were reproduced locally with complete output.
|
|
7
32
|
|
|
8
33
|
## Mode: plan vs fix
|
|
9
34
|
|
|
@@ -1,84 +1,165 @@
|
|
|
1
1
|
# Datadog APM Traces
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Correlate a Playwright network instance with backend spans in Datadog's **APM Spans index**. Use the per-request `attempts[].network.instances[].traceId`; do not use the test-level fixture annotation.
|
|
4
4
|
|
|
5
5
|
## Prerequisites
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Phase 0 of the flaky-debug skill must already have proved that `pup` can read APM spans and that the exact CI artifact is accessible. Do not run `pup auth status`; call `pup traces search` directly because environment-variable authentication can work in sandboxes where `pup auth status` does not.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- **Environment variables** (`DD_API_KEY` + `DD_APP_KEY`) โ the path used in sandboxes and CI.
|
|
9
|
+
If a query fails with `401`, run `pup auth login` or provide `DD_API_KEY` and `DD_APP_KEY`. For `403`, obtain APM read access. Do not continue an investigation without this access.
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
## Which trace ID is authoritative?
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
Use these sources in order:
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- **`--limit` defaults to 50.** Max is 1000. For large traces, you may need multiple paginated calls (but pup handles most pagination internally).
|
|
20
|
-
- **Query syntax for traces:** `service:<name> resource_name:<path> @duration:>5s env:production status:error operation_name:<op>`
|
|
15
|
+
1. The response `traceparent`, exposed as `network.instances[].traceId`. It identifies the context the backend actually selected.
|
|
16
|
+
2. For an aborted or unreadable response, the request's `x-datadog-trace-id`. Reporter versions containing the Datadog fallback normalize its unsigned decimal value to a 32-character, zero-padded hexadecimal trace ID.
|
|
17
|
+
3. The request `traceparent` only when no Datadog request context exists.
|
|
21
18
|
|
|
22
|
-
|
|
19
|
+
Do **not** query the test-level `traceparent` annotation. The Playwright fixture sets a W3C header, but Datadog RUM also adds a different `x-datadog-*` context to first-party requests. The observed staging backend selects the Datadog context when the two conflict.
|
|
23
20
|
|
|
24
|
-
|
|
21
|
+
For reports produced by an older reporter, inspect the full Playwright trace's request headers. Convert `x-datadog-trace-id` as described below. If neither a response trace nor the Datadog request header is available, use the request-ID correlation path instead of claiming that the fixture ID represents the backend trace.
|
|
22
|
+
|
|
23
|
+
## Known-good query recipe
|
|
24
|
+
|
|
25
|
+
### 1. Set an exact time window
|
|
26
|
+
|
|
27
|
+
Derive the request time from the attempt's `startTime` plus the network instance's `offsetMs`. Use a narrow absolute RFC 3339 window around the request; this avoids false matches and is safer than relying on `pup`'s one-hour default.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pup traces search \
|
|
31
|
+
--query='env:staging trace_id:<TRACE_ID>' \
|
|
32
|
+
--from='2026-07-06T14:10:00Z' \
|
|
33
|
+
--to='2026-07-06T14:20:00Z' \
|
|
34
|
+
--limit=1000
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Start without a service filter when ownership is uncertain. Once the service is known, add it to reduce noise.
|
|
38
|
+
|
|
39
|
+
### 2. Use the staging service name
|
|
40
|
+
|
|
41
|
+
Staging APM service names are `cbh-*` prefixed. For example:
|
|
25
42
|
|
|
26
43
|
```bash
|
|
27
|
-
pup traces search
|
|
44
|
+
pup traces search \
|
|
45
|
+
--query='env:staging service:cbh-backend-main trace_id:<TRACE_ID>' \
|
|
46
|
+
--from='<RFC3339_START>' \
|
|
47
|
+
--to='<RFC3339_END>' \
|
|
48
|
+
--limit=1000
|
|
28
49
|
```
|
|
29
50
|
|
|
30
|
-
|
|
51
|
+
`service:cbh-backend-main` works; `service:backend-main` returns nothing. Other examples include `cbh-user`, `cbh-bg-jobs`, and `cbh-documents-service-backend`.
|
|
31
52
|
|
|
32
|
-
|
|
53
|
+
### 3. Use a supported ID representation
|
|
33
54
|
|
|
34
|
-
|
|
55
|
+
`pup traces search` accepts either:
|
|
35
56
|
|
|
36
|
-
|
|
57
|
+
- the full 32-character hexadecimal trace ID returned by the spans API, or
|
|
58
|
+
- the unsigned decimal value of the lower 64 bits.
|
|
59
|
+
|
|
60
|
+
Do not convert the entire 128-bit value to decimal; the APM Spans search did not match that representation in the live verification.
|
|
61
|
+
|
|
62
|
+
Convert a 32-character W3C/Datadog hexadecimal ID to its lower-64 decimal form:
|
|
37
63
|
|
|
38
64
|
```bash
|
|
39
|
-
|
|
65
|
+
node -e '
|
|
66
|
+
const id = process.argv[1].replace(/^0x/, "");
|
|
67
|
+
if (!/^[0-9a-f]{32}$/i.test(id)) process.exit(1);
|
|
68
|
+
console.log(BigInt(`0x${id.slice(-16)}`).toString(10));
|
|
69
|
+
' '<TRACE_ID>'
|
|
40
70
|
```
|
|
41
71
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
.span_id โ unique span identifier
|
|
51
|
-
.trace_id โ shared across all spans in the trace
|
|
52
|
-
.parent_id โ parent span (for building the call tree)
|
|
53
|
-
.service โ service name (e.g., "cbh-backend-main")
|
|
54
|
-
.operation_name โ operation (e.g., "express.request", "express.middleware", "http.request")
|
|
55
|
-
.resource_name โ resource (e.g., "GET /api/v1/users", "<anonymous>")
|
|
56
|
-
.status โ "ok" or "error"
|
|
57
|
-
.start_timestamp โ ISO 8601 start time
|
|
58
|
-
.end_timestamp โ ISO 8601 end time
|
|
59
|
-
.custom.duration โ duration in NANOSECONDS (divide by 1,000,000 for ms)
|
|
60
|
-
.custom.env โ environment (e.g., "staging", "production")
|
|
61
|
-
.custom.error โ error object with .message, .file, .fingerprint (null if no error)
|
|
62
|
-
.custom.type โ span type (e.g., "web", "http", "mongodb", "redis", "worker")
|
|
63
|
-
.custom.service โ service name (also at top level)
|
|
64
|
-
.tags[] โ array of tag strings
|
|
72
|
+
Normalize an `x-datadog-trace-id` decimal value to the reporter's 32-character hexadecimal form:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
node -e '
|
|
76
|
+
const value = BigInt(process.argv[1]);
|
|
77
|
+
if (value <= 0n || value > 0xffffffffffffffffn) process.exit(1);
|
|
78
|
+
console.log(value.toString(16).padStart(32, "0"));
|
|
79
|
+
' '<X_DATADOG_TRACE_ID>'
|
|
65
80
|
```
|
|
66
81
|
|
|
67
|
-
|
|
82
|
+
### 4. Query a span ID only as a secondary lookup
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pup traces search \
|
|
86
|
+
--query='env:staging span_id:<SPAN_ID>' \
|
|
87
|
+
--from='<RFC3339_START>' \
|
|
88
|
+
--to='<RFC3339_END>' \
|
|
89
|
+
--limit=1
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
A response `traceparent` contains the backend span ID. A request fallback contains the upstream parent span ID, which may not itself be an indexed backend span; the trace ID remains authoritative.
|
|
93
|
+
|
|
94
|
+
### 5. Summarize relevant spans
|
|
95
|
+
|
|
96
|
+
Durations are nanoseconds. Divide by 1,000,000 for milliseconds.
|
|
68
97
|
|
|
69
98
|
```bash
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
99
|
+
pup traces search \
|
|
100
|
+
--query='env:staging trace_id:<TRACE_ID>' \
|
|
101
|
+
--from='<RFC3339_START>' \
|
|
102
|
+
--to='<RFC3339_END>' \
|
|
103
|
+
--limit=1000 \
|
|
104
|
+
| jq '[.data[].attributes | {
|
|
105
|
+
trace_id,
|
|
106
|
+
span_id,
|
|
107
|
+
parent_id,
|
|
108
|
+
service,
|
|
109
|
+
operation: .operation_name,
|
|
110
|
+
resource: .resource_name,
|
|
111
|
+
status,
|
|
112
|
+
retained_by,
|
|
113
|
+
duration_ms: ((.custom.duration // 0) / 1000000 | . * 100 | round / 100),
|
|
114
|
+
error: .custom.error.message
|
|
79
115
|
}]'
|
|
80
116
|
```
|
|
81
117
|
|
|
82
|
-
|
|
118
|
+
## Retention limitation and fallback correlation
|
|
119
|
+
|
|
120
|
+
`pup traces search` searches indexed spans, not every ingested span. An ingested trace is available in Live Search for only 15 minutes unless a retention mechanism indexes it. A zero-result indexed query after that window does **not** prove that propagation or ingestion failed.
|
|
121
|
+
|
|
122
|
+
If no indexed span exists:
|
|
123
|
+
|
|
124
|
+
1. Record the exact query, environment, service variants, ID representations, and absolute time window tried.
|
|
125
|
+
2. Search logs in the same window using the API Gateway/request ID, exact method/path, and service. The reporter may expose `requestId`; setup diagnostics may expose `apiGatewayRequestId`.
|
|
126
|
+
3. Correlate the response status/body and the owning service from the report. Do not lower confidence merely because a success trace was not selected for retention; lower it only when a necessary causal link remains unproved.
|
|
127
|
+
4. For a new occurrence, run the APM lookup within 15 minutes or add an explicit retention strategy for test traffic before relying on historical APM lookup.
|
|
128
|
+
|
|
129
|
+
Example log search shape:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
pup logs search \
|
|
133
|
+
--query='env:staging "<API_GATEWAY_REQUEST_ID>"' \
|
|
134
|
+
--from='<RFC3339_START>' \
|
|
135
|
+
--to='<RFC3339_END>' \
|
|
136
|
+
--limit=100
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Audit proof: why the fixture ID cannot be the bridge
|
|
140
|
+
|
|
141
|
+
The STAFF-1792 audit used the failed attempt from `cbh-admin-frontend` CI run `29337068333` (`2026-07-14T13:35:30Z`) and its raw Playwright trace:
|
|
142
|
+
|
|
143
|
+
- The request carried fixture W3C context `00-0df9d80ac12e173dfcfc55aa29379ba6-5819a315ecd12173-01`.
|
|
144
|
+
- Datadog RUM added `x-datadog-trace-id: 13639781014258445719`, `x-datadog-parent-id: 7268017665183408395`, origin `rum`, and sampling priority `1`.
|
|
145
|
+
- The backend response carried `00-0000000000000000bd4a3c90d8fded97-277d492d139029e1-01`. `bd4a3c90d8fded97` is exactly the hexadecimal form of the request's decimal `x-datadog-trace-id`, not the fixture trace ID.
|
|
146
|
+
|
|
147
|
+
This proves header propagation reached the backend, but the backend selected the Datadog RUM context. Minting a differently shaped W3C fixture ID cannot fix that conflict by itself. The reporter therefore uses the response trace and, when the response is unreadable, the Datadog request context.
|
|
148
|
+
|
|
149
|
+
The same audit checked backend and Datadog configuration:
|
|
150
|
+
|
|
151
|
+
- `clipboard-health/src/tracer.ts` calls `tracer.init({ logLevel: "error" })` without a propagation-style override; the locked `dd-trace` version is `5.27.1`.
|
|
152
|
+
- No customer APM head-sampling rules were returned for `cbh-backend-main`/staging, and adaptive sampling was not onboarded.
|
|
153
|
+
- The retention-filter API returned `401` for the available OAuth session, so the audit could not enumerate organization retention filters and does not infer that none exist. Indexed sample spans reported `retained_by: diversity_sampling`.
|
|
154
|
+
|
|
155
|
+
Historical indexed proof comes from STAFF-1678. Its backend response trace ID `00000000000000001732fff1044f982e` converts to decimal `1671679822332401710`; this exact query returned retained `cbh-user` spans for `POST /api/user/create`:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
pup traces search \
|
|
159
|
+
--query='trace_id:1671679822332401710 env:staging service:cbh-user resource_name:"POST /api/user/create"' \
|
|
160
|
+
--from='2026-07-06T14:10:00Z' \
|
|
161
|
+
--to='2026-07-06T14:20:00Z' \
|
|
162
|
+
--limit=5
|
|
163
|
+
```
|
|
83
164
|
|
|
84
|
-
|
|
165
|
+
Those spans reported `retained_by: diversity_sampling`. This is the working alternative correlation path: use the backend-selected per-request trace ID when it was retained; otherwise correlate by API Gateway/request ID plus exact time, method, path, and service.
|
|
@@ -136,6 +136,8 @@ Scan `attempts[].network.instances[]` for 4xx/5xx responses near the failure's `
|
|
|
136
136
|
|
|
137
137
|
**`traceId`** โ when present on a failing instance (`attempts[].network.instances[].traceId`), you must follow [`./datadog-apm-traces.md`](./datadog-apm-traces.md) to correlate with backend behavior. This is the bridge between frontend test failure and potential backend root cause.
|
|
138
138
|
|
|
139
|
+
Use the per-request `network.instances[].traceId`, not the test-level `traceparent` annotation. Datadog RUM adds `x-datadog-*` headers to first-party requests, and the staging backend selects that context when it conflicts with the fixture's W3C `traceparent`. The reporter prefers the response `traceparent`; for an unreadable/aborted response it normalizes the request's `x-datadog-trace-id` to the same zero-padded hexadecimal form. Older reporter versions may fall back to the fixture ID instead; inspect the full Playwright trace for `x-datadog-trace-id` or use the request-ID/time-window correlation path in `datadog-apm-traces.md`.
|
|
140
|
+
|
|
139
141
|
If no expected request was emitted, say that explicitly and do not diagnose backend latency for that action. Instead, use the trace, console/page errors, session/permission state, and frontend code path to explain why the request never started.
|
|
140
142
|
|
|
141
143
|
Check `attempts[].network.summary` for saturation. Non-zero `instancesDroppedByGroupCap`, `instancesDroppedByInstanceCap`, or `instancesEvictedAfterAdmission` means retained content is a sample and the request you care about may have been dropped โ note this as a confidence-reducing factor. `instancesDroppedByFilter` alone is expected (static assets are filtered by design). v3 caps: instances 500, groups 200, bodies 100 per attempt.
|
|
@@ -6,20 +6,32 @@ Shared tail of the flaky-debug planning phase, used by both [`plan-e2e.md`](./pl
|
|
|
6
6
|
|
|
7
7
|
Rate your confidence in the root cause on a 1-5 scale. Report this score alongside your evidence.
|
|
8
8
|
|
|
9
|
-
| Score | Meaning | Criteria
|
|
10
|
-
| ----- | ------------------- |
|
|
11
|
-
| **5** | Certain | Root cause is directly visible in artifacts
|
|
12
|
-
| **4** | High confidence |
|
|
13
|
-
| **3** | Moderate confidence | Evidence is consistent with the diagnosis but alternative explanations remain plausible. Flag the alternatives explicitly
|
|
14
|
-
| **2** | Low confidence | Limited evidence, mostly reasoning from code patterns rather than observed artifacts. Recommend gathering more data before committing to a fix
|
|
15
|
-
| **1** | Speculative | No direct evidence for the root cause. The fix is a best guess. Recommend reproducing the failure locally or adding instrumentation before proceeding
|
|
9
|
+
| Score | Meaning | Criteria |
|
|
10
|
+
| ----- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
11
|
+
| **5** | Certain | Root cause is directly visible in artifacts AND reproduced by inducing it โ fault injection in the harness (delay/fail the blamed response or step) or a focused lower-level test that deterministically triggers the race. Without reproduction, the ceiling is 4 |
|
|
12
|
+
| **4** | High confidence | The chain terminates at an evidenced cause (file/line, config key, or log line) but one intermediate link is inferred rather than observed. An unevidenced terminal cause is a broken chain, capped at 2 (see [Causal Chain](#causal-chain)) |
|
|
13
|
+
| **3** | Moderate confidence | Evidence is consistent with the diagnosis but alternative explanations remain plausible. Flag the alternatives explicitly |
|
|
14
|
+
| **2** | Low confidence | Limited evidence, mostly reasoning from code patterns rather than observed artifacts. Recommend gathering more data before committing to a fix |
|
|
15
|
+
| **1** | Speculative | No direct evidence for the root cause. The fix is a best guess. Recommend reproducing the failure locally or adding instrumentation before proceeding |
|
|
16
16
|
|
|
17
17
|
Apply the score:
|
|
18
18
|
|
|
19
19
|
- **If >2:** continue to [Decide Fix Approach](#decide-fix-approach).
|
|
20
|
-
- **If less than 5/5:** the plan must include the frontend and/or backend observability changes that would make the next occurrence
|
|
20
|
+
- **If less than 5/5:** the plan must include the frontend and/or backend observability changes that would make the next occurrence's root cause directly visible in artifacts (the artifact half of 5/5; reaching 5/5 additionally requires reproduction per [Causal Chain](#causal-chain)). Scope recommendations to the repositories and services on the causal chain; resolve owners via the groundtruth registry rather than assuming the failure belongs to the repo the test lives in.
|
|
21
21
|
- **If confidence is 2 or below:** do not propose a code fix. Instead, recommend specific instrumentation or reproduction steps to raise confidence.
|
|
22
22
|
|
|
23
|
+
## Causal Chain
|
|
24
|
+
|
|
25
|
+
Every plan must trace the failure to a terminal _cause_, not a symptom:
|
|
26
|
+
|
|
27
|
+
failing assertion โ app/UI state โ network/trace/log evidence โ owning service and repo โ cause at a file/line, config key, or specific log line.
|
|
28
|
+
|
|
29
|
+
- A status code, timeout, or throttle is a link in the chain, never the terminus. "The request 500ed" or "setup was throttled" is where the investigation continues, not where it stops.
|
|
30
|
+
- The link types adapt to the failure surface. CI/setup, fixture, component, and unit failures substitute build logs, fixture state, or runner artifacts for network evidence, and the owning package/repo for a deployed service. The invariant is the terminus โ a cause, not a symptom โ not the specific link types.
|
|
31
|
+
- When a network request or deployed service is implicated, resolve its owning service and repo via the groundtruth ownership registry (`ClipboardHealth/groundtruth`: `registry/services.json` โ `registry/repos.json`; per-repo context in `context/devin-wiki/<repo>/`). Follow the chain into that repo's code โ do not stop at the repo the test lives in.
|
|
32
|
+
- When the causal event may be outside the test's own request path (seeding, deploys, CDC lag, async jobs), trace-ID lookup cannot reach it. Use time-window log queries scoped to the run instead.
|
|
33
|
+
- If evidence runs out, state exactly which link breaks and what observability would extend it. That caps confidence at 2, and the instrumentation becomes the deliverable.
|
|
34
|
+
|
|
23
35
|
## Decide Fix Approach
|
|
24
36
|
|
|
25
37
|
Applies to all test types.
|
|
@@ -84,9 +96,10 @@ Produce the plan with these fields:
|
|
|
84
96
|
- **Current main status:** whether the failing commit's code path still exists on current `main`, has already been fixed, or has changed enough that the plan must be adjusted
|
|
85
97
|
- **Symptom:** what failed and where
|
|
86
98
|
- **Root cause:** concise technical explanation
|
|
99
|
+
- **Causal chain:** each link from failing assertion to terminal cause with its evidence, or the explicit break point and the observability that would extend it (see [Causal Chain](#causal-chain))
|
|
87
100
|
- **Evidence:** artifacts supporting the diagnosis (traces, network, error messages, screenshots as applicable)
|
|
88
101
|
- **Proposed fix:** test harness, product, or both โ with the specific file(s) and the change you would make
|
|
89
|
-
- **Observability to reach 5/5:** required when confidence is less than 5/5. List the frontend and/or backend telemetry, logging, tracing, reporter, or metric changes that would make this flake
|
|
102
|
+
- **Observability to reach 5/5:** required when confidence is less than 5/5. List the frontend and/or backend telemetry, logging, tracing, reporter, or metric changes that would make this flake's root cause directly visible in artifacts next time (reproduction then completes 5/5). Include another repository only when the evidence implicates it. Use "N/A -- confidence is 5/5" only for a 5/5 plan.
|
|
90
103
|
- **Sibling candidates:** files that appear to share the same anti-pattern, for the reviewer (or fix.md) to confirm. Or "N/A -- fix is test-specific" if the issue is one-off (see [`fix.md`](./fix.md) for what counts as a structural anti-pattern worth searching for).
|
|
91
104
|
- **Validation plan:** lint/typecheck commands and test commands to run after applying the fix
|
|
92
105
|
- **Open questions:** anything that needs human input before fixing
|