configs/whp-state.d/ -- plain directories shared between the two Go uids
(whp-panel and whp-jobs) through the group whp-state. Prep Task 6.

One file per area, named by the ledger area as written: <area>.list (e.g.
backups.list, sites-vhost.list). Each non-empty line that does not start
with '#':

    <absolute dir> <owner> <mode> <root-openers>

  <absolute dir>  canonical (no "..", ".", "//", trailing "/"), strictly below
                  one of the roots:
                      /var/lib/whp      (PHP's existing state root; e.g.
                                         /var/lib/whp/bulk-jobs)
                      /docker/backups
                  Never /var/lib/whp-state (it does not exist), never
                  /var/lib/whp-panel (its sql/shared/ is shared by
                  whp-stack-converge-go.sh itself, ruling P5; the rest of it
                  is the panel's alone).
  <owner>         root, whp-panel or whp-jobs
  <mode>          four octal digits with setgid and no "other" bits:
                  2770, 2750, 2700, 2710, ...
  <root-openers>  the contract (K3, prep Task 6 fix round 1). Either
                      none
                  -- no root process ever opens, creates, renames or unlinks
                  a name inside the directory -- or a comma list
                      nofollow:<opener>[,nofollow:<opener>...]
                  naming EVERY root process that does (a script path, a
                  privd op, a unit), each of which opens names there only
                  with O_NOFOLLOW and relative to a directory fd it opened
                  itself (openat/fsafe.OpenBeneath; never a path string
                  re-resolved later, never `cp`/`chmod`/`chown` by path).

A directory both uids can write is attacker-writable from either side
(T0 whp-panel, T3 whp-jobs). A root process that follows a planted symlink
or races a rename there is a root write primitive. If an operation cannot
meet the nofollow + fd-relative rule, it does not belong in a shared
directory: put it behind privd (the root side checks and opens), and list
the directory with "none".

Example:

    # backups: request files the panel drops for the scheduler
    /var/lib/whp/backups/requests whp-jobs 2770 nofollow:privd:backup.claim

scripts/ensure-whp-jobs.sh (run only by `whp-stack go`) creates each missing
directory (parents must already exist), then converges it to
<owner>:whp-state <mode>. It refuses -- and the switch aborts -- on a path
outside the roots, a symlink anywhere on the path, an existing ancestor below
the root that is not a root-owned, non-group/other-writable directory, an
existing leaf that is not a directory, a missing or malformed <root-openers>
field, or any other malformed line. The opener list is a declaration a
reviewer checks against the named code; the script cannot verify it. It never
removes a directory a list no longer names.

The units get no automatic access: whp-jobs@.service writes only its own
paths plus /var/lib/whp-panel/sql/shared. A lane that lists a directory adds the
ReadWritePaths= in its own drop-in, or flags prep.

Anything that is not a plain directory (spool ownership, lock files, secret
copies) is a converge hook instead: scripts/whp-stack-converge.d/README.
