Verdict provenance: falsifiable engineVersion and an engineRef field - #247
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR improves review verdict provenance by (1) adding an optional engineRef field (verbatim GITHUB_ACTION_REF) to the translation-review-verdict block and (2) making engineVersion falsifiable on non-release refs by suffixing the package version with sanitized build metadata (e.g. 0.25.0+main). This aligns harness (@main) verdict attribution with the actual code that produced the verdict while keeping release-tag verdicts unchanged.
Changes:
- Add
engineRef?: stringtoReviewVerdictV2and wire it into both verdict construction sites (normal review path + deletion-only path). - Update
getEngineVersion()to suffix non-release refs as semver build metadata and addgetEngineRef(). - Extend tests and documentation to cover the new field, suffix semantics, and fail-closed validation behavior.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/reviewer.ts | Wires engineRef: getEngineRef() into both normal and deletion-only verdict block construction. |
| src/review-verdict.ts | Adds engineRef to the verdict contract, introduces getEngineRef(), and updates getEngineVersion() to suffix non-release refs; validator fail-closes on malformed engineRef. |
| src/tests/reviewer-deletion.test.ts | Adds an end-to-end wiring test ensuring deletion-path verdicts include engineRef and a suffixed engineVersion when GITHUB_ACTION_REF is set. |
| src/tests/review-verdict.test.ts | Adds round-trip and malformed-value tests for engineRef, plus ref/suffix behavior tests for getEngineVersion()/getEngineRef(), and an end-to-end emitted-block wiring test. |
| docs/user/metadata-contract.md | Documents engineRef and clarifies engineVersion suffix sanitization and non-equality with engineRef. |
| dist-action/index.js | Updates the committed action bundle to include the new runtime provenance logic and verdict fields. |
| CHANGELOG.md | Adds an Unreleased entry describing the provenance fix and new engineRef field. |
| .dev/log/2026-08-05-engine-ref.md | Adds a maintainer log entry documenting the design and rationale for runtime ref provenance. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
… provenance (#244) package.json on a branch carries the previous release's number until the release commit bumps it, so every @main-produced verdict — including all harness verdicts — asserted a release that did not produce it. The fix is runtime, not build-time: GITHUB_ACTION_REF is read at verdict construction, the version gains a +<ref> build-metadata suffix when the ref is not a release-shaped tag, and a new optional engineRef field carries the ref verbatim. Build-time embedding was rejected — it would break the byte-identical dist rebuild check and embed the parent commit's SHA. Field addition only: no schemaVersion bump, per the contract's own versioning rules. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mmcky
force-pushed
the
fix/244-engine-ref
branch
from
August 5, 2026 01:36
ff37944 to
9dab95d
Compare
Copilot catch on #247: the suffix rule ran unconditionally, so an unresolvable package.json on a branch ref produced 'unknown+main', breaking the contract's documented sentinel for consumers keying off the exact string. The suffix decision is now a pure exported helper (formatEngineVersion) so the sentinel branch — unreachable through getEngineVersion in Jest — is directly unit-tested. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # CHANGELOG.md # dist-action/index.js.map
This was referenced Aug 5, 2026
mmcky
added a commit
to QuantEcon/status-translations
that referenced
this pull request
Aug 6, 2026
… backfill to v0.22.0 (#2) * Capture review verdicts nightly into an append-only event store, with backfill to v0.22.0 collector/verdicts.py captures translation-review-verdict blocks from review comments across the production editions into data/verdicts.jsonl, run as a separate step in the nightly collect workflow. Design departs from the spec in #1 on four verified points: - Routing keys on `recommendation`, not `wouldAutoMerge`: 44 of the 47 live verdicts ran under auto-merge-mode `off`, where wouldAutoMerge is null; recommendation exists on all 47 and shows a 12/47 auto-merge base rate the shadow-only field would render as zero. - Events, not snapshot fields: the verdict population includes merged/closed PRs and re-review supersedes in place, so verdicts get an append-only store keyed (repo, pr, reviewedHeadSha, timestamp) rather than a place in data/history/ snapshots. No schema_version bump — latest.json is untouched. - Backfill included: GitHub retains superseded comment bodies, so the store starts at v0.22.0 (2026-07-22), not at first capture. This commit ships the backfilled corpus: 61 events — 47 current verdicts, 7 superseded ones recovered via userContentEdits (four distinct-SHA re-reviews on one PR alone), 7 pre-v0.22.0 no-verdict records. - engineRef captured but not relied on: the provenance field from QuantEcon/action-translation#247 is on main but unreleased, so it is null fleet-wide today. Parsing is fail-closed per the engine metadata contract: last block only, malformed last block recorded as no-verdict, never a fallback to an earlier block. Reruns are idempotent (verified: second run appends 0). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * collect: continue-on-error on verdict capture so the snapshot still publishes The workflow comment promised a capture failure wouldn't kill the snapshot, but a failed step aborts the job before the commit/push and deploy. Flagged by Copilot review on #2. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.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 #244.
package.jsonon a branch carries the previous release's number until the release commit bumps it, so every@main-produced verdict — including every harness verdict ever written, the exact place pre-release behaviour is meant to be observed — asserted a release that did not produce it (all five ml calibration verdicts said0.24.0while their run logs showed the post-#237 glossary).The mechanism is runtime, not build-time, per the review comment: the runner sets
GITHUB_ACTION_REFfor the executing action step, and nothing needed to change in the build. Build-time embedding (the issue's "cheapest" shape) was rejected because it would break the release pre-flight's byte-identicaldist-action/rebuild check, make version bumps require rebuilds, and embed the parent commit's SHA — the bundle committed in commit C is necessarily built before C exists.Behaviour by pin:
engineVersionengineRef@v0(release-tag checkout, bumped package.json)0.25.0— unchanged, was always truthfulv0@main0.25.0+main— falsifiablemain0.25.0+<sha>— exact tree attribution for freeContract: pure field addition — no
schemaVersionbump, per the contract's own versioning rules ("field additions are non-breaking") and thediffCheckSourcesprecedent.docs/user/metadata-contract.mddocuments both the new field and the suffix semantics. The validator treats a present-but-malformedengineRefas a wrong-shape block, fail-closed likewouldAutoMerge.Known limit, accepted deliberately: on
@mainthe ref is lineage, not an exact tree. Resolving ref→SHA via the API at review time would add a network failure mode and a checkout-vs-query race to every review; the verdict's timestamp plus harness run logs already resolvemain-at-time when it matters, and the harness is the only@mainsurface.A pre-PR adversarial review (six lenses over the diff, findings verified by independent refuters) found the correctness and fail-closed lenses clean but caught two gaps, both fixed here: the
engineRefwiring at the two verdict-construction sites was pinned by no test — a verifier empirically deleted both lines and the full suite stayed green, because Jest has noGITHUB_ACTION_REFandJSON.stringifydrops the undefined field, so a future refactor could silently drop the field this PR exists to add; there are now end-to-end tests on both the normal review path and the deletion path that set the env var and assert the parsed block carriesengineRefand the suffixed version. And the sanitisation rule was missing from the contract doc — the code appends the sanitised ref (feat/x→+feat-x) whileengineRefis verbatim, so a consumer implementing from the spec could wrongly assumeengineVersion.split('+')[1] === engineRef; the contract row now states the character rule and the non-equality explicitly.Tests: the suffix logic across release-tag / branch / SHA / absent-env refs, ref sanitisation for semver build metadata,
getEngineReftrimming and empty-string handling, verdict round-trip with and withoutengineRef, fail-closed rejection of malformed values, and the two end-to-end wiring tests above. Verification beyond CI: the first harness review run after this merges should showengineVersion: 0.25.0+mainandengineRef: mainin its verdict block — observable on the next organic harness PR without any dedicated run.Why now: QuantEcon/project-translation#22's edit-density-per-engine-version analysis and the Stage 4 floor calibration both need verdicts attributable to the code that produced them, and the WS8 dashboard lanes — the verdict block's first real consumers — are about to be built. Field and format changes cost least while consumer count is zero.
🤖 Generated with Claude Code