Testing

This page describes safe local tests, linked tests, coverage, and release-readiness checks.

Tracked implementation updates: pm-52eh, pm-mcxr, pm-u42x, pm-atfm, pm-xmp5, pm-39cqqx, pm-5cgm2z, pm-avv3wx, pm-rizqb6, pm-95h7pg, pm-giks4s, pm-xa3t0o, pm-e97jyf, pm-efkvdy, pm-ed28wi, and pm-5ug5xq.

Agent Quick Context

  • Unit and integration tests must not read or write real .agents/pm data.
  • Prefer node scripts/run-tests.mjs ... because it creates sandboxed PM_PATH and PM_GLOBAL_PATH.
  • Linked-test execution injects isolated PM_PATH and PM_GLOBAL_PATH for every command and applies stored-command provenance checks before process creation. Direct runners are accepted; prefer node scripts/run-tests.mjs ... when the repository provides it because the wrapper also reproduces build, coverage, and cleanup policy.
  • Run linked tests before closing the item that owns the work.

Tracked documentation work: pm-u9d0.

Local/hosted gate parity is tracked by pm-ei6x66.

Standard Local Checks

pnpm build
pnpm lint
pnpm typecheck
node scripts/run-tests.mjs test
node scripts/run-tests.mjs coverage

For the exact ordered local preflight used to make release-readiness claims, run the registry-owned entrypoint:

pnpm verify:preflight

scripts/release/gate-registry.json is the executable plan for this command: each ordered step declares its command, arguments, environment, capture mode, and whether an explicit skip flag is permitted. Receipts distinguish passed steps from declared skips, and quality:gate-registry maps hosted workflow claims to the same canonical gate IDs. Hosted-only environment isolation and tracker-integrity steps remain explicit entries with reasons rather than silently disappearing from local parity.

node scripts/run-tests.mjs wraps Vitest in temporary tracker roots, disables external Sentry delivery for the build, test workers, and their nested CLI children, then cleans the roots up. Instrumentation tests can still exercise Sentry initialization through their mocked module boundary; ordinary negative fixtures must never create production incidents from a developer host.

Temporary directories must live outside the checkout and outside any ancestor workspace with initialized tracker data. The runner rejects a checkout-local temporary root, including a symlink alias, before starting build or test processes (pm-bukwmy). If the default temporary filesystem is full, set TMPDIR (or TEMP/TMP on Windows) to an existing isolated scratch directory; an ignored directory inside the repository is not isolated. Filesystem fixtures must honor node:os's tmpdir() and remove only the temporary directories they created.

Public SDK changes additionally run semantic surface and import-cost contracts:

pnpm sdk:surface:check
pnpm benchmark:sdk-entrypoints:check
pnpm benchmark:transport:check

The surface gate detects exported signature, type-parameter, declaration-kind, and stable error-code drift across the aggregate and every narrow SDK entrypoint. The performance gates protect entrypoint import cost and one-item CLI cold-start overhead without touching the repository tracker.

pnpm lint and pnpm quality:static are the same canonical local static gate. The gate layers ESLint rules for shipped source, package, plugin, and script surfaces that match the CodeFactor maintainability findings this repo tracks (complexity, no-unsafe-optional-chaining, and the relevant eslint-plugin-unicorn mechanical rules), jscpd duplicate detection across source and tests, and the repo-specific quality:static gate. The dedicated quality:static gate remains authoritative for source/exported docstring coverage, orphan-module checks, directory-load caps, and the TypeScript-aware duplicate/complexity checks that are tailored to pm's source layout; pnpm lint delegates to it instead of running a second threshold profile. It also includes a changed-file CodeFactor-parity complexity scan for shipped source, package, and script files so PR-local CodeFactor maintainability annotations fail locally before commit or push. Existing legacy high-complexity test fixtures are tracked separately and must not be used as precedent for new changed production/script code.

