The install path a stranger reads, and a CI probe that never probed #246

Merged
bvandeusen merged 2 commits from dev into main 2026-09-02 11:25:28 -04:00
2 Commits
Author SHA1 Message Date
bvandeusenandClaude Opus 5 3590c478f5 docs+ci: folder import stays retired, and fix a readiness probe that never probed
CI / lint (push) Successful in 3s
Build images / sign-extension (push) Successful in 4s
CI / extension-version (push) Successful in 3s
Build images / build-ml (push) Successful in 7s
Build images / build-agent (push) Successful in 13s
Build images / build-web (push) Successful in 7s
CI / frontend-build (push) Successful in 22s
extension / lint (push) Successful in 29s
CI / backend-lint-and-test (push) Successful in 49s
CI / integration (push) Successful in 1m57s
extension / lint (pull_request) Successful in 22s
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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TTjbZZ6JirCMSaJzQV1RhA
2026-09-02 00:51:25 -04:00
bvandeusenandClaude Opus 5 8a4af589f1 docs: write the install path for someone who is not the operator (#3271)
Build images / sign-extension (push) Successful in 4s
Build images / build-agent (push) Successful in 9s
Build images / build-ml (push) Successful in 29s
Build images / build-web (push) Successful in 23s
CI / lint (push) Successful in 3s
CI / extension-version (push) Successful in 4s
CI / frontend-build (push) Successful in 20s
CI / backend-lint-and-test (push) Successful in 30s
CI / integration (push) Successful in 3m42s
FC has no login — no User model, no session auth, nothing. That was a
deliberate call for a single-operator tool and it stays (operator, this
session), but it was nowhere in the docs, and the app stores live Patreon /
SubscribeStar / Pixiv session cookies on accounts that carry a payment
method. Anyone standing this up from the README could reasonably have put it
behind a TLS-terminating proxy and considered it handled.

So the no-auth posture is now stated three times, in the three places someone
decides where to bind the port: README has a "Before you expose it" section
above the install instructions, .env.example explains why there is no auth
variable in it, and the compose header says it before the first service.

SECURITY.md claimed the opposite. It listed "a multi-user sharing ACL —
instances can be shared" among the things worth protecting; there are no
accounts to share between. That was rule 47 applied to a codebase that does
not implement it, and it would have told a researcher FC holds a boundary it
does not. Replaced with the real posture, including that TLS without an
authenticating layer in front changes nothing.

Also corrected, all of it stale rather than wrong-at-the-time:

- EXTENSION_API_KEY was dead config. config.py read it into a field nothing
  consumed; the real key is generated into app_setting on first use and
  managed in the UI. Removed from config.py, compose and .env.example.
- .env.example pointed at docs/superpowers/specs/… — there is no docs/ dir —
  and described the extension key as "lands in FC-3", closed 2026-05-21.
- The /import mount comment described an FC-5 ImageRepo migration run from
  "Settings → Maintenance → Legacy migration", a surface with no frontend.
- README said the extension installs from Settings → Maintenance. It is on
  Subscriptions → Settings.

README is now split: running FC above the line, developing FC below it, with
requirements, first run, the extension, upgrading and troubleshooting on the
running side. First run documents the one real gap it found — a new installer
with a library on disk has no button to import it, only POST
/api/import/trigger, because the manual-scan UI was retired 2026-07-02 when
that stopped mattering for an established install. Filed as #3367.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017QHszn9H8VBvx5Ke8x1hvw
2026-09-02 00:16:23 -04:00