catalog: the lifecycle implementation itself (fixes the previous commit)
The previous commit landed only the new test/badge files: a 'git stash' used to compare REUSE.md ref-check output silently dropped the staged index, so every modification to an existing file was left behind and that commit does not build. This adds the metadata field, the predicates, the fail-closed deploy gate, the catalog filter, the funcmap entries, the template edits and the docs that those tests exercise.
This commit is contained in:
@@ -1,5 +1,55 @@
|
||||
## Changelog
|
||||
|
||||
### v0.158.0 — apps get a lifecycle: available / hidden / abandoned (2026-07-21)
|
||||
|
||||
No agent coupling; MinAgent unchanged.
|
||||
|
||||
Until now the catalog knew only two states: a template is present, or it is gone. "Gone" is not a
|
||||
usable way to withdraw an app, because **it orphans every customer already running it** — their app
|
||||
gets flagged `Elavult` and offered a Törlés button, for software that works fine. That is what the
|
||||
short-lived `retired/` directory move (2026-07-21, same day) would have done, and it is why this
|
||||
replaces it.
|
||||
|
||||
`.felhom.yml` gains an optional top-level `lifecycle:`:
|
||||
|
||||
- **`available`** — the default. Absent or empty means this, so all 52 existing templates are
|
||||
unchanged.
|
||||
- **`hidden`** — not offered for new installs. Nothing is shown to anyone already running it; "we
|
||||
stopped offering this" is not their problem.
|
||||
- **`abandoned`** — not offered for new installs, AND every box already running it carries a
|
||||
permanent „Nem karbantartott" badge plus a notice on the app page: *„Az alkalmazás fejlesztője
|
||||
felhagyott a fejlesztéssel. A telepített verzió továbbra is használható, de frissítések és
|
||||
biztonsági javítások már nem érkeznek hozzá."*
|
||||
|
||||
**A deployed instance keeps full function in every state.** Lifecycle governs what is OFFERED, never
|
||||
what runs.
|
||||
|
||||
- **The deploy gate is server-side and fail-closed** (`api.deployStack`, before any mutation), with
|
||||
the ruled Hungarian refusal „Ez az alkalmazás jelenleg nem telepíthető." Hiding a button is not a
|
||||
gate — a stale link, a bookmarked deploy form or a direct POST must all be refused. A second check
|
||||
in `stacks.DeployStack` covers any future caller that does not route through the API.
|
||||
- **The unknown-value posture is fail-OPEN, deliberately, and it is the opposite of the gate's.** An
|
||||
unrecognised value degrades to `available` with one WARN. A typo — or a state added in a later
|
||||
catalog than this controller understands — must never silently pull a working app out of every
|
||||
customer's catalog. The gate that actually protects installation reads the same
|
||||
`EffectiveLifecycle`, so the two can never disagree.
|
||||
- **Orphan detection is untouched, and that is asserted.** Withdrawn templates stay in the catalog
|
||||
tree; `getCatalogTemplateSlugs` never looks at lifecycle. A red-proof adds that filter and shows
|
||||
the abandoned app immediately reading as an orphan.
|
||||
- **Badge plumbing is generic**: `MetaBadge` + the `meta_badge` partial + a `lifecycleBadge` funcmap
|
||||
entry. R-56's difficulty labels are meant to be a sibling funcmap function returning the same type
|
||||
— no new markup, no new CSS.
|
||||
- **plant-it returns to `templates/`** as the first `abandoned` app, so the mechanism is proven on
|
||||
the case that motivated it. Its compose is deliberately left as-is: the app is not installable, and
|
||||
rewriting it would imply it is.
|
||||
|
||||
**Red-proofs, all four run:** removing the API gate → the wiring test reports the gate INERT;
|
||||
dropping the `Deployed ||` clause from the catalog filter → a customer's running app vanishes from
|
||||
their own Alkalmazások page; removing the badge line → the abandoned app renders unmarked; making
|
||||
orphan detection lifecycle-aware → `catalog set = map[bookstack:true]`, the two withdrawn apps read
|
||||
as orphans. The wiring test walks the AST, not `strings.Contains`, because a commented-out call
|
||||
still contains the string; it also asserts the gate precedes `DeployStack`.
|
||||
|
||||
### v0.157.1 — anchor the `controller` .gitignore entry (2026-07-21)
|
||||
|
||||
Tooling only; no behaviour change, no rebuild needed.
|
||||
|
||||
Reference in New Issue
Block a user