SDK Evidence Traceability and Integrity
Tracker references: pm-f86lth, pm-cstuys, pm-jb1ron, pm-2irc1p, pm-u5c27w, and pm-blvfye.
This contract turns linked evidence into a bidirectional context primitive. Items can continue to declare the files that explain their implementation, while agents and packages can resolve a source path back to its owning work without scanning tracker files at indexed scale.
Reverse source lookup
Use pm files lookup with one or more project-relative or absolute paths:
pm files lookup src/sdk/files.ts
pm files lookup src/sdk/files.ts docs/SDK_EVIDENCE_TRACEABILITY.md --limit 20
pm files lookup /absolute/project/src/sdk/files.ts --scope project --strict-read --json
pm files lookup src/sdk/files.ts --explain
pm files lookup src/sdk/files.ts --lines 650:720 --decision-depth 12 --json
The command normalizes in-project absolute paths to project-relative paths, deduplicates targets, and returns referencing items in deterministic priority, update-time, and ID order. The default result limit is 50. Use --offset for bounded pagination or --no-truncate for an authoritative unbounded source scan.
Every response includes:
paths,total,count,offset,limit,has_more, andtruncated;- a compact item identity plus only the linked-file records that matched;
completeness.statusasunchecked,complete, orpartial;completeness.sourceasindexorsource_scan; and- non-fatal source-read
warningswhen completeness is partial.
--strict-read fails instead of returning partial source-scan results. Indexed reads are intentionally reported as unchecked: they are cursor-bound projections optimized for bounded context retrieval, while strict reads force authoritative item loading.
Explain why source exists
--explain upgrades reverse lookup from an ownership list to a bounded context
projection. Every match adds:
- its linked-file evidence and compact
value,why_now,outcome, andobjectiverationale; - the shortest typed relationship path to a governing Decision, including inverse edge names when traversal crosses an edge backwards;
- a deterministic relevance score used before normal priority, update-time, and id tie-breakers; and
- explicit ambiguity codes when Git attribution is unavailable, selected lines have no mapped commit, no governing Decision is reachable, or several equally short Decisions exist.
--lines start:end is an inclusive, one-based selector that implies
--explain and accepts exactly one path. It runs bounded git blame and a
256-commit path log. A blamed commit contributes only when its commit message
contains the exact pm item id, so Git history supplements linked tracker
evidence without inventing lineage. Git failures are non-fatal and appear as
ambiguity rather than silently claiming attribution. --decision-depth is
bounded from 1 through 32 and defaults to 8.
The top-level traceability_receipt reports the requested range, blamed,
mapped, and unmapped commit counts, and effective decision depth. Explained
lookups use an authoritative source scan because a compact metadata index does
not contain the rationale and graph fields required to support the answer.
SDK and MCP
Linked-test metadata edits provide a public SDK operation for correcting one test while retaining its position, original provenance and immutable history, with matching CLI and MCP action options.
The public SDK exposes both reusable-client and one-shot forms:
import { PmClient, filesLookup } from "@unbrained/pm-cli/sdk";
const client = new PmClient({ cwd: process.cwd() });
const fromClient = await client.filesLookup({
paths: ["src/sdk/files.ts"],
limit: 20,
explain: true,
lineRange: { start: 650, end: 720 },
decisionDepth: 12,
});
const oneShot = await filesLookup(
{ paths: ["docs/SDK_EVIDENCE_TRACEABILITY.md"], strictRead: true },
{ cwd: process.cwd() },
);
The MCP files action uses the same primitive when lookupPath is present and
accepts explain, lines, and decisionDepth. The dedicated files_lookup
tool exposes the same fields. id remains required for item-local add, remove,
discover, and list operations; reverse lookup instead requires one or more
lookupPath values. Use pm contracts --command files --flags-only --json for
the active machine contract.
SDK hosts that manage authoritative item writes directly can use queryLinkedFileMetadataIndex from the public item-metadata-index surface. The reverse projection is rebuilt from linked-file collections and updated in the same derived-index writer section as normal metadata deltas. A missing, stale, corrupt, or extension-incompatible index must fall back to authoritative reads.
Atomic evidence replacement
pm update and pm update-many support atomic replacement for files and docs, matching the established dependency and test contracts:
pm update <id> \
--file path=src/new.ts,scope=project,note="current implementation" \
--replace-files \
--doc path=docs/new.md,scope=project,note="current contract" \
--replace-docs
Replacement requires at least one corresponding --file or --doc value and cannot be combined with its clear flag. Validation occurs before mutation, so invalid replacement requests do not partially clear evidence. Ownership bypasses continue to reject replacement operations.
Repeating an already-present pm files --add or pm docs --add batch is a true no-op: changed is false, the item file is not rewritten, and append-only history receives no synthetic mutation entry.
An explicit non-empty replacement note updates the existing path/scope entry
atomically. A bare-path retry preserves its note; a different scope identifies
a separate link. The same rule applies to glob additions and standalone
--note. Migration collisions first retain the established last matching
entry; an explicit note revision then applies to that surviving identity.
This fixes pm-zqxlfs:
pm files <id> --add path=src/new.ts,note="verified current implementation"
pm docs <id> --add docs/new.md --note "verified current contract"
Audited history redaction participates in the same projection transaction as ordinary item mutation. After rewriting an item and its history stream, pm invalidates drift verification state and incrementally refreshes the metadata index before releasing the derived-index lock. A warmed index therefore cannot pair pre-redaction item content with post-redaction history during validation.
Compact Plan mutation receipts
Tracked by pm-hqy7lr.
CLI and MCP Plan mutations return identity, action, step identity when available,
complete step counts, materialization/skip/warning counts, and an inspection
command. They omit bodies, resume context, and unrelated steps, so a single-step
update does not grow with the Plan. pm plan show <id> --depth deep retrieves
the complete current Plan without repeating a mutation. The omission receipt
explicitly distinguishes this acknowledgement from a full read.
Local CLI/SDK recovery commands include the resolved --pm-path, safely quoted,
so they inspect the same tracker even with a non-default root. MCP receipts
omit the server-resolved filesystem root in both compact and full output.
For MCP recovery, call pm_plan with subcommand: "show", depth: "deep",
the receipt ID, and the original request's workspace selection (path or cwd).
SDK runPlan retains its full typed result and adds mutation_receipt for
consumers that need a compact acknowledgement. Existing full transport output
is available with CLI --full-changed-fields or MCP fullChangedFields: true.
The named PlanMutationReceipt type is exported from @unbrained/pm-cli/sdk.
CLI --no-changed-fields also selects a compact Plan receipt.
Read-only plan show retains its existing projection behavior.
Operational receipts
Linked tests recognize compound acquisition failures such as “could not acquire … lock” together with contention context such as “already running” or “held by another” as infra_collision. Generic assertion text mentioning a lock or timeout remains assertion_failure, preventing false infrastructure classifications. A command refused by clone-local provenance policy is classified separately as trust_refusal, so reports do not misstate a pre-execution safety decision as an assertion failure.
Telemetry flush receipts distinguish progress from completion:
queue_entries_drainedis the exact valid-entry delta;queue_progressedmeans at least one entry was removed;queue_emptymeans no valid entries remain; and- compatibility field
queue_drainedis equivalent toqueue_empty, never merely “the queue got smaller.”
Packages should use queue_empty when a workflow requires complete delivery and queue_progressed when partial forward progress is sufficient.
Duplicate similarity treats the complete external issue code as identity. Codes
such as BD-30-A and BD-30-B are distinct sibling work and receive only their
ordinary title-token similarity; exact repetitions of the full code retain the
strong issue_code signal. This keeps duplicate-close guidance from collapsing
decomposed work that shares a numeric family prefix.
Metadata validation applies a separate, evidence-backed title classifier.
Upper-case prefixes remain conventional issue codes. Mixed-case prefixes must
have a code delimiter, an explicit body marker/backtick reference, or match the
configured item-id prefix. Natural-language compounds such as Match-3,
Covid-19, and Wi-Fi-6 therefore do not produce dishonest rename-or-merge
warnings, while GH-1118, Bug-12: ..., and configured formats remain
detectable without an ever-growing word dictionary.
De docs/SDK_EVIDENCE_TRACEABILITY.md en pm 2026.11.13. Ver en GitHub