MotirBuilding in public
MOTIR · moooon
onMotir
You’re viewing a public project. Anyone can view it — no account needed. Sign in to submit, upvote, or comment on requests.View-only — you can’t edit work items
MOTIR-2673

(starter) Ship the design-result publish lane in the platform starter's CI — its OWN paths-filtered workflow, absent (not skipped) on PRs that touch no design asset

Done
Description

Give every project scaffolded from the platform starter the same design-result publishing from day one — the MOTIR-1941 move for this artifact class. Its own repository, its own PR (one subtask = one repo = one PR); it ships the publisher, not the product surface, because the app the starter scaffolds is a Motir CLIENT, not a second Motir.

⚠️ It is NOT a copy of the motir-core step, and the difference is verified, not assumed. On moooon-B-V/nextjs-prisma-vercel-starter the workflows are acceptance-video.yml, ci.yml and cleanup-preview-deployments.ymlci.yml has no design-guards job (its jobs are lint, typecheck, unit, build, …) and the repo has no design/ directory at all. So there is no existing always-on design job to hang a step on, which changes the shape:

  • A separate, paths-filtered workflow (design-result.yml, on: pull_request with paths: ['design/**']), mirroring the starter's own acceptance-video.yml rather than motir-core's in-job step. A job-level if: is NOT equivalent: a skipped job still REPORTS a greyed check, so every scaffolded project would show a permanently-skipping Design result on every PR — the exact defect MOTIR-1958 filed against this same repo's acceptance lane. Only a workflow that never triggers leaves no check behind.
  • Seed the convention it filters on. With no design/ directory, the filter matches nothing and the lane is dead on arrival. Establish the three-file convention in the starter — a design/README.md (or a worked example area) explaining the design-notes.md + *.mock.html + .png set and the design/<KEY>-<slug> branch convention the publisher resolves the target from.
  • The publisher script is vendored, not imported. A scaffolded project has no dependency on motir-core, so scripts/upload-design-assets.mjs is copied in with its own tests. Keep it recognisably the same file so a fix in one is portable to the other, and say so in its header.
  • BYOK-correct by default. Keyless OIDC first with id-token: write, the API-token secret as fallback, and a no-credential run that logs and exits 0 — a fresh scaffold has neither, and a starter whose CI fails on a brand-new project is worse than one that publishes nothing.

Acceptance criteria

  • .github/workflows/design-result.yml exists, triggers only on pull_request with paths: ['design/**'] (plus its own definition), and requests id-token: write + contents: read.
  • A PR that touches no design asset produces no check at all for this lane — not a skipped one; asserted the way the starter's existing lane tests assert their arrangement.
  • scripts/upload-design-assets.mjs is vendored with its unit tests, and its header names motir-core as the upstream so the two stay portable.
  • With no OIDC and no token secret the run logs that publishing is opt-in and exits 0; the lane is green on a scaffold that has never connected to Motir.
  • The starter documents the design three-file convention and the design/<KEY>-<slug> branch convention, so the paths: filter has something to match and a scaffolded project knows what to produce.
  • The starter's existing lanes (ci.yml, acceptance-video.yml) are unchanged in behaviour, and no new always-on check is added.
  • The README / scaffold docs mention the lane in the same place they mention the acceptance-video lane, so an adopter finds both together.

Context refs

  • moooon-B-V/nextjs-prisma-vercel-starter.github/workflows/acceptance-video.yml (the paths-filtered lane this mirrors), .github/workflows/ci.yml (verified: no design-guards job).
  • MOTIR-1941 — the acceptance-lane port this repeats.
  • MOTIR-1958 — why a job-level if: is not "absent, not skipped".
  • MOTIR-2668 — the motir-core publisher this vendors, and the reason its shape differs here.
  • MOTIR-2667 — the endpoints the vendored script calls (a scaffolded project talks to Motir over HTTP like any other client).