ci/runbook.md
Use this runbook when Test Optimization breaks a customer's JavaScript tests or sends no test data.
The validator answers two separate questions:
dd-trace report one real project test when initialized correctly?It also checks Early Flake Detection, Auto Test Retries, and Test Management when Basic Reporting succeeds.
Recommended agent prompt:
From the current repository, resolve
dd-traceonly withnode -p "require.resolve('dd-trace/package.json', { paths: [process.cwd()] })", then read and execute the adjacentci/runbook.md. Do not search outside this repository. Reading the single resolved package path, including its symlink target, is allowed.
dd-trace; do not search sibling repositories, home
directories, package-manager stores, or unrelated temporary directories.node <repository-contained-runner> <one-test-file>.node <repository-file> test runner; the resulting direct command is shown in the approval plan.This boundary intentionally prefers an incomplete result over interpreting an arbitrary command language.
From the customer repository, resolve the installed package without searching outside the repository. For example:
node -p "require.resolve('dd-trace/package.json', { paths: [process.cwd()] })"
Then run its validator:
node ./node_modules/dd-trace/ci/validate-test-optimization.js --init-manifest
If the manifest already exists, --init-manifest validates it instead of overwriting it. A valid manifest whose
physical repository root matches the current repository can be reused; refresh only its ciWiring evidence before
printing a new plan. If it is invalid or belongs to another repository, the validator identifies the exact manifest
path but does not delete it. Inspect and remove only that file before scaffolding again. Existing approval files and
reports are never deleted to recover from this condition.
The scaffold performs bounded static discovery. For each supported framework, it records:
Live adapters exist for Cucumber, Cypress, Jest, Mocha, Playwright, and Vitest.
The scaffold excludes type declarations and explicit type-test conventions. For Jest, Mocha, and Vitest it prefers
normal *.test.* or *.spec.* files. A non-suffixed file is eligible under a conventional __tests__, spec, test,
or tests directory; a bare test.* file may also directly import the selected framework. If every confident Cypress representative directly
accesses a localhost application, that framework requires setup; discovery does not start the application.
Fallbacks are normal framework-owned files selected during the same bounded discovery. The approval plan displays them in order, and the validator tries one only when an earlier candidate does not pass cleanly. It stops without trying more candidates when the evidence proves a shared prerequisite, such as a blocked browser launch, missing browser runtime, unavailable test runner, or execution-environment restriction that would affect every candidate.
Literal Vitest --project selection is retained only when one project name maps unambiguously to a static,
repository-contained config and test scope. It does not select tests from the broader workspace as a substitute.
Cucumber profiles are expanded statically without loading customer JavaScript. Bounded support imports, hooks, world
parameters, and runtime options are retained; profile feature globs, filters, retries, publishing, and formatters are
removed. Basic and generated checks use one exact feature plus a validator-selected JSON formatter. Dynamic or
ambiguous profiles remain a validator limitation. Cucumber versions before 8 remain static-audit-only because their
CLI cannot bypass an auto-loaded customer profile with a validator-owned configuration; do not change the working
directory or load that profile dynamically to force live validation.
The manifest is data, not an execution plan. Do not edit the scaffolded runner, representative test, generated-test
strategy, or validator settings. Do not add argv, shell commands, package scripts, setup commands, fallback tests, or
wrapper commands. The only agent-edited section is ciWiring. If the scaffold cannot select a direct runner or one
representative file, leave that framework incomplete.
If ciDiscovery.reviewRequired is true, inspect only ciDiscovery.reviewTargets, in order. Stop after identifying one
relevant test job for each runnable framework.
For a repository with multiple selected frameworks, review and record CI evidence independently for each framework. The selected job must belong to that framework's project and resolve to that framework's runner or package script. Never reuse evidence from another framework merely because it is nearby in the same workflow.
Record only inert evidence in that framework's ciWiring:
configFile: absolute path to the CI file;job key and optional literal step;command: only the exact literal command bytes from that job's execution field; put explanations in evidence;workingDirectory: the effective directory, including a statically known provider default;initialization.status and short evidence;transport.mode and short evidence;NODE_OPTIONS, Datadog configuration, operating system, shell, or transport.Set reviewComplete to true only when configuration relevant to initialization, runner invocation, and transport is
resolved. An ordinary Node.js version matrix is not unresolved evidence unless it changes one of those facts.
Record the CI job's actual effective working directory. Never replace a repository-root wrapper's working directory
with the selected framework package merely to make static resolution succeed; leave that wrapper unresolved instead.
Preserve harmless emoji presentation selectors in literal job and step labels; do not remove or rewrite them merely
to satisfy manifest validation. Bidirectional controls and other unsafe invisible characters remain forbidden.
Record initialization and transport independently of command indirection: use not_configured when the selected job
contains no visible dd-trace/ci/init, and none when it declares neither agentless transport nor an Agent. GitHub
repository and organization secrets or variables are not ambient job environment; do not list them as unresolved
unless the workflow explicitly references them. Do not carry evidence from unselected jobs into the selected job.
Do not add generic wrapper-propagation uncertainty when a direct or bounded package-script path already proves that
initialization is absent.
The CI audit is deliberately conservative:
package.json.
Lifecycle scripts are disclosed but are never executed.dd-trace/ci/init in its checksum-bound CI job can
produce NOT CONFIGURED only after the final framework invocation is resolved. When visible initialization or
transport is missing but the runner remains unresolved, those facts are reported independently and the overall CI
conclusion remains incomplete.NODE_OPTIONS reset can produce a confirmed finding.No CI or package command is executed.
Validate the manifest without running project code:
node ./node_modules/dd-trace/ci/validate-test-optimization.js \
--manifest ./dd-test-optimization-validation-manifest.json \
--validate-manifest
Finalize discovery and CI evidence before printing the complete approval plan:
node ./node_modules/dd-trace/ci/validate-test-optimization.js \
--manifest ./dd-test-optimization-validation-manifest.json \
--out ./dd-test-optimization-validation-results \
--print-plan
Before producing a plan for local validation, the validator loads the installed dd-trace/ci/init entrypoint in an
isolated child with tracing disabled. A missing runtime dependency or unloadable installed package stops before
approval and is reported as an installed-package blocker, not a project compatibility problem.
Plan generation also evaluates the recorded CI evidence with the same bounded static analysis used by the final report. Structurally invalid job, step, command, or working-directory evidence is shown as incomplete before approval. This analysis does not execute the CI command, a package script, or project code.
The plan leads with one approval summary: eligible frameworks, required browser or localhost capabilities, mutable paths, cleanup behavior, and the fact that CI is static-only. It then shows every direct runner command, selected and fallback test, prerequisite, working directory, timeout, temporary source, cleanup target, and the final checksum-bound validator command once.
If no selected framework has an eligible local command, --print-plan writes a final static-only report instead of an
empty live approval plan. No new approval artifact or project command is created. Present that report and stop.
Present the complete delimited plan in the next user-facing message. Ask exactly once:
Approve executing exactly the plan above?
Do not run more discovery while waiting. After printing the plan, do not edit the manifest. Any correction or retry requires a fresh plan and fresh approval.
After approval, run only the checksum-bound command printed in the plan. Do not modify it, append an exit-code command, add a pipe or redirection, prefix environment variables, wrap it in a shell, add setup, change permissions, or substitute a package script. Use the agent platform's process result to obtain the exit code.
The live validator creates one fixed single-flight lock in the result directory. An existing lock means another validation may be active or an interrupted run needs inspection. The validator never reclaims it automatically. Remove only that exact lock after confirming no validation process is active, then render and approve a fresh plan.
If the agent platform offers a narrowly scoped native permission for that exact command, request it once. If the platform hard-denies the command, do not retry with a bypass or broader allowlist. Give the exact command to the user to run in a normal project terminal, then interpret the generated report.
The approval JSON records browser_process and localhost_socket as machine-readable required capabilities when the
selected tests need them. These are declarations for the host agent; the validator does not request permissions, start
listeners, or retry in another environment. When the printed plan says browser execution is required, including
browser-backed Cucumber support code, submit the exact checksum-bound validator command through the platform's narrowly
scoped native permission flow after approval.
Do not replace it with a direct browser command or broaden permissions. If browser launch is still denied, report that
exact prerequisite and ask the user to run the unchanged command and SHA from execution-plan.md in a terminal where
the project's normal browser tests already work. Apply the same rule when the selected test's declared localhost
capability is denied.
The validator:
Each framework is independent. A missing browser, runner, build artifact, service, localhost permission, or other prerequisite leaves only that framework incomplete.
Keep these conclusions independent so an incomplete CI audit does not erase a successful local result:
CONFIGURED, NOT CONFIGURED, ACTION REQUIRED, or INCOMPLETE.Use these blocker classes exactly:
PROJECT_SETUP_REQUIRED: a normal dependency, build artifact, application, browser, or runner prerequisite is
missing.EXECUTION_ENVIRONMENT_BLOCKED: the host denied a required browser process or localhost socket.VALIDATOR_LIMITATION: bounded discovery or collection cannot safely select the project test.UNSUPPORTED_VERSION: the installed framework version is outside the supported range.CLEAN_TEST_FAILED: the representative test failed before Datadog initialization and current evidence cannot
attribute the failure more precisely.Then apply the strongest relevant interpretation:
dd-trace can report in this project; fix the identified CI configuration.dd-trace compatibility bug; use the clean confirmation and debug
artifacts for engineering investigation.build/, dist/, or generated output: report PROJECT_SETUP_REQUIRED, name the repository's literal
build script when one exists, and ask the customer to complete that normal build themselves. This classification
still applies when a browser runner starts but reports the missing output from a setup hook. The validator never
executes the build.dd-trace failure.ECONNREFUSED: the project application is unavailable. Start it through
the project's normal setup before creating a fresh plan; the validator does not start it.Advanced checks are useful after Basic Reporting and do not depend on a conclusive CI audit.
Report:
dd-test-optimization-validation-results/report.md.Exit codes are:
0: completed without a confirmed problem;1: completed with a confirmed actionable problem;2: one or more selected checks are incomplete or blocked; completed conclusions remain valid;3: validator implementation or orchestration error.A nonzero exit code does not by itself mean dd-trace is broken. Always include the matching meaning above in the
console summary; in particular, exit 1 is a confirmed actionable finding and is not a validator failure.
report.md is final only when it contains Report state: FINAL. Report state: PENDING means the approved process
started but did not finish; do not summarize per-check conclusions from that file.
After presenting the report, stop. Do not repair evidence, inspect validator internals, or retry without a fresh plan
and approval.