Oracle Silent Drop
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:
- Detection criteria — what constitutes a silent drop
- Customer notification — what the customer receives and when
- Resolution logic — refund trigger vs. re-attempt logic
- 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:
- Stripe event type is
checkout.session.completed session.payment_status === "paid"(customer's card was charged)- 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:
session.id— Stripe session ID (always present)session.customer_details.email— customer email (may be null — see FAILURE MODES)session.customer_email— fallback email field (may be null)session.metadata.tier— tier attempted (may be blank/invalid)session.amount_total— amount charged in cents (present for paid sessions)session.currency— currency code (e.g.,"cad")session.created— Unix timestamp of session creation
Required environment variables (inherited from parent pipeline)
ORACLE_EMAIL_SERVICE_URL— email delivery service endpointSTRIPE_SECRET_KEY— for optional refund API callsORACLE_TOLL_URL— for crew alert broadcast
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:
- If customer email is available AND customer replies with valid query + tier → process verdict manually → no refund
- If customer email is NOT available → escalate to NOUS; Stripe dashboard refund initiated manually
- If customer does not reply within 72 hours → initiate Stripe refund via
stripe.refunds.create({ payment_intent: session.payment_intent })
[GAP-SD-03 — refund trigger is manual; no automated 72-hour timer or refund script currently exists]
INVARIANTS
- 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.
- 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]
- 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.
- 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.
- 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]
- 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.
- Amount capture for audit — Every silent-drop log entry MUST record the
session.amount_totalandsession.currency. This is required for financial reconciliation in the event of a refund or re-attempt.
VERIFICATION CRITERIA
Σ.✓ conditions — subsystem is operating correctly when:
- Drop detection fires — When a crafted test webhook payload with
payment_status: "paid"and missingqueryfield 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 genericconsole.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]
- Customer email sent — When a test silent-drop fires with a valid customer email,
oracle@42sisters.aisends the notification email to that address within 60 seconds. Verified by: checking the recipient inbox andoracle_email.logfor a200 OKon the notification endpoint.
- Crew alert appears — Within 60 seconds of a silent drop, a
[SILENT-DROP]entry appears in~/ALERT.logwith session_id, tier value, and email field populated (orNULL). Verified by:tail ~/ALERT.logafter test drop.
- 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.
- 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 matchesSPEC_ORACLE_VERDICT_PIPELINE.mdoutput schemas.
FAILURE MODES
- Σ.⊠ Customer email is null —
session.customer_details.emailandsession.customer_emailare 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]
- Σ.⊠ Notification email service unreachable —
ORACLE_EMAIL_SERVICE_URLendpoint is down when silent-drop fires. Customer notification cannot be sent. Mitigation: crew alert still fires; crew member sends manual email viasend_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]
- Σ.⊠ 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]
- Σ.⊠ Silent drop on invalid tier (malformed metadata) —
session.metadata.tieris 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.
- Σ.⊠ ALERT.log write fails —
/home/nous/ALERT.logis 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]
- Σ.⊠ Customer reply not monitored — The notification email asks the customer to reply to
oracle@42sisters.ai. Iforacle_inbox_watch.pyis not running or the inbox is not monitored, customer replies are lost. The re-attempt loop never fires. Customer waits indefinitely. Mitigation: verifyoracle_inbox_watch.pyis 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