ManifestProvenance: say why build_git_sha is absent (closes #100) - #102
Conversation
There was a problem hiding this comment.
1 issue found across 10 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="crates/subc-protocol/src/manifest.rs">
<violation number="1" location="crates/subc-protocol/src/manifest.rs:730">
P2: A direct literal can set both fields, and the derived serializer emits both, but `ManifestProvenance` deserialization rejects that JSON. Validate this contradiction before serialization or prevent unvalidated direct construction.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
|
||
| impl ManifestProvenance { | ||
| pub fn validate(&self) -> Result<(), ManifestProvenanceError> { | ||
| if let (Some(_), Some(reason)) = ( |
There was a problem hiding this comment.
P2: A direct literal can set both fields, and the derived serializer emits both, but ManifestProvenance deserialization rejects that JSON. Validate this contradiction before serialization or prevent unvalidated direct construction.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/subc-protocol/src/manifest.rs, line 730:
<comment>A direct literal can set both fields, and the derived serializer emits both, but `ManifestProvenance` deserialization rejects that JSON. Validate this contradiction before serialization or prevent unvalidated direct construction.</comment>
<file context>
@@ -641,8 +727,24 @@ impl std::error::Error for ManifestProvenanceError {}
impl ManifestProvenance {
pub fn validate(&self) -> Result<(), ManifestProvenanceError> {
+ if let (Some(_), Some(reason)) = (
+ self.build_git_sha.as_ref(),
+ self.build_git_sha_absence_reason.as_ref(),
</file context>
|
Read the diff and ran the merge tree locally before spending the matrix: fmt clean, Three things worth saying beyond "looks right": The compatibility correction is the most valuable part of this PR, and it was your own catch: the first shape broke Rider 1 landed as unrepresentable rather than rejected, which is stronger than what I asked for. The bytes proof is the right kind: hardcoded literals for the legacy path's wire output, not values derived from the new implementation — so a regression in the serializer cannot agree with itself. And you ran the discriminating mutation (legacy path emitting One observation, not a change request: Versions: |
…fusal does not refuse the tests c1cac9a (0.17.44) made parse_doc refuse a relative storage data home. Three existing tests then failed on the Windows leg: /data, /forced/data/home and /abs/home are RELATIVE on Windows (no drive letter), so the refusal was firing on the tests' own fixtures rather than on anything the tests meant to assert. Master has been red on Windows since that commit; the push runs in between were cancelled by my own docs-only pushes (cancel-in-progress), and the first run to complete was d8355fc's. Both iceteaSA twins (#101, #102) inherited the red. Fix is in the tests, not the guard: an abs() helper that yields C:\... on Windows and the POSIX path elsewhere, with the reason at its definition. The guard is correct; the fixtures assumed POSIX absoluteness. subc-core 0.17.45 (the wire check counts every non-comment line, test or not). #101 and #102 will need one more bump each on rebase; that cost is mine.
|
The Windows red on your twin was mine, not yours — read from the job log rather than assumed: the three failing tests ( Fixed at |
CONSUMER-IMPACT: The existing three-Option build_provenance signature remains source- and wire-compatible: it emits no build_git_sha_absence_reason because legacy callers provide no tree state. New source-aware callers use build_provenance_from_source with BuildGitShaSource. subc-protocol 0.19.2 is additive; existing consumers compile unchanged.
affa4dd to
ceb703b
Compare
|
Rebased onto This one took a real conflict rather than a clean replay — both Verified the resolution rather than trusting the edit — my first pass confirmed a and Gates on the rebased head: workspace tests zero failures · clippy Merge order as you set it: #101 then this. |
|
Landing this myself rather than asking for a fourth rebase. While you were rebasing I took 0.17.46 for a forwarding-test drain-budget fix ( Merged locally onto master as a stack: #101 → 0.17.47 ( |
|
Published: |
Closes #100. Both riders held, and the signature stayed compatible — which was not the first shape I built.
The reason
BuildGitShaAbsenceReason—DeclinedDirty,NeverDerived,NoGitDir, plusForwardCompatibleUnknown(String)per the #79 ruling, named so a reader sees it is the forward-compat arm and not a cause. Optional,skip_serializing_if, present only whenbuild_git_shais absent.Rider 1: contradiction is unrepresentable, not rejected
The reason is derived by the helper that decides the omission, and the input makes a contradicting call impossible to write rather than an error to catch:
NeverDerivedandNoGitDircarry no revision field, so "NeverDerived with a sha" does not typecheck.DeclinedDirtyis reachable only fromGit { tree_state: Dirty }. Callers cannot supply a reason at all.Rider 2: the stamp rule is pure
A function of its arguments, so both branches run in a test without rebuilding. This was the half you called sharper, and it is the reason the refusing branch is now reachable at all:
build.rs's current rule readsenv!inline, so its refusal path has never executed in a test.The signature stayed compatible — and that was a correction
The first implementation changed
build_provenance's signature in place. Before opening this I checked who calls it outside this repo: five fleet consumers do, with the three-argument form — broca, cerebellum, claustrum, insula, synapse. Sample,broca-module-serve/src/manifest.rs:65:All five would have failed to compile. That matters more than an ordinary break here: #83 moved this helper into
subc-protocolspecifically so transport-direct modules that cannot link the client SDK could still build honest provenance. Breaking its signature re-imposes the cost that move was made to remove — and it is a source break with no wire change, so no lockfile, version pin, wire-crate check or golden fixture would have caught it. It surfaces as five other repos' red builds, on their clock.So:
build_provenance(Option<&str>, Option<&str>, Option<&str>)— unchanged semantics, emits no reason.build_provenance_from_source(BuildGitShaSource<'_>, …)— the reason-bearing path. This repo's own callers migrated to it.The doc comment says why the legacy path names no reason: not because absence has no cause there, but because a caller that has not told us the tree state has given us no ground to name one, and guessing would be the fabrication this issue exists to prevent.
Compatibility is proved from outside the crate
An in-crate test can compile for reasons an external consumer cannot rely on, so the proof is a doc-test — doc-tests compile as a separate crate against the public API, exactly the linkage those five repos have:
And the bytes, not just the field:
legacy_build_provenance_keeps_master_wire_bytes_without_an_absence_reasonasserts exactserde_json::to_stringoutput against hardcoded literals (not values derived from the new implementation) for a canonical 40-hex sha,None, and the"unknown"sentinel.I ran the discriminating mutation myself rather than take it on report — making the legacy path emit
Some(NeverDerived)reds both proofs:Restored, 48/48 green, tree clean.
Versions
subc-protocol0.19.2 — additive now that the old signature is retained; nothing a consumer must change to compile.subc-core0.17.46, avoiding 0.17.45 which PR #101 is holding.Gates: workspace 1357 passed / 0 failed · clippy
-D warnings· fmt ·check-wire-crate-versions.sh6 crates, none unbumped · no golden fixtures changed.CONSUMER-IMPACT:additive. Existing three-argument callers compile unchanged and their wire output is byte-identical; the absence reason is opt-in via the new entry point.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary by cubic
Adds an optional
build_git_sha_absence_reasonfield toManifestProvenanceso consumers can see whybuild_git_shais missing, closing #100. The legacybuild_provenanceAPI keeps its three-argument signature and emits no reason; source-aware callers use the newbuild_provenance_from_sourceentry point.New Features
BuildGitShaAbsenceReasondistinguishesDeclinedDirty,NeverDerived, andNoGitDir, and preserves unknown future reasons asForwardCompatibleUnknown(String).BuildGitShaSourceprevents assigning a SHA toNeverDerivedorNoGitDir, and the dirty-tree rule is a pureattestable_commitfunction.Migration
build_provenance(...)callers compile unchanged and keep byte-identical wire output.ManifestProvenanceliterals need the newbuild_git_sha_absence_reason: Nonefield;subc-protocolis bumped to 0.19.2.Written for commit ceb703b. Summary will update on new commits.