# NutriCoach v1.4.0 Todo 3 consolidation checkpoint

## Current boundary

- Todo remains `Implement append-only day-status sidecar` in progress.
- Product edits are paused after three substantive integrity review failures.
- No commit, push, PR, merge, tag, release, live config/service/provider,
  customer, or network action occurred.

## Passing behavior

- Domain, filesystem-boundary, and store modules remain below 250 pure LOC.
- Focused sidecar suites: 32 passed.
- Existing canonical event/store regressions: 49 passed.
- LSP, ruff, ty, basedpyright, compileall, and no-excuse passed.
- Append/replay/reopen, mode 0600, fsync, hash chain, legal late transition,
  correction-stable timeliness, torn-tail repair, interior corruption,
  concurrency, and old-reader coexistence passed.
- Symlink/hardlink/non-regular/mode/owner/link-count/path identity cases fail
  closed.
- Canonical sequence reversal and same-sequence digest disagreement fail.
- Forged logical keys fail even when row digests are recomputed.

## Three substantive review failures

### Review 1 - direct filesystem and domain boundaries

- Symlinked plans parent wrote outside customer root.
- Hard-linked sidecar was accepted.
- Canonical sequence reversal was accepted.
- Rehashed arbitrary logical key was accepted.
- r2 repaired all four.

### Review 2 - ancestor attachment before mutation

- After descriptors were acquired, an ancestor was renamed and the configured
  path recreated.
- Append wrote into the detached renamed tree.
- r3 added stable-anchor component descriptors and attachment revalidation.

### Review 3 - rename after final check

- Barrier paused immediately before `os.write`.
- After the last attachment revalidation, a level-two ancestor was renamed and
  recreated.
- Append returned `appended=true`; detached sidecar gained the row and the
  replacement configured namespace remained empty.

## Root constraint

On POSIX, holding an open directory/file descriptor does not prevent another
process from renaming an ancestor. A final name/descriptor check followed by
`write` always has a scheduling point between check and mutation. Advisory
locks do not stop an uncooperative rename.

The current requested invariant — reject before *any* mutation when an
arbitrary external process renames an ancestor after the final check but before
`write` — cannot be guaranteed by another check alone.

## Decision options

### A - descriptor-stable commit semantics

Once the full chain is validated and the sidecar lock is held, the open inode
is the authority for that append. If namespace drift is detected after append,
record `committed_with_namespace_drift` and require reconciliation; never
pretend the append failed or retry it.

- Smallest change.
- Preserves append-only/exactly-once truth.
- The configured path may temporarily not expose the committed row.

### B - stable profile-owned authority root (recommended)

Move v1.4 sidecars out of mutable customer subtrees into a dedicated
profile-owned authority directory keyed by opaque customer ID. The configured
customer path becomes an input identity, not the storage namespace.

- Removes customer-tree ancestor rename from the commit path.
- Better matches authority/ledger storage.
- Requires a broader Todo 3 storage-path change plus migration/retention
  inventory updates, while canonical events remain untouched.

### C - cooperative namespace lock

Require every legitimate customer-tree renamer to acquire the same stable
profile-level lock before rename.

- Smaller product change than B.
- Cannot protect against uncooperative/external renames; the strict verifier
  must test cooperative behavior only.

No further product work should occur until A, B, or C is selected.
