feat(cli): pic triggers ls --group + group-template journeys + docs (§11 tail T4)
- apply_service: trigger_report(group) → TriggerTemplateInfo
(kind/target/script/enabled); resolve_inherited_targets_for(Group) now
surfaces the group's OWN endpoint scripts so a template's handler
validates (fixes "binds to unknown script" when the handler is a
pre-existing group script, not declared in the same manifest).
- apply_api: GET /groups/{id}/triggers (GroupScriptsRead).
- CLI: `pic triggers ls --group <g>` (--app/--group mutually exclusive)
+ the client method + DTO.
- tests/group_trigger_templates.rs (manager-core, live DB): the chain
union matches a descendant app's kv insert against the group template
and NOT a sibling subtree — the isolation boundary, deterministic.
- tests/group_triggers.rs (journey): apply a kv template, ls --group
shows it, re-apply NoOp, cron-on-group rejected.
- docs: design §4.5 (live-event-kinds decision + deferrals), CLAUDE.md.
Full journey suite 119/119; workspace tests 0 failures; clippy -D clean;
schema unchanged (blessed in T1).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -377,9 +377,25 @@ Two distinct constraints:
|
||||
|
||||
> **Ergonomic debt (accepted, watch it):** because triggers don't inherit, 100 tenant apps each
|
||||
> needing the same 5 triggers = 500 declarations. The fix is group trigger/route **templates** that
|
||||
> fan out per descendant (a *template/instantiation* mechanism, not inheritance) — deferred, but it
|
||||
> bites early if tenant cardinality is high. Pressure-test against real tenant counts before
|
||||
> committing to the narrow-inheritance choice (§5.1).
|
||||
> fan out per descendant — deferred, but it bites early if tenant cardinality is high. Pressure-test
|
||||
> against real tenant counts before committing to the narrow-inheritance choice (§5.1).
|
||||
>
|
||||
> **Shipped — group TRIGGER templates (live, event kinds).** Implemented as **live inheritance via the
|
||||
> ancestor-chain CTE**, not the materialized "instantiation" this note first sketched — consistent with
|
||||
> how vars/secrets/scripts/§11.6 collections all resolve. A `[group]` declares an EVENT trigger
|
||||
> (kv/docs/files/pubsub) binding a group-owned handler; `triggers` gained a polymorphic owner
|
||||
> (`0056_group_triggers.sql`, nullable `group_id`, mirrors `0050`), and the dispatcher's
|
||||
> `list_matching_kv/docs/files` + the pubsub publish fan-out prepend `CHAIN_LEVELS_CTE` and
|
||||
> `JOIN chain c ON (t.app_id = c.app_owner OR t.group_id = c.group_owner)` — so a descendant app's event
|
||||
> matches its own triggers **plus** ancestor-group templates in one query, the handler running under the
|
||||
> firing app's `app_id` (the Phase-4 boundary). **That walk is the isolation boundary**: a
|
||||
> sibling-subtree app never sees the template (pinned by `tests/group_trigger_templates.rs`). Authoring
|
||||
> is `[[triggers.kv]]` (etc.) on a `[group]`; read-only `pic triggers ls --group`. **Deferred:** the
|
||||
> **stateful** kinds (cron `last_fired_at`, queue advisory-lock, email sealed secret) need per-app rows
|
||||
> → materialization, rejected on a `[group]`; **route templates** (same live shape, but the in-memory
|
||||
> `RouteTable` would need inherited templates per app + new recompile-invalidation edges); per-app
|
||||
> opt-out / cross-owner dedup (a descendant re-declaring an identical trigger double-fires — "overlapping
|
||||
> triggers coexist").
|
||||
|
||||
### 4.6 Secrets & `pull`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user