(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
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.yml — ci.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_requestwithpaths: ['design/**']), mirroring the starter's ownacceptance-video.ymlrather than motir-core's in-job step. A job-levelif:is NOT equivalent: a skipped job still REPORTS a greyed check, so every scaffolded project would show a permanently-skippingDesign resulton 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 — adesign/README.md(or a worked example area) explaining thedesign-notes.md+*.mock.html+.pngset and thedesign/<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.mjsis 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.ymlexists, triggers only onpull_requestwithpaths: ['design/**'](plus its own definition), and requestsid-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.mjsis 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 thepaths: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: nodesign-guardsjob).- 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).