Skip to content

feat(release): publish localized changelog metadata - #5518

Closed
PerishCode wants to merge 14 commits into
mainfrom
feat/silent-updates-changelog-cicd
Closed

feat(release): publish localized changelog metadata#5518
PerishCode wants to merge 14 commits into
mainfrom
feat/silent-updates-changelog-cicd

Conversation

@PerishCode

Copy link
Copy Markdown
Contributor

Related to #5071 and #5343.

Why

The updater and release work exposed a missing delivery contract: release notes had no channel-consistent source convention, immutable publication path, public metadata projection, or strict stable gate. That left release operators and future consumers to couple source discovery, storage layout, metadata assembly, and rendering decisions together.

This PR establishes that mechanism in tools-release after the product team split the lightweight What's New experience into an independent path. The goal is to make localized changelog delivery deterministic now while keeping source format, storage, metadata, and eventual rendering independently replaceable.

What users will see

There is no new updater UI in this PR. Release operators can author localized Markdown at docs/CHANGELOG/v<full-release-version>/<locale>.md; successful releases publish immutable locale assets and expose their URL, media type, SHA-256, and byte size through metadata.json.releaseNote.content.

Stable releases now fail before platform builds when required en and zh-CN notes are missing or malformed. Beta, prerelease, and preview use the same pipeline but may explicitly publish without notes when no matching version directory exists.

