Commit Graph

18 Commits

Author SHA1 Message Date
Mark 1351fa63d2 fix(showcase): apply durable worker policy in staging 2026-08-24 17:59:22 -07:00
Mark fc14045c0a fix(showcase): register CrewAI flows production instance 2026-08-20 17:06:09 -07:00
Ran Shem Tov 12cf10b9c7 feat(showcase): deploy CrewAI conversational flows to staging 2026-08-14 16:05:40 -07:00
Jordan Ritter ce0ea8bd20 test(showcase): update SSOT tests for dual-env prod harness-workers
The prod harness-workers backfill (e88d01a) inverts the old
"harness-workers is staging-only" invariant. Update the 8 stale
assertions across 3 test files that still encoded staging-only,
deriving the new expected values from the SSOT (railway-envs.ts) and
the regenerated railway-envs.generated.json:

- healthcheckPathFor/emit healthcheckPath: prod now /health (was undefined/omitted)
- repoNameFor(prod): now resolves showcase-harness (was throw)
- envsFor: now [prod, staging] (was [staging])
- the worker-shape test: dual-env, domainless+probe-disabled in BOTH
  envs, gateValidated:true / gateIgnore dropped (per SSOT)
- computePromoteClosure: harness-workers now Tier-1 promoted, not
  skipped; the always-Tier-1 set no longer filters it out
- expandImageConsumers(prod) / default prod redeploy scope (39->40):
  the dual-env worker now joins the prod showcase-harness redeploy scope
2026-06-25 23:05:18 -07:00
Jordan Ritter 27dcf4a404 fix(showcase): promote strands-typescript to production (dual-env SSOT)
The showcase-strands-typescript integration was staging-only: it had no
production Railway serviceInstance, so the prod D6 dashboard column showed
a uniform false-red (every cell errorClass=goto-error, backendUrl="") —
the probe navigated a bare relative path because the harness had no prod
health record / backendUrl to discover.

Provisions the prod serviceInstance (8a50728e-6119-43c4-b59c-d9535b6717a4,
domain showcase-strands-typescript-production.up.railway.app, healthcheck
/api/health, image pinned to the GHCR @sha256 digest, OPENAI_BASE_URL at
prod aimock) and brings the SSOT to the dual-env showcase-strands shape:

- railway-envs.ts: add the prod env entry with the real instanceId,
  gateValidated:true, drop gateIgnore, remove the legacyJsonCompat
  prod-domain placeholder.
- railway-envs.generated.json: regenerated (prod instanceId/domain, probe.prod
  true, prod healthcheck; moved into the promote closure, tier 2).
- railway-envs.golden.json: regenerated to include the new prod (service,env)
  pair (intentional behavior change, not a refactor regression).
- showcase_promote.yml: dropdown regenerated to list strands-typescript.
- verify-railway-image-refs.test.ts / redeploy-env.test.ts: update the
  gateValidated/scope counts (39->40 gate targets, prod default 38->39) and the
  now-stale staging-only comments.

RED->GREEN (live prod): BEFORE /api/health 404, prod PocketBase
health:strands-typescript totalItems:0, the 3 named D6 cells all
errorClass=goto-error backendUrl="". AFTER /api/health 200, prod PocketBase
health:strands-typescript present (status:200, valid url),
verify-railway-image-refs OK 80 instances.
2026-06-25 13:22:31 -07:00
Ran Shem Tov d6f618dc03 fix(showcase): make default redeploy scope env-aware for staging-only services
The strands-typescript SSOT entry is ciBuilt:true but staging-only (prod
instance not yet provisioned). redeploy-env.ts's default scope was the full
CI_BUILT_SERVICES set for BOTH envs, so a staging-only ciBuilt service would
wrongly enter the prod default scope and fail a manual `redeploy-env.ts prod`
(no prod instance). Filter the default scope by env declaration (explicit
--services stays unfiltered, preserving the contract-pin that an operator can
force a named service in an env it does not declare). imageOf expansion was
already env-aware; this extends the same invariant to the base scope.