The same required static gate validates an explicit seven-day Dependabot cooldown for every updater and requires both npm and GitHub Actions entries. Missing values, semver overrides outside 7–90 days, invalid YAML, removed updaters, and include/exclude bypasses fail the gate. The maximum follows GitHub's cooldown limits. Security updates retain GitHub's separate security-update behavior. The negative controls are tracked by pm-gkut and pm-dmo5.

Release synchronization and commit staging share one distribution manifest inventory. The pm-t4prek regression bumps versions in a temporary Git repository and reads the resulting commit to verify workspace versions and exact plugin runtime pins. The pipeline checks version consistency immediately before staging, including required string versions and runtime pins in both plugin package manifests; tests of a prepared working tree alone cannot establish that the release commit contains those changes.

lint:duplicates runs three zero-clone profiles: the broad repository profile, the production cross-format profile, and a supplemental long-table profile at 28 lines / 80 tokens. The last profile detects the historical GH-508 normalizer tables below the other profiles' token floors; it does not replace their shorter line thresholds. Its real detector regression rejects the historical table rows and accepts a shared declaration. The earlier 12-line / 60-token exploratory census informed calibration, but is not the enforced profile. These bounded profiles do not claim complete equivalence with hosted analyzers. See pm-xspd for calibration evidence.

The local parity rules catch analyzer classes before push. The mandatory hosted proof runs after the final commit is pushed and both apps have finished:

pnpm quality:hosted-analysis

This command reads commit-scoped GitHub results for git rev-parse HEAD. It passes only when DeepScan explicitly reports 0 new issues and CodeFactor completes successfully with No issues found. The exact commit is authoritative. For GitHub merge and squash commits whose apps report only on the reviewed PR head, the gate accepts that evidence only after proving the source and target have the same immutable Git tree. Squash commits also require one unambiguous GitHub PR association to a closed PR merged into main. Missing, pending, failed, skipped, stale, ambiguous, and different-tree results all fail. pnpm release:gates includes the same non-skippable verification, so run it only after the pushed reviewed head's hosted analyzers are terminal.

Focused Test Runs

node scripts/run-tests.mjs test -- tests/unit/output.spec.ts
node scripts/run-tests.mjs test -- tests/integration/cli.integration.spec.ts

Use focused runs while iterating, then run coverage before closure when risk or scope warrants it.

CI Retry and Timeout Diagnostics

Platform regressions from pm-hrhfgi and pm-zk67yf have portable negative controls. Complete source scans process at most 32 item files per batch; the descriptor pressure fixture fails unbounded reads while requiring genuine permission failures to remain visible. The 10,000-item aggregation fixture separately verifies completeness before pagination. Git fixtures that assert exact bytes declare repository-local core.autocrlf=false and core.eol=lf so host defaults cannot change the restoration target. Send generated shell scripts through stdin (bash -s) so their size cannot exceed Windows command-line limits. Runtime compaction is tested through a real directory alias as well as its physical path, including original source mapping and repeated-compaction byte stability. These tests run in the full suite on the Nightly Validation platform matrix.

CI retains the 30-second per-test timeout and retries one failed attempt. A test that passes only on retry is reported as flaky rather than silently folded into the pass count; a persistent assertion still fails after the bounded retry. Local runs do not retry, so deterministic failures stay immediate while iterating.

Vitest's GitHub reporter emits annotations and retry evidence. The repository reliability reporter additionally writes .vitest-reports/reliability-<shard>.json and appends a job-summary table with the test identity, file, duration, effective timeout, retry count, shard, and failure detail. Tests completing at or above 80% of their timeout are recorded as at-risk before load turns them into timeouts. Coverage shards upload this JSON beside their blob report, so recurrence can be measured without decoding the coverage artifact or re-reading raw logs.

PM_TEST_SHARD supplies a stable shard identity and PM_TEST_RELIABILITY_REPORT_DIR can redirect the JSON report for an isolated harness. These variables affect diagnostics only; they do not change test selection, retry count, timeout, or verdicts.

Coverage Governance

