Add publisher-side provenance: map a code_id back to a commit#9
Merged
Conversation
A code_id is a content hash, which answers 'are these compilers serving the same code?' but not 'which control-repo commit produced it?'. The artifact excludes .git and .r10k-deploy.json, so a compiler has no path back to a commit. Troubleshooting a divergent compiler could tell you *that* it differed but not *what* it came from. The publisher already has the answer on disk: .r10k-deploy.json is excluded from sealing but not deleted, so at seal time the publisher reads r10k's resolved commit (the signature field) and appends a record to <state>/provenance.jsonl, keyed by code_id. codavox provenance <env> <code_id> reads that log locally on the publisher and prints the commit — no network I/O, so it needs no second client path or TLS. Three properties are deliberate and load-bearing: - Publisher-only. The log never enters an artifact or reaches a compiler, so it cannot influence a code_id or the bytes served. Reading .r10k-deploy.json here does not change sealing, which still excludes it. - One code_id, many commits. A commit that leaves resolved content unchanged seals to the same id, so an id can list several commits — recorded history, not a conflict. - Best-effort, never load-bearing. A missing or malformed .r10k-deploy.json records nothing and never fails a deploy, and a query with no record prints 'no provenance recorded' and exits 0. This is not a no-fallbacks violation: that rule forbids serving wrong content while reporting success. Provenance is diagnostic; its honest absence is the correct answer, never a stand-in from a different version. The log is the first persistent state codavox keeps, and it stays on the publisher; compilers remain stateless except for their version directories. No HTTP endpoint yet — the query is local-read only until a remote consumer exists. Signed-off-by: Michael Harp <mike@mikeharp.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the one troubleshooting question the content-addressed design can't answer on its own: which control-repo commit produced the version this compiler is serving?
Why
A
code_idis a content hash — great for "are these two compilers serving the same code?", useless for "what commit is this?". Sealing deliberately strips.gitand.r10k-deploy.json, so a compiler carries no path back to a commit. Today you can detect that a compiler diverged but not trace what it came from.How
The publisher already has the answer sitting in the staging tree:
.r10k-deploy.jsonis excluded from sealing but not deleted. At seal time the publisher reads r10k's resolved commit (thesignaturefield) and appends a record to<state>/provenance.jsonl, keyed bycode_id.codavox provenance <env> <code_id>reads that log locally on the publisher and prints the commit. No network I/O — per the design decision, the CLI is local-read only, so there's no second TLS client path to maintain.Three deliberate properties
code_idor the bytes served. Reading.r10k-deploy.jsonhere does not change sealing, which still excludes it — verified by a test that thecode_idis identical with and without capture.code_id, many commits. A commit that leaves resolved content unchanged seals to the same id, so an id can list several commits — recorded history, not a conflict..r10k-deploy.jsonrecords nothing and never fails a deploy; a query with no record printsno provenance recordedand exits0. This is not a no-fallbacks violation: that rule forbids serving wrong content while reporting success. Provenance is diagnostic — its honest absence is the correct answer, never a stand-in from another version.Scope notes
0700dir,0600file). Compilers remain stateless except for their version directories.code-id/code-contentare untouched: still a single symlink read and a single file read.Tests
internal/publish— capture, missing/malformed deploy file degrade cleanly, dedup, persistence across reopen, one-id-many-commits, env/id isolation, and code_id-unchanged-by-capture.cmd/codavox— the subcommand reads the local log,--json, unrecorded-id is empty+exit 0, and bad-arg rejection.Verified locally:
go test -race ./...,golangci-lint0 issues, gofmt/vet clean, markdownlint clean.🤖 Generated with Claude Code