Update the inventory-lock test counts for the new service (total 40->41,
CI_BUILT 38->39, staging default scope 39->40; prod default scope stays 38 as
the staging-only service is now correctly excluded).
2026-06-24 19:54:49 +02:00
Jordan Ritter 808bc4741d feat(showcase): promote-closure SSOT (tiers/runtimeDeps/serviceRefs) + computePromoteClosure + 12 starter entries + oxfmt-canonical emit 2026-06-19 12:23:22 -07:00
Jordan Ritter 2e675a7bdd docs(showcase): correct webhooks-bounce/imageOf/serviceEnvPairs claims, test hygiene (redeploy scripts)
The webhooks SSOT comment claimed the push-driven default scope is
"guaranteed" to leave webhooks untouched — false: a push touching the
build workflow files trips the workflow_config paths-filter disjunct,
which selects every matrix slot (webhooks included; its skip_build slot
still reports success and enters the redeploy CSV). Reworded to state
the actual behavior. imageOf doc now states the enforced NON-EMPTY
subset constraint; serviceEnvPairs doc now truthfully says it has no
consumers yet; file header notes the probe flag default and
bin/railway's Ruby-only "stage" synonym.

Test hygiene: drop the stale bin/railway line-number citation from a
test name, the _envConfigTypeAnchor (EnvironmentConfig is genuinely
referenced by the shape-compile test), a dead eslint-disable, and a
dead `as never` cast (env is an open string); align the webhooks
dispatch-name pin regex with the extraction regex's whitespace
tolerance.
2026-06-10 09:28:10 -07:00
Jordan Ritter a0ef5e7ef2 fix(showcase): close env-registry cross-wire/orphan/case/prototype gaps, trim REDEPLOY_SUMMARY_JSON
assertEnvRegistryConsistent gains four clauses: (iv) a key present in
both ENV_IDS and ENV_ID_BY_NAME must carry the same env-id (ENV_IDS.prod
drifted to the staging id previously passed every clause while
resolveEnv("prod") silently returned staging); (v) every ENV_IDS env-id
must be carried by a canonical name (was only caught lazily in
resolveEnv); (vi) registry keys must be trim().toLowerCase()-normalized
(resolveEnv lowercases input, so a non-lowercase spelling is registered
but unreachable); (vii) no registry key may be an Object.prototype
property name.

expandImageConsumers' per-entry env skip-check becomes an own-property
test (Object.hasOwn) for uniformity with every other lookup in the file.

