Files
PiCloud/crates
MechaCat02 8a559ea178 feat(apply): atomic project-tree apply with cross-node inherited binding (Phase 5 C3)
Phase 5 C3 — the headline. A whole project subtree (group + app nodes) is
reconciled in ONE Postgres transaction, all-or-nothing.

`POST /api/v1/admin/tree/{plan,apply}` take a `TreeBundle { nodes: [{kind,
slug, bundle}] }`. The actor must hold the relevant read/write caps for EVERY
node (per-kind, widened on prune) — `authz_tree` + reusable
`require_{app,group}_node_writes` (now shared with the single-node handlers).

Engine:
  * The in-tx reconcile body of `apply_owner` is extracted to `reconcile_node_tx`
    (returns the node's post-create `name → script_id`), so single-node and
    tree apply share one implementation — behaviour-preserving (391 unit tests
    + app journeys green).
  * `prepare_tree` resolves each slug→owner, validates (an app's route/trigger
    target may bind to an in-tree ancestor group's script), computes each
    node's plan, and folds a combined bound-plan token = every node's
    `state_token` + every in-scope group's `structure_version` (so a reparent
    or content edit between plan and apply trips StateMoved).
  * `apply_tree`: lock every node key (sorted, deadlock-free); reconcile GROUPS
    first, recording each group's `name → id` in an in-memory index; then APPS,
    resolving inherited route/trigger targets nearest-ancestor-wins across the
    in-tree index (incl. scripts created earlier in THIS tx, invisible to the
    pool resolver) and pre-existing out-of-tree ancestors. One commit, one
    post-commit route refresh.

Live-validated against the dev DB:
  * Headline: a group node creates `shared`; an app node in the SAME apply
    binds `GET /greet` to it — the route ends up bound to the group-owned
    script, and re-plan is all-noop (idempotent).
  * Atomicity: one invalid node → 422 and ZERO rows written (the valid group
    node's script is not created).

CLI tree discovery + `pic plan/apply` tree mode is C4; journeys + docs are C5.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 22:18:07 +02:00
..