docs+test(hierarchies): end-to-end review follow-ups (M5/M6/M7)

Findings from a 3-lens end-to-end review (correctness, security, tests).
Security review came back clean (cross-repo authz sound, isolation intact,
M5 gate sound modulo the documented manifest-trust boundary). No behavior
changes here — only accuracy + coverage:

- apply_service Phase B2: correct the descendant-expansion comment. The chain
  is COMMITTED ancestry (ancestors() reads the pool), so a reparent in the same
  apply takes effect next apply — same "one more apply" shape the in-tree path
  and group-create reparenting already have. Authz stays sound: the gate and the
  expansion consume the SAME chain (checked == written).
- doc §4.5: document the two known "one more apply / no data risk" limitations
  — reparent-in-same-apply template resolution, and the `{env}` source split
  (declared apps use --env; cross-repo descendants use apps.environment).
- approval journey: give the app real (`[vars]`) content so the editor member's
  AppVarsWrite is actually exercised — the admin-gate test now proves approval
  is ABOVE editor-write, not just "any non-admin is refused". (Vars cascade with
  the app; scripts are ON DELETE RESTRICT and would break AppGuard teardown.)
- templates journey: assert descendant expansions are idempotent (stable row
  ids on re-apply — no churn), matching the in-tree guarantee.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-28 19:57:21 +02:00
parent 22d6c33d0b
commit aa2831da90
4 changed files with 62 additions and 7 deletions

View File

@@ -413,6 +413,16 @@ Two distinct constraints:
> the template immediately, so var + template converge in one apply. A
> trigger template whose only change is a non-identity field (e.g. dispatch_mode) is a no-op on
> re-apply, mirroring the existing trigger-identity limitation (recreate to change those).
>
> **Known limitations (both "one more apply", no data risk):** (1) Template fan-out resolves against a
> node's **committed** ancestry — `apply` computes app chains before the transaction's structural
> reconcile — so a template gained or lost by a **reparent performed in the *same* apply** takes effect
> on the next apply (the same shape as "reparenting into a freshly-created group needs a second apply").
> (2) The `{env}` placeholder resolves to the apply's `--env` for **declared** apps but to the app's own
> `apps.environment` column for **cross-repo descendants**; if a template uses `{env}` and those two
> disagree, that descendant's expansion can churn between applies (and a descendant with a NULL
> `environment` + an `{env}` template aborts the apply, naming the app). Set the descendant's environment,
> or avoid `{env}` in templates fanned across heterogeneous-env subtrees.
### 4.6 Secrets & `pull`