Documentation
¶
Overview ¶
Package provenance defines a versioned, JSON-marshalable schema for recording what an AI coding agent did to a repository and why, per ADR-0032 ("Agent-First Development Experience"), P1: "Add provenance and handoff JSON".
This package is a standalone data schema. It intentionally does not import github.com/mediusfy/modulex or any other package in this repository: a future `modulex agent handoff` CLI (out of scope for this package), a CI step, or any other tool can depend on provenance alone to produce or consume an Envelope, without pulling in the runtime library.
Building a handoff artifact ¶
env := provenance.Envelope{
SchemaVersion: provenance.SchemaVersion,
Repository: provenance.RepoState{
Path: "/repo",
Branch: "MOD-66-provenance-handoff-json",
Commit: "abc1234",
Dirty: false,
},
Agent: provenance.AgentInfo{
Name: "claude",
Tool: "claude-code",
},
CreatedAt: time.Now().UTC(),
}
env.Redact()
if err := env.Validate(); err != nil {
return err
}
b, err := json.Marshal(env)
See docs/planning/provenance-handoff-schema.md for the full guide, including the redaction and validation guarantees and their limits.
Index ¶
- Constants
- func RedactHighConfidenceSecrets(s string) (string, bool)
- func RedactSecrets(s string) (string, bool)
- type AgentInfo
- type Approval
- type ChangeType
- type CommandClass
- type CommandResult
- type Envelope
- type FileChange
- type RepoState
- type RollbackStatus
- type Status
- type VerificationCategory
- type VerificationResult
Constants ¶
const RedactionMarker = redactionMarker
RedactionMarker is the exported form of redactionMarker, for a caller (e.g. review.ScanSecrets) that redacts using its own additional patterns alongside RedactHighConfidenceSecrets/RedactSecrets and wants the resulting marker to match exactly.
const SchemaVersion = "1.0.0"
SchemaVersion is the current version of the Envelope schema, using a plain semver string (not a Go module path or API version) because the schema is consumed as data, not as a Go API: it may be read by non-Go tooling (a future CLI, CI steps, MCP clients) that has no notion of Go module compatibility rules. Bump the minor version for backward-compatible additions (new optional fields) and the major version for breaking changes (renamed/removed/retyped fields), and document the change in CHANGELOG.md whenever Envelope's shape changes.
Variables ¶
This section is empty.
Functions ¶
func RedactHighConfidenceSecrets ¶ added in v0.7.0
RedactHighConfidenceSecrets is like RedactSecrets but excludes genericAssignmentPattern, the loose key/token/password/secret catch-all tuned for free-text command output (see its doc comment). Prefer this over RedactSecrets when scanning source code rather than command output — e.g. review.ScanSecrets, which pairs it with its own stricter, quote-required generic rule instead.
func RedactSecrets ¶ added in v0.7.0
RedactSecrets replaces every secret-shaped match in s with the redaction marker ("[REDACTED]"), reporting whether any replacement was made. It is the exported form of the same best-effort, pattern-based detection Redact uses internally (see secretPatterns' doc comment for what it does and does not catch), exposed so other packages needing secret-shaped-value detection (e.g. review's diff secret scan, Jira MOD-65) reuse this one pattern set instead of maintaining a second, divergent copy.
Types ¶
type AgentInfo ¶
type AgentInfo struct {
// Name identifies the agent (e.g. "claude", "codex", "kimi").
Name string `json:"name"`
// Version is the agent/model version, if known.
Version string `json:"version,omitempty"`
// Tool identifies the host tool or SDK (e.g. "claude-code").
Tool string `json:"tool,omitempty"`
// ToolVersion is the host tool's version, if known.
ToolVersion string `json:"tool_version,omitempty"`
// CLIVersion is the version of the modulex agent CLI (or equivalent)
// that generated this envelope, if any.
CLIVersion string `json:"cli_version,omitempty"`
}
AgentInfo records which agent, tool, and CLI produced the envelope.
type Approval ¶
type Approval struct {
// Action names what was approved (e.g. "push", "release").
Action string `json:"action"`
ApprovedBy string `json:"approved_by"`
ApprovedAt time.Time `json:"approved_at"`
// Notes is free text. Redact before persisting; see Envelope.Redact.
Notes string `json:"notes,omitempty"`
}
Approval records a human approval granted for an elevated action (push, release, deletion, infrastructure change, etc.), per ADR-0032's human-approval boundary.
type ChangeType ¶
type ChangeType string
ChangeType describes how a file was affected.
const ( ChangeAdded ChangeType = "added" ChangeModified ChangeType = "modified" ChangeDeleted ChangeType = "deleted" ChangeRenamed ChangeType = "renamed" )
type CommandClass ¶
type CommandClass string
CommandClass classifies a command by the kind of impact it can have, per ADR-0032's requirement to "classify commands by filesystem, network, destructive, and approval impact."
const ( // ClassSafe commands are read-only and side-effect-free. ClassSafe CommandClass = "safe" // ClassMutating commands write to the local filesystem/repository. ClassMutating CommandClass = "mutating" // ClassNetworked commands perform network I/O. ClassNetworked CommandClass = "networked" // ClassDestructive commands can delete or irreversibly overwrite data. ClassDestructive CommandClass = "destructive" // ClassApprovalRequired commands require explicit human approval before // running (e.g. push, release, infrastructure changes). ClassApprovalRequired CommandClass = "approval_required" )
type CommandResult ¶
type CommandResult struct {
// Name is the command or Make target invoked (e.g. "make test").
Name string `json:"name"`
Args []string `json:"args,omitempty"`
Classification CommandClass `json:"classification"`
Status Status `json:"status"`
// ExitCode is the process exit code. It is meaningless (and should be
// ignored by consumers) when Status is StatusSkipped,
// StatusUnavailable, or StatusApprovalRequired, so it is a pointer:
// nil means "no exit code", distinct from an explicit 0 (success).
ExitCode *int `json:"exit_code,omitempty"`
// Duration is wall-clock time the command took to run, encoded as a
// nanosecond count (time.Duration's default JSON encoding). Zero for
// commands that never ran.
Duration time.Duration `json:"duration_ns,omitempty"`
// EnvironmentNeeds lists tools, services, or credentials the command
// required (e.g. "docker", "GITHUB_TOKEN"), without ever including
// their values.
EnvironmentNeeds []string `json:"environment_needs,omitempty"`
// Output is a free-text capture of command output. Redact before
// persisting; see Envelope.Redact.
Output string `json:"output,omitempty"`
// Reason explains a StatusSkipped/StatusUnavailable/
// StatusApprovalRequired status. Required (non-empty) in those cases;
// see Envelope.Validate.
Reason string `json:"reason,omitempty"`
}
CommandResult records one command the agent ran: its classification, outcome, exit code, duration, and any environment requirements. Output is free text and MUST be passed through Envelope.Redact (or independently scrubbed) before persisting or transmitting the envelope; see the package doc and docs/planning/provenance-handoff-schema.md.
type Envelope ¶
type Envelope struct {
SchemaVersion string `json:"schema_version"`
Repository RepoState `json:"repository"`
Agent AgentInfo `json:"agent"`
// Changes lists every file the agent touched, in the order they were
// changed.
Changes []FileChange `json:"changes,omitempty"`
// Commands lists every command the agent ran, in execution order.
Commands []CommandResult `json:"commands,omitempty"`
// Verification lists every verification step (focused, full, boundary,
// compatibility, security, secret-scan, changelog, ...), in the order
// they were run.
Verification []VerificationResult `json:"verification,omitempty"`
// Approvals lists human approvals granted for elevated actions, if any.
Approvals []Approval `json:"approvals,omitempty"`
// Rollback describes rollback availability/status for this change. Nil
// means rollback was not assessed (distinct from an assessed-but-
// unavailable RollbackStatus{Available: false}).
Rollback *RollbackStatus `json:"rollback,omitempty"`
// CreatedAt is when this envelope was produced.
CreatedAt time.Time `json:"created_at"`
}
Envelope is the top-level, versioned provenance/handoff record for one unit of agent work. It is designed to be marshaled to JSON and attached to a PR description, a CI artifact, an MCP response, or an audit log.
json.Marshal(envelope) produces a deterministic field order because every field is either a scalar or an ordered slice — there are no map types in this schema, so there is nothing that needs sorting before marshaling (contrast with the core module's Manager.Diagnostics/ModuleContract, which do sort map-derived slices for the same determinism goal; this package does not import or reference that code).
func (*Envelope) Redact ¶
func (e *Envelope) Redact()
Redact scrubs secret-shaped values from every free-text field in the envelope (command args/output/reason, verification message/reason, approval notes, rollback notes), replacing matches in place with redactionMarker ("[REDACTED]").
This is a best-effort pattern-based safety net (see secretPatterns' doc comment), not a guarantee that no secret can leak through. Callers should still avoid putting secrets into these fields in the first place, per docs/planning/agent-safety-policy.md.
func (*Envelope) Validate ¶
Validate checks that the envelope is structurally well-formed and free of unredacted secret-shaped values, returning a single error (via errors.Join) naming every problem found, or nil if the envelope is valid.
Structural checks:
- SchemaVersion, Repository.Path, Repository.Commit, and CreatedAt are required (non-empty/non-zero).
- Every CommandResult and VerificationResult with Status == StatusSkipped or StatusUnavailable must carry a non-empty Reason.
Secret checks: every free-text field (command args/output/reason, verification message/reason, approval notes, rollback notes) is scanned with the same best-effort detection Redact uses. A caller should call Redact before Validate; Validate exists as a backstop so an envelope with a live secret in it cannot be marshaled/persisted without an explicit error, even if Redact was skipped. See Redact's doc comment for the limits of this detection.
type FileChange ¶
type FileChange struct {
Path string `json:"path"`
// OldPath is set for ChangeRenamed to record the file's previous path.
OldPath string `json:"old_path,omitempty"`
Type ChangeType `json:"type"`
// Hash is a content hash of the file after the change, in
// "<algorithm>:<hex>" form (e.g. "sha256:abc123..."). Empty if not
// computed (e.g. for a deleted file).
Hash string `json:"hash,omitempty"`
}
FileChange records one changed file and, when available, a content hash of the resulting artifact (e.g. "sha256:<hex>") so a reviewer or CI system can verify the handoff matches the actual diff.
type RepoState ¶
type RepoState struct {
Path string `json:"path"`
Branch string `json:"branch,omitempty"`
Commit string `json:"commit"`
// Dirty is true if the worktree had uncommitted changes (staged or
// unstaged) at the time this envelope was produced.
Dirty bool `json:"dirty"`
}
RepoState records the repository path, branch, commit, and dirty-worktree state the envelope was produced from.
type RollbackStatus ¶
type RollbackStatus struct {
// Available is true if a rollback path (e.g. a git revert, a retained
// patch) exists for this change.
Available bool `json:"available"`
// Applied is true if a rollback has actually been performed.
Applied bool `json:"applied"`
// Method describes the rollback mechanism (e.g. "git revert <sha>").
Method string `json:"method,omitempty"`
// Notes is free text. Redact before persisting; see Envelope.Redact.
Notes string `json:"notes,omitempty"`
}
RollbackStatus records whether the change can be rolled back and whether a rollback has been applied.
type Status ¶
type Status string
Status is the outcome of a command or verification step. Modeling this as an explicit enum rather than a bool is required so that "did not run" and "ran and passed" are never confused: a missing tool, an unmet approval gate, and an intentional skip are all distinct from both success and failure.
const ( // StatusPass means the step ran and succeeded. StatusPass Status = "pass" // StatusFail means the step ran and failed. StatusFail Status = "fail" // StatusSkipped means the step was intentionally not run (e.g. out of // scope for this change). Requires a non-empty Reason. StatusSkipped Status = "skipped" // tool or service was missing). Requires a non-empty Reason. StatusUnavailable Status = "unavailable" // StatusApprovalRequired means the step is gated behind human approval // and has not (yet) been approved. StatusApprovalRequired Status = "approval_required" )
type VerificationCategory ¶
type VerificationCategory string
VerificationCategory groups a VerificationResult by the kind of check it represents, per ADR-0032's "focused and full verification results" and "boundary, compatibility, security, and secret-scan results." Modeling these as a Category field on one VerificationResult type (rather than separate top-level slices per category) keeps the schema flat and lets new categories be added without a breaking schema change.
const ( VerificationFocused VerificationCategory = "focused" VerificationFull VerificationCategory = "full" VerificationBoundary VerificationCategory = "boundary" VerificationCompatibility VerificationCategory = "compatibility" VerificationSecurity VerificationCategory = "security" VerificationSecretScan VerificationCategory = "secret_scan" VerificationChangelog VerificationCategory = "changelog" )
type VerificationResult ¶
type VerificationResult struct {
Name string `json:"name"`
Category VerificationCategory `json:"category"`
Status Status `json:"status"`
Duration time.Duration `json:"duration_ns,omitempty"`
// Message is free-text detail (e.g. a failure summary). Redact before
// persisting; see Envelope.Redact.
Message string `json:"message,omitempty"`
// Reason explains a StatusSkipped/StatusUnavailable/
// StatusApprovalRequired status. Required (non-empty) in those cases;
// see Envelope.Validate.
Reason string `json:"reason,omitempty"`
}
VerificationResult records the outcome of one verification step (a focused check, a full repository gate, a boundary/compatibility/security/ secret-scan pass, etc.), distinguished by Category.