REDEPLOY_SUMMARY_JSON is trimmed before the set-but-empty branch so a
whitespace-only value hits the loud warn path instead of attempting a
JSON write against a garbage path.
2026-06-10 09:28:09 -07:00
Jordan Ritter 3cf06a7e49 fix(showcase): uniform own-property accessors, new SSOT invariants, fail-loud exit default (redeploy scripts)
- railway-envs: route envsFor/instanceIdFor/domainFor/probeEnabled (and
  repoNameFor) through shared getEntry/getEnvCfg own-property helpers so
  inherited Object.prototype keys on either axis produce the curated
  error (or probeEnabled's contract false) instead of raw TypeErrors,
  silent undefined, or a spurious probe=true.
- railway-envs: two new module-load invariants (synthetic-map
  injectable): assertEnvRegistryConsistent (per-service env keys are
  registered canonical names; ENV_ID_BY_NAME env-ids unique; every
  canonical name has an ENV_IDS spelling) and
  assertServiceAndInstanceIdsUnique (serviceId unique per entry,
  instanceId globally unique).
- redeploy-env: invert the exit-code policy to fail-loud by default —
  any env except the documented staging carve-out exits non-zero on
  per-service failure (a future preview/canary env inherits fatal
  semantics instead of silently swallowing failures).
- redeploy-env: sanitize per-service THROWN error messages through
  sanitizeErrorBody before recording; flatten bare \r in the summary
  table escape.
- redeploy-env: warn on set-but-empty REDEPLOY_SUMMARY_JSON; reject
  flag-like --services CSV parts (both forms) and a flag-like first
  argument (missing env); derive usage env lists from ENV_IDS.
- tests: prototype-key sweep across all accessors, invariant
  positive/negative coverage, third-env exit-code pin, sanitization and
  CLI-guard coverage, makeLiveRedeploy !res.ok and non-true mutation
  branches.
2026-06-10 09:06:55 -07:00
Jordan Ritter bee835c4b0 chore(showcase): SSOT invariant hardening + doc accuracy (redeploy scripts) 2026-06-10 08:28:16 -07:00
Jordan Ritter c71d183247 fix(showcase): unify env-name authority + fail-loud SSOT accessors (redeploy scripts)
Confirmation-CR bucket-(a) fixes for PR #5353 — one coherent concern:
env-name resolution has exactly ONE authority (the ENV_IDS /
ENV_ID_BY_NAME registries) and SSOT accessors fail loud instead of
silently returning wrong values.

- runRedeploy: resolve envId via ENV_ID_BY_NAME with an Object.hasOwn
  guard + fail-loud throw listing the registered envs. Removes the
  hardcoded `prod`/`staging` pair check and PRODUCTION/STAGING ternary
  that contradicted the SSOT's documented open-env contract ("a new env
  needs only a registry entry"); the registry lookup subsumes it.
- resolveEnv: derive resolution entirely from the registries (ENV_IDS
  spellings -> env-id -> canonical ENV_ID_BY_NAME name) instead of its
  own hardcoded synonym chain. Behavior identical for
  prod/production/staging; still throws on unknowns, and now also
  throws on a mis-wired registry (a spelling whose env-id has no
  canonical name).
- serviceForDispatchName: fix the docstring's false "CI-built service"
  claim — it does no ciBuilt filtering and tests pin the unfiltered
  behavior (the non-CI-built webhooks resolves).
- repoNameFor: fail loud (consistent with instanceIdFor/domainFor)
  instead of silently echoing the service name — the exact
  silently-wrong-GHCR-name class this PR's hardening targets. Throws on
  unknown service, on an env not registered in ENV_ID_BY_NAME
  (unnormalized synonyms like "production"), and on a registered env
  the service does not declare. Keeps the documented default (the
  service name) for declared envs without an override.
  Call-site enumeration confirming nothing relies on the old fallback:
    - verify-railway-image-refs.ts:523 — iterates the entry's DECLARED
      environments keys, registry-filtered, SSOT-matched service names
    - __tests__/railway-envs.golden.test.ts:81 — iterates envsFor(name)
      (declared envs only) over real SSOT keys
    - railway-envs.test.ts repoNameFor cases — dual-env services,
      prod/staging only
    - __tests__/verify-railway-image-refs.test.ts:264 — FIVE_NEW keys,
      all dual-env
- resolveTargetServices: throw when an explicitly-provided services
  list resolves to zero entries (whitespace-only programmatic input)
  instead of letting runRedeploy exit 0 having redeployed nothing; the
  default undefined -> full CI-built scope is unchanged.
- makeLiveRedeploy: add signal: AbortSignal.timeout(30s) so a hung
  Railway API records a per-service FAIL instead of stalling CI, and
  pass GraphQL errors[].message through sanitizeErrorBody for
  consistency with the HTTP-error path. Exported for direct unit tests.

Red-green: 11 new tests (open-env registry resolution incl. a
runtime-registered hypothetical env, repoNameFor negatives,
empty-resolution throw, abort-signal presence, GraphQL error
sanitization) all failed against the old code; full showcase/scripts
suite green (50 files, 1807 tests) + tsc --noEmit clean.
2026-06-10 08:28:16 -07:00
Jordan Ritter 0b097d0c89 fix(showcase): fail loud on unnormalized env in expandImageConsumers; prune redundant assertions 2026-06-09 18:17:21 -07:00
Jordan Ritter 26a43a794f fix(showcase): reject prototype-key service names; sync redeploy scope docs 2026-06-09 18:09:01 -07:00
Jordan Ritter 58c655beee docs(showcase): correct stale redeploy default-scope claims; stub summary env in tests 2026-06-09 17:52:16 -07:00
Jordan Ritter 2af5d691ef fix(showcase): redeploy image consumers (harness-workers) when their shared image is rebuilt
harness-workers runs the SAME showcase-harness GHCR image as the harness
scheduler but has ciBuilt:false (it has no build slot of its own), and the
CI staging redeploy scope was derived purely from ciBuilt — so a main-merge
rebuild of showcase-harness:latest only bounced the scheduler while the
workers silently kept running the stale image (PR #5352's worker-side fixes
never reached staging).

Model image consumption explicitly in the SSOT instead:

- railway-envs.ts: new optional `imageOf` field on ServiceEntry — the SSOT
  key of the ciBuilt service whose image this entry runs. Set
  `imageOf: "harness"` on harness-workers. New module-load invariant
  `assertImageConsumersValid` (fail-loud, same style as
  assertDispatchNamesUnique): imageOf must name an existing SSOT key, the
  target must be ciBuilt, and the consumer itself must not be ciBuilt.
- redeploy-env.ts: new `expandImageConsumers(names, env)` applied inside
  runRedeploy — the redeploy set becomes the resolved scope PLUS any
  service whose imageOf points at a service already in scope. Env-aware:
  a consumer only joins envs it declares, so the staging-only worker
  never enters a prod redeploy (prod behavior unchanged).

No workflow change needed: showcase_build.yml keeps passing the
built-and-successful dispatch_names; the script expands them. Gate
behavior (gateIgnore / image-ref gate), the generated JSON
(emit --check passes byte-identical), and the promote dropdown are all
untouched. harness-legacy deliberately gets no imageOf (pinned pre-fleet
digest; must not follow rebuilds).
2026-06-09 17:40:41 -07:00
Jordan Ritter 3c138ec450 ci(showcase): build & push the PocketBase image from main
PocketBase had no CI build path: `ghcr.io/copilotkit/showcase-pocketbase`
was a stale April `:latest`, and there was no way to ship pb_migrations /
pb_hooks changes without an ad-hoc manual build. Add a `pocketbase` slot to
showcase_build.yml's build matrix, mirroring the harness/aimock entries:
  - dispatch_name `showcase-pocketbase`, context `showcase/pocketbase`, its
    own Dockerfile, health `/api/health`, railway_id from the SSOT.
  - a paths-filter key gated to `showcase/pocketbase/**` so the slot only
    rebuilds when PB's own files change (the image is self-contained — no
    shared-module copy), not on every showcase push.
  - the workflow_dispatch service choice so PB is human-targetable.

Flip the SSOT entry (railway-envs.ts) to `ciBuilt: true` with
`dispatchName: "showcase-pocketbase"` so it is built+pushed (`:sha` +
`:latest`) and joins the default staging-redeploy scope; the build's
redeploy step only touches the matrix-intersect-success set, so PB still
only redeploys when its own files change. Regenerate
railway-envs.generated.json and the showcase_promote.yml service dropdown,
and update the SSOT/redeploy tests that pinned PB as out-of-band
(CI_BUILT_SERVICES 25 -> 26; webhooks stays the only non-CI-built service).
2026-06-04 12:23:05 -07:00
Jordan Ritter 7fad3c119d feat(showcase): add redeploy-env.ts for explicit per-env Railway redeploys
Resolves dispatchName/SSOT keys to service IDs and calls serviceInstanceRedeploy.
Default scope is the 25 CI-built services (never pocketbase/webhooks). Staging
failures are non-blocking (exit 0); prod failures exit 1. Config errors fail loud.
2026-05-29 11:45:02 -07:00