Skip to content

feat(cli): add test-only offline playtest packaging - #131

Merged
imjlk merged 90 commits into
mainfrom
codex/offline-network-policy
Aug 11, 2026
Merged

imjlk merged 90 commits into
mainfrom
codex/offline-network-policy

Conversation

@imjlk

@imjlk imjlk commented Aug 9, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • add mpgd game offline-playtest <game> for packaging an existing web-preview artifact into one direct-file HTML test bundle
  • inline bundled JavaScript, styles, and statically discoverable local assets while denying network APIs and unsupported runtime features
  • keep the workflow outside mpgd.targets.json, release manifests, PWA/deployment flows, and store-submission artifacts
  • emit test-only README and JSON evidence, including source target, limitations, size, and SHA-256
  • refuse unsafe output paths, symlink traversal, overlapping source/output directories, and non-generated content reuse
  • document the workflow and its server-feature, Worker, dynamic-asset, and file:// storage limitations in kit and generated-game guides
  • add an @mpgd/cli minor Sampo changeset

Verification

  • pnpm check
  • pnpm test
  • pnpm smoke:cli-offline-playtest
  • pnpm build:packages
  • pnpm pack:packages:prepared
  • ocr review --commit deb9f6f (6 findings; all patched)
  • ocr review --commit c7ba417 (0 findings)

pnpm sampo:release:dry-run is intentionally branch-gated and reported that releases are allowed only from main.

Scope boundary

This is test-play tooling only. It does not claim full offline support for a game and does not create a new distribution target. Server-backed identity, purchases, ads, reward grants, leaderboards, and cloud saves remain unavailable unless the game supplies its own disabled/local fallback.

Summary by CodeRabbit

  • New Features

    • Added mpgd game offline-playtest to create self-contained, network-blocked browser test copies from web previews.
    • Generated packages include local assets, entry files, metadata, evidence, and safety restrictions.
    • Added validation for unsupported online, browser-dependent, and external-resource scenarios.
  • Documentation

    • Documented setup, commands, output locations, limitations, and fallback requirements.
  • Tests

    • Added comprehensive smoke tests covering packaging, assets, security, validation, and deterministic output.
  • Maintenance

    • Updated framework, CLI, and development-tooling compatibility.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The CLI adds a test-only offline-playtest workflow. It packages web-preview output into a network-blocked direct-file bundle with evidence and validation. The change also aligns Apps-in-Toss tooling with version 3.0.2 and adds peer-rule validation.

Changes

Offline playtest workflow

