Oracle Silent Drop

SPEC_ORACLE_SILENT_DROP.md · 2026-04-20

SPEC_ORACLE_SILENT_DROP — Oracle Silent-Drop Customer Notification

Version: 1.0 | Status: AUTHORIZED | Authority: α.13 | Date: 2026-04-16


PURPOSE

When a Stripe checkout.session.completed event arrives at /api/webhook with payment_status === "paid" but a missing or invalid query or tier field, the pipeline silently exits without processing. The customer has paid but receives nothing: no verdict, no email, no explanation. This is a silent drop.

This specification defines:

  1. Detection criteria — what constitutes a silent drop
  2. Customer notification — what the customer receives and when
  3. Resolution logic — refund trigger vs. re-attempt logic
  4. Crew alert broadcast — how the crew is notified

The silent-drop notification subsystem is a child component of the Oracle Verdict Pipeline (see SPEC_ORACLE_VERDICT_PIPELINE.md, GAP-05). It does not replace the main pipeline — it fires only when the main pipeline cannot proceed due to missing session data.


INPUTS

Primary trigger — Webhook silent-drop condition

Fires when ALL of the following are true:

  1. Stripe event type is checkout.session.completed
  2. session.payment_status === "paid" (customer's card was charged)
  3. At least one of:

- query resolves to empty string (both custom_fields[key="idea"].text.value and metadata.q0…qn are absent or blank)

- tier resolves to empty string (session.metadata.tier absent or blank)

- tier is present but not a member of { "quick", "full", "strategy" } (invalid tier key)

Code location: /home/nous/Aether/app/app/api/webhook/route.ts lines 205–208:


if (!query || !tier || !VERDICT_PROMPT[tier]) {
  console.error("Webhook: missing query or tier in session", sessionId);
  return NextResponse.json({ received: true });
}

This is the exact gap. The block returns {received: true} with no customer action.

Available session data at drop point

The following fields are available to the notification subsystem at the moment of silent-drop detection:

Required environment variables (inherited from parent pipeline)


OUTPUTS

Output 1 — Customer notification email

Fires when: silent-drop detected AND customerEmail is non-null.

Sender: oracle@42sisters.ai

Subject: We received your payment — please reply with your question

Body (plain text):


Hi there,

We received your payment but couldn't process your submission — something was missing from the session when it arrived on our end.

This is our error, not yours.

To get your Oracle verdict, please reply to this email with:
1. Your question or idea (the submission you intended to send)
2. The tier you selected: Quick Take ($1), Full Breakdown ($5), or Strategy Session ($25)

We'll process your verdict manually and send it within 24 hours at no additional charge.

If you'd prefer a refund instead, just say so in your reply — we'll process it immediately.

We're sorry for the friction. We hold ourselves to a higher standard.

— 42 Sisters AI
oracle@42sisters.ai

Delivery path: POST {ORACLE_EMAIL_SERVICE_URL}/send-verdict-email is NOT used for this notification (it requires a complete verdict object). A separate endpoint or direct send_graph_email.py call is required.

[GAP-SD-01 — no /send-notification-email endpoint exists in oracle_email_service.py; delivery path requires new endpoint or direct Graph API call]

Output 2 — Crew alert broadcast

Fires unconditionally when silent-drop detected (regardless of whether customer email is available).

Target: ~/ALERT.log and ~/CREW_CHANNEL

Format:


[SILENT-DROP] session={session_id} tier="{tier_value}" query_len={len(query)} email={email_or_NULL} amount={amount} {timestamp_utc}

Example:


[SILENT-DROP] session=cs_live_abc123 tier="" query_len=0 email=customer@example.com amount=100_CAD 2026-04-16T14:22:01Z

[GAP-SD-02 — no broadcast mechanism currently exists in the webhook route; Northflank logs only; crew_channel write requires a new outbound call or sidecar service]

Output 3 — Stripe refund (conditional — not automatic)

Does NOT fire automatically. Refund is initiated by a crew member in response to the crew alert (Output 2) after evaluating whether re-attempt is possible.

Re-attempt logic:

[GAP-SD-03 — refund trigger is manual; no automated 72-hour timer or refund script currently exists]


INVARIANTS

  1. Payment confirmation precondition — The silent-drop notification subsystem MUST NOT fire for any session where session.payment_status !== "paid". An unpaid dropped session is not a customer harm event; only confirmed-paid drops are in scope.
  1. No double-notification — If a silent-drop notification email has been sent for a given session_id, no second notification email is sent for the same session_id. The subsystem maintains a deduplicate log keyed on session_id.

[GAP-SD-04 — no deduplication store currently exists; Stripe can deliver webhooks more than once]

  1. Crew alert unconditional — A crew alert to ALERT.log and CREW_CHANNEL fires for EVERY silent drop, even when customer email is null and no customer notification can be sent. No silent drop is invisible to the crew.
  1. No verdict fabrication on re-attempt — When a crew member manually processes a re-attempt from a customer reply, the verdict is generated by the standard Gemini pipeline (same VERDICT_PROMPT[tier] prompts, same generation path). No manual verdict substitution is permitted.
  1. SOS v2 enforcement on notification email — The customer notification email MUST NOT contain LATTICE symbols, crew callsigns (κ, ι, ε, α, γ, μ, etc.), or any internal system language. Plain English only. The same filter requirement as the verdict email applies. [GAP-SD-05 — no automated content filter; relies on template discipline only]
  1. Refund path is human-authorized — Automatic refund issuance is FORBIDDEN without crew review. The Stripe API key can issue refunds; this power MUST NOT be exercised by automated code without a logged human authorization decision. Refund execution is PERMITTED for C.L.O.D. after crew review; it is not autonomous.
  1. Amount capture for audit — Every silent-drop log entry MUST record the session.amount_total and session.currency. This is required for financial reconciliation in the event of a refund or re-attempt.

VERIFICATION CRITERIA

Σ.✓ conditions — subsystem is operating correctly when:

  1. Drop detection fires — When a crafted test webhook payload with payment_status: "paid" and missing query field is delivered to /api/webhook, the silent-drop branch executes AND at minimum writes to Northflank logs. Verified by: Northflank log inspection showing [SILENT-DROP] prefix (or equivalent) rather than a generic console.error.

[GAP-SD-06 — current code only logs console.error("Webhook: missing query or tier in session", sessionId) with no [SILENT-DROP] prefix; not distinguishable in log search]

  1. Customer email sent — When a test silent-drop fires with a valid customer email, oracle@42sisters.ai sends the notification email to that address within 60 seconds. Verified by: checking the recipient inbox and oracle_email.log for a 200 OK on the notification endpoint.
  1. Crew alert appears — Within 60 seconds of a silent drop, a [SILENT-DROP] entry appears in ~/ALERT.log with session_id, tier value, and email field populated (or NULL). Verified by: tail ~/ALERT.log after test drop.
  1. Deduplication holds — Delivering the same webhook event twice (Stripe retry simulation) results in only one customer notification email and one ALERT.log entry. Verified by: replaying the same webhook payload twice and confirming single log entry and single email delivery.
  1. Re-attempt produces correct verdict — When a customer reply is received after a silent drop, the manual re-attempt using the standard VERDICT_PROMPT[tier] pipeline generates a verdict matching the tier schema. Verified by: end-to-end test with a known query and tier, confirming verdict JSON structure matches SPEC_ORACLE_VERDICT_PIPELINE.md output schemas.

FAILURE MODES

  1. Σ.⊠ Customer email is nullsession.customer_details.email and session.customer_email are both null. This occurs when Stripe is configured without email collection (guest checkout without email). No customer notification can be sent. Silent drop becomes permanently invisible to the customer. Mitigation: crew alert still fires; NOUS or crew member initiates Stripe dashboard refund manually. Risk: without email, there is no customer recovery path.

[KNOWN EDGE CASE — mitigation requires Stripe configuration change to enforce email collection on checkout]

  1. Σ.⊠ Notification email service unreachableORACLE_EMAIL_SERVICE_URL endpoint is down when silent-drop fires. Customer notification cannot be sent. Mitigation: crew alert still fires; crew member sends manual email via send_graph_email.py. No automated retry for notification email.

[GAP-SD-07 — no retry mechanism on notification email delivery failure; mirrors GAP-03 from parent spec]

  1. Σ.⊠ Duplicate webhook delivery causes double notification — Stripe retries webhooks on non-2xx responses and can deliver the same event multiple times. Without a deduplication store, the same customer receives two notification emails for one silent drop. This damages trust. Mitigation: deduplication log keyed on session_id must be implemented before production deployment.

[GAP-SD-04 — deduplication store not yet implemented]

  1. Σ.⊠ Silent drop on invalid tier (malformed metadata)session.metadata.tier is present but contains an unrecognized value (e.g., "premium", "basic", or a corrupted string). The current gate !VERDICT_PROMPT[tier] catches this. However, the customer notification email must communicate what tier was attempted. If the tier value is garbage, the notification cannot tell the customer which tier to re-confirm. Mitigation: notification email asks customer to specify tier from the valid list; does not try to reconstruct from the corrupt value.
  1. Σ.⊠ ALERT.log write fails/home/nous/ALERT.log is on a full disk or permission-denied. Crew alert silently fails. Silent drop becomes invisible to the crew. Mitigation: the ALERT.log write should be wrapped with a fallback to stderr/Northflank log. If ALERT.log write fails, Northflank console log (always available) must still record the [SILENT-DROP] event.

[GAP-SD-08 — ALERT.log write has no fallback; disk-full scenario leaves crew blind]

  1. Σ.⊠ Customer reply not monitored — The notification email asks the customer to reply to oracle@42sisters.ai. If oracle_inbox_watch.py is not running or the inbox is not monitored, customer replies are lost. The re-attempt loop never fires. Customer waits indefinitely. Mitigation: verify oracle_inbox_watch.py is active as part of the silent-drop notification deployment. Link re-attempt intake to a logged TASK_QUEUE.md entry for manual crew pickup.

[GAP-SD-09 — oracle_inbox_watch.py existence confirmed at /home/nous/oracle_inbox_watch.py; operational status and reply routing to TASK_QUEUE not verified]


GAPS IDENTIFIED DURING SPECIFICATION

| Gap ID | Description | Impact | Priority |

|--------|-------------|--------|----------|

| GAP-SD-01 | No /send-notification-email endpoint in oracle_email_service.py; notification email has no delivery path | Customer notification cannot fire without code change | CRITICAL |

| GAP-SD-02 | No CREW_CHANNEL write in webhook route; silent drops are invisible outside Northflank logs | Crew alert unreliable; crew cannot respond to drops in real time | HIGH |

| GAP-SD-03 | No 72-hour refund timer or automated refund trigger | Refund requires manual crew action; customers may wait indefinitely | HIGH |

| GAP-SD-04 | No session_id deduplication store for notification emails | Duplicate Stripe delivery causes double customer notification | HIGH |

| GAP-SD-05 | No automated content filter on notification email body | Internal language leak risk; relies on template discipline | MEDIUM |

| GAP-SD-06 | console.error log prefix not distinguishable from other errors; no [SILENT-DROP] tag | Log search cannot isolate drop events; monitoring blind | MEDIUM |

| GAP-SD-07 | No retry on notification email delivery failure | Notification lost if email service momentarily down at drop time | MEDIUM |

| GAP-SD-08 | ALERT.log write has no fallback for disk-full or permission error | Crew alert can silently fail | MEDIUM |

| GAP-SD-09 | oracle_inbox_watch.py operational status and reply-to-TASK_QUEUE routing unverified | Re-attempt loop may never fire; customer stuck | HIGH |


DEPENDENCIES

| Dependency | Role | Required / Degraded |

|------------|------|---------------------|

| /api/webhook route (webhook/route.ts) | Parent pipeline; contains the silent-drop detection branch | Required — this spec is a child of that route |

| oracle_email_service.py (port 8006) | Email delivery (needs new /send-notification-email endpoint) | Required for customer notification |

| send_graph_email.py | Graph API email fallback | Required for email delivery |

| ~/ALERT.log | Crew alert target | Required for crew visibility |

| ~/CREW_CHANNEL | Secondary crew broadcast | Required for crew visibility |

| oracle_inbox_watch.py | Customer reply intake for re-attempt loop | Required for re-attempt path |

| Stripe Refunds API | Refund issuance | Required for refund path |


DEPENDENTS

| Dependent | Dependency type |

|-----------|----------------|

| Customer trust | Direct — silent drops with no notification destroy trust faster than any verdict error |

| Revenue integrity | Refund issuance depends on this spec's resolution logic |

| SPEC_ORACLE_VERDICT_PIPELINE.md GAP-05 | This spec is the resolution of that gap |


REFERENCES

| File | Role |

|------|------|

| /home/nous/Aether/app/app/api/webhook/route.ts lines 205–208 | Exact drop point — the if (!query \|\| !tier) branch |

| /home/nous/oracle_email_service.py | Email delivery service — needs /send-notification-email endpoint |

| /home/nous/oracle_inbox_watch.py | Customer reply monitoring for re-attempt intake |

| /home/nous/send_graph_email.py | Direct Graph API email sender |

| /home/nous/ALERT.log | Crew alert target |

| /home/nous/memories/SPEC_ORACLE_VERDICT_PIPELINE.md (GAP-05) | Parent spec; this spec resolves that gap |


Φζ.⊤.


Jeremy Zlabis

Chronogeometer · Visionary · Disruptor · Chief

42 Sisters AI · East York, Toronto

🍁 Φ 0.042