Skip to content
Side-Effect Firewall

The twin cannot act on the real world.

No default public egress. Clone-local DNS. A stateful Stripe that answers offline, mail rendered and captured rather than sent. Unknown destinations are denied and written to the attempted-effect ledger.

containment map
EGRESS
Fail-closed egress boundary
network namespace sealed; run 08f2
0 escaped
candidate
Application attempts an external effect
POST api.stripe.com/v1/charges
POST api.sendgrid.com/v3/mail/send
TCP 18.4.2.9:443
mandatory gateway
Resolve, inspect, then apply the first explicit rule
Default posture: BLOCK. Unknown or ambiguous traffic fails closed.
contained outcomes
Mock, capture, or block without public egress
Stripe pack
MOCK; stateful response
Mail inbox
CAPTURE; rendered artifact
Unknown host
BLOCK; no route out
attempted-effect ledgerevery gateway decision is append-only
Side-effect containment architecture: application requests pass through clone-local resolution and a mandatory gateway before being simulated, captured, or blocked, with each gateway decision written to the attempted-effect ledger.
Attempted-effect ledger

Every outbound attempt is recorded, including the denials. Six per-host modes, from refusing outright to answering from an offline pack. Never a live processor.

af net log; run 08f2
LEDGER
6
decisions
2
blocked
0
escaped
attempted effectmodereceipt
POSTapi.stripe.com/v1/chargesMOCKch_sim_08f2
POSTapi.sendgrid.com/v3/mail/sendCAPTUREmsg_sim_2a91
POSThooks.slack.com/services/T0/B0CAPTUREreq_sim_91c0
POSTapi.openai.com/v1/chat/completionsMOCKmock_5b12
GETapi.prod.internal/v1/healthBLOCKdeny_01
CONNECTexample.com:443BLOCKdeny_02
MOCK / CAPTURE / BLOCK are the only visible outcomes here. Every row represents an attempted effect; none escaped.
Attempted-effect ledger containing six gateway decisions: four safely handled by mock or capture modes, two blocked, and zero requests escaping the twin.
  • stripe.pack.local
    MOCK
    stateful offline pack
    Stripe charge lifecycle
    contained
    request
    POST /v1/charges
    amount 4900; usd; cus_sim_11
    mock response
    200 OK; ch_sim_08f2
    status succeeded; livemode false
    Clone-local state transition persisted
    cus_sim_11; charge.created; api.stripe.com never resolved
    A Stripe charge request is answered by the stateful clone-local pack, which returns a simulated charge and records the state transition without contacting Stripe.
  • capture inbox
    CAPTURE
    searchable artifact
    Rendered, not delivered
    202 shape
    Order #4182
    msg_sim_2a91; multipart/alternative
    not sent
    from
    checkout@twin.local
    to
    customer@example.test
    subject
    Your order #4182
    plainhtml
    POST /v3/mail/send returns provider-shaped 202; no delivery attempted.
    A SendGrid API call is terminated inside the twin and rendered as a captured MIME message that can be inspected, but is never delivered.
  • policy trace
    BLOCK
    unknown destination
    CONNECT example.com:443
    refused
    1. 01Resolve hostexample.com
    2. 02Match explicit rulenone
    3. 03Apply defaultBLOCK
    4. 04Write decisiondeny_02
    Socket not opened; 0 bytes out; denial receipt deny_02 recorded.
    An unlisted connection to example.com is evaluated by the gateway, matches no explicit rule, inherits the BLOCK default, and receives a denial receipt in the decision log.

IllustrativeSix rows chosen to show mocked calls, captured messages and denials. The hosts, the modes and the decision log are real: af net log prints every request the gateway decided, allowed as well as refused, and af ci summarises them on the pull request. A packet that never reaches the gateway, such as a connection straight to a public address, leaves no row: it fails at the network instead, which is stronger and is the section below. A denied destination is denied inside the twin; it does not on its own fail the check.

Containment is not a rule you can edit. A direct-IP attempt does not get out.

Clone-local DNS is not enough if the twin dials an address. The gateway matches domain, IP, protocol, method, and operation. Unknown destinations, unresolved secrets, or missing isolation block the run. Convenience does not silently override containment.

  • No default egress

    There is no default public internet route from the twin.

  • Clone-local DNS

    Production hostnames do not resolve to production.

  • Mandatory gateway

    Domain, IP, protocol, method, and operation policies at the edge.

  • A stateful Stripe

    One built-in pack answers the Stripe API from a clone-local ledger. Other mocked hosts answer without keeping state.

network namespace; route trace
NO ROUTE
isolation boundary
Two paths. Neither bypasses containment.
default route none
named host
Gateway path
01Candidate applicationapi.stripe.com:443
02Clone-local DNSstripe.pack.local
03Mandatory gatewayMOCK; decision logged
network resultcontained response
raw address
Direct IP has no route
01Candidate applicationTCP 18.4.2.9:443
02Route lookup0.0.0.0/0 -> none
Public network unreachableENETUNREACH; 0 bytes out
gateway
not reached
ledger row
none
Containment is structural
no DNS dependency; no editable bypass; no public route
Comparison of a hostname request routed through clone-local DNS and the mandatory gateway with a direct-IP request stopped by the network namespace because no public default route exists. The direct-IP failure returns ENETUNREACH and creates no gateway ledger row.

Charging a live processor is an existential failure. Not a warning. Not a retry.

Existential failure
Charging cards, emailing users, or invoking production webhooks from a twin is a failed containment model. Read-only forwarding exists only for explicitly approved endpoints. Request and response redaction is mandatory. The ledger is the proof.
Next

Know what happens before you deploy.

Create a disposable production twin for every risky change. Catch migration failures before they reach customers.