skills: NEW felhom-app-catalog (4th skill) — catalog authoring workflow, proven on SparkyFitness
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -4,75 +4,76 @@
|
||||
|
||||
---
|
||||
|
||||
# REPORT — Golden rebuild 0.98.3 (drill B5 + B1) — docs half (2026-07-03)
|
||||
# REPORT — `felhom-app-catalog` skill (4th) + SparkyFitness finalized as its worked example (2026-07-03)
|
||||
|
||||
Implementation half in `felhom-agent/REPORT.md` (build-golden.sh v2.0.0 @ `ceca355`). Full drill
|
||||
evidence: **`documentation/audits/DRILL-golden-098-2026-07-03.md`** (A–D transcripts, unit states,
|
||||
resolution-order + fetch/sha proofs, cleanup, observations). This repo's changes are docs-only.
|
||||
Companion half in `app-catalog-felhom.eu/REPORT.md` (the template changes + live-deploy evidence).
|
||||
|
||||
## Baselines
|
||||
|
||||
| Repo | Base → head |
|
||||
|---|---|
|
||||
| felhom.eu | `2e33a8b` → this push (docs) |
|
||||
| felhom-agent | `c9f963d` → `ceca355` (script + CHANGELOG) |
|
||||
| felhom-controller | untouched; **0.98.3** reconfirmed current + pullable, and is the baked tag |
|
||||
| felhom.eu | `7ad111c` → this push (`skills/felhom-app-catalog/SKILL.md` NEW + docs) |
|
||||
| app-catalog-felhom.eu | `15cdf7b` → `c7490f7` (sparkyfitness finalized + REUSE.md probe-naming row) |
|
||||
| felhom-controller | READ-ONLY (sync.go + healthprobe.go consulted to state consumer behavior accurately) |
|
||||
|
||||
## What shipped (system-level)
|
||||
## The skill
|
||||
|
||||
- **Golden 0.98.3** — bakes controller 0.98.3 + the `felhom-controller-bootstrap.path` unit;
|
||||
published to Gitea (`felhom-golden/0.98.3/golden.tar.zst`, HTTP 201, round-trip sha
|
||||
`b9a02ef1b6f02b9b58babc4c6aad9cf6c053ebdfba116c78c8e7830de757fd01`) and **operator-vouched** in
|
||||
the Day-0 manifest (now: agent 0.63.0 + golden 0.98.3 — verified via `/api/v1/artifacts`).
|
||||
- **B5 dead:** clean-room Day-0 install (Scenario C, local golden; Scenario D, vouched Gitea
|
||||
fetch + sha verify) lands controller **0.98.3 on first boot**; `selfupdate/check` reports
|
||||
up-to-date → the box self-manages; agent selftest clean; bentopdf deploys + answers 200.
|
||||
- **B1 dead:** isolated proof — service condition-failed + path `active (waiting)` on a mount-less
|
||||
boot; `pct set -mp9 …` against the RUNNING guest started the controller in ~1 s, no reboot
|
||||
(`uptime -s` unchanged). Installer v1.9.1 reboot retained as belt (removal = recorded cleanup).
|
||||
- **Workflow, not reference:** research → inspect-the-image healthcheck choice → compose →
|
||||
`.felhom.yml` → live UI deploy on demo → verify healthy → reconcile count → finish. Every field
|
||||
table is a POINTER to app-catalog `REUSE.md` §1–2 / `README.md` §format — the shipped SKILL.md
|
||||
contains no field tables at all (checked); the one new fact it teaches (probe-container naming)
|
||||
was placed in REUSE.md and is referenced from the skill.
|
||||
- **Installer:** no change needed — `install_skills.py` auto-discovers `skills/*/SKILL.md` dirs
|
||||
(line 69). Ran it: `felhom-app-catalog junction -> E:\git\felhom.eu\skills\felhom-app-catalog`.
|
||||
- **Fresh-session discovery:** `claude -p "List your custom skills…"` → all 4 listed
|
||||
(`felhom-app-catalog`, `felhom-build-deploy`, `felhom-testing`, `felhom-ui-design`).
|
||||
|
||||
## Docs changed (this repo)
|
||||
## Two verified facts the exercise added to the knowledge base
|
||||
|
||||
- `documentation/runbooks/day0-install.md` — **D.1b retired** to a one-line `selfupdate/check`
|
||||
verification; old procedure → Part F troubleshooting row keyed on "golden older than 0.86.0";
|
||||
header versions line (script v1.9.1 / agent v0.63.0 / golden v0.98.3); A.3 drilled-known-good
|
||||
pair + vouch-≥0.98.3 note; A.4 floor text rewritten + raise-floor recommendation.
|
||||
- `documentation/audits/DRILL-day0-cleanroom-2026-07-03.md` — ledger **B1, B5 → FIXED**; R6
|
||||
belt-note.
|
||||
- `documentation/backlog/FOLLOWUP-golden-default-controller-tag.md` + `backlog/README.md` —
|
||||
**RESOLVED** (M18/M19 convention: file kept + annotated, README entry marked FIXED; the note's
|
||||
`:0.43.0` numbers were history — the live default had already rotted to `:0.85.1`, which is the
|
||||
form of the problem the mandatory arg kills).
|
||||
- NEW `documentation/audits/DRILL-golden-098-2026-07-03.md` — the evidence doc.
|
||||
1. **Probe-container naming (REUSE.md row, new):** the controller-side `healthcheck.checks[]`
|
||||
probe dials the container named EXACTLY like the stack dir; fallback = first running
|
||||
prefix-match — in a multi-container stack that can be the DB. Convention: exposed service's
|
||||
`container_name` = stack name (vaultwarden/rallly already comply; sparkyfitness now does).
|
||||
2. **BusyBox `ash` `command -v` takes ONE argument** — `command -v wget curl node python3`
|
||||
reported "wget only" in both SparkyFitness images while per-tool runs showed curl (and node in
|
||||
the server) present. The skill's inspect command is a per-tool loop for this reason.
|
||||
|
||||
## Key proofs (short form; transcripts in the evidence doc)
|
||||
## SparkyFitness — markers resolved by inspection (no more VERIFY-BEFORE-FINALIZE)
|
||||
|
||||
| Gate | Evidence |
|
||||
|---|---|
|
||||
| B5 red-proof | no-arg `build-golden.sh` dies with usage, exit 1, before any `pct` op (run on Windows + in the drill VM) |
|
||||
| Scenario A | `[golden] build-golden.sh v2.0.0 — baking controller …0.98.3`; vzdump log: mp0 AND mp1 **included**; guest 9100 destroyed |
|
||||
| Scenario B | before: `ConditionPathExists … not met` + path `active (waiting)`; after mp9 hot-plug: service SUCCESS @ +1 s, container `Up (healthy)` 0.98.3, boot time unchanged |
|
||||
| Scenario C | `[SKIP] using local golden: …18_01_21.tar.zst` (resolution order); first boot 0.98.3; `update_available:false`; hub rows agent 0.63.0 / controller 0.98.3; bentopdf 200 |
|
||||
| Publish | pre-delete 404 → PUT **201** → round-trip GET sha **matches** |
|
||||
| Scenario D | `fetching golden v0.98.3 from Gitea` → `verified sha256 b9a02ef1… matches the hub manifest` → SUCCESS; first boot 0.98.3; up-to-date |
|
||||
| Cleanup | all 8 drill-1 hub tables at count **0**, demo-felhom + peti-felhom intact; drill VM reverted to `virgin` (kept); bake cred file removed |
|
||||
| Image (both tags RESOLVE) | wget | curl | node | python3 | Family chosen |
|
||||
|---|---|---|---|---|---|
|
||||
| `codewithcj/sparkyfitness:v0.17.2` (nginx SPA) | /usr/bin/wget | /usr/bin/curl | no | no | BusyBox-wget `--spider :80/` (kept — most common family) |
|
||||
| `codewithcj/sparkyfitness_server:v0.17.2` (Node) | /usr/bin/wget | /usr/bin/curl | /usr/local/bin/node v24.17.0 | no | node-exec HTTP GET `:3010/api/health` status<400 (real status check, kept) |
|
||||
|
||||
Secrets: registry read-cred via 0600 env file only; the bake script's in-guest
|
||||
`docker logout + rm /root/.docker/config.json` line is present and ran before archiving; publish
|
||||
used the build server's out-of-band Gitea admin credential; nothing committed.
|
||||
`/api/health` existence proven live: `{"status":"UP"}`. `mem_limit` arithmetic verified:
|
||||
512 (db) + 1024 (server) + 256 (frontend) = **1792M** = the `.felhom.yml` value (comment added).
|
||||
|
||||
## Observations / operator follow-ups
|
||||
## Live validation (method stated per claim)
|
||||
|
||||
1. **SECURITY:** the customer-config `git.token` (held by every customer box) is a Gitea **admin**
|
||||
token with **package-WRITE** — the bake proved it by successfully publishing with it. The
|
||||
manifest-sha chain protects installs from tampered artifacts, but the capability shouldn't exist
|
||||
customer-side: issue a scoped read-only account/token + rotate.
|
||||
2. `build-golden.sh`'s publish block auto-fires whenever `REGISTRY_*` is set (needed for the pull
|
||||
too) → it published BEFORE Scenario C; deleted (204) and re-published after the gate. Candidate
|
||||
cleanup: a `GOLDEN_PUBLISH=1` opt-in flag.
|
||||
3. The installer's post-provision reboot is now redundant (path unit wins first) — candidate
|
||||
removal in a future installer version; kept per the task rules.
|
||||
4. Recommended: raise the global controller floor to 0.98.3 (UI, 1 min) for drift protection.
|
||||
5. Drill-environment note: launching the drill VM with `dhcpstart=10.0.2.30` (+ explicit
|
||||
`hostfwd…-10.0.2.15:22`) eliminates the prior drill's slirp DHCP/IP-collision quirk — worth
|
||||
using in every future drill.
|
||||
SparkyFitness was ALREADY deployed on demo from the draft (4 h prior, three containers healthy) —
|
||||
so the live action was applying the FINALIZED template: "Sablonok frissítése" then the card's
|
||||
"Frissítés", both clicked in the real dashboard via the browser bridge (claude-in-chrome).
|
||||
Compose recreated only the renamed frontend (`sparkyfitness`, healthy in 21 s); server + db
|
||||
untouched (Up 4 h) → the two `data_key` secrets were NOT regenerated, as required. Verifications:
|
||||
git-sync file content, `docker ps`, `/api/health`, traefik Host-header curl (200), and
|
||||
`GET /api/stacks/sparkyfitness` (the endpoint the UI polls) — controller probe verdict
|
||||
`healthy: true, http :80/ → 200 (6ms)` against the renamed container. Kept deployed (7.3 option A;
|
||||
expendable demo box, real catalog app).
|
||||
|
||||
## App-count reconciliation (recorded, NOT fixed)
|
||||
|
||||
Real catalog: **53** templates. Website `gyik.html` claims "több mint 45" (true but lagging);
|
||||
`alkalmazasok.html` per-category `app-count` spans sum **49** ≠ 53. Website fixes are
|
||||
`felhom-ui-design` + `site_gates.py` territory — separate task.
|
||||
|
||||
## Observations (not acted on)
|
||||
|
||||
- The controller UI card and `docker ps` agreed throughout; the probe's DEBUG-level per-stack log
|
||||
lines are invisible at INFO — the `GET /api/stacks/<name>` endpoint is the reliable verdict
|
||||
source for validation.
|
||||
- `paperless-ngx`'s containers (`paperless-webserver`…) match NEITHER the exact-name nor the
|
||||
prefix fallback of its stack name `paperless-ngx` — its controller-side probe likely never runs
|
||||
(silently "skipped no container"). Candidate follow-up: rename or add a probe-container hint;
|
||||
NOT touched here.
|
||||
- The pre-rename fallback DID probe the right container on demo (probe was green before the
|
||||
update) — the rename converts order-dependent luck into the deterministic convention.
|
||||
|
||||
Reference in New Issue
Block a user