Skip to content

fix: symmetric SynthOrg/DHI image verification cache#1878

Merged
Aureliolo merged 4 commits into
mainfrom
fix/image-verify-cache-parity
May 13, 2026
Merged

fix: symmetric SynthOrg/DHI image verification cache#1878
Aureliolo merged 4 commits into
mainfrom
fix/image-verify-cache-parity

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Why

After synthorg update to v0.8.3-dev.15, the next synthorg start showed Verify SynthOrg Images (cached) while DHI images re-verified. The two image groups should always cache (or invalidate) symmetrically: either both (cached) or both fresh.

Root cause (3 stacked bugs)

  1. hasSynthOrgDigests (cli/cmd/start.go) only checked key presence by bare service name. hasDHIDigests was much stricter: it compared the cached digest against verify.DHIPinnedIndexDigest (the Renovate-baked binary pin). On a tag bump, SynthOrg cache would silently go stale across ImageTag changes (masked today only because the update path always overwrites the map; accidental safety).
  2. verifyAndPinForUpdate (cli/cmd/update.go) only verified SynthOrg images via verify.BuildImageRefs, never DHI. DHI images were pulled by pullAllImages but skipped verification entirely during update.
  3. pullAndPersist (cli/cmd/update.go) did updatedState.VerifiedDigests = digestPins, replacing the whole map. Every dhi:* key was wiped on every update. Combined with bug 2, the post-update cache contained only SynthOrg pins, so the next start found DHI keys missing and re-verified.

The wipe path (cli/cmd/wipe.go) had the same Bug-1 shape and a latent state-aliasing issue (wc.state was loaded once and never reloaded after the persist, so subsequent pulls fell back to floating tag refs for sandbox/sidecar/fine-tune).