Coverage gating now targets literal all-source coverage across runtime code families:

  • vitest.config.ts includes canonical authoring sources across src, packages (.ts), scripts, plugins, and docs/examples.
  • Generated package JavaScript mirrors are not separately gated; coverage is enforced on their TypeScript sources.
  • Thresholds are strict 100/100/100/100 for lines, branches, functions, and statements.
  • Avoid reintroducing curated coverage allowlists; keep the full all-source corpus measurable and gated.
  • Prefer extending existing test files and shared helpers so new coverage remains fast and non-duplicative.
  • Prefer extracting deterministic pure helpers (and unit-testing them) when an orchestration-heavy file is difficult to cover directly.

Static quality also enforces source documentation coverage through pnpm quality:static: every src/**/*.ts source file needs a module TSDoc block, every exported declaration needs a non-module TSDoc block, and known generated boilerplate summaries are rejected.

Test Strength and Documentation Content

The required static gate also runs SDK mutation testing and the documentation content ratchet, tracked by pm-zclzll and pm-dvwm. These add behavioral and content checks while retaining exact 100/100/100/100 coverage and all docstring floors.

TOON Storage Round-Trip Gate

History-only lifecycle reconstruction and recovery contracts are described in History durability and recovery. Their integration suite is part of the required all-source test run and compares historical projections against independently captured item files, including after removing those files.

TOON item serialization is a fail-closed storage boundary. Before returning bytes to any create, update, merge, migration, or package caller, pm decodes the new @toon-format/toon output and compares it with the JSON-like canonical payload. A decode failure or the first field-level mismatch raises item_document_roundtrip_failed; no item bytes are written.

The property suite exercises generated and adversarial agent text, including array-header spellings, colons, quotes, backslashes, newlines, Unicode, comment prefixes, and bracketed endpoint-shaped strings:

node scripts/run-tests.mjs test -- tests/fuzz/project-boundaries.fuzz.spec.ts

Major codec upgrades additionally require a complete read/serialize/read sweep over every tracked .toon item, strict history and storage validation, the packed npx consumer smoke, and Bun SDK/bunx execution. A dependency-only green unit suite is not sufficient evidence for changing the canonical storage codec.

Directory-load cap and the tests/unit split

pnpm quality:static also caps each directory under src/, tests/, and packages/ at 120 .ts files (--max-files-per-dir, default 120). This keeps any single directory navigable and forces load to be partitioned by area rather than piling into one folder. tests/unit/ is therefore split into per-area subdirectories (tests/unit/commands/, tests/unit/core/, tests/unit/cli/, tests/unit/mcp/, tests/unit/extensions/, …) instead of a single flat directory.

When adding a unit test, place it in the matching tests/unit/<area>/ subdirectory (or merge into an existing spec there); never add a file directly to tests/unit/. The static-quality-gate directory-load contract test asserts the live repository stays at or below the cap and that the magic number matches the gate default, so drift is caught before CI's static gate fails.

Search Quality Evaluation

search-advanced exposes an advisory golden-query harness for relevance drift checks.

Fixture source:

  • tests/search-eval/golden-queries.json

Local run:

pm package install search-advanced --project
pm reindex --mode keyword --eval --eval-fixtures tests/search-eval/golden-queries.json --json

Fixture authoring notes:

  • Each fixture must include query, expected_top_ids, and optionally mode (keyword|semantic|hybrid) and min_ndcg_at_5 (0..1).
  • Keep expected IDs deterministic and scoped to stable seed data so CI does not flap.
  • Add new fixtures for regressions before tuning search defaults.

The repository-native pm eval corpus is a required CI and release gate:

pnpm build
pnpm quality:retrieval-eval

tests/search-eval/retrieval-gate-baseline.json enforces query count, nDCG, MRR, precision, and recall. The corpus includes at least one intentionally non-saturated judgment set so recall regressions remain observable. The required context-quality command also runs an impossible perfect-score negative control and fails if pm eval --fail-under stops returning a non-zero exit. Refresh the baseline only with pnpm quality:retrieval-eval:update after reviewing query-level ranking changes.

Context Quality Evaluation

The required context relevance gate proves that pm context and pm next assemble the right bounded working set, not only that search returns relevant documents.