Surface area

  • UI — new page / dialog / panel / menu item / setting / empty state in apps/web or apps/desktop (including Electron menu bar)
  • Keyboard shortcut — new or changed
  • CLI / env var — new od subcommand or flag, new tools-dev / tools-pack / tools-pr flag, or new OD_* env var
  • API / contract — new /api/* endpoint, new SSE event, or changed shape in packages/contracts
  • Extension point — new entry under skills/, design-systems/, design-templates/, or craft/, or change to the skills protocol
  • i18n keys — added new translation keys (see TRANSLATIONS.md for the locale workflow)
  • New top-level dependency — adding any new entry to the root package.json (dependencies or devDependencies); workspace-package package.json files are out of scope. Include a paragraph on what we get vs. what bytes we ship (see CONTRIBUTING.md → Code style)
  • Default behavior change — changes what existing users experience without opting in (default model, default setting, file/SQLite schema, auto-network on startup, auto-install)
  • None — internal refactor, docs, tests, or translation update only

Screenshots

Not applicable. This PR has no UI diff against main; release-note rendering remains a separate consumer concern.

Bug fix verification

Not applicable; this is a release delivery feature rather than a bug fix.

Validation

  • pnpm install
  • pnpm guard (78 checks passed after the latest main merge)
  • pnpm typecheck
  • pnpm --filter @open-design/tools-release test (16 tests)
  • pnpm --filter @open-design/tools-serve exec vitest run tests/release-metadata-publish.test.ts (2 tests)
  • pnpm --filter @open-design/tools-pack exec vitest run tests/release-workflows.test.ts
  • pnpm --filter @open-design/e2e exec vitest run -c vitest.config.ts tests/packaged-smoke-workflow.test.ts (46 tests)
  • actionlint for all five changed release workflows
  • Local stable 0.14.1 dry-run: planned bilingual immutable uploads, candidate metadata assembly, and verification passed without storage access
  • Two local tools-serve + tools-pack packaged loops: 0.14.1-beta.1000 -> .1001 -> .1002 and .2000 -> .2001 -> .2002, including build, install, update, restart, stop, uninstall, and cleanup
  • Two complete remote release-beta publishes: 0.14.1-beta.3 and 0.14.1-beta.4, including macOS arm64 and Windows x64 builds/smokes, bilingual immutable note publication, metadata verification, and latest promotion

Nix is not installed locally, so nix flake check was not rerun. The lockfile hash path remains covered by the repository's PR validation/autofix gate.

free666799 and others added 14 commits July 2, 2026 20:53
After an update, the home surface shows a one-time bottom-right card with
the release highlights (title, copy, optional image) and a "See what's new"
link. Content ships in the release feed metadata.json as an optional
whatsNew block sourced from tools/release/whats-new/<baseVersion>.json;
versions without highlights fall back to generic copy linking the release
notes. The card shows once per version, keyed on a locally stored
last-seen version, and never on fresh installs.

- packages/contracts: WhatsNewContent/WhatsNewResponse DTOs + analytics props
- daemon: GET /api/whats-new (channel feed fetch, 1h cache, stale/null
  degradation) + od whats-new CLI mirror
- web: WhatsNewPopup card (CSS Module, i18n chrome in 19 locales,
  surface_view/ui_click tracking), lastSeen decision logic in lib/whats-new
- release tooling: publish-metadata forwards the optional whatsNew block and
  fails loudly on malformed files; docs in tools/pack/AGENTS.md and
  tools/release/whats-new/README.md
… locale overrides

Address review feedback on the post-update what's-new card:

- EntryShell passes `active={view === 'home'}` into WhatsNewPopup, and the
  component defers its fetch/show decision (and `page_name: 'home'`
  analytics) until Home is the active entry view, so direct routes like
  /projects no longer surface the card or emit home-page events.
- The document-level Escape listener now ignores already-handled events
  (`defaultPrevented`) and hides the card without marking the version as
  seen or firing the dismiss analytics event, so a stray Escape no longer
  permanently spends the once-per-version card.
- publish-metadata validates the optional `locales` block at publish time
  (plain-object shape, non-empty `title`/`body`, HTTPS `linkUrl`) so
  malformed locale overrides fail the publish loudly instead of being
  silently dropped by the daemon parser; README documents the contract.

Generated-By: looper 0.9.11 (runner=fixer, agent=claude-code)
Replace the startsWith("https://") checks in readWhatsNewBlock with a
shared assertHttpsUrl helper that trims, constructs new URL(...), and
requires protocol === "https:", mirroring the daemon readHttpsUrl parser
so values it would silently drop (e.g. "https://") fail the publish
loudly for imageUrl, linkUrl, and locale linkUrl.

Generated-By: looper 0.9.11 (runner=fixer, agent=claude-code)
…first Home load

The card's fetch effect armed its once-guard when the fetch STARTED, and the
effect teardown re-armed it — so React StrictMode's double-invoke (dev) or a
Home toggle mid-fetch cancelled the first fetch, the second effect run saw the
guard still set and bailed, and the resolved-but-cancelled fetch re-armed the
guard without ever showing the card. The card then never appeared until the
Home view toggled again.

Arm the guard only once a decision is actually REACHED (fetch resolved with a
payload); keep the `cancelled` flag purely as a state-update guard that no
longer re-arms the fetch. A superseded fetch drops and the surviving one
records the decision, so the card shows on first Home activation and a genuine
mid-fetch Home exit still retries on the next activation.

Red spec: apps/web/tests/components/WhatsNewPopup.test.tsx renders under
StrictMode and asserts the card appears — red on the previous effect, green now.
# Conflicts:
#	packages/contracts/src/analytics/events.ts
…hangelog-cicd

# Conflicts:
#	apps/web/src/components/EntryShell.tsx
#	apps/web/src/i18n/locales/zh-CN.ts
#	apps/web/src/i18n/locales/zh-TW.ts
#	tools/pack/AGENTS.md
#	tools/release/src/storage/publish-metadata.ts
@PerishCode
PerishCode requested a review from a team as a code owner July 13, 2026 04:48
@PerishCode

Copy link
Copy Markdown
Contributor Author

Superseded by #5520. The replacement PR carries the identical 25-file diff on a clean latest-main branch with one commit, removing the pre-squash #5071 reference history from review.

@PerishCode PerishCode closed this Jul 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Landing page preview

This PR is deployed to a Cloudflare Pages preview — not staging or production:

@lefarcen
lefarcen requested a review from nettee July 13, 2026 04:53
@lefarcen lefarcen added size/XL PR changes 700-1500 lines risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps type/feature New feature skip-validation Maintainer override: bot will not auto-add needs-validation on this PR. labels Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps size/XL PR changes 700-1500 lines skip-validation Maintainer override: bot will not auto-add needs-validation on this PR. type/feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants