Skip to content

feat(target-config): add release identity contract - #124

Merged
imjlk merged 3 commits into
mainfrom
codex/release-identity
Aug 3, 2026
Merged

imjlk merged 3 commits into
mainfrom
codex/release-identity

Conversation

@imjlk

@imjlk imjlk commented Aug 1, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • add a shared immutable release identity contract for multi-target artifacts
  • keep a common human-facing release label separate from native package/build counters
  • document versioning rules and verify legacy manifest merging

Validation

  • pnpm check
  • pnpm smoke:release-manifest-merge
  • final OCR re-review: no findings

Summary by CodeRabbit

  • New Features

    • Added shared release identity information, including game versions, release revisions, labels, and release IDs.
    • Release manifests now support optional release identity details while remaining compatible with legacy manifests.
    • Target release versions now use consistent, non-resetting release labels across platforms.
  • Bug Fixes

    • Added validation for mismatched versions, labels, revisions, and release identifiers.
    • Improved semantic-version validation and release-manifest merging behavior.
  • Documentation

    • Updated release versioning guidance covering revision allocation, label validation, and platform-specific build version rules.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@imjlk, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 40 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bdff998b-ae5a-48e1-8c13-0a66128c931e

📥 Commits

Reviewing files that changed from the base of the PR and between 063ddb0 and 77a1084.

📒 Files selected for processing (4)
  • release.manifest.schema.json
  • tools/smoke/release-manifest-merge.ts
  • tools/target/app-version.ts
  • tools/target/build-target.ts
📝 Walkthrough

Walkthrough

The change adds shared release identity utilities, extends release manifests with optional identity data, integrates identity creation and validation into manifest generation and merging, updates final SemVer checks, and documents the release versioning model.

Changes

Release identity and manifest integration

Layer / File(s) Summary
Release identity utilities
packages/target-config/src/*, packages/target-config/test/*, packages/release-manifest/package.json
The target-config package adds release identity types and helpers for SemVer validation, revision parsing, label creation, and release ID formatting. Smoke tests cover valid and invalid inputs.
Manifest identity contract
packages/release-manifest/src/index.ts, release.manifest.schema.json
Release manifests optionally include releaseIdentity. Validation checks canonical labels, matching game versions, and formatted release IDs.
Manifest generation and merge flow
tools/target/*, tools/smoke/release-manifest-merge.ts
Manifest generation reads release identity inputs, emits identity-derived values, compares identity fields during merges, and uses shared final-SemVer validation. Smoke tests cover legacy manifests and revision changes.
Versioning contract documentation
docs/MULTI_TARGET_RELEASE_VERSIONING.md, .sampo/changesets/jovial-warden-akka.md
The documentation defines release revisions, common labels, target build counters, validation, manifest handling, and the package patch release.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ReleaseManifestMergeSmoke
  participant generate-release-manifest
  participant target-config
  participant ReleaseManifest
  ReleaseManifestMergeSmoke->>generate-release-manifest: provide release revision and expected label
  generate-release-manifest->>target-config: create canonical release identity
  target-config-->>generate-release-manifest: return release label and revision
  generate-release-manifest->>ReleaseManifest: emit releaseIdentity and releaseId
  ReleaseManifest->>ReleaseManifest: validate identity and releaseId
Loading

Possibly related PRs

Poem

A rabbit labels each release,
With revisions that never cease.
SemVer stays neat, IDs align,
Manifests merge by one design.
Hop, hop—the targets now agree!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the main change: adding a release identity contract to target-config.
Description check ✅ Passed The description includes the required Summary and Validation sections and explains the main changes and validation performed.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/release-identity

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 74839cd0c5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +30 to +32
const semVerPattern = new RegExp(
`^${semVerCore}(?:-${preReleaseIdentifier}(?:\\.${preReleaseIdentifier})*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$`,
'u',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve SemVer build metadata in release IDs

When releaseRevision is omitted, this pattern accepts a valid version such as 1.2.3+sha, and createMpgdReleaseIdentity uses it verbatim as the label. generate-release-manifest.ts then passes that label to formatMpgdReleaseId, whose component validation rejects every +, so manifest generation now fails for APP_VERSION or package.json.version values containing SemVer build metadata that worked before this commit. The accepted version grammar and release-ID encoding need to compose, or metadata must be rejected explicitly at the identity boundary.

Useful? React with 👍 / 👎.

Comment on lines +79 to +80
if (manifest.gameVersion !== releaseIdentity.gameVersion) {
throw new TypeError('Release manifest gameVersion must match releaseIdentity.gameVersion.');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject noncanonical nested game versions

If a schema-valid or hand-edited manifest contains releaseIdentity.gameVersion: " 1.0.0 " while the top-level version, label, and release ID are canonical, createMpgdReleaseIdentity trims the nested value and this comparison succeeds because it checks only the top-level value against the normalized result. The validator therefore returns a noncanonical identity; when another target is generated with "1.0.0", hasMatchingReleaseIdentity raw-compares the nested strings and resets the manifest instead of preserving the earlier targets. Check the original nested value against the normalized value, analogous to the label check above.

Useful? React with 👍 / 👎.

Comment on lines +329 to +330
if (previous === undefined || next === undefined) {
return true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Separate legacy prereleases from revision labels

When the previous file is a legacy manifest for game version 1.0.0-v42, its old release ID is identical to the new release ID for { gameVersion: "1.0.0", releaseRevision: 42 } when the build ID is reused. If the source and other contract fields also match—for example, APP_VERSION is changed between builds from the same checkout while the default BUILD_ID=local is retained—this unconditional match preserves targets built for the prerelease inside the final release manifest. Compare the legacy top-level game version as well, or otherwise disambiguate legacy prerelease labels before merging.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/target-config/src/releaseIdentity.ts`:
- Around line 90-136: Update normalizeMpgdSemVer to reject SemVer values
containing build metadata (+ suffix), so gameVersion cannot produce a label with
the reserved release-ID separator. Ensure createMpgdReleaseIdentity fails at
normalization time with a clear TypeError, while preserving acceptance of valid
versions without build metadata.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 985fbbe8-86d1-485f-a9b9-a56cc79d7e89

📥 Commits

Reviewing files that changed from the base of the PR and between 0e23de1 and 74839cd.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • .sampo/changesets/jovial-warden-akka.md
  • docs/MULTI_TARGET_RELEASE_VERSIONING.md
  • packages/release-manifest/package.json
  • packages/release-manifest/src/index.ts
  • packages/target-config/src/index.ts
  • packages/target-config/src/releaseIdentity.ts
  • packages/target-config/test/target-config-smoke.ts
  • release.manifest.schema.json
  • tools/smoke/release-manifest-merge.ts
  • tools/target/generate-release-manifest.ts
  • tools/target/native-release-identity.ts

imjlk commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

리뷰 피드백을 063ddb0에 반영했습니다.

  • SemVer build metadata를 release identity 경계에서 명확히 거부해 release ID의 + 구분자 충돌을 방지했습니다.
  • releaseIdentity.gameVersion의 비정규 공백 입력을 manifest 검증에서 거부합니다.
  • legacy prerelease(1.0.0-v42)와 새 release revision label이 같은 release ID를 갖더라도 병합되지 않도록 top-level game version을 비교합니다.
  • 각 경로에 회귀 테스트를 추가했습니다.

검증:

  • pnpm check
  • pnpm smoke:release-manifest-merge

@codex review
@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026 •

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Commit summary and diff ==='
git show --stat --oneline --decorate --no-renames 063ddb0
git diff --no-ext-diff --unified=80 063ddb0^ 063ddb0 -- \
  packages/target-config/src/releaseIdentity.ts \
  packages/target-config/test/target-config-smoke.ts \
  packages/release-manifest/src/index.ts \
  tools/target/generate-release-manifest.ts \
  tools/smoke/release-manifest-merge.ts

echo '=== Relevant file outlines ==='
ast-grep outline packages/target-config/src/releaseIdentity.ts --view expanded
ast-grep outline packages/release-manifest/src/index.ts --view expanded
ast-grep outline tools/target/generate-release-manifest.ts --view expanded
ast-grep outline tools/smoke/release-manifest-merge.ts --view expanded

echo '=== Release identity and merge call sites ==='
rg -n -C 4 --glob '*.ts' \
  '(createMpgdReleaseIdentity|formatMpgdReleaseId|assertReleaseManifest|releaseIdentity|gameVersion)' \
  packages tools

Length of output: 88522


@imjlk 063ddb0을 검토했습니다.

추가적인 차단 문제를 발견하지 못했습니다.

  • normalizeMpgdSemVer가 SemVer build metadata의 +를 거부합니다.
  • assertReleaseManifest가 비정규 releaseIdentity.gameVersion 값을 거부합니다.
  • legacy manifest 병합 시 top-level gameVersion을 비교합니다.
  • 1.0.0-v42 legacy prerelease와 1.0.0 revision 42의 충돌을 회귀 테스트가 검증합니다.

보고한 검증 명령은 이 환경에서 독립 실행하지 않았습니다.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tools/smoke/release-manifest-merge.ts (1)

122-142: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Assert the migrated release identity, not only the target key.

The assertion at Line 139 verifies only that microsoft-store replaced the old target. It does not verify the merged gameVersion, releaseIdentity, or releaseId. The validator in packages/release-manifest/src/index.ts accepts manifests without releaseIdentity, so an incomplete merge can still pass. Store the merged manifest and assert the expected revision-42 identity and derived release ID.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/smoke/release-manifest-merge.ts` around lines 122 - 142, Update the
second runManifest verification in the release-manifest merge test to store the
resulting manifest, then assert the revision-42 merged gameVersion,
releaseIdentity, and derived releaseId in addition to the microsoft-store target
key. Use the expected identity values produced by the releaseRevision: 42 input
and preserve the existing target assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tools/smoke/release-manifest-merge.ts`:
- Around line 122-142: Update the second runManifest verification in the
release-manifest merge test to store the resulting manifest, then assert the
revision-42 merged gameVersion, releaseIdentity, and derived releaseId in
addition to the microsoft-store target key. Use the expected identity values
produced by the releaseRevision: 42 input and preserve the existing target
assertion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 70388571-afc3-47f1-a484-ef4bf1a60fba

📥 Commits

Reviewing files that changed from the base of the PR and between 74839cd and 063ddb0.

📒 Files selected for processing (5)
  • packages/release-manifest/src/index.ts
  • packages/target-config/src/releaseIdentity.ts
  • packages/target-config/test/target-config-smoke.ts
  • tools/smoke/release-manifest-merge.ts
  • tools/target/generate-release-manifest.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/target-config/test/target-config-smoke.ts
  • packages/target-config/src/releaseIdentity.ts
  • packages/release-manifest/src/index.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 063ddb0848

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread release.manifest.schema.json Outdated
"required": ["gameVersion", "label"],
"properties": {
"gameVersion": { "type": "string", "minLength": 1 },
"releaseRevision": { "type": "integer", "minimum": 1 },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Cap release revisions at the safe-integer limit

When a manifest is validated only against this JSON Schema, a revision such as 9007199254740992 is accepted because it is an integer above the minimum, but assertReleaseManifest later passes it to createMpgdReleaseIdentity, which rejects every value outside Number.isSafeInteger. This makes schema-valid manifests unusable by the runtime validator; add a maximum of 9007199254740991 so both contracts enforce the same boundary.

Useful? React with 👍 / 👎.

gitSha: provenance.sourceGitSha,
kitGitSha: provenance.kitGitSha,
gameVersion,
gameVersion: releaseIdentity.gameVersion,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject or propagate padded APP_VERSION consistently

When a target is built directly with an APP_VERSION such as " 1.0.0 ", build-target.ts passes that raw value to Vite, whose starter config embeds it as __APP_VERSION__, while createMpgdReleaseIdentity trims it and this line records "1.0.0" in the release manifest. The shipped artifact therefore reports a different version from its provenance manifest (and the Microsoft Store artifact verification explicitly rejects that mismatch); either reject noncanonical input before building or use the normalized value for both the build and manifest.

Useful? React with 👍 / 👎.

imjlk commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

Addressed the latest review feedback in 77a1084.

  • Added Number.MAX_SAFE_INTEGER as the JSON Schema maximum for releaseIdentity.releaseRevision, matching the runtime validator.
  • Added an early canonical APP_VERSION check before provenance capture or target build execution, preventing the Vite artifact version from diverging from the release manifest.
  • Added regression coverage for both the schema boundary and padded APP_VERSION rejection.

Validation:

  • pnpm check
  • pnpm smoke:release-manifest-merge

@codex review
@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026 •

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Commit and changed files ==='
git show --stat --oneline --no-renames 77a1084
git diff --name-only 77a1084^ 77a1084

echo '=== Commit diff ==='
git diff --no-ext-diff --unified=100 77a1084^ 77a1084 -- \
  release.manifest.schema.json \
  tools/target/generate-release-manifest.ts \
  tools/smoke/release-manifest-merge.ts \
  packages/target-config/src/releaseIdentity.ts \
  packages/release-manifest/src/index.ts \
  packages/target-config/test/target-config-smoke.ts

echo '=== File outlines ==='
ast-grep outline tools/target/generate-release-manifest.ts --view expanded
ast-grep outline tools/smoke/release-manifest-merge.ts --view expanded
ast-grep outline packages/target-config/src/releaseIdentity.ts --view expanded

echo '=== APP_VERSION, releaseRevision, and schema call sites ==='
rg -n -C 5 --glob '*.ts' --glob '*.json' \
  '(APP_VERSION|releaseRevision|MAX_SAFE_INTEGER|createMpgdReleaseIdentity|assertReleaseManifest)' \
  packages tools release.manifest.schema.json

Length of output: 91582


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== build-target imports and execution order ==='
sed -n '1,180p' tools/target/build-target.ts

echo '=== APP_VERSION helper ==='
cat -n tools/target/app-version.ts

echo '=== Build-target test candidates ==='
fd -t f -E node_modules -E dist 'build-target|app-version' tools packages

echo '=== Build target execution and test references ==='
rg -n -C 5 --glob '*.ts' --glob '*.json' --glob '*.yml' --glob '*.yaml' \
  '(build-target\.ts|requireCanonicalAppVersion|resolveReleaseProvenance|pnpm.*build:target)' \
  tools packages .github package.json pnpm-workspace.yaml 2>/dev/null || true

echo '=== Changed-file complete diff ==='
git diff --check 77a1084^ 77a1084

Length of output: 26372


@imjlk 77a1084을 검토했습니다.

추가 차단 문제를 발견하지 못했습니다.

  • JSON Schema의 releaseIdentity.releaseRevision.maximum은 Number.MAX_SAFE_INTEGER와 일치합니다.
  • requireCanonicalAppVersion은 공백이 포함된 APP_VERSION을 거부합니다.
  • build-target.ts는 provenance 캡처, preflight, 아이콘 생성, Vite 빌드보다 먼저 APP_VERSION을 검증합니다.
  • 회귀 테스트는 schema 경계와 패딩된 APP_VERSION 거부를 확인합니다.
  • git diff --check은 문제를 보고하지 않았습니다.

보고한 pnpm check 및 pnpm smoke:release-manifest-merge는 이 환경에서 독립 실행하지 않았습니다.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: 77a1084801

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@imjlk
imjlk merged commit f49b70f into main Aug 3, 2026
6 checks passed
@imjlk
imjlk deleted the codex/release-identity branch October 27, 2026 11:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant