(motir-core) `main` has not deployed since 2026-09-01 20:53 — MOTIR-4094 promoted two specs into a lane whose port and whose mock registration order they were never written for
Opened by Zhu Yue ·
Deploy to Fly is gated on CI complete. Playwright E2E at-scale (billing-cloud) has failed on every push to main since MOTIR-4094 merged, so the deploy has been skipped three times running and production is serving f57739b20 (2026-09-01 20:53) while main is four commits ahead. The hourly Deploy freshness schedule has been red since 22:00 that night.
Last green deploy: run 33557965931. Red since: 33559672591, 33614732025, and counting.
Two tests fail, deterministically, both retries, on every run. Both are consequences of the same promotion, and neither is a flake — MOTIR-4124 merged in the same window and was the obvious suspect, but it is exonerated: it never touches the ask path.
1 · cloud-public-redirect.spec.ts — a hard-coded lane port
The spec was written for the acceptance lane and hard-codes its origin:
const APP = 'http://localhost:3200';
MOTIR-4094 renamed it acceptance-public-redirect → cloud-public-redirect, which moves it under playwright.cloud.config.ts (testMatch: '**/cloud-*.spec.ts') — a lane that serves on 3100. Every request dies connect ECONNREFUSED ::1:3200. It is the only promoted spec carrying a literal port.
2 · cloud-ask-about-this-project.spec.ts — two seams claiming one undici path
The cloud lane is the only lane that sets both E2E_TEST_LESSONS=1 and E2E_TEST_AI_JOBS=1. instrumentation.ts installs the lessons seam (entry 5) before the jobs seam (entry 6), and undici matches interceptors in registration order — so lib/test-lessons-mock.ts wins all three /v1/jobs paths on the MOTIR_AI_URL origin:
| path | lessons seam answers | what the ask journey needs |
|---|---|---|
POST /v1/jobs | { jobId: 'job_lessons_e2e' } | e2e-ask_project-<n> — the id carries the kind |
GET /v1/jobs/:id/stream | succeeded | the real frame vocabulary |
GET /v1/jobs/:id | result: { operations: [] } | result.ask.{intent,answer,citations} |
aiAskService.settle cannot read an outcome out of { operations: [] }, returns { outcome: 'silent' }, and PlanChangeRail renders ASK_SILENT — "Nothing came back. Try asking that a different way." — which is exactly what the failure artifact's page snapshot shows. The mock's own comment claims it wins "for POST /v1/jobs and the jobs mock still serves everything else"; it also registers the two GETs, so that sentence has never been true.
Nothing caught it because the two flags had never been on in the same lane as this spec before.
Acceptance criteria
- No spec under
tests/e2e/hard-codes an application port; the redirect spec resolves its origin from the lane'sbaseURL, so it followsE2E_BASE_URLtoo. - With
E2E_TEST_LESSONS=1andE2E_TEST_AI_JOBS=1, the jobs seam answers the whole/v1/jobsprotocol and the lessons seam still performs its capture write — split by SUBJECT, not by registration order, so re-orderinginstrumentation.tscannot resurrect this. cloud-ask-about-this-project.spec.tsandcloud-public-redirect.spec.tspass in the cloud lane, and the threecloud-lesson-*.spec.tsspecs (which own the capture assertions) stay green.Deploy to Flyruns on the merge commit.
Out of scope
MOTIR-4093 (the lifecycle guard's missing credential) and the Deploy freshness workflow's own reporting bug — its step runs under bash -e, so report=$(node scripts/assert-deploy-freshness.mjs …) aborts before echo "$report" and the "behind by what, since when" summary it exists to write is empty on exactly the runs that need it. Its own card.
Discussion
No comments yet.
Adding to this discussion signs you in on app.motir.co and brings you back to this request.