From 3590c478f5f9ed1fb25327f284986897f7825b87 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 2 Sep 2026 00:51:25 -0400 Subject: [PATCH] docs+ci: folder import stays retired, and fix a readiness probe that never probed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two unrelated things, both found while closing out milestone 328. **Folder import (#3367).** The operator's call, this session: the import-from-file surface was abandoned on purpose and is not coming back — "it has its own complexities that we didn't need." The README and the compose comment both described the missing button as a rough edge with a tracking issue, which promised a fix that is not coming. Both now say the retirement is the decision, name Subscriptions as the supported way to fill a new install, and describe /api/import/trigger as an unsupported escape hatch for anyone who wants to script one. **The CI readiness probe.** ci.yml's integration job and baseline.yml both waited for Postgres with `(echo > /dev/tcp/$PG_IP/5432)`. Those steps run under `sh -e` — act's default shell — where /dev/tcp is not a magic path but a filename that does not exist. The probe could therefore never succeed: run 18035, a GREEN run, spends 05:20:53 → 05:22:53 in that loop and exits it by exhaustion, not by connecting. Every integration run has been paying a flat 120s for a check that established nothing, and proceeding regardless. Replaced with a socket connect in python (present in the image, no package needed), and exhausting the budget is now a named failure instead of a silent fall-through — rule 156. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01TTjbZZ6JirCMSaJzQV1RhA --- .forgejo/workflows/baseline.yml | 13 ++++++++++++- .forgejo/workflows/ci.yml | 19 ++++++++++++++++++- README.md | 22 ++++++++++++---------- docker-compose.yml | 14 ++++++++------ 4 files changed, 50 insertions(+), 18 deletions(-) diff --git a/.forgejo/workflows/baseline.yml b/.forgejo/workflows/baseline.yml index 32a8d9a..afe39e2 100644 --- a/.forgejo/workflows/baseline.yml +++ b/.forgejo/workflows/baseline.yml @@ -87,10 +87,21 @@ jobs: test -n "$PG_IP" echo "PG_CONTAINER=$PG" >> "$GITHUB_ENV" echo "DB_HOST=$PG_IP" >> "$GITHUB_ENV" + # Socket probe in python, not bash's /dev/tcp — these steps run under + # `sh -e`, where that path does not exist. Same fix and same reasoning + # as ci.yml's integration job; see the comment there. + pg_ready="" for i in $(seq 1 60); do - (echo > "/dev/tcp/$PG_IP/5432") >/dev/null 2>&1 && break + if python -c "import socket,sys; s=socket.socket(); s.settimeout(2); sys.exit(0 if s.connect_ex(('$PG_IP', 5432)) == 0 else 1)"; then + pg_ready=1 + break + fi sleep 2 done + if [ -z "$pg_ready" ]; then + echo "postgres at $PG_IP:5432 did not accept a connection within 120s" + exit 1 + fi if command -v uv >/dev/null 2>&1; then uv pip install --system -r requirements.txt else diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index af31cb5..fb71947 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -255,10 +255,27 @@ jobs: export DB_HOST="$PG_IP" export CELERY_BROKER_URL="redis://$RD_IP:6379/0" export CELERY_RESULT_BACKEND="redis://$RD_IP:6379/0" + # These steps run under `sh -e`, not bash, so bash's /dev/tcp magic + # path does not exist here — the probe this loop used to run could + # never succeed and simply burned the full 120s on every run, green + # or red, then continued without having established anything. Python + # is in the image and needs no installed package for a socket + # connect, so it is the probe. Exhausting the budget is now a named + # failure rather than a silent fall-through (rule 156): if Postgres + # is genuinely not up, that is what the log should say, instead of + # whatever the first query happens to raise two minutes later. + pg_ready="" for i in $(seq 1 60); do - (echo > "/dev/tcp/$PG_IP/5432") >/dev/null 2>&1 && break + if python -c "import socket,sys; s=socket.socket(); s.settimeout(2); sys.exit(0 if s.connect_ex(('$PG_IP', 5432)) == 0 else 1)"; then + pg_ready=1 + break + fi sleep 2 done + if [ -z "$pg_ready" ]; then + echo "postgres at $PG_IP:5432 did not accept a connection within 120s" + exit 1 + fi if command -v uv >/dev/null 2>&1; then uv pip install --system -r requirements.txt pytest pytest-asyncio else diff --git a/README.md b/README.md index 1f2af0b..22c89d5 100644 --- a/README.md +++ b/README.md @@ -94,17 +94,19 @@ A few things are worth knowing about the first few minutes: than broken. It is idempotent — a restart resumes rather than refetches. - **The gallery starts empty**, and that is the expected state. Add a creator under **Subscriptions** and it fills as posts come down. -- **If you already have a library on disk**, note that importing it is - currently an API call rather than a button — the manual-scan UI was retired - in July 2026, when imports started arriving entirely via downloads and the - extension. Mount the folder at `./import` and kick it off with: +- **If you already have a library on disk**, there is no screen that imports + it, and there is not going to be one. Folder ingestion had a UI until July + 2026; it was retired once posts began arriving entirely through + subscriptions and the browser extension, and the decision to leave it + retired is deliberate — the folder path carries complexity the product does + not need in order to do its job. The supported way to fill a new install is + to add the creators you follow under **Subscriptions** and let it pull. - ```bash - curl -X POST http://localhost:8080/api/import/trigger - ``` - - Progress shows up under **Settings → Activity**. This is a known rough - edge, not the intended shape (#3367). + The `/api/import/trigger` endpoint is still wired up for anyone who wants to + script a one-off against a folder mounted at `./import`, and its progress + shows under **Settings → Activity**. Treat it as an unsupported escape + hatch rather than a feature: nothing in the UI drives it and nothing else + in this README depends on it. - **To download from a paywalled account**, FabledCurator needs that account's session — see the browser extension below. Without one it can still fetch public posts. diff --git a/docker-compose.yml b/docker-compose.yml index cf13fa0..fd68189 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -136,9 +136,9 @@ services: volumes: - ./images:/images - ./import:/import - # /import is the staging area for ingesting a library you already have - # on disk. Drop files in ./import, or bind-mount an existing directory - # under it as below, then trigger the scan: + # /import is a staging area for scripting a one-off ingest of a library + # you already have on disk. Drop files in ./import, or bind-mount an + # existing directory under it as below, then trigger the scan: # # curl -X POST http://localhost:8080/api/import/trigger # @@ -146,9 +146,11 @@ services: # worker + scheduler services mount the same /import so the scan can run # on whichever lane picks it up. # - # There is no UI button for this: the manual-scan surface was retired - # 2026-07-02 once imports arrived via downloads + the extension, which is - # true for an established install and not for a new one. Tracked in #3367. + # Deliberately has no UI. The manual-scan surface was retired 2026-07-02 + # once imports arrived via subscriptions + the extension, and the call + # not to restore it stands (operator, 2026-09-02): folder ingestion + # brings complexity the product does not need. The endpoint stays as an + # unsupported escape hatch; the supported way in is Subscriptions. # - /srv/media/my-library:/import/my-library:ro depends_on: postgres: { condition: service_healthy }