# Removing the boot-time notification banners from the macOS golden base

Every clone boots with three persistent **alert-style** banners in the top-right,
over the screenshotted desktop:

| Banner | Real source | Notes |
|---|---|---|
| **Data Access Blocked** — "NucleicVMAgent tried to access your data from other apps and was blocked" | `NucleicVMAgent` lacks **Full Disk Access**; TCC blocks it and posts this | The default computer-use path is host-side, so this is cosmetic *unless* you use the in-guest native/ax path — but the block fires every time the agent runs. |
| **Multiple Extensions Added** — "Xcode-beta added multiple extensions" | Background Task Management (`com.apple.BTMNotificationAgent`) | BTM already records Xcode-beta as `notified`, so it will **not** re-post — see "replay" below. |
| **Tips** — "Learn how to take a screenshot" | Tips (`com.apple.tips` / `tipsd`) | `tipsd` runs and the Tips window auto-launches despite the Phase 5¾ `launchctl disable`. |

## Two things must be true — and the constraints are tight

This was verified on a live macOS 27 clone of the current base:

- **SIP is ENABLED** in the sealed base, and it is **not MDM-enrolled** (no
  configuration profiles). That rules out three whole families of fix:
  - `TCC.db` cannot be read or written from any shell (not even root) → no
    scripted Full Disk Access grant, no scripted per-app notification toggle.
  - PPPC (`com.apple.TCC…`) and `com.apple.notificationsettings` **profiles are
    only honored via MDM** — a manually-installed `.mobileconfig` is ignored.
  - The DND assertion store and the delivered-notification store are
    TCC-protected from the shell.
- **The banners are REPLAYED from the base snapshot, not regenerated each boot.**
  BTM already marks the extensions `notified` (it won't post again), yet the
  banner appears on every clone — so the base was **sealed with these alerts
  still on screen (undismissed)**, and every clone inherits that screen state.
  `killall NotificationCenter`/`usernoted` do not clear persistent alerts (the
  UI just relaunches and re-draws them), which is why the existing timer fails.

## Do NOT use a blanket suppressor (DND / notifications-off)

A tester may be exercising an app's own notifications, so the fix must be
**surgical — kill only these three sources and leave the notification framework
fully working.** That rules out Do Not Disturb and any global "notifications
off": DND is verified to suppress *new* notifications, so it would also swallow
the banners a developer is trying to see.

**It also means the existing `killall NotificationCenter` LaunchAgent (Phase
5⅞+) must be removed** — beyond being ineffective against these persistent
alerts, its 60-second sweep would dismiss an app-under-test's intended
notifications. It is actively wrong for the notification-testing use case.

## The fix: surgical, at base-build time, captured in the snapshot

Because SIP blocks scripting the relevant stores, the durable fix is a small set
of **targeted settings applied once while building the golden base** — each
scoped to a single source, each captured in the sealed snapshot, none touching
the notification framework as a whole:

1. **NucleicVMAgent → Full Disk Access.** Removes *Data Access Blocked* at the
   source and unblocks the agent's native path. Only affects the agent.
2. **Tips → notifications off** (and actually stop `tipsd`). Removes *Tips*.
   Per-app; every other app still notifies normally.
3. **Seal the base clean.** Dismiss any remaining on-screen alert before the
   final shutdown (Notification Center ▸ Clear All). BTM won't re-post the
   extensions banner once it's dismissed, so the clones stay clean.
4. **Remove the `killall NotificationCenter` LaunchAgent** (Phase 5⅞+).

How you apply 1–2 depends on how you build the base — pick one lane:

### Lane A — build with SIP off (matches the script's existing TCC path)
The provisioner already writes the agent's other TCC grants via `sqlite3` when
SIP is disabled (Phase 7c/7d). In that same window:
- **FDA:** add `kTCCServiceSystemPolicyAllFiles` for the agent bundle to the
  Phase 7d grant loop — one extra service, keyed by
  `xyz.blakeslee.nucleic.vmagent` with the app's designated requirement.
- **Tips:** the per-app notification flag lives in `~/Library/Preferences/com.apple.ncprefs.plist`
  (user domain, not SIP-protected) — settable while building, but the format is
  opaque; the reliable path is the GUI toggle in Lane B, done once and snapshotted.

### Lane B — SIP stays on (this base today): GUI toggles during the build
The base build already drives a GUI session, and GUI settings persist into the
snapshot. Do these once, before sealing:
- **FDA:** System Settings ▸ Privacy & Security ▸ **Full Disk Access** ▸ add
  `NucleicVMAgent`.
- **Tips:** System Settings ▸ Notifications ▸ **Tips** ▸ turn **Allow
  Notifications** off.
- Then Notification Center ▸ **Clear All**, and shut down to seal.

### Lane C — adopt MDM
If the base is ever MDM-enrolled, the two profiles in this directory are the
clean declarative form of 1–2 (they are per-app / agent-scoped, i.e. **not** a
blanket suppressor):
- `nucleic-vmagent-fda.mobileconfig` — Full Disk Access for the agent.
- `nucleic-suppress-notifications.mobileconfig` — disables notifications for
  `com.apple.tips` and `com.apple.BTMNotificationAgent` only.

Both validate with `plutil -lint`. They are inert without MDM.

## Summary

- Root-cause each source (FDA for the agent; Tips off); **do not** blanket-suppress.
- Seal the base with the alerts dismissed — that is what actually stops the
  per-boot replay.
- Delete the `killall NotificationCenter` timer; it is ineffective here and
  harmful to the notification-testing use case.
- Lane A (SIP-off build) makes FDA scriptable; Lane B (GUI, SIP-on) works on the
  current base; Lane C (MDM) uses the profiles here.
