The Docker backend cannot launch a bottle on this host: the
orchestrator publishes 127.0.0.1:8099 but is attached only to the
`--internal` control network, so Docker accepts the mapping and never
establishes the forward (PortBindings set, NetworkSettings.Ports
empty). Every launch dies on `orchestrator did not become healthy`.
That is independent of the demo and left alone here, because fixing it
means touching the L3 isolation the control network exists to provide.
Pin the tape to macos-container, which launches cleanly, and drop the
Docker daemon check and image pre-warm from setup. The pre-warm is not
replaced with a `container build` equivalent: build_image() applies
--dns handling that would become a second, drifting copy in shell, and
the warm layer cache already keeps rebuilds fast. Pre-warm never kept
BuildKit off camera anyway — the launcher prints CACHED lines
regardless, so that comment was wrong when it was written.
Launch via --headless. The interactive path opens four selectors in a
row and the tape drove none of them; it also lists every bottle in
~/.bot-bottle/bottles/, putting the operator's own bottle names in a
GIF that ships in the README. --headless is one-shot by construction
(`claude -p`), so all probes ride in on a single --prompt rather than
being typed as follow-ups into a session that has already exited.
Spell the probes as literal shell commands. Left in English, one take
had the agent substitute a placeholder for $FAKE_TOKEN: the DLP
scanner had nothing to match and gitleaks found nothing to flag, so
both controls reported a clean pass without ever being exercised.
Neither curl discards the body, so the recording shows the host-filter
refusal and the DLP refusal as visibly different reasons instead of
two identical 403s.
Drop the git/gitleaks probe. In the last run carrying it, gitleaks
reported `no leaks found` on an AKIA-shaped key and the gate forwarded
the push, which failed only because upstream.invalid does not resolve.
A recording of that reads as the gate catching a secret while showing
the opposite. Tracked in #541.
Refs #540
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The demo has been unrunnable since eafd1c1f deleted bot-bottle.demo.json
as a pre-YAML-migration artifact. demo-setup.sh still copied that file
under `set -euo pipefail`, so demo.sh and demo-record.sh both exited
non-zero before launching anything.
Rebuild the fixtures in the current per-file Markdown format. Bottles
are only read from $HOME/.bot-bottle/bottles/ — manifest/index.py
ignores a bottles/ dir in CWD by design (PRD 0011) — so setup now
installs into real config and pairs every write with a .demo-backup
that teardown restores. Teardown compares content before removing, so
a second run cannot delete the user's restored original.
Point the DLP probe at the bottle's own example.org route rather than
api.anthropic.com/dlp-probe. The provider-injected anthropic route
defaults to `redact`, which would forward a scrubbed request instead of
refusing; the declared route sets outbound_on_match: block so probe 3
stays the hard 403 the demo is showing off. Left at the default
`supervise` it would instead hold the request open for up to 300s
awaiting operator approval and stall the recording.
Also drop the stale pipelock naming from the tape (egress is the
gateway's own scanner now), fix demo.sh's ./cli.py invocation, and
pre-warm Dockerfile.gateway instead of the removed Dockerfile.git-gate.
Refs #540
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Squashes the demo-build arc: initial GIF + scripts, refactor to drive
recording through real cli.py, theme/timing tweaks, and the switch to
prompt-driven probes.