Skip to content

feat: dev channel builds with incremental pre-releases between stable releases#715

Merged
Aureliolo merged 4 commits intomainfrom
feat/dev-channel-builds
Mar 22, 2026
Merged

feat: dev channel builds with incremental pre-releases between stable releases#715
Aureliolo merged 4 commits intomainfrom
feat/dev-channel-builds

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Summary

  • Every push to main between stable releases creates a PEP 440 dev pre-release (e.g. v0.4.7.dev3) with full pipeline: Docker images, CLI binaries, cosign signatures, SLSA provenance
  • CLI supports stable / dev update channels via synthorg config set channel dev
  • Dev builds reuse existing Docker + CLI workflows by creating proper v* tags

Changes

New workflow: dev-release.yml

  • Computes dev version from Release Please pending PR + commit count since last tag
  • Creates lightweight git tag via GitHub API + GitHub pre-release (marked pre-release)
  • Auto-cleans old dev pre-releases (keeps 5 most recent)
  • Concurrency group prevents race conditions between parallel runs

Docker workflow

  • Adds rolling dev tag for dev builds (only on refs/tags/v*.dev*)
  • Prevents major.minor tag on dev builds (avoids overwriting stable 0.4 tag)

Finalize-release workflow

  • Guards against publishing dev pre-releases (they're already non-draft)

CLI (cli/)

  • Channel config field (stable / dev) with validation
  • synthorg config set channel dev/stable command
  • synthorg config show and synthorg status display current channel
  • CheckForChannel / CheckDev in selfupdate with dev-aware version comparison
  • Generic fetchJSON[T] replaces duplicate HTTP fetch functions
  • User-Agent header on all GitHub API requests
  • log_level validation with allowlist (was accepting arbitrary values)
  • Table-driven tests for splitDev, compareWithDev, isDevUpdateAvailable

Docs

  • CLAUDE.md: dev-release workflow, dev channel flow, config command, dev tags
  • README.md: config command in quick start

Pre-PR Review

4 agents ran (go-reviewer, infra-reviewer, security-reviewer, docs-consistency), 18 findings addressed in the second commit.

Test plan

  • Push to main triggers dev-release.yml, creates v0.4.7.devN tag + pre-release
  • Docker workflow triggers on dev tag, builds all 3 images with dev + version tags
  • CLI workflow triggers, GoReleaser produces binaries with dev version
  • finalize-release does NOT publish dev pre-releases
  • synthorg config set channel dev persists in config.json
  • synthorg update on dev channel finds dev pre-releases
  • Stable release always preferred over dev at same base version
  • Old dev pre-releases cleaned up (>5 removed)
  • go test ./... passes (including new version comparison tests)

Closes #713

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 22, 2026

Dependency Review

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

OpenSSF Scorecard

PackageVersionScoreDetails
actions/actions/checkout de0fac2e4500dabe0009e67214ff5f5447ce83dd 🟢 5.9
Details
CheckScoreReason
Maintained⚠️ 23 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 2
Code-Review🟢 10all changesets reviewed
Binary-Artifacts🟢 10no binaries found in the repo
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Packaging⚠️ -1packaging workflow not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Pinned-Dependencies🟢 3dependency not pinned by hash detected -- score normalized to 3
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
SAST🟢 8SAST tool detected but not run on all commits

Scanned Files

  • .github/workflows/dev-release.yml

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 22, 2026

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: dc193c45-52a3-48fa-a722-99640845ee8a

📥 Commits

Reviewing files that changed from the base of the PR and between 5749d59 and addb9d3.

📒 Files selected for processing (1)
  • cli/internal/selfupdate/updater.go
📜 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). (4)
  • GitHub Check: Build Backend
  • GitHub Check: Build Web
  • GitHub Check: CLI Test (windows-latest)
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (1)
cli/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

Use Cobra framework for CLI commands and charmbracelet libraries (huh, lipgloss) for interactive UI

Files:

  • cli/internal/selfupdate/updater.go
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: CLI workflow (`.github/workflows/cli.yml`) runs Go lint (golangci-lint + go vet) + test (race, coverage) + build (cross-compile matrix) + vulnerability check (govulncheck) + fuzz testing. Cross-compiles for linux/darwin/windows × amd64/arm64. GoReleaser release on v* tags with cosign keyless signing and SLSA L3 attestations.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/docker.yml : Docker workflow: builds backend + web + sandbox images, pushes to GHCR, signs with cosign. SLSA L3 provenance attestations via actions/attest-build-provenance. Scans: Trivy (CRITICAL = hard fail, HIGH = warn) + Grype (critical cutoff) + CIS Docker Benchmark v1.6.0 compliance (informational). CVE triage via .github/.trivyignore.yaml and .github/.grype.yaml. Images only pushed after scans pass. Triggers on push to main and version tags (v*).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use `/review-dep-pr` to review Dependabot PRs before merging.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Commits: <type>: <description> — types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen (commit-msg hook). Signed commits: required on main via branch protection — all commits must be GPG/SSH signed.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/finalize-release.yml : Finalize Release workflow: publishes draft releases created by Release Please. Triggers on workflow_run completion of Docker and CLI workflows. Verifies both workflows succeeded for the associated tag before publishing. Extracts CLI checksums, cosign verification, and container verification data from HTML comments, assembles into combined Verification section. Guards against PR-triggered runs. Handles TOCTOU races. Immutable releases enabled—once published, release assets and body cannot be modified.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to .github/workflows/**/*.yml : Path filtering: dorny/paths-filter detects Python/dashboard/docker changes; jobs only run when their domain is affected. CLI has its own workflow (cli.yml).
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.

Applied to files:

  • cli/internal/selfupdate/updater.go
🧬 Code graph analysis (1)
cli/internal/selfupdate/updater.go (1)
cli/internal/version/version.go (1)
  • Version (9-9)
🔇 Additional comments (8)
cli/internal/selfupdate/updater.go (8)

247-260: Silent fallback for malformed .dev tags.

This was previously flagged. The function silently returns -1 (treating as non-dev) when parsing fails for malformed tags like v0.4.7.dev or v0.4.7.devABC. While defensive, consider logging a warning to aid debugging malformed release tags.


46-50: LGTM! Shared HTTP client for connection reuse.

This addresses the previous review feedback about reusing http.Client for connection pooling. The separation between apiClient (30s timeout for metadata) and the download client (5m timeout) is well-designed.


74-96: LGTM! Clean channel routing and struct design.

The CheckForChannel router and devRelease struct provide a clean abstraction for handling both stable and dev channels.


98-139: LGTM! Well-structured dev channel logic.

Good separation with CheckDevFromURL for testability. Error handling covers edge cases (empty releases, selection failure, version comparison).


141-180: LGTM! Robust release selection logic.

All edge cases are handled correctly:

  • Both nil → error
  • Only dev/only stable → returns available one
  • Both exist → prefers stable if newer or equal

The documented reliance on GitHub API ordering (newest-first) is a reasonable assumption for this use case.


182-217: LGTM! Clean generic JSON fetcher.

Good practices throughout:

  • Shared client for connection reuse
  • User-Agent header for API calls
  • Explicit rate limit handling (403/429)
  • Bounded reads with LimitReader
  • Consistent error wrapping

219-245: LGTM! Correct dev-aware version comparison.

The ordering logic is sound: stable release beats dev release of same base version, and higher dev numbers beat lower ones. The documented comparison order (v0.4.7 > v0.4.7.dev3 > v0.4.7.dev2 > v0.4.6) is correctly implemented.


262-305: LGTM! Clean dev-aware update logic and refactoring.

isDevUpdateAvailable correctly handles the "dev" placeholder version (always offers updates for dev builds). The CheckFromURL refactoring via fetchReleasefetchJSON[Release] cleanly reduces duplication while maintaining equivalent behavior to the previous implementation.


Walkthrough

Adds a GitHub Actions workflow .github/workflows/dev-release.yml that creates incremental PEP 440 dev pre-releases (e.g., v0.4.6.dev3) on pushes to main, computing dev numbers from commits since the latest stable tag, skipping release-bump commits and existing stable tags, and pruning older dev pre-releases. Adjusts .github/workflows/docker.yml to emit a dev rolling image tag for .dev refs and skip semver tags for .dev refs. Updates finalize-release.yml to skip publishing for .dev branches. Adds CLI persistent channel (stable/dev), channel-aware self-update logic, related tests, and documentation updates.

Suggested labels

autorelease: tagged

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding dev channel builds with incremental PEP 440 pre-releases between stable releases, which is the primary objective.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, covering dev-release workflow, Docker workflow changes, CLI config features, and documentation updates.
Linked Issues check ✅ Passed The PR implements all major requirements from issue #713: dev-release.yml workflow with PEP 440 versioning, Docker tag strategy (dev rolling + specific), GitHub pre-releases with cleanup, CLI channel config with validation, and dev-aware update checks.
Out of Scope Changes check ✅ Passed All changes align with issue #713 scope: dev-release workflow, Docker/finalize-release updates for dev tags, CLI channel config with update checks, and documentation. No unrelated changes detected.
Docstring Coverage ✅ Passed Docstring coverage is 41.30% which is sufficient. The required threshold is 40.00%.

✏️ 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.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a new 'dev' update channel for the synthorg CLI, enabling users to access pre-release builds with the latest features and fixes. It automates the creation and management of these dev releases, integrating them into the existing Docker and CLI workflows. The changes also include CLI configuration updates and version comparison logic to handle dev releases correctly.

Highlights

  • Dev Channel Builds: Introduces a 'dev' update channel, allowing users to receive pre-release builds between stable releases.
  • Automated Dev Releases: Automates the creation of dev pre-releases on every push to the main branch, including Docker images, CLI binaries, and signatures.
  • CLI Configuration: Adds a channel configuration option to the CLI, enabling users to switch between 'stable' and 'dev' update channels.
  • Version Comparison: Implements dev-aware version comparison logic to ensure stable releases are preferred over dev releases when available.
Ignored Files
  • Ignored by pattern: .github/workflows/** (3)
    • .github/workflows/dev-release.yml
    • .github/workflows/docker.yml
    • .github/workflows/finalize-release.yml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@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: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/dev-release.yml:
- Around line 114-131: If the tag creation (gh api creating refs/tags/$DEV_TAG)
succeeds but gh release create "$DEV_TAG" fails, ensure you remove the orphaned
tag on failure: run a cleanup step that deletes refs/tags/$DEV_TAG via the
GitHub API (the same gh api endpoint but with DELETE) when gh release create
returns non-zero (implement with a conditional check or a trap so it runs on
error). Update the workflow around the gh api
"repos/$GITHUB_REPOSITORY/git/refs" and gh release create "$DEV_TAG" steps to
perform the delete cleanup (or roll both actions into an atomic procedure using
a trap) so dangling tags are removed on partial failure.

In `@cli/internal/config/state.go`:
- Around line 165-167: In validate(), add a check for the LogLevel field similar
to the Channel check: if s.LogLevel != "" && !IsValidLogLevel(s.LogLevel) then
return a formatted error (e.g., "invalid log level %q: must be one of %s") using
sortedKeys(validLogLevels); target the validate() method and reference
s.LogLevel, IsValidLogLevel, and validLogLevels to locate and implement the
guard.
- Around line 106-123: The validation map validLogLevels is using "warning" but
the rest of the code (including generate.go's allowedLogLevels and tests) expect
"warn", causing validation mismatch; update the validLogLevels declaration to
use "warn" instead of "warning" so IsValidLogLevel and LogLevelNames align with
generate.go and the rest of the system (leave sortedKeys and related functions
unchanged).

In `@cli/internal/selfupdate/updater.go`:
- Around line 236-249: The splitDev function currently swallows malformed ".dev"
suffixes (e.g., "v0.4.7.dev" or "v0.4.7.devABC") by returning -1 as if there is
no dev tag; change splitDev to surface that parsing failure by returning an
additional error (signature splitDev(v string) (devNum int, base string, err
error)) or at minimum emit a warning via the existing logger when
strconv.Atoi(numStr) fails or when numStr is empty. Update callers to handle the
returned error (or ignore after logging) and ensure the function still returns
base correctly on success; reference splitDev, numStr and the strconv.Atoi call
when making the change.
🪄 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: de11c498-55c7-4fad-8623-25c6e0915919

📥 Commits

Reviewing files that changed from the base of the PR and between dc6bd3f and 60f3eb0.

📒 Files selected for processing (11)
  • .github/workflows/dev-release.yml
  • .github/workflows/docker.yml
  • .github/workflows/finalize-release.yml
  • CLAUDE.md
  • README.md
  • cli/cmd/config.go
  • cli/cmd/status.go
  • cli/cmd/update.go
  • cli/internal/config/state.go
  • cli/internal/selfupdate/updater.go
  • cli/internal/selfupdate/updater_version_test.go
📜 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: CLI Test (windows-latest)
  • GitHub Check: CLI Test (macos-latest)
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Web
  • GitHub Check: Build Backend
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
cli/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

Use Cobra framework for CLI commands and charmbracelet libraries (huh, lipgloss) for interactive UI

Files:

  • cli/cmd/status.go
  • cli/cmd/update.go
  • cli/internal/selfupdate/updater_version_test.go
  • cli/cmd/config.go
  • cli/internal/config/state.go
  • cli/internal/selfupdate/updater.go
cli/**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

Use native testing.F fuzz functions for Go fuzzing (e.g., FuzzYamlStr)

Files:

  • cli/internal/selfupdate/updater_version_test.go
🧠 Learnings (30)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/docker.yml : Docker workflow: builds backend + web + sandbox images, pushes to GHCR, signs with cosign. SLSA L3 provenance attestations via actions/attest-build-provenance. Scans: Trivy (CRITICAL = hard fail, HIGH = warn) + Grype (critical cutoff) + CIS Docker Benchmark v1.6.0 compliance (informational). CVE triage via .github/.trivyignore.yaml and .github/.grype.yaml. Images only pushed after scans pass. Triggers on push to main and version tags (v*).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use `/review-dep-pr` to review Dependabot PRs before merging.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: CLI workflow (`.github/workflows/cli.yml`) runs Go lint (golangci-lint + go vet) + test (race, coverage) + build (cross-compile matrix) + vulnerability check (govulncheck) + fuzz testing. Cross-compiles for linux/darwin/windows × amd64/arm64. GoReleaser release on v* tags with cosign keyless signing and SLSA L3 attestations.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Commits: <type>: <description> — types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen (commit-msg hook). Signed commits: required on main via branch protection — all commits must be GPG/SSH signed.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/finalize-release.yml : Finalize Release workflow: publishes draft releases created by Release Please. Triggers on workflow_run completion of Docker and CLI workflows. Verifies both workflows succeeded for the associated tag before publishing. Extracts CLI checksums, cosign verification, and container verification data from HTML comments, assembles into combined Verification section. Guards against PR-triggered runs. Handles TOCTOU races. Immutable releases enabled—once published, release assets and body cannot be modified.
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docker/Dockerfile.sandbox : Docker sandbox: `synthorg-sandbox` — Python 3.14 + Node.js + git, non-root (UID 10001), agent code execution sandbox

Applied to files:

  • README.md
  • CLAUDE.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...

Applied to files:

  • README.md
  • CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).

Applied to files:

  • cli/cmd/status.go
  • cli/cmd/update.go
  • CLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/go.mod : Go CLI dependencies: Go 1.26+, Cobra (commands), charmbracelet/huh (interactive CLI), charmbracelet/lipgloss (styled output).

Applied to files:

  • cli/cmd/status.go
  • CLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/finalize-release.yml : Finalize Release workflow: publishes draft releases created by Release Please. Triggers on workflow_run completion of Docker and CLI workflows. Verifies both workflows succeeded for the associated tag before publishing. Extracts CLI checksums, cosign verification, and container verification data from HTML comments, assembles into combined Verification section. Guards against PR-triggered runs. Handles TOCTOU races. Immutable releases enabled—once published, release assets and body cannot be modified.

Applied to files:

  • .github/workflows/finalize-release.yml
  • CLAUDE.md
  • .github/workflows/docker.yml
  • .github/workflows/dev-release.yml
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use `/review-dep-pr` to review Dependabot PRs before merging.

Applied to files:

  • .github/workflows/finalize-release.yml
  • CLAUDE.md
  • .github/workflows/docker.yml
  • .github/workflows/dev-release.yml
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to .github/workflows/**/*.yml : Path filtering: dorny/paths-filter detects Python/dashboard/docker changes; jobs only run when their domain is affected. CLI has its own workflow (cli.yml).

