Scope to the change set. If none was named, default to the load-bearing surfaces:
Skim, don't deep-read — the goal is to spot bugs, not summarize files.
-
Manifest validation gaps. createHost Phase-1 catches conflicts before any plugin code runs. For every new contribution type added: is the cross-plugin uniqueness check actually present in createHost.ts? A missing check means two plugins can silently overlap (same SQL name, same server action qualified name, same audit channel) and the second write wins at runtime.
-
Activation-order edges. computeActivationOrder uses consumes (hard edge) but NOT contributesTo (per D-0014, intentional). When a plugin both consumes an ApiRef and contributes to that owner's ExtensionPoint, the owner sees partial contributions during its own activate(). Any plugin that reads extensionPointRegistry.consume(...) during activate() is a candidate for silent partial-set bugs. Check that owners that need the FULL set defer the consume to post-activation, or read host.extensionPointRegistry directly.
-
Floor enforcement coverage. merger.ts walks scalars, objects, AND keyed-list items (D-0012). D-0016 closed the floor-inside-nested-object gap. Hunt for: floor on a list field (does the strategy honor it?), floor on a union-strategy list item, floor on a field nested deeper than two levels. Are tests asserting the floor wins, or only that the value MATCHES — a no-op test passes if floor never fired.
-
Mutator atomicity. mutator.apply(ops, author) must be all-or-nothing across ops. If op #3 of 5 fails floor validation, ops #1 and #2 must NOT be persisted. Look for for (const op of ops) { source.write(...) } shapes — that's the broken pattern.
-
HMR singleton leaks. apps/host/src/boot.ts pins on globalThis.__pluginHost. Any module-scope let cached: T | undefined in runtime code that holds a pool, watcher, file handle, or websocket leaks across HMR. Search the codebase for let .* = undefined at module top and confirm globalThis or no-resource-holding.
-
Server-action input validation. Every ServerAction.validateInput runs BEFORE the handler. Does it actually narrow the type (raw: unknown → I), or does it cast (return raw as I)? Cast-only validators let through any shape and crash inside the handler.
-
Auditor declared-emitter enforcement. Auditor.declareEmitters(pluginId, [...]) builds a per-plugin allowlist. Plugins that declare nothing get LENIENT mode (any eventId works). Is that intentional? In production it should probably be strict for known plugins.
-
Audit transactional pairing. When (in Phase 8+) the writer is DB-backed, the auditor's begin+success pair MUST land in the same transaction as the data write. Otherwise a crashed write leaves a success record claiming a write that never happened. Phase 7.4's InMemoryAuditWriter doesn't have this risk, but the Phase-8 wire-up does.
-
State-machine actor leaks. xstate actors started via stateMachineRegistry.create() keep running until the caller stops them. A server action that creates an actor and forgets it leaks a closure per request. Look for registry.create(...) without a matching actor.stop() (or an explicit "actors are ephemeral per call, GC handles it" comment).
-
Realtime subscriber error isolation. RealtimeBus.publish catches per-subscriber errors and returns them in result.errors. If the caller doesn't read result.errors, error swallowing is invisible. Check every publish() call site — is the result inspected?
-
Plugin-scoped db query escape. ctx.db.tables exposes ONLY the calling plugin's tables. The phantom guard is "every plugin builds queries against ctx.db.tables, never imports tables from another package directly". The boundary test enforces this for sibling-plugin imports of apiRefs.ts / extensionPoints.ts, but does it cover tables.ts?
-
Op-apply path divergence. applyOp in @plugin/core is the canonical set/unset implementation. The host's AdminFormClient used to reimplement it locally (caught in 5.7a). Search for any new setAtPath / unsetAtPath style helper that bypasses applyOp.
-
Server-only boundary. Server components import from @plugin/runtime; client components must NOT. A client component pulling in @plugin/runtime exposes the host's Source (filesystem reads), the Mutator, and registry internals to the browser bundle. Look for "use client" files importing @plugin/runtime.
-
Snapshot drift. Every iteration commits a snapshot — JSON for contracts, JPEG for UI. If a phase change touches behavior but no snapshot changed, the snapshot is too loose (just type names, not values) or the iteration didn't actually capture the right surface.
Walk the list. Skip what doesn't apply. Add branches that fit the specific area touched.
Inline in the conversation, ~300–500 words. Group by severity. For each finding:
Do NOT propose fixes — just the bug. End with a one-sentence delta vs. the last red-team-plugin if one exists. Be terse. Be specific.
You are the main session — don't create scratch files. Output findings inline. End with a git status check; nothing new should be staged.