Commit Graph

19 Commits

Author SHA1 Message Date
Ran Shem Tov 61eed4a4ad fix(showcase): harden CrewAI D6 parity on a3 2026-08-07 17:50:13 +03:00
Mike Ryan 98711fbefb fix(showcase): stage Angular artifacts in deployment images 2026-07-23 09:46:29 -07:00
Mike Ryan 637845bb7c feat(showcase): checkpoint 3 - shared build and proof pair 2026-07-23 07:14:55 -07:00
Jordan Ritter 8c8ead1a02 fix(showcase): propagate _slot_offset_ports failure so the port-conflict guard fails loudly on a bad slot
_slot_ports_free consumed _slot_offset_ports via process substitution
(done < <(...)), so a die on an out-of-range/non-numeric slot exited only
the subshell — the loop read zero ports, any_held stayed 0, and the
function returned 0 ("all free"), silently defeating the port-conflict
guard for a bad slot. Capture into a variable with || die so the failure
propagates to the caller. Real-surface bats prove a bad slot now fails
loudly while valid-slot free/held behavior is unchanged.
2026-06-26 13:38:29 -07:00
Jordan Ritter 42e17cf6c3 fix(showcase): reconcile slot liveness against container state, add kept-stack TTL + reap self-id label
A --keep'd isolated stack whose owning process had exited (but whose
containers kept running) was classified 'live' forever and never reaped,
leaking Docker stacks indefinitely. Introduce a start-time-verified
_owner_liveness probe and a new 'kept' state, an ISOLATE_KEEP_TTL (4h,
SHOWCASE_ISOLATE_KEEP_TTL-overridable) that flips an over-age kept slot
to 'stale' so the sweep reclaims it, a com.copilotkit.showcase.isolate
self-id label stamped by apply_isolation, a 'slots --reapable' filter,
and a macOS lsof COMMAND-truncation fix in the own-project port filter.
Real-surface bats cover the liveness false-positive and TTL reaping.
2026-06-26 12:54:55 -07:00
Jordan Ritter dc72e9cac8 feat(cvdiag): Python _shared bootstrap module + 12-integration reachability wiring (L0-C) 2026-06-18 14:06:57 -07:00
Jordan Ritter cb197773ee feat(showcase): rewrite --isolate slot picker with pinned slots, port probe, and slot 0 reservation
- Centralize ISOLATE_MAX_SLOT=45 constant
- Add helpers: _slot_offset_ports, _slot_liveness, _slot_ports_free, _slot_state
- Rewrite _claim_isolate_slot to reserve slot 0, honor SHOWCASE_ISO_SLOT, port-probe via lsof
- Document benign mkdir/rmdir race in auto-pick path
- Shift dashboard host port 3200 → 3210 in apply_isolation / restore_isolation
- Pass slot entry path + project to _reap_isolate_slot in pinned-path retry
- _slot_state reports offset=0 for the base stack (slot 0)
- _slot_state degrades gracefully to ports=? when lsof is missing
2026-06-17 16:44:12 -07:00
Jordan Ritter edc77f8090 fix(showcase/harness): pass slug via env var to python rewriter instead of bash interpolation
The python rewriter in apply_isolation previously interpolated $slug
directly into the inline python source via bash. A slug containing a
single quote would break the python literal. Internal-tool risk only
(slug is developer-typed), but cheap to harden.

Pass slug via SHOWCASE_ISO_SLUG env var and read os.environ.get(...)
inside the python heredoc. Defense-in-depth; no behavior change for
valid slugs.
2026-06-15 11:16:24 -07:00
Jordan Ritter 5e641d88c9 fix(showcase/harness): override LOCAL_SERVICES_JSON in --isolate generator to target the requested slug
The persistent stack's docker-compose.local.yml hardcodes LOCAL_SERVICES_JSON
to the langgraph-python sample for fast N=1 local demos. When --isolate
spawns an iso1 stack with a different slug (e.g. ms-agent-python), the
iso1 harness container inherited that hardcoded value, causing
discovery.railway-services.local-injection to enumerate the wrong service
(showcase-langgraph-python instead of showcase-<requested-slug>). The iso1
probe then targeted the wrong container, broke red-green verification, and
left D5 cells unwritten.

Inject a per-slug LOCAL_SERVICES_JSON override into the iso1 compose
generator so iso1 always probes the slug passed via --isolate.
2026-06-15 10:38:06 -07:00
Jordan Ritter 171943469a fix(showcase): guard reaper against reserved 'showcase' record + isolate review fixes
Cross-session review fixes for the --isolate machinery (one concern:
source + test + docs).