Applied to files:

  • .github/workflows/finalize-release.yml
  • CLAUDE.md
  • .github/workflows/docker.yml
  • .github/workflows/dev-release.yml
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.

Applied to files:

  • .github/workflows/finalize-release.yml
  • CLAUDE.md
  • .github/workflows/dev-release.yml
📚 Learning: 2026-03-15T12:00:18.113Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).

Applied to files:

  • .github/workflows/finalize-release.yml
  • CLAUDE.md
  • .github/workflows/docker.yml
  • .github/workflows/dev-release.yml
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/docker.yml : Docker workflow: builds backend + web + sandbox images, pushes to GHCR, signs with cosign. SLSA L3 provenance attestations via actions/attest-build-provenance. Scans: Trivy (CRITICAL = hard fail, HIGH = warn) + Grype (critical cutoff) + CIS Docker Benchmark v1.6.0 compliance (informational). CVE triage via .github/.trivyignore.yaml and .github/.grype.yaml. Images only pushed after scans pass. Triggers on push to main and version tags (v*).

Applied to files:

  • .github/workflows/finalize-release.yml
  • CLAUDE.md
  • .github/workflows/docker.yml
  • .github/workflows/dev-release.yml
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: CLI workflow (`.github/workflows/cli.yml`) runs Go lint (golangci-lint + go vet) + test (race, coverage) + build (cross-compile matrix) + vulnerability check (govulncheck) + fuzz testing. Cross-compiles for linux/darwin/windows × amd64/arm64. GoReleaser release on v* tags with cosign keyless signing and SLSA L3 attestations.

Applied to files:

  • .github/workflows/finalize-release.yml
  • CLAUDE.md
  • .github/workflows/dev-release.yml
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.

Applied to files:

  • CLAUDE.md
  • .github/workflows/docker.yml
📚 Learning: 2026-03-15T16:38:08.735Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T16:38:08.735Z
Learning: Applies to docker/** : Docker build context: single root .dockerignore (both images build with context: .). Tags: CI tags images with version from pyproject.toml ([tool.commitizen].version), semver, and SHA.

Applied to files:

  • CLAUDE.md
  • .github/workflows/docker.yml
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Applies to docker/Dockerfile* : All Docker images must use Chainguard distroless (backend), nginx-unprivileged (web), or Python + Node.js (sandbox) with non-root users

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docker/Dockerfile : Docker: 3-stage build (builder → setup → distroless runtime) for backend, Chainguard Python, non-root (UID 65532), CIS-hardened

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Sign container images with cosign and generate SLSA L3 provenance in Docker build workflow

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to docker/Dockerfile.web : `nginxinc/nginx-unprivileged` base with non-root user (UID 101), Vue 3 SPA (PrimeVue + Tailwind CSS), SPA routing, API/WebSocket proxy to backend

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Applies to cli/**/*.go : Use Cobra framework for CLI commands and charmbracelet libraries (huh, lipgloss) for interactive UI

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-16T19:52:03.656Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T19:52:03.656Z
Learning: Applies to cli/**/*.go : Lint CLI Go code with golangci-lint and go vet; test with go test -race; check vulnerabilities with govulncheck

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T20:45:14.430Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T20:45:14.430Z
Learning: Shell commands: for Go CLI work, cd cli is an exception because Go tooling requires working directory to be the module root. Go commands require `cd cli` for other work, never use `cd`.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Run Go commands from `cli/` directory as the working directory since Go module is in `cli/` (exception to no-cd rule)

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Run Go lint via `golangci-lint run`, vet via `go vet`, tests via `go test ./...`, and fuzz via `go test -fuzz=FuzzTarget -fuzztime=30s`

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to cli/**/*.go : Lint Go code with `golangci-lint` and `go vet`. Run tests with `-race` flag to detect race conditions.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Add `Release-As: <version>` trailer as the final paragraph of PR body (separated by blank line) to override version bumping in Release Please

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Version locations: `pyproject.toml` (`[tool.commitizen].version`) and `src/synthorg/__init__.py` (`__version__`)

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T12:00:18.113Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Commits: <type>: <description> — types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen (commit-msg hook). Signed commits: required on main via branch protection — all commits must be GPG/SSH signed.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Pre-commit hooks: trailing-whitespace, end-of-file-fixer, check-yaml, check-toml, check-json, check-merge-conflict, check-added-large-files, no-commit-to-branch (main), ruff check+format, gitleaks, hadolint (Dockerfile linting).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Dependabot: auto-updates Docker image digests and versions daily.

Applied to files:

  • .github/workflows/docker.yml
🧬 Code graph analysis (4)
cli/cmd/update.go (3)
cli/internal/config/state.go (1)
  • Load (64-102)
web/src/api/types.ts (1)
  • Channel (591-595)
cli/internal/selfupdate/updater.go (1)
  • CheckForChannel (70-75)
cli/cmd/config.go (1)
cli/internal/config/state.go (6)
  • Load (64-102)
  • IsValidChannel (110-112)
  • ChannelNames (115-115)
  • IsValidLogLevel (118-120)
  • LogLevelNames (123-123)
  • Save (218-232)
cli/internal/config/state.go (1)
web/src/api/types.ts (1)
  • Channel (591-595)
cli/internal/selfupdate/updater.go (1)
cli/internal/version/version.go (1)
  • Version (9-9)
🔇 Additional comments (29)
cli/cmd/status.go (1)

76-81: LGTM!

The channel display integrates cleanly with existing version info output, using the DisplayChannel() helper for consistent formatting.

README.md (1)

105-105: LGTM!

Clear documentation of the new dev channel opt-in command with a concise explanatory comment.

.github/workflows/finalize-release.yml (1)

24-31: LGTM!

The guard correctly excludes dev pre-releases from finalization. Dev pre-releases are created as non-draft by dev-release.yml and don't require this workflow's verification assembly step.

cli/cmd/update.go (1)

112-124: LGTM!

The channel-aware update logic correctly:

  1. Defaults to "stable" when config load fails or channel is empty
  2. Provides user feedback when checking the dev channel
  3. Routes through CheckForChannel which handles the stable/dev branching
CLAUDE.md (4)

98-98: LGTM!

Docker tag documentation accurately reflects the new dev version scheme and rolling dev tag.


134-134: LGTM!

CLI command list updated to include the new config command.


226-226: LGTM!

Clear documentation of the dev channel workflow and opt-in mechanism.


245-246: LGTM!

CI documentation accurately describes the new dev-release.yml workflow behavior and the updated finalize-release.yml guard.

.github/workflows/docker.yml (3)

93-94: LGTM!

The tagging logic correctly:

  1. Excludes major.minor semver tags for dev builds (prevents dev releases from overwriting stable minor tags)
  2. Adds a rolling dev tag for dev pre-releases

282-283: LGTM!

Consistent tagging logic applied to the web image.


467-468: LGTM!

Consistent tagging logic applied to the sandbox image.

cli/internal/selfupdate/updater_version_test.go (1)

43-140: LGTM!

Comprehensive table-driven tests for the dev version comparison logic:

  • TestSplitDev: covers numeric dev suffixes, empty/invalid suffixes, and stable versions
  • TestCompareWithDev: validates ordering rules between stable and dev releases
  • TestIsDevUpdateAvailable: confirms update availability semantics (stable beats same-base dev, higher base dev is an update, etc.)
cli/cmd/config.go (3)

32-47: LGTM!

The config set command is well-structured with clear documentation of supported keys and their valid values.


77-77: LGTM!

Channel display added consistently with other config fields.


93-123: LGTM!

The runConfigSet handler correctly:

  1. Validates keys against an explicit allowlist with helpful error messages
  2. Uses config.IsValidChannel/IsValidLogLevel for value validation
  3. Includes valid options in error messages via ChannelNames()/LogLevelNames()
  4. Persists changes atomically via config.Save
cli/internal/config/state.go (3)

19-19: LGTM!

The new Channel field is correctly added to the State struct with appropriate JSON serialization tag.


39-39: LGTM!

Defaulting to "stable" aligns with the design where users must explicitly opt-in to the dev channel.


49-55: LGTM!

DisplayChannel() correctly provides backward compatibility by defaulting empty channels to "stable", which handles existing config files gracefully during migration.

.github/workflows/dev-release.yml (6)

12-16: LGTM!

Empty top-level permissions with job-scoped contents: write follows least-privilege principle. The concurrency group with cancel-in-progress: true correctly prevents race conditions on rapid pushes to main.


32-35: LGTM!

fetch-depth: 0 is required for git describe and git rev-list to work correctly. persist-credentials: false is a good security practice.


37-48: LGTM!

Correctly skips dev release creation when a stable tag already points at HEAD, preventing duplicate releases.


91-102: LGTM!

Idempotency check prevents re-creating existing dev tags on workflow re-runs.


140-147: LGTM!

The cleanup logic correctly implements the "keep last 5 dev pre-releases" policy from the PR objectives. Using --cleanup-tag ensures both the release and its associated tag are removed.


55-61: No action needed. The --match pattern correctly excludes dev tags.

The glob pattern v[0-9]*.[0-9]*.[0-9]* matches three version components separated by literal dots, where [0-9]* restricts each component to digits only. This correctly excludes tags like v0.4.7.dev1 since .dev1 does not match the digit-only requirement of the final [0-9]*. The code works as intended without modification.

			> Likely an incorrect or invalid review comment.
cli/internal/selfupdate/updater.go (5)

27-33: LGTM!

Constants are well-defined with clear documentation. The devReleasesURL correctly uses per_page=20 to fetch recent releases including pre-releases.


67-75: LGTM!

Clean channel-based routing. Defaulting unknown channels to stable is safe behavior.


110-126: LGTM!

The logic correctly identifies dev pre-releases (both Prerelease flag AND .dev in tag name), distinguishing them from other pre-release types like RCs. Draft releases are properly excluded.


170-206: LGTM!

Well-implemented generic HTTP helper with proper rate-limit handling, User-Agent header (per PR objectives), and response size limiting.


264-294: LGTM!

Clean refactor that leverages the new generic fetchJSON helper while maintaining the stable update check logic.

Comment on lines +236 to +249
// splitDev splits "0.4.7.dev3" into (3, "0.4.7") or (-1, "0.4.7") if no .dev suffix.
func splitDev(v string) (devNum int, base string) {
idx := strings.Index(v, ".dev")
if idx < 0 {
return -1, v
}
base = v[:idx]
numStr := v[idx+4:] // skip ".dev"
n, err := strconv.Atoi(numStr)
if err != nil {
return -1, v
}
return release, nil
return n, base
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Silent fallback in splitDev may mask malformed dev tags.

When parsing fails (e.g., v0.4.7.dev without a number, or v0.4.7.devABC), the function silently returns -1 treating it as a non-dev version. While this is defensive, consider logging a warning or returning an error to aid debugging malformed release tags.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cli/internal/selfupdate/updater.go` around lines 236 - 249, The splitDev
function currently swallows malformed ".dev" suffixes (e.g., "v0.4.7.dev" or
"v0.4.7.devABC") by returning -1 as if there is no dev tag; change splitDev to
surface that parsing failure by returning an additional error (signature
splitDev(v string) (devNum int, base string, err error)) or at minimum emit a
warning via the existing logger when strconv.Atoi(numStr) fails or when numStr
is empty. Update callers to handle the returned error (or ignore after logging)
and ensure the function still returns base correctly on success; reference
splitDev, numStr and the strconv.Atoi call when making the change.

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 introduces a 'dev' update channel for pre-release builds, a significant feature enhancement. The implementation is of high quality, with good refactoring (e.g., generic fetchJSON) and thorough testing. The changes are comprehensive, affecting CI/CD, Docker, and the CLI. I have a couple of suggestions to improve configuration handling robustness and maintainability.

}
state.LogLevel = value
default:
return fmt.Errorf("unknown config key %q (supported: channel, log_level)", key)
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

The list of supported keys is hardcoded in this error message. This could become out of sync if more keys are added to the switch statement. To improve maintainability, you could refactor this to use a map of handlers for each key. This would provide a single source of truth for supported keys and their validation logic, and the error message could be generated dynamically from the map's keys.

Comment on lines +165 to +167
if s.Channel != "" && !IsValidChannel(s.Channel) {
return fmt.Errorf("invalid channel %q: must be one of %s", s.Channel, sortedKeys(validChannels))
}
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

You've added validation for the channel field in config.Load, which is great for robustness. To be consistent, you should also validate the log_level field here. Currently, an invalid log_level in config.json would be loaded without error, whereas synthorg config set correctly validates it. Adding validation in State.validate() ensures that the configuration is always valid, regardless of how it's modified.

Suggested change
if s.Channel != "" && !IsValidChannel(s.Channel) {
return fmt.Errorf("invalid channel %q: must be one of %s", s.Channel, sortedKeys(validChannels))
}
if s.Channel != "" && !IsValidChannel(s.Channel) {
return fmt.Errorf("invalid channel %q: must be one of %s", s.Channel, sortedKeys(validChannels))
}
if !IsValidLogLevel(s.LogLevel) {
return fmt.Errorf("invalid log_level %q: must be one of %s", s.LogLevel, LogLevelNames())
}

Aureliolo and others added 3 commits March 22, 2026 13:55
… releases

Add a dev-release workflow that creates PEP 440 dev versions (v0.4.7.dev1,
v0.4.7.dev2, etc.) on every push to main between stable releases. Dev builds
get full pipeline treatment: Docker images, CLI binaries, cosign signatures,
and SLSA provenance -- triggered by creating proper v* tags that the existing
Docker and CLI workflows already handle.

CLI changes:
- Add Channel config field ("stable" / "dev") with validation
- Add CheckDev/CheckForChannel to selfupdate with dev-aware version comparison
- Add `synthorg config set channel dev` command
- Show channel in `synthorg status` and `synthorg config show`

Workflow changes:
- New dev-release.yml: compute dev version, create tag + pre-release, cleanup
- docker.yml: add rolling `dev` tag for dev builds
- finalize-release.yml: guard against publishing dev pre-releases

Closes #713

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pre-reviewed by 4 agents (go-reviewer, infra-reviewer, security-reviewer,
docs-consistency), 18 findings addressed:

Workflow fixes:
- Use GitHub API for tag creation instead of git push (persist-credentials: false)
- Add concurrency group to prevent race between parallel dev-release runs
- Fix expression injection: use env vars instead of inline ${{ }} in run steps
- Add explicit sort for dev release cleanup robustness
- Tighten dev tag enable expression to require refs/tags/v prefix

Go fixes:
- Add log_level validation with allowlist (was accepting arbitrary values)
- Replace duplicate fetchDevReleases/fetchRelease with generic fetchJSON[T]
- Surface compareWithDev errors instead of silently swallowing them
- Add User-Agent header to GitHub API requests
- Unexport DevReleasesURL (only used internally)
- Extract DisplayChannel() helper to deduplicate channel fallback logic
- Add rate-limit-aware error messages for 403/429 responses

Tests:
- Add table-driven tests for splitDev, compareWithDev, isDevUpdateAvailable

Docs:
- CLAUDE.md: add dev-release workflow, dev channel, config command, dev tags
- README.md: add config command to quick start

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Guard Docker app_version tag against dev builds (prevents overwriting
  stable image tags)
- Fix git describe to exclude dev tags via grep filter (prevents broken
  version computation after first dev release)
- Use atomic gh release create --target instead of separate tag + release
  API calls (prevents orphaned tags on partial failure)
- Fix validLogLevels to use "warn" instead of "warning" (aligns with
  compose/generate.go's allowedLogLevels)
- Add LogLevel validation to config validate() (catches invalid values
  on config load, not just config set)
- Extract selectBestRelease and resolveUpdateChannel helpers (functions
  exceeded 50-line limit)
- Make config set error message dynamic via supportedConfigKeys slice
- Add error path tests for compareWithDev and isDevUpdateAvailable
- Add unit tests for IsValidChannel, IsValidLogLevel, DisplayChannel
- Add config set command tests (valid channel, invalid channel, unknown key)
- Add integration tests for CheckDevFromURL with mocked HTTP server
- Add rate-limit (403) response test for fetchJSON
- Update docs: user_guide.md (config command, dev channel), operations.md
  (channel-aware update), tech-stack.md (dev channel mention)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Aureliolo Aureliolo force-pushed the feat/dev-channel-builds branch from 60f3eb0 to 5749d59 Compare March 22, 2026 13:01
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 22, 2026 13:02 — with GitHub Actions Inactive
Copy link
Copy Markdown

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cli/internal/selfupdate/updater.go`:
- Around line 177-179: fetchJSON currently creates a new http.Client on each
call which prevents connection reuse; change it to use a shared client by either
introducing a package-level variable (e.g. var httpClient =
&http.Client{Timeout: 30 * time.Second}) or by adding an http.Client parameter
to fetchJSON so callers can pass a reused client; update references to fetchJSON
accordingly and ensure the timeout is set on the shared client or preserved by
callers.
🪄 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: 1b3c8af3-c4fc-42f0-9754-f97c1cf1c312

📥 Commits

Reviewing files that changed from the base of the PR and between 60f3eb0 and 5749d59.

📒 Files selected for processing (17)
  • .github/workflows/dev-release.yml
  • .github/workflows/docker.yml
  • .github/workflows/finalize-release.yml
  • CLAUDE.md
  • README.md
  • cli/cmd/config.go
  • cli/cmd/config_test.go
  • cli/cmd/status.go
  • cli/cmd/update.go
  • cli/internal/config/state.go
  • cli/internal/config/state_test.go
  • cli/internal/selfupdate/updater.go
  • cli/internal/selfupdate/updater_test.go
  • cli/internal/selfupdate/updater_version_test.go
  • docs/architecture/tech-stack.md
  • docs/design/operations.md
  • docs/user_guide.md
📜 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). (5)
  • GitHub Check: CLI Test (windows-latest)
  • GitHub Check: Build Backend
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Web
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
cli/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

Use Cobra framework for CLI commands and charmbracelet libraries (huh, lipgloss) for interactive UI

Files:

  • cli/cmd/status.go
  • cli/cmd/update.go
  • cli/internal/selfupdate/updater_test.go
  • cli/cmd/config_test.go
  • cli/internal/config/state.go
  • cli/internal/config/state_test.go
  • cli/internal/selfupdate/updater.go
  • cli/internal/selfupdate/updater_version_test.go
  • cli/cmd/config.go
cli/**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

Use native testing.F fuzz functions for Go fuzzing (e.g., FuzzYamlStr)

Files:

  • cli/internal/selfupdate/updater_test.go
  • cli/cmd/config_test.go
  • cli/internal/config/state_test.go
  • cli/internal/selfupdate/updater_version_test.go
🧠 Learnings (40)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: CLI workflow (`.github/workflows/cli.yml`) runs Go lint (golangci-lint + go vet) + test (race, coverage) + build (cross-compile matrix) + vulnerability check (govulncheck) + fuzz testing. Cross-compiles for linux/darwin/windows × amd64/arm64. GoReleaser release on v* tags with cosign keyless signing and SLSA L3 attestations.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/docker.yml : Docker workflow: builds backend + web + sandbox images, pushes to GHCR, signs with cosign. SLSA L3 provenance attestations via actions/attest-build-provenance. Scans: Trivy (CRITICAL = hard fail, HIGH = warn) + Grype (critical cutoff) + CIS Docker Benchmark v1.6.0 compliance (informational). CVE triage via .github/.trivyignore.yaml and .github/.grype.yaml. Images only pushed after scans pass. Triggers on push to main and version tags (v*).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use `/review-dep-pr` to review Dependabot PRs before merging.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/finalize-release.yml : Finalize Release workflow: publishes draft releases created by Release Please. Triggers on workflow_run completion of Docker and CLI workflows. Verifies both workflows succeeded for the associated tag before publishing. Extracts CLI checksums, cosign verification, and container verification data from HTML comments, assembles into combined Verification section. Guards against PR-triggered runs. Handles TOCTOU races. Immutable releases enabled—once published, release assets and body cannot be modified.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to .github/workflows/**/*.yml : Path filtering: dorny/paths-filter detects Python/dashboard/docker changes; jobs only run when their domain is affected. CLI has its own workflow (cli.yml).
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docker/Dockerfile.sandbox : Docker sandbox: `synthorg-sandbox` — Python 3.14 + Node.js + git, non-root (UID 10001), agent code execution sandbox

Applied to files:

  • README.md
  • docs/user_guide.md
  • CLAUDE.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...

Applied to files:

  • README.md
  • docs/architecture/tech-stack.md
  • docs/user_guide.md
  • CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).

Applied to files:

  • cli/cmd/status.go
  • cli/cmd/update.go
  • CLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/go.mod : Go CLI dependencies: Go 1.26+, Cobra (commands), charmbracelet/huh (interactive CLI), charmbracelet/lipgloss (styled output).

Applied to files:

  • cli/cmd/status.go
  • CLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/finalize-release.yml : Finalize Release workflow: publishes draft releases created by Release Please. Triggers on workflow_run completion of Docker and CLI workflows. Verifies both workflows succeeded for the associated tag before publishing. Extracts CLI checksums, cosign verification, and container verification data from HTML comments, assembles into combined Verification section. Guards against PR-triggered runs. Handles TOCTOU races. Immutable releases enabled—once published, release assets and body cannot be modified.

Applied to files:

  • .github/workflows/finalize-release.yml
  • CLAUDE.md
  • .github/workflows/docker.yml
  • .github/workflows/dev-release.yml
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.

Applied to files:

  • .github/workflows/finalize-release.yml
  • CLAUDE.md
  • .github/workflows/dev-release.yml
  • cli/internal/selfupdate/updater.go
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use `/review-dep-pr` to review Dependabot PRs before merging.

Applied to files:

  • .github/workflows/finalize-release.yml
  • CLAUDE.md
  • .github/workflows/docker.yml
  • .github/workflows/dev-release.yml
📚 Learning: 2026-03-15T12:00:18.113Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).

Applied to files:

  • .github/workflows/finalize-release.yml
  • CLAUDE.md
  • .github/workflows/docker.yml
  • .github/workflows/dev-release.yml
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/docker.yml : Docker workflow: builds backend + web + sandbox images, pushes to GHCR, signs with cosign. SLSA L3 provenance attestations via actions/attest-build-provenance. Scans: Trivy (CRITICAL = hard fail, HIGH = warn) + Grype (critical cutoff) + CIS Docker Benchmark v1.6.0 compliance (informational). CVE triage via .github/.trivyignore.yaml and .github/.grype.yaml. Images only pushed after scans pass. Triggers on push to main and version tags (v*).

Applied to files:

  • .github/workflows/finalize-release.yml
  • CLAUDE.md
  • .github/workflows/docker.yml
  • .github/workflows/dev-release.yml
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: CLI workflow (`.github/workflows/cli.yml`) runs Go lint (golangci-lint + go vet) + test (race, coverage) + build (cross-compile matrix) + vulnerability check (govulncheck) + fuzz testing. Cross-compiles for linux/darwin/windows × amd64/arm64. GoReleaser release on v* tags with cosign keyless signing and SLSA L3 attestations.

Applied to files:

  • .github/workflows/finalize-release.yml
  • docs/architecture/tech-stack.md
  • docs/design/operations.md
  • CLAUDE.md
  • .github/workflows/docker.yml
  • .github/workflows/dev-release.yml
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.

Applied to files:

  • docs/architecture/tech-stack.md
  • docs/design/operations.md
  • CLAUDE.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/security/**/*.py : Security package (security/): SecOps agent, rule engine (soft-allow/hard-deny, fail-closed), audit log, output scanner, output scan response policies (redact/withhold/log-only/autonomy-tiered), risk classifier, risk tier classifier, action type registry, ToolInvoker security integration, progressive trust (4 strategies), autonomy levels (presets, resolver, change strategy), timeout policies (park/resume)

Applied to files:

  • docs/architecture/tech-stack.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Documentation source in `docs/` (Markdown, built with Zensical). Design spec in `docs/design/` (7 pages: index, agents, organization, communication, engine, memory, operations). Architecture in `docs/architecture/` (overview, tech-stack, decision log). Roadmap in `docs/roadmap/`. Security in `docs/security.md`. Licensing in `docs/licensing.md`. Reference in `docs/reference/`. REST API reference in `docs/rest-api.md`. Library reference in `docs/api/` (auto-generated from docstrings). Custom templates in `docs/overrides/`. Config in `mkdocs.yml`.

Applied to files:

  • docs/architecture/tech-stack.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to go.mod : Maintain Go 1.26+ requirement. Dependencies: Cobra (CLI framework), charmbracelet/huh and charmbracelet/lipgloss (UI), sigstore-go (code signing), go-containerregistry (container image verification), go-tuf (TUF client for Sigstore).

Applied to files:

  • docs/architecture/tech-stack.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/api/**/*.py : API package (api/): Litestar REST + WebSocket with controllers, guards, channels, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint, provider management endpoint (CRUD + test + presets), backup endpoint, RFC 9457 structured errors, AppState hot-reload slots, service auto-wiring (Phase 1 at construction, Phase 2 on startup), lifecycle helpers

Applied to files:

  • docs/architecture/tech-stack.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.

Applied to files:

  • docs/architecture/tech-stack.md
  • docs/user_guide.md
  • CLAUDE.md
  • .github/workflows/docker.yml
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/security/**/*.py : Security module includes SecOps agent, rule engine (soft-allow/hard-deny), audit log, output scanner, risk classifier, autonomy levels (4 strategies), timeout policies.

Applied to files:

  • docs/architecture/tech-stack.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Security: SecOps agent, rule engine (soft-allow/hard-deny, fail-closed), audit log, output scanner, output scan response policies (redact/withhold/log-only/autonomy-tiered), risk classifier, risk tier classifier, action type registry, ToolInvoker security integration, progressive trust (4 strategies: disabled/weighted/per-category/milestone), autonomy levels (presets, resolver, change strategy), timeout policies (park/resume).

Applied to files:

  • docs/architecture/tech-stack.md
📚 Learning: 2026-03-18T08:23:08.912Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T08:23:08.912Z
Learning: When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality.

Applied to files:

  • docs/design/operations.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality

Applied to files:

  • docs/design/operations.md
📚 Learning: 2026-03-15T16:38:08.735Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T16:38:08.735Z
Learning: Applies to docker/** : Docker build context: single root .dockerignore (both images build with context: .). Tags: CI tags images with version from pyproject.toml ([tool.commitizen].version), semver, and SHA.

Applied to files:

  • CLAUDE.md
  • .github/workflows/docker.yml
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Applies to docker/Dockerfile* : All Docker images must use Chainguard distroless (backend), nginx-unprivileged (web), or Python + Node.js (sandbox) with non-root users

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docker/Dockerfile : Docker: 3-stage build (builder → setup → distroless runtime) for backend, Chainguard Python, non-root (UID 65532), CIS-hardened

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Sign container images with cosign and generate SLSA L3 provenance in Docker build workflow

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to docker/Dockerfile.web : `nginxinc/nginx-unprivileged` base with non-root user (UID 101), Vue 3 SPA (PrimeVue + Tailwind CSS), SPA routing, API/WebSocket proxy to backend

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Applies to cli/**/*.go : Use Cobra framework for CLI commands and charmbracelet libraries (huh, lipgloss) for interactive UI

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-16T19:52:03.656Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T19:52:03.656Z
Learning: Applies to cli/**/*.go : Lint CLI Go code with golangci-lint and go vet; test with go test -race; check vulnerabilities with govulncheck

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T20:45:14.430Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T20:45:14.430Z
Learning: Shell commands: for Go CLI work, cd cli is an exception because Go tooling requires working directory to be the module root. Go commands require `cd cli` for other work, never use `cd`.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Run Go commands from `cli/` directory as the working directory since Go module is in `cli/` (exception to no-cd rule)

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Run Go lint via `golangci-lint run`, vet via `go vet`, tests via `go test ./...`, and fuzz via `go test -fuzz=FuzzTarget -fuzztime=30s`

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to cli/**/*.go : Lint Go code with `golangci-lint` and `go vet`. Run tests with `-race` flag to detect race conditions.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Add `Release-As: <version>` trailer as the final paragraph of PR body (separated by blank line) to override version bumping in Release Please

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Version locations: `pyproject.toml` (`[tool.commitizen].version`) and `src/synthorg/__init__.py` (`__version__`)

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T12:00:18.113Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Commits: <type>: <description> — types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen (commit-msg hook). Signed commits: required on main via branch protection — all commits must be GPG/SSH signed.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to .github/workflows/**/*.yml : Path filtering: dorny/paths-filter detects Python/dashboard/docker changes; jobs only run when their domain is affected. CLI has its own workflow (cli.yml).

Applied to files:

  • CLAUDE.md
  • .github/workflows/docker.yml
  • .github/workflows/dev-release.yml
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Pre-commit hooks: trailing-whitespace, end-of-file-fixer, check-yaml, check-toml, check-json, check-merge-conflict, check-added-large-files, no-commit-to-branch (main), ruff check+format, gitleaks, hadolint (Dockerfile linting).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Dependabot: auto-updates Docker image digests and versions daily.

Applied to files:

  • .github/workflows/docker.yml
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions.

Applied to files:

  • cli/internal/config/state.go
📚 Learning: 2026-03-15T21:49:53.264Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:49:53.264Z
Learning: Fix everything valid — never skip when review agents find valid issues (including pre-existing issues in surrounding code, suggestions, and findings adjacent to the PR's changes). No deferring, no 'out of scope' skipping.

Applied to files:

  • .github/workflows/dev-release.yml
🧬 Code graph analysis (7)
cli/cmd/update.go (2)
cli/internal/selfupdate/updater.go (1)
  • CheckForChannel (70-75)
cli/internal/config/state.go (1)
  • Load (64-102)
cli/internal/selfupdate/updater_test.go (1)
cli/internal/selfupdate/updater.go (2)
  • Asset (52-55)
  • CheckDevFromURL (99-132)
cli/cmd/config_test.go (3)
cli/internal/config/state.go (3)
  • DefaultState (35-47)
  • Save (221-235)
  • Load (64-102)
cli/internal/config/paths.go (1)
  • DataDir (18-31)
cli/cmd/root.go (1)
  • Execute (101-107)
cli/internal/config/state.go (1)
web/src/api/types.ts (1)
  • Channel (591-595)
cli/internal/config/state_test.go (1)
cli/internal/config/state.go (4)
  • IsValidChannel (110-112)
  • IsValidLogLevel (118-120)
  • State (16-30)
  • Load (64-102)
cli/internal/selfupdate/updater.go (1)
cli/internal/version/version.go (1)
  • Version (9-9)
cli/cmd/config.go (1)
cli/internal/config/state.go (6)
  • Load (64-102)
  • IsValidChannel (110-112)
  • ChannelNames (115-115)
  • IsValidLogLevel (118-120)
  • LogLevelNames (123-123)
  • Save (221-235)
🔇 Additional comments (31)
README.md (1)

105-105: LGTM!

The documentation update correctly introduces the config set channel dev command to opt in to pre-release builds, with a clear inline comment explaining its purpose.

cli/cmd/status.go (1)

76-82: LGTM!

The channel display is cleanly integrated into printVersionInfo, maintaining consistency with the existing KeyValue output pattern. The use of DisplayChannel() correctly handles the fallback to "stable" when the channel is unset.

.github/workflows/finalize-release.yml (1)

24-31: LGTM!

The guard condition correctly excludes .dev tags from finalization. The combination of startsWith(head_branch, 'v') and !contains(head_branch, '.dev') properly distinguishes stable releases (e.g., v0.4.7) from dev pre-releases (e.g., v0.4.7.dev3). The added comments clearly document the rationale.

docs/architecture/tech-stack.md (1)

65-65: LGTM!

The tech stack documentation accurately describes the new channel selection feature alongside the existing CLI capabilities.

docs/design/operations.md (1)

1039-1048: LGTM!

The documentation accurately reflects the channel-aware update behavior (stable/dev) and the compose template refresh with diff approval. This aligns with the implementation in cli/cmd/update.go.

cli/cmd/update.go (2)

112-118: LGTM!

The channel-aware update check provides clear user feedback distinguishing between dev and stable channel checks. The conditional messaging improves transparency about which channel is being queried.


157-165: LGTM!

The resolveUpdateChannel function correctly implements a fail-safe pattern: if config loading fails or the channel is empty, it defaults to "stable". This ensures update checks can proceed even with configuration issues, while users explicitly on the dev channel receive dev updates.

cli/internal/selfupdate/updater_test.go (4)

826-853: LGTM!

Comprehensive test for dev channel release selection. Correctly validates that v0.4.7.dev3 is selected over v0.4.6 when the dev version is newer.


855-882: LGTM!

Good edge case coverage: validates that stable v0.4.7 is preferred over v0.4.7.dev3 when they share the same base version, ensuring users get stable releases when available.


884-899: LGTM!

Validates proper error handling when all releases are drafts, ensuring the function doesn't silently succeed with no valid release.


901-914: LGTM!

Good coverage for GitHub API rate limiting (HTTP 403). The assertion that the error contains "rate-limited" ensures user-friendly error messages.

docs/user_guide.md (1)

27-29: LGTM!

Clear and comprehensive documentation for the dev channel feature. The user guide properly explains:

  • How to opt in (synthorg config set channel dev)
  • What the dev channel provides (artifacts on every push to main)
  • How to switch back to stable

This gives users the information they need to make an informed choice about tracking pre-release builds.

.github/workflows/docker.yml (1)

91-95: LGTM! Dev channel tagging logic is consistent across all three images.

The gating correctly:

  • Excludes .dev refs from stable version tags (raw app_version) and semver major.minor tags
  • Enables the rolling dev tag only for .dev refs
  • Preserves type=semver,pattern={{version}} for .dev refs so the full dev version (e.g., 0.4.7.dev3) is tagged

Also applies to: 280-284, 465-469

CLAUDE.md (1)

98-98: LGTM! Documentation accurately reflects the new dev channel workflow.

The updates correctly document:

  • Dev tag format (v0.4.7.dev3) and rolling dev tag
  • New config command in CLI
  • Dev channel opt-in via synthorg config set channel dev
  • dev-release.yml behavior and automatic cleanup
  • finalize-release.yml skipping dev pre-releases

Also applies to: 134-134, 226-226, 245-246

cli/cmd/config_test.go (1)

117-178: Good test coverage for config set command.

The tests appropriately cover:

  • Successful persistence and reload verification
  • Invalid channel value rejection
  • Unknown key rejection

One minor consideration: The tests share rootCmd state via SetArgs/SetOut/SetErr. This is consistent with the existing tests in the file and appears safe since each test uses isolated temp directories.

cli/internal/selfupdate/updater_version_test.go (1)

43-142: Excellent table-driven test coverage for dev version semantics.

The tests comprehensively cover:

  • splitDev: Normal cases, edge cases (empty/non-numeric .dev suffix treated as stable)
  • compareWithDev: Ordering rules including "stable beats same-base dev", "higher base wins despite dev", error propagation
  • isDevUpdateAvailable: All update scenarios including the important "stable release is an update from dev" case (Line 121)

The sign-comparison pattern for wantCmp values is appropriate for comparison functions.

cli/cmd/config.go (1)

36-51: Clean implementation of config set command using Cobra patterns.

The implementation correctly:

  • Validates key against supportedConfigKeys with a clear error message
  • Validates values using config.IsValidChannel/config.IsValidLogLevel with valid options in error messages
  • Loads existing config, mutates, and persists via config.Save()
  • Provides user feedback via out.Success()

As per coding guidelines: Uses Cobra framework correctly for CLI commands.

Also applies to: 97-127

cli/internal/config/state.go (1)

19-19: LGTM! Channel field and validation properly implemented.

The implementation correctly:

  • Adds Channel field with JSON tag and "stable" default
  • Provides DisplayChannel() for safe display of empty values
  • Uses "warn" (not "warning") in validLogLevels to match actual system usage
  • Guards validation with empty-string checks so missing JSON fields use defaults

Past review concerns were addressed: log level validation uses "warn" and validate() now checks both Channel and LogLevel.

Also applies to: 39-39, 49-55, 106-123, 165-170

cli/internal/config/state_test.go (1)

207-305: Thorough test coverage for channel and log level validation.

The tests comprehensively verify:

  • IsValidChannel: Accepts only stable/dev, rejects empty/unknown/case-variants
  • IsValidLogLevel: Correctly rejects "warning" (system uses "warn"), case-sensitive
  • DisplayChannel(): Returns "stable" for empty values
  • Load() validation: Rejects invalid values, allows empty values (falls back to defaults via unmarshalling onto DefaultState())

The comment on Line 281 ("empty log level uses default from DefaultState") accurately explains the behavior.

.github/workflows/dev-release.yml (5)

1-16: Good workflow structure with proper permissions and concurrency.

  • permissions: {} at workflow level with contents: write only at job level follows least-privilege principle
  • concurrency: dev-release with cancel-in-progress: true prevents race conditions between rapid pushes
  • Pinned action SHA (actions/checkout@de0fac...) ensures reproducibility

24-48: Robust skip conditions for Release Please commits and existing stable tags.

The skip logic correctly handles:

  • Release Please version-bump merges (chore(main): release)
  • Commits with Release-As: trailer
  • Commits already tagged with a stable version (regex ^v[0-9]+\.[0-9]+\.[0-9]+$)

50-91: Version computation logic is sound.

The algorithm correctly:

  1. Finds last stable tag (excludes .dev tags via grep -vE)
  2. Gets next version from Release Please pending PR, or falls back to patch bump
  3. Counts commits since last stable tag for the dev number
  4. Skips gracefully when no commits exist since last tag

115-131: Atomic tag+release creation addresses prior review concern.

Using gh release create "$DEV_TAG" --target "$GITHUB_SHA" creates both the tag and release atomically. This approach is cleaner than the previously suggested cleanup-on-failure pattern, as it avoids orphaned tags entirely by not creating the tag separately.

This addresses the past review comment about partial failure leaving dangling tags.


132-146: Dev pre-release cleanup is well-implemented.

The cleanup logic:

  • Keeps the 5 most recent dev pre-releases (sorted by createdAt descending)
  • Uses --cleanup-tag to remove associated tags when deleting releases
  • Uses || true to continue on individual deletion failures

One consideration: if gh release list returns fewer than 50 releases, the jq filter safely handles this.

cli/internal/selfupdate/updater.go (7)

213-254: Version comparison logic is sound.

The compareWithDev function correctly implements the ordering: v0.4.7 > v0.4.7.dev3 > v0.4.7.dev2 > v0.4.6. The splitDev silent fallback for malformed dev tags was previously flagged as a nitpick.


27-43: LGTM!

Constants are well-organized. The per_page=20 is sufficient given the dev release cleanup policy keeps only 5 most recent dev pre-releases.


67-75: LGTM!

Clean dispatch function with clear documentation. The explicit "dev" check with implicit stable fallback aligns with the design goal of preferring stable by default.


83-132: LGTM!

Good use of generics with fetchJSON[[]devRelease]. The conversion to Release for findAssets reuses existing logic cleanly. Error handling is comprehensive.


145-153: Pre-releases without .dev suffix are silently skipped.

The condition r.Prerelease && strings.Contains(r.TagName, ".dev") means pre-releases like v0.5.0-alpha or v0.5.0-rc1 would be treated as neither dev nor stable, effectively ignored. This appears intentional per the PR objectives (only PEP 440 .devN format is supported), but worth confirming this is the desired behavior.


256-267: LGTM!

The special case for cur == "dev" correctly handles source builds where version.Version defaults to "dev", ensuring they always see updates as available.


269-299: LGTM!

Clean refactor leveraging the generic fetchJSON[Release]. The structure now mirrors CheckDevFromURL for consistency.

Replace per-call http.Client allocation with a package-level apiClient
(30s timeout). Keeps the download path's separate client with longer
timeout (5min) unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 22, 2026 13:10 — with GitHub Actions Inactive
@Aureliolo Aureliolo merged commit 0e8a714 into main Mar 22, 2026
47 checks passed
@Aureliolo Aureliolo deleted the feat/dev-channel-builds branch March 22, 2026 13:15
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 22, 2026 13:15 — with GitHub Actions Inactive
Aureliolo added a commit that referenced this pull request Mar 22, 2026
…716)

## Summary

- Tags created with the default `GITHUB_TOKEN` do not fire `push` events
for other workflows (GitHub Actions anti-recursion safeguard)
- The `v0.4.7.dev3` dev pre-release was created successfully but Docker
and CLI workflows never triggered
- Switch to `RELEASE_PLEASE_TOKEN` (PAT) for the `gh release create
--target` step so downstream workflows trigger on dev tags
- Cleanup step keeps using `github.token` since it doesn't need to
trigger anything

## Context

After merging #715, the dev-release workflow ran and created
`v0.4.7.dev3` correctly, but the Docker and CLI pipelines never fired.
This is the same pattern used by `release.yml` which uses a PAT for
Release Please to ensure tag-triggered workflows run.

## Test plan

- [ ] Push to main triggers `dev-release.yml`, creates dev tag +
pre-release
- [ ] Docker workflow triggers on the dev tag (was broken before this
fix)
- [ ] CLI workflow triggers on the dev tag (was broken before this fix)
- [ ] Finalize-release correctly skips dev pre-releases (unchanged)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Aureliolo added a commit that referenced this pull request Mar 22, 2026
#729)

## Summary

- Switch dev tag format from PEP 440 (`v0.4.7.dev3`) to semver
(`v0.4.7-dev.3`) so GoReleaser can parse them
- Create dev releases as **draft** pre-releases instead of published, so
they flow through the exact same finalize-release pipeline as stable
releases
- Remove the dev exclusion guard from finalize-release -- both stable
and dev releases now use the same lifecycle

## Why

After merging #715 and #716, the dev-release workflow correctly created
tags and triggered downstream pipelines, but both failed:
1. **CLI**: GoReleaser rejected `v0.4.7.dev4` as invalid semver (`failed
to parse tag as semver`)
2. **Docker**: SBOM attachment failed because dev releases were created
as published (immutable), blocking asset uploads

## How it works now

Same pipeline, zero special-casing:

1. `dev-release.yml` creates **draft** pre-release + tag (via PAT)
2. Docker workflow triggers on tag -- builds, scans, pushes, attaches
SBOMs to draft
3. CLI workflow triggers on tag -- GoReleaser builds binaries, attaches
to draft
4. `finalize-release.yml` publishes the draft once both succeed

This is identical to the stable release flow.

## Changes

- `dev-release.yml`: semver tag format (`-dev.N`), `--draft
--prerelease`, updated grep/jq filters
- `docker.yml`: `.dev` -> `-dev.` in all contains() checks
- `finalize-release.yml`: removed `!contains(.dev)` guard -- handles
both stable and dev
- `cli/internal/selfupdate/updater.go`: `splitDev` and
`selectBestRelease` parse `-dev.` format
- `cli/internal/selfupdate/updater_version_test.go`: all test cases
updated
- `cli/internal/selfupdate/updater_test.go`: integration test cases
updated
- `CLAUDE.md`: updated tag examples and descriptions
- Cleaned up old `v0.4.7.dev3` and `v0.4.7.dev4` releases/tags

## Test plan

- [ ] Push to main triggers `dev-release.yml`, creates `v0.4.7-dev.N`
tag + **draft** pre-release
- [ ] Docker workflow triggers, builds all 3 images, attaches SBOMs to
draft
- [ ] CLI workflow triggers, GoReleaser builds binaries, attaches to
draft
- [ ] `finalize-release` publishes the draft after both succeed
- [ ] `go test ./...` passes (verified locally)
- [ ] `synthorg update` on dev channel finds semver dev releases

Closes #713

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Aureliolo added a commit that referenced this pull request Mar 22, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.4.7](v0.4.6...v0.4.7)
(2026-03-22)


### Features

* add system user for CLI-to-backend authentication
([#710](#710))
([dc6bd3f](dc6bd3f))
* dev channel builds with incremental pre-releases between stable
releases ([#715](#715))
([0e8a714](0e8a714))
* replace hardcoded name pools with Faker multi-locale name generation
([#714](#714))
([5edc6ec](5edc6ec))


### Bug Fixes

* dev-release tag creation, dependabot coverage, go -C cli convention
([#730](#730))
([7634843](7634843))
* improve name generation step UX and fix sentinel expansion bug
([#739](#739))
([f03fd05](f03fd05))
* settings page UX polish -- toggle bug, source badges, form
improvements ([#712](#712))
([d16a0ac](d16a0ac))
* switch dev tags to semver and use same release pipeline as stable
([#729](#729))
([4df6b9b](4df6b9b)),
closes [#713](#713)
* unify CLI image discovery and standardize Go tooling
([#738](#738))
([712a785](712a785))
* use PAT in dev-release workflow to trigger downstream pipelines
([#716](#716))
([d767aa3](d767aa3))


### CI/CD

* bump astral-sh/setup-uv from 7.4.0 to 7.6.0 in
/.github/actions/setup-python-uv in the minor-and-patch group
([#731](#731))
([7887257](7887257))
* bump the minor-and-patch group with 3 updates
([#735](#735))
([7cd253a](7cd253a))
* bump wrangler from 4.75.0 to 4.76.0 in /.github in the minor-and-patch
group ([#732](#732))
([a6cafc7](a6cafc7))
* clean up all dev releases and tags on stable release
([#737](#737))
([8d90f5c](8d90f5c))


### Maintenance

* bump the minor-and-patch group across 2 directories with 2 updates
([#733](#733))
([2b60069](2b60069))
* bump the minor-and-patch group with 3 updates
([#734](#734))
([859bc25](859bc25))
* fix dependabot labels and add scope tags
([#736](#736))
([677eb15](677eb15))
* remove redundant pytest.mark.timeout(30) markers
([#740](#740))
([9ec2163](9ec2163))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
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.

feat: dev channel builds with incremental pre-releases between stable releases

1 participant