{"_type":"issue","id":"forgejo-mcp-1b4","title":"Build dedicated release-tools container image for op1st Tekton release pipeline","description":"Currently .tekton/tasks/goreleaser-release.yaml installs syft + goreleaser at runtime in separate Tekton Steps, which fails (exit 127) because /usr/local/bin/ is per-container, not shared across Steps in a Pod. Workaround in current code is to collapse all installs+run into one Step (loses log granularity, repeats install on every release run, fragile to upstream URL changes). Proper fix: build a custom OCI image with pinned Go + syft + goreleaser + cosign + jq + curl + node22 + npx + @anthropic-ai/mcpb prefetched. Reference this image from all three Tasks (goreleaser-release, cosign-sign-release, mcpb-pack). Image rebuild on tool bump only. Likely lives in op1st-emea-b4mad or ghcr.io/operate-first/release-tools.","acceptance_criteria":"Image published at a stable registry path; .tekton/tasks/*.yaml reference it via params with versioned tag; release pipeline still passes; install-at-runtime removed; Renovate/dependabot config bumps the image tag","notes":"PR #155 merged into main as 550db7f. OpenSpec design + adversarial review now canonical. Implementation work begins on branch feat/release-tools-image-impl. Tracking via /var/home/goern/Source/codeberg.org/goern/forgejo-mcp-release-tools-impl worktree. Dev team release-tools-image-iter1 spawned for iteration 1 (source tree only; pipelines deferred to iter 2).","status":"closed","priority":0,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-25T11:47:01Z","created_by":"Christoph Görn","updated_at":"2026-05-25T22:20:29Z","started_at":"2026-05-25T12:09:21Z","closed_at":"2026-05-25T22:20:29Z","close_reason":"PR #157 merged (commit e02cf56). release-tools image built and pushed to codeberg.org/operate-first/release-tools:latest (sha256:b0387a762c54). All .tekton/tasks/ rewritten. OpenSpec change implemented end-to-end.","dependencies":[{"issue_id":"forgejo-mcp-1b4","depends_on_id":"forgejo-mcp-29g","type":"blocks","created_at":"2026-05-25T11:47:15Z","created_by":"Christoph Görn","metadata":"{}"}],"dependency_count":1,"dependent_count":5,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-wbw","title":"Fix PaC task annotation YAML folding bug in .tekton/release-tools-*.yaml","description":"PipelinesAsCode failed on PR #172 with 'annotations in pipeline are in wrong format: [git-clone,\\n .tekton/release-tools/tasks/build-image.yaml,...]'. Two PaC PipelineRun manifests use 'pipelinesascode.tekton.dev/task: \u003e-' with continuation lines indented one space deeper than the first content line. YAML folded scalar (\u003e-) preserves newlines when continuation lines are MORE indented than the first content line, so PaC sees a literal multi-line string instead of a flat bracketed list. Affects: .tekton/release-tools-on-pull-request-build.yaml and .tekton/release-tools-on-tag-publish.yaml.","notes":"Fix: collapse the bracketed task list to a single double-quoted string on the annotation line, e.g.:\n pipelinesascode.tekton.dev/task: \"[git-clone, .tekton/release-tools/tasks/build-image.yaml, .tekton/release-tools/tasks/verify-image-tools.yaml, .tekton/release-tools/tasks/syft-scan-image.yaml]\"\nPR #172 comment: https://codeberg.org/goern/forgejo-mcp/pulls/172#issuecomment-16027445","status":"closed","priority":1,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-28T15:35:11Z","created_by":"Christoph Görn","updated_at":"2026-05-28T15:36:11Z","started_at":"2026-05-28T15:35:15Z","closed_at":"2026-05-28T15:36:11Z","close_reason":"Fixed in 3a12931. PaC task annotations collapsed to single-line inline lists in release-tools-on-pull-request-build.yaml + release-tools-on-tag-publish.yaml.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-kva","title":"fix: cosign-sign task fails with --output-signature deprecated","description":"cosign v2.4+ deprecated --output-signature in favor of --bundle. When new-bundle-format is active (now default), --output-signature is silently ignored and cosign tries to write bundle to empty path → 'create bundle file: open : no such file or directory'. Fix: replace --output-signature with --bundle in .tekton/tasks/cosign-sign-release.yaml (and .forgejo/workflows/release.yml for consistency). External: PipelineRun on-tag-push-release-srlfm, task cosign-sign.","status":"closed","priority":1,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-26T06:19:20Z","created_by":"Christoph Görn","updated_at":"2026-05-26T06:19:52Z","started_at":"2026-05-26T06:19:22Z","closed_at":"2026-05-26T06:19:52Z","close_reason":"Fixed: --output-signature → --bundle in cosign-sign-release.yaml and release.yml. Committed cee6465.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-aps","title":"Fix build-image task: remove privileged, use rootless buildah","description":"build-image.yaml sets securityContext.privileged: true which is rejected by OpenShift container-build SCC bound to the pipeline SA. Fix: remove privileged: true, run as UID 1000, use --isolation=chroot --storage-driver=vfs so buildah works rootless under container-build SCC.","status":"closed","priority":1,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-25T23:10:09Z","created_by":"Christoph Görn","updated_at":"2026-05-26T00:14:57Z","started_at":"2026-05-25T23:10:13Z","closed_at":"2026-05-26T00:14:57Z","close_reason":"PR #163 open. All task bugs fixed and validated by run11. build/push/sign/sbom/promote all succeeded.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-8sz","title":"Move release-tools PipelineRuns to .tekton/ root — PaC v0.42.0 does not scan subdirectories","description":"PaC v0.42.0 only reads PipelineRun YAMLs from .tekton/*.yaml (root level). .tekton/release-tools/on-tag-publish.yaml and on-pull-request-build.yaml are invisible to PaC and never trigger. Fix: move both PipelineRun files to .tekton/ root with release-tools- prefix. Task YAMLs in .tekton/release-tools/tasks/ stay in place (PaC fetches them by explicit path in the task annotation).","status":"closed","priority":1,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-25T22:53:37Z","created_by":"Christoph Görn","updated_at":"2026-05-25T22:59:33Z","started_at":"2026-05-25T22:53:40Z","closed_at":"2026-05-25T22:59:33Z","close_reason":"PR #160 merged — PipelineRuns moved to .tekton/ root, CEL fixed","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-00o","title":"Restore cosign fail-closed signing after release-tools/v1.0.0 bootstrap ships","description":"Bootstrap exception: the first release-tools/v1.0.0 publish run will be invoked with SKIP_SIGN=true PipelineRun param so signing is skipped (allowed per D4 of design.md — chicken-egg unknowns at first end-to-end run). After v1.0.0 is published and pullable, run a smoke release-tools/v1.0.1 (no-op image bump or tooling rev) with SKIP_SIGN=false (default) to confirm cosign-signing-key Secret shape matches and signature objects land in codeberg.org/operate-first/release-tools registry. Verify cosign verify --key \u003cop1st-pub\u003e against the v1.0.1 manifest. Once green: remove the SKIP_SIGN param from on-tag-publish.yaml entirely (revert to spec.md A3 fail-closed posture exactly).","acceptance_criteria":"release-tools/v1.0.1 (or later) published with SKIP_SIGN=false. cosign verify succeeds. SKIP_SIGN param removed from on-tag-publish.yaml. Bead closes when commit landing the removal merges.","notes":"PR #158 created: https://codeberg.org/goern/forgejo-mcp/pulls/158. Code removes SKIP_SIGN param, validate-skip-sign task, and all when: guards — cosign-sign/attach-sbom now unconditional. Pre-merge: operator must verify release-tools/v1.0.1 publishes with signing enabled and cosign verify passes.","status":"closed","priority":1,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-25T17:08:31Z","created_by":"Christoph Görn","updated_at":"2026-05-26T00:14:57Z","started_at":"2026-05-25T22:34:46Z","closed_at":"2026-05-26T00:14:57Z","close_reason":"PR #158 merged. v1.0.1 published with signing enabled (run11 succeeded). SKIP_SIGN removed from on-tag-publish.yaml. A3 fail-closed posture restored.","dependencies":[{"issue_id":"forgejo-mcp-00o","depends_on_id":"forgejo-mcp-1b4","type":"blocks","created_at":"2026-05-25T17:08:36Z","created_by":"Christoph Görn","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-j52","title":"Split cosign keypair: separate release-tools-image signing from release-artifact signing","description":"Origin: L4 from release-tools-image adversarial review. v1.0.0 of the image is signed with the same cosign-signing-key Secret used to sign forgejo-mcp release artifacts. The release-tools image is consumed by .tekton/tasks/cosign-sign-release.yaml at release time, so a compromised image (via Containerfile change, transitive dep, or npm-package takeover) has access to the signing key and can sign attacker-supplied binaries. Mitigation: provision a second keypair in op1st-pipelines (e.g. cosign-signing-key-images vs cosign-signing-key-artifacts) so a release-tools image compromise cannot forge release artifact signatures. Coordinate with op1st-emea-b4mad maintainers for the second secret + reflector ruleset.","notes":"Blocked on op1st-emea-b4mad-yn5 (op1st-emea-b4mad beads, P1): 'Provision second cosign keypair to isolate release-tools image signing from forgejo-mcp artifact signing'. That task covers Secret provisioning + reflector ruleset. forgejo-mcp-j52 unblocks once op1st-emea-b4mad-yn5 is complete and both Secrets exist in op1st-pipelines.","status":"closed","priority":1,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-25T13:52:20Z","created_by":"Christoph Görn","updated_at":"2026-05-26T09:18:37Z","started_at":"2026-05-26T09:05:07Z","closed_at":"2026-05-26T09:18:37Z","close_reason":"PR #164 merged, cosign-signing-key-artifacts + cosign-signing-key-images confirmed in op1st-pipelines, v2.25.1 released with correct key separation.","dependencies":[{"issue_id":"forgejo-mcp-j52","depends_on_id":"forgejo-mcp-1b4","type":"blocks","created_at":"2026-05-25T13:52:44Z","created_by":"Christoph Görn","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-3h2","title":"Tighten release-tools pinning: vendor goreleaser, SHA256-verify curl-installed binaries","description":"Origin: L2 from release-tools-image adversarial review. The v1.0.0 image installs goreleaser via 'go install \u003ctag\u003e' which re-resolves transitive deps from proxy.golang.org on every build; syft and cosign installed via curl by tag only (no SHA256 verify). A transitive-dep takeover in goreleaser's module graph OR a CDN poisoning of anchore/sigstore release URLs would ship unnoticed. Fix: vendor goreleaser source at pinned SHA (build via 'go build' from a committed go.mod/go.sum), and SHA256-verify all curl-downloaded binaries against checksums recorded in VERSIONS.md before installing them.","notes":"PR #159: https://codeberg.org/goern/forgejo-mcp/pulls/159. goreleaser: go install → prebuilt tarball + dual SHA256 verify. syft: curl|sh → direct tarball + dual SHA256 verify. Hashes in VERSIONS.md + Containerfile ARG defaults. cosign unchanged.","status":"closed","priority":1,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-25T13:52:15Z","created_by":"Christoph Görn","updated_at":"2026-05-26T00:14:57Z","started_at":"2026-05-25T22:37:39Z","closed_at":"2026-05-26T00:14:57Z","close_reason":"PR #159 merged. goreleaser+syft now SHA256-verified via dual check against repo hash and publisher checksums.txt. Filename bug fixed in PR #162.","dependencies":[{"issue_id":"forgejo-mcp-3h2","depends_on_id":"forgejo-mcp-1b4","type":"blocks","created_at":"2026-05-25T13:52:44Z","created_by":"Christoph Görn","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-aun","title":"Hummingbird base health monitoring: SLO on hi/go tag lag + scheduled CVE rescan","description":"Origin: A6 + L6 from release-tools-image adversarial review (openspec/changes/release-tools-image/review.md). Hummingbird is young; hi/go may lag upstream Go releases. Renovate bumps tags but does NOT surface CVEs landing between bumps. Need: (a) documented SLO for acceptable lag between upstream Go GA and hi/go:\u003cver\u003e-builder availability, (b) second-source mirror policy if Red Hat pulls a tag mid-cycle, (c) scheduled PipelineRun (e.g. weekly) that pulls the published release-tools image and runs grype or trivy against it, opening issues on findings. Defer until release-tools-image v1.0.0 ships + one CVE-cycle of operational data exists.","notes":"Tracked in design.md Open Questions as forgejo-mcp-bd-A6L6 placeholder. Filed under Status/Blocked per acceptance criteria of release-tools-image change.","status":"open","priority":1,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-05-25T13:52:10Z","created_by":"Christoph Görn","updated_at":"2026-05-25T13:52:10Z","dependencies":[{"issue_id":"forgejo-mcp-aun","depends_on_id":"forgejo-mcp-1b4","type":"blocks","created_at":"2026-05-25T13:52:44Z","created_by":"Christoph Görn","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-trb","title":"Fix goreleaser-release Task: move Go cache out of git checkout to avoid dirty-tree","description":"GoReleaser run on v2.24.1 failed: 'git is in a dirty state' caused by GOCACHE=/workspace/src/.gocache + GOMODCACHE=/workspace/src/.gomodcache placing untracked dirs inside the repo. GoReleaser checks git status before publishing and bails on any uncommitted/untracked content. Fix: move caches to /tmp/gocache + /tmp/gomodcache (per-step but acceptable; release runs once per tag).","acceptance_criteria":"goreleaser release succeeds on v2.24.2; cosign-sign + mcpb-pack downstream Tasks complete; all 8 assets uploaded","status":"closed","priority":1,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-25T11:54:05Z","created_by":"Christoph Görn","updated_at":"2026-05-25T11:55:30Z","started_at":"2026-05-25T11:54:05Z","closed_at":"2026-05-25T11:55:30Z","close_reason":"PR #154 merged. Go cache moved to /tmp. v2.24.2 cut next.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-29g","title":"Fix goreleaser-release Task: collapse install steps to survive Pod step-isolation","description":"Path B workaround for forgejo-mcp-1b4. Step containers in a Tekton Pod don't share /usr/local/bin/, so syft + goreleaser installed in install-* steps disappear before the release step runs (exit 127 'goreleaser: command not found' on first v2.24.0 run). Collapse install-syft + install-goreleaser + release into a single Step that installs both tools inline and then invokes goreleaser release. Smoke-test stays separate (reads from dist/ on workspace). Proper image-based fix tracked in forgejo-mcp-1b4.","acceptance_criteria":"goreleaser-release Task succeeds end-to-end on v2.24.1; all 8 release assets uploaded to Codeberg; cosign-sign + mcpb-pack downstream Tasks complete","status":"closed","priority":1,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-25T11:47:11Z","created_by":"Christoph Görn","updated_at":"2026-05-25T11:49:15Z","started_at":"2026-05-25T11:47:15Z","closed_at":"2026-05-25T11:49:15Z","close_reason":"PR #153 merged. Inline syft+goreleaser install in release Step; v2.24.1 cut next to validate.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-hvr","title":"Fix release workflow smoke-test: --help + dead ldflags break v2.23.0 release","description":"Release run 172 (tag v2.23.0) failed at smoke-test step in .forgejo/workflows/release.yml. Two compounding bugs:\n\n1. main.go declares 'var Version = \"dev\"' but .goreleaser.yml ldflags inject '-X main.BuildTag={{.Version}}' (and BuildCommit/BuildDate). Symbol main.BuildTag is not defined anywhere — grep returns zero hits. So Version stays 'dev' in shipped binaries.\n\n2. Smoke-test runs '$BIN --help' but the CLI uses flag.NewFlagSet with ExitOnError; --help is undefined, exits non-zero with 'flag provided but not defined: -help' on stderr and Usage banner. The expected regex '^forgejo-mcp ${VERSION}([+-]|$)' never matches.\n\nFix:\n- .goreleaser.yml: rewrite ldflags to -X main.Version={{.Version}} (drop dead BuildCommit/BuildDate or wire them to real vars).\n- .forgejo/workflows/release.yml: invoke '$BIN version' (the 'version' subcommand documented in cmd.go isVersionRequest) instead of '--help'.\n\nTracks: https://codeberg.org/goern/forgejo-mcp/actions/runs/172","notes":"PR #149 opened: https://codeberg.org/goern/forgejo-mcp/pulls/149. Fix verified locally (ldflags + 'version' subcommand). Awaiting merge + next release tag to re-cut release pipeline.","status":"closed","priority":1,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-25T08:28:14Z","created_by":"Christoph Görn","updated_at":"2026-05-25T08:37:38Z","started_at":"2026-05-25T08:28:17Z","closed_at":"2026-05-25T08:37:38Z","close_reason":"PR #149 merged into main (merge commit 332b989). Release pipeline fixed; next semantic-release tag (v2.23.1+) will re-cut a clean release.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-5x8","title":"fix: add pull_request event to Codeberg webhook for op1st PaC","description":"Codeberg repo webhook (id 60326) to op1st Pipelines-as-Code controller only subscribes to push event. No pull_request event delivered, so on-pull-request, openspec-validate-pr, code-scans PR pipelines never fire on any open PR (#126, #138, #139). Push pipelines on main work fine (verified on 4f57c57). Fix: PATCH hook events to include pull_request (and pull_request_comment for /ok-to-test on fork PRs).","notes":"Verified via curl: events=['push']. Root cause of all three open PRs lacking PaC statuses.","status":"closed","priority":1,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-24T07:13:31Z","created_by":"Christoph Görn","updated_at":"2026-05-24T07:16:46Z","started_at":"2026-05-24T07:15:18Z","closed_at":"2026-05-24T07:16:46Z","close_reason":"Patched webhook 60326 events from ['push'] to push+pull_request+pull_request_comment (plus auto-expanded subevents). Verified: /test comment on PR #139 triggered op1st Pipelines as Code / on-pull-request status (pending). All future PR opens/syncs/comments will now reach PaC.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-f37","title":"CI: add lint, race, mod-tidy, govulncheck to go-ci task","description":"Current .tekton/tasks/go-ci.yaml only does build+test. Missing critical correctness gates. Add golangci-lint (gofmt, errcheck, staticcheck, ineffassign, gosec), go test -race -shuffle=on -count=1, go mod tidy drift check, govulncheck ./...","acceptance_criteria":"go vet runs, golangci-lint runs (warning-only first pass acceptable), race detector on, govulncheck zero high-severity findings, go.mod/go.sum drift fails build","notes":"PR opened: https://codeberg.org/goern/forgejo-mcp/pulls/142 (mergeable). Bead stays in_progress until merge — close on merge.","status":"closed","priority":1,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-24T07:06:30Z","created_by":"Christoph Görn","updated_at":"2026-05-24T07:24:57Z","started_at":"2026-05-24T07:06:57Z","closed_at":"2026-05-24T07:24:57Z","close_reason":"Merged via PR #142 (rebase). Step 1 hardening live in main.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-o5b","title":"Gate image :latest promotion to stable releases only","description":"promote-image-tag (.tekton/release-tools/tasks/promote-image-tag.yaml) unconditionally tags BOTH :vX.Y.Z and :latest. The release pipeline triggers on any refs/tags/v[0-9], including pre-releases (alpha/beta/rc). Result: a pre-release would move :latest to a non-stable image. For v2.27.0-alpha.1 (2026-06-01) :latest was deliberately skipped via a manual skopeo copy. Fix: skip the :latest promotion when TAG matches a pre-release pattern (contains '-'), or pass a PROMOTE_LATEST flag from the pipeline computed from the tag.","status":"closed","priority":2,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-06-01T08:59:32Z","created_by":"Christoph Görn","updated_at":"2026-06-01T09:08:59Z","closed_at":"2026-06-01T09:08:59Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-01e","title":"Add OWNERS file to authorize PaC CI triggering","description":"PR #178 (author: byteflavour) is blocked with 'User byteflavour is not allowed to trigger CI via pull_request in this repo'. This is Pipelines as Code (op1st-pipelines ns), which reads a Prow-style OWNERS file from the default branch to decide who may trigger a PipelineRun without /ok-to-test. Add OWNERS listing goern, byteflavour, b4mad-renovate, op1st-gitops so their PRs trigger CI automatically.","status":"closed","priority":2,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-31T19:00:57Z","created_by":"Christoph Görn","updated_at":"2026-05-31T19:02:06Z","started_at":"2026-05-31T19:01:00Z","closed_at":"2026-05-31T19:02:06Z","close_reason":"OWNERS file added on main branch; PaC will now auto-trigger for goern, byteflavour, b4mad-renovate, op1st-gitops PRs. Unblocks PR #178.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-vbz","title":"Update Containerfile to use hummingbird-project based containers","description":"Migrate Containerfile base images from registry.access.redhat.com (go builder + core-runtime) to hummingbird-project based containers. Affects both build stage and runtime stage. Verify build still works (make build, CGO_ENABLED=0) and image runs the forgejo-mcp entrypoint.","notes":"Project Hummingbird = Red Hat hardened images (gitlab.com/redhat/hummingbird/containers), public mirror quay.io/hummingbird/*, non-root. Current Containerfile uses registry.access.redhat.com/hi/* (same images, RH registry). Migration = repoint to quay mirror. Mapping: build stage /hi/go:1.26.3-builder -\u003e quay.io/hummingbird/go:\u003cver\u003e-builder ; runtime /hi/core-runtime:2.42 -\u003e quay.io/hummingbird/core-runtime (or quay.io/hummingbird/static, binary is CGO_ENABLED=0 static). Decide static vs core-runtime, pin tags + digests. Verify: make build (CGO_ENABLED=0), image runs /app/forgejo-mcp entrypoint.","status":"closed","priority":2,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-31T18:39:10Z","created_by":"Christoph Görn","updated_at":"2026-05-31T19:23:43Z","started_at":"2026-05-31T18:44:31Z","closed_at":"2026-05-31T19:23:43Z","close_reason":"Done in PR (branch feat/hummingbird-containers, commit 988398a). Containerfile repointed to quay.io/hummingbird/{go,core-runtime} (identical digests); VERSION injected via build-arg fixing empty version/--version output.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-5zy","title":"Track + visualize release asset download counts","description":"Forgejo API exposes cumulative download_count per release asset, but keeps no history. Snapshot daily into JSONL (git = time-series DB), then visualize per-release and feat-vs-fix (semver-bump classification) in a static Chart.js dashboard. Scheduler: one reintroduced Forgejo Actions cron workflow (Tekton-only stack otherwise; user accepted the tradeoff).","status":"closed","priority":2,"issue_type":"feature","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-31T14:55:18Z","created_by":"Christoph Görn","updated_at":"2026-05-31T15:06:14Z","started_at":"2026-05-31T14:55:22Z","closed_at":"2026-05-31T15:06:14Z","close_reason":"Shipped via PR #177 — daily download tracking + Chart.js dashboard","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-dn0","title":"Extend release pipeline to build and push an OCI container image","description":"The app release pipeline (.tekton/on-tag-push-release.yaml, fired on tag push) builds binaries via GoReleaser + cosign-signs + packs mcpb, but does NOT build or publish an OCI container image for forgejo-mcp itself. A multi-stage root Containerfile already exists and builds a working runtime image — it's just never built/pushed on release.\n\nScope:\n- On tag push, build the OCI image from the root Containerfile (binary already produced by 'make build').\n- Push by digest to a registry (Codeberg package/OCI registry under goern/forgejo-mcp, or quay — decide), tagged with the release version + a moving tag (e.g. latest).\n- Sign the image with cosign and attach an SBOM, matching the binary-release security posture.\n- REUSE the existing Tekton tasks already in-repo for the release-tools image: .tekton/release-tools/tasks/{build-image,push-image-by-digest,cosign-sign-image-by-digest,cosign-attach-sbom,promote-image-tag}.yaml — wire them into the app release pipeline rather than authoring new ones.\n- Document the published image (registry path, supported tags, cosign verify command) in README.\n\nOpen decisions: target registry + namespace; whether to build multi-arch (amd64/arm64); tag scheme (semver + latest); whether image publish gates on the same tag event as GoReleaser or a separate pipeline.\n\nWhy: ship a runnable container so users can 'podman run' the MCP server without building from source; aligns app distribution with the already-containerized release-tools image and the signed-binary posture.","status":"closed","priority":2,"issue_type":"feature","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-31T14:45:07Z","created_by":"Christoph Görn","updated_at":"2026-06-01T06:49:21Z","started_at":"2026-06-01T06:29:55Z","closed_at":"2026-06-01T06:49:21Z","close_reason":"Implemented: tag-push release pipeline now builds, signs, SBOM-attaches and publishes the OCI image to codeberg.org/goern/forgejo-mcp by reusing the release-tools tasks. Commit bdfd968.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-fd6","title":"Label tools + label resource templates","description":"forgejo-mcp exposes list_repo_labels / list_org_labels / add_issue_labels / remove_issue_labels, but has NO label CRUD: cannot create, edit, or delete a repo/org label. Surfaced 2026-05-31 while creating the 'RFC - Request For Comments' label for #176 — had to fall back to raw curl against the Forgejo REST API because no MCP tool exists. (Reactions read was the same gap.)\n\nScope:\n- Tools: create_label, edit_label, delete_label for repo labels (POST/PATCH/DELETE /repos/{o}/{r}/labels[/{id}]); consider org-label equivalents (/orgs/{org}/labels).\n- Resource templates: forgejo://repo/{owner}/{repo}/label/{id} and/or a labels listing resource, so labels are URI-addressable like the existing issue/pr/commit resources. Follow operation/resource conventions (ParseXxx, Bounded, MapForgejoError) and docs/design/output-bounding.md.\n- Implement via forgejo-sdk where available, else pkg/forgejo raw-HTTP (DoJSON) like the wiki/attachment precedent.\n- Surface in README tool+resource tables and AGENTS.md.\n\nWhy: closes a real CRUD gap (label management currently impossible via MCP) and extends the resource-template surface to labels for discoverability.","status":"open","priority":2,"issue_type":"feature","owner":"goern@b4mad.net","created_at":"2026-05-31T14:40:12Z","created_by":"Christoph Görn","updated_at":"2026-05-31T14:40:12Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-3ph","title":"OpenSpec: wiki tools via direct API + wiki page resource template","description":"Codeberg issue #32 (goern/forgejo-mcp). Author an OpenSpec change proposing wiki support implemented via direct Forgejo REST API calls (pkg/forgejo/rawhttp.go DoJSON helpers) rather than forgejo-sdk v3 (which has NO wiki methods — current operation/wiki/wiki.go behind //go:build wiki tag does not compile). Scope: 6 wiki tools (list/get/get_revisions/create/update/delete), a forgejo://repo/{owner}/{repo}/wiki/{pageName} resource template, output-bounding compliance, discovery surfacing (README+AGENTS.md), and a showboat demo. This bead covers authoring the spec only.","status":"closed","priority":2,"issue_type":"feature","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-31T12:49:49Z","created_by":"Christoph Görn","updated_at":"2026-05-31T12:54:17Z","started_at":"2026-05-31T12:49:53Z","closed_at":"2026-05-31T12:54:17Z","close_reason":"OpenSpec change add-wiki-support authored, validated (--strict), pushed as PR #176; minutes on Codeberg #32. Implementation tracked by the spec tasks.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-pkz","title":"demos: mcp-resource-templates walkthrough for forgejo:// URIs","description":"PR #172 shipped 7 resource templates on the forgejo:// scheme (owner, repo, commit, commit-status, issue, comment, pr), but no entry in demos/ covers them. Other features in demos/ all have one-file-per-feature walkthroughs (see demos/README.md). This is the gap that aligns with the deferred OpenSpec task 1.11 (manual client verification).\n\nDeliverable: demos/mcp-resource-templates.md following the structure in demos/README.md:\n1. Background / what resource templates are and why (instance-portable forgejo:// URIs, additive to tools, JSON + markdown sidecar)\n2. Setup (export FORGEJO_URL, FORGEJO_ACCESS_TOKEN, make build)\n3. Walkthrough — one shell block per URI template (7 total) with REAL output captured against codeberg.org/goern/forgejo-mcp. Note: --cli does NOT support resources, so use stdio JSON-RPC: echo a resources/list or resources/read request, pipe to ./forgejo-mcp -t stdio -url $FORGEJO_URL -token $FORGEJO_ACCESS_TOKEN, parse with jq/python.\n4. End-to-end / autonomous agent workflow — how an MCP client uses templates instead of tools (e.g. fetch repo metadata + recent commits via templates, fall back to list_repo_commits for pagination).\n\nConstraints:\n- Must use real codeberg.org payloads, not fabricated.\n- Must show both JSON and markdown sidecar where applicable (commit/issue/pr/comment).\n- Must document the EmbeddedListCap=30 truncation sentinel + comments_list_tool escape hatch.\n- Keep payloads excerpted where huge (use jq/python to slice).\n- Follow demos/bounded-responses.md style for tone.\n\nRelated: PR #172 (forgejo-mcp-13x), follow-ups forgejo-mcp-7ra (subscribe) and forgejo-mcp-7de (cap telemetry). Closes part of deferred OpenSpec task 1.11.","notes":"PR #173 opened — https://codeberg.org/goern/forgejo-mcp/pulls/173. Branch: demo-resource-templates. Commit: 945b54b. Bead stays in_progress until PR merges. Bead closes at merge time per workflow-issue-pr-create-bead. Security: gitleaks clean, no token leaks, only commit SHAs in 40+ char matches.","status":"closed","priority":2,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-05-28T15:59:40Z","created_by":"Christoph Görn","updated_at":"2026-05-28T22:29:09Z","started_at":"2026-05-28T15:59:54Z","closed_at":"2026-05-28T22:29:09Z","close_reason":"Merged via PR #173 (commit 12613c1a). Demo file demos/mcp-resource-templates.md shipped on main. Gitleaks clean, CI green, op1st-gitops PaC pipelines all success.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-ylb","title":"Address all PR #172 code review findings (fix-pull_172)","description":"Umbrella bead tracking all 13 fix beads created from the automated code review on https://codeberg.org/goern/forgejo-mcp/pulls/172#issuecomment-16022165. Closes when all child fix beads are closed. Two clusters dominate the findings: (1) truncation sentinel never fires because 4 SDK call sites pass empty options and Forgejo's default PageSize=30 == EmbeddedListCap; (2) parse errors in 4 sibling handlers wrap with fmt.Errorf instead of resource.MapForgejoError, losing -32602. Plus errors.go substring-classification, owner fallback, parse.go empty-segment handling, and a typo.","notes":"Children (13 beads):\n\nHigh-impact (P2, 5 beads):\n- forgejo-mcp-cmw — Fix double-wrapped ResourceError in resources_commit.go:51\n- forgejo-mcp-u3y — Pass PageSize \u003e EmbeddedListCap to ListIssueComments (issue/resources.go:93)\n- forgejo-mcp-ghr — Pass PageSize \u003e EmbeddedListCap to ListIssueComments (pull/resources.go:108)\n- forgejo-mcp-5dz — Pass PageSize \u003e EmbeddedListCap to ListPullReviews (pull/resources.go:111)\n- forgejo-mcp-827 — Pass PageSize \u003e EmbeddedListCap to ListStatuses (resources_status.go:73)\n\nMedium-impact (P3, 8 beads):\n- forgejo-mcp-vzz — Map parse error via MapForgejoError (resources_commit.go:39)\n- forgejo-mcp-s2g — Map parse error via MapForgejoError (resources_repo.go:61)\n- forgejo-mcp-g5s — Map parse error via MapForgejoError (resources_status.go:65)\n- forgejo-mcp-iqi — Map parse error via MapForgejoError (resources_owner.go:56)\n- forgejo-mcp-wgs — Replace substring-based HTTP classification (errors.go:26)\n- forgejo-mcp-91j — Fix user→org fallback masking + nil-userErr (resources_owner.go:96)\n- forgejo-mcp-16t — Reject empty/whitespace URI segments (parse.go:220)\n- forgejo-mcp-8ia — Fix CommmentsTruncated typo (pull/resources.go:79)","status":"closed","priority":2,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-05-28T13:48:49Z","created_by":"Christoph Görn","updated_at":"2026-05-28T14:18:53Z","closed_at":"2026-05-28T14:18:53Z","close_reason":"All 13 review findings fixed in commits 683404c..182898a. PR #172 review-fix chain complete.","dependencies":[{"issue_id":"forgejo-mcp-ylb","depends_on_id":"forgejo-mcp-16t","type":"blocks","created_at":"2026-05-28T13:48:54Z","created_by":"Christoph Görn","metadata":"{}"},{"issue_id":"forgejo-mcp-ylb","depends_on_id":"forgejo-mcp-5dz","type":"blocks","created_at":"2026-05-28T13:48:53Z","created_by":"Christoph Görn","metadata":"{}"},{"issue_id":"forgejo-mcp-ylb","depends_on_id":"forgejo-mcp-827","type":"blocks","created_at":"2026-05-28T13:48:53Z","created_by":"Christoph Görn","metadata":"{}"},{"issue_id":"forgejo-mcp-ylb","depends_on_id":"forgejo-mcp-8ia","type":"blocks","created_at":"2026-05-28T13:48:54Z","created_by":"Christoph Görn","metadata":"{}"},{"issue_id":"forgejo-mcp-ylb","depends_on_id":"forgejo-mcp-91j","type":"blocks","created_at":"2026-05-28T13:48:53Z","created_by":"Christoph Görn","metadata":"{}"},{"issue_id":"forgejo-mcp-ylb","depends_on_id":"forgejo-mcp-cmw","type":"blocks","created_at":"2026-05-28T13:48:52Z","created_by":"Christoph Görn","metadata":"{}"},{"issue_id":"forgejo-mcp-ylb","depends_on_id":"forgejo-mcp-g5s","type":"blocks","created_at":"2026-05-28T13:48:53Z","created_by":"Christoph Görn","metadata":"{}"},{"issue_id":"forgejo-mcp-ylb","depends_on_id":"forgejo-mcp-ghr","type":"blocks","created_at":"2026-05-28T13:48:53Z","created_by":"Christoph Görn","metadata":"{}"},{"issue_id":"forgejo-mcp-ylb","depends_on_id":"forgejo-mcp-iqi","type":"blocks","created_at":"2026-05-28T13:48:53Z","created_by":"Christoph Görn","metadata":"{}"},{"issue_id":"forgejo-mcp-ylb","depends_on_id":"forgejo-mcp-s2g","type":"blocks","created_at":"2026-05-28T13:48:53Z","created_by":"Christoph Görn","metadata":"{}"},{"issue_id":"forgejo-mcp-ylb","depends_on_id":"forgejo-mcp-u3y","type":"blocks","created_at":"2026-05-28T13:48:52Z","created_by":"Christoph Görn","metadata":"{}"},{"issue_id":"forgejo-mcp-ylb","depends_on_id":"forgejo-mcp-vzz","type":"blocks","created_at":"2026-05-28T13:48:53Z","created_by":"Christoph Görn","metadata":"{}"},{"issue_id":"forgejo-mcp-ylb","depends_on_id":"forgejo-mcp-wgs","type":"blocks","created_at":"2026-05-28T13:48:53Z","created_by":"Christoph Görn","metadata":"{}"}],"dependency_count":13,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-5dz","title":"Pass PageSize \u003e EmbeddedListCap to ListPullReviews in operation/pull/resources.go:111","description":"ListPullReviews with empty options — reviews capped at server default 30 = EmbeddedListCap so reviews_truncated/reviews_list_tool sentinel never fires. ReviewCount: len(reviews) also wrong (first-page count, not total). Review: https://codeberg.org/goern/forgejo-mcp/pulls/172#issuecomment-16022165 (conf 92).","notes":"Fix: at operation/pull/resources.go:111, pass forgejo_sdk.ListPullReviewsOptions{ListOptions: forgejo_sdk.ListOptions{PageSize: resource.EmbeddedListCap + 1}}. For accurate ReviewCount when truncated, either omit the field when truncated or paginate fully (probably out of scope for v1; document the caveat).","status":"closed","priority":2,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-28T13:46:42Z","created_by":"Christoph Görn","updated_at":"2026-05-28T14:18:53Z","started_at":"2026-05-28T14:17:15Z","closed_at":"2026-05-28T14:18:53Z","close_reason":"All 13 review findings fixed in commits 683404c..182898a. PR #172 review-fix chain complete.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-827","title":"Pass PageSize \u003e EmbeddedListCap to ListStatuses in operation/repo/resources_status.go:73","description":"ListStatuses with empty ListStatusesOption{} — server pages at default 30 = EmbeddedListCap so the \u003ecap truncation check never fires for SHAs with many status contexts. AGENTS.md output-bounding rule violated. Review: https://codeberg.org/goern/forgejo-mcp/pulls/172#issuecomment-16022165 (conf 90).","notes":"Fix: at operation/repo/resources_status.go:73, pass forgejo_sdk.ListStatusesOption{ListOptions: forgejo_sdk.ListOptions{PageSize: resource.EmbeddedListCap + 1}}.","status":"closed","priority":2,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-28T13:46:42Z","created_by":"Christoph Görn","updated_at":"2026-05-28T14:14:17Z","started_at":"2026-05-28T14:11:59Z","closed_at":"2026-05-28T14:14:17Z","close_reason":"Fixed in ee1217d. PageSize=cap+1; truncation sentinel surfaces correctly.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-cmw","title":"Fix double-wrapped ResourceError in operation/repo/resources_commit.go:51","description":"commitResourceHandler does 'return nil, fmt.Errorf(\"%w\", mappedErr)' where mappedErr is *resource.ResourceError. Downstream code using err.(*resource.ResourceError) gets (nil, false) — so -32603 internal error surfaces instead of the intended -32003/-32002 for commit URIs only. Every other handler returns the ResourceError directly. Review: https://codeberg.org/goern/forgejo-mcp/pulls/172#issuecomment-16022165 (conf 92).","notes":"Fix: at operation/repo/resources_commit.go:50-51, replace\n mappedErr := resource.MapForgejoError(uri, fmt.Errorf(\"%d %s\", resp.StatusCode, err.Error()))\n return nil, fmt.Errorf(\"%w\", mappedErr)\nwith\n return nil, resource.MapForgejoError(uri, fmt.Errorf(\"%d %s\", resp.StatusCode, err.Error()))","status":"closed","priority":2,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-28T13:46:42Z","created_by":"Christoph Görn","updated_at":"2026-05-28T13:57:03Z","started_at":"2026-05-28T13:55:39Z","closed_at":"2026-05-28T13:57:03Z","close_reason":"Fixed in f8d661e. ResourceError now returned directly; type-assertion surfaces correct JSON-RPC code.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-ghr","title":"Pass PageSize \u003e EmbeddedListCap to ListIssueComments in operation/pull/resources.go:108","description":"Same defect as issue handler — PR comments ListIssueComments uses empty options so server caps at default 30 = EmbeddedListCap, sentinel never fires. Review: https://codeberg.org/goern/forgejo-mcp/pulls/172#issuecomment-16022165 (conf 92).","notes":"Fix: at operation/pull/resources.go:108, pass forgejo_sdk.ListIssueCommentOptions{ListOptions: forgejo_sdk.ListOptions{PageSize: resource.EmbeddedListCap + 1}}.","status":"closed","priority":2,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-28T13:46:42Z","created_by":"Christoph Görn","updated_at":"2026-05-28T14:17:15Z","started_at":"2026-05-28T14:15:49Z","closed_at":"2026-05-28T14:17:15Z","close_reason":"Fixed in 9e5b930.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-u3y","title":"Pass PageSize \u003e EmbeddedListCap to ListIssueComments in operation/issue/resources.go:93","description":"ListIssueComments called with default ListIssueCommentOptions{}. Forgejo's default PageSize=30 == EmbeddedListCap, so the \u003ecap truncation check NEVER fires. Issues with \u003e30 comments silently lose the recent_comments_truncated/list_tool sentinel. AGENTS.md output-bounding rule violated. Review: https://codeberg.org/goern/forgejo-mcp/pulls/172#issuecomment-16022165 (conf 92).","notes":"Fix: at operation/issue/resources.go:93, pass an explicit PageSize:\n comments, _, _ := client.ListIssueComments(params.Owner, params.Repo, params.Index,\n forgejo_sdk.ListIssueCommentOptions{ListOptions: forgejo_sdk.ListOptions{PageSize: resource.EmbeddedListCap + 1}})\nVerify via a new test that 31 mock comments produce truncated=true.","status":"closed","priority":2,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-28T13:46:42Z","created_by":"Christoph Görn","updated_at":"2026-05-28T14:15:49Z","started_at":"2026-05-28T14:14:17Z","closed_at":"2026-05-28T14:15:49Z","close_reason":"Fixed in 321b1a0.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-13x","title":"Implement all 7 slices of mcp-resource-templates (resource framework + 7 entity resources + docs)","description":"Implement the first two slices of the mcp-resource-templates OpenSpec change merged via PR #148. Slice 1 (mcp-resources-core): server.WithResourceCapabilities(false,false), operation/resource/ package (parse, register, bound, errors helpers), RegisterCoreResources stub wired in operation/operation.go, plus unit tests. Slice 2 (mcp-resource-commit): operation/repository/resources_commit.go with RegisterCommitResource, forgejo://repo/{owner}/{repo}/commit/{sha} template, JSON + markdown sidecar handler, unit tests, wiring, README row. Verifier: go build ./... \u0026\u0026 go test ./... . Driven via team:dev-loop.","notes":"Originally scoped to slices 1+2. Team:dev-loop completed all 7 slices in one session. PR #172 opened: https://codeberg.org/goern/forgejo-mcp/pulls/172. Awaiting CI + review. Follow-ups: forgejo-mcp-7ra (subscribe=true), forgejo-mcp-7de (EmbeddedListCap).","status":"closed","priority":2,"issue_type":"feature","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-28T12:15:54Z","created_by":"Christoph Görn","updated_at":"2026-05-28T15:49:26Z","started_at":"2026-05-28T12:15:58Z","closed_at":"2026-05-28T15:49:26Z","close_reason":"PR #172 merged to main (commit 872d4c5). 7 slices shipped. Follow-ups tracked in 7ra/7de. Manual client verification (task 1.11) remains post-merge work.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-1tc","title":"Fix openspec spec/release-tools-image format (missing Purpose+Requirements headers)","description":"The archived spec at openspec/specs/release-tools-image/spec.md (introduced in bd92d21) starts with '## ADDED Requirements' (the change-delta format), but openspec validate --strict requires top-level specs to have '## Purpose' and '## Requirements' headers. This breaks the Tekton openspec-validate gate on any PR that merges main, including PR #148. Fix: rewrite spec headers to conventional spec format. Land via PR #148 to unblock it.","status":"closed","priority":2,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-28T12:02:16Z","created_by":"Christoph Görn","updated_at":"2026-05-28T12:03:06Z","started_at":"2026-05-28T12:02:19Z","closed_at":"2026-05-28T12:03:06Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-het","title":"Dashboard: focus mode highlights node + neighbours in subway map","description":"When user clicks an issue card in the registry, highlight that bead node plus its transitive dependencies and dependants in the dependency graph. Dim unrelated nodes/edges. Clicking the same card again clears focus.","acceptance_criteria":"Clicking an issue card highlights the matching subway-map station and its full upstream + downstream chain; unrelated stations and edges dim; clicking the focused card again or any non-station SVG area clears focus.","status":"closed","priority":2,"issue_type":"feature","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-26T13:39:15Z","created_by":"Christoph Görn","updated_at":"2026-05-26T13:42:48Z","started_at":"2026-05-26T13:39:18Z","closed_at":"2026-05-26T13:42:48Z","close_reason":"focus-mode shipped in 8fc1e75 — card click dims unrelated dep-graph nodes, highlights full ancestor+descendant chain; SVG background click clears focus","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-3a9","title":"Dashboard: subway-map dependency graph","description":"Replace the flat text edge list in beads-dashboard.html with a layered SVG subway-map view of issue dependencies. Goals: visualise upstream→downstream chains, colour 'lines' per source issue, click station to jump to that issue card.","acceptance_criteria":"SVG renders all dep edges with no overlapping stations; click on a station selects and scrolls to the matching issue; nodes coloured by status (closed/in_progress/open); responsive layout (page still usable at 800px width).","status":"closed","priority":2,"issue_type":"feature","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-25T23:08:05Z","created_by":"Christoph Görn","updated_at":"2026-05-25T23:10:21Z","started_at":"2026-05-25T23:08:09Z","closed_at":"2026-05-25T23:10:21Z","close_reason":"subway-map dep view shipped in beads-dashboard.html — layered SVG with orthogonal routing, status-coloured stations, click-to-jump.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-wqm","title":"Rewrite .tekton/tasks/ to use release-tools image (drop runtime installs)","description":"All 5 tasks in .tekton/tasks/ still install tools at runtime (microdnf, curl, go install, npx -y, npm install -g). With govulncheck and openspec now baked into the release-tools image, all runtime installs can be removed. Tasks to rewrite: goreleaser-release (syft+goreleaser go install), cosign-sign-release (microdnf jq+curl in upload step), mcpb-pack (npx -y mcpb + apt-get jq), go-ci (govulncheck go install), openspec-validate (npm install -g openspec). Each task should use RELEASE_TOOLS_IMAGE param defaulting to codeberg.org/operate-first/release-tools:latest. External PR: https://codeberg.org/goern/forgejo-mcp/pulls/157","status":"closed","priority":2,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-25T21:21:01Z","created_by":"Christoph Görn","updated_at":"2026-05-25T21:24:08Z","started_at":"2026-05-25T21:21:04Z","closed_at":"2026-05-25T21:24:08Z","close_reason":"All 5 tasks rewritten in commit 0dcb2e1. No runtime installs remain. Minutes posted to PR #157.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-6t6","title":"Fix code review issues from PR #157 automated review","description":"Address all 11 inline review comments from the automated multi-agent review on PR #157 (release-tools image + Tekton pipelines). Comments span: (1) build-image IMAGE_DIGEST extraction broken, (2) syft-scan-image tries registry pull for unpushed image, (3) push-image-by-digest TOCTOU concern, (4) Containerfile floating base tag, (5) syft installer from main branch, (6) cosign no integrity verify, (7) npm install -g re-resolves transitive deps, (8-9) cosign-sign + cosign-attach-sbom unverified downloads, (10) SKIP_SIGN ungated, (11) mutable cosign.pub URL in README. External PR: https://codeberg.org/goern/forgejo-mcp/pulls/157","status":"closed","priority":2,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-25T21:04:41Z","created_by":"Christoph Görn","updated_at":"2026-05-25T21:12:09Z","started_at":"2026-05-25T21:04:45Z","closed_at":"2026-05-25T21:12:09Z","close_reason":"All 11 review findings fixed in commit d59b910, pushed to feat/release-tools-pipelines, minutes posted to PR #157","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-46j","title":"Publish SLSA provenance attestation for release-tools image via Tekton Chains","description":"Origin: L5 from release-tools-image adversarial review. Tekton Chains is deployed in op1st-pipelines (per ADR docs/design/release-pipeline-migration.md and op1st-emea-b4mad manifests/applications/op1st-pipelines/tekton-chains.yaml) but the release-tools publish pipeline does not consume its in-toto SLSA v1.0 attestations. Cosign signature alone attests signer-holds-key, NOT build-provenance binding image digest → PipelineRun → git commit → builder identity. With key-split (L4) still pending, the provenance gap is exploitable. Fix: enable Chains annotations on the publish PipelineRun (chains.tekton.dev/transparency-upload: true), have Chains produce SLSA v1.0 provenance, attach as cosign attestation, document 'cosign verify-attestation --type slsaprovenance' in README.","notes":"PR #165 opened: https://codeberg.org/goern/forgejo-mcp/pulls/165. Changes: chains.tekton.dev/transparency-upload annotation, IMAGE_URL+IMAGE_DIGEST pipeline results, push-image-by-digest IMAGE_URL result, README verify-attestation section, ADR addendum.","status":"closed","priority":2,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-25T13:52:26Z","created_by":"Christoph Görn","updated_at":"2026-05-26T13:09:04Z","started_at":"2026-05-26T13:04:36Z","closed_at":"2026-05-26T13:09:04Z","close_reason":"PR #165 merged — Tekton Chains SLSA provenance enabled for release-tools image","dependencies":[{"issue_id":"forgejo-mcp-46j","depends_on_id":"forgejo-mcp-1b4","type":"blocks","created_at":"2026-05-25T13:52:44Z","created_by":"Christoph Görn","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-a2y","title":"Remove in-repo secrets/ + use op1st-emea-b4mad as normative source for cosign public key","description":"Delete secrets/cosign.pub, secrets/cosign-signing-key.enc.yaml, secrets/.gitkeep (and the dir). Cosign-signing-key public key normative source moves to https://codeberg.org/operate-first/op1st-emea-b4mad/raw/.../cosign-signing-key.pub, matching the Tekton release pipeline's signing key in op1st-pipelines namespace. Note: legacy releases signed via Forgejo Actions (Codeberg Actions COSIGN_PRIVATE_KEY) used a different keypair (now-deleted secrets/cosign.pub) — historical verification still possible via git history of commit 791ef6d.","acceptance_criteria":"secrets/ directory removed from main; .gitignore rules for secrets/ cleaned up; README Verifying Releases chapter points at op1st-emea-b4mad URL; ADR + runbook references updated; legacy-key note explains historical signature verification","notes":"PR opened: https://codeberg.org/goern/forgejo-mcp/pulls/152 (branch chore/remove-stale-secrets). Stale secrets/ + scripts/cosign-keygen.sh removed; README + ADR + runbook now point at op1st-emea-b4mad/.../cosign-signing-key.pub (commit 8a3c55e5).","status":"closed","priority":2,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-25T11:33:54Z","created_by":"Christoph Görn","updated_at":"2026-05-25T11:38:24Z","started_at":"2026-05-25T11:34:01Z","closed_at":"2026-05-25T11:38:24Z","close_reason":"PR #152 merged. secrets/ + scripts/cosign-keygen.sh removed; README + ADR + runbook now point at op1st-emea-b4mad/.../cosign-signing-key.pub as normative source.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-n85","title":"Disable Forgejo Actions release workflow auto-trigger (soft cutover)","description":"Switch .forgejo/workflows/release.yml trigger from 'push tags v*' to 'workflow_dispatch' only. Stops auto-firing on tag push while preserving the file as a manual fallback if the op1st Tekton release pipeline (added in PR #150) fails. Full file deletion deferred to forgejo-mcp-gdz once 2 successful Tekton releases prove the cutover.","acceptance_criteria":".forgejo/workflows/release.yml on=workflow_dispatch only; ADR addendum noting soft-disable date; PR opened","notes":"PR opened: https://codeberg.org/goern/forgejo-mcp/pulls/151 (branch chore/disable-forgejo-release). Trigger switched to workflow_dispatch only; ADR moved to Accepted (soft-cutover phase). Close on merge.","status":"closed","priority":2,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-25T11:29:02Z","created_by":"Christoph Görn","updated_at":"2026-05-25T11:31:15Z","started_at":"2026-05-25T11:29:06Z","closed_at":"2026-05-25T11:31:15Z","close_reason":"PR #151 merged. Trigger now workflow_dispatch only; Tekton sole auto-firing release path; Forgejo workflow preserved as manual fallback.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-d4b","title":"Migrate Forgejo release workflow to op1st Tekton pipeline","description":"Port .forgejo/workflows/release.yml to .tekton/ as a PipelinesAsCode release pipeline triggered on tag push v*. Cover all current features: GoReleaser w/ syft SBOMs, smoke-test of linux/amd64 binary, cosign sign-blob of checksums.txt + upload, .mcpb pack per platform (linux/darwin × amd64/arm64) + upload to Codeberg release. Run in parallel with existing Forgejo Actions release; cutover deferred. Add ADR + migration notes.","design":"PipelinesAsCode on-event=push with on-target-branch=refs/tags/v* (matches forgejo-mcp-33k cross-repo spike pattern only if PaC supports tag-push; falls back to tag-push directly). Three new tasks mirroring go-ci.yaml structure. Secrets: RELEASE_TOKEN, COSIGN_PRIVATE_KEY/PASSWORD assumed present in op1st-pipelines namespace. Existing release.yml stays untouched.","acceptance_criteria":"release pipeline yaml in .tekton/ triggered by tag push v*; reusable tasks for goreleaser, cosign-sign-blob, mcpb-pack defined under .tekton/tasks/; docs/design/release-pipeline-migration.md ADR explaining parallel-run + cutover criteria; PR opened on Codeberg","notes":"PR #150: https://codeberg.org/goern/forgejo-mcp/pulls/150. Secret validation done 2026-05-25: op1st-release-token + cosign-signing-key both confirmed in op1st-pipelines (shape + scope + cosign.pub match). Pipeline ready; next v* tag triggers parallel Tekton run. Close after 2 successful Tekton releases satisfy ADR cutover criteria.","status":"closed","priority":2,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-25T09:10:22Z","created_by":"Christoph Görn","updated_at":"2026-05-25T11:28:00Z","started_at":"2026-05-25T09:10:26Z","closed_at":"2026-05-25T11:28:00Z","close_reason":"PR #150 merged (commit 6c824c9). All acceptance criteria met: .tekton release PipelineRun + 3 reusable Tasks + ADR + runbook + README verification chapter all in main. Parallel-run begins on next v* tag. Cutover decision tracked in forgejo-mcp-gdz.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-dhd","title":"ci: gitleaks allowlist for placeholder tokens in demo docs","description":"gitleaks 'generic-api-key' rule flags 'Authorization: token invalid_token' on demos/multi-tenant-http.md:109 (commit bd08d6147 on fork branch byteflavour/stateless-token, incoming PR). The token is intentional test data — request 4 in the multi-tenant HTTP demo shows what an invalid token does. Add a path+regex-scoped allowlist so demo docs can use placeholder tokens (invalid_token, changeme, etc.) without tripping the scanner, while real generic-api-key detection stays intact elsewhere.","acceptance_criteria":"gitleaks scan over demos/multi-tenant-http.md returns 0 leaks. Real secret patterns elsewhere in repo still flagged. Allowlist scope limited to demos/*.md.","notes":"PR opened: https://codeberg.org/goern/forgejo-mcp/pulls/147 (mergeable). Per-rule allowlist on curl-auth-header scoped to demos/*.md + placeholder regexes. Local gitleaks v8.30.1 negative test confirms real github-pat still flagged.","status":"closed","priority":2,"issue_type":"bug","owner":"goern@b4mad.net","created_at":"2026-05-25T07:21:45Z","created_by":"Christoph Görn","updated_at":"2026-05-25T07:46:29Z","closed_at":"2026-05-25T07:46:29Z","close_reason":"PR #147 merged 2026-05-25T09:45:33+02:00; worktree + local branch ci/gitleaks-allowlist-demos cleaned up","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-phn","title":"Set Codeberg Actions secrets COSIGN_PRIVATE_KEY and COSIGN_PASSWORD","description":"Mirror cosign signing material from SOPS-encrypted secrets/cosign-signing-key.enc.yaml into Codeberg Actions repo secrets so the release pipeline can sign artifacts. Source-of-truth stays in SOPS; this is one-way sync to CI.","notes":"Decrypt with sops, extract via yq, PUT to Forgejo API /repos/goern/forgejo-mcp/actions/secrets/{name}. Never write plaintext to disk.","status":"closed","priority":2,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-24T11:09:58Z","created_by":"Christoph Görn","updated_at":"2026-05-24T11:11:01Z","started_at":"2026-05-24T11:10:08Z","closed_at":"2026-05-24T11:11:01Z","close_reason":"Both Codeberg Actions secrets created (HTTP 201). Verified via API list. Source-of-truth remains secrets/cosign-signing-key.enc.yaml (SOPS).","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-p1p","title":"ci: bump x/net + jsonparser to clear govulncheck advisories (run #151)","description":"Forgejo Actions ci.yml run #151 (https://codeberg.org/goern/forgejo-mcp/actions/runs/151) flagged govulncheck findings. Local scan (govulncheck v1.3.0) shows 7 findings: 0 reachable, 2 package-level (x/net/idna GO-2026-5026, buger/jsonparser GO-2026-4514), 5 module-level (x/net/html GO-2026-5025..5030). Default govulncheck exits 0 on non-reachable findings, so the CI failure may be from a stricter flag/version on the runner — fix in this PR clears them regardless. Bump x/net to v0.55.0 (clears 6), add direct require for buger/jsonparser v1.1.2 to override transitive (clears 1).","acceptance_criteria":"govulncheck ./... locally returns 0 findings at all tiers OR only retains findings not present in advisories. Next ci.yml run on a fresh PR passes the govulncheck step.","notes":"PR opened: https://codeberg.org/goern/forgejo-mcp/pulls/145 (mergeable). Local govulncheck verified clean at all tiers.","status":"closed","priority":2,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-24T11:06:20Z","created_by":"Christoph Görn","updated_at":"2026-05-25T22:28:25Z","started_at":"2026-05-24T11:06:27Z","closed_at":"2026-05-25T22:28:25Z","close_reason":"PR #145 merged 2026-05-25 (612da9f). govulncheck ./... on main: no vulnerabilities. All 7 advisories cleared.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-1l5","title":"RFC: introduce MCP resource templates for core entities (owner, repo, commit, issue, pr, comment, status)","description":"## Why\n\nforgejo-mcp is currently tool-only. No MCP resources registered in operation/operation.go. Core Forgejo entities (owner, repo, commit, issue, pr, comment, status) are noun-like, addressable, and often immutable or stable — natural fit for MCP resource templates. Exposing them as resources unlocks:\n\n- URI-based references the LLM can auto-resolve (e.g. PR diff mentions a sha → fetch commit resource)\n- Cacheable, content-addressable lookup (commits especially)\n- Cleaner composition: a PR resource can link to commit + comment resources instead of forcing tool-call ceremony\n\nDoing this piecemeal (one entity at a time) creates an inconsistent server. A coherent design pass covering all seven entities at once avoids that.\n\n## What\n\nProduce an OpenSpec proposal that designs MCP resource templates for:\n\n- owner (user or org): `forgejo://owner/{name}`\n- repo: `forgejo://repo/{owner}/{repo}`\n- commit: `forgejo://repo/{owner}/{repo}/commit/{sha}`\n- issue: `forgejo://repo/{owner}/{repo}/issue/{index}`\n- pr: `forgejo://repo/{owner}/{repo}/pr/{index}`\n- comment: `forgejo://repo/{owner}/{repo}/{issue|pr}/{index}/comment/{id}`\n- status: `forgejo://repo/{owner}/{repo}/commit/{sha}/status` (combined) + `.../statuses` (list)\n\nURI scheme above is illustrative — proposal must justify final scheme.\n\n## Acceptance criteria\n\n- OpenSpec change proposal created via /openspec-propose covering all 7 entity templates\n- Proposal includes: URI scheme rationale, capability registration changes to operation/operation.go, handler pattern, MIME type per resource, relationship to existing tools (coexist or replace?), output bounding strategy (AGENTS.md docs/design/output-bounding.md), client compatibility matrix, migration/rollout plan\n- design.md addresses: listable vs template-only per entity, subscription semantics (do we support resource updates?), error handling for missing/private entities, auth scope\n- Specs cover behavior for each of the 7 entities\n- Tasks broken down per-entity so implementation can land incrementally even though design is unified\n\n## Out of scope\n\n- Implementation (this bead = design only)\n- Wiki/projects resources (blocked upstream per docs/plans/)\n- Webhook/event resources\n\n## Notes\n\nDriven by session discussion 2026-05-24 around replacing curl-based commit status fetches with proper MCP surface. Decision: design resources holistically rather than one-off per entity.","notes":"OpenSpec change created at openspec/changes/mcp-resource-templates/ on branch worktree-rfc-resource-templates. 4/4 artifacts pass strict validation (proposal, design, 8 spec files, tasks). 13 design decisions documented. 7-slice rollout plan in tasks.md. Ready for /opsx:apply to start implementation.","status":"closed","priority":2,"issue_type":"feature","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-24T07:35:50Z","created_by":"Christoph Görn","updated_at":"2026-05-25T08:04:39Z","started_at":"2026-05-25T07:30:03Z","closed_at":"2026-05-25T08:04:39Z","close_reason":"OpenSpec proposal complete: proposal.md, design.md, 8 spec files, tasks.md all pass strict validation. Branch: worktree-rfc-resource-templates.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-e9i","title":"CI: investigate Forgejo Actions ci.yml failure on PR #143","description":"First run of .forgejo/workflows/ci.yml (run #147, SHA d711f32) failed at 3m43s. Merged anyway. No per-step detail available via Codeberg API. Need to: (1) open https://codeberg.org/goern/forgejo-mcp/actions/runs/147 in browser, identify which step failed; (2) fix root cause (likely candidates: golangci-lint-action@v6 incompatibility on Codeberg runner, cache mount permissions, missing toolchain, setup-go@v6 quirk); (3) verify on follow-up PR.","acceptance_criteria":"ci.yml run on a fresh PR completes with all steps green (lint warn-only acceptable). Document root cause in bd notes.","status":"closed","priority":2,"issue_type":"bug","owner":"goern@b4mad.net","created_at":"2026-05-24T07:35:45Z","created_by":"Christoph Görn","updated_at":"2026-05-26T09:18:37Z","closed_at":"2026-05-26T09:18:37Z","close_reason":"ci.yml deleted — Forgejo Actions CI superseded by Tekton PaC pipeline. Failure moot.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-51l","title":"CI: harden release pipeline (SBOM, cosign, smoke-test)","description":"release.yml ships .mcpb per platform but never verifies binary boots. Add: syft SBOM upload as release asset, cosign sign binaries+containers (keyless via OIDC if available, else key from secret), smoke-test ./forgejo-mcp --version per arch before .mcpb upload.","acceptance_criteria":"SBOM uploaded per release, signatures verifiable, smoke-test runs on linux/amd64 at minimum","notes":"PR opened: https://codeberg.org/goern/forgejo-mcp/pulls/144 (mergeable). Branch ci/step3-release-hardening. 3 commits:\n1. .goreleaser.yml: checksums + per-archive CycloneDX SBOMs via syft\n2. release.yml: syft + cosign install, smoke-test linux/amd64 binary, conditional cosign sign-blob on checksums.txt\n3. scripts/cosign-keygen.sh: SOPS-encrypted k8s Secret keypair generator (tmpfs + shred + no-echo password)\n\nSigning gated on COSIGN_PRIVATE_KEY + COSIGN_PASSWORD repo secrets — releases keep working until secret provisioned. Activation steps in PR body.\n\nLocal verification:\n- goreleaser check → 1 configuration file(s) validated\n- YAML lint → OK\n- bash -n on script → OK (no shellcheck available locally)\n\nUntested in PR (require tagged release): SBOM upload path, smoke-test on real built binary, cosign sign flow.","status":"closed","priority":2,"issue_type":"feature","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-24T07:06:38Z","created_by":"Christoph Görn","updated_at":"2026-05-24T10:59:53Z","started_at":"2026-05-24T10:30:14Z","closed_at":"2026-05-24T10:59:53Z","close_reason":"Merged via PR #144 (commit b2c67f8). Activation pending: run scripts/cosign-keygen.sh, add COSIGN_PRIVATE_KEY + COSIGN_PASSWORD to Codeberg Actions secrets, then signing kicks in on next v* tag.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-9n2","title":"CI: add Forgejo Actions PR workflow with Go cache","description":"Tekton has no cross-run Go cache (PVC ephemeral). Add .forgejo/workflows/ci.yml mirroring go-ci gates on codeberg-small runner using actions/setup-go cache. Run parallel to Tekton 2 weeks, then decide canonical.","acceptance_criteria":"ci.yml runs on pull_request + push to main, uses setup-go cache, runs build/test/lint/race/govulncheck, completes \u003c5min on cache hit","notes":"PR opened: https://codeberg.org/goern/forgejo-mcp/pulls/143 (mergeable). Will close on merge. First Forgejo Actions run will be cold-cache; verify \u003c5min on second run.","status":"closed","priority":2,"issue_type":"feature","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-24T07:06:34Z","created_by":"Christoph Görn","updated_at":"2026-05-24T07:35:56Z","started_at":"2026-05-24T07:25:05Z","closed_at":"2026-05-24T07:35:56Z","close_reason":"Merged via PR #143 (rebase, force_merge — run #147 failed, fix tracked in forgejo-mcp-e9i).","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-33k","title":"C5 spike: verify cross-repo workflow_call on Codeberg Forgejo v11.x","description":"Battle-test of forgejo-action-code-review deferred this spike. Spike scaffolding under openspec/changes/forgejo-action-code-review/spikes/c5-cross-repo-workflow-call/. Library + consumer repos already exist on Codeberg (goern/c5-spike-lib, goern/c5-spike-consumer). Remaining steps: (1) create tag v0.0.1 on c5-spike-lib main, (2) set repo secret SPIKE_SECRET on both repos, (3) push trigger commit to c5-spike-consumer main, (4) observe whether cross-repo uses: resolves, secret propagates, event context shape. Result drives design.md D9: keep Path B as recommended, or demote to experimental.","status":"open","priority":2,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-05-13T06:33:23Z","created_by":"Christoph Görn","updated_at":"2026-05-24T06:02:27Z","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-673","title":"Implement forgejo-action-code-review workflow","description":"OpenSpec change forgejo-action-code-review has spec deltas (8 capability requirements, PR specs/action-code-review/spec.md) but no implementation. The workflow file .forgejo/workflows/claude-code-review.yml does not exist. Need to ship the reusable Forgejo Actions workflow that runs Claude Code with forgejo-mcp on PR events, installs CC, registers forgejo-mcp as MCP server, runs /code-review skill in -p mode, and posts findings via create_pull_review. Depends on forgejo-code-review-skill (delivered). See openspec/changes/forgejo-action-code-review/ for proposal + specs.","status":"open","priority":2,"issue_type":"feature","owner":"goern@b4mad.net","created_at":"2026-05-12T13:37:41Z","created_by":"Christoph Görn","updated_at":"2026-05-12T13:37:41Z","dependencies":[{"issue_id":"forgejo-mcp-673","depends_on_id":"forgejo-mcp-33k","type":"blocks","created_at":"2026-05-13T06:33:31Z","created_by":"Christoph Görn","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-fdx","title":"Migrate openspec validate from Forgejo Actions to op1st Tekton","description":"Pivot PR 132: drop .forgejo/workflows/openspec.yml, add Tekton PipelineRuns for openspec validate using op1st-pipelines (PaC). Path-gated via CEL on openspec/** and .tekton/*openspec* changes. Same trigger semantics: push to main + PR open/sync.","acceptance_criteria":"- .tekton/tasks/openspec-validate.yaml runs openspec@1.3.1 validate --all --strict --no-interactive\n- .tekton/on-pull-request-openspec.yaml + on-push-to-main-openspec.yaml gate on path changes via CEL\n- .forgejo/workflows/openspec.yml deleted\n- PR 132 retitled to reflect Tekton migration","status":"closed","priority":2,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-05-12T07:46:04Z","created_by":"Christoph Görn","updated_at":"2026-05-12T07:48:35Z","closed_at":"2026-05-12T07:48:35Z","close_reason":"Landed in PR 132 commit fbd1203 on feat/openspec-workflow. on-pull-request-openspec PipelineRun green (24s). Old .forgejo/workflows/openspec.yml deleted.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-43k","title":"Replace .forgejo/workflows/go.yml with op1st Tekton CI","description":"Codeberg Forgejo runners enforce strict job time limits. Move CI to op1st-pipelines (Pipelines-as-Code on OpenShift). Run go build + go test on every push to main and every PR change. Follow patterns from goern/epaper-service and feeldata/feeldata.app.","acceptance_criteria":"- .tekton/repository.yaml registers repo with op1st-pipelines\n- .tekton/on-push-to-main.yaml triggers go build + go test on push to main\n- .tekton/on-pull-request.yaml triggers go build + go test on PR open/sync\n- Custom go-ci task uses docker.io/library/golang:1.25\n- PaC secrets reuse codeberg-runner-openshift-pac + codeberg-org-op1st-pipelines\n- .forgejo/workflows/go.yml deleted","notes":"Tracked on Codeberg as goern/forgejo-mcp#133 (https://codeberg.org/goern/forgejo-mcp/issues/133). Implementation in commit ae35a30. Remaining: Repository CR apply in op1st-pipelines namespace (cluster-side, out-of-band).","status":"closed","priority":2,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-05-12T06:38:01Z","created_by":"Christoph Görn","updated_at":"2026-05-12T06:40:54Z","closed_at":"2026-05-12T06:39:55Z","close_reason":"Implemented in commit ae35a30. .tekton/ PaC config + go-ci task replace .forgejo/workflows/go.yml.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-zwr","title":"Complete add-bounded-text-responses change for Codeberg #124","description":"Pre-existing scaffold at openspec/changes/add-bounded-text-responses/ has only proposal.md. Codeberg issue #124 (\"Add paged or per-file diff\", reporter fiesh, Kind/Enhancement, Reviewed/Confirmed) is still open.\n\nProposal scope:\n- Add optional `file_path` param to get_pull_request_diff (per-file slicing on `diff --git` boundaries)\n- Add optional `start_line` + `end_line` to get_file_content (1-indexed inclusive line slice)\n- README updates for missing tool entries\n\nRemaining work:\n- Add design.md, specs/bounded-pr-diff/spec.md, specs/bounded-file-content/spec.md, tasks.md\n- Implement in operation/pull/pull.go + operation/repo/file.go\n- Optional pkg/diff/ helper for unified-diff splitting\n- Tests per proposal's Impact section\n\nCurrently fails `openspec validate --all --strict` with 'no deltas found', so it blocks forgejo-mcp-6jc (workflow).\n\nUpstream: https://codeberg.org/goern/forgejo-mcp/issues/124","status":"closed","priority":2,"issue_type":"feature","owner":"goern@b4mad.net","created_at":"2026-05-11T14:32:54Z","created_by":"Christoph Görn","updated_at":"2026-05-24T06:02:27Z","closed_at":"2026-05-11T14:58:24Z","close_reason":"Impl + tests landed in PR #131 (commit dda4ba1). New pkg/diff splitter; get_pull_request_diff gained file_path; get_file_content gained start_line/end_line with clamping. 11 new unit tests; full suite green. README tool table updated incl previously-missing entries.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-6jc","title":"Add Forgejo Actions workflow for openspec validate","description":"Add `.forgejo/workflows/openspec.yml` running `openspec validate --all --strict --no-interactive` on PRs touching `openspec/**` or the workflow file itself. Reference: https://codeberg.org/goern/epaper-service/src/branch/main/.forgejo/workflows/openspec.yml\n\nPinned version: `@fission-ai/openspec@1.3.1` (current local).\n\nBlocked by the 4 spec/change cleanup tasks (forgejo-mcp-6un, forgejo-mcp-a0p, forgejo-mcp-517, forgejo-mcp-cpb) — workflow strict would fail on day 1 otherwise.","status":"closed","priority":2,"issue_type":"feature","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-11T14:18:58Z","created_by":"Christoph Görn","updated_at":"2026-05-11T15:04:35Z","started_at":"2026-05-11T15:03:34Z","closed_at":"2026-05-11T15:04:35Z","close_reason":"Landed in PR #132 (commit 16ca60f). Workflow runs openspec validate --all --strict on openspec/** and workflow file changes, modeled on epaper-service workflow. Pre-existing failures (4 specs/changes) were cleaned up first so gate is green from day one.","dependencies":[{"issue_id":"forgejo-mcp-6jc","depends_on_id":"forgejo-mcp-517","type":"blocks","created_at":"2026-05-11T14:19:03Z","created_by":"Christoph Görn","metadata":"{}"},{"issue_id":"forgejo-mcp-6jc","depends_on_id":"forgejo-mcp-6un","type":"blocks","created_at":"2026-05-11T14:19:02Z","created_by":"Christoph Görn","metadata":"{}"},{"issue_id":"forgejo-mcp-6jc","depends_on_id":"forgejo-mcp-a0p","type":"blocks","created_at":"2026-05-11T14:19:02Z","created_by":"Christoph Görn","metadata":"{}"},{"issue_id":"forgejo-mcp-6jc","depends_on_id":"forgejo-mcp-cpb","type":"blocks","created_at":"2026-05-11T14:19:03Z","created_by":"Christoph Görn","metadata":"{}"},{"issue_id":"forgejo-mcp-6jc","depends_on_id":"forgejo-mcp-zwr","type":"blocks","created_at":"2026-05-11T14:33:02Z","created_by":"Christoph Görn","metadata":"{}"}],"dependency_count":5,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-cpb","title":"Fix openspec change: forgejo-action-code-review has no deltas","description":"openspec/changes/forgejo-action-code-review/ fails validation:\n\n```\n✗ [ERROR] file: Change must have at least one delta. No deltas found.\nEnsure your change has a specs/ directory with capability folders containing .md files\nthat use delta headers (## ADDED/MODIFIED/REMOVED/RENAMED Requirements) and that each\nrequirement includes at least one \"#### Scenario:\" block.\n```\n\nAdd a `specs/\u003ccapability\u003e/spec.md` with `## ADDED Requirements` deltas and scenarios reflecting the change's intent. Probably has design.md but no spec delta.","status":"closed","priority":2,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-11T14:18:52Z","created_by":"Christoph Görn","updated_at":"2026-05-24T06:02:27Z","started_at":"2026-05-11T14:40:50Z","closed_at":"2026-05-11T14:42:00Z","close_reason":"Landed in commit a83a033. Added specs/action-code-review/spec.md with 8 capability requirements + scenarios. openspec validate forgejo-action-code-review --strict passes.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-517","title":"Fix openspec spec: pr-review-write missing Purpose/Requirements headers","description":"openspec/specs/pr-review-write/spec.md fails validation with the same missing-headers error as cli-mode and merge-pull-request. Add `## Purpose` and `## Requirements` sections.","status":"closed","priority":2,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-05-11T14:18:45Z","created_by":"Christoph Görn","updated_at":"2026-05-24T06:02:27Z","closed_at":"2026-05-11T14:30:43Z","close_reason":"Landed in commit c8a7883. Both specs now carry Purpose + Requirements headers; openspec validate --strict passes.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-a0p","title":"Fix openspec spec: merge-pull-request missing Purpose/Requirements headers","description":"openspec/specs/merge-pull-request/spec.md fails strict + non-strict validation with the same missing-headers error as cli-mode. Add `## Purpose` and `## Requirements` sections.","status":"closed","priority":2,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-05-11T14:18:41Z","created_by":"Christoph Görn","updated_at":"2026-05-24T06:02:27Z","closed_at":"2026-05-11T14:30:43Z","close_reason":"Landed in commit c8a7883. Both specs now carry Purpose + Requirements headers; openspec validate --strict passes.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-6un","title":"Fix openspec spec: cli-mode missing Purpose/Requirements headers","description":"openspec/specs/cli-mode/spec.md fails strict + non-strict validation:\n\n```\n✗ [ERROR] file: Spec must have a Purpose section.\nMissing required sections. Expected headers: \"## Purpose\" and \"## Requirements\"\n```\n\nAdd the two missing top-level section headers. Content already implies a purpose — promote it. Prerequisite for forgejo-mcp-NEW-workflow.","status":"closed","priority":2,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-05-11T14:18:36Z","created_by":"Christoph Görn","updated_at":"2026-05-24T06:02:27Z","closed_at":"2026-05-11T14:29:36Z","close_reason":"Landed in commit 23db899. cli-mode spec now has Purpose + Requirements headers; openspec validate cli-mode --strict passes.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-0ep","title":"Add MCP tools for Forgejo releases","description":"Codeberg issue #127: surface release operations (list, get, create, edit, delete, list assets) as MCP tools to help generate release notes and changelogs.\n\nUpstream: https://codeberg.org/goern/forgejo-mcp/issues/127","status":"closed","priority":2,"issue_type":"feature","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-11T13:26:17Z","created_by":"Christoph Görn","updated_at":"2026-05-12T14:56:12Z","started_at":"2026-05-11T13:26:22Z","closed_at":"2026-05-12T14:56:12Z","close_reason":"PR #134 merged (https://codeberg.org/goern/forgejo-mcp/pulls/134); 14 tools live","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-efo","title":"Fix update_issue tool: assignee field ignored by Forgejo API","description":"The mcp__codeberg__update_issue tool exposes a singular 'assignee' parameter, but Forgejo's EditIssueOption ignores the deprecated singular field in current API versions and only honors the 'assignees' array.\n\nObserved in issue goern/forgejo-mcp#127: calling update_issue with assignee=goern returned HTTP 200 but a follow-up GET still shows assignees:null.\n\nWhat needs to be done:\n- Locate the update_issue handler in operation/issue/ (or wherever EditIssue is wired)\n- Change the SDK call to pass assignees=[]string{assignee} (or expose an 'assignees' parameter directly)\n- Keep the singular 'assignee' param for backward compat, but convert to array before SDK call\n- Add an integration test that asserts the assignee actually persists after update\n\nAcceptance:\n- update_issue with assignee=\u003cuser\u003e results in assignees containing that user on subsequent GET\n- Upstream tracking: codeberg.org/goern/forgejo-mcp#\u003cTBD\u003e","status":"closed","priority":2,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-11T13:24:23Z","created_by":"Christoph Görn","updated_at":"2026-05-11T13:29:56Z","started_at":"2026-05-11T13:25:58Z","closed_at":"2026-05-11T13:29:56Z","close_reason":"Fix landed in commit 6291213. Singular 'assignee' now wired to opt.Assignees=[]string{assignee}. New 'assignees' CSV param overrides. Unit tests in operation/issue/issue_test.go cover singular, CSV, clear, and omit cases. Upstream: codeberg.org/goern/forgejo-mcp#128.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-e0j","title":"docs(design): codify output-bounding rule from #124","description":"Issue #124 surfaced unbounded MCP tool outputs (diffs, files, pull-files lists) blowing up context windows. Codify the rule derived in triage as a design doc and reference it from AGENTS.md so every new tool considers output bounding by default. Three sub-rules: no silent truncation, bound by domain shape (line/per-file/page), always resumable.","status":"closed","priority":2,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-10T14:09:42Z","created_by":"Christoph Görn","updated_at":"2026-05-10T14:12:04Z","started_at":"2026-05-10T14:09:45Z","closed_at":"2026-05-10T14:12:04Z","close_reason":"Landed in 1412cbe — docs/design/output-bounding.md + AGENTS.md checklist update.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-xv0","title":"OpenSpec change for org-label support in list_repo_labels","description":"Sub-task of forgejo-mcp-7ch. Author OpenSpec change covering:\n- New tool list_org_labels(org, page, limit)\n- Augmentation of list_repo_labels with include_org_labels bool (default true) and scope tag on each label\n- Use pkg/forgejo.DoJSONList against /orgs/{org}/labels (no SDK upgrade)\n- Test plan: httptest server fixtures for repo-only, org-only, merged, 404→empty\n\nOutput: artifacts under openspec/changes/\u003cchange-id\u003e/ following experimental workflow (proposal, design, tasks, deltas).","status":"closed","priority":2,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-05-09T20:38:32Z","created_by":"Christoph Görn","updated_at":"2026-05-24T06:02:27Z","closed_at":"2026-05-09T20:43:52Z","close_reason":"OpenSpec change add-org-label-support authored on branch issues/125","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-7ch","title":"list_repo_labels missing org-level labels (#125)","description":"Codeberg issue #125: list_repo_labels exposes only repo-scoped labels. Forgejo API also exposes /orgs/{org}/labels which SDK v3 does not bind. For org-owned repos, org labels are usable on issues but invisible to MCP — model cannot discover their IDs.\n\nImpl path:\n- Add new tool list_org_labels(org, page, limit) using pkg/forgejo.DoJSONList against /orgs/{org}/labels.\n- Augment list_repo_labels with bool include_org_labels (default true). When repo owner is org, merge org labels and tag each with scope=repo|org.\n- No SDK upgrade required — same pattern as attachments raw-HTTP path.\n- Tests via httptest server matching pkg/forgejo/*_test.go patterns.\n\nAcceptance:\n- list_repo_labels of an org-owned repo returns repo+org labels with scope tag.\n- list_org_labels callable standalone.\n- 404 from org endpoint maps to empty (no error).\n- include_org_labels=false suppresses merge.\n- Tests cover both tools.","acceptance_criteria":"list_repo_labels returns org labels when repo owner is org; new list_org_labels tool callable; tests cover both","notes":"Merged in PR #130 (squash, 2026-05-12). Closes Codeberg #125.","status":"closed","priority":2,"issue_type":"bug","owner":"goern@b4mad.net","created_at":"2026-05-09T20:38:27Z","created_by":"Christoph Görn","updated_at":"2026-05-12T08:41:22Z","closed_at":"2026-05-11T14:48:41Z","dependencies":[{"issue_id":"forgejo-mcp-7ch","depends_on_id":"forgejo-mcp-xv0","type":"blocks","created_at":"2026-05-09T20:38:35Z","created_by":"Christoph Görn","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-9y4","title":"Wire .mcpb build into release pipeline","description":"PR #118 adds extension/ scaffolding for Claude Desktop Extension (.mcpb) but does NOT produce .mcpb on release. Maintainer must extend release.yml so users get downloadable .mcpb per release.\n\nRequired:\n1. Inject release tag into extension/manifest.json version field (currently hardcoded 2.20.0). Use jq before mcpb pack.\n2. Build per-platform .mcpb archives OR single .mcpb with server.mcp_config.platform_overrides bundling all 4 binaries (linux/darwin x amd64/arm64).\n3. Attach resulting .mcpb file(s) to Codeberg release alongside existing tar.gz archives.\n4. Optional: sign with npx @anthropic-ai/mcpb sign.\n\nWhy: PR #118 leaves this explicitly as follow-up. Without it, end users on releases page see only tar.gz binaries, no drag-and-drop install artifact. Extension story incomplete from end-user POV.\n\nHow to apply: extend .forgejo/workflows/release.yml with post-goreleaser job. Use dist/ artifacts produced by goreleaser as input. See PR #118 review for concrete shell snippet.","acceptance_criteria":"- Each tagged release on codeberg.org/goern/forgejo-mcp/releases includes .mcpb artifact(s)\n- manifest.json version matches release tag at pack time (no hardcoded version drift)\n- .mcpb installs cleanly in Claude Desktop on at least linux-amd64 and darwin-arm64\n- Smoke test (extension/test_smoke.py) runs in CI before pack","status":"closed","priority":2,"issue_type":"feature","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-07T20:23:07Z","created_by":"Christoph Görn","updated_at":"2026-05-07T21:02:47Z","started_at":"2026-05-07T20:25:53Z","closed_at":"2026-05-07T21:02:47Z","close_reason":"Shipped in PR #122 (commit fdc6305): release.yml builds and attaches per-platform .mcpb (linux/darwin x amd64/arm64) with jq-based manifest version injection. Local make target added in commit 679d593.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-vsm","title":"E2E test script for attachment tools","description":"Shell script in test/e2e/attachments.sh that exercises ./forgejo-mcp --cli end-to-end against live Codeberg: create issue, upload attachment, list, get, verify browser_download_url, cleanup. Validates v2.19.0-alpha.1 attachment tools work in real deployment as referenced in issue #106.","status":"closed","priority":2,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-04-27T06:54:05Z","created_by":"Christoph Görn","updated_at":"2026-04-27T06:55:37Z","started_at":"2026-04-27T06:54:10Z","closed_at":"2026-04-27T06:55:37Z","close_reason":"Script at test/e2e/attachments.sh, passes live against Codeberg, committed 8ec35e5.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-zhi","title":"Amend issue-attachments spec: lower inline cap to 1 MiB and always include download URL","description":"Follow-up to heathen711's feedback on https://codeberg.org/goern/forgejo-mcp/issues/106. After discussion (comments 13562510, 13701827, 13703888), the agreed scope is two narrow changes to docs/plans/issue-attachments.md: (1) lower MaxInlineDownloadBytes from 10 MiB to 1 MiB, (2) always include browser_download_url in download_*_attachment responses regardless of size. Files under the cap return base64-encoded bytes inline (current MCP-protocol-native behavior); files over the cap return metadata + URL only, and the LLM is expected to fall through to a curl/Bash fetch using its existing token. Earlier proposals — save_to_path parameter and inline:true flag — dropped per heathen711's reasoning: file-path returns introduce tmpfile hygiene + cross-container permission problems, which is exactly why MCP standardised on pipe-based binary delivery; size-cap discrimination already gives the metadata-vs-bytes split without an extra flag. Must land before forgejo-mcp-ydg implementation starts.","design":"Two-line behavioural change: const MaxInlineDownloadBytes = 1 * 1024 * 1024 (was 10 * 1024 * 1024); download_*_attachment response shape always carries browser_download_url alongside metadata, with bytes only if size \u003c cap. No new tool-surface parameters. Open Question #2 in the spec (private-repo auth on browser_download_url) becomes load-bearing — the fall-through-to-curl pattern only works if the URL accepts Authorization: token $TOKEN; verify in Part 1 of the implementation.","acceptance_criteria":"docs/plans/issue-attachments.md updated with save_to_path parameter, 1 MiB cap, always-include-download-url rule, and metadata-default behavior. Parameter matrix reflects the new column. Acceptance criteria section includes save_to_path round-trip test. heathen711 notified of the amendment on issue #106.","status":"closed","priority":2,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-04-24T14:14:05Z","created_by":"Christoph Görn","updated_at":"2026-05-24T06:02:27Z","started_at":"2026-04-26T10:45:34Z","closed_at":"2026-04-26T10:46:59Z","close_reason":"Spec amended in docs/plans/issue-attachments.md: cap lowered to 1 MiB, browser_download_url always included, Open Question #2 promoted to load-bearing Part-1 verification step, acceptance criteria updated to cover both under-cap and over-cap paths. Implementation issue forgejo-mcp-ydg is now unblocked.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-ya6","title":"Issue/PR time tracking: tracked-time + stopwatch MCP tools","description":"Adds 10 MCP tools wrapping forgejo-sdk/v3's tracked-time and stopwatch APIs. Covers list/add/reset/delete tracked-time entries on issues and PRs (which share index space in Forgejo), plus start/stop/cancel/list_my stopwatches. No raw-HTTP helper needed — SDK has full coverage. Spec: docs/plans/issue-time-tracking.md.","design":"SDK-wrapping approach (not raw HTTP): forgejo-sdk/v3 exposes AddTime/ListIssueTrackedTimes/ResetIssueTime/DeleteTime + StartIssueStopWatch/StopIssueStopWatch/DeleteIssueStopwatch/GetMyStopwatches. Verbs mirror API primitives (chose option B over 'set' convenience wrapper to avoid non-atomic reset+add race on shared state). Duration parsing via stdlib time.ParseDuration — no extra dep. Issue/PR unified: single tool set covers both because Forgejo shares index namespace.","acceptance_criteria":"All 10 tools registered and callable; add_issue_time accepts either 'seconds' (int) or 'duration' (string like '15m'); list_issue_tracked_times returns entries with id/time/user; reset clears all entries; delete removes one; stopwatch start→stop produces a tracked-time entry visible via list; cancel discards without creating an entry; make build + go test ./... pass; both demo files run cleanly.","status":"closed","priority":2,"issue_type":"feature","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-04-21T20:38:06Z","created_by":"Christoph Görn","updated_at":"2026-04-21T20:48:54Z","started_at":"2026-04-21T20:42:04Z","closed_at":"2026-04-21T20:48:54Z","close_reason":"Implemented in commit (see git log); 10 MCP tools + tests + 2 showboat demos + README update.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-ydg","title":"Issue \u0026 comment attachments: full CRUD MCP tools","description":"Closes upstream Codeberg issue goern/forgejo-mcp#106: attachments on issues are invisible to the MCP because GET /issues/{index} does not embed them, and forgejo-sdk/v3 has zero issue-attachment methods. Spec: docs/plans/issue-attachments.md (amended per forgejo-mcp-zhi). Delivers 12 new tools (list/get/download/create/edit/delete × issue + comment), a raw-HTTP helper (pkg/forgejo/rawhttp.go), binary content return via mcp.BlobResourceContents with a 1 MiB inline cap, browser_download_url always included for over-cap fall-through, and two Showboat demos (demos/issue-attachments.md, demos/comment-attachments.md). Part 1 of implementation must verify private-repo auth on browser_download_url before Part 3 begins (load-bearing — see Open Question #2 in spec).","design":"Approach 2: raw HTTP inside forgejo-mcp (chosen over upstream-first and replace-directive hybrid). Rationale: attachment endpoints are stable Gitea/Forgejo routes, raw-HTTP surface is small and contained behind one helper package, shipping time beats SDK-consistency. Risk (field drift) mitigated by reusing forgejo_sdk.Attachment as DTO + demos as live-integration canaries.","acceptance_criteria":"All 12 tools registered and callable; list_issue_attachments on goern/forgejo-mcp#106 returns the uploaded PDF metadata; download_issue_attachment round-trips bytes sha256-identical; edit/delete round-trip works for both issues and comments; list on empty entity returns []; make build + go test ./... pass; both demo files run cleanly end-to-end.","status":"closed","priority":2,"issue_type":"feature","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-04-21T20:29:49Z","created_by":"Christoph Görn","updated_at":"2026-04-26T11:11:40Z","started_at":"2026-04-26T10:58:41Z","closed_at":"2026-04-26T11:11:40Z","close_reason":"Implemented in PR #109 (feature/issue-attachments). 12 tools, rawhttp helper, all tests green, live-verified against Codeberg API.","dependencies":[{"issue_id":"forgejo-mcp-ydg","depends_on_id":"forgejo-mcp-zhi","type":"blocks","created_at":"2026-04-24T14:14:10Z","created_by":"Christoph Görn","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-aa6","title":"Migrate cosign attach sbom to cosign attest","description":"cosign-attach-sbom.yaml uses 'cosign attach sbom', which cosign deprecated (removal slated soon after 2024-02-22, see sigstore/cosign#2755) and which does NOT sign the SBOM. Migrate to 'cosign attest --predicate \u003csbom\u003e --type cyclonedx --key \u003ckey\u003e' so the SBOM is a signed attestation. Surfaced as a WARNING during v2.27.0-alpha.1 SBOM attach (2026-06-01).","status":"open","priority":3,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-06-01T08:59:34Z","created_by":"Christoph Görn","updated_at":"2026-06-01T08:59:34Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-hxv","title":"MCP tool get_forgejo_mcp_server_version may always report 'dev'","description":"operation/version/version.go reads pkg/flag.Version. cmd/cmd.go injects the build version into the user-agent and operation.Run, but verify whether pkg/flag.Version is ever assigned. If not, get_forgejo_mcp_server_version returns 'dev' even when the CLI version/--version command reports the real injected version (now fixed for containers via build-arg in PR feat/hummingbird-containers). Wire flag.Version from the injected main.Version if missing.","status":"open","priority":3,"issue_type":"bug","owner":"goern@b4mad.net","created_at":"2026-05-31T19:23:37Z","created_by":"Christoph Görn","updated_at":"2026-05-31T19:23:37Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-16t","title":"Reject empty/whitespace URI segments in operation/resource/parse.go:220","description":"splitPath silently collapses empty segments — forgejo://repo/foo//bar (double slash) and forgejo://repo/foo/bar/ (trailing slash) parse as the canonical forgejo://repo/foo/bar. PR promotes these URIs as content-addressable cache keys but multiple distinct URIs map to the same resource. URL-decoded whitespace-only segments (forgejo://repo/%20/%20/...) pass blank/whitespace owner/repo to the SDK, surfacing as 404 instead of -32602. Review: https://codeberg.org/goern/forgejo-mcp/pulls/172#issuecomment-16022165 (conf 80).","notes":"Fix: at operation/resource/parse.go:220, change splitPath to either (a) reject empty/whitespace segments (return error to parseForgejoURI which already returns error), OR (b) document canonicalisation explicitly. Recommend (a) — strictness preserves URI identity for caching. Add parse_test.go cases: double slash, trailing slash, percent-encoded whitespace owner/repo.","status":"closed","priority":3,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-28T13:47:09Z","created_by":"Christoph Görn","updated_at":"2026-05-28T13:58:38Z","started_at":"2026-05-28T13:57:03Z","closed_at":"2026-05-28T13:58:38Z","close_reason":"Fixed in 55a39f4. parseForgejoURI rejects empty/whitespace segments; test cases added; full suite green.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-91j","title":"Fix user→org fallback masking real errors + nil-userErr edge case in operation/user/resources_owner.go:96","description":"Two failure modes: (a) when GetOrg fails with orgResp==nil (network/DNS/context-cancel), handler returns MapForgejoError(uri, userErr) — surfacing original 404 instead of the real transport error; (b) if userErr is nil (u==nil err==nil SDK edge), MapForgejoError(nil)=nil and handler returns (nil, nil), violating MCP semantics. Review: https://codeberg.org/goern/forgejo-mcp/pulls/172#issuecomment-16022165 (conf 82).","notes":"Fix: at operation/user/resources_owner.go:90-97, restructure:\n if orgErr != nil {\n if orgResp != nil \u0026\u0026 orgResp.StatusCode == 404 {\n // both 404 — surface explicit not-found\n return nil, \u0026resource.ResourceError{URI: uri, Code: -32003, Message: \"owner not found: \" + req.Params.URI}\n }\n if orgResp != nil {\n return nil, resource.MapForgejoError(uri, fmt.Errorf(\"%d %s\", orgResp.StatusCode, orgErr.Error()))\n }\n return nil, resource.MapForgejoError(uri, orgErr) // prefer the real orgErr over original userErr\n }","status":"closed","priority":3,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-28T13:47:09Z","created_by":"Christoph Görn","updated_at":"2026-05-28T14:11:59Z","started_at":"2026-05-28T14:09:36Z","closed_at":"2026-05-28T14:11:59Z","close_reason":"Fixed in 19f1efd.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-g5s","title":"Map parse error via resource.MapForgejoError in operation/repo/resources_status.go:65","description":"Same parse-error inconsistency. Malformed status URIs (including short SHA) lose -32602. Review: https://codeberg.org/goern/forgejo-mcp/pulls/172#issuecomment-16022165 (conf 88).","notes":"Fix: at operation/repo/resources_status.go:64-65, replace the fmt.Errorf wrap with resource.MapForgejoError(uri, err).","status":"closed","priority":3,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-28T13:47:09Z","created_by":"Christoph Görn","updated_at":"2026-05-28T14:03:29Z","started_at":"2026-05-28T14:02:12Z","closed_at":"2026-05-28T14:03:29Z","close_reason":"Fixed in 10c8403.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-iqi","title":"Map parse error via resource.MapForgejoError in operation/user/resources_owner.go:56","description":"Same parse-error inconsistency. Malformed owner URIs lose -32602. Review: https://codeberg.org/goern/forgejo-mcp/pulls/172#issuecomment-16022165 (conf 88).","notes":"Fix: at operation/user/resources_owner.go:55-56, replace the fmt.Errorf wrap with resource.MapForgejoError(uri, err).","status":"closed","priority":3,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-28T13:47:09Z","created_by":"Christoph Görn","updated_at":"2026-05-28T14:05:07Z","started_at":"2026-05-28T14:03:29Z","closed_at":"2026-05-28T14:05:07Z","close_reason":"Fixed in 6cecf67.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-s2g","title":"Map parse error via resource.MapForgejoError in operation/repo/resources_repo.go:61","description":"Same parse-error inconsistency as commit handler. Malformed repo URIs lose -32602. Review: https://codeberg.org/goern/forgejo-mcp/pulls/172#issuecomment-16022165 (conf 88).","notes":"Fix: at operation/repo/resources_repo.go:60-61, replace the fmt.Errorf wrap with resource.MapForgejoError(uri, err).","status":"closed","priority":3,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-28T13:47:09Z","created_by":"Christoph Görn","updated_at":"2026-05-28T14:02:11Z","started_at":"2026-05-28T14:00:47Z","closed_at":"2026-05-28T14:02:11Z","close_reason":"Fixed in 0c177af. Same pattern as vzz.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-wgs","title":"Replace substring-based HTTP classification in operation/resource/errors.go:26","description":"MapForgejoError classifies HTTP results by substring search on the formatted error string. Two failure modes: (1) URIs/error bodies legitimately containing '404' or 'Forbidden' get misclassified; (2) parser errors of shape 'invalid URI: expected forgejo://...' do NOT match any -32602 substring so wrong-shape URIs fall through to -32603 internal-error instead of -32602 invalid-params. Review: https://codeberg.org/goern/forgejo-mcp/pulls/172#issuecomment-16022165 (conf 88).","notes":"Fix: change MapForgejoError signature to accept an HTTP status int (handlers already have resp.StatusCode at the call site) — e.g. MapForgejoError(uri string, status int, err error) — and dispatch on status, not substring. For parser errors, use a sentinel error type (var ErrInvalidParams = errors.New(\"invalid params\")) and errors.Is for the -32602 path. Update all 7 handler call sites.","status":"closed","priority":3,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-28T13:47:09Z","created_by":"Christoph Görn","updated_at":"2026-05-28T14:09:35Z","started_at":"2026-05-28T14:05:08Z","closed_at":"2026-05-28T14:09:35Z","close_reason":"Fixed in 1aa797a. ErrInvalidParams sentinel introduced; -32602 surfaces correctly.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-vzz","title":"Map parse error via resource.MapForgejoError in operation/repo/resources_commit.go:39","description":"Parse-error path uses fmt.Errorf instead of resource.MapForgejoError. Malformed commit URIs lose the -32602 invalid-params JSON-RPC code. Inconsistent with issue/pr handlers. Review: https://codeberg.org/goern/forgejo-mcp/pulls/172#issuecomment-16022165 (conf 88).","notes":"Fix: at operation/repo/resources_commit.go:38-39, replace\n if err != nil {\n return nil, fmt.Errorf(\"invalid commit resource URI: %w\", err)\n }\nwith\n if err != nil {\n return nil, resource.MapForgejoError(uri, err)\n }","status":"closed","priority":3,"issue_type":"bug","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-28T13:47:08Z","created_by":"Christoph Görn","updated_at":"2026-05-28T14:00:47Z","started_at":"2026-05-28T13:58:38Z","closed_at":"2026-05-28T14:00:47Z","close_reason":"Fixed in 81d1945. Parse errors now mapped via MapForgejoError; type-assertion surfaces *ResourceError. -32602 elevation pending forgejo-mcp-wgs.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-8ia","title":"Fix CommmentsTruncated typo in operation/pull/resources.go:79","description":"Rename prResourcePayload.CommmentsTruncated (three m's) to CommentsTruncated. JSON tag comments_truncated keeps wire format. Cosmetic but easy to mis-reference. Review comment: https://codeberg.org/goern/forgejo-mcp/pulls/172#issuecomment-16022165 (conf 95).","notes":"Fix: edit operation/pull/resources.go line 79 — replace 'CommmentsTruncated bool' with 'CommentsTruncated bool'. Also update the assignment site (search for CommmentsTruncated:). Run go build \u0026\u0026 go test ./operation/pull/...","status":"closed","priority":3,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-28T13:46:21Z","created_by":"Christoph Görn","updated_at":"2026-05-28T13:55:39Z","started_at":"2026-05-28T13:54:08Z","closed_at":"2026-05-28T13:55:39Z","close_reason":"Fixed in commit 683404c on PR #172 branch. Field renamed CommmentsTruncated → CommentsTruncated; JSON tag unchanged; tests pass.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-mzr","title":"Move beads-dashboard.html into .beads/ as dashboard.html","description":"Relocate the standalone dashboard from repo root into the .beads/ directory so the dashboard ships next to its data source. Update fetch path from '.beads/issues.jsonl' to 'issues.jsonl' (now sibling). No other consumers (CHANGELOG line is history).","acceptance_criteria":"File served at .beads/dashboard.html loads .beads/issues.jsonl successfully (HTTP 200, fetch resolves).","status":"closed","priority":3,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-26T13:44:56Z","created_by":"Christoph Görn","updated_at":"2026-05-26T13:45:33Z","started_at":"2026-05-26T13:45:01Z","closed_at":"2026-05-26T13:45:33Z","close_reason":"moved beads-dashboard.html → .beads/dashboard.html; fetch path updated to sibling issues.jsonl; HTTP 200 verified","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-gdz","title":"Decide Tekton release pipeline cutover after 2 successful runs","description":"Followup to forgejo-mcp-d4b. After 2 consecutive v* releases where the op1st Tekton pipeline succeeds end-to-end and produces assets matching the Forgejo Actions output, decide canonical release path per docs/design/release-pipeline-migration.md cutover criteria. If Tekton wins: open PR removing .forgejo/workflows/release.yml. If not: file follow-up bugs explaining why and revisit.","acceptance_criteria":"ADR addendum or new commit on docs/design/release-pipeline-migration.md recording the decision; redundant pipeline (.forgejo/workflows/release.yml OR the .tekton release pipeline) removed in a single PR","notes":"Validation state after first live run cycle:\n- v2.24.0: phantom tag, no Release on Codeberg (goreleaser exit 127)\n- v2.24.1: phantom tag, no Release on Codeberg (goreleaser dirty-tree)\n- v2.24.2: 13/14 assets on Codeberg, no .sig (cosign step distroless-no-shell). Counts as partial first Tekton release.\n\nCutover criteria require 2 consecutive end-to-end successes including .sig. v2.24.2 does not qualify. Next clean Tekton release must come AFTER forgejo-mcp-1b4 (release-tools image). Once that lands, need 2 clean releases before deleting .forgejo/workflows/release.yml. Until then: pipeline stays parallel-ready, Forgejo release.yml stays as workflow_dispatch fallback.","status":"closed","priority":3,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-05-25T11:27:33Z","created_by":"Christoph Görn","updated_at":"2026-05-26T09:30:22Z","closed_at":"2026-05-26T09:30:22Z","close_reason":"ADR addendum written in docs/design/release-pipeline-migration.md. Hard cutover executed after v2.25.1 (first clean end-to-end Tekton run). .forgejo/workflows/release.yml deleted commit 1777cca.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-02o","title":"Label Codeberg PR #145 via codeberg-label skill","description":"Test new codeberg-label skill end-to-end on https://codeberg.org/goern/forgejo-mcp/pulls/145. Sonnet subagent picks labels; main session applies via forgejo-mcp.","status":"closed","priority":3,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-25T07:23:23Z","created_by":"Christoph Görn","updated_at":"2026-05-25T07:24:59Z","started_at":"2026-05-25T07:23:30Z","closed_at":"2026-05-25T07:24:59Z","close_reason":"Labeled PR #145 with Kind/Security + Priority/Critical via codeberg-label skill; minutes posted.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-e8e","title":"CI: coverage report + pre-commit parity job","description":"Post coverage as PR comment (codecov-cli or go tool cover artifact). Add CI job that runs .pre-commit-config.yaml hooks so they're enforced beyond local dev.","status":"open","priority":3,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-05-24T07:06:47Z","created_by":"Christoph Görn","updated_at":"2026-05-24T07:06:47Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-zuh","title":"CI: container build sanity on PR + edge tag on main","description":"Containerfile builds only via Konflux currently. Add PR job that builds container image as sanity check (no push). On push to main, push :edge tag to registry.","status":"open","priority":3,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-05-24T07:06:45Z","created_by":"Christoph Görn","updated_at":"2026-05-24T07:06:45Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-1p1","title":"CI: add go-licenses + conventional commits PR title check","description":"Catch GPL contamination via go-licenses check. Gate Conventional Commits PR title earlier than .releaserc post-merge (use commitlint or equivalent action).","notes":"PR #166 opened: https://codeberg.org/goern/forgejo-mcp/pulls/166. Changes: go-licenses v1.6.0 in release-tools image + license-check step in go-ci (forbidden/restricted denied); new commit-title-check task validates PR title via PAC {{ body.pull_request.title }} AND all PR branch commits; on-pull-request pipeline wires it parallel to build-and-test.","status":"closed","priority":3,"issue_type":"task","assignee":"Christoph Görn","owner":"goern@b4mad.net","created_at":"2026-05-24T07:06:42Z","created_by":"Christoph Görn","updated_at":"2026-05-26T13:30:59Z","started_at":"2026-05-26T13:12:18Z","closed_at":"2026-05-26T13:30:59Z","close_reason":"PR #166 merged","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-td8","title":"CI: decide canonical PR gate (Tekton vs Forgejo Actions)","description":"After 2 weeks of parallel Forgejo Actions + Tekton PR gates, evaluate reliability/speed/contributor-visibility and pick one as canonical. Keep Tekton/Konflux only for signed container builds if Forgejo Actions wins.","acceptance_criteria":"ADR or design note in docs/design/ recording decision + rationale, redundant pipeline removed","status":"closed","priority":3,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-05-24T07:06:40Z","created_by":"Christoph Görn","updated_at":"2026-05-26T09:18:37Z","closed_at":"2026-05-26T09:18:37Z","close_reason":"Decision made: Tekton is canonical PR gate. Forgejo Actions workflows removed in commit 1777cca.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-p0y","title":"Cleanup C4 spike state on Codeberg","description":"Battle-test of forgejo-action-code-review created throwaway repos: goern/c4-spike-target and fork tinytalesshop/c4-spike-target. Both should be deleted once team confirms spike findings have been preserved in battle-test.md and design.md (already done). Also: PR #2 on goern/c4-spike-target is open; close it. Also: tag v0.0.1 not yet created on c5-spike-lib (and secrets not set on c5-spike-lib/c5-spike-consumer) — see related C5 spike issue. Delete all 3 c5 repos when C5 spike completes too.","status":"open","priority":3,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-05-13T06:33:26Z","created_by":"Christoph Görn","updated_at":"2026-05-13T06:33:26Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-7de","title":"Revisit EmbeddedListCap (currently 30) when resource usage telemetry is available","description":"Slice 1 of mcp-resource-templates set operation/resource.EmbeddedListCap = 30 per design.md D8. The cap was chosen by analogy to existing list_* tools, without telemetry. This follow-up tracks revisiting the constant once we have real usage data (issue/PR comment-count distribution, truncation hit rate). Likely outcomes: keep 30, raise to 50, or expose per-resource override.","status":"open","priority":4,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-05-28T13:18:35Z","created_by":"Christoph Görn","updated_at":"2026-05-28T13:18:35Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-7ra","title":"Revisit WithResourceCapabilities(subscribe=true) once a real subscription use case appears","description":"Slice 1 of mcp-resource-templates registered server.WithResourceCapabilities(false, false) per design.md D5 — read-on-demand only, no subscriptions. This follow-up tracks revisiting the subscribe=true path when a real consumer use case appears (e.g., dashboard pushing live updates). Out-of-scope for the initial 7-entity rollout; gating signal is concrete client demand, not telemetry.","status":"open","priority":4,"issue_type":"task","owner":"goern@b4mad.net","created_at":"2026-05-28T13:18:29Z","created_by":"Christoph Görn","updated_at":"2026-05-28T13:18:29Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"forgejo-mcp-7g9","title":"Refactor release-tools image into smaller purpose-specific images","description":"release-tools image has grown to include goreleaser, syft, cosign, go, node, npm, mcpb, jq, curl, govulncheck, and openspec. This is a monolithic image that does not follow SRP. Refactor into smaller purpose-specific images: e.g. build-release (goreleaser+syft+go), sign-release (cosign), pack-release (node+npm+mcpb), validate (openspec), scan (govulncheck+syft). Each image should be smaller, faster to pull, and easier to audit. Coordinate with the release-pipeline-use-release-tools-image change and the forgejo-mcp-gdz cutover criteria. Do not start until at least 2 successful releases using the monolithic image confirm operational correctness.","status":"open","priority":4,"issue_type":"feature","owner":"goern@b4mad.net","created_at":"2026-05-25T21:17:18Z","created_by":"Christoph Görn","updated_at":"2026-05-25T21:17:18Z","dependency_count":0,"dependent_count":0,"comment_count":0}