Agent Provenance ADR Amendment

Tracker reference: pm-oskdmu. Implementation lineage: pm-itsjf0, pm-0zcwz6, pm-1zhfls, pm-pwq0g5, and pm-te6elw, with bounded automatic resolution and patch-free historical reads implemented by pm-ffz0a9, pm-v8gfi7, and pm-3yxwv5.

Status: accepted amendment to pm-qwuber. The original stable-author contract remains authoritative; this amendment replaces only its fixed model-only provenance shape.

Decision

Mutation history may retain bounded descriptive agent provenance independently from the stable mutation author. agent_provenance is a string-keyed map whose values are either { value, source } observations or null when a detected harness declares a dimension but cannot expose a value.

The default runtime understands model, effort, role, topic, and version. Harness descriptors and trusted embedded hosts may add dimensions such as topic without a storage migration. The legacy agent_model and agent_model_source fields remain populated from agent_provenance.model for backward-compatible readers.

The precedence for each dimension is:

  1. explicit PM_AGENT_<DIMENSION> override;
  2. the selected harness descriptor's environment keys;
  3. MCP client provenance;
  4. trusted embedding-host provenance;
  5. bounded argv values.
  6. an explicitly declared bounded local resolver.

detectAgentIdentity() and detectHarnessIdentity() use ambient invocation signals when called with no argument. An explicitly supplied signal object remains isolated from ambient state. SDK hosts that need async-safe scoping use runWithHarnessDetectionSignals().

Privacy and security boundary

Provenance values are descriptive context, never authentication or authorization principals. Values are trimmed, length-bounded, and obtained only from literal descriptor keys, trusted caller data, or a named bounded resolver. Detection does not spawn processes, traverse process trees, evaluate user regexes, or access the network. The built-in Claude resolver may read only the tail of the current session's harness-owned JSONL file to recover its recorded model/version. It caps file bytes, lines, and line length, extracts only those two allow-listed values, and fails closed. agent_identity.probes_enabled or PM_AGENT_PROBES=off disables every local resolver without disabling ordinary environment, argv, client, or host detection.

Raw session identifiers remain transient and are never written to history or telemetry. When a harness and session are both present, history may retain only the existing domain-separated, truncated agent_instance digest. Public telemetry continues to use installation-scoped hashes or presence booleans; it does not export raw provenance values.

Compatibility

All new history fields are optional. Readers must accept:

  • legacy entries with no agent fields;
  • model-only entries using agent_model and agent_model_source;
  • new entries with agent_provenance;
  • explicit model: null, effort: null, or role: null observations meaning the dimension was declared but unavailable for a detected harness.

MCP clients may supply a bounded clientInfo.provenance map during initialize. The server retains only valid dimension names and trimmed values, then resolves that map inside the invocation-scoped identity context for every mutation. A missing MCP signal is recorded as explicit null; it is never confused with a legacy entry that predates the dimension.

Unknown provenance dimensions are preserved as data and do not change author resolution. Removing a dimension from a descriptor never rewrites existing history.

Historical disposition

The repository snapshot measured at the start of the 2026-08-01 migration contains 42,679 immutable history entries. Privacy-safe aggregation by the presence and shape of agent_provenance.effort found 549 observed values, 166 explicitly unavailable values, and 41,964 entries with no effort key. No raw provenance value, session identifier, or instance digest was exported during that measurement.

The missing group is retained as legacy_missing; it is never backfilled from nearby mutations or inferred from another surface. The unavailable group means the dimension was declared at write time but could not be observed. The observed group remains the only group suitable for effort-based evaluation. Repository history does not persist the CLI-versus-MCP transport as an identity field, and the current snapshot contains no committed agent_instance group mixing an observed effort with a legacy-missing effort. Historical MCP records from the original isolated reproduction therefore keep the same immutable disposition: missing means unknown, not a change in effort.

Consumers grouping one session must treat legacy_missing, explicit unavailability, and an observed value as three distinct states. Rewriting the hash chain would erase the evidence that motivated this amendment and could fabricate precision that was never captured.

SDK and completeness contracts

The aggregate and core SDK entrypoints export:

  • AGENT_PROVENANCE_DIMENSIONS;
  • detectAgentIdentity() and detectHarnessIdentity();
  • analyzeAgentProvenanceDescriptorCoverage() for the descriptor capability matrix and negative controls;
  • summarizeAgentModelProvenance() for observed, unavailable, legacy-missing, and inert-capture reporting;
  • analyzeSdkCliParameterCompleteness() for a derived bidirectional CLI flag and strict SDK parameter matrix.
  • projectHistoryProvenance(), compileHistoryProvenanceMatcher(), and summarizeHistoryProvenance() for immutable, patch-free reads and bounded completeness reporting.

pm history <id>, pm activity, and pm events share --provenance, --provenance-summary, repeatable --harness, repeatable --agent-instance, and repeatable --provenance-filter dimension=value. The provenance projection never returns JSON Patch operations or document hashes. History rows retain their original one-based stream version after filtering. Events use the same predicates in the durable derived index, so consumers do not need to scan raw history payloads.

Legacy author interpretation is workspace-owned data under agent_identity.identity_vocabulary. It contains a monotonically managed version and exact literal-to-harness aliases. Reads disclose both the version and whether a harness was recorded, resolved by vocabulary, or remains unresolved; immutable authors and hashes are never rewritten.

The SDK/CLI matrix classifies every input as shared, positional, transport, presentation, local adapter, scope selector, compatibility alias, or SDK-native. An unknown CLI flag fails closed as unclassified. Committed test baselines cap every waiver category and the representative behavioral-envelope corpus, so coverage may expand and waivers may shrink without returning to a curated hand-picked list.

Operational guidance

Use provenance to answer context questions such as which harness/model/effort performed a mutation or whether a capture source is inert. Do not use it to decide who is allowed to mutate an item. Use author, ownership, and explicit project policy for authorization and coordination.


Agent_provenance_adr remote
Report an issue