ci: build and push Docker image to Forgejo registry on master #1

Merged
bjoern merged 3 commits from ci/docker-publish into master 2026-09-15 06:15:39 +02:00
Member

What

Adds a Forgejo Actions workflow that builds the Docker image and pushes it to the Forgejo container registry on every push to master (+ workflow_dispatch):

  • git.kagaku.eu/teamai/categoraiserver:latest — tracks master (push events only)
  • git.kagaku.eu/teamai/categoraiserver:<short-sha> — every build, for rollback / pre-merge testing

A manually dispatched branch build publishes only its sha tag — :latest is never unreviewed code (same guard as Kagura's workflow).

Same pattern as angela_assistant / Kagura's docker-publish.yml:

  • runs-on: docker, docker/build-push-action@v6 + buildx
  • Registry login via TeamAI org secrets REGISTRY_USER / REGISTRY_TOKEN (Forgejo's automatic GITHUB_TOKEN cannot write packages)
  • No submodule handling and no paths filter — single-project repo, every push is build-relevant

deploy/docker-compose.yml (new)

Registry-pull variant for the Portainer web editor — image: instead of build:. The root docker-compose.yml stays for local development builds. Volumes become external: true; the header comment documents the one-time docker volume create commands (copied from the root compose's CIFS definition).

Merge checklist

  • REGISTRY_USER / REGISTRY_TOKEN must be available to this repo — org-level actions secrets cover this automatically; if they were only set per-repo on Kagura/angela, add them once under Settings → Actions → Secrets.
  • First run on master after merge should go green and git.kagaku.eu/teamai/categoraiserver:latest should appear in the registry.
  • Portainer: create stack from deploy/docker-compose.yml, create the external volumes first.

No code changes — build config only.

## What Adds a Forgejo Actions workflow that builds the Docker image and pushes it to the Forgejo container registry on every push to `master` (+ `workflow_dispatch`): - `git.kagaku.eu/teamai/categoraiserver:latest` — tracks master (push events only) - `git.kagaku.eu/teamai/categoraiserver:<short-sha>` — every build, for rollback / pre-merge testing A manually dispatched **branch** build publishes only its sha tag — `:latest` is never unreviewed code (same guard as Kagura's workflow). Same pattern as angela_assistant / Kagura's `docker-publish.yml`: - `runs-on: docker`, `docker/build-push-action@v6` + buildx - Registry login via TeamAI org secrets `REGISTRY_USER` / `REGISTRY_TOKEN` (Forgejo's automatic `GITHUB_TOKEN` cannot write packages) - No submodule handling and no `paths` filter — single-project repo, every push is build-relevant ## deploy/docker-compose.yml (new) Registry-pull variant for the Portainer web editor — `image:` instead of `build:`. The root `docker-compose.yml` stays for local development builds. Volumes become `external: true`; the header comment documents the one-time `docker volume create` commands (copied from the root compose's CIFS definition). ## Merge checklist - [ ] `REGISTRY_USER` / `REGISTRY_TOKEN` must be available to this repo — org-level actions secrets cover this automatically; if they were only set per-repo on Kagura/angela, add them once under Settings → Actions → Secrets. - [ ] First run on master after merge should go green and `git.kagaku.eu/teamai/categoraiserver:latest` should appear in the registry. - [ ] Portainer: create stack from `deploy/docker-compose.yml`, create the external volumes first. No code changes — build config only.
Every master push builds the Docker image and pushes :latest + short-sha
to git.kagaku.eu/teamai/categoraiserver. Adds a registry-pull Portainer
compose under deploy/ (root compose stays for local builds).
Manual workflow_dispatch builds publish only their short-sha tag;
:latest stays reserved for merged master (matches Kagura's guard).
Member

🔮 fufu~ Jibril reviewed your code!

Ooh, a brand-new repo's very first PR — build config only, no code to sink my teeth into~ So instead I fetched your two named siblings (Kagura and doujin-manager docker-publish.yml) and diffed your workflow against them line by line. That's where the fun was hiding. ♪

Verdict: ⛔ I can't let this pass~ ♡

The bones are lovely — action versions, login, buildx, the deploy compose, all faithful. But your :latest tag has two unguarded doors, and :latest is your production channel (your own deploy compose says so: "Update the stack with re-pull pulls :latest"). A tag that production pulls on every redeploy deserves the same armor its siblings wear~

⛔ These need fixing before I'm satisfied~

  1. [.github/workflows/docker-publish.yml:14 + :46] — workflow_dispatch unconditionally publishes :latest. The PR body says "same pattern as Kagura's docker-publish.yml", but Kagura guards exactly this — I quote its comment: "A manually dispatched branch build publishes its version tag alone, so Portainer's :latest is never quietly replaced by unmerged work." Your copy dispatches on any branch (Forgejo runs the branch's own workflow file) and pushes that branch's image as :latest. Fufu~ you wouldn't test this very workflow by dispatching it on ci/docker-publish pre-merge… and silently flash unmerged code into the production tag, would you? ♡ That's precisely the footgun Kagura's conditional exists for.
    Fix: mirror Kagura — compute the tag list in a step and append :latest only when github.event_name == 'push':

    - name: Compute image tags
      id: tags
      shell: bash
      run: |
        IMAGE=git.kagaku.eu/teamai/categoraiserver
        TAGS="$IMAGE:${GITHUB_SHA::7}"
        if [ "${{ github.event_name }}" = "push" ]; then
          TAGS="$TAGS
        $IMAGE:latest"
        fi
        { echo "list<<EOF"; echo "$TAGS"; echo "EOF"; } >> "$GITHUB_OUTPUT"
    

    then tags: ${{ steps.tags.outputs.list }}.

  2. [.github/workflows/docker-publish.yml:10 (missing)] — no concurrency group. doujin-manager's workflow queues per-ref with a comment describing this exact failure: "Queue runs per ref instead of racing pushes of :latest. No cancel-in-progress: a half-cancelled push must never leave a stale :latest behind." Two quick pushes to master → two parallel build-and-push jobs → last writer on :latest is nondeterministic, so Portainer's next re-pull can serve the older commit. Nondeterministic production state from a race is a bug, not a style preference~
    Fix:

    concurrency:
      group: docker-publish-${{ github.ref }}
    

    (deliberately without cancel-in-progress, per the sibling's reasoning).

💡 Little ideas (non-blocking)~

  1. [deploy/docker-compose.yml:44-48] — /home/appuser/local (the local SQLite db from appsettings.Container.json) isn't volume-mounted; a container recreate wipes it. Inherited faithfully from the root compose, and DatabaseSyncService syncs to the CIFS remote, so likely rebuildable — but if the local db ever holds anything precious, give it its own external volume.
  2. [deploy/docker-compose.yml:39] — start_period: 40s (+3×30s retries) is the only grace before the healthcheck kills the container, and DatabaseSyncService blocks startup on the initial sync. Same value as the root compose, so presumably fine in practice — just bump it if first-boot sync ever gets slow.

✅ What I liked~

  • The deploy compose header is a gem — one-time docker volume create commands with the full CIFS options copied verbatim from the root compose's driver_opts (I diffed them: username/uid=1000/iocharset/vers=3.0/file_mode/dir_mode — exact match). Future-you will thank present-you~
  • Correct omissions where siblings need things you don't: no fetch-depth: 0 (no MinVer here — your Dockerfile passes no APP_VERSION), no submodules: true (no .gitmodules), no paths filter (single-project repo, and doujin-manager documented why paths filters bite anyway).
  • Healthcheck verified against reality: /scalar is really mapped (app.MapScalarApiReference(), Program.cs:99) and curl really ships in the runtime image (Dockerfile apt-get line). And the PR body's merge checklist is honest about the secrets prerequisite — Forgejo's automatic GITHUB_TOKEN indeed can't write packages.
  • Both new files parse as valid YAML, image name all-lowercase, sha-tag-for-rollback is a nice touch. ♪

(No test-coverage ask this time — the repo has no test projects and this PR adds zero runtime code; the workflow's first live run on master IS the test. fufu~ I checked anyway~)


Automated review by Jibril · 2026-09-14
CI/CD: absent for head SHA d13db31 (no workflow has run) · Local checks: YAML validated (both files), healthcheck endpoint + curl cross-verified vs Program.cs/Dockerfile, sibling workflows (Kagura, doujin-manager docker-publish.yml) fetched and diffed

## 🔮 fufu~ Jibril reviewed your code! Ooh, a brand-new repo's very first PR — build config only, no code to sink my teeth into~ So instead I fetched your two named siblings (`Kagura` and `doujin-manager` `docker-publish.yml`) and diffed your workflow against them line by line. That's where the fun was hiding. ♪ ### Verdict: ⛔ I can't let this pass~ ♡ The bones are lovely — action versions, login, buildx, the deploy compose, all faithful. But your `:latest` tag has **two unguarded doors**, and `:latest` is your production channel (your own deploy compose says so: *"Update the stack with re-pull pulls :latest"*). A tag that production pulls on every redeploy deserves the same armor its siblings wear~ #### ⛔ These need fixing before I'm satisfied~ 1. **[.github/workflows/docker-publish.yml:14 + :46]** — `workflow_dispatch` **unconditionally publishes `:latest`**. The PR body says "same pattern as Kagura's docker-publish.yml", but Kagura guards exactly this — I quote its comment: *"A manually dispatched branch build publishes its version tag alone, so Portainer's `:latest` is never quietly replaced by unmerged work."* Your copy dispatches on **any branch** (Forgejo runs the branch's own workflow file) and pushes that branch's image as `:latest`. Fufu~ you wouldn't test this very workflow by dispatching it on `ci/docker-publish` pre-merge… and silently flash unmerged code into the production tag, would you? ♡ That's precisely the footgun Kagura's conditional exists for. Fix: mirror Kagura — compute the tag list in a step and append `:latest` only when `github.event_name == 'push'`: ```yaml - name: Compute image tags id: tags shell: bash run: | IMAGE=git.kagaku.eu/teamai/categoraiserver TAGS="$IMAGE:${GITHUB_SHA::7}" if [ "${{ github.event_name }}" = "push" ]; then TAGS="$TAGS $IMAGE:latest" fi { echo "list<<EOF"; echo "$TAGS"; echo "EOF"; } >> "$GITHUB_OUTPUT" ``` then `tags: ${{ steps.tags.outputs.list }}`. 2. **[.github/workflows/docker-publish.yml:10 (missing)]** — **no `concurrency` group**. `doujin-manager`'s workflow queues per-ref with a comment describing this exact failure: *"Queue runs per ref instead of racing pushes of `:latest`. No cancel-in-progress: a half-cancelled push must never leave a stale `:latest` behind."* Two quick pushes to master → two parallel build-and-push jobs → **last writer on `:latest` is nondeterministic**, so Portainer's next re-pull can serve the *older* commit. Nondeterministic production state from a race is a bug, not a style preference~ Fix: ```yaml concurrency: group: docker-publish-${{ github.ref }} ``` (deliberately **without** `cancel-in-progress`, per the sibling's reasoning). #### 💡 Little ideas (non-blocking)~ 1. **[deploy/docker-compose.yml:44-48]** — `/home/appuser/local` (the local SQLite db from `appsettings.Container.json`) isn't volume-mounted; a container recreate wipes it. Inherited faithfully from the root compose, and `DatabaseSyncService` syncs to the CIFS remote, so likely rebuildable — but if the local db ever holds anything precious, give it its own external volume. 2. **[deploy/docker-compose.yml:39]** — `start_period: 40s` (+3×30s retries) is the only grace before the healthcheck kills the container, and `DatabaseSyncService` *blocks startup* on the initial sync. Same value as the root compose, so presumably fine in practice — just bump it if first-boot sync ever gets slow. #### ✅ What I liked~ - The **deploy compose header** is a gem — one-time `docker volume create` commands with the full CIFS options copied verbatim from the root compose's `driver_opts` (I diffed them: username/uid=1000/iocharset/vers=3.0/file_mode/dir_mode — exact match). Future-you will thank present-you~ - Correct omissions where siblings need things you don't: no `fetch-depth: 0` (no MinVer here — your Dockerfile passes no `APP_VERSION`), no `submodules: true` (no `.gitmodules`), no `paths` filter (single-project repo, and doujin-manager documented why paths filters bite anyway). - Healthcheck verified against reality: `/scalar` is really mapped (`app.MapScalarApiReference()`, Program.cs:99) and `curl` really ships in the runtime image (Dockerfile apt-get line). And the PR body's merge checklist is honest about the secrets prerequisite — Forgejo's automatic `GITHUB_TOKEN` indeed can't write packages. - Both new files parse as valid YAML, image name all-lowercase, sha-tag-for-rollback is a nice touch. ♪ *(No test-coverage ask this time — the repo has no test projects and this PR adds zero runtime code; the workflow's first live run on master IS the test. fufu~ I checked anyway~)* --- *Automated review by Jibril · 2026-09-14* *CI/CD: absent for head SHA d13db31 (no workflow has run) · Local checks: YAML validated (both files), healthcheck endpoint + curl cross-verified vs Program.cs/Dockerfile, sibling workflows (Kagura, doujin-manager docker-publish.yml) fetched and diffed*
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh! A build-config PR~ My favorite kind — pure plumbing, no runtime code to misbehave... but that just means every line has to be exactly right, because nobody tests their pipelines until 2 AM when the registry rejects a push~ ♡ So I tested it for you. Fufu~

Verdict: ✅ Looks good to me~

✅ What I liked~

  • The :latest dispatch guard is genuinely correct — and I verified it, not just read it. I extracted the tag script and ran both arms against the real head SHA: push → git.kagaku.eu/teamai/categoraiserver:001631b + :latest; workflow_dispatch → sha tag only, :latest untouched. The env: indirection for github.event_name (instead of interpolating ${{ }} directly inside the script) is the injection-safe form — cleaner than Kagura's sibling version, and it fixes a real gap in angela's workflow, which has workflow_dispatch without the guard and would happily overwrite :latest with an unmerged branch. You took the best sibling and improved it~ ♪
  • Per-repo tailoring is thoughtful, not copy-paste: no submodule handling (verified: no .gitmodules in this repo, unlike Kagura/angela), no MinVer versioning (verified: no Directory.Build.props — short-sha tags like angela are the right scheme here), no paths filter with the justification written in a comment. Each omission is deliberate and documented. That's the good kind of consistency — pattern-faithful, not cargo-culted.
  • Registry login is byte-for-byte the established TeamAI pattern — REGISTRY_USER/REGISTRY_TOKEN org secrets, same comment explaining why the automatic GITHUB_TOKEN can't write packages. Matches Kagura and angela exactly.
  • deploy/docker-compose.yml is a faithful sibling of angela's Portainer stack file — header with one-time prerequisites, image: instead of build:, external volumes with the exact docker volume create CIFS command copied from the root compose, and the service definition (ports 8001:5001, env, volume mounts, /scalar healthcheck timings) matches the root compose property-for-property. The secrets in the comments are <SMB_USER>/<SMB_PASS> placeholders only — nothing real leaked~
  • The merge checklist honestly flags the one thing I can't verify from the repo side (org secrets availability) instead of pretending it's done. I appreciate that~

💡 Little ideas (non-blocking)~

  1. [.github/workflows/docker-publish.yml] — No concurrency: group, so two rapid master pushes race each other into the registry (last-write-wins on :latest, wasted build minutes). Kagura and angela don't have one either, so this is an org-wide someday-idea, not a repo-specific gap — consistency wins for now. concurrency: { group: docker-publish-${{ github.ref }}, cancel-in-progress: true } would be the shape if you ever want it.

No code paths, no test debt, no coverage questions — for a config-only PR, the "test" is the workflow surviving contact with the runner, and everything checkable locally checks out. Merge it and let the first master push be the proof~ fufu~ ♡


Automated review by Jibril · 2026-09-14
CI/CD: absent for head SHA 001631b (no coverage bot, 0 prior comments) · Local checks: YAML validated (workflow + both composes), tag-script both arms simulated against real head SHA, sibling-diffed vs Kagura + angela docker-publish.yml + angela deploy/docker-compose.yml, submodule/MinVer absence verified

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh! A build-config PR~ My favorite kind — pure plumbing, no runtime code to misbehave... but that just means every line has to be *exactly* right, because nobody tests their pipelines until 2 AM when the registry rejects a push~ ♡ So I tested it for you. Fufu~ ### Verdict: ✅ Looks good to me~ #### ✅ What I liked~ - **The `:latest` dispatch guard is genuinely correct** — and I *verified* it, not just read it. I extracted the tag script and ran both arms against the real head SHA: `push` → `git.kagaku.eu/teamai/categoraiserver:001631b` **+** `:latest`; `workflow_dispatch` → sha tag only, `:latest` untouched. The `env:` indirection for `github.event_name` (instead of interpolating `${{ }}` directly inside the script) is the injection-safe form — cleaner than Kagura's sibling version, and it fixes a real gap in angela's workflow, which has `workflow_dispatch` **without** the guard and would happily overwrite `:latest` with an unmerged branch. You took the best sibling and improved it~ ♪ - **Per-repo tailoring is thoughtful, not copy-paste**: no submodule handling (verified: no `.gitmodules` in this repo, unlike Kagura/angela), no MinVer versioning (verified: no `Directory.Build.props` — short-sha tags like angela are the right scheme here), no `paths` filter with the justification written in a comment. Each *omission* is deliberate and documented. That's the good kind of consistency — pattern-faithful, not cargo-culted. - **Registry login is byte-for-byte the established TeamAI pattern** — `REGISTRY_USER`/`REGISTRY_TOKEN` org secrets, same comment explaining why the automatic `GITHUB_TOKEN` can't write packages. Matches Kagura and angela exactly. - **`deploy/docker-compose.yml` is a faithful sibling of angela's Portainer stack file** — header with one-time prerequisites, `image:` instead of `build:`, external volumes with the exact `docker volume create` CIFS command copied from the root compose, and the service definition (ports `8001:5001`, env, volume mounts, `/scalar` healthcheck timings) matches the root compose property-for-property. The secrets in the comments are `<SMB_USER>`/`<SMB_PASS>` placeholders only — nothing real leaked~ - The merge checklist honestly flags the one thing I *can't* verify from the repo side (org secrets availability) instead of pretending it's done. I appreciate that~ #### 💡 Little ideas (non-blocking)~ 1. **[.github/workflows/docker-publish.yml]** — No `concurrency:` group, so two rapid master pushes race each other into the registry (last-write-wins on `:latest`, wasted build minutes). Kagura and angela don't have one either, so this is an org-wide someday-idea, not a repo-specific gap — consistency wins for now. `concurrency: { group: docker-publish-${{ github.ref }}, cancel-in-progress: true }` would be the shape if you ever want it. No code paths, no test debt, no coverage questions — for a config-only PR, the "test" is the workflow surviving contact with the runner, and everything checkable locally checks out. Merge it and let the first master push be the proof~ fufu~ ♡ --- *Automated review by Jibril · 2026-09-14* *CI/CD: absent for head SHA 001631b (no coverage bot, 0 prior comments) · Local checks: YAML validated (workflow + both composes), tag-script both arms simulated against real head SHA, sibling-diffed vs Kagura + angela `docker-publish.yml` + angela `deploy/docker-compose.yml`, submodule/MinVer absence verified*
Two rapid master pushes raced their build-and-push jobs; last writer
on :latest was nondeterministic. Queue per ref without cancel-in-progress,
matching doujin-manager's reasoning: a half-cancelled push must never
leave a stale :latest behind.
Author
Member

Both blockers from the ⛔ review addressed — head is now 4d0410b:

1. :latest dispatch guard (already in 001631b, verified by your re-run) — dispatch publishes sha-only; :latest only on push events.

2. Concurrency group (4d0410b) — added:

concurrency:
  group: docker-publish-${{ github.ref }}

Deliberately without cancel-in-progress, per your first review's reasoning (and doujin-manager's actual comment, which I fetched to check — your second review's cancel-in-progress: true aside would cancel an in-flight push mid-upload; the earliest-first reading wins): a half-cancelled push must never leave a stale :latest behind. Queuing serializes rapid master pushes, killing the last-writer-wins race.

Verified on the remote branch via fresh clone + raw-byte check: concurrency group present, no cancel-in-progress key, dispatch guard from 001631b intact, secret refs un-mangled, YAML parses.

Non-blocking ideas (local db volume, start_period) left for a follow-up when the container's real-world first-boot behavior is known — noted, not forgotten.

Both blockers from the ⛔ review addressed — head is now `4d0410b`: **1. `:latest` dispatch guard** (already in `001631b`, verified by your re-run) — dispatch publishes sha-only; `:latest` only on push events. **2. Concurrency group** (`4d0410b`) — added: ```yaml concurrency: group: docker-publish-${{ github.ref }} ``` Deliberately **without** `cancel-in-progress`, per your first review's reasoning (and doujin-manager's actual comment, which I fetched to check — your second review's `cancel-in-progress: true` aside would cancel an in-flight push mid-upload; the earliest-first reading wins): a half-cancelled push must never leave a stale `:latest` behind. Queuing serializes rapid master pushes, killing the last-writer-wins race. Verified on the remote branch via fresh clone + raw-byte check: concurrency group present, no `cancel-in-progress` key, dispatch guard from `001631b` intact, secret refs un-mangled, YAML parses. Non-blocking ideas (local db volume, `start_period`) left for a follow-up when the container's real-world first-boot behavior is known — noted, not forgotten.
Member

🔮 fufu~ Jibril reviewed your code!

Round three~ The :latest armor is complete now, and I checked every rivet myself — not from your reply, from the tree. ♪

Verdict: ✅ Looks good to me~

4d0410b is exactly what I asked for, and nothing it shouldn't be: a surgical +5/-0 in .github/workflows/docker-publish.yml only (verified: git diff 001631b..4d0410b touches one file, five added lines, zero deletions — the dispatch guard from 001631b byte-intact, secrets untouched).

✅ What I liked~

  • Blocker 2 closed to the letter. concurrency: group: docker-publish-${{ github.ref }} with no cancel-in-progress key — I parsed the YAML and grepped for the key form specifically, because a stray occurrence in the comment must never be mistaken for the option. The comment itself is doujin-manager's reasoning verbatim: a half-cancelled push must never leave a stale :latest behind. Rapid master pushes now queue instead of racing — the last-writer-wins nondeterminism is dead~
  • Blocker 1 still standing guard. Re-simulated the tag script against the real head SHA: push → git.kagaku.eu/teamai/categoraiserver:4d0410b + :latest; workflow_dispatch → sha tag only. The env: indirection for event_name remains the injection-safe form. A guard that survives a later commit is a guard that was written properly~ ♡
  • Deploy compose parity re-verified property-for-property against the root compose: ports 8001:5001, environment (map-form vs list-form — semantically identical, Compose accepts both), healthcheck timings including start_period: 40s, and both volume mounts. Image-only (no build:), volumes external: true, placeholders-only secrets in the header comments.
  • All three YAML files parse clean at the new head.
  • And your fix-reply demonstrated the right instincts: you fetched doujin-manager's actual comment to adjudicate my two reviews' contradictory cancel-in-progress asides and correctly sided with the earliest-first reasoning. Reading the siblings yourself instead of trusting the reviewer's paraphrase — fufu~ that's exactly how this is supposed to work~ ♪

💡 Little ideas (non-blocking)~

  1. The deferred items (local-SQLite volume mount, start_period headroom for first-boot sync) remain correctly parked with a stated trigger — revisit when the container's real-world first-boot behavior is known. No action needed now.

Both blockers from the ⛔ review are closed, verified against the tree at 4d0410b, with zero scope creep between them. The :latest channel now has both pieces of armor its siblings wear. Merge it and let the first master push light the pipeline up~ fufu~ ♡


Automated review by Jibril · 2026-09-14
CI/CD: absent for head SHA 4d0410b (workflow itself lands in this PR — its first master run is the test) · Local checks: incremental diff verified surgical (1 file, +5/-0), tag-script both arms re-simulated at real head SHA, concurrency key parsed + key-form grep (comment-only hit excluded), YAML validated (workflow + both composes), deploy↔root compose property parity re-verified

## 🔮 fufu~ Jibril reviewed your code! Round three~ The `:latest` armor is complete now, and I checked every rivet myself — not from your reply, from the tree. ♪ ### Verdict: ✅ Looks good to me~ **4d0410b** is exactly what I asked for, and nothing it shouldn't be: a surgical +5/-0 in `.github/workflows/docker-publish.yml` **only** (verified: `git diff 001631b..4d0410b` touches one file, five added lines, zero deletions — the dispatch guard from `001631b` byte-intact, secrets untouched). #### ✅ What I liked~ - **Blocker 2 closed to the letter.** `concurrency: group: docker-publish-${{ github.ref }}` with **no `cancel-in-progress` key** — I parsed the YAML and grepped for the key form specifically, because a stray occurrence in the *comment* must never be mistaken for the option. The comment itself is doujin-manager's reasoning verbatim: a half-cancelled push must never leave a stale `:latest` behind. Rapid master pushes now queue instead of racing — the last-writer-wins nondeterminism is dead~ - **Blocker 1 still standing guard.** Re-simulated the tag script against the real head SHA: `push` → `git.kagaku.eu/teamai/categoraiserver:4d0410b` + `:latest`; `workflow_dispatch` → sha tag only. The `env:` indirection for `event_name` remains the injection-safe form. A guard that survives a later commit is a guard that was written properly~ ♡ - **Deploy compose parity re-verified property-for-property** against the root compose: ports `8001:5001`, environment (map-form vs list-form — semantically identical, Compose accepts both), healthcheck timings including `start_period: 40s`, and both volume mounts. Image-only (no `build:`), volumes `external: true`, placeholders-only secrets in the header comments. - All three YAML files parse clean at the new head. - And your fix-reply demonstrated the right instincts: you fetched doujin-manager's actual comment to adjudicate my two reviews' contradictory `cancel-in-progress` asides and correctly sided with the earliest-first reasoning. Reading the siblings *yourself* instead of trusting the reviewer's paraphrase — fufu~ that's exactly how this is supposed to work~ ♪ #### 💡 Little ideas (non-blocking)~ 1. The deferred items (local-SQLite volume mount, `start_period` headroom for first-boot sync) remain correctly parked with a stated trigger — revisit when the container's real-world first-boot behavior is known. No action needed now. Both blockers from the ⛔ review are closed, verified against the tree at `4d0410b`, with zero scope creep between them. The `:latest` channel now has both pieces of armor its siblings wear. Merge it and let the first master push light the pipeline up~ fufu~ ♡ --- *Automated review by Jibril · 2026-09-14* *CI/CD: absent for head SHA 4d0410b (workflow itself lands in this PR — its first master run is the test) · Local checks: incremental diff verified surgical (1 file, +5/-0), tag-script both arms re-simulated at real head SHA, concurrency key parsed + key-form grep (comment-only hit excluded), YAML validated (workflow + both composes), deploy↔root compose property parity re-verified*
bjoern merged commit 27eedcdfe7 into master 2026-09-15 06:15:39 +02:00
bjoern deleted branch ci/docker-publish 2026-09-15 06:15:39 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
TeamAI/CategoraiServer!1
No description provided.