Layer / File(s) Summary
CLI command and packaging contract
packages/cli/package.json, packages/cli/src/index.ts
The CLI exports the offline-playtest API and adds mpgd game offline-playtest with path and size options.
Bundle assembly and asset inlining
packages/cli/src/offline-playtest.ts
The packager bundles JavaScript, transforms HTML and CSS, embeds supported assets, applies CSP and network guards, and writes evidence metadata.
Path, symlink, and reusable-output validation
packages/cli/src/offline-playtest.ts
The packager validates containment, references, symlinks, size limits, output locations, and generated-output integrity.
Smoke coverage and workflow documentation
tools/smoke/cli-offline-playtest.ts, README.md, docs/GAME_DEVELOPMENT.md, packages/cli/templates/phaser-game/*, package.json, .sampo/changesets/offline-playtest-bundle.md
Smoke tests cover packaging, transformations, rejected features, asset handling, and path safety. Documentation and release metadata describe the test-only workflow.

Stable Apps-in-Toss tooling

Layer / File(s) Summary
Stable package and workspace versions
apps/target-ait/package.json, packages/cli/templates/phaser-game/apps/target-ait/package.json, packages/cli/templates/phaser-game/pnpm-workspace.yaml, pnpm-workspace.yaml
The application and template use @ait-co/devtools 0.1.140. Workspace rules allow the matching web framework version.
Typed SDK host test dependencies
adapters/ait/src/host.test.ts
SDK-backed test overrides use callable types and support probes with default support values.
Workspace peer-rule validation
tools/validate-starter-workflow.ts
Starter validation parses peer rules and checks the devtools and framework version mapping.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Developer
  participant CLI
  participant WebPreview
  participant OfflinePackager
  participant FileSystem
  Developer->>CLI: Run offline-playtest
  CLI->>WebPreview: Read prepared web-preview metadata
  CLI->>OfflinePackager: Pass artifact and output paths
  OfflinePackager->>FileSystem: Bundle files and inline supported assets
  OfflinePackager->>FileSystem: Write index.html, README, and evidence JSON
  OfflinePackager-->>CLI: Return entry and evidence paths
  CLI-->>Developer: Print test-only output details
Loading

Possibly related PRs

  • imjlk/mpgd-kit#7: Introduced the CLI surface extended by this offline-playtest command.
  • imjlk/mpgd-kit#113: Updated the same AIT devtools version in application and template manifests.
  • imjlk/mpgd-kit#130: Updated the same AIT adapter, SDK, and workspace integration surfaces.

Poem

A rabbit packs the preview tight,
With hashes glowing in the night.
CSP guards every hop and hare,
Stable tools align just right.
“Test-only,” the rabbit sings—
Then opens files without wings.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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
Title check ✅ Passed The title clearly and concisely describes the main CLI change: test-only offline playtest packaging.
Description check ✅ Passed The description explains the change, scope, limitations, and verification commands, but uses different headings and does not include checklist formatting.
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.
✨ 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/offline-network-policy

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.

@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: 2

🧹 Nitpick comments (2)
packages/cli/src/offline-playtest.ts (2)

77-103: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider adding common Phaser asset types to mimeTypes.

readAssetDataUrl throws for any extension that is absent from this map. Phaser games commonly ship .m4a, .opus, .fnt, .atlas, .glsl, and .gltf/.glb files. Those references fail packaging today. Add the common types, or keep the strict list and document the supported extension set in the limitations text.

🤖 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 `@packages/cli/src/offline-playtest.ts` around lines 77 - 103, Expand the
mimeTypes map used by readAssetDataUrl to include the common Phaser asset
extensions .m4a, .opus, .fnt, .atlas, .glsl, .gltf, and .glb with appropriate
MIME types. Ensure these assets no longer trigger the unsupported-extension
error during packaging.

718-720: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Escape quote before building the regular expression.

quote currently comes from a capture group limited to ", ', and `, so new RegExp(quote, 'gu') is safe today. The call is fragile against a future change to literalPattern. Use escapeRegExp(quote), or replace the regular expression with split(quote).join(...). This also removes the static-analysis warning.

♻️ Proposed change
 function escapeForQuote(value: string, quote: string): string {
-  return value.replace(/\\/gu, '\\\\').replace(new RegExp(quote, 'gu'), `\\${quote}`);
+  return value.replace(/\\/gu, '\\\\').replace(new RegExp(escapeRegExp(quote), 'gu'), `\\${quote}`);
 }
🤖 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 `@packages/cli/src/offline-playtest.ts` around lines 718 - 720, Update
escapeForQuote to escape quote before using it to construct the regular
expression, preferably via the existing escapeRegExp helper, or avoid dynamic
regex construction with split/join. Preserve escaping of backslashes and quote
characters while removing the static-analysis warning.

Source: Linters/SAST tools

🤖 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/cli/src/offline-playtest.ts`:
- Around line 204-219: Update extractModuleEntry so inline script bodies are
also validated by assertSupportedBundledRuntime after the external module entry
is removed, or explicitly reject any remaining inline script elements. Ensure
new Worker usage in inline scripts cannot pass packaging while preserving
extraction of the single external module entry.

In `@README.md`:
- Around line 98-99: Update the README command output path from
artifacts/offline-playtest/index.html to
examples/phaser-starter/artifacts/offline-playtest/index.html, matching the game
root passed by the command and the actual generated file location.

---

Nitpick comments:
In `@packages/cli/src/offline-playtest.ts`:
- Around line 77-103: Expand the mimeTypes map used by readAssetDataUrl to
include the common Phaser asset extensions .m4a, .opus, .fnt, .atlas, .glsl,
.gltf, and .glb with appropriate MIME types. Ensure these assets no longer
trigger the unsupported-extension error during packaging.
- Around line 718-720: Update escapeForQuote to escape quote before using it to
construct the regular expression, preferably via the existing escapeRegExp
helper, or avoid dynamic regex construction with split/join. Preserve escaping
of backslashes and quote characters while removing the static-analysis warning.
🪄 Autofix

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: f84f5334-8841-4b08-9494-c4495de2e70a

📥 Commits

Reviewing files that changed from the base of the PR and between 9b4e1d4 and c7ba417.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (10)
  • .sampo/changesets/offline-playtest-bundle.md
  • README.md
  • docs/GAME_DEVELOPMENT.md
  • package.json
  • packages/cli/package.json
  • packages/cli/src/index.ts
  • packages/cli/src/offline-playtest.ts
  • packages/cli/templates/phaser-game/README.md
  • packages/cli/templates/phaser-game/docs/MPGD_KIT_WORKFLOWS.md
  • tools/smoke/cli-offline-playtest.ts

Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread README.md Resolved

@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: c7ba4174e7

ℹ️ 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 packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
@imjlk

imjlk commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@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: 2f5e37b901

ℹ️ 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 packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
@imjlk

imjlk commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@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: 3

🤖 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/cli/src/offline-playtest.ts`:
- Line 241: Update the script validation around
assertSupportedBundledRuntime(output) to match external script tags regardless
of whether their bodies are empty or contain fallback content, so every
src-based script is counted and rejected when not inlined. Add a smoke fixture
covering an external script with a non-whitespace fallback body.
- Around line 369-370: Replace raw CSS string matching and substitution in
packages/cli/src/offline-playtest.ts at lines 369-370 and 384-445 with CSS token
parsing: process only genuine CSS url tokens, detect and report only actual
`@import` at-keywords, and avoid matches inside strings, comments, or content
values. Update the smoke fixture in tools/smoke/cli-offline-playtest.ts at lines
108-121 and 243-255 to cover escaped `@import` tokens and text that must not be
rewritten.

In `@tools/validate-starter-workflow.ts`:
- Around line 789-798: The peer-rule check in the validator must verify the rule
within the YAML `peerDependencyRules.allowedVersions` mapping rather than using
`workspace.includes`. Update the validation around `expectedAitDevtoolsPeerRule`
to parse the workspace or scope matching to that specific mapping, so comments
and rules under other keys do not satisfy it; add a negative test covering a
commented or misplaced rule.
🪄 Autofix

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: 764dceda-7e7d-4fe2-b5ee-23352aac302a

📥 Commits

Reviewing files that changed from the base of the PR and between c7ba417 and 18fbff2.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (16)
  • .sampo/changesets/offline-playtest-bundle.md
  • README.md
  • adapters/ait/package.json
  • adapters/ait/src/host.test.ts
  • apps/target-ait/package.json
  • docs/GAME_DEVELOPMENT.md
  • docs/ROADMAP_CHECKLIST.md
  • packages/cli/src/offline-playtest.ts
  • packages/cli/templates/phaser-game/README.md
  • packages/cli/templates/phaser-game/apps/target-ait/package.json
  • packages/cli/templates/phaser-game/docs/MPGD_KIT_WORKFLOWS.md
  • packages/cli/templates/phaser-game/package.json
  • packages/cli/templates/phaser-game/pnpm-workspace.yaml
  • pnpm-workspace.yaml
  • tools/smoke/cli-offline-playtest.ts
  • tools/validate-starter-workflow.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • README.md
  • docs/GAME_DEVELOPMENT.md
  • packages/cli/templates/phaser-game/docs/MPGD_KIT_WORKFLOWS.md
  • packages/cli/templates/phaser-game/README.md

Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread tools/validate-starter-workflow.ts Resolved

@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: 18fbff2b59

ℹ️ 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 packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
@imjlk

imjlk commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@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: ff284d4c6b

ℹ️ 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 packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
@imjlk

imjlk commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@imjlk

imjlk commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Already reviewed.

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.

Actionable comments posted: 3

🧹 Nitpick comments (2)
packages/cli/src/offline-playtest.ts (1)

1171-1178: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Consider checking the asset size before base64 encoding.

readAssetDataUrl reads the whole asset and produces a base64 string. The total size check runs only after the final HTML is assembled. A single large asset therefore allocates the buffer, the base64 string, and the accumulated HTML before the limit rejects the run. A cheap statSync(assetFile).size check against the configured maximum fails earlier and keeps memory bounded.

This is a test-only tool, so treat this as optional.

🤖 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 `@packages/cli/src/offline-playtest.ts` around lines 1171 - 1178, Optionally
add an early asset-size guard in readAssetDataUrl using statSync(assetFile).size
before readFileSync and base64 encoding. Compare the file size with the
configured maximum and reject oversized assets before allocating their contents,
while preserving the existing GLTF validation and data-URL flow for permitted
assets.
tools/smoke/cli-offline-playtest.ts (1)

349-361: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a fixture for an asset directory whose name contains regex metacharacters.

The existing fixture uses the file name sprite(2x).png inside the plain assets directory. Only directory names are interpolated into the literal pattern in packages/cli/src/offline-playtest.ts, so this fixture does not exercise that path. A directory named for example assets(2x) currently produces an invalid RegExp. Add such a fixture to lock in the fix.

🤖 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/cli-offline-playtest.ts` around lines 349 - 361, Add a
smoke-playtest fixture alongside the existing parenthesizedCssHtml case using an
asset directory name containing regex metacharacters, such as assets(2x), and
place the CSS and referenced image under that directory. Assert the asset is
inlined successfully, covering the directory interpolation path in
packageAndReadFixture.
🤖 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/cli/src/offline-playtest.ts`:
- Around line 416-422: Escape every entry in context.assetDirectories with the
existing escapeRegExp helper before joining them into assetDirectoryAlternative
in packages/cli/src/offline-playtest.ts#416-422. Add a smoke fixture in
tools/smoke/cli-offline-playtest.ts#349-361 using an asset directory such as
assets(2x), and assert that packaging succeeds and inlines the asset.
- Around line 464-471: Update isJavaScriptScriptType to strip the MIME parameter
portion after the first semicolon, trim the remaining essence, and compare that
normalized value against javascriptScriptTypes. Preserve the existing handling
for undefined or empty type values.

In `@tools/validate-starter-workflow.ts`:
- Around line 2117-2121: The allowedVersions parser in
validatePeerDependencyRuleParser must only scan nested entries when
allowedVersions is a mapping, not a scalar or block scalar. Track the value/node
type when entering allowedVersions, skip nested selector parsing for scalar
values such as allowedVersions: |, and add corresponding block-scalar invalid
cases to the existing invalid fixtures.

---

Nitpick comments:
In `@packages/cli/src/offline-playtest.ts`:
- Around line 1171-1178: Optionally add an early asset-size guard in
readAssetDataUrl using statSync(assetFile).size before readFileSync and base64
encoding. Compare the file size with the configured maximum and reject oversized
assets before allocating their contents, while preserving the existing GLTF
validation and data-URL flow for permitted assets.

In `@tools/smoke/cli-offline-playtest.ts`:
- Around line 349-361: Add a smoke-playtest fixture alongside the existing
parenthesizedCssHtml case using an asset directory name containing regex
metacharacters, such as assets(2x), and place the CSS and referenced image under
that directory. Assert the asset is inlined successfully, covering the directory
interpolation path in packageAndReadFixture.
🪄 Autofix

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: 765764c3-29e3-429f-9079-b47b9e5619e3

📥 Commits

Reviewing files that changed from the base of the PR and between 18fbff2 and 5528446.

📒 Files selected for processing (6)
  • .sampo/changesets/offline-playtest-bundle.md
  • docs/GAME_DEVELOPMENT.md
  • packages/cli/src/offline-playtest.ts
  • packages/cli/templates/phaser-game/README.md
  • tools/smoke/cli-offline-playtest.ts
  • tools/validate-starter-workflow.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • .sampo/changesets/offline-playtest-bundle.md
  • docs/GAME_DEVELOPMENT.md
  • packages/cli/templates/phaser-game/README.md

Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread tools/validate-starter-workflow.ts Resolved

@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: 55284462b2

ℹ️ 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 packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
@imjlk

imjlk commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@imjlk

imjlk commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

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 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: 20c1df9677

ℹ️ 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 packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
@imjlk

imjlk commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@imjlk

imjlk commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

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 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: 2f6c6199ee

ℹ️ 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 packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
@imjlk

imjlk commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@imjlk

imjlk commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Already reviewed.

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)
packages/cli/src/offline-playtest.ts (1)

305-316: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Simplify the loop body.

The loop keeps an empty if body and a trailing blank line. Invert the condition to remove the dead structure.

♻️ Proposed simplification
   for (const externalScript of externalScripts) {
-    if (externalScript === match) {
-      continue;
-    }
-
-    if (!hasNoModuleAttribute(externalScript[2] ?? '')) {
+    if (externalScript !== match && !hasNoModuleAttribute(externalScript[2] ?? '')) {
       throw new Error(
         'Offline playtest does not support additional external scripts beyond the module entry.',
       );
     }
-
   }
🤖 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 `@packages/cli/src/offline-playtest.ts` around lines 305 - 316, In the loop
over externalScripts, invert the match condition so validation runs only when
externalScript !== match, removing the empty continue branch and trailing blank
line while preserving the existing hasNoModuleAttribute check and error
behavior.
🤖 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 `@packages/cli/src/offline-playtest.ts`:
- Around line 305-316: In the loop over externalScripts, invert the match
condition so validation runs only when externalScript !== match, removing the
empty continue branch and trailing blank line while preserving the existing
hasNoModuleAttribute check and error behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1ca4e5b7-205b-4c24-b7fc-4753481fab43

📥 Commits

Reviewing files that changed from the base of the PR and between 5528446 and 2824416.

📒 Files selected for processing (7)
  • README.md
  • docs/GAME_DEVELOPMENT.md
  • packages/cli/src/offline-playtest.ts
  • packages/cli/templates/phaser-game/README.md
  • packages/cli/templates/phaser-game/docs/MPGD_KIT_WORKFLOWS.md
  • tools/smoke/cli-offline-playtest.ts
  • tools/validate-starter-workflow.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/cli/templates/phaser-game/docs/MPGD_KIT_WORKFLOWS.md
  • packages/cli/templates/phaser-game/README.md
  • README.md
  • tools/validate-starter-workflow.ts
  • docs/GAME_DEVELOPMENT.md

@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: 2824416ae3

ℹ️ 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 packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
@imjlk

imjlk commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@imjlk

imjlk commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="38e6b42e4815ed77571ccc73bde5ad0fd5bc0711"
head="baac48f54e428e9750f735565c43abe414300491"

printf '%s\n' '--- requested revision and ancestry ---'
git rev-parse "$head"
git merge-base --is-ancestor "$base" "$head" &&
  echo 'previous-reviewed-head-is-ancestor: yes' ||
  echo 'previous-reviewed-head-is-ancestor: no'
git show --no-patch --format='%H%n%P%n%s%n%b' "$head"
git log --oneline "${base}..${head}"
git diff --no-ext-diff --name-status "${base}..${head}"
git diff --no-ext-diff --stat "${base}..${head}"
git diff --no-ext-diff --check "${base}..${head}"

printf '%s\n' '--- focused incremental patch ---'
git diff --no-ext-diff --unified=40 "${base}..${head}" -- \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts

printf '%s\n' '--- affected implementation map ---'
ast-grep outline packages/cli/src/offline-playtest.ts \
  --items all --type function \
  --match 'timer|Timer|bind|Bind|callable|Callable|class|Class|heritage|Heritage|optional|Optional|native|Native|alias|Alias'

printf '%s\n' '--- timer binding, inheritance, optional call, and regression references ---'
rg -n -i -C 10 \
  '\b(resolve|track|find|is|assert)[A-Za-z]*(?:Native|Callable|Alias|Binding|Timer|Class|Heritage)[A-Za-z]*\b|\
\b(setTimeout|setInterval|bind|call|apply|extends|super|optional|callback|native callable|class heritage)\b|\
\?\.\s*(?:\(|\[)|\?\.\s*[A-Za-z_$]|shadowed|member-owned' \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts

printf '%s\n' '--- changed source contexts ---'
git diff --no-ext-diff --unified=0 "${base}..${head}" -- \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts |
  awk '
    /^diff --git/ { file=$3; sub("^a/", "", file) }
    /^@@/ && match($0, /\+([0-9]+)(,([0-9]+))?/, p) {
      start=p[1]-35; if (start < 1) start=1
      count=(p[3] ? p[3] : 1); end=p[1]+count+75
      print file, start, end
    }' |
  sort -u |
  while read -r file start end; do
    printf "\n--- %s lines %s-%s ---\n" "$file" "$start" "$end"
    sed -n "${start},${end}p" "$file" |
      awk -v line="$start" '{ printf "%6d  %s\n", line++, $0 }'
  done

Length of output: 38412


🏁 Script executed:

#!/bin/bash
set -euo pipefail

show_range() {
  local file="$1" start="$2" end="$3"
  printf '\n--- %s lines %s-%s ---\n' "$file" "$start" "$end"
  sed -n "${start},${end}p" "$file" |
    awk -v line="$start" '{ printf "%6d  %s\n", line++, $0 }'
}

printf '%s\n' '--- callable validation and resolver ---'
show_range packages/cli/src/offline-playtest.ts 5370 6165

printf '%s\n' '--- runtime normalization and validation order ---'
show_range packages/cli/src/offline-playtest.ts 7350 7485

printf '%s\n' '--- timer and inheritance smoke tests ---'
show_range tools/smoke/cli-offline-playtest.ts 170 265
show_range tools/smoke/cli-offline-playtest.ts 2735 2840

printf '%s\n' '--- optional call and bind coverage ---'
rg -n -i -C 8 \
  'optional.*(fetch|timer|bind|callable)|(?:fetch|setTimeout|setInterval|Function|Worker).*\?\.|\?\.?\s*\(' \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts

printf '%s\n' '--- class heritage and timer binding references ---'
rg -n -i -C 8 \
  'class.*extends|extends.*(?:Worker|Function|Base)|timer-bound-callback|bind\s*\(' \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts

printf '%s\n' '--- diff check ---'
git diff --no-ext-diff --check \
  38e6b42e4815ed77571ccc73bde5ad0fd5bc0711..baac48f54e428e9750f735565c43abe414300491

Length of output: 116229


@imjlk I reviewed exact HEAD baac48f54e428e9750f735565c43abe414300491.

I found one issue.

readNativeCallableClassHeritage() in packages/cli/src/offline-playtest.ts uses \s+ around extends. JavaScript permits comments in this position. Therefore, this source bypasses the new inherited-callable tracking:

const BackgroundWorker = class /* native worker base */ extends Worker {};
new BackgroundWorker("./worker.js");

