provenance

package
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 9, 2026 License: MIT Imports: 5 Imported by: 0

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

View Source
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.

View Source
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

func RedactHighConfidenceSecrets(s string) (string, bool)

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

func RedactSecrets(s string) (string, bool)

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

func (e *Envelope) Validate() error

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"
	// StatusUnavailable means the step could not be run (e.g. a required
	// 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"
	// VerificationProtectedPaths categorizes a check of whether a diff
	// touches a path contract.Contract.ProtectedPaths declares off-limits
	// without explicit human approval, per ADR-0032's "generated and
	// protected paths" and docs/planning/agent-safety-policy.md's
	// protected-paths list. See review.CheckProtectedPaths.
	VerificationProtectedPaths VerificationCategory = "protected_paths"
)

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL