Closed general

publish hero gate: the existing-hero grace path accepts a create-time text billboard, so app/skill pages ship without a Hero Studio image

Colby Knox · 1mo ago ·closed by Colby Knox

Colby's ask 2026-09-16: require a real (studio-generated) hero for skill pages; today they are bypassed. The bypass is server-side, in the publish gate:

  1. page create requires only a billboard with headline + subhead (HERO_REQUIRED_AT_CREATE, server.js ~1516). The row is written with hero_type "billboard" and the manifest hero is NOT marked auto.
  2. pkg publish (~11603) computes existingHasHero = !!(row.hero_type || row.hero_path) and only excludes billboards whose page.json hero has auto: true. A create-time text billboard passes that check, so a manifest that OMITS hero publishes forever under the grace path with no image at all.
  3. HERO_STUDIO_REQUIRED (~4216) fires only when the publish manifest carries a hero object; an omitted hero skips it, so the studio-provenance check never runs for these pages.

Ask (server): for type app and skill, the grace path should accept only an existing hero that is an image/video with a path (hero_type image|video and hero_path set), never a billboard; and when the manifest omits hero, run the studio-provenance check against the page's served hero (same validator as 4216). A text-only billboard from create is the wiki's placeholder until the first push, not a hero, and the publish response should say so with HERO_STUDIO_REQUIRED and the studio recovery hints. Suggest the same rule on repo push of page.json for app/skill pages.

CLI side (this thread, adom-wiki 1.7.48): the hero finding for app/skill is no longer downgradable by --skip-lint, and the existing-page softener only softens when the served hero is an image path. Studio side: skills without screenshots get a generated "skill card" showcase so the AI can pose a hero without a real screenshot (adom/hero-studio 0.20.8).

3 Replies

Colby Knox · 1mo ago

Server side (Colby-main): reproduced against a real server with both gates live, and the mechanism is narrower than described above.

Pages created on or after the studio cutover (2026-07-24) are already blocked. Create a skill with a text billboard, publish a version whose manifest omits hero: the grace path does pass HERO_REQUIRED, but the studio gate falls back to the page's own hero, finds no bytes behind the billboard, and refuses with HERO_STUDIO_REQUIRED, reason no_hero, with the studio recovery hints. Point 3 above does not hold: the studio gate is not skipped when the manifest omits hero.

The real gap is the grandfather clause. The same publish on a page created before 2026-07-24 returns 201 and ships with the text-only billboard, because reuseOk = !heroChanged && grandfathered. That clause is deliberate (pages predating the cutover keep publishing until they next touch their hero), and it is what lets a text-only hero live forever.

Prod audit (read-only, every app and skill page):

pages
app + skill pages 305 (160 apps, 145 skills)
studio hero 70
image hero, not studio-made 126
text-only billboard, created after the cutover (blocked today) 24
text-only billboard, created before the cutover (can still publish) 85

Most of the 85 are the 2026-05-28 migration batch, and many are private.

Interaction with adom-wiki 1.7.48: the CLI now refuses those same 85 pages client-side, so for anyone on 1.7.48 the grandfather clause is already closed in practice while the server still allows it. A publisher on an older CLI or a raw API call still gets through.

Options for Colby, none applied yet:

  1. Close it on the server to match the CLI: for app/skill, the grandfather clause excuses only an existing image or video hero with a path, never a text-only billboard. Blocks republishing of the 85 until each gets a studio hero; owners include kyle and john.
  2. Close it only for public pages (about a third of the 85), leaving private migration pages alone.
  3. Leave the server as is and let the CLI carry the rule.

Colby's call. The regression test for whichever option lands will cover both the post-cutover refusal (currently untested with both gates live) and the grandfather path.

Colby Knox · 1mo ago

Shipped option 1 on prod (git-wiki 157cd52), per Colby.

The grandfather clause now excuses only a hero that is a file. An app or skill page whose hero is a text-only billboard (headline and subhead, no image) is refused on publish whether it predates the studio cutover or not: HERO_STUDIO_REQUIRED, reason billboard_retired, with data.text_only_hero: true and data.grandfathered, plus the studio recovery chain naming adom-wiki page hero <owner>/<slug> --image .... Pre-cutover image heroes and billboards composed from a screenshot keep publishing unchanged.

Effect on prod: the 85 text-only pages from the audit above (adom 68, kyle 16, john 1) can't publish again until each gets a studio hero. Nothing is unpublished; the next publish is what asks.

Verified: test/packages/hero-text-only-gate.test.mjs runs with both hero gates live (20 checks, and it fails on the previous code where the grandfathered page returned 201); the existing studio gate (81) and hero-at-create (12) suites pass; full gate 334 green; a throwaway skill page on staging was refused with the new marker and soft-deleted. Repo push is unchanged: README edits on those pages still push.

Colby Knox · 1mo ago

Correction to the counts above: the page listing returned 14 pages twice. Deduplicated, the pages newly blocked by 157cd52 are 73, not 85: 64 skills and 9 apps (owners adom 57, kyle 15, john 1). The 22 text-only pages created after the cutover (5 skills, 17 apps) were already blocked before this change. Hardware is outside this gate entirely and is unaffected.

Log in to reply.