The expression does not match readNativeCallableClassHeritage(). BackgroundWorker then receives no worker kind. The native Worker validator only detects direct new Worker(...) expressions. The packager can accept a Worker-derived class.

Use javascriptTriviaPatternSource in readNativeCallableClassHeritage(). Add a smoke case for an anonymous class expression with comment trivia before extends.

The timer bind callback-state handling is correct for the inspected cases.

The class chain and named anonymous-class smoke cases cover the normal inheritance forms.

The optional aliased native-fetch smoke case is present.

git diff --check found no whitespace errors.

I completed a static review only. I did not run pnpm check or pnpm smoke:cli-offline-playtest.

You are interacting with an AI system.

imjlk commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Please review current PR HEAD af2dfaaa90cd5d45e11e1352b594a090beb4c6b2. This final incremental follow-up broadens callable class heritage parsing to parenthesized and sequence expressions; all prior timer/optional-call tests remain green.

imjlk commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Please review current PR HEAD af2dfaaa90cd5d45e11e1352b594a090beb4c6b2. This final incremental follow-up broadens callable class heritage parsing to parenthesized and sequence expressions; all prior timer/optional-call tests remain green.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="baac48f54e428e9750f735565c43abe414300491"
head="af2dfaaa90cd5d45e11e1352b594a090beb4c6b2"

printf '%s\n' '--- requested revision and ancestry ---'
git rev-parse "$head"
git merge-base --is-ancestor "$base" "$head" &&
  echo 'previous-reviewed-head-is-ancestor: yes' ||
  echo 'previous-reviewed-head-is-ancestor: no'
git show --no-patch --format='%H%n%P%n%s%n%b' "$head"
git log --oneline "${base}..${head}"
git diff --no-ext-diff --name-status "${base}..${head}"
git diff --no-ext-diff --stat "${base}..${head}"
git diff --no-ext-diff --check "${base}..${head}"

printf '%s\n' '--- focused incremental patch ---'
git diff --no-ext-diff --unified=45 "${base}..${head}" -- \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts

printf '%s\n' '--- affected function map ---'
ast-grep outline packages/cli/src/offline-playtest.ts \
  --items all --type function \
  --match 'heritage|Heritage|class|Class|callable|Callable|native|Native|sequence|Sequence|parenthesized|Parenthesized'

printf '%s\n' '--- class heritage parser, callable resolver, normalizers, and regression cases ---'
rg -n -i -C 12 \
  '\b(readNativeCallableClassHeritage|resolveNativeCallable|assertNoUnsupportedNativeCallables|normalizeStaticJavaScriptPropertyAccess|unwrapJavaScriptParenthesizedRange|findJavaScriptExpressionRange|findMatchingJavaScriptClosingParenthesis)\b|class\s+.*extends|extends\s*\(|extends.*[,)]|heritage|sequence|parenthes|callable class|optional.*call|timer.*bind' \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts

printf '%s\n' '--- changed source contexts ---'
git diff --no-ext-diff --unified=0 "${base}..${head}" -- \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts |
  awk '
    /^diff --git/ { file=$3; sub("^a/", "", file) }
    /^@@/ && match($0, /\+([0-9]+)(,([0-9]+))?/, p) {
      start=p[1]-35; if (start < 1) start=1
      count=(p[3] ? p[3] : 1); end=p[1]+count+80
      print file, start, end
    }' |
  sort -u |
  while read -r file start end; do
    printf "\n--- %s lines %s-%s ---\n" "$file" "$start" "$end"
    sed -n "${start},${end}p" "$file" |
      awk -v line="$start" '{ printf "%6d  %s\n", line++, $0 }'
  done

Length of output: 144949


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="baac48f54e428e9750f735565c43abe414300491"
head="af2dfaaa90cd5d45e11e1352b594a090beb4c6b2"

printf '%s\n' '--- exact incremental patch ---'
git diff --no-ext-diff --unified=20 "${base}..${head}" -- \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts

printf '%s\n' '--- heritage expression classification and body-boundary helpers ---'
sed -n '5738,5795p' packages/cli/src/offline-playtest.ts |
  awk 'BEGIN { line=5738 } { printf "%6d  %s\n", line++, $0 }'
sed -n '6048,6090p' packages/cli/src/offline-playtest.ts |
  awk 'BEGIN { line=6048 } { printf "%6d  %s\n", line++, $0 }'
rg -n -A90 -B8 \
  '^function (findJavaScriptNamedExpressionBody|unwrapBalancedOuterParentheses|findSequenceExpressionLastValue)\b' \
  packages/cli/src/offline-playtest.ts

printf '%s\n' '--- all class-heritage smoke cases and assertion helper ---'
sed -n '190,255p' tools/smoke/cli-offline-playtest.ts |
  awk 'BEGIN { line=190 } { printf "%6d  %s\n", line++, $0 }'
rg -n -A35 -B5 '^async function assertWorkerRejected\b|^function assertWorkerRejected\b' \
  tools/smoke/cli-offline-playtest.ts

printf '%s\n' '--- whitespace check ---'
git diff --no-ext-diff --check "${base}..${head}"

Length of output: 26042


@imjlk I reviewed exact HEAD af2dfaaa90cd5d45e11e1352b594a090beb4c6b2.

The previous reviewed commit baac48f54e428e9750f735565c43abe414300491 is an ancestor of this commit.

The class-heritage parser now reads the full heritage expression up to the class body. It supports trivia around extends.

The native callable resolver now handles:

  • Parenthesized heritage expressions, such as extends (Base).
  • Sequence heritage expressions, such as extends (0, Base).
  • Named and anonymous class forms.

The resolver propagates the native worker kind from Base. The Worker validation then rejects construction through the derived class.

The added smoke tests cover both parenthesized and sequence Worker heritage cases.

git diff --check found no whitespace errors.

I found no new actionable issue in the reviewed changes.

I completed a static review only. I did not run pnpm check or pnpm smoke:cli-offline-playtest.

You are interacting with an AI system.

imjlk commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

Addressed the CodeRabbit finding from baac48f5: af2dfaaa switched class-heritage parsing to javascriptTriviaPatternSource, and fec715c4 adds the exact anonymous-class comment-trivia regression fixture. Offline smoke passes.

imjlk commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Please review final current PR HEAD fec715c47d0accf55a01874a57747d45485e3696, including the timer bind distinction and parenthesized, sequenced, and comment-trivia class heritage regressions.

imjlk commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Please review final current PR HEAD fec715c47d0accf55a01874a57747d45485e3696, including the exact comment-trivia class heritage regression.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="af2dfaaa90cd5d45e11e1352b594a090beb4c6b2"
head="fec715c47d0accf55a01874a57747d45485e3696"

printf '%s\n' '--- requested revision and ancestry ---'
git rev-parse "$head"
git merge-base --is-ancestor "$base" "$head" &&
  echo 'previous-reviewed-head-is-ancestor: yes' ||
  echo 'previous-reviewed-head-is-ancestor: no'
git show --no-patch --format='%H%n%P%n%s%n%b' "$head"
git log --oneline "${base}..${head}"
git diff --no-ext-diff --stat "${base}..${head}"
git diff --no-ext-diff --name-status "${base}..${head}"
git diff --no-ext-diff --check "${base}..${head}"

printf '%s\n' '--- focused incremental patch ---'
git diff --no-ext-diff --unified=45 "${base}..${head}" -- \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts

printf '%s\n' '--- affected function map ---'
ast-grep outline packages/cli/src/offline-playtest.ts \
  --items all --type function \
  --match 'heritage|Heritage|class|Class|callable|Callable|native|Native|trivia|Trivia'

printf '%s\n' '--- parser, callable propagation, and regression references ---'
rg -n -i -C 12 \
  '\b(readNativeCallableClassHeritage|resolveNativeCallable|assertNoUnsupportedNativeCallables|javascriptTriviaPatternSource|findJavaScriptNamedExpressionBody|findSequenceExpressionLastValue|unwrapBalancedOuterParentheses)\b|class\s*/\*|extends\s+Worker|comment-trivia|heritage|anonymous-class' \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts

printf '%s\n' '--- exact relevant source regions ---'
sed -n '5715,5815p' packages/cli/src/offline-playtest.ts |
  awk 'BEGIN { line=5715 } { printf "%6d  %s\n", line++, $0 }'
sed -n '6025,6115p' packages/cli/src/offline-playtest.ts |
  awk 'BEGIN { line=6025 } { printf "%6d  %s\n", line++, $0 }'
rg -n -A35 -B8 \
  'anonymous.*comment|comment.*trivia|native worker base|class /\*' \
  tools/smoke/cli-offline-playtest.ts

Length of output: 70236


@imjlk I reviewed exact HEAD fec715c47d0accf55a01874a57747d45485e3696.

The previous reviewed commit af2dfaaa90cd5d45e11e1352b594a090beb4c6b2 is an ancestor of this commit.

The incremental commit adds the exact comment-trivia regression fixture:

const BackgroundWorker = class /* retained trivia */ extends /* native base */ Worker {};
new BackgroundWorker("./worker.js");

readNativeCallableClassHeritage() uses javascriptTriviaPatternSource before and after extends. It accepts the fixture form.

The callable resolver extracts Worker as the class heritage. It propagates the worker kind to BackgroundWorker. The existing Worker validation rejects construction through that class.

git diff --check found no whitespace errors.

I found no new actionable issue in the reviewed change.

I completed a static review only. I did not run pnpm check or pnpm smoke:cli-offline-playtest.

You are interacting with an AI system.

@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: fec715c47d

ℹ️ 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 packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved

imjlk commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Please review current PR HEAD 8fb8b97a3369647d94e9da85b5cc5aee31c98f8b. This consolidates native class-heritage rejection, bind.call argument provenance, dynamic HTML/SVG script blocking, and browser-compatible raw-text end-tag parsing.

imjlk commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Please review current PR HEAD 8fb8b97a3369647d94e9da85b5cc5aee31c98f8b. This consolidates native class-heritage rejection, bind.call argument provenance, dynamic HTML/SVG script blocking, and browser-compatible raw-text end-tag parsing.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="fec715c47d0accf55a01874a57747d45485e3696"
head="8fb8b97a3369647d94e9da85b5cc5aee31c98f8b"

printf '%s\n' '--- requested revision and ancestry ---'
git rev-parse "$head"
git merge-base --is-ancestor "$base" "$head" &&
  echo 'previous-reviewed-head-is-ancestor: yes' ||
  echo 'previous-reviewed-head-is-ancestor: no'
git show --no-patch --format='%H%n%P%n%s%n%b' "$head"
git log --oneline "${base}..${head}"
git diff --no-ext-diff --name-status "${base}..${head}"
git diff --no-ext-diff --stat "${base}..${head}"
git diff --no-ext-diff --check "${base}..${head}"

printf '%s\n' '--- focused incremental patch ---'
git diff --no-ext-diff --unified=35 "${base}..${head}" -- \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts

printf '%s\n' '--- affected implementation map ---'
ast-grep outline packages/cli/src/offline-playtest.ts \
  --items all --type function \
  --match 'class|Class|heritage|Heritage|bind|Bind|call|Call|script|Script|raw|Raw|html|Html|svg|Svg|native|Native'

printf '%s\n' '--- parser, validator, and regression references ---'
rg -n -i -C 12 \
  '\b(readNativeCallableClassHeritage|resolveNativeCallable|assertNoUnsupportedNativeCallables|\
findJavaScript.*Argument|bind.*call|call.*bind|\
assertNo.*Script|dynamic.*(?:html|svg|script)|raw.*text|end.tag|\
parse.*(?:html|svg)|javascriptTriviaPatternSource)\b|\
class.*extends|\.bind\s*\(|\.call\s*\(|createElement|innerHTML|outerHTML|insertAdjacentHTML|\
<svg|<script|</script' \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts

printf '%s\n' '--- changed source contexts ---'
git diff --no-ext-diff --unified=0 "${base}..${head}" -- \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts |
  awk '
    /^diff --git/ { file=$3; sub("^a/", "", file) }
    /^@@/ && match($0, /\+([0-9]+)(,([0-9]+))?/, p) {
      start=p[1]-35; if (start < 1) start=1
      count=(p[3] ? p[3] : 1); end=p[1]+count+80
      print file, start, end
    }' |
  sort -u |
  while read -r file start end; do
    printf "\n--- %s lines %s-%s ---\n" "$file" "$start" "$end"
    sed -n "${start},${end}p" "$file" |
      awk -v line="$start" '{ printf "%6d  %s\n", line++, $0 }'
  done

Length of output: 59519


🏁 Script executed:

#!/bin/bash
set -euo pipefail

show_range() {
  local file="$1" start="$2" end="$3"
  printf '\n--- %s lines %s-%s ---\n' "$file" "$start" "$end"
  sed -n "${start},${end}p" "$file" |
    awk -v line="$start" '{ printf "%6d  %s\n", line++, $0 }'
}

printf '%s\n' '--- raw-text parsing and HTML consumers ---'
show_range packages/cli/src/offline-playtest.ts 620 835
show_range packages/cli/src/offline-playtest.ts 4950 5075
show_range packages/cli/src/offline-playtest.ts 5150 5348

printf '%s\n' '--- native callable resolution and class heritage rejection ---'
show_range packages/cli/src/offline-playtest.ts 5400 5750
show_range packages/cli/src/offline-playtest.ts 5970 6235

printf '%s\n' '--- dynamic-element validation and runtime guard assembly ---'
show_range packages/cli/src/offline-playtest.ts 5340 5405
show_range packages/cli/src/offline-playtest.ts 6235 6335

printf '%s\n' '--- exact smoke-test contexts ---'
show_range tools/smoke/cli-offline-playtest.ts 185 255
show_range tools/smoke/cli-offline-playtest.ts 720 815
show_range tools/smoke/cli-offline-playtest.ts 945 1010
show_range tools/smoke/cli-offline-playtest.ts 2780 2870

printf '%s\n' '--- focused references ---'
rg -n -i -C 6 \
  'findNativeCallableClassHeritages|readNativeCallableClassHeritage|deriveBoundNativeCallableKinds|readBoundNativeCallableExpression|createHtmlRawTextPattern|transformOutsideHtmlRawText|maskHtmlRawTextBodies|dynamically created script|blockedTag|nested-bind-call|attributed-script-end|property-stored-worker' \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts

printf '%s\n' '--- full incremental diff integrity ---'
git diff --no-ext-diff --check \
  fec715c47d0accf55a01874a57747d45485e3696..8fb8b97a3369647d94e9da85b5cc5aee31c98f8b

Length of output: 111764


@imjlk I reviewed exact HEAD 8fb8b97a3369647d94e9da85b5cc5aee31c98f8b.

I found one issue.

renderOfflineRuntimeGuard() blocks script only when the namespace is HTML or omitted. The blockedTag() condition applies the namespace check to every blocked tag:

(namespace===undefined||String(namespace).toLowerCase()==='http://www.w3.org/1999/xhtml')
  && ['meta','object','embed','script'].includes(...)

Therefore, Document.prototype.createElementNS() still permits an SVG script at runtime:

document.createElementNS("http://www.w3.org/2000/svg", "script");

The static validator rejects the direct form. However, it cannot reject all runtime-computed tag or namespace values. An SVG script can then bypass the runtime guard.

Apply the HTML-namespace restriction only to meta, object, and embed. Reject script in every namespace. Add a runtime-guard regression that verifies SVG script creation throws after packaging.

The incremental change correctly adds:

  • Direct rejection for native Worker and evaluator class heritage.
  • bind.call() argument handling for timer callback provenance.
  • Static rejection for dynamic HTML and SVG script creation.
  • Raw-text closing-tag handling for <script ignored>.

git diff --check found no whitespace errors.

I completed a static review only. I did not run pnpm check or pnpm smoke:cli-offline-playtest.

You are interacting with an AI system.

imjlk commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

Addressed the remaining SVG runtime bypass in d14db81. Document.prototype.createElementNS now rejects script in every namespace, while the HTML-only tag policy remains namespace-scoped. I also added a VM-based regression that executes the generated runtime guard and verifies SVG createElementNS(..., 'script') throws. pnpm smoke:cli-offline-playtest and the full pnpm check pass.

imjlk commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

/coderabbitai review d14db81

imjlk commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

/codex review d14db81

