Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
dd2bbfd
chore(release): add Helm chart, Grafana dashboard, GoReleaser + workf…
flyingrobots Sep 12, 2025
37ca42d
docs: add evidence README; add confidence scores to promotion checkli…
flyingrobots Sep 12, 2025
605ea9d
chore(gitignore): ignore Obsidian (.obsidian) and refine VS Code rule…
flyingrobots Sep 12, 2025
66ca59a
chore(vscode): add minimal workspace settings and extension recommend…
flyingrobots Sep 12, 2025
8b6a17f
chore(license): add copyright header to all Go source files
flyingrobots Sep 12, 2025
d45946d
chore(ci,release): align Go toolchain to 1.25.x across workflows and …
flyingrobots Sep 12, 2025
8dac5ed
feat(admin): add purge-all command to clear queues, heartbeats, proce…
flyingrobots Sep 12, 2025
b223210
docs(evidence): add run_bench.sh harness and README usage
flyingrobots Sep 12, 2025
8ddbb5a
fix(breaker): enforce single probe in HalfOpen; count trips; improve …
flyingrobots Sep 12, 2025
207ca84
chore: remove CLAUDE-CODE-REVIEW.md from VCS (review doc not to be co…
flyingrobots Sep 12, 2025
25d8cc7
docs(decisions): add did-not-agree index
flyingrobots Sep 12, 2025
4918a18
docs(decisions): document rate limiter choice and rationale
flyingrobots Sep 12, 2025
4bb66e0
docs(decisions): document BRPOPLPUSH prioritization approach and devi…
flyingrobots Sep 12, 2025
773b361
docs(decisions): document SCAN-based reaper rationale and revisit cri…
flyingrobots Sep 12, 2025
f25f669
docs(decisions): document metrics scope deferral and rationale
flyingrobots Sep 12, 2025
2a026f3
docs(decisions): document Go 1.25.x toolchain choice and rationale
flyingrobots Sep 12, 2025
5ddfd98
test(breaker): add HalfOpen single-probe load test under concurrent A…
flyingrobots Sep 12, 2025
842f342
test(worker): add breaker integration test ensuring Open state pauses…
flyingrobots Sep 12, 2025
4b1ef37
docs: add testing guide with per-suite descriptions and isolated run …
flyingrobots Sep 12, 2025
09eddd7
docs: normalize all code examples to fenced Markdown blocks with lang…
flyingrobots Sep 12, 2025
9ee3e5e
docs(testing): restore code-fenced, copy/paste test commands per suit…
flyingrobots Sep 12, 2025
a3dead2
chore(docs): add markdownlint (CI via GitHub Action) and pre-commit a…
flyingrobots Sep 12, 2025
dbd897f
docs: add contributing/docs linting section (markdownlint hooks + loc…
flyingrobots Sep 12, 2025
4f44ea6
chore(docs): markdownlint repo-wide pass; update config to disable MD…
flyingrobots Sep 12, 2025
738e606
chore(make): add mdlint target to run markdownlint-cli2 across docs
flyingrobots Sep 13, 2025
202c488
Update .github/workflows/goreleaser.yml
flyingrobots Sep 13, 2025
d09edac
Update .goreleaser.yaml
flyingrobots Sep 13, 2025
59e1d27
Update .goreleaser.yaml
flyingrobots Sep 13, 2025
11220a1
Update .vscode/settings.json
flyingrobots Sep 13, 2025
518d193
Update .githooks/pre-commit
flyingrobots Sep 15, 2025
72f6e31
Update .github/workflows/changelog.yml
flyingrobots Sep 15, 2025
190293a
Update .github/workflows/changelog.yml
flyingrobots Sep 15, 2025
423df1e
Update .github/workflows/ci.yml
flyingrobots Sep 15, 2025
203fdf5
Update .github/workflows/ci.yml
flyingrobots Sep 15, 2025
698655f
Update .github/workflows/goreleaser.yml
flyingrobots Sep 15, 2025
2f598e2
Update deploy/grafana/dashboards/work-queue.json
flyingrobots Sep 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
# Markdown lint + autofix staged Markdown files
set -euo pipefail

mapfile -d '' -t _staged < <(git diff --cached --name-only --diff-filter=ACM -z)
md_files=()
for f in "${_staged[@]}"; do
[[ "$f" =~ \.(md|MD|mdx|MDX)$ ]] && md_files+=("$f")
done
Comment on lines +5 to +9
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

This breaks on macOS’ default Bash (3.2). Ditch mapfile-only path and cover renames.

Bash 3.2 lacks mapfile; your hook dies on vanilla macs. Also you ignore renamed/type-changed files.

Apply this diff:

-mapfile -d '' -t _staged < <(git diff --cached --name-only --diff-filter=ACM -z)
+_staged=()
+if type -t mapfile >/dev/null 2>&1; then
+  mapfile -d '' -t _staged < <(git diff --cached --name-only --diff-filter=ACMRT -z)
+else
+  # Fallback compatible with Bash 3.2
+  while IFS= read -r -d $'\0' f; do _staged+=("$f"); done < <(git diff --cached --name-only --diff-filter=ACMRT -z)
+fi
 md_files=()
 for f in "${_staged[@]}"; do
   [[ "$f" =~ \.(md|MD|mdx|MDX)$ ]] && md_files+=("$f")
 done
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
mapfile -d '' -t _staged < <(git diff --cached --name-only --diff-filter=ACM -z)
md_files=()
for f in "${_staged[@]}"; do
[[ "$f" =~ \.(md|MD|mdx|MDX)$ ]] && md_files+=("$f")
done
_staged=()
if type -t mapfile >/dev/null 2>&1; then
mapfile -d '' -t _staged < <(git diff --cached --name-only --diff-filter=ACMRT -z)
else
# Fallback compatible with Bash 3.2
while IFS= read -r -d $'\0' f; do
_staged+=("$f")
done < <(git diff --cached --name-only --diff-filter=ACMRT -z)
fi
md_files=()
for f in "${_staged[@]}"; do
[[ "$f" =~ \.(md|MD|mdx|MDX)$ ]] && md_files+=("$f")
done
🤖 Prompt for AI Agents
.githooks/pre-commit around lines 5 to 9: the hook uses Bash-only mapfile which
breaks on macOS Bash 3.2 and also omits renamed/type-changed files; replace the
mapfile pipeline with a portable while IFS= read -r -d '' loop that reads git
diff --cached --name-only --diff-filter=ACMR -z output into an array (preserving
filenames with spaces/newlines), and change the git diff --diff-filter flags to
include R and T (ACMR) so renamed/type-changed files are captured; ensure the
resulting md_files detection loop remains the same and works with the populated
array.

if [[ ${#md_files[@]} -eq 0 ]]; then
exit 0
fi

echo "[pre-commit] markdownlint-cli2 --fix on staged Markdown files"
if command -v npx >/dev/null 2>&1; then
# Run with --fix so minor issues are auto-corrected
npx -y markdownlint-cli2 --fix "${md_files[@]}" || true
# Re-stage any modified files
git add -- "${md_files[@]}" || true
# Verify no errors remain; block commit if they do
if ! npx -y markdownlint-cli2 "${md_files[@]}"; then
Comment on lines +14 to +21
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Optional: use lint-staged and stop reinventing half a pre-commit framework.

Let a battle-tested tool handle staged-only semantics and partial hunks. Keep this hook as a thin wrapper.

Minimal change inside this hook:

-echo "[pre-commit] markdownlint-cli2 --fix on staged Markdown files"
+echo "[pre-commit] lint-staged: markdownlint on staged Markdown files"
 if command -v npx >/dev/null 2>&1; then
-  # Run with --fix so minor issues are auto-corrected
-  npx -y markdownlint-cli2 --fix "${md_files[@]}" || true
-  # Re-stage any modified files
-  git add -- "${md_files[@]}" || true
-  # Verify no errors remain; block commit if they do
-  if ! npx -y markdownlint-cli2 "${md_files[@]}"; then
-    echo "Markdownlint errors remain after autofix. Aborting commit." >&2
-    exit 1
-  fi
+  npx -y lint-staged
 else

Then configure lint-staged (package.json or .lintstagedrc) to run:
"*.{md,mdx}": "markdownlint-cli2 --fix" and it will re-stage only the fixed hunks.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
echo "[pre-commit] markdownlint-cli2 --fix on staged Markdown files"
if command -v npx >/dev/null 2>&1; then
# Run with --fix so minor issues are auto-corrected
npx -y markdownlint-cli2 --fix "${md_files[@]}" || true
# Re-stage any modified files
git add -- "${md_files[@]}" || true
# Verify no errors remain; block commit if they do
if ! npx -y markdownlint-cli2 "${md_files[@]}"; then
echo "[pre-commit] lint-staged: markdownlint on staged Markdown files"
if command -v npx >/dev/null 2>&1; then
npx -y lint-staged
else
echo "npx not found. Skipping markdownlint autofix. Install Node.js to enable autofix." >&2
fi
🤖 Prompt for AI Agents
.githooks/pre-commit lines 14-21: the hook reimplements staged-file handling for
Markdown linting; replace this ad-hoc logic with lint-staged. Add a lint-staged
config (package.json "lint-staged" or .lintstagedrc) mapping "*.{md,mdx}":
"markdownlint-cli2 --fix" and ensure markdownlint-cli2 is a devDependency, then
simplify the hook to invoke npx -y lint-staged (so only staged hunks are fixed
and re-staged) and propagate its exit code to block the commit on failures.

echo "Markdownlint errors remain after autofix. Aborting commit." >&2
exit 1
fi
Comment on lines +15 to +24
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Stop auto-staging unintended junk; lint the INDEX, not the working tree.

Right now you blindly re-add files after mutating the working tree. If a dev staged only some hunks, your hook will slurp in the rest. Hard fail when there are unstaged changes in targeted files, and don’t swallow failures.

Apply this diff:

 if command -v npx >/dev/null 2>&1; then
+  # Refuse to proceed if any targeted file has unstaged changes.
+  for f in "${md_files[@]}"; do
+    if ! git diff --quiet -- "$f"; then
+      echo "Unstaged changes detected in $f; aborting to avoid staging unintended hunks. Stash or fully stage Markdown changes and retry." >&2
+      exit 1
+    fi
+  done
   # Run with --fix so minor issues are auto-corrected
-  npx -y markdownlint-cli2 --fix "${md_files[@]}" || true
+  npx -y markdownlint-cli2 --fix "${md_files[@]}"
   # Re-stage any modified files
-  git add -- "${md_files[@]}" || true
+  git add -- "${md_files[@]}"
   # Verify no errors remain; block commit if they do
   if ! npx -y markdownlint-cli2 "${md_files[@]}"; then
     echo "Markdownlint errors remain after autofix. Aborting commit." >&2
     exit 1
   fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if command -v npx >/dev/null 2>&1; then
# Run with --fix so minor issues are auto-corrected
npx -y markdownlint-cli2 --fix "${md_files[@]}" || true
# Re-stage any modified files
git add -- "${md_files[@]}" || true
# Verify no errors remain; block commit if they do
if ! npx -y markdownlint-cli2 "${md_files[@]}"; then
echo "Markdownlint errors remain after autofix. Aborting commit." >&2
exit 1
fi
if command -v npx >/dev/null 2>&1; then
# Refuse to proceed if any targeted file has unstaged changes.
for f in "${md_files[@]}"; do
if ! git diff --quiet -- "$f"; then
echo "Unstaged changes detected in $f; aborting to avoid staging unintended hunks. Stash or fully stage Markdown changes and retry." >&2
exit 1
fi
done
# Run with --fix so minor issues are auto-corrected
npx -y markdownlint-cli2 --fix "${md_files[@]}"
# Re-stage any modified files
git add -- "${md_files[@]}"
# Verify no errors remain; block commit if they do
if ! npx -y markdownlint-cli2 "${md_files[@]}"; then
echo "Markdownlint errors remain after autofix. Aborting commit." >&2
exit 1
fi

else
echo "npx not found. Skipping markdownlint autofix. Install Node.js to enable autofix." >&2
fi

exit 0
18 changes: 18 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# CODEOWNERS maps file patterns to required reviewers.
# Patterns the people will be automatically requested for review.
# See: https://docs.github.com/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners

# Default owner for entire repository
* @flyingrobots

# CI/CD and workflows
.github/** @flyingrobots

# Helm chart and deployment assets
deploy/** @flyingrobots

# Go source
cmd/** @flyingrobots
internal/** @flyingrobots
test/** @flyingrobots

40 changes: 40 additions & 0 deletions .github/workflows/changelog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Update Changelog

on:
workflow_dispatch:
push:
tags:
- 'v*'

permissions:
contents: write

jobs:
changelog:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
ref: ${{ github.event.repository.default_branch }}
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.25.x'
- name: Install git-chglog
run: go install github.com/git-chglog/git-chglog/cmd/git-chglog@v0.15.4
- name: Generate CHANGELOG.md
run: |
if ! $(go env GOPATH)/bin/git-chglog -o CHANGELOG.md; then
echo "git-chglog not configured; skipping update"; exit 0
fi
- name: Commit changes
run: |
git config user.name "github-actions"
git config user.email "github-actions@github.com"
git add CHANGELOG.md
git diff --cached --quiet && echo "no changes" || git commit -m "chore(changelog): update CHANGELOG for ${GITHUB_REF_NAME}"
- name: Push changes
run: |
git push origin HEAD:${{ github.event.repository.default_branch }} || echo "no push"
22 changes: 21 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,18 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.24.x'
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.25.x'
cache: true
- name: Tidy
run: go mod download
- name: Govulncheck
uses: golang/govulncheck-action@v1
with:
go-version-input: '1.25.x'
vulncheck-version: 'v1.1.3'
- name: Tidy
run: go mod tidy
- name: Vet
Expand All @@ -35,6 +46,15 @@ jobs:
env:
E2E_REDIS_ADDR: localhost:6379
run: go test ./... -race -count=1
- name: E2E determinism (5x)
env:
E2E_REDIS_ADDR: 127.0.0.1:6379
run: |
set -euo pipefail
for i in {1..5}; do
echo "Run #$i"
go test ./test/e2e -run TestE2E_WorkerCompletesJobWithRealRedis -race -count=1
done
- name: Govulncheck
run: |
go install golang.org/x/vuln/cmd/govulncheck@latest
Expand Down
41 changes: 41 additions & 0 deletions .github/workflows/goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: GoReleaser

on:
push:
tags:
- 'v*'
workflow_dispatch: {}

permissions:
contents: write
packages: write

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- uses: actions/setup-go@v5
with:
go-version: '1.25.x'
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Buildx
uses: docker/setup-buildx-action@v3
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Comment on lines +34 to +41
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Scope permissions narrowly and surface attestations.

Consider adding provenance/signing (SLSA/cosign) and setting tighter permissions per step. Not blocking, but you’ll thank me later.

🤖 Prompt for AI Agents
.github/workflows/goreleaser.yml lines 31-38: tighten the step permissions and
enable provenance/signing for releases by (1) adding a top-level permissions
block that limits the job to the minimum rights (e.g., contents: read, id-token:
write for OIDC token exchange, and only add packages or actions permissions if
absolutely required), (2) granting the goreleaser step only the specific
environment variables/secrets it needs instead of full GITHUB_TOKEN scope, and
(3) enabling artifact provenance and signing by calling goreleaser with
provenance flags and/or invoking a cosign/sigstore step after build (or
configure goreleaser to sign) using OIDC (id-token) and the COSIGN_* secrets so
releases are attested and signed. Ensure the workflow creates and exposes
attestations (SLSA provenance) and that any tokens/secrets are minimal and
scoped.

Comment on lines +35 to +41
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

“version: latest” is non-deterministic. Pin your toolchain.

Releases must be reproducible.

-      - name: Run GoReleaser
-        uses: goreleaser/goreleaser-action@v6
+      - name: Run GoReleaser
+        uses: goreleaser/goreleaser-action@v6
         with:
           distribution: goreleaser
-          version: latest
+          version: v2.6.1 # pin a known-good Goreleaser version
           args: release --clean

Also consider guarding workflow_dispatch to snapshots to avoid accidental publishes:

-          args: release --clean
+          args: ${{ github.event_name == 'workflow_dispatch' && 'release --clean --skip=publish --snapshot' || 'release --clean' }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: v2.6.1 # pin a known-good Goreleaser version
args: ${{ github.event_name == 'workflow_dispatch' && 'release --clean --skip=publish --snapshot' || 'release --clean' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
🤖 Prompt for AI Agents
.github/workflows/goreleaser.yml lines 35-41: the action uses a
non-deterministic "version: latest" which prevents reproducible releases and
risks accidental publishes; replace "latest" with a pinned Goreleaser version
(e.g. a specific tag or semver like v1.22.0 or the exact commit/tag you
validated) so the toolchain is fixed, and add a guard to workflow_dispatch (for
example require a specific input like "type=snapshot" or restrict dispatch to a
snapshot branch or protect with a conditional that only runs on tagged or main
branch) to prevent accidental publishes.

21 changes: 21 additions & 0 deletions .github/workflows/markdownlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Markdown Lint

on:
pull_request:
push:
branches: [ main ]

Comment on lines +3 to +7
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix YAML lint errors and tighten permissions.

Quote the “on” key (truthy warning), remove extra spaces in inline array, and set least-privilege token.

-on:
+"on":
   pull_request:
   push:
-    branches: [ main ]
+    branches: [main]
+
+permissions:
+  contents: read
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
on:
pull_request:
push:
branches: [ main ]
"on":
pull_request:
push:
branches: [main]
permissions:
contents: read
🧰 Tools
🪛 YAMLlint (1.37.1)

[warning] 3-3: truthy value should be one of [false, true]

(truthy)


[error] 6-6: too many spaces inside brackets

(brackets)


[error] 6-6: too many spaces inside brackets

(brackets)

🤖 Prompt for AI Agents
.github/workflows/markdownlint.yml lines 3-7: fix YAML lint issues and tighten
permissions by quoting the top-level on key ("on"), collapse the inline array
spacing to branches: [main] (remove extra spaces), and add a minimal permissions
block (e.g., permissions: contents: read) to enforce least-privilege for the
workflow token; update the file accordingly so the YAML linter and GitHub
Actions permission requirements are satisfied.

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run markdownlint-cli2
uses: DavidAnson/markdownlint-cli2-action@v17
Comment on lines +12 to +16
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Pin Actions by commit SHA. Tags are mutable; don’t ship supply-chain roulette.

Lock both actions to immutable SHAs and add a comment with the tag for readability.

-      - uses: actions/checkout@v4
+      - uses: actions/checkout@<COMMIT-SHA> # v4
@@
-      - name: Run markdownlint-cli2
-        uses: DavidAnson/markdownlint-cli2-action@v17
+      - name: Run markdownlint-cli2
+        uses: DavidAnson/markdownlint-cli2-action@<COMMIT-SHA> # v17

If you want, I can fetch the current SHAs and open a follow-up PR with the exact pins.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

if [ -f .github/workflows/markdownlint.yml ]; then
  echo "FOUND: .github/workflows/markdownlint.yml"
  nl -ba .github/workflows/markdownlint.yml | sed -n '1,200p'
else
  echo "NOT_FOUND: .github/workflows/markdownlint.yml"
  echo "Searching for markdownlint workflow files..."
  rg -n --hidden --glob '!.git' --glob '!node_modules' 'markdownlint' || true
fi

Length of output: 82


🏁 Script executed:

#!/bin/bash
set -euo pipefail

if [ -f .github/workflows/markdownlint.yml ]; then
  echo "FOUND: .github/workflows/markdownlint.yml"
  echo "----- start file -----"
  sed -n '1,200p' .github/workflows/markdownlint.yml || true
  echo "----- end file -----"
else
  echo "NOT_FOUND: .github/workflows/markdownlint.yml"
fi

Length of output: 495


Pin Actions to immutable commit SHAs — stop using mutable tags.

Tags are mutable; don't ship supply‑chain roulette. Pin both actions to exact commit SHAs and add a comment with the tag for readability.

File: .github/workflows/markdownlint.yml (lines 12–16)

-      - uses: actions/checkout@v4
+      - uses: actions/checkout@<COMMIT-SHA> # v4
@@
-      - name: Run markdownlint-cli2
-        uses: DavidAnson/markdownlint-cli2-action@v17
+      - name: Run markdownlint-cli2
+        uses: DavidAnson/markdownlint-cli2-action@<COMMIT-SHA> # v17

I can fetch the current SHAs and open a follow-up PR with the exact pins.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
.github/workflows/markdownlint.yml lines 12–16: the workflow uses mutable tags
for actions (actions/checkout@v4 and DavidAnson/markdownlint-cli2-action@v17);
replace each uses: reference with the exact immutable commit SHA for that action
(e.g., actions/checkout@<COMMIT_SHA> and
DavidAnson/markdownlint-cli2-action@<COMMIT_SHA>) and add an inline comment on
the same line or above preserving the human-readable tag (e.g., # was @v4) for
traceability; ensure the checkout action still has with: fetch-depth: 0
preserved and verify the SHAs point to the intended versions before committing.

with:
config: .markdownlint.yaml
globs: |
**/*.md
!**/node_modules/**
3 changes: 1 addition & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.24.x'
go-version: '1.25.x'
- name: Build binary
run: |
make tidy
Expand All @@ -39,4 +39,3 @@ jobs:
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true

9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,17 @@ go.work

# IDE/Editor
.idea/
.vscode/
# VS Code: ignore all by default, allow key shared files
.vscode/*
!.vscode/extensions.json
!.vscode/settings.json
!.vscode/launch.json
Comment on lines +27 to +31
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Selective .vscode tracking is fine; ensure no secrets slip in.

extensions.json/settings.json/launch.json can hold credentials (e.g., debug env). Recommend adding a pre-commit check to block secrets in these files.

🤖 Prompt for AI Agents
In .gitignore around lines 27 to 31, the reviewer asks for a safeguard because
tracked .vscode files (extensions.json, settings.json, launch.json) can contain
secrets; add a pre-commit hook or integrate a repository check (e.g., Husky +
lint-staged or a CI check) that scans those specific files for
secrets/credentials and rejects commits when patterns are detected. Implement
the hook to run a lightweight secret scanner (regex checks for common patterns
like AWS keys, private keys, auth tokens, env var declarations) only on
.vscode/extensions.json, .vscode/settings.json, and .vscode/launch.json, and
ensure it exits non-zero with a clear error message instructing the developer to
remove secrets or move them to environment variables; add documentation in
CONTRIBUTING.md about the check and how to bypass temporarily with
maintainer-approved workflow.

*.swp
*.swo

# Obsidian
.obsidian/

# Logs
*.log
logs/
47 changes: 47 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
version: 2

project_name: job-queue-system

builds:
- id: job-queue-system
main: ./cmd/job-queue-system
env:
- CGO_ENABLED=0
goos: [linux, darwin, windows]
goarch: [amd64, arm64]
ldflags:
- -s -w -X main.version={{.Version}}
Comment on lines +12 to +13
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Harden builds: add -trimpath for reproducibility.

Reduces path leakage and improves determinism.

     ldflags:
-      - -s -w -X main.version={{.Version}}
+      - -s -w -trimpath -X main.version={{.Version}}

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
.goreleaser.yaml around lines 12 to 13: the current ldflags "-s -w -X
main.version={{.Version}}" can leak build paths and harm reproducibility; add
the "-trimpath" linker flag to the ldflags list (e.g. include -trimpath
alongside -s and -w) so builds are hardened and path information is removed for
deterministic outputs.


archives:
- id: binaries
builds: [job-queue-system]
format: tar.gz
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
format_overrides:
- goos: windows
format: zip
checksum:
name_template: "checksums_{{ .Version }}.txt"

changelog:
sort: desc
use: github

dockers:
- image_templates:
- ghcr.io/{{ .RepoOwner }}/{{ .RepoName }}:{{ .Version }}
- ghcr.io/{{ .RepoOwner }}/{{ .RepoName }}:latest
Comment on lines +31 to +33
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Don’t slap :latest on alpha builds.

Tagging “latest” for pre-releases is how you torch users. Gate “latest” to stable releases only (e.g., via templating/conditions or a separate docker entry that runs only when not prerelease). Verify the exact GoReleaser field to key off (e.g., .Prerelease or similar) and wire it accordingly.


🌐 Web query:

How to conditionally add the "latest" Docker tag only for non-prerelease builds in GoReleaser v2? Provide the recommended config snippet.

💡 Result:

Use GoReleaser template conditionals in image_templates to emit :latest only when .Prerelease is empty (i.e., not a prerelease). Example config snippet:

.goreleaser.yaml
dockers:

  • image_templates:
    • "myuser/myimage:{{ .Tag }}"
    • '{{ if eq .Prerelease "" }}myuser/myimage:latest{{ end }}'

References: GoReleaser Docker docs [1], Template variables (.Prerelease) [2].


DO NOT tag prereleases with :latest — gate :latest to stable releases.

File: .goreleaser.yaml (lines 31–33) — replace the unconditional :latest with a template conditional that only emits :latest when .Prerelease is empty:

  • image_templates:
    • ghcr.io/{{ .RepoOwner }}/{{ .RepoName }}:{{ .Version }}
    • '{{ if eq .Prerelease "" }}ghcr.io/{{ .RepoOwner }}/{{ .RepoName }}:latest{{ end }}'

This uses .Prerelease to ensure only stable releases get :latest.

🤖 Prompt for AI Agents
.goreleaser.yaml around lines 31 to 33: the image_templates list unconditionally
emits a :latest tag which will tag prereleases; modify the template to only emit
the :latest entry when .Prerelease is empty by replacing the unconditional
:latest line with a conditional template that checks eq .Prerelease "" and only
outputs the ghcr.io/{{ .RepoOwner }}/{{ .RepoName }}:latest entry in that case,
keeping the version-tag line unchanged.

dockerfile: Dockerfile
build_flag_templates:
- "--pull"

Comment on lines +30 to +37
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enable multi-arch Docker images via buildx + add OCI labels.

Without buildx/platforms, images will be single-arch (runner default). Add platforms and basic OCI labels.

 dockers:
   - image_templates:
       - ghcr.io/{{ .RepoOwner }}/{{ .RepoName }}:{{ .Version }}
       - ghcr.io/{{ .RepoOwner }}/{{ .RepoName }}:latest
     dockerfile: Dockerfile
+    use: buildx
+    platforms:
+      - linux/amd64
+      - linux/arm64
     build_flag_templates:
       - "--pull"
+    labels:
+      - "org.opencontainers.image.source={{.GitURL}}"
+      - "org.opencontainers.image.revision={{.FullCommit}}"
+      - "org.opencontainers.image.version={{.Version}}"

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In .goreleaser.yaml around lines 28-35, the dockers entry needs multi-arch
buildx configuration and basic OCI labels; update the dockers block to include a
platforms array (e.g. linux/amd64, linux/arm64) so GoReleaser will use buildx to
produce multi-arch images, and add an oci/labels map with standard keys
(org.opencontainers.image.title, description, url, source, created, version,
authors) populated from template variables ({{ .ProjectName }}, {{ .Version }},
{{ .RepoURL }}, {{ .CommitDate }} etc.); ensure the labels are nested under the
docker build entry and keep existing image_templates and build_flag_templates
intact so images are built multi-arch and carry OCI metadata.

release:
github:
owner: '{{.Env.GITHUB_REPOSITORY_OWNER}}'
name: '{{.Env.GITHUB_REPOSITORY_NAME}}'
draft: false
prerelease: auto

snapshot:
name_template: SNAPSHOT-{{ .ShortCommit }}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Kill the stray trailing blank line.

YAMLlint already complained. Remove it.

-  name_template: SNAPSHOT-{{ .ShortCommit }}
-
+  name_template: SNAPSHOT-{{ .ShortCommit }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
name_template: SNAPSHOT-{{ .ShortCommit }}
name_template: SNAPSHOT-{{ .ShortCommit }}
🤖 Prompt for AI Agents
In .goreleaser.yaml around line 46, there is a stray trailing blank line after
the "name_template: SNAPSHOT-{{ .ShortCommit }}" entry; remove that empty line
so the file has no extra blank line at the end (save the file without the
trailing newline) to satisfy yamllint.


28 changes: 28 additions & 0 deletions .markdownlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
default: true

# Allow long lines in docs where URLs and code blocks occur
MD013: false

# Permit duplicate headings at different levels/siblings only
MD024:
siblings_only: true

# Heading punctuation rules (common sentence punctuation)
MD026:
punctuation: ".,;:!"

# Allow first line not to be a top-level heading (some docs start with metadata)
MD041: false

# Code block style
MD046:
style: fenced

# Inline code spans: allow backticks in text without strict checks
MD038: false

# Ordered list item prefix flexible (allow any numbering)
MD029: false

# Allow inline HTML (used in some docs)
MD033: false
Comment on lines +27 to +28
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Stop blanket-disabling MD033; scope it.

Turning off MD033 project-wide is lazy and dangerous. Allow only the minimal elements you actually need.

-# Allow inline HTML (used in some docs)
-MD033: false
+# Allow inline HTML for specific safe elements only
+MD033:
+  allowed_elements:
+    - br
+    - img
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Allow inline HTML (used in some docs)
MD033: false
# Allow inline HTML for specific safe elements only
MD033:
allowed_elements:
- br
- img
🤖 Prompt for AI Agents
In .markdownlint.yaml around lines 27-28, you currently disable MD033
project-wide; remove that global "MD033: false" entry and instead scope the rule
disable to only the files that need inline HTML by either (A) adding an
overrides block mapping specific file glob(s) to MD033: false (e.g. an
"overrides:" array with objects containing "files:" globs and "rules:" or rule
settings), or (B) delete the global setting and add in-file disables where
required (<!-- markdownlint-disable MD033 --> / <!-- markdownlint-enable MD033
-->) so only the minimal targets allow inline HTML. Ensure no other rules are
unintentionally affected.

6 changes: 6 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"recommendations": [
"golang.go"
],
"unwantedRecommendations": []
}
Comment on lines +1 to +6
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Add YAML/Helm tooling to match new chart assets

Recommend adding Kubernetes/Helm and YAML support to align with the new Helm chart and K8s manifests.

 {
   "recommendations": [
-    "golang.go"
+    "golang.go",
+    "redhat.vscode-yaml",
+    "ms-kubernetes-tools.vscode-kubernetes-tools"
   ],
   "unwantedRecommendations": []
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{
"recommendations": [
"golang.go"
],
"unwantedRecommendations": []
}
{
"recommendations": [
"golang.go",
"redhat.vscode-yaml",
"ms-kubernetes-tools.vscode-kubernetes-tools"
],
"unwantedRecommendations": []
}
🤖 Prompt for AI Agents
.vscode/extensions.json around lines 1 to 6: the workspace extensions list only
recommends the Go extension but the repo now contains Helm charts and Kubernetes
YAML manifests; update the recommendations array to include YAML and
Helm/Kubernetes tooling (for example add "redhat.vscode-yaml",
"ms-azuretools.vscode-helm" and "ms-kubernetes-tools.vscode-kubernetes-tools")
so users get proper linting, schema support and Helm assistance when opening the
workspace.

18 changes: 18 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"editor.formatOnSave": false,
"[go]": {
"editor.formatOnSave": true,
"[go]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
},
},
"gopls": {
"ui.semanticTokens": true,
"build.experimentalWorkspaceModule": true
},
Comment on lines +12 to +15
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify gopls experimental flag; it may be obsolete

gopls’s build.experimentalWorkspaceModule has changed across versions; confirm it’s still valid with your pinned Go extension/gopls. If obsolete, drop it.

   "gopls": {
     "ui.semanticTokens": true,
-    "build.experimentalWorkspaceModule": true
+    // "build.experimentalWorkspaceModule": true
   },

To verify with upstream docs:


🌐 Web query:

Is gopls setting "build.experimentalWorkspaceModule" still supported in the latest gopls? If deprecated, what is the recommended default behavior or replacement?

💡 Result:

Short answer: No — it was deprecated and then removed. Use go.work (multi-module workspace support in the go command) instead.

Details / sources:

  • Deprecation announced (replaced by go.work; removed in gopls v0.11.0+). [1]
  • Release notes / removal and recommended replacement (create a go.work; e.g. go work use -r .). [2][3]

Sources:
[1] gopls v0.10.x release notes (deprecates experimentalWorkspaceModule in favor of go.work).
[2] gopls v0.12.0 notes (removes the setting; instructs using go.work / go work use -r .).
[3] GitHub issue tracking removal of experimentalWorkspaceModule.


Remove deprecated gopls setting "build.experimentalWorkspaceModule"

Deprecated in gopls v0.10.x and removed by v0.12.0; use go.work (e.g. go work use -r .) for multi-module workspaces. Action: delete the "build.experimentalWorkspaceModule" entry from .vscode/settings.json (lines 9–12); do not comment it out (JSON has no comments).

🤖 Prompt for AI Agents
In .vscode/settings.json around lines 9 to 12, the gopls setting
"build.experimentalWorkspaceModule" is deprecated and should be removed; edit
the file and delete the "build.experimentalWorkspaceModule": true entry (do not
comment it out), leaving the rest of the "gopls" object intact and ensure the
JSON remains valid.

"go.testFlags": ["-race", "-count=1"],
"go.toolsManagement.autoUpdate": true
Comment on lines +16 to +17
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Test flags trade-off

Running tests with -race and -count=1 by default is great for catching issues but slower. If dev feedback becomes a concern, consider moving -race to a separate profile/task.

🤖 Prompt for AI Agents
In .vscode/settings.json at lines 13-14 the default go.testFlags include
["-race", "-count=1"], which slows local feedback; remove "-race" from the
default go.testFlags and add a separate configuration/task for race-enabled
tests (or a VS Code test profile) so developers can run fast tests by default
while still having an easy opt-in for race detection; update settings.json to
set go.testFlags to ["-count=1"] and add a new task or profile (e.g., in
.vscode/tasks.json or launch configurations) named "Go: test (race)" that
invokes tests with ["-race","-count=1"] and document usage in the project
README.

}
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
All notable changes to this project will be documented in this file.

## [Unreleased]

- Admin CLI: stats, peek, purge-dlq
- Health/readiness endpoints
- Queue length gauges updater
Expand All @@ -12,4 +13,3 @@ All notable changes to this project will be documented in this file.
- Worker active gauge
- E2E tests with Redis service in CI
- Govulncheck in CI

14 changes: 14 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,17 @@ tidy:

version:
@echo $(VERSION)

.PHONY: hooks
hooks:
@git config core.hooksPath .githooks
@chmod +x .githooks/pre-commit
@echo "Git hooks enabled (pre-commit markdownlint autofix)."

.PHONY: mdlint
mdlint:
@if ! command -v npx >/dev/null 2>&1; then \
echo "npx not found. Please install Node.js to run markdownlint."; \
exit 1; \
fi
@npx -y markdownlint-cli2 "**/*.md" "!**/node_modules/**"
Comment on lines +33 to +39
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Add a clean target. Don’t ship a Makefile without it.

Satisfies checkmake and basic developer hygiene.

 .PHONY: mdlint
 mdlint:
 	@if ! command -v npx >/dev/null 2>&1; then \
 		echo "npx not found. Please install Node.js to run markdownlint."; \
 		exit 1; \
 	fi
 	@npx -y markdownlint-cli2 "**/*.md" "!**/node_modules/**"
+
+.PHONY: clean
+clean:
+	rm -rf bin
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.PHONY: mdlint
mdlint:
@if ! command -v npx >/dev/null 2>&1; then \
echo "npx not found. Please install Node.js to run markdownlint."; \
exit 1; \
fi
@npx -y markdownlint-cli2 "**/*.md" "!**/node_modules/**"
.PHONY: mdlint
mdlint:
@if ! command -v npx >/dev/null 2>&1; then \
echo "npx not found. Please install Node.js to run markdownlint."; \
exit 1; \
fi
@npx -y markdownlint-cli2 "**/*.md" "!**/node_modules/**"
.PHONY: clean
clean:
rm -rf bin
🧰 Tools
🪛 checkmake (0.2.2)

[warning] 33-33: Missing required phony target "clean"

(minphony)

🤖 Prompt for AI Agents
In Makefile around lines 33 to 39, there's no clean target; add a .PHONY: clean
and implement a clean target that removes common generated artifacts (e.g.,
build/dist directories, temporary and cache files like .cache, .venv, *.pyc,
node_modules/.cache, and any markdownlint or other tool caches) so developers
can restore a pristine repo state; keep the recipe idempotent and safe (use rm
-rf for the known artifact paths only).

Loading