Skip to content

Commit dfe85c9

Browse files
ci(live-e2e): boot the workspace backend and run the live lane as the required Live E2E UI job (#27212)
Fixes #27154 Clause-②: no Metadata-protocol: none ## 维护者速读 - **改了什么:** live e2e 四条 spec 改为用本树工作区自建的 `@objectstack/cli` 启动 `examples/app-showcase` 后端(HEAD console 对 HEAD backend),已发布版本钉退役;`ci.yml` 新增 `Live E2E UI` job,并登记进 `REQUIRED_CONTEXTS`。 - **为什么改:** 按已发布版本钉后端,每次发版都得同步抬钉,否则 `ui/` 的 PR 全红(#25914 实测 18.1.0 下 0/5);裁决 6464191239 字母 D 第 2 步要求改为工作区后端后再升为 required。 - **风险与回滚:** Tier H(`.github/workflows/ci.yml`、`AGENTS.md`);回滚 = 还原本 PR(job、注册行、两处名单文字、两个脚本)。新 job 超时上限 40 分钟由一次本地冷跑推得,首批 CI 数据后需复核。 - **先看:** `ui/e2e/live/ci/start-backend.sh`(prepare 只校验构建产物、不再拉包)→ `ci.yml` 的 `live-e2e-ui` job → `scripts/check-required-contexts.mjs` 新注册行。 - **两分钟验证:** 打开本 PR 的 checks,`Live E2E UI` 应为绿色,日志 “Run the live e2e specs” 一步显示 `5 passed`。 - **需要你做的:** 合并后在 `main` 的 ruleset 里把 `Live E2E UI` 勾为 required(席位做不了)。 ## What changes - `ui/e2e/live/ci/start-backend.sh` boots the WORKSPACE backend: this tree's built `@objectstack/cli` (through `examples/app-showcase/node_modules/.bin/objectstack`) runs `objectstack dev --seed-admin --fresh -p $LIVE_BACKEND_PORT` from the checked-out showcase. Same default port (4010), same seeded sign-in readiness poll (300 s), same pid file, so `stop-backend.sh` is unchanged and its PID contract holds. `prepare` no longer resolves a release tag, sparse-checks-out a release or `npm install`s published tarballs; it checks the build prerequisite (the app's config, the installed CLI bin, `packages/cli/dist/index.js`) and refuses by name with the build command when one is missing. The vitest override and the stamp retire with the install. - `ui/e2e/live/ci/backend.env` declares `LIVE_BACKEND_APP=examples/app-showcase` and no published pin; its comment records why `OBJECTSTACK_VERSION` retired. - `.github/workflows/ci.yml` adds `live-e2e-ui` / `Live E2E UI`: install, build the CLI + showcase closure and the seven packages the Console builds against, `vite build` the Console with `VITE_BASE_PATH=/`, provision Chromium through `ensure-chromium-ready.sh`, boot the backend, serve `vite preview` on :5190 with `DEV_PROXY_TARGET=http://localhost:4010`, and run `pnpm --dir ui run test:e2e:live:ci --retries 0`. Triggers: the workflow's existing `pull_request` and `merge_group` (plus push/schedule, as every job in the file). `if:` is Build & E2E UI's condition verbatim (`ui_tree`, `ui || ui_consumers`, with `!cancelled()`). No `continue-on-error`, no retry wrapper, no spec edited or skipped. Caches are restore-only (pnpm store, Build Core's turbo seed, the Playwright browsers Build & E2E UI saves). - `scripts/check-required-contexts.mjs`: a `REQUIRED_CONTEXTS` row for `ci.yml:live-e2e-ui → 'Live E2E UI'`, and the name added to the two `statesTheSet` instruction surfaces' `mustName`; `AGENTS.md` (nine → ten contexts) and `.claude/skills/pm-dispatch/references/platform-readings.md` (九个 → 十个) name it. - `ui/scripts/__tests__/ensure-chromium-ready.test.ts` reads the new job as a second Chromium provisioner (its comment said `live-e2e.yml` "comes back here with that port"); `helpers/root-ci.ts` exports the job id as `UI_LIVE_E2E_JOB`, outside `UI_JOBS`. - `docs/agents/multi-agent-discipline.md` (advisory checks ride through) now counts ten required contexts, and the `ci.yml` `filter` job comment counts five `* UI` jobs (Type Check UI, Test UI, Lint UI, Build & E2E UI and Live E2E UI). ## Tests Measured before wiring, on the workspace boot, at commit `7a48258d` (the re-shaped scripts; base `2f96d874`). Setup: `pnpm install --frozen-lockfile`; turbo build of the CLI + showcase closure and the seven Console packages (65/65 tasks, 384 s cold under the shared-box lock); `VITE_BASE_PATH=/ vite build` of `ui/apps/console` (119 s); `start-backend.sh` exit 0, ready in 19 s (`@objectstack/cli 18.2.0` workspace); `vite preview --port 5190` with `DEV_PROXY_TARGET=http://localhost:4010`; `LIVE_API_URL=http://localhost:4010`, `LIVE_APP_URL=http://localhost:5190`; one backend for all five runs, as one CI job boots once. | Run | Exit | Wall (s) | action-modal | master-detail: populated parent | master-detail: task line | saved-view-filter | screen-flow | |---|---|---|---|---|---|---|---| | 1 | 0 | 26 | pass | pass | pass | pass | pass | | 2 | 0 | 23 | pass | pass | pass | pass | pass | | 3 | 0 | 22 | pass | pass | pass | pass | pass | | 4 | 0 | 23 | pass | pass | pass | pass | pass | | 5 | 0 | 21 | pass | pass | pass | pass | pass | 5/5 runs green, 5/5 tests per run; Playwright's own totals 24.1 s / 20.5 s / 20.7 s / 21.2 s / 19.9 s. Wall times are shared-box seconds. Teardown: `stop-backend.sh` stopped the recorded pid; the preview processes I started were stopped by pid. Derived gates (`node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` at `191e9d5e`, after merging `origin/main`): 87 commands, each exit captured before any pipe. 85 exit 0, including `pnpm check:required-contexts` (lists `ci.yml:live-e2e-ui → 'Live E2E UI'`), `check:workflow-status-functions`, `check:stall-guard-budget`, `check:pm-expected-skips`, `check:aggregator-roster`, `check:bash32-floor`, `check:ci-filter-parity`, `check:pm-skill-ratchet`, and `pnpm --dir ui exec vitest run scripts/` (175 files passed, 2 skipped; 5020 tests passed). Two did not measure the diff: `check:dual-build-cjs-loads` exit 3 (PREREQUISITE NOT MET: no full `pnpm build` here) and `check:dts-closure` exit 1, which named only `ui/apps/console/plugin.d.ts`, missing from the `dist/` my bare `vite build` left behind; with that ignored directory removed it exits 0 (233/233 declaration files present). `--ran` with exit codes: 87 derived, 86 run, 1 NOT-MEASURED (the exit 3). No package changes, so no changeset (`skip-changeset`). On head `3f0b396f` (the text patch round): `CI` pull_request run 40678137074; `Live E2E UI` (job 122782123641) concluded success in 87 s of job wall time (Console build 11 s, backend boot 10 s, specs 18 s). ## Acceptance notes - **The one step left is the maintainer's:** add `Live E2E UI` to the `main` ruleset's required status checks, in the same sitting as the merge (#9325 two-step). Until then `--verify-required-set` reports the row in direction A (pinned, not required), report-only. - Ceiling `timeout-minutes: 40` is derived from one cold local run (≈730 s ⇒ max(36.5, 27.2) ⇒ 40, the rule above Lint UI), since the job has no CI population yet; the derivation sits beside the job and asks to be re-derived from the first population. Follow-up: #27228 (re-derive from at least 20 CI runs and pin it in `turbo-cache-save-bound.test.ts`). - The gate is Build & E2E UI's, as the card asks: a PR that changes only backend packages outside `ui/` and the seven `ui_consumers` packages (for example `packages/runtime`) skips this job, so a backend regression that breaks the live specs surfaces on the next `ui` PR or on `main`'s push run. Recorded, not widened. - Not edited (claim: no spec edited): the header of `ui/e2e/live/saved-view-filter.spec.ts` still describes the retired `OBJECTSTACK_VERSION` pin. Follow-up: #27228. - `vite preview` runs in the background for the rest of the job and is reaped by the runner at job end; the backend is stopped by `stop-backend.sh` under `if: always()`. ## Verification Read this PR's `Live E2E UI` check: steps "Boot the workspace backend" (ends `ready: seeded sign-in answered on :4010`) and "Run the live e2e specs" (ends `5 passed`). --- _Generated by [Claude Code](https://claude.ai/code/session_01QSeKYoUcDM1MUzjdaCjt6U)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 2d05cd4 commit dfe85c9

9 files changed

Lines changed: 292 additions & 219 deletions

File tree

‎.claude/skills/pm-dispatch/references/platform-readings.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,9 +385,9 @@
385385
- 强制档不因临缺授权降档:临缺非退役,退役唯维护者裁;不达档起隔离达档子代理或等档。
386386
- 本车道强制多是过宽的回忆:`dispatch-gates.mjs --tier PATH` 逐路径现推,路径线是下限非放行。
387387
- 该脚本只答自己那棵树:姊妹仓路径回 absent from this tree,姊妹仓的档位与条款②只能手推。
388-
- required checks 的名单是每仓事实,objectstack 九个:
388+
- required checks 的名单是每仓事实,objectstack 十个:
389389
`TypeScript Type Check` · `Lint & Repo Gates` · `Test Core` · `Build Core` · `Lint UI` ·
390-
`Governed Surface Queue Guard` · `Type Check UI` · `Test UI` · `Build & E2E UI`。
390+
`Governed Surface Queue Guard` · `Type Check UI` · `Test UI` · `Build & E2E UI` · `Live E2E UI`。
391391
- ⭐ 本表的 `mustName` 声明 `statesTheSet` ⇒ 必须逐字等于注册表,加注册行不跟改本表即红。
392392
- ⇒ 门绿即名单逐字齐全的读数;⛔ 但数量词未钉:实测 七→六 照绿,只能手跟改。
393393
- ⛔ 聚合命令同样不作判定:`check:type-check-debt` 可在包级 typecheck 绿时红。

‎.github/workflows/ci.yml‎

Lines changed: 182 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ jobs:
162162
# filter below and the `test` job's `if:` (#9829, #10015).
163163
crosspkg: ${{ github.event_name != 'merge_group' && steps.changes.outputs.crosspkg || 'true' }}
164164
# The objectui tree under `ui/` (objectstack#25677). Three outputs, read
165-
# together by the four `* UI` jobs at the bottom of this file:
165+
# together by the five `* UI` jobs at the bottom of this file (Type Check
166+
# UI, Test UI, Lint UI, Build & E2E UI and Live E2E UI):
166167
# ui — a path under ui/, a root file the ui jobs build from
167168
# (the lockfile, the workspace, turbo.json), or a root
168169
# the ui gates read (every root workflow, the prompts,
@@ -175,7 +176,7 @@ jobs:
175176
# On merge_group `ui` and `ui_consumers` come from the queue diff
176177
# (objectstack#25867): an entry whose merged diff against
177178
# `merge_group.base_sha` touches no ui path and none of the seven
178-
# packages skips the four ui jobs, exactly as the same diff does on its
179+
# packages skips the five ui jobs, exactly as the same diff does on its
179180
# PR head; an entry that touches one runs them. If the step fails (the
180181
# base cannot be fetched, the diff errors), it is `continue-on-error`
181182
# there, its outputs are empty and `|| 'true'` runs every ui job.
@@ -4448,6 +4449,185 @@ jobs:
44484449
path: ~/.cache/ms-playwright
44494450
key: playwright-${{ runner.os }}-${{ steps.playwright-version.outputs.version }}
44504451

4452+
# ── Live E2E UI: the Console against a real backend (#27154) ─────────────
4453+
# Row 17 of the objectstack#25697 workflow roster, objectui's `live-e2e.yml`,
4454+
# "kept, follow-up port": it has run nowhere since #26058 deleted
4455+
# `ui/.github/workflows/`. Ruling 6435339772 Q1 A made it required; ruling
4456+
# 6464191239 letter D re-based it on the WORKSPACE backend, so it runs the
4457+
# HEAD Console against the HEAD backend and no published version is pinned
4458+
# anywhere (`ui/e2e/live/ci/backend.env` says why the pin retired).
4459+
#
4460+
# What it runs: the four allowlisted live specs, `test:e2e:live:ci`, with
4461+
# `--retries 0` (the config's own value, stated again on the command line),
4462+
# against `objectstack dev --seed-admin --fresh` serving `examples/app-showcase`
4463+
# from this tree's own built CLI (`ui/e2e/live/ci/start-backend.sh`) and the
4464+
# Console's production build served by `vite preview`, whose `/api` proxy
4465+
# (the Console's `server.proxy`, which preview inherits) points at that
4466+
# backend through DEV_PROXY_TARGET. ⛔ No retry wrapper and no
4467+
# `continue-on-error` anywhere in this job: a red run is a red check.
4468+
#
4469+
# Gated as Build & E2E UI is. Not behind Build UI Deps: this job builds a
4470+
# larger closure (the CLI and the showcase app's) than the seven packages that
4471+
# job hands on, so it restores Build Core's turbo seed instead.
4472+
#
4473+
# Ceiling: there is no CI population yet, so it is derived from one cold
4474+
# local run on 4 shared cores (#27154, 2026-10-28), by the rule above Lint UI:
4475+
# install 60 s + closure build 384 s + Console build 119 s + backend boot
4476+
# 19 s + specs 26 s + browser provisioning and setup ~120 s ≈ 730 s
4477+
# (12.2 min) => max(36.5, 27.2) => 40. Re-derive from the first population.
4478+
live-e2e-ui:
4479+
name: Live E2E UI
4480+
needs: filter
4481+
if: ${{ !cancelled() && needs.filter.outputs.ui_tree != 'false' && (needs.filter.outputs.ui != 'false' || needs.filter.outputs.ui_consumers != 'false') }}
4482+
runs-on: ubuntu-latest
4483+
timeout-minutes: 40
4484+
permissions:
4485+
contents: read
4486+
env:
4487+
# The Console's build OOMs at Node's default heap (see Build & E2E UI).
4488+
NODE_OPTIONS: --max-old-space-size=4096
4489+
# LIVE_BACKEND_DIR is set on the two steps that run the scripts: the
4490+
# `runner` context is not available in a job-level `env:`, and a
4491+
# workflow that names it there does not validate at all.
4492+
LIVE_BACKEND_PORT: '4010'
4493+
LIVE_API_URL: http://localhost:4010
4494+
LIVE_APP_URL: http://localhost:5190
4495+
4496+
steps:
4497+
- name: Checkout repository
4498+
uses: actions/checkout@v7
4499+
4500+
- name: Setup Node.js
4501+
uses: actions/setup-node@v7
4502+
with:
4503+
node-version-file: .nvmrc
4504+
4505+
- name: Setup pnpm
4506+
uses: ./.github/actions/setup-pnpm
4507+
4508+
- name: Get pnpm store directory
4509+
shell: bash
4510+
run: |
4511+
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
4512+
4513+
# Restore only, here and below: Build UI Deps saves the store and Build
4514+
# Core the turbo seed.
4515+
- name: Restore pnpm cache
4516+
uses: actions/cache/restore@v6
4517+
with:
4518+
path: ${{ env.STORE_PATH }}
4519+
key: ${{ runner.os }}-pnpm-store-v3-${{ hashFiles('**/pnpm-lock.yaml') }}
4520+
restore-keys: |
4521+
${{ runner.os }}-pnpm-store-v3-
4522+
4523+
- name: Restore Turbo cache
4524+
uses: actions/cache/restore@v6
4525+
with:
4526+
path: .turbo/cache
4527+
key: ${{ runner.os }}-turbo-build-core-${{ github.ref_name }}-${{ github.sha }}
4528+
restore-keys: |
4529+
${{ runner.os }}-turbo-build-core-${{ github.ref_name }}-
4530+
${{ runner.os }}-turbo-build-core-
4531+
4532+
- name: Install dependencies
4533+
run: pnpm install --frozen-lockfile
4534+
4535+
# The backend's closure (the CLI and the showcase app, the `pkg...` form
4536+
# Dogfood Verify CLI uses) plus the seven packages the Console builds
4537+
# against, the same filters as Build & E2E UI's build step.
4538+
- name: Build the workspace backend and the @objectstack packages objectui consumes
4539+
run: |
4540+
pnpm exec turbo run build --concurrency=4 \
4541+
--filter=@objectstack/cli... \
4542+
--filter=@objectstack/example-showcase... \
4543+
--filter=@objectstack/spec... \
4544+
--filter=@objectstack/client... \
4545+
--filter=@objectstack/core... \
4546+
--filter=@objectstack/formula... \
4547+
--filter=@objectstack/lint... \
4548+
--filter=@objectstack/sdui-parser... \
4549+
--filter=@objectstack/types...
4550+
4551+
# Served at the root, where the live specs navigate.
4552+
- name: Build the Console for the live lane
4553+
env:
4554+
VITE_BASE_PATH: /
4555+
run: pnpm --dir ui/apps/console exec vite build
4556+
4557+
- name: Get the Playwright version
4558+
id: playwright-version
4559+
run: |
4560+
set -eo pipefail
4561+
if ! version=$(pnpm --dir ui list @playwright/test --depth=0 --json | jq -r '.[0].devDependencies["@playwright/test"].version'); then
4562+
echo "::error::Reading the @playwright/test version failed (pnpm list --json | jq). Refusing to write a Playwright browser cache key from it."
4563+
exit 1
4564+
fi
4565+
if [ -z "$version" ] || [ "$version" = "null" ]; then
4566+
echo "::error::Could not resolve the @playwright/test version (got: '${version}'). Refusing to write an empty or null version into the Playwright browser cache key."
4567+
exit 1
4568+
fi
4569+
echo "version=$version" >> "$GITHUB_OUTPUT"
4570+
4571+
# Build & E2E UI saves this key; this job only reads it.
4572+
- name: Restore Playwright browsers
4573+
id: playwright-cache
4574+
uses: actions/cache/restore@v6
4575+
with:
4576+
path: ~/.cache/ms-playwright
4577+
key: playwright-${{ runner.os }}-${{ steps.playwright-version.outputs.version }}
4578+
4579+
- name: Install Playwright browsers
4580+
if: steps.playwright-cache.outputs.cache-hit != 'true'
4581+
run: pnpm --dir ui exec playwright install chromium
4582+
4583+
- name: Ensure Chromium can launch
4584+
working-directory: ui/scripts
4585+
run: bash ensure-chromium-ready.sh
4586+
4587+
- name: Boot the workspace backend
4588+
env:
4589+
LIVE_BACKEND_DIR: ${{ runner.temp }}/live-backend
4590+
run: bash ui/e2e/live/ci/start-backend.sh
4591+
4592+
# In the background for the rest of the job; the runner reaps it at job
4593+
# end. Ready = the Console's index answers through the preview server.
4594+
- name: Serve the Console with vite preview
4595+
env:
4596+
DEV_PROXY_TARGET: http://localhost:4010
4597+
run: |
4598+
cd ui/apps/console
4599+
nohup pnpm exec vite preview --port 5190 --strictPort > "$RUNNER_TEMP/vite-preview.log" 2>&1 &
4600+
deadline=$((SECONDS + 60))
4601+
until curl -sf -o /dev/null http://localhost:5190/; do
4602+
if [ "$SECONDS" -ge "$deadline" ]; then
4603+
echo "::error::vite preview did not answer on :5190 within 60 s."
4604+
cat "$RUNNER_TEMP/vite-preview.log"
4605+
exit 1
4606+
fi
4607+
sleep 1
4608+
done
4609+
echo "vite preview answers on :5190, proxying /api to :4010."
4610+
4611+
- name: Run the live e2e specs
4612+
run: pnpm --dir ui run test:e2e:live:ci --retries 0
4613+
4614+
- name: Stop the workspace backend
4615+
if: ${{ always() }}
4616+
env:
4617+
LIVE_BACKEND_DIR: ${{ runner.temp }}/live-backend
4618+
run: bash ui/e2e/live/ci/stop-backend.sh
4619+
4620+
- name: Upload failure artefacts
4621+
if: ${{ !cancelled() && failure() }}
4622+
uses: actions/upload-artifact@v7
4623+
with:
4624+
name: ui-live-e2e-failure-artifacts
4625+
path: |
4626+
ui/test-results/
4627+
${{ runner.temp }}/live-backend/backend.log
4628+
${{ runner.temp }}/vite-preview.log
4629+
retention-days: 14
4630+
44514631
# ── UI Published Artifacts: two objectui gates over a full build (#26717) ─
44524632
# Rows 23 and 21 of the objectstack#25697 workflow roster, "kept, follow-up
44534633
# port" (objectui's published-dist-gate.yml and node-esm-load-gate.yml), both

‎AGENTS.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -503,11 +503,11 @@ Even inside your own worktree, operate defensively:
503503
yet"; `in_progress` is not a pass, and arming a red PR hides it
504504
([why](docs/agents/multi-agent-discipline.md#arming-a-red-pr-hides-it)). Always read *two* things:
505505
the queue branch **and** `origin/main`. And **the queue enforces only the required
506-
set** — nine contexts block: `Lint & Repo Gates` (all `check:*` gates), `TypeScript Type Check`,
507-
`Test Core`, `Build Core`, `Governed Surface Queue Guard`, `Lint UI`, `Type Check UI`, `Test UI`
508-
and `Build & E2E UI`; a check outside those nine is advisory
506+
set** — ten contexts block: `Lint & Repo Gates` (all `check:*` gates), `TypeScript Type Check`,
507+
`Test Core`, `Build Core`, `Governed Surface Queue Guard`, `Lint UI`, `Type Check UI`, `Test UI`,
508+
`Build & E2E UI` and `Live E2E UI`; a check outside those ten is advisory
509509
([why that matters](docs/agents/multi-agent-discipline.md#advisory-checks-ride-through)). A required context is
510-
matched by check-run name, so a rename detaches its gate silently — treat those nine names as contract.
510+
matched by check-run name, so a rename detaches its gate silently — treat those ten names as contract.
511511
**Two speeds** — PR and queue runs carry the fast set; `main`'s scheduled and push runs carry the full
512512
battery ([detail](docs/agents/multi-agent-discipline.md#two-speeds-which-runs-carry-which-battery)).
513513
**Main-red:** a full-battery red is its lane's first work — triage files it under

‎docs/agents/multi-agent-discipline.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ Arming a red PR does not queue it, it hides it:
123123

124124
← [`AGENTS.md` › Multi-agent working discipline](../../AGENTS.md#multi-agent-working-discipline)
125125

126-
A check outside those nine is advisory and rides through, and an advisory red
126+
A check outside those ten is advisory and rides through, and an advisory red
127127
that lands rides `main`'s merge ref into every later PR until stanched.
128128

129129
## Two speeds: which runs carry which battery

‎scripts/check-required-contexts.mjs‎

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,16 @@ export const REQUIRED_CONTEXTS = [
480480
'after the ui flake reading 6436579765 (0/50); the ruleset entry is the maintainer\'s, in the same sitting as the merge (#9325)',
481481
carries: 'the sharded `ui/` vitest matrix, `Test UI (k/16)`, read through the aggregate job',
482482
},
483+
{
484+
workflow: 'ci.yml',
485+
job: 'live-e2e-ui',
486+
context: 'Live E2E UI',
487+
authorized:
488+
'#25914 ruling 6435339772 Q1 A (the required check), re-based by ruling 6464191239 letter D on the workspace backend, ' +
489+
'maintainer 「其他同意」 2026-10-28T08:22Z — this row is the repo half (#27154); the ruleset entry is the maintainer\'s, ' +
490+
'in the same sitting as the merge (#9325)',
491+
carries: 'the Console against a real workspace backend: the allowlisted `ui/e2e/live` specs',
492+
},
483493
];
484494

485495
/**
@@ -595,9 +605,10 @@ export const INSTRUCTION_SURFACES = [
595605
// the judge. Then 7→5 by #22998 (two-speed CI: the dogfood and temporal
596606
// contexts moved to the full battery). Then 5→7 by #25853 (the `ui/`
597607
// import's `Lint UI` and `Build & E2E UI`), 7→8 with `Type Check UI`
598-
// once bill item 49 closed (#25856), and 8→9 with the `Test UI` aggregate
599-
// (#26460). The full set is pinned here so the corrected sentence cannot
600-
// rot back — a rename in ANY of the nine reddens this gate instead.
608+
// once bill item 49 closed (#25856), 8→9 with the `Test UI` aggregate
609+
// (#26460), and 9→10 with `Live E2E UI` (#27154). The full set is pinned
610+
// here so the corrected sentence cannot rot back — a rename in ANY of the
611+
// ten reddens this gate instead.
601612
file: 'AGENTS.md',
602613
statesTheSet: true,
603614
mustName: [
@@ -610,6 +621,7 @@ export const INSTRUCTION_SURFACES = [
610621
'Build & E2E UI',
611622
'Type Check UI',
612623
'Test UI',
624+
'Live E2E UI',
613625
],
614626
},
615627
{
@@ -642,6 +654,7 @@ export const INSTRUCTION_SURFACES = [
642654
'Build & E2E UI',
643655
'Type Check UI',
644656
'Test UI',
657+
'Live E2E UI',
645658
],
646659
},
647660
{
@@ -663,7 +676,7 @@ export const INSTRUCTION_SURFACES = [
663676
* of the six surfaces have one; `AGENTS.md` does not, because a repo-root FILE
664677
* has no separator to be found by — so an AGENTS.md card derived this gate not
665678
* at all, while that surface is the one carrying `mustName` for every
666-
* required context (widened 2→6 by #9677, 6→7 by #17798, 7→5 by #22998, 5→7 by #25853, 7→8, 8→9 by #26460). Editing the merge-queue
679+
* required context (widened 2→6 by #9677, 6→7 by #17798, 7→5 by #22998, 5→7 by #25853, 7→8, 8→9 by #26460, 9→10 by #27154). Editing the merge-queue
667680
* paragraph there is precisely how this gate goes red, and it was reachable
668681
* only by judgment.
669682
*

‎ui/e2e/live/ci/backend.env‎

Lines changed: 15 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,17 @@
1-
# Pins for the CI live-e2e backend (see start-backend.sh and
2-
# .github/workflows/live-e2e.yml).
1+
# What the live-e2e backend serves (see start-backend.sh and the `Live E2E UI`
2+
# job in .github/workflows/ci.yml).
33
#
4-
# OBJECTSTACK_VERSION — the published @objectstack/* npm version the backend
5-
# runs on. Until objectui moved into the objectstack repository it had to
6-
# match the @objectstack/spec version this repo's pnpm-lock.yaml resolved,
7-
# and objectui's CI-guide pin test (deleted by objectstack#26058) required the two equal
8-
# (objectui#7689).
9-
# Since the import (objectstack#25803) the console builds against the
10-
# workspace's own @objectstack/spec, a lockfile link with no version, so
11-
# that comparison is retired and this value is the published backend the
12-
# lane runs, nothing more.
4+
# LIVE_BACKEND_APP — the app directory, relative to the repository root, that
5+
# start-backend.sh boots with this tree's own built `@objectstack/cli`. The
6+
# live specs target the showcase's objects and seeded records.
137
#
14-
# This file declares exactly ONE @objectstack pin, and that is the whole
15-
# design: the commit is derived from it, see below.
16-
OBJECTSTACK_VERSION=18.2.0
17-
18-
# There is deliberately no OBJECTSTACK_REF key here. The objectstack-ai/objectstack
19-
# commit the showcase app metadata is sparse-checked-out from is DERIVED at
20-
# boot by start-backend.sh, from the release tag
21-
# `@objectstack/cli@${OBJECTSTACK_VERSION}` — `git ls-remote --tags`, taking
22-
# the peeled `^{}` sha of the annotated tag — and the script refuses to start
23-
# when that tag does not resolve to a 40-character sha. The app source and the
24-
# published packages it runs on therefore come from the same release BY
25-
# CONSTRUCTION; there is no second value to move, so the two cannot disagree.
26-
# (Mirror image of the framework repo's `.objectui-sha` console pin.)
27-
#
28-
# It used to be a hand-moved sha here, carrying a stated MUST — "always the
29-
# commit the release tag points at" — that nothing could check, on the
30-
# reasoning that resolving the tag needs the objectstack repository and the
31-
# unit lane cannot reach it. True of the unit lane, and beside the point: the
32-
# live lane clones that very repository at boot to get the app, so the lane
33-
# that CONSUMES the value could always resolve it. objectui#7964 retired the
34-
# pin rather than add a check inside an `informational` lane nobody reads.
35-
#
36-
# ⚠️ One consequence, stated rather than papered over. The workflow caches the
37-
# prepared fixture under `live-backend-<os>-<hashFiles(backend.env)>`, and the
38-
# resolved sha is no longer in this file. A version bump still moves the key,
39-
# because the version is what the sha is derived from. But if the
40-
# `@objectstack/cli@${OBJECTSTACK_VERSION}` tag were ever re-pointed at another
41-
# commit after a fixture had been cached, that stale fixture would still be
42-
# served until OBJECTSTACK_VERSION itself moved. start-backend.sh's own stamp
43-
# carries the RESOLVED sha, so a re-point is caught in a reused scratch dir;
44-
# the Actions cache is the one path it is not caught on. Published release tags
45-
# are not expected to move, and moving one is the anomaly, not this lane.
46-
47-
# There is no `better-auth` pin here any more. BETTER_AUTH_VERSION and
48-
# e2e/live/ci/better-auth-pin.mjs held the family at 1.7.2 while the published
49-
# @objectstack/plugin-auth imported an export 1.7.3 removed (objectstack#16186,
50-
# objectui#8084). They were retired together in the 17.5.0 bump, as their own
51-
# text prescribed (objectui#11073, maintainer ruling on objectui#11111):
52-
# plugin-auth 17.5.0 declares the whole family at exactly 1.7.3 and no longer
53-
# imports that export, so the published artifact's own manifest is the pin.
54-
# Holding 1.7.2 on it made the lane test a pair nobody ships, and the seeded
55-
# sign-in never answered.
8+
# There is no published-version pin here any more (objectstack#27154, ruling
9+
# 6464191239 letter D step 2). Until then this file declared
10+
# OBJECTSTACK_VERSION, the published `@objectstack/*` release the backend
11+
# ran, and start-backend.sh derived the showcase commit from that release's
12+
# tag. A HEAD console against a published backend goes red each time the
13+
# console passes the last release (#25914: 0/5 runs green on 18.1.0 against
14+
# the 18.2.0 tree), so a required lane on a pin is a lockstep bump on every
15+
# release. The lane now runs HEAD against HEAD, and the pin, the tag resolve
16+
# and the npm install retired together.
17+
LIVE_BACKEND_APP=examples/app-showcase

0 commit comments

Comments
 (0)