1) Reaper reserved-name guard (critical): _reap_isolate_slot trusted
   slot records — a record naming 'showcase' (corrupt, or written by an
   older CLI version before apply_isolation reserved the name) passes
   the charset regex, so the reap ran `docker compose -p showcase down
   --remove-orphans --volumes` against the LIVE default stack,
   destroying the PocketBase named volume. The reserved name now gets
   the same treatment as the path-traversal guard: warn (naming the
   record and why it is dangerous) and leave the slot intact for manual
   inspection — no compose-down, no state removal.

   Call-site enumeration: _reap_isolate_slot's sole caller is
   _sweep_isolate_slots, at 3 sites (dead-PID reap, project-recorded/
   no-owner reap, age-fallback reap), all passing
   "$slot_entry" "$slot_proj" — all three flow through the new guard
   identically.

   Red-green: the new bats test ("a slot whose project record reads the
   RESERVED 'showcase' is left intact...") was run against the UNFIXED
   code first and FAILED — the sweep logged "Attempting to reclaim
   stale slot 0 (project showcase has no live containers and no
   recorded owner)" and reaped the slot. It passes with the guard.

2) .iso-bak restore race: two concurrent runs can both see a stale
   backup; the loser's mv is the FINAL command of its `[ -f ] && mv`
   AND-list, so its failure trips set -e and kills the CLI pre-claim
   with a raw error. Both mv's now carry `2>/dev/null || true` — the
   survivor's restore wins, the loser proceeds with restored originals.

3) Keep-test absence regexes greped only the `--project-name <name>
   down` spelling; the reaper's own downs use `-p <name> down`, so a
   keep-branch regression via the -p form passed undetected. Both keep
   absence assertions now match `(--project-name|-p) <name> down`.
   Mutation-verified: a temporary -p-form compose-down added to the
   keep branch made BOTH broadened tests FAIL; reverted, suite green.
   (All other absence assertions use the word-matched generic
   `compose ... down` regex, which already covers both spellings.)

4) RUNBOOK.md/DEBUGGING.md contradicted shipped code: the manual
   teardown was quoted without --volumes plus notes claiming
   `down --remove-orphans` leaves named volumes (the shipped survival
   notice and every teardown path include --volumes), and the name rule
   was documented as `[a-z0-9_-]+` (actual: starts with [a-z0-9], then
   [a-z0-9_-], uppercase normalized with a warn, 'showcase' reserved).
   Both updated to the shipped semantics; the now-redundant separate
   `down --volumes` snippets removed.

Verification: full `bats showcase/scripts/__tests__/` green (60 tests);
shellcheck on _common.sh shows no new warnings vs baseline
(pre-existing SC2034/SC2115 only, line-shifted).
2026-06-10 08:58:28 -07:00
Jordan Ritter f2ed2b28ef fix(showcase): harden isolate state machine — --keep wiring, default-stack guards, registry concurrency
- ISOLATE_KEEP promoted to a global so --keep survives cmd_test return
  into the trap scope
- early-die and default-stack protection: failed --isolate setup no
  longer tears down the default stack; half-initialized state is
  cleaned up on the way out
- liveness/PID/age reaping signals with a sweep lock: heartbeat
  updates, own-pid lock release, tombstones, and a claim-then-verify
  duplicate-name guard close slot-registry races (TOCTOU, lock
  takeover, reap order)
- teardown robustness: --volumes on every compose down, failed-down
  runs preserve state for diagnosis, reap remnants get a compose-down,
  path-traversal guard, uniform rm guards under set -e
- name validation: --isolate names must start with a lowercase letter
  or digit; reserved name 'showcase' rejected (it aliases the default
  stack)
- fail-loud warning before pre-down of an existing stack; help text
  updated

Result of an 8-round, 7-agent code-review loop with red-green
verified fixes.
2026-06-09 18:17:55 -07:00
Jordan Ritter da504c147c fix(showcase): honor --keep on the isolate teardown path
Previously the EXIT-trap restore_isolation always tore down the isolated
stack, ignoring --keep. Now restore_isolation reads a keep flag (set in
cmd-test.sh when --keep is parsed): when kept it skips compose down, the run-dir
removal, and the slot release, and instead prints a survival notice with the
project, slot, the three offset host ports, and the exact manual teardown
command. The kept stack's live containers keep its slot from being reaped.
2026-06-09 12:52:33 -07:00
Jordan Ritter 1d31c2782b feat(showcase): reap stale isolate slots by compose-project liveness
Persist the compose project name into each claimed slot dir, and at claim time
reap any slot whose recorded project has no live containers (queried via
docker ps --filter label=com.docker.compose.project). This correctly leaves a
--keep'd stack's slot alone since its containers are still up. The existing
PID/age heuristics remain as a fallback for slots predating the project file.
2026-06-09 12:52:12 -07:00
Jordan Ritter 887191db95 refactor(showcase): migrate isolate runtime state to XDG_STATE_HOME
Move the --isolate slot registry and per-run scratch dir off /tmp (wiped on
reboot, world-writable) to $XDG_STATE_HOME/copilotkit/showcase (slots/ and
runs/<name>). The run dir is now keyed by the finalized project name instead
of the PID so a kept run is locatable for manual teardown. Adds a bats suite
covering the new state-base helper and run-dir location.
2026-06-09 12:51:53 -07:00
Jordan Ritter 671cc6ae1d feat(showcase/harness): support concurrent --isolate runs
- scripts/cli/_common.sh apply_isolation rewrites compose-file relative
  paths to absolute (build/context/dockerfile/volumes/env_file), enforces
  the docker compose [a-z0-9_-] project-name rule (normalize-with-warn or
  hard fail), and exports SHOWCASE_COMPOSE_FILE / SHOWCASE_INFRA_PORT_OFFSET
  plus offset host URLs (AIMOCK_URL_LOCAL / DASHBOARD_URL_LOCAL /
  POCKETBASE_URL_LOCAL) so the TS harness CLI talks to THIS project's
  aimock instead of the default :4010
- harness/src/cli/{aimock-rebuild,config,doctor,lifecycle}.ts honor the
  new env vars; lifecycle picks up the offset infra port for health
  probes so concurrent stacks no longer report each other's services as
  healthy
- Commit a generated harness/package-lock.json (new file) so npm ci
  resolves deterministically
2026-05-29 16:15:47 -07:00
Jordan Ritter d49dcc4fc9 fix(showcase): add --project-name to isolated compose commands
The COMPOSE_CMD in apply_isolation was missing --project-name, so Docker
Compose would infer the project name from the directory and collide with
the base showcase stack (and other isolated runs). Adding --project-name
ensures containers, networks, and volumes are fully scoped to the
isolation slot.
2026-05-01 00:09:30 -07:00
Jordan Ritter 7e4dad042c fix(showcase): temp overlay isolation + slot-based port allocation
apply_isolation previously mutated docker-compose.local.yml and
local-ports.json in-place with .iso-bak backups. If the process crashed
the originals stayed corrupted with +200 port offsets, breaking all
subsequent showcase commands.

Now writes modified copies to a temp directory and overrides
COMPOSE_FILE/PORTS_FILE shell variables so downstream code reads from
the overlay. Originals are never touched. restore_isolation just removes
the temp dir.

Also replaces hardcoded +200 port offset with atomic mkdir-based slot
allocation. Two parallel --isolate runs now get different port ranges
(slot 0 = +200, slot 1 = +400, etc.) instead of colliding on the same
ports. Container names include the slot number for collision-free Docker
naming. Stale slots from crashed runs are reclaimed via PID liveness
checks and a 2-hour age fallback.

TS harness files (config.ts, lifecycle.ts, doctor.ts) honor
LOCAL_PORTS_FILE env var so they read offset ports from the temp overlay.
2026-05-01 00:08:16 -07:00
Jordan Ritter f9578b2ab7 feat(showcase): add --isolate flag for parallel-safe local testing
When passed to `showcase test`, creates an isolated Docker Compose
project with offset ports (+200) and renamed containers, allowing
multiple agents/sessions to run showcase tests simultaneously without
container conflicts.

Usage:
  showcase test agno --d5 --isolate           # auto-names isolate-<PID>
  showcase test agno --d5 --isolate d5verify  # explicit name
2026-04-30 16:31:12 -07:00
Jordan Ritter 58b423d167 feat(showcase): add unified CLI dispatcher and shared utilities
bin/showcase auto-discovers cmd-*.sh plugins, routes built-in commands
(up/down/build/ps/ports), and provides stage_shared/restore_symlinks
for Docker Compose volume management.

_common.sh provides shared variables (SHOWCASE_ROOT, COMPOSE_CMD,
COMPOSE_FILE), output helpers (die/info/warn/success), and container
utilities (slug_to_container, slug_to_port, wait_healthy).
2026-04-28 22:29:21 -07:00