Fixture and baseline sources:

  • tests/context-eval/golden-scenarios.json — reviewable scratch, real-shaped, synthetic-scale, and returning-agent continuity judgments.
  • tests/context-eval/baseline.json — committed aggregate and per-scenario metrics from the accepted structural/scorer behavior.

Run the required gate locally:

pnpm build
pnpm quality:context-eval

The gate creates isolated temporary trackers through PmClient, reads them only through the public context() / next() SDK primitives, and reports nDCG, reciprocal rank, required-item recall, continuity coverage, token-budget adherence, and served-item signal attribution. It fails when an explicit corpus threshold is missed or any aggregate metric regresses below the committed baseline.

Benchmark and evaluation populations that need realistic project structure should use the public SDK shapes documented in Portable Corpus Shapes. pnpm benchmark:corpus-shapes remeasures the same SDK operations across equal-count scratch and representative populations and records their measured profiles.

When a deliberate ranking change improves or intentionally redefines the golden judgments, review the scenario-level diff first, then refresh the baseline:

pnpm quality:context-eval -- --update
pnpm quality:context-eval

Do not update the baseline merely to make CI green. Change judgments and rationales in the corpus when product intent changes, and commit the corpus, baseline, scorer tests, and SDK documentation together.

Context-intent classification has a separate calibration receipt and one manifest-backed recovery spelling:

pnpm context:intent:calibrate
pnpm context:intent:calibrate --update

The gate verifies that package.json exposes that exact script before it reads or refreshes scripts/release/context-intent-calibration.json. A missing or renamed script therefore fails with the same command contributors are told to run, and pnpm forwards --update to the calibration gate.

Hosted Gate Registry

Tracked by pm-k6t4yb and pm-b2hc4x.

Every workflow job is discovered by its stable workflow-file#job-id identity and matched exactly against scripts/release/gate-registry.json; human-facing step names never define the inventory. Each registry entry declares:

  • a canonical pm owner;
  • the enforced workflow jobs it participates in;
  • actionable failure taxonomy;
  • explicit bypass policy and audit rationale;
  • an executable negative-control test and assertion.

Run the fail-closed inventory locally:

pnpm quality:gate-registry
node scripts/release/gate-registry.mjs --inventory

pnpm quality:static includes the registry. A new workflow job fails until it is declared under at least one canonical gate, and a removed or renamed job id fails until stale policy is reconciled. Display-name edits do not mutate gate identity. Public source claims are mapped to exact evidence strings and an enforced registry entry so documentation cannot silently advertise advisory behavior. The inventory output lists registry-derived registered job IDs beside the parsed workflow_jobs; validation requires the two sets to match exactly.

Tracker Context-Quality Ratchets

Tracked by pm-ips23h, pm-kpftft, and pm-4ok4ex, with lifecycle-stable outcome reachability owned by pm-g4k74y and pm-bzmeaa.

The SDK-owned assurance registry stores tracker context-quality measurements, floors, ceilings, lifetimes, enforcement, and executable negative controls in .agents/pm/assurance.json. The tracker-context-quality gate covers stored relationship kinds, validator debt, health checks, graph findings, structural cut points, and typed reachability to outcome milestones. One workspace assurance context reuses identical graph, validate, and health evaluations, so a broad gate has one authoritative snapshot without repeatedly rescanning it. Outcome enforcement uses an all-status reachable population, unreachable ceiling, and basis-point floor. Active and terminal populations remain diagnostics: absolute per-lifecycle floors would mistake normal close or reopen transitions for relationship loss.

Run the same gate used by hosted CI:

pnpm quality:tracker-measurements
pm assurance run tracker-context-quality --trigger ci --dry-run --json

Every native assertion contains both a passing boundary case and an impossible case that must fail. Changes flow through pm assurance put, which refuses a weaker bound, scope, lifetime, or enforcement unless a verified Decision item authorizes it. scripts/release/gate-registry.json separately inventories the retired bespoke gate and gives every graph subcommand either a named automated consumer or an explicit interactive-only classification.

Agent Output Token Budgets

Run the required PR gate locally:

pnpm build
pnpm quality:token-budget

