Skip to content

Record module commits in provenance, and look versions up by label - #107

Merged
miharp merged 1 commit into
mainfrom
provenance-module-commits
Oct 15, 2026
Merged

miharp merged 1 commit into
mainfrom
provenance-module-commits

Conversation

@miharp

@miharp miharp commented Oct 15, 2026

Copy link
Copy Markdown
Owner

Fixes #106.

Problem

A code_id from an old report could be traced to the control-repo commit, and no further:

  • Module commits were recorded nowhere. A :branch or a tag that moves resolves to whatever the remote held at deploy time, so the control-repo commit does not say which module code a version contains. By the time anyone asks, the tree is gone too: the publisher keeps only the current artifact, compilers reap old versions, and the seal excludes .git.
  • The label found nothing. codavox provenance matched the full code_id only, so the short id in a run log or the catalog label returned no provenance recorded.

Change

  • Module commits at seal time. Store.Reseal reads each git module's HEAD and remote.origin.url from its own .git in the basedir, where r10k leaves the resolved commit checked out as a detached HEAD. The control repo's own .git is skipped; its commit is already recorded. .git stays excluded from sealing, so the code_id is unchanged.
  • Not module_deploys. r10k's list in .r10k-deploy.json goes stale: r10k deploy module, which codavox deploy --modules runs, does not rewrite the file. The harness reproduces this before checking the fix.
  • Honest gaps. A HEAD that is not a bare object id lists the module with no commit. Credentials are stripped from the remote, because the command prints it. Forge modules are not listed (see the issue for why).
  • Whole-record comparison. A record is skipped only when both the commit and the modules match the newest one, so existing logs gain modules at the next reseal with no migration.
  • Lookup by label or prefix. codavox provenance production-a3f1c9e4b2d8, or a unique prefix. An ambiguous prefix is an error naming every match. --modules prints the module commits; --json always includes them.
  • Docs. publishing.md gains Module commits and Proving where a version came from, which re-seals the recorded commits to prove them. Also updated: commands.md, and the provenance log's size and backup notes in production.md.

Test plan

  • go test -race ./..., go vet, gofmt, shellcheck, cspell, markdownlint
  • golangci-lint v2.12.2: 0 issues (run under GOTOOLCHAIN=go1.26.9 to match CI)
  • Unit tests: module capture (detached HEAD, symbolic HEAD, .git file, control repo skipped), credential stripping, [remote "origin"] parsing, whole-record skipping across reopen, backfilling an older log, prefix matching, and the command's label, prefix, ambiguity, and --modules output
  • Integration harness locally, all features passed. Feature 10 checks that after deploy --modules, .r10k-deploy.json still names the old module commit and provenance names the new one. Feature 14 looks up a real catalog's label on the publisher and finds both the control-repo and module commits.

Assisted by Claude.

A code_id from an old report could be traced to the control-repo commit
that produced it, but not to the module code inside it. A control-repo
commit pins a module only when its Puppetfile entry is immutable; a
branch resolves to whatever the remote held at deploy time. By the time
anyone asks, the tree is usually gone as well: the publisher keeps only
the current artifact, compilers reap superseded versions, and the seal
excludes .git.

The publisher now records each git module's path, commit, and origin at
seal time, read from the module's own .git in the basedir, where r10k
leaves the resolved commit checked out as a detached HEAD. The
module_deploys list r10k writes into .r10k-deploy.json would be simpler,
but `r10k deploy module`, which `codavox deploy --modules` runs, does not
rewrite that file, so after a module deploy the list names the module's
previous commit. The harness reproduces that before checking the fix. PE
has the same gap: Code Manager's module deploys run the same command,
and the file sync commit carries the stale list.

Credentials are stripped from the remote, because `codavox provenance`
prints it. A HEAD that is not a bare object id records the module with
no commit rather than resolving a reference. Forge modules are not
listed: nothing on disk tells one apart from a module committed to the
control repo, and a pinned Forge version is already answered by the
Puppetfile at the recorded commit.

A record is now skipped only when both the commit and the modules match
the newest one for its environment and code_id, so an existing log gains
modules at the publisher's next reseal with no migration.

`codavox provenance` also accepts the catalog label config-version
prints, or any code_id prefix that names one version, because that is
what a run log shows. A prefix that matches several is refused with each
match named, never answered with one of them. --modules prints the
module commits.

Fixes #106

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Michael Harp <mike@mikeharp.com>
@miharp
miharp merged commit 748620e into main Oct 15, 2026
13 checks passed
@miharp
miharp deleted the provenance-module-commits branch October 15, 2026 18:14
miharp added a commit that referenced this pull request Oct 16, 2026
The release workflow refuses a tag that installation.md does not
document, so the install lines move to 0.11.0.

Nothing has to change before upgrading, but the provenance log behaves
differently (#107), and the note says how: the upgraded publisher's
first reseal writes a record with module commits for every
environment's current version, versions sealed earlier keep none, and
each record now grows by about 150 bytes per git module. It also says
that codavox provenance now takes a catalog label or a unique prefix,
and that its --json output only gains a modules array.

Lab: batches B, F, and I green (57/57) against a 748620e snapshot built
with go1.26.9, including the new I9: the label from a real agent run
leads codavox provenance --modules to the lab's one git module at the
commit its v0.6.0 tag names on the GitHub remote, with the Forge
modules beside it unlisted (codavox-lab 57121e8).

Signed-off-by: Michael Harp <mike@mikeharp.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provenance names the control-repo commit but not the module commits a code_id came from

1 participant