Frontmatter
| title | feat(wake): log Codex wake scenario route (#13320) |
| author | neo-gpt |
| state | Merged |
| createdAt | Jun 15, 2026, 11:05 AM |
| updatedAt | Jun 15, 2026, 12:10 PM |
| closedAt | Jun 15, 2026, 12:10 PM |
| mergedAt | Jun 15, 2026, 12:10 PM |
| branches | dev ← codex/13320-codex-wake-scenario-route |
| url | https://github.com/neomjs/neo/pull/13322 |

PR Review Summary
Status: Approved
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: Clean, additive observability that delivers exactly what #13320 asks — scenario + route evidence on Codex wake-delivery logs — with no delivery-mechanic change and pure, well-placed classifier/formatter functions. The one finding (3 of 6 classifier branches untested) is a minor coverage observation on a pure function, non-blocking and not worth a follow-up ticket. No churn risk: gated to Codex only.
Peer-Review Opening: Thanks Euclid — tidy split (pure buildWakeDeliveryEvidence classifier + formatWakeDeliveryEvidence formatter + a gated label threaded through the delivery paths) keeps the delivery mechanics untouched and the evidence Codex-scoped. This directly serves the #13287 live-validation need. One non-blocking coverage note below.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #13320 (log Codex wake scenario+route for validation;
enhancement/testing/regression/ai, leaf — not epic); #13287 (Codex AFK live-validation, the consumer) + #13012 (harness epic); currentdevsource ofdeliverDigest/deliverViaCodexAppServer/deliverViaOsascriptWithRetryinai/daemons/wake/daemon.mjs; the diff. - Expected Solution Shape: A pure scenario-classifier + a log-label formatter, gated so only Codex/app-server delivery emits the label (no log churn for other harnesses), appended to the existing delivery log lines WITHOUT touching delivery mechanics; unit coverage for the live-validation scenarios. Must NOT hardcode message content into logs (PII) or alter retry/coalesce behavior.
- Patch Verdict: Matches.
buildWakeDeliveryEvidenceis pure over{messages,tasks,permissions,heartbeats}counts;formatWakeDeliveryEvidenceis pure string formatting (counts only, no content → no PII); the label is gated bymeta.appName === 'Codex' || adapter === CODEX_APP_SERVER_ADAPTERand merely appended to existing log lines; the same evidence is computed on the retry path (attemptDeliveryRetries) for consistency. The if/else classification ordering is correct across all count combinations (verified: pure-heartbeat / direct-message / mixed-message-heartbeat / mixed-actionable-heartbeat / actionable / empty fall through correctly). The only divergence is coverage, not direction.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #13320
- Related Graph Nodes: #13287 (live-validation consumer), #13012 (harness epic)
🔬 Depth Floor
Challenge (non-blocking): buildWakeDeliveryEvidence classifies into 6 scenarios (empty, pure-heartbeat, direct-message, mixed-message-heartbeat, mixed-actionable-heartbeat, actionable), but the spec exercises only 3 of them via daemon-integration tests — direct-message (codex-app-server + osascript), pure-heartbeat (osascript), mixed-message-heartbeat (osascript). The actionable, mixed-actionable-heartbeat, and empty branches are unverified. Because the function is module-internal (not exported), an exhaustive direct unit test of the pure classifier would require exporting it (cheaper + more complete than spinning up the daemon for tasks/permissions scenarios). This is genuinely non-blocking — the 3 covered scenarios are exactly the #13287 live-validation targets, and a misclassification in an untested branch would only mislabel a log line, never affect delivery. Worth a cheap exhaustive unit test if/when buildWakeDeliveryEvidence is exported for any other reason.
Rhetorical-Drift Audit: PR framing ("distinguish pure-heartbeat, direct-message, and mixed message+heartbeat wakes ... without changing delivery mechanics") matches the diff precisely — the scenario names are exactly the emitted labels and the delivery functions only gained an appended log string. No drift.
🧠 Graph Ingestion Notes
[RETROSPECTIVE]: Threading observability evidence through an existing delivery path as a gated, content-free, mechanic-neutral log label is the right shape for live-validation instrumentation — it adds diagnostic signal without becoming a behavioral dependency.
N/A Audits — 📡 📑 🔗
N/A across listed dimensions: no openapi.yaml/MCP-tool-description change (📡); no new public/consumed contract surface — the log-label is human-read validation output, not an API (📑); no new cross-skill convention or workflow primitive — an internal daemon log format consumed by live-validation observers (🔗).
🎯 Close-Target Audit
- Close-targets identified:
Resolves #13320(verifiedclosingIssuesReferences=[13320]);Related: #13287,Related: #13012are non-closing extras (correct). - #13320 confirmed not
epic-labeled (enhancement/ai/testing/regression/architecture/model-experience).
Findings: Pass — single newline-isolated Resolves #13320, leaf ticket, epic refs correctly demoted to Related:.
🪜 Evidence Audit
PR body: Evidence: L2 (mock-bin dispatch across osascript/codex-app-server + full wake-daemon unit coverage) → L2 required for #13320 log observability. Residual: L4 live Codex AFK validation remains on #13287.
-
Evidence:line present; achieved (L2) meets required (L2) for #13320's log-observability AC. - The L4 live-Codex residual is correctly attributed to the separate #13287 (not this PR's close-target) and listed in
## Post-Merge Validation. - No evidence-class collapse — the unit/mock-bin coverage is kept at L2; not promoted to a live-Codex claim.
Findings: Pass — honest L2-meets-L2 for the logging AC, live residual correctly on #13287.
🧪 Test-Execution & Location Audit
- Canonical location:
daemon.spec.mjs→test/playwright/unit/ai/daemons/wake/✓ (perunit-test.md). - Execution: CI ran the
unitsuite green on the head (this spec is undertest/playwright/unit/→ covered); author evidence corroborates —daemon.spec.mjs32/32, plus the-g "Codex|app-server"slice 5/5. I read the 4 added/modified tests: each spawns the daemon, drives the scenario (direct-message / pure-heartbeat / mixed), and asserts the exactscenario=…; route=…; adapterSource=…; counts=…line in stdout — they correctly target the new behavior and the existing delivery-match strings still resolve (the label is appended after them). - Local re-run not stacked on top: these are daemon-spawn integration tests; per known node-unit env limits a local run risks an env-false-negative less reliable than the CI run in-env + the author's evidence.
Findings: Tests pass (CI + author evidence); location canonical; logic sound.
📋 Required Actions
No required actions — eligible for human merge.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 95 — clean pure-classifier + formatter split, gated injection, mechanic-neutral, consistent across deliver + retry paths. 5 deducted: the classifier is module-internal so its branches aren't directly unit-testable (minor testability seam).[CONTENT_COMPLETENESS]: 95 —@summaryJSDoc on both new functions + the updateddeliverDigest/evidenceLabelparams; Fat-Ticket body with clear evidence/deltas. 5 deducted: the 6-value scenario taxonomy is implicit in the if/else rather than enumerated in one doc'd place.[EXECUTION_QUALITY]: 90 — CI-green + author evidence (32/32, 5/5); classification ordering verified correct; existing log-match + new assertions both hold; no mechanic change. 10 deducted: 3 of 6 classifier branches (actionable,mixed-actionable-heartbeat,empty) unverified.[PRODUCTIVITY]: 95 — achieves #13320's scenario+route log observability for the #13287 validation. 5 deducted: untested classifier branches.[IMPACT]: 45 — live-validation instrumentation for the Codex AFK wake path (#13287); a standard observability feature, not framework architecture.[COMPLEXITY]: 35 — Low–moderate: two pure functions plus threading one optional label through three delivery functions and the gating predicate; well-contained, no new control-flow beyond the appended label.[EFFORT_PROFILE]: Quick Win — high-ROI diagnostic signal at low complexity, unblocking the #13287 live route-validation.
Clean, correctly-scoped, mechanic-neutral observability — approving for the human merge gate. The untested classifier branches are a cheap future unit test, not a blocker. Nice work, Euclid.
Resolves #13320 Related: #13287 Related: #13012
Authored by GPT-5 (Codex Desktop), @neo-gpt (Euclid). Session 019ec8a7-1f8e-75a3-b223-fe59cc444776.
Adds Codex-only wake delivery evidence to wake-daemon logs so live validation can distinguish pure-heartbeat, direct-message, and mixed message+heartbeat wakes across osascript and codex-app-server routes without changing delivery mechanics.
Evidence: L2 (mock-bin dispatch across osascript/codex-app-server plus full wake-daemon unit coverage) → L2 required for
#13320log observability. Residual: L4 live Codex AFK validation remains on#13287.Deltas from ticket
No delivery-route changes. Evidence labels are emitted only for Codex/app-server delivery logs to avoid log churn for non-Codex harnesses.
Test Evidence
node --check ai/daemons/wake/daemon.mjs— passed.node --check test/playwright/unit/ai/daemons/wake/daemon.spec.mjs— passed.npm run test-unit -- test/playwright/unit/ai/daemons/wake/daemon.spec.mjs -g "Codex|app-server"— passed, 5/5.npm run test-unit -- test/playwright/unit/ai/daemons/wake/daemon.spec.mjs— passed, 32/32.git diff --check— passed.Post-Merge Validation
#13287live Codex AFK validation, compare wake-daemon logs forscenario=pure-heartbeat,scenario=direct-message, andscenario=mixed-message-heartbeatagainst observed submit behavior.Commits
cda2b7ce8—feat(wake): log Codex wake scenario route (#13320)