The isolated fixture contains a medium-scale linked workspace. Discovery surfaces (--help and contract projections) use reviewable ratcheted byte baselines. Answer surfaces including activity, deps, graph, duplicates, events, health, list, get, context, next, search, and validate are measured against their live SDK command contracts. A deliberately full, unbounded activity query must exceed the default contract, proving the gate can fail when a default becomes accidentally unbounded.

Refresh scripts/release/token-budgets.json only for an intentional discovery surface change:

node scripts/release/token-budget-gate.mjs --update
pnpm quality:token-budget

The manifest records baseline bytes and estimated tokens for visible review deltas. Updating it cannot raise answer ceilings, which remain owned by PM_COMMAND_OUTPUT_BUDGET_CONTRACTS.

Diagnostic ceilings share the executable refusal gate:

pnpm quality:recovery-closure

The gate replays 117 refusal contracts: 18 closed-domain rows, 88 grammar-derived required-argument omissions, seven closed positional-action families, and four tracker-preflight states. It also ratchets ten representative failure paths against PM_DIAGNOSTIC_OUTPUT_BUDGET_CONTRACTS. Every diagnostic must fit its declared JSON ceiling and preserve a mechanically actionable correction; executable retry argv is never collection-truncated. The missing-probe negative control and the authoritative tracker-state snapshot prove that the corpus cannot silently shrink or turn a refusal into a mutation.

The gate starts every fixture command from a closed environment allowlist. It retains only declared process-portability inputs such as PATH, temporary and home roots, and Windows process-launch variables, then supplies fixed locale, timezone, author, telemetry, and isolated tracker settings. Undeclared host values cannot reach measured output, including future harness variables that the descriptor registry does not yet know about.

Linked Tests

Add tests to the item that owns the work:

pm test <item-id> --add command="node scripts/run-tests.mjs test -- tests/unit/output.spec.ts",timeout_seconds=240
pm test <item-id> --run --progress

For broader sweeps:

pm test-all --status in_progress --progress

Do not link pm test-all itself as an item-level test command. It creates recursive orchestration. Use --fail-on-empty-test-run for release/readiness gates where selecting zero linked tests should fail instead of producing an inconclusive pass. Use --progress for long foreground sweeps; it prints parent-level pm test-all selection, per-item start/end, and final summary lines in addition to the linked-test command progress emitted by pm test.

Package Ecosystem Smoke

After pnpm build, external package compatibility can be checked without touching the repository tracker:

pnpm smoke:external-packages -- --limit 10
pnpm smoke:external-packages -- --package pm-changelog

The harness creates one temporary project per package, sets sandboxed PM_PATH and PM_GLOBAL_PATH, installs the package with pm install npm:<name> --project, runs pm package doctor --project --detail deep --trace, and probes runtime contracts with pm contracts --runtime-only --availability-only. Use --discover-only for the npm package list and --keep-temp only when debugging a failing package root.

PM Context Modes

Linked PM commands default to schema context: settings and extensions are seeded, but tracker item data stays isolated. When a linked command is a PM tracker-read such as pm validate, the default mismatch error suggests --auto-pm-context, which keeps schema isolation for ordinary commands and routes only tracker-read PM commands through seeded tracker data.

The runner resolves every selected command's effective context before it creates temporary sandboxes. Runs whose effective context is schema initialize only their schema roots; a non-PM command explicitly configured with pm_context_mode: "tracker" still requires tracker data. Tracker roots and item data are materialized only when at least one selected command requires tracker context. This preserves source isolation without copying an unrelated tracker into constrained temporary storage. Capacity, permission, and resource failures while seeding a required tracker surface as typed, path-redacted host-environment refusals with recovery steps. When a legacy source tracker has settings but no _workspace history, tracker mode creates the sandbox's initial audited settings snapshot from the exact source bytes. Existing source workspace history is copied unchanged, including real drift, so linked validation never masks a source integrity failure.

Source Workspace Modes

Linked tests have a separate source-workspace contract. Store a default on one entry with workspace_context_mode, or choose a run-level mode with --workspace-context:

pm test <item-id> --add-json '{"command":"pnpm quality:static","workspace_context_mode":"isolated"}'
pm test <item-id> --run --workspace-context snapshot --override-linked-workspace-context
  • source (default) runs in the source checkout and exposes its read-only source-context environment, preserving existing linked-test behavior.
  • isolated runs from an empty disposable directory and removes PM_SOURCE_WORKSPACE_ROOT, PM_SOURCE_PM_PATH, and the source-context access declaration. Use it only for commands that do not require checkout files.
  • snapshot copies the workspace into the linked-test sandbox, runs from that copy, and binds its .agents/pm path to the selected temporary tracker. .git, .agents, node_modules, coverage output, and common cache directories are excluded at every directory depth; an existing top-level node_modules is linked read-only by convention. Built output remains available so linked commands such as node dist/cli.js keep working. Writes therefore land in the disposable snapshot rather than the source checkout.

Every result reports the requested/effective workspace mode, working directory, exposed source root, and trust decision. Recorded test_runs retain the effective workspace mode and trust reason beside the command.

Linked-Test Command Trust

Linked commands are stored shell programs, so merge-unioned tracker data is an execution boundary. New command entries record author, creation time, source branch when available, and whether the item merge driver introduced the entry. Locally created commands keep their previous run behavior. Commands marked as merge-unioned or carrying a different source ref fail before process creation. Malformed provenance is sanitized to the additive provenance_invalid marker and receives the same fail-closed treatment; it is never normalized into a trusted legacy command. These pre-execution refusals use the trust_refusal failure category, separate from command or assertion failures.

Command-string shape is intentionally not treated as a security boundary. Direct node --test, Vitest, package-manager, shell-wrapped, and non-Node runners are accepted consistently because the runtime injects tracker isolation for all of them. classifyLinkedTestCommandSafety exposes the same SDK policy to package hosts and returns advisory runner classification; provenance review and acknowledgment remain the execution trust boundary.

Choose one explicit recovery:

# Review and trust the item's current command fingerprints in this clone.
pm test <item-id> --acknowledge-linked-tests

# Or permit a single reviewed run. Both controls are required.
pm config project set untrusted-linked-test-execution enabled
pm test <item-id> --run --allow-untrusted-linked-tests

Acknowledgments live in the clone-local ignored runtime directory and bind to the full command, tracker/workspace context, environment controls, host-safety mode, and provenance fingerprint; editing any of those fields requires a new review. Enabling the project policy alone never executes an untrusted command, and the per-run flag alone is also refused. Inspect all unacknowledged entries without executing them with:

pm validate --check-command-references --verbose-diagnostics

Use explicit modes when needed:

pm test <item-id> --run --pm-context schema
pm test <item-id> --run --pm-context tracker
pm test <item-id> --run --pm-context auto --check-context --auto-pm-context

For complex linked-test commands, prefer JSON input so shell syntax survives unchanged:

pm test <item-id> --add-json '{"command":"node scripts/run-tests.mjs test -- tests/unit/output.spec.ts","timeout_seconds":240}'

To rerun a focused subset without editing linked-test metadata:

pm test <item-id> --run --match output
pm test <item-id> --run --only-index 2
pm test <item-id> --run --only-last

Linked-command stdout and stderr are captured through temporary regular files, then read back with the 20 MiB per-stream retention bound. This keeps inherited descriptors blocking for Bun, Rust, and other runtimes that treat EAGAIN on a non-blocking stdout pipe as fatal. Output beyond the bound is drained to disk, the child still completes normally, and the result records a truncation notice instead of misclassifying a transport failure as a test assertion.

Strict governance flags:

pm test <item-id> --run \
  --fail-on-context-mismatch \
  --fail-on-skipped \
  --fail-on-empty-test-run \
  --require-assertions-for-pm

Structured quantitative evidence can be recorded and queried without parsing logs or comments:

pm test <item-id> --run \
  --measure coverage=100,unit=percent,threshold=100 \
  --measure p95_latency=42,unit=ms,threshold=50
