Skip to content

Commit 0522b7f

Browse files
committed
refactor(showcase): rename showcase/ops → showcase/harness
The monitoring/alerting service is a test harness (probes, assertions, alerting), not an operations service. Rename the directory, package name (@copilotkit/showcase-ops → @copilotkit/showcase-harness), all internal references (Dockerfile, Prometheus metric prefix showcase_ops_ → showcase_harness_, orchestrator log messages, probe YAML nameExcludes, test fixtures), and regenerate pnpm-lock.yaml. Wire protocol names (X-Ops-* headers) and shell-dashboard internal API naming (OPS_BASE_URL, ops-api.ts) are intentionally unchanged — they are stable contracts between sender and receiver.
1 parent c47ac31 commit 0522b7f

234 files changed

Lines changed: 340 additions & 343 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

pnpm-lock.yaml

Lines changed: 97 additions & 100 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ packages:
99
- "examples/showcases/generative-ui-playground"
1010
- "!examples/v1/_legacy"
1111
- "showcase/scripts"
12-
- "showcase/ops"
12+
- "showcase/harness"
1313
# NOTE: `showcase/shell-dashboard` is intentionally NOT part of this
1414
# pnpm workspace. It's a flat, standalone Next.js app that ships its
1515
# own package-lock.json and is built with `npm ci` (see its Dockerfile).
1616
# Including it here would force it into the pnpm lockfile, which
1717
# breaks its independent deploy path and invalidates the npm-based
1818
# Docker build. `showcase/scripts` IS in the workspace because the
19-
# ops package imports from it and both use pnpm.
19+
# harness package imports from it and both use pnpm.
2020
onlyBuiltDependencies:
2121
- better-sqlite3
Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ WORKDIR /repo
44
RUN corepack enable
55

66
COPY pnpm-workspace.yaml package.json pnpm-lock.yaml .pnpmfile.cjs ./
7-
COPY showcase/ops/package.json ./showcase/ops/package.json
7+
COPY showcase/harness/package.json ./showcase/harness/package.json
88
# Copy every workspace package.json manifest (but NOT source / node_modules).
99
# The version-drift probe's pnpm-packages discovery source parses these at
1010
# runtime. Doing this in the build stage (rather than COPY-ing packages/
@@ -23,10 +23,10 @@ RUN mkdir -p ./packages && \
2323

2424
# `--ignore-scripts` skips the root `prepare` hook (lefthook install), which
2525
# requires `git` and is meaningless inside the build image. Deps themselves
26-
# don't rely on postinstall scripts in showcase-ops.
27-
RUN pnpm install --frozen-lockfile --ignore-scripts --filter @copilotkit/showcase-ops...
26+
# don't rely on postinstall scripts in showcase-harness.
27+
RUN pnpm install --frozen-lockfile --ignore-scripts --filter @copilotkit/showcase-harness...
2828

29-
COPY showcase/ops ./showcase/ops
29+
COPY showcase/harness ./showcase/harness
3030
# e2e-smoke probe: generate registry.json at build time (the file is
3131
# gitignored, so it won't exist in a clean checkout). Copy the scripts
3232
# directory plus shared/packages metadata the generator reads, install
@@ -39,20 +39,20 @@ COPY showcase/scripts/ ./showcase/scripts/
3939
RUN cd showcase/scripts && npm ci --silent \
4040
&& node node_modules/tsx/dist/cli.mjs generate-registry.ts
4141

42-
RUN pnpm --filter @copilotkit/showcase-ops build
42+
RUN pnpm --filter @copilotkit/showcase-harness build
4343

4444
# `pnpm deploy` materializes a standalone, hoisted node_modules with only
4545
# production deps into /deploy — no symlinks into /repo/node_modules/.pnpm.
4646
# Without this, the runtime stage would copy a pnpm-hoisted tree whose
4747
# symlinks point into paths that don't exist in the final image.
4848
# `--legacy` keeps pnpm v10+'s `deploy` usable without requiring
4949
# `inject-workspace-packages=true` across the repo — we don't use
50-
# injected workspace deps in showcase-ops.
50+
# injected workspace deps in showcase-harness.
5151
# Verified on pnpm 10.13.x — the `--legacy` flag semantics shifted in the
5252
# 10.x line (pre-10.x `deploy` was itself the legacy behavior and the flag
5353
# was a no-op). Pin the comment to the repo's committed pnpm version so
5454
# future upgrades surface the dependency.
55-
RUN pnpm --filter @copilotkit/showcase-ops --prod --legacy --ignore-scripts deploy /deploy
55+
RUN pnpm --filter @copilotkit/showcase-harness --prod --legacy --ignore-scripts deploy /deploy
5656

5757
# Runtime stage: Debian-slim (not Alpine) because the e2e-smoke probe
5858
# driver launches chromium in-process via `playwright`. Playwright's
@@ -74,10 +74,10 @@ ENV QA_REPO_ROOT=/app
7474
# orchestrator reads the same env at runtime via `playwright`'s own
7575
# default resolution logic.
7676
ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
77-
COPY --from=build /repo/showcase/ops/dist ./dist
77+
COPY --from=build /repo/showcase/harness/dist ./dist
7878
COPY --from=build /deploy/node_modules ./node_modules
7979
COPY --from=build /deploy/package.json ./package.json
80-
COPY --from=build /repo/showcase/ops/config ./config
80+
COPY --from=build /repo/showcase/harness/config ./config
8181
# e2e-smoke probe: install chromium + its system deps. `--with-deps`
8282
# pulls in libnss3, libatk, libxkbcommon, libdrm, etc. via apt. Runs as
8383
# root because apt-get needs root. Call `playwright/cli.js` directly
Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# showcase-ops
1+
# showcase-harness
22

33
In-cluster observability service for the showcase fleet. Runs on Railway, receives signed webhooks from GitHub Actions, executes cron-driven probes, persists state to PocketBase, classifies state transitions, and delivers alerts to Slack.
44

@@ -12,21 +12,21 @@ This section is for everyone who needs to add an alert rule, rotate a secret, or
1212

1313
## 1.1 Inspect a running instance
1414

15-
Production URL: `https://showcase-ops-production.up.railway.app`
15+
Production URL: `https://showcase-harness-production.up.railway.app`
1616

1717
- **`GET /health`** — JSON: `{status, pb, loop, rules, schedulerJobs}`. `pb:"ok"` means PocketBase reachable; `loop:"ok"` means the scheduler tick has advanced in the last interval; `rules` is the count of successfully compiled YAMLs; `schedulerJobs` is the count of registered cron entries.
1818
- **`GET /metrics`** — Prometheus exposition. Key counters:
19-
- `showcase_ops_probe_runs{dimension=...}` — per-dimension probe executions
20-
- `showcase_ops_alert_matches{rule=...}` — rule match count
21-
- `showcase_ops_alert_sends{target=...}` — successful target deliveries
22-
- `showcase_ops_rule_reloads` — increments on SIGHUP / file watcher reload
23-
- `showcase_ops_webhook_rejections{reason=...}` — HMAC and payload-validation failures; `reason` is one of `stale`, `invalid-signature-format`, `invalid-signature`, `missing-signature`, `missing-timestamp`, `invalid-payload`, `unknown`
19+
- `showcase_harness_probe_runs{dimension=...}` — per-dimension probe executions
20+
- `showcase_harness_alert_matches{rule=...}` — rule match count
21+
- `showcase_harness_alert_sends{target=...}` — successful target deliveries
22+
- `showcase_harness_rule_reloads` — increments on SIGHUP / file watcher reload
23+
- `showcase_harness_webhook_rejections{reason=...}` — HMAC and payload-validation failures; `reason` is one of `stale`, `invalid-signature-format`, `invalid-signature`, `missing-signature`, `missing-timestamp`, `invalid-payload`, `unknown`
2424
- **`POST /webhooks/deploy`** — HMAC-signed webhook ingest for `deploy.result` events. Canonical payload: `METHOD|PATH|TS|sha256(body)` with `sha256=<hex>` signature in `X-Ops-Signature`. Path must be the route constant (`/webhooks/deploy`), not `c.req.path`. 300s skew tolerance.
25-
- **Logs**`railway logs --service showcase-ops` or the Railway dashboard. All lines are structured JSON: `{level, msg, ts, ...fields}`. Grep targets: `alert-engine.bootstrap-suppress` (gate suppressed a send), `writer.failed` (PB persist failed, always re-emits on bus), `suppress.eval-failed` (a suppress DSL expression threw), `rules.reload.failed` (load-time validation rejected a YAML).
25+
- **Logs**`railway logs --service showcase-harness` or the Railway dashboard. All lines are structured JSON: `{level, msg, ts, ...fields}`. Grep targets: `alert-engine.bootstrap-suppress` (gate suppressed a send), `writer.failed` (PB persist failed, always re-emits on bus), `suppress.eval-failed` (a suppress DSL expression threw), `rules.reload.failed` (load-time validation rejected a YAML).
2626

2727
## 1.2 Environment variables
2828

29-
All read at boot unless marked otherwise. See `showcase/ops/src/orchestrator.ts`.
29+
All read at boot unless marked otherwise. See `showcase/harness/src/orchestrator.ts`.
3030

3131
**Required in production:**
3232

@@ -35,7 +35,7 @@ All read at boot unless marked otherwise. See `showcase/ops/src/orchestrator.ts`
3535
| `POCKETBASE_URL` | Internal PB endpoint (`http://showcase-pocketbase.railway.internal:8090`). Boot refuses to start if unset when `NODE_ENV=production`. |
3636
| `POCKETBASE_SUPERUSER_EMAIL` | Admin auth for ops to write status rows. |
3737
| `POCKETBASE_SUPERUSER_PASSWORD` | Paired. |
38-
| `SHARED_SECRET` | Current HMAC secret for `/webhooks/deploy`. 64-hex recommended. Signer side lives in repo secret `SHOWCASE_OPS_SHARED_SECRET`. |
38+
| `SHARED_SECRET` | Current HMAC secret for `/webhooks/deploy`. 64-hex recommended. Signer side lives in repo secret `SHOWCASE_HARNESS_SHARED_SECRET`. |
3939

4040
**Optional:**
4141

@@ -58,12 +58,12 @@ All read at boot unless marked otherwise. See `showcase/ops/src/orchestrator.ts`
5858

5959
| Secret | Used by |
6060
| ---------------------------- | ------------------------------------------------- |
61-
| `SHOWCASE_OPS_URL` | `notify-ops` step in `showcase_deploy.yml`. |
62-
| `SHOWCASE_OPS_SHARED_SECRET` | Same — paired with the service's `SHARED_SECRET`. |
61+
| `SHOWCASE_HARNESS_URL` | `notify-harness` step in `showcase_deploy.yml`. |
62+
| `SHOWCASE_HARNESS_SHARED_SECRET` | Same — paired with the service's `SHARED_SECRET`. |
6363

6464
## 1.3 Alert rule YAMLs
6565

66-
Location: `showcase/ops/config/alerts/*.yml`. The loader picks up every `.yml`/`.yaml` file except `_defaults.yml`, merges defaults in, compiles each rule through a Zod schema + structural validators, and hot-reloads on file changes (`chokidar`) or SIGHUP.
66+
Location: `showcase/harness/config/alerts/*.yml`. The loader picks up every `.yml`/`.yaml` file except `_defaults.yml`, merges defaults in, compiles each rule through a Zod schema + structural validators, and hot-reloads on file changes (`chokidar`) or SIGHUP.
6767

6868
### File layout
6969

