feat: add Agent Attention playground experiment - #1
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThe PR adds the Agent Attention approval-gate experiment, including a Python CLI, Codex Stop hook, Apple Reminders integration, macOS URL handler, tests, and documentation. It also renames plugin metadata and resets release metadata for version ChangesAgent Attention experiment and plugin rebrand
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Agent
participant CLI as agent-attention.py
participant Reminders as Apple Reminders
participant StopHook as Codex Stop hook
participant Codex
Agent->>CLI: submit approval intent
CLI->>Reminders: create and verify approval reminder
Reminders-->>CLI: report completed approval
CLI->>CLI: record delivery and terminal outcome
Codex->>StopHook: send Stop payload
StopHook->>CLI: check_stop(session_id)
CLI-->>StopHook: return allow or continue
StopHook-->>Codex: emit stop decision
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (8)
experiments/agent-attention/skill/SKILL.md (1)
27-28: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueName the outcome command explicitly.
Steps 1 through 3 name
submitdirectly. Step 6 says "the owner's outcome command" instead. Namerecord-outcomeso the agent does not need to rediscover it, and state that it previews by default.♻️ Proposed wording
6. After exact-task delivery, apply only the stated approval meaning, run the - continuation, then use the owner’s outcome command. + continuation, then preview `record-outcome` and rerun it with `--execute`.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@experiments/agent-attention/skill/SKILL.md` around lines 27 - 28, Update step 6 in the skill instructions to explicitly name the owner’s outcome command as record-outcome, and state that it previews by default while preserving the existing sequence and approval meaning.experiments/agent-attention/runtime/agent-attention/test_agent_attention.py (1)
154-155: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMake the fake
remindctlfail on unknown subcommands.The
elsebranch answers every unrecognized subcommand with thedoctorauthorization payload. If the runtime ever calls a wrong or renamed subcommand, the fake still returns parseable JSON and the test passes. That hides the regression.Match
doctorexplicitly and exit non-zero for anything else.💚 Proposed fix
-else: - print(json.dumps({"authorization": {"authorized": True}})) +elif args[0] == "doctor": + print(json.dumps({"authorization": {"authorized": True}})) +else: + print("unsupported remindctl subcommand: " + args[0], file=sys.stderr) + raise SystemExit(2)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@experiments/agent-attention/runtime/agent-attention/test_agent_attention.py` around lines 154 - 155, Update the fake remindctl command handler around the existing else branch to match the doctor subcommand explicitly and return its authorization JSON only for that command. For every other unrecognized subcommand, exit with a non-zero status instead of emitting a successful payload.experiments/agent-attention/runtime/agent-attention/install-link-handler.sh (1)
9-16: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a preflight check for
swiftcandlsregister.The script depends on
swiftc, which ships with Xcode or the Command Line Tools, and onlsregisterat the hard-coded path in Line 9. If either is absent,set -eaborts with a raw shell or compiler error. Every other command in this experiment returns one structured JSON result, so the failure mode here is inconsistent and harder to act on.Check both before you build.
♻️ Proposed change
+if ! command -v swiftc >/dev/null 2>&1; then + printf '{"status":"error","repair":"install Xcode Command Line Tools to provide swiftc"}\n' >&2 + exit 1 +fi +if [[ ! -x "$register_bin" ]]; then + printf '{"status":"error","repair":"lsregister is not available at the expected LaunchServices path"}\n' >&2 + exit 1 +fi + mkdir -p "$macos_dir"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@experiments/agent-attention/runtime/agent-attention/install-link-handler.sh` around lines 9 - 16, Add a preflight validation before the build commands in install-link-handler.sh: verify that swiftc is available and that the register_bin path for lsregister exists and is executable. If either dependency is missing, emit the script’s structured JSON failure result and exit before mkdir, compilation, or registration; preserve the existing successful installation output.experiments/agent-attention/runtime/agent-attention/agent-attention.py (3)
55-66: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winConsider a temp-file plus rename write for state durability.
write_jsonopens the target withO_TRUNCand writes in place. If the process stops between truncation and the final write, the state file stays truncated and laterload_jsoncalls fail on invalid JSON. Gate custody state (requests/,gates/,receipts/) then needs manual repair.The exclusive-create path must stay as is, because it provides the claim semantics. Only the non-exclusive path needs the rename.
♻️ Proposed durable write for the non-exclusive path
def write_json(path: Path, value: Any, *, exclusive: bool = False) -> bool: """Write private JSON atomically enough for single-host gate custody.""" path.parent.mkdir(parents=True, exist_ok=True, mode=0o700) - flags = os.O_WRONLY | os.O_CREAT | (os.O_EXCL if exclusive else os.O_TRUNC) - try: - descriptor = os.open(path, flags, 0o600) - except FileExistsError: - return False - with os.fdopen(descriptor, "w", encoding="utf-8") as handle: - json.dump(value, handle, sort_keys=True) - handle.write("\n") - return True + if exclusive: + try: + descriptor = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) + except FileExistsError: + return False + with os.fdopen(descriptor, "w", encoding="utf-8") as handle: + json.dump(value, handle, sort_keys=True) + handle.write("\n") + return True + temporary = path.with_name(f"{path.name}.{os.getpid()}.tmp") + descriptor = os.open(temporary, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) + with os.fdopen(descriptor, "w", encoding="utf-8") as handle: + json.dump(value, handle, sort_keys=True) + handle.write("\n") + handle.flush() + os.fsync(handle.fileno()) + os.replace(temporary, path) + return True🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@experiments/agent-attention/runtime/agent-attention/agent-attention.py` around lines 55 - 66, Update write_json so only non-exclusive writes use a uniquely named temporary file in the target directory, write and close the JSON there, then atomically replace the target via rename. Preserve the existing O_EXCL creation path and its FileExistsError behavior unchanged, and clean up temporary files when non-exclusive writes fail.
1004-1008: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReuse
append_audithere.
append_auditat Line 69 already performs the same directory creation, append, andchmodsequence.record_outcomecalls it at Line 780 and Line 839. Use it here so one function owns audit file permissions.♻️ Proposed refactor
- log_path = state_dir / "audit.jsonl" - log_path.parent.mkdir(parents=True, exist_ok=True, mode=0o700) - with log_path.open("a", encoding="utf-8") as handle: - handle.write(json.dumps(receipt, sort_keys=True) + "\n") - os.chmod(log_path, 0o600) + append_audit(state_dir / "audit.jsonl", receipt)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@experiments/agent-attention/runtime/agent-attention/agent-attention.py` around lines 1004 - 1008, Update record_outcome to call the existing append_audit helper instead of manually creating the audit directory, appending JSON, and changing permissions. Pass the existing log_path and receipt values so append_audit remains the single owner of audit file handling and permissions.
148-158: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemove the unused
gate_noteshelper. No repository call site references it.submit_approvalusesrouter_notesinstead. Keep it only if external callers rely on it.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@experiments/agent-attention/runtime/agent-attention/agent-attention.py` around lines 148 - 158, Remove the unused gate_notes helper and its associated formatting logic. Keep submit_approval and its router_notes flow unchanged, unless repository-wide evidence shows external callers depend on gate_notes.experiments/agent-attention/hooks/agent-attention-codex-stop.test.ts (1)
100-115: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueThis test requires
python3onPATH.The test calls
handleAgentAttentionStopwithout a runtime, so it usescreateDefaultRuntimeand spawnspython3.handleAgentAttentionStopdoes not catch owner errors; onlyrunAgentAttentionStopdoes. Ifpython3is absent, the test fails with a spawn error rather than a clear message about the missing dependency.State the dependency in the test name, or assert the failure mode explicitly so the cause is obvious.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@experiments/agent-attention/hooks/agent-attention-codex-stop.test.ts` around lines 100 - 115, Update the test name around handleAgentAttentionStop to explicitly state that it requires python3 on PATH, or change the test to assert the expected missing-dependency failure. Ensure the test clearly communicates the runtime dependency instead of allowing an unhandled spawn error to obscure the cause.experiments/agent-attention/hooks/agent-attention-codex-stop.ts (1)
134-142: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winAdd a spawn-level timeout to the owner check.
Set
timeoutto5000milliseconds. This is below the Codex hook timeout of 10 seconds and keeps a hungpython3process inside the adapter, whererunAgentAttentionStopcan return a block response.♻️ Proposed change
const process = Bun.spawn( ['python3', owner, 'check-stop', '--thread-id', threadId], - { stdout: 'pipe', stderr: 'pipe' }, + { stdout: 'pipe', stderr: 'pipe', timeout: 5000 }, )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@experiments/agent-attention/hooks/agent-attention-codex-stop.ts` around lines 134 - 142, Update the Bun.spawn options in the owner-check flow of runAgentAttentionStop to include a 5000-millisecond timeout, ensuring a hung python3 process terminates within the adapter while preserving the existing stdout, stderr, and exit-code handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@experiments/agent-attention/runtime/agent-attention/agent-attention.py`:
- Around line 868-886: Update the mapping-processing loop around event_id and
the reminder validation checks so an unresolved, mismatched-title, or
missing-required-notes reminder records repair state for that mapping, includes
its reminder ID in the error details, and continues to the next mapping instead
of raising out of the poll. Preserve the refusal to infer approval and the
existing handling for completed reminders.
- Around line 350-392: Update submit_approval so all paths that do not leave a
live gate release request_lock_path. Wrap the request-processing body after
exclusive lock creation in try/finally, unlinking the lock in finally; remove
the existing success/idempotent-path unlink calls so cleanup is centralized and
also covers request-claim collisions and every ContractError.
- Around line 637-648: Validate reminder_id at the start of read_gate_mapping
before constructing the gates path, reusing the existing validate_event_id shape
check used by record_delivery. Reject invalid or path-like IDs while preserving
normal mapping loading and validation for valid IDs, including the downstream
remindctl edit flow.
- Around line 1081-1101: Update the doctor flow around run_json to pass an
appropriate timeout_seconds value when invoking remindctl doctor. Validate that
reminders is a dictionary before accessing it; for any other JSON shape, raise
the established ContractError so main emits a structured result instead of a
traceback. Use the validated reminders["authorization"]["authorized"] value when
computing ready, preserving the existing config and handler checks.
In `@experiments/agent-attention/runtime/agent-attention/test_agent_attention.py`:
- Around line 663-675: Adjust the elapsed-time assertion in
test_watch_bounds_a_hung_remindctl_call so it remains clearly below the
configured 2-second fake remindctl hang while allowing additional subprocess
startup and teardown time. Keep the existing return-code and
bounded-execution-window assertions unchanged.
- Line 305: Update the read-only preview assertion in the relevant test method
to reload the inventory from self.inventory_path after the CLI subprocess
completes, then assert that the persisted target notes do not contain
"Outcome:". Do not assert against self.target, since the subprocess cannot
mutate that in-memory fixture.
---
Nitpick comments:
In `@experiments/agent-attention/hooks/agent-attention-codex-stop.test.ts`:
- Around line 100-115: Update the test name around handleAgentAttentionStop to
explicitly state that it requires python3 on PATH, or change the test to assert
the expected missing-dependency failure. Ensure the test clearly communicates
the runtime dependency instead of allowing an unhandled spawn error to obscure
the cause.
In `@experiments/agent-attention/hooks/agent-attention-codex-stop.ts`:
- Around line 134-142: Update the Bun.spawn options in the owner-check flow of
runAgentAttentionStop to include a 5000-millisecond timeout, ensuring a hung
python3 process terminates within the adapter while preserving the existing
stdout, stderr, and exit-code handling.
In `@experiments/agent-attention/runtime/agent-attention/agent-attention.py`:
- Around line 55-66: Update write_json so only non-exclusive writes use a
uniquely named temporary file in the target directory, write and close the JSON
there, then atomically replace the target via rename. Preserve the existing
O_EXCL creation path and its FileExistsError behavior unchanged, and clean up
temporary files when non-exclusive writes fail.
- Around line 1004-1008: Update record_outcome to call the existing append_audit
helper instead of manually creating the audit directory, appending JSON, and
changing permissions. Pass the existing log_path and receipt values so
append_audit remains the single owner of audit file handling and permissions.
- Around line 148-158: Remove the unused gate_notes helper and its associated
formatting logic. Keep submit_approval and its router_notes flow unchanged,
unless repository-wide evidence shows external callers depend on gate_notes.
In `@experiments/agent-attention/runtime/agent-attention/install-link-handler.sh`:
- Around line 9-16: Add a preflight validation before the build commands in
install-link-handler.sh: verify that swiftc is available and that the
register_bin path for lsregister exists and is executable. If either dependency
is missing, emit the script’s structured JSON failure result and exit before
mkdir, compilation, or registration; preserve the existing successful
installation output.
In `@experiments/agent-attention/runtime/agent-attention/test_agent_attention.py`:
- Around line 154-155: Update the fake remindctl command handler around the
existing else branch to match the doctor subcommand explicitly and return its
authorization JSON only for that command. For every other unrecognized
subcommand, exit with a non-zero status instead of emitting a successful
payload.
In `@experiments/agent-attention/skill/SKILL.md`:
- Around line 27-28: Update step 6 in the skill instructions to explicitly name
the owner’s outcome command as record-outcome, and state that it previews by
default while preserving the existing sequence and approval meaning.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 70f14b62-b58a-43bc-93aa-9566a53ff98c
⛔ Files ignored due to path filters (1)
plugin/hooks/fixture/lifecycle-mechanics-proof.generated.jsonis excluded by!**/*.generated.*
📒 Files selected for processing (24)
.agents/plugins/marketplace.json.claude-plugin/marketplace.json.github/.release-please-manifest.json.github/release-please-config.jsonCHANGELOG.mdexperiments/agent-attention/README.mdexperiments/agent-attention/hooks/agent-attention-codex-stop.test.tsexperiments/agent-attention/hooks/agent-attention-codex-stop.tsexperiments/agent-attention/hooks/codex-hooks.fixture.jsonexperiments/agent-attention/runtime/agent-attention/README.mdexperiments/agent-attention/runtime/agent-attention/agent-attention.pyexperiments/agent-attention/runtime/agent-attention/install-link-handler.shexperiments/agent-attention/runtime/agent-attention/link-handler/Info.plistexperiments/agent-attention/runtime/agent-attention/link-handler/main.swiftexperiments/agent-attention/runtime/agent-attention/test_agent_attention.pyexperiments/agent-attention/skill/SKILL.mdpackage.jsonplugin.config.jsonplugin/.claude-plugin/plugin.jsonplugin/.codex-plugin/plugin.jsonplugin/hooks/fixture/lifecycle-mechanics-proof.source.jsonscripts/native-capability-hook.test.tsscripts/native-capability-surface.test.tsscripts/prove-harness-install.test.ts
💤 Files with no reviewable changes (1)
- CHANGELOG.md
|
@codex review |
|
@codex review |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 17415f9add
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dd78ce2cab
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9abd4c252d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@coderabbitai review |
✅ Action performedReview finished.
|
- validate created reminder IDs before mapping writes - preserve structured repair state for invalid IDs
|
@codex review |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 55eb90484f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 13f44c9129
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8227ae4f47
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1ab89e92f9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a57e59de4c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5961d42366
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bd476c7e49
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| or state.get("thread_id") != mapping["thread_id"] | ||
| ): | ||
| return | ||
| write_json( |
There was a problem hiding this comment.
Serialize declared-state reconciliation
When two pollers reconcile a crash-left declared request, one can read declared here, pause while the other advances the request through gated and record-outcome writes completed, and then overwrite that terminal state with its stale gated snapshot. The fresh evidence beyond the earlier serialized-updater fix is that this reconciliation write bypasses update_request_state and the per-thread flock entirely; perform the status check and transition under the same locked, monotonic update path.
Useful? React with 👍 / 👎.
| descriptor = acquire_request_lock( | ||
| lock_path, | ||
| {"thread_id": mapping["thread_id"], "operation": "update-request-state"}, | ||
| blocking=True, |
There was a problem hiding this comment.
Keep the lock inode stable for blocking waiters
When an updater blocks here behind a held lock, it retains a descriptor for the current inode, but release_request_lock() unlinks that inode before unlocking it. A later updater can therefore create and lock a replacement file while the waiter acquires the now-unlinked old inode, allowing both request-state updates to run concurrently and reintroducing the completed-to-delivered regression this lock is intended to prevent. The fresh evidence beyond the earlier serialization fix is the new blocking use of the existing unlink-on-release lock; keep a persistent lock path or revalidate the inode after acquisition.
Useful? React with 👍 / 👎.
Outcome
Move the proven Agent Attention source, thin skill, native adapter, and focused tests into the private v0.3-derived plugin playground as its first active experiment.
Boundaries
plugin/payload.Proof
bun run generate:check: passed.bun run build: passed.bun run release:validate: passed.bun run prove:all: passed at9d564faa6ab404253cf13703698a909a680ea7e2.Deferred
Plugin activation, installation, release, live Reminders smoke, and persistent 15-second background qualification remain separate approval-gated units.
Summary by CodeRabbit