What changed

  • cli/internal/config/state.go: new VerifiedImageTag string sentinel field (json:"verified_image_tag,omitempty"). Records which ImageTag the SynthOrg pins were verified against. Existing on-disk state.json files unmarshal it as "", which never matches a real tag, so the first start after upgrade triggers a one-time re-verify and the cache becomes self-healing.
  • cli/cmd/verify_pipeline.go (new): imagesVerifyResult struct + verifyImagesWithCache helper + verifySynthOrgGroup + synthOrgPins filter. One cache-aware verification helper for both SynthOrg and DHI image groups, reused by start / update / wipe.
  • cli/cmd/start.go: hasSynthOrgDigests now requires state.VerifiedImageTag == state.ImageTag (mirrors hasDHIDigests's strictness). verifyAndPullStartImages refactored to route through the new helper. Dead helpers (verifyAndPinImages, renderVerifyBox) deleted.
  • cli/cmd/update.go: verifyAndPinForUpdate routes through the new helper (now also verifies DHI during update). pullAndPersist merges pins via a new mergeVerifiedDigests helper instead of replacing, and sets VerifiedImageTag = tag.
  • cli/cmd/wipe.go: extracted wipeContext.verifyAndPin, routes through the new helper, reloads state after persist (fixes the floating-tag-pull latent bug).
  • cli/cmd/config.go: invalidatesVerifiedDigests paths now also clear state.VerifiedImageTag so the sentinel drops alongside the pin map.
  • docs/reference/cli-persistence-backends.md + cli/CLAUDE.md: describe the shared verified_digests map and the new verified_image_tag sentinel.

Plus pre-existing docs drift surfaced by the pre-PR docs-consistency review: default_nats_url removed from the settable/compose-affecting lists (env-only); settable-key count corrected from 37 to 40 to match supportedConfigKeys.

Behaviour after this PR

  • Clean update then start: helper writes both groups, sentinel set; next start shows both panels as (cached). Symmetric.
  • Update where Renovate also moved a DHI pin: SynthOrg re-verifies (tag changed), DHI cache misses (binary pin moved), both re-verified during update, both persisted. Next start: both (cached). Symmetric.
  • synthorg config set image_tag X.Y.Z: clears verified_digests AND verified_image_tag; next start re-verifies both. Symmetric.

Test plan

  • Added cli/cmd/verify_pipeline_test.go with a table-driven TestHasSynthOrgDigests covering sentinel-mismatch, missing-sentinel (legacy state shape), missing-pin, full cache hit, sandbox-disabled hit. Plus TestSynthOrgPins_ExcludesDHIKeys, three TestMergeVerifiedDigests_* cases (preserves DHI, nil-in/nil-out, non-mutation).
  • Added TestConfigSetImageTag_ClearsVerifiedDigestsAndImageTag in cli/cmd/config_test.go.
  • go -C cli vet ./... clean.
  • golangci-lint run 0 issues.
  • go -C cli test ./... all packages pass.
  • go -C cli build ./... succeeds.

End-to-end manual verification suggested after merge:

  1. synthorg update to a new dev release; observe both panels verified DURING update.
  2. synthorg start; both panels should show (cached).
  3. synthorg config set image_tag 0.0.0-fake && synthorg start; both panels should re-verify (sentinel mismatch).
  4. Restore real tag and synthorg start; both panels cached again.

Review coverage

Pre-reviewed by 4 agents:

  • docs-consistency: surfaced 4 docs drift items; all 4 fixed (2 caused by this PR's code change, 2 pre-existing).
  • comment-quality-rot: clean.
  • go-reviewer: clean ("no critical findings, ready for merge").
  • go-conventions-enforcer: surfaced 4 items; 1 valid (table-driven consolidation, applied), 3 misapplied (flagged in triage as NOT VALID with rationale).

Total: 5 valid findings, all 5 implemented in this PR.

Aureliolo added 2 commits May 12, 2026 15:01
After 'synthorg update', the next 'synthorg start' showed
'Verify SynthOrg Images (cached)' while DHI images re-verified. Three
asymmetries combined:

- hasSynthOrgDigests only checked key presence (no expected-source
  comparison), unlike hasDHIDigests which compares cached digest against
  the binary-baked Renovate pin.
- verifyAndPinForUpdate verified SynthOrg images only, never DHI.
- pullAndPersist replaced state.VerifiedDigests instead of merging,
  wiping all dhi:* keys on every update.

Add VerifiedImageTag sentinel on State to record which tag the SynthOrg
pins were verified against; hasSynthOrgDigests now rejects on mismatch,
mirroring DHI's strictness. Extract verifyImagesWithCache helper that
runs cache-aware verification of both groups and route start, update,
and wipe through it. pullAndPersist merges instead of replaces and sets
the sentinel. config set image_tag clears both fields together. Wipe's
state-aliasing issue (pulls falling back to floating tag refs after a
SynthOrg-only verify) is fixed by reloading wc.state after persist.
Pre-reviewed by 4 agents, 5 valid findings addressed.

- cli/CLAUDE.md + docs/reference/cli-persistence-backends.md: describe
  the verified_digests map as shared by SynthOrg and DHI pins (not
  DHI-only) and document verified_image_tag as the SynthOrg-side
  cache sentinel.
- cli/cmd/verify_pipeline_test.go: consolidate the five
  hasSynthOrgDigests unit tests into one table-driven test with
  subtests.
- docs/reference/cli-config-subcommands.md: drop default_nats_url
  (env-only, no longer settable) from the tunables list and the
  compose-affecting list; correct the settable-key count from 37
  to 40 (matches supportedConfigKeys).
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 12, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 12, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e664ea00-01d3-45b4-bd23-02d0f187feb7

📥 Commits

Reviewing files that changed from the base of the PR and between db2ab7a and d0bf481.

📒 Files selected for processing (2)
  • .github/workflows/cli.yml
  • scripts/check_cli_bench_regression.sh
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Lighthouse Site
  • GitHub Check: CLI Bench Regression
  • GitHub Check: CLI Test (windows-latest)
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Build Web Assets (melange)
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.sh

📄 CodeRabbit inference engine (CLAUDE.md)

For shell scripting: see ~/.claude/rules/common/bash.md for canonical rules on cd, git -C, and Bash file-write patterns

Files:

  • scripts/check_cli_bench_regression.sh
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-12T18:26:57.106Z
Learning: Run `scripts/install_cli_tools.sh` once per development machine to install the pinned golangci-lint version, and re-run after bumping the version
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-12T18:26:57.106Z
Learning: Keep `cli/internal/config/` for configuration management, `cli/internal/docker/` for Docker interactions, `cli/internal/compose/` for compose-file generation, and `cli/internal/health/` for health checking
🔇 Additional comments (2)
scripts/check_cli_bench_regression.sh (1)

37-42: Good stabilization change for CI benchmark noise.

Raising the default BENCH_COUNT while keeping env override support is a solid, low-risk adjustment for more stable benchstat output on shared runners.

.github/workflows/cli.yml (1)

208-208: Workflow and script defaults are now aligned.

Explicitly setting BENCH_COUNT: 10 here keeps CI intent clear and consistent with the script behavior.


Walkthrough

This PR extends image verification caching to track which ImageTag value the cached SynthOrg digests were verified against via a new VerifiedImageTag field. A centralized verifyImagesWithCache pipeline checks cache validity by matching tags and digest coverage, merges freshly verified pins while maintaining separate keying for SynthOrg vs DHI images, and tracks reverification flags. Cache invalidation is extended across config changes, and the start, update, and wipe commands are refactored to use the unified verification infrastructure. Documentation is updated to reflect the expanded key inventory and unified image verification approach.

Suggested labels

autorelease: tagged

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: symmetric SynthOrg/DHI image verification cache' accurately reflects the main change: fixing an asymmetry bug in image verification caching between two image groups.
Description check ✅ Passed The description is comprehensively related to the changeset, explaining root causes, implementation details, and testing. It clearly connects the code changes to the documented PR objectives.
Docstring Coverage ✅ Passed Docstring coverage is 46.15% which is sufficient. The required threshold is 40.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@Aureliolo Aureliolo temporarily deployed to cloudflare-preview May 12, 2026 17:44 — with GitHub Actions Inactive
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the image verification process into a unified, cache-aware pipeline shared across the start, update, and wipe commands. It introduces a VerifiedImageTag sentinel in the configuration state to ensure cached SynthOrg digests remain valid for the active tag, alongside updated documentation and expanded test coverage. Reviewer feedback recommends adopting Go 1.21 maps idioms for cleaner map deletions and more robust mutation checks in tests, while also cautioning against sharing mutable data across parallel subtests to avoid potential data races.

Comment thread cli/cmd/verify_pipeline.go Outdated
Comment on lines +64 to +68
for k := range merged {
if !strings.HasPrefix(k, "dhi:") {
delete(merged, k)
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For improved readability and to leverage modern Go idioms, you could replace this loop with maps.DeleteFunc (available since Go 1.21). This would make the intent of deleting specific keys from the map more explicit.

		maps.DeleteFunc(merged, func(k, _ string) bool { return !strings.HasPrefix(k, "dhi:") })

Comment thread cli/cmd/verify_pipeline_test.go Outdated
Comment on lines +33 to +34
missingSidecar := fullSandboxedPins(false, "")
delete(missingSidecar, "sidecar")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Sharing mutable test data like missingSidecar across parallel subtests can be fragile. If a future test case were added that also uses and modifies this map, it could introduce a data race. To make the test more robust, consider creating a fresh copy of the map for each test case that needs it, for example by defining it inside the subtest's t.Run.

Comment thread cli/cmd/verify_pipeline_test.go Outdated
Comment on lines +175 to +180
if existing["backend"] != "sha256:0000000000000000000000000000000000000000000000000000000000000000" {
t.Error("mergeVerifiedDigests must not mutate the existing map")
}
if fresh["backend"] != "sha256:1111111111111111111111111111111111111111111111111111111111111111" {
t.Error("mergeVerifiedDigests must not mutate the fresh map")
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This check for mutation is good, but it's a bit brittle as it only checks a single key. If other keys were added to the test maps, a mutation in them would go unnoticed. For a more robust check, you could clone the maps before calling mergeVerifiedDigests and then compare them for equality afterwards. For example:

	originalExisting := maps.Clone(existing)
	originalFresh := maps.Clone(fresh)

	_ = mergeVerifiedDigests(existing, fresh)

	if !maps.Equal(existing, originalExisting) {
		t.Error("mergeVerifiedDigests must not mutate the existing map")
	}
	if !maps.Equal(fresh, originalFresh) {
		t.Error("mergeVerifiedDigests must not mutate the fresh map")
	}

This requires importing the maps package (available since Go 1.21).

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cli/cmd/start.go`:
- Around line 189-199: The code currently reloads the stored config
unconditionally after setting state.VerifiedDigests when
result.SynthOrgReverified || result.DHIReverified, which can discard the
in-memory verified pins if config.Save fails; change the flow so that you only
call config.Load/GetGlobalOpts and replace state when config.Save succeeds
(i.e., check the error from config.Save and skip the reload on failure),
ensuring state.VerifiedDigests and state.VerifiedImageTag set in this invocation
are preserved when config.Save returns an error; reference the
result.SynthOrgReverified/result.DHIReverified branch,
state.VerifiedDigests/state.VerifiedImageTag, config.Save, and
config.Load/GetGlobalOpts to locate and update the logic.

In `@cli/cmd/verify_pipeline_test.go`:
- Around line 33-34: The test currently calls fullSandboxedPins(false, "") and
then mutates the returned map via delete(missingSidecar, "sidecar"), which risks
sharing mutated state; instead create a local modified copy or inline the
fixture for the subtest so you never mutate the original map returned by
fullSandboxedPins. Locate the usage of fullSandboxedPins and missingSidecar in
the test, clone the map into a new variable (or construct the modified map
inline) and remove the "sidecar" key from that copy before passing it to the
subtest, ensuring no package-scoped map is mutated prior to t.Parallel().

In `@docs/reference/cli-config-subcommands.md`:
- Around line 15-16: The docs table incorrectly states that `get <key>` exposes
40 keys; update that count to 42 to reflect the two additional read-only keys
`memory_backend` and `persistence_backend` so the line "`get <key>` | Get a
single config value (40 gettable keys)" becomes "(42 gettable keys)". Ensure the
corresponding `set <key>` line remains unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8b7763a0-b439-494a-8b7a-73d0c05b911e

📥 Commits

Reviewing files that changed from the base of the PR and between 5d957fe and e2f8a61.

📒 Files selected for processing (11)
  • cli/CLAUDE.md
  • cli/cmd/config.go
  • cli/cmd/config_test.go
  • cli/cmd/start.go
  • cli/cmd/update.go
  • cli/cmd/verify_pipeline.go
  • cli/cmd/verify_pipeline_test.go
  • cli/cmd/wipe.go
  • cli/internal/config/state.go
  • docs/reference/cli-config-subcommands.md
  • docs/reference/cli-persistence-backends.md
📜 Review details
🧰 Additional context used
📓 Path-based instructions (7)
cli/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

For CLI work: use go -C cli command, never cd cli; see cli/CLAUDE.md for CLI-specific rules

Files:

  • cli/cmd/config_test.go
  • cli/internal/config/state.go
  • cli/cmd/wipe.go
  • cli/cmd/config.go
  • cli/cmd/verify_pipeline_test.go
  • cli/cmd/verify_pipeline.go
  • cli/cmd/update.go
  • cli/cmd/start.go
cli/cmd/**/*.go

📄 CodeRabbit inference engine (cli/CLAUDE.md)

All CLI commands accept persistent flags with precedence order: flag > env var > config > default; support --data-dir, --skip-verify, --quiet, --verbose, --no-color, --plain, --json, --yes, and --help-all

Exit codes: 0=success, 1=runtime error, 2=usage error, 3=unhealthy (backend/containers), 4=unreachable (Docker), 10=updates available

Per-command flags must follow the documented table: init requires --backend-port, --web-port, --sandbox, --log-level for non-interactive mode; start supports --no-wait, --timeout, --no-pull, --dry-run, --no-detach, --no-verify; and so on per the full Per-Command Flags table

Files:

  • cli/cmd/config_test.go
  • cli/cmd/wipe.go
  • cli/cmd/config.go
  • cli/cmd/verify_pipeline_test.go
  • cli/cmd/verify_pipeline.go
  • cli/cmd/update.go
  • cli/cmd/start.go
{README.md,docs/**/*.md}

📄 CodeRabbit inference engine (CLAUDE.md)

Source numerics in README and public docs from data/runtime_stats.yaml via <!--RS:NAME--> markers per data/README.md

Files:

  • docs/reference/cli-persistence-backends.md
  • docs/reference/cli-config-subcommands.md
docs/**/*.{md,d2}

📄 CodeRabbit inference engine (CLAUDE.md)

Use d2 for architecture and nested container diagrams; use mermaid for flowcharts, sequence diagrams, and pipelines; use Markdown tables for tabular data. D2 theme 200 (Dark Mauve), D2 CLI pinned to v0.7.1.

Files:

  • docs/reference/cli-persistence-backends.md
  • docs/reference/cli-config-subcommands.md
cli/internal/{config,verify}/**/*.go

📄 CodeRabbit inference engine (cli/CLAUDE.md)

Overriding any of registry_host, image_repo_prefix, dhi_registry, postgres_image_tag, or nats_image_tag disables image signature and SLSA verification for that invocation only and writes a stderr warning

Files:

  • cli/internal/config/state.go
cli/internal/config/**/*.go

📄 CodeRabbit inference engine (cli/CLAUDE.md)

Backend auto-wire precedence: when both SYNTHORG_DATABASE_URL and SYNTHORG_DB_PATH are present, SYNTHORG_DATABASE_URL wins and Postgres is initialized; malformed URLs must raise loudly at startup rather than silently falling back

Files:

  • cli/internal/config/state.go
cli/internal/{verify,config}/**/*.go

📄 CodeRabbit inference engine (cli/CLAUDE.md)

Image verification cache uses a verified_digests map shared by SynthOrg and DHI pins, with verified_image_tag as the SynthOrg-side cache sentinel; reference in docs/reference/cli-persistence-backends.md

Files:

  • cli/internal/config/state.go
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-12T17:43:45.275Z
Learning: Package structure for CLI: `cmd/` contains Cobra commands and global options; `internal/` contains version, config, docker, compose, health, diagnostics, images, selfupdate, completion, ui, verify, and backup modules
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-12T17:43:45.275Z
Learning: Environment variable namespace `SYNTHORG_*` covers backend/channel overrides, image/registry overrides, timeouts/retry tuning, byte caps, and ports; full reference in `docs/reference/cli-env-vars.md`
🔇 Additional comments (7)
cli/cmd/update.go (3)

616-628: LGTM! Clean merge implementation with proper nil handling.

The mergeVerifiedDigests function correctly:

  1. Returns nil when both inputs are empty (preserving compose's nil-pin fallback)
  2. Creates a new map to avoid aliasing the original inputs
  3. Uses maps.Copy for clean overlay semantics (fresh wins on conflict)

630-670: LGTM! Well-structured separation of SynthOrg compose pins vs full cache.

The refactored verifyAndPinForUpdate properly:

  1. Uses the cache-aware verifyImagesWithCache for consistent verification
  2. Writes only SynthOrg pins to compose via synthOrgPins(result.Pins)
  3. Returns the full pin map (including DHI keys) for state persistence

This correctly addresses the asymmetric caching issue described in the PR objectives.


587-614: LGTM! Proper merge-before-pull and sentinel tracking.

The updated pullAndPersist flow correctly:

  1. Merges fresh pins with existing (preserving cached DHI keys)
  2. Uses merged pins for the pull operation
  3. Sets VerifiedImageTag sentinel after successful pull to enable cache validation

This addresses the PR objective of preventing stale SynthOrg cache across ImageTag changes.

cli/cmd/wipe.go (2)

385-426: LGTM! Cache-aware verification with proper state reload.

The verifyAndPin method correctly:

  1. Honors --skip-verify consistently with other commands
  2. Conditionally writes compose only when SynthOrg was reverified
  3. Sets the VerifiedImageTag sentinel alongside VerifiedDigests
  4. Reloads state from disk after persist (lines 420-424) to fix the state-aliasing bug mentioned in the PR objectives

The reload-after-persist pattern ensures wc.state reflects the freshly-pinned references for subsequent pull operations, avoiding the stale reference issue.


376-383: LGTM!

Clean integration of the cache-aware verification step before pulling images.

cli/cmd/verify_pipeline_test.go (2)

106-132: LGTM! Comprehensive DHI key filtering test.

Good coverage of the synthOrgPins filtering behavior, verifying that:

  1. Only bare-name SynthOrg keys are retained
  2. All dhi:-prefixed keys are excluded
  3. Various DHI key patterns (platform, attestation, signature) are handled

134-181: LGTM! Thorough merge behavior tests.

The tests for mergeVerifiedDigests properly verify:

  1. Fresh pins overlay existing ones for shared keys
  2. DHI keys are preserved from the existing map
  3. nil inputs return nil (preserving compose's fallback path)
  4. Input maps are not mutated (important for avoiding aliasing bugs)

These tests directly validate the fix for the state-aliasing bug mentioned in the PR objectives.

Comment thread cli/cmd/start.go Outdated
Comment thread cli/cmd/verify_pipeline_test.go Outdated
Comment thread docs/reference/cli-config-subcommands.md Outdated
…ing diagnostics)

- cli/cmd/start.go: only reload config when Save succeeds; preserve in-memory
  VerifiedDigests/VerifiedImageTag when Save fails (CodeRabbit, MAJOR)
- cli/cmd/verify_pipeline.go: replace SynthOrg + DHI delete-loops with
  maps.DeleteFunc Go-1.21 idiom (Gemini)
- cli/cmd/verify_pipeline_test.go: inline the "missing sidecar" pin map in
  TestHasSynthOrgDigests instead of mutating a package-scope variable before
  parallel subtests run (Gemini + CodeRabbit)
- cli/cmd/verify_pipeline_test.go: harden TestMergeVerifiedDigests_DoesNotMutateInputs
  with maps.Clone + maps.Equal so any future key mutation is caught (Gemini)
- docs/reference/cli-config-subcommands.md: correct `config get` key count
  to 42 (memory_backend + persistence_backend are read-only but gettable)
  (CodeRabbit)
- cli/cmd/update.go: use errors.AsType[*exec.ExitError] (Go 1.26 stdlib)
- cli/cmd/config_test.go: use strings.SplitSeq for range iteration
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview May 12, 2026 18:05 — with GitHub Actions Inactive
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 12, 2026
ci(cli-bench): bump BENCH_COUNT 5 -> 10 to clear benchstat's n>=6 floor

The `IsValidImageTag` benchmark tripped the +15% regression gate at
+16.17% on this PR, but the function source is byte-identical between
the merge-base and PR HEAD (the PR only adds a new field to the State
struct, no impact on the IsValidImageTag hot path). benchstat itself
warned `need >= 6 samples for confidence interval at level 0.95` on
every comparison row.

Bumping BENCH_COUNT 5 -> 10 in both the workflow env and the script
default crosses benchstat's n>=6 threshold so confidence intervals
actually compute, and tightens the standard error by ~sqrt(2). Real
15%+ regressions still surface; sub-100ns microbenchmark wobble on
shared CI runners stops being a false positive.

Threshold stays at 15%.
@codecov
Copy link
Copy Markdown

codecov Bot commented May 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 84.96%. Comparing base (5d957fe) to head (d0bf481).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1878      +/-   ##
==========================================
- Coverage   84.97%   84.96%   -0.01%     
==========================================
  Files        1804     1804              
  Lines      105548   105548              
  Branches     9206     9206              
==========================================
- Hits        89687    89683       -4     
- Misses      13632    13634       +2     
- Partials     2229     2231       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Aureliolo Aureliolo merged commit 1e1764e into main May 13, 2026
91 of 93 checks passed
@Aureliolo Aureliolo deleted the fix/image-verify-cache-parity branch May 13, 2026 02:07
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview May 13, 2026 02:07 — with GitHub Actions Inactive
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.

1 participant