imjlk commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Please review exact current PR HEAD d14db813ce066cd1e2a462cd4eb366b2e91a6190, including the namespace-independent runtime script block and VM execution regression.

imjlk commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Please review exact current PR HEAD d14db813ce066cd1e2a462cd4eb366b2e91a6190. The prior SVG namespace finding is fixed and covered by executing the generated runtime guard in a VM regression.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="8fb8b97a3369647d94e9da85b5cc5aee31c98f8b"
head="d14db813ce066cd1e2a462cd4eb366b2e91a6190"

printf '%s\n' '--- revision and ancestry ---'
git rev-parse "$head"
git merge-base --is-ancestor "$base" "$head" && echo 'previous-reviewed-head-is-ancestor: yes' || echo 'previous-reviewed-head-is-ancestor: no'
git show --no-patch --format='%H%n%P%n%s%n%b' "$head"
git log --oneline "${base}..${head}"
git diff --no-ext-diff --name-status "${base}..${head}"
git diff --no-ext-diff --stat "${base}..${head}"
git diff --no-ext-diff --check "${base}..${head}"

printf '%s\n' '--- incremental patch ---'
git diff --no-ext-diff --unified=45 "${base}..${head}" -- \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts

printf '%s\n' '--- relevant implementation map ---'
ast-grep outline packages/cli/src/offline-playtest.ts \
  --items all --type function \
  --match 'render|Render|runtime|Runtime|guard|Guard|element|Element|script|Script'

printf '%s\n' '--- runtime guard and regression references ---'
rg -n -i -C 12 \
  '\b(renderOfflineRuntimeGuard|blockedTag|createElementNS|createElement|vm|runIn|context|svg|script|namespace)\b' \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts

printf '%s\n' '--- changed source contexts ---'
git diff --no-ext-diff --unified=0 "${base}..${head}" -- \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts |
  awk '
    /^diff --git/ { file=$3; sub("^a/", "", file) }
    /^@@/ && match($0, /\+([0-9]+)(,([0-9]+))?/, p) {
      start=p[1]-30; if (start < 1) start=1
      count=(p[3] ? p[3] : 1); end=p[1]+count+70
      print file, start, end
    }' |
  sort -u |
  while read -r file start end; do
    printf "\n--- %s lines %s-%s ---\n" "$file" "$start" "$end"
    sed -n "${start},${end}p" "$file" |
      awk -v line="$start" '{ printf "%6d  %s\n", line++, $0 }'
  done

Length of output: 202191


@imjlk I reviewed exact HEAD d14db813ce066cd1e2a462cd4eb366b2e91a6190.

The previous reviewed commit 8fb8b97a3369647d94e9da85b5cc5aee31c98f8b is an ancestor of this commit.

The runtime guard now rejects script in every namespace through Document.prototype.createElementNS().

The guard keeps the HTML-namespace restriction for meta, object, and embed.

The VM regression extracts the generated guard from the packaged HTML. It executes the guard. It verifies that this call throws:

document.createElementNS("http://www.w3.org/2000/svg", "script")

This resolves the prior SVG namespace bypass.

git diff --check found no whitespace errors.

I found no new actionable issue in the reviewed change.

I completed a static review only. I did not run pnpm check or pnpm smoke:cli-offline-playtest.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

You are interacting with an AI system.

@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: d14db813ce

ℹ️ 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 packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved
Comment thread packages/cli/src/offline-playtest.ts Resolved

imjlk commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

Implemented the six exact-head findings in c328579 as a category-wide hardening pass (qualified DOM names, evaluator invocation forms, native style receivers, markup sinks, reflective workers, and all navigation setters). Full pnpm check, the offline CLI smoke suite, git diff --check, and delegated OCR file/rule review all pass.

@coderabbitai review
@codex review

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="d14db813ce066cd1e2a462cd4eb366b2e91a6190"

printf '%s\n' '--- PR head and ancestry ---'
git rev-parse HEAD
git merge-base --is-ancestor "$base" HEAD &&
  echo 'previous-reviewed-head-is-ancestor: yes' ||
  echo 'previous-reviewed-head-is-ancestor: no'
git show --no-patch --format='%H%n%P%n%s%n%b' HEAD
git log --oneline "${base}..HEAD"

printf '%s\n' '--- changed paths and patch integrity ---'
git diff --no-ext-diff --name-status "${base}..HEAD"
git diff --no-ext-diff --stat "${base}..HEAD"
git diff --no-ext-diff --check "${base}..HEAD"

printf '%s\n' '--- focused incremental patch ---'
git diff --no-ext-diff --unified=32 "${base}..HEAD" -- \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts

printf '%s\n' '--- relevant function outline ---'
ast-grep outline packages/cli/src/offline-playtest.ts \
  --items all --type function \
  --match 'dom|Dom|style|Style|markup|Markup|html|Html|worker|Worker|navigation|Navigation|location|Location|evaluator|Evaluator|runtime|Runtime|guard|Guard'

printf '%s\n' '--- implementation and regression references ---'
rg -n -i -C 10 \
  '\b(renderOfflineRuntimeGuard|assertSupportedBundledRuntime|assertNoUnsupportedNativeCallables|\
createElement(?:NS)?|innerHTML|outerHTML|insertAdjacentHTML|cssText|setProperty|\
Worker|SharedWorker|Reflect|eval|Function|setTimeout|setInterval|location|assign|replace|href|\
navigation|qualified|style|markup)\b' \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts

Length of output: 77519


🏁 Script executed:

#!/bin/bash
set -euo pipefail

show_range() {
  local file="$1"
  local start="$2"
  local end="$3"
  printf '\n--- %s lines %s-%s ---\n' "$file" "$start" "$end"
  sed -n "${start},${end}p" "$file" |
    awk -v line="$start" '{ printf "%6d  %s\n", line++, $0 }'
}

printf '%s\n' '--- runtime guard and bundled-runtime validation ---'
show_range packages/cli/src/offline-playtest.ts 5350 5725

printf '%s\n' '--- native callable classification and reflective invocation validation ---'
show_range packages/cli/src/offline-playtest.ts 5725 6255

printf '%s\n' '--- dynamic DOM, markup, and native document-element validation ---'
show_range packages/cli/src/offline-playtest.ts 6255 6715

printf '%s\n' '--- worker and navigation validation ---'
show_range packages/cli/src/offline-playtest.ts 6815 7355

printf '%s\n' '--- new smoke-test fixtures, including runtime guard execution ---'
sed -n '1,150p;230,420p;850,1030p;2120,2210p;2925,3025p' \
  tools/smoke/cli-offline-playtest.ts |
  awk '{ printf "%6d  %s\n", NR, $0 }'

printf '%s\n' '--- focused implementation and regression references ---'
rg -n -i -C 5 \
  'renderOfflineRuntimeHardeningGuard|assertNoUnsafeMarkupInjection|isNativeDocumentElementExpression|\
Reflect\.(apply|construct)|native-document-style|markup|svg:script|\
location-(host|hostname|pathname|port|protocol|search)|optional-(eval|function)|indirect-sequence-eval' \
  packages/cli/src/offline-playtest.ts \
  tools/smoke/cli-offline-playtest.ts

Length of output: 120311


@imjlk I reviewed exact HEAD c328579b2d77ac47d8d969719a125f2ead4dd416.

The previous reviewed commit d14db813ce066cd1e2a462cd4eb366b2e91a6190 is an ancestor of this commit.

The incremental changes address the stated categories:

  • Qualified native document element receivers now support style asset inlining and reject external style URLs.
  • Native evaluator checks now cover optional calls, grouped sequence calls, and direct Reflect.apply() or Reflect.construct() forms.
  • Dynamic DOM script checks now use the local name. This rejects svg:script.
  • Native DOM markup sinks now reject innerHTML, outerHTML, insertAdjacentHTML, setHTML, and setHTMLUnsafe.
  • Runtime hardening blocks the same markup sinks, Range.prototype.createContextualFragment(), and reflective Worker construction.
  • Navigation validation and runtime hardening now cover host, hostname, pathname, port, protocol, and search. Fragment-only location.hash remains allowed.

The smoke suite includes static and VM-executed regressions for these paths. The member-owned markup and style cases remain permitted.

git diff --check reported no whitespace errors.

I found no new actionable issue in the reviewed changes.

I completed a static review only. I did not independently run pnpm check or pnpm smoke:cli-offline-playtest.

You are interacting with an AI system.

@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: c328579b2d

ℹ️ 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".

}

function renderOfflineRuntimeHardeningGuard(): string {
return `(()=>{const denied=(api,value)=>new TypeError('[mpgd offline playtest] '+api+' blocked network access: '+String(value));const localName=(name)=>String(name).toLowerCase().split(':').at(-1);if(globalThis.Document){for(const methodName of ['createElement','createElementNS']){const method=Document.prototype[methodName];if(typeof method==='function'){Document.prototype[methodName]=function(...args){const name=args[methodName==='createElementNS'?1:0];if(localName(name)==='script')throw denied('document.'+methodName,name);return method.apply(this,args)}}}}const blockMarkup=(prototype)=>{if(!prototype)return;for(const property of ['innerHTML','outerHTML']){const descriptor=Object.getOwnPropertyDescriptor(prototype,property);if(descriptor?.set){try{Object.defineProperty(prototype,property,{...descriptor,set(value){throw denied(property,value)}})}catch{}}}for(const methodName of ['insertAdjacentHTML','setHTML','setHTMLUnsafe']){if(typeof prototype[methodName]==='function'){try{Object.defineProperty(prototype,methodName,{configurable:true,writable:true,value:(...args)=>{throw denied(methodName,args.at(-1))}})}catch{}}}};blockMarkup(globalThis.Element?.prototype);blockMarkup(globalThis.ShadowRoot?.prototype);if(globalThis.Range?.prototype&&typeof Range.prototype.createContextualFragment==='function'){try{Object.defineProperty(Range.prototype,'createContextualFragment',{configurable:true,writable:true,value:(value)=>{throw denied('Range.createContextualFragment',value)}})}catch{}}for(const name of ['Worker','SharedWorker']){const Native=globalThis[name];if(typeof Native==='function'){try{globalThis[name]=new Proxy(Native,{construct(_target,args){throw denied(name,args[0])}})}catch{}}}if(globalThis.Location){for(const property of ['href','host','hostname','pathname','port','protocol','search']){const descriptor=Object.getOwnPropertyDescriptor(Location.prototype,property);if(descriptor?.set){try{Object.defineProperty(Location.prototype,property,{...descriptor,set(value){throw denied('location.'+property,value)}})}catch{}}}}})();`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reject runtime-installed string event handlers

When retained code calls document.body.setAttribute("onclick", "window.location='https://example.com'"), the handler body remains hidden inside a string and passes bundled-runtime navigation validation. The CSP explicitly permits inline script, the runtime guards do not wrap setAttribute, and the click guard only rejects non-fragment anchors, so clicking a non-anchor descendant executes the handler and navigates away from an artifact claiming to block script-driven navigation. Reject native on* attribute writes just as source HTML event-handler attributes are rejected.

Useful? React with 👍 / 👎.

Comment on lines +7214 to +7215
if (target === undefined || property !== 'href') {
continue;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Cover every Location setter in descriptor checks

This check only rejects a descriptor lookup when the property is exactly href, so Object.getOwnPropertyDescriptor(location, "pathname").set.call(location, "/escape") passes validation and invokes the native navigation setter without matching a direct Location assignment. Location navigation attributes are legacy-unforgeable own properties, so the attempted Location.prototype setter replacement does not protect this path; include all newly covered navigation attributes here rather than retaining the href-only condition.

Useful? React with 👍 / 👎.

Comment on lines +1971 to +1972
if (css === undefined) {
return;

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 unresolved resource-bearing style values

When a proven native receiver uses a runtime-computed resource value, such as document.body.style.backgroundImage = url("/assets/${theme}.png")``, static resolution returns undefined and this branch silently preserves the assignment. The generated direct-file CSP permits images only from `data:` or `blob:`, so the artifact packages successfully but the background fails at runtime; reject unresolved values for resource-bearing CSS properties while continuing to allow dynamic non-resource properties such as `color`.

Useful? React with 👍 / 👎.

Comment on lines +3784 to +3786
const loaderPattern = new RegExp(
`(?<![$.\\u200C\\u200D\\p{ID_Continue}])(${javascriptIdentifierPatternSource})\\s*\\.\\s*load\\s*\\.\\s*(${loaderMethods})\\s*\\(`,
'gu',

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 Trace bound Phaser loader methods

When application code binds a proven loader method, for example const loadImage = scene.load.image.bind(scene.load); loadImage("hero", "/assets/pixel.png"), this direct receiver.load.method(...) pattern never marks the URL argument for inlining. The artifact therefore retains the local path, and Phaser's eventual XHR is rejected by the generated runtime guard because only data: and blob: URLs are allowed; propagate proven Phaser loader provenance through bind and aliases or reject such retained calls during packaging.

Useful? React with 👍 / 👎.

@imjlk
imjlk merged commit 0fbd973 into main Aug 11, 2026
6 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Aug 11, 2026
@imjlk
imjlk deleted the codex/offline-network-policy branch October 27, 2026 11:26
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