pm test <item-id> --metric-below coverage=100 --metric-diff p95_latency

Measurements are stored on the producing test_runs row, retained with the bounded run history, and exposed consistently by CLI, SDK, MCP, and contracts. Each recorded row also keeps a bounded executions list with the exact linked command, requested/effective pm_context_mode, effective workspace mode, and trust reason, so tracker-backed verification remains attributable after the transient process logs are gone.

Linked-Test Assertions

Linked tests can include assertion metadata:

pm test <item-id> --add \
  command="pm list --status open --json",timeout_seconds=120,assert_json_field_gte=count:0

Common assertion keys include:

  • assert_stdout_contains
  • assert_stdout_regex
  • assert_stderr_contains
  • assert_stderr_regex
  • assert_stdout_min_lines
  • assert_json_field_equals
  • assert_json_field_gte

Background Runs

pm test <item-id> --run --background
pm test-all --status in_progress --background
pm test-runs
pm test-runs status <run-id>
pm test-runs logs <run-id> --tail 100
pm test-runs stop <run-id>
pm test-runs resume <run-id>

Background run fingerprints prevent duplicate parallel runs for the same linked-test set. For long test-all runs, pm test-runs status <run-id> --json includes the latest aggregate item coordinates (item_index, item_total, item_id) plus linked-test coordinates and current_command when the child emits progress. Use pm test-runs logs <run-id> --stream stderr only when the compact status message is not enough.

The bundled pm-linked-test-adapters package is the first-party package exemplar for background run management. Install it in an isolated project when validating package-provided test-run surfaces:

pm package install linked-test-adapters --project
pm package doctor --project --detail deep --trace
pm test-runs list --json

The package activates the test-runs command family and keeps subprocess handling behind an explicit package permission declaration, so it is a useful smoke target for package, permission, and command-contract changes.

Release-Readiness Checks

For substantial changes:

pnpm build
pnpm typecheck
node scripts/run-tests.mjs coverage
pm validate --check-resolution --check-history-drift
pm health --check-only

When release readiness requires external GitHub security telemetry in addition to local checks, run:

gh issue list --state open --limit 100 --json number,title,updatedAt,url
gh pr list --state open --limit 50 --json number,title,headRefName,reviewDecision,url
gh api "repos/unbraind/pm-cli/dependabot/alerts?state=open&per_page=100"
gh api "repos/unbraind/pm-cli/secret-scanning/alerts?state=open&per_page=100"
gh api "repos/unbraind/pm-cli/code-scanning/alerts?state=open&per_page=100"

code-scanning/alerts can return 404 no analysis found until at least one CodeQL run has completed.

For documentation-only changes, at minimum run:

pnpm build
rg -n "forbidden-private-token-or-path" README.md docs

Replace the placeholder pattern with the actual sensitive term being guarded in the current task.

Contract Snapshot Gate

Tracked by pm-d6kq.

pm contracts --full --json is a public machine-readable SDK and agent surface. Keep its committed golden snapshot current when command contracts, schemas, aliases, or extension-provided command contracts intentionally change:

pnpm build
pnpm contracts:update
pnpm contracts:check

CI runs pnpm contracts:check in the static gate. Snapshot diffs should be reviewed like an API change and paired with the package-owned changelog flow when the contract surface changes intentionally.

The agent-facing output-size gate is separate from schema drift. Run pnpm quality:token-surface after changing help, contracts, or MCP tool registration. It measures root help, every advertised command help page, the summary/default/full contracts family, and MCP tools/list against scripts/agent-token-surface-baseline.json. Use pnpm quality:token-surface:update only for an intentional reviewed change; the baseline stores explicit byte ceilings with headroom rather than volatile timestamps or package versions.

The CLI contract snapshot is separate from the TypeScript SDK surface snapshot. When public SDK declarations or SDK error codes change, also run:

pnpm sdk:surface:check

Use pnpm sdk:surface:update only for reviewed additive changes. Breaking changes require the explicit --acknowledge-breaking "<release rationale>" argument documented in SDK.


Testing remote
Report an issue