@@ -189,7 +189,7 @@ Dedupe key is `alpha-sorted([rule.id, key, trigger1, trigger2, ...])` joined by
189189

190190
## 1.3a Probe configs
191191

192-
Location: `showcase/ops/config/probes/*.yml`. One YAML per probe. Loaded at startup + hot-reloaded via chokidar + SIGHUP, exactly like alert rules (`probes.reloaded` / `probes.reload.failed` emit on the bus on success/error).
192+
Location: `showcase/harness/config/probes/*.yml`. One YAML per probe. Loaded at startup + hot-reloaded via chokidar + SIGHUP, exactly like alert rules (`probes.reloaded` / `probes.reload.failed` emit on the bus on success/error).
193193

194194
A probe config binds a `kind` (driver) to a `schedule` (cron) and a target shape. At each tick the scheduler calls the driver with one input per target; every driver invocation produces one `ProbeResult` which flows through `writer.write()` → `status.changed` → the alert engine. One YAML = one scheduler entry = N target invocations per tick.
195195

@@ -289,13 +289,13 @@ First resolution per alias per process emits a `slack-webhook.alias-resolved` in
289289

290290
## 1.5 Shared-secret rotation
291291

292-
See `showcase/ops/docs/rotation-drill.md` for the full runbook. Summary: stage `SHARED_SECRET_PREV` = current, set `SHARED_SECRET` = new, rotate GitHub Actions secret `SHOWCASE_OPS_SHARED_SECRET`, drop `PREV` after one full CI cycle confirms the new key works.
292+
See `showcase/harness/docs/rotation-drill.md` for the full runbook. Summary: stage `SHARED_SECRET_PREV` = current, set `SHARED_SECRET` = new, rotate GitHub Actions secret `SHOWCASE_HARNESS_SHARED_SECRET`, drop `PREV` after one full CI cycle confirms the new key works.
293293

294294
---
295295

296296
# Part 2 — Build it, run it, extend it
297297

298-
This section is for anyone touching `showcase/ops/src/` or the Dockerfile.
298+
This section is for anyone touching `showcase/harness/src/` or the Dockerfile.
299299

300300
## 2.1 Architecture
301301

@@ -393,8 +393,8 @@ src/
393393
## 2.3 Local dev
394394
395395
```bash
396-
cd showcase/ops
397-
pnpm install --filter @copilotkit/showcase-ops
396+
cd showcase/harness
397+
pnpm install --filter @copilotkit/showcase-harness
398398
pnpm dev # tsx watch src/orchestrator.ts
399399
400400
# Or just run the built artifact:
@@ -420,13 +420,13 @@ All LLM-adjacent targets (none in this service today, but see `aimock`) should u
420420

421421
## 2.5 Build + deploy
422422

423-
Production runs a single image on Railway, pulled from `ghcr.io/copilotkit/showcase-ops:latest`.
423+
Production runs a single image on Railway, pulled from `ghcr.io/copilotkit/showcase-harness:latest`.
424424

425425
```bash
426426
# 1) Build + push (amd64 is required — Railway runs x86 hosts)
427427
docker buildx build --platform linux/amd64 --push \
428-
-f showcase/ops/Dockerfile \
429-
-t ghcr.io/copilotkit/showcase-ops:latest .
428+
-f showcase/harness/Dockerfile \
429+
-t ghcr.io/copilotkit/showcase-harness:latest .
430430

431431
# 2) Trigger a Railway redeploy pinned to the new digest.
432432
# serviceInstanceDeployV2 forces a fresh snapshot — serviceInstanceRedeploy
@@ -438,13 +438,13 @@ curl -s -X POST https://backboard.railway.com/graphql/v2 \
438438
-d '{"query":"mutation { serviceInstanceDeployV2(serviceId:\"3a14bfed-0537-4d71-897b-7c593dca161d\", environmentId:\"b14919f4-6417-429f-848d-c6ae2201e04f\") }"}'
439439

440440
# 3) Verify
441-
curl -s https://showcase-ops-production.up.railway.app/health
441+
curl -s https://showcase-harness-production.up.railway.app/health
442442
# {"status":"ok","pb":"ok","loop":"ok","rules":8,"schedulerJobs":3}
443443
```
444444

445445
Railway service/environment IDs above are for the `showcase` project's production environment.
446446

447-
There is no CI workflow that auto-builds showcase-ops. Deploys are manual until a build job lands.
447+
There is no CI workflow that auto-builds showcase-harness. Deploys are manual until a build job lands.
448448

449449
## 2.6 Adding things
450450

@@ -464,20 +464,20 @@ There is no CI workflow that auto-builds showcase-ops. Deploys are manual until
464464

465465
- **PocketBase 0.22 auth** — superuser auth uses `/api/admins` (pre-0.23 endpoint); a warn-once log calls this out at boot. Upgrade path: drop the legacy fallback once deployed PB is 0.23+.
466466
- **No integration tests**`test/integration/` and `test/e2e/` dirs exist but are empty. Unit coverage is dense (675 tests across 37 files) but no test hits a live PB or posts a real Slack webhook end-to-end.
467-
- **No auto-build workflow** — push to main does not produce a new `ghcr.io/copilotkit/showcase-ops:latest`; deploys are manual via §2.5.
467+
- **No auto-build workflow** — push to main does not produce a new `ghcr.io/copilotkit/showcase-harness:latest`; deploys are manual via §2.5.
468468
- **`/metrics` is unauthenticated** — intentional, gated by Railway private networking. If the service ever moves to a public mesh, add a scraper token.
469469
- **Bootstrap window is 15m and not env-overridable** — shift requires a code change to `AlertEngineDeps.bootstrapWindowMs`.
470470

471471
## 2.8 Related
472472

473-
- `.github/workflows/showcase_deploy.yml` — sender side of the `/webhooks/deploy` handshake. `notify-ops` step signs and POSTs.
473+
- `.github/workflows/showcase_deploy.yml` — sender side of the `/webhooks/deploy` handshake. `notify-harness` step signs and POSTs.
474474
- `showcase/pocketbase/` — PB image + migrations. Deployed as `showcase-pocketbase` Railway service.
475475
- `showcase/aimock/` — fixture-based LLM mock. The aimock-wiring probe checks that every showcase package routes through it.
476-
- `showcase/ops/docs/rotation-drill.md` — secret rotation.
476+
- `showcase/harness/docs/rotation-drill.md` — secret rotation.
477477

478478
## 2.9 Legacy cron workflows — where their logic lives now
479479

480-
The four legacy GitHub Actions cron workflows (`showcase_smoke-monitor`, `showcase_drift-detection`, `showcase_drift-report`, `showcase_redirect-report`) are replaced by in-process probes driven by showcase-ops. Each legacy workflow lane maps to one YAML probe config + one driver in `src/probes/drivers/`:
480+
The four legacy GitHub Actions cron workflows (`showcase_smoke-monitor`, `showcase_drift-detection`, `showcase_drift-report`, `showcase_redirect-report`) are replaced by in-process probes driven by showcase-harness. Each legacy workflow lane maps to one YAML probe config + one driver in `src/probes/drivers/`:
481481

482482
| Legacy workflow | New probe YAML | Driver | Discovery |
483483
| ------------------------------------------ | ----------------------------------------- | ----------------------- | ------------------ |
File renamed without changes.
File renamed without changes.

showcase/ops/config/alerts/agent-red-tick.yml renamed to showcase/harness/config/alerts/agent-red-tick.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ targets:
3030
- kind: slack_webhook
3131
webhook: oss_alerts
3232

33-
# errorDesc is pre-sanitized in showcase/ops/src/probes/drivers/sanitize.ts
33+
# errorDesc is pre-sanitized in showcase/harness/src/probes/drivers/sanitize.ts
3434
# — triple-brace intentional so literal characters survive to Slack.
3535
template:
3636
text: |
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)