You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Mini App contract forward port and manifest compatibility #252
The repository carries the shipped generation of the Mini App contract, minus its window block, and an
installed Mini App package written for the desktop client is accepted by the package reader instead of
being rejected before it can run.
Acceptance criteria
The Mini App contract matches the shipped generation's leading part and omits the window block as
one contiguous tail, rather than as hand-picked omissions.
The type surface compiles with no new workspace dependency, and no existing consumer of the Mini
App response types needs a change.
A package manifest declaring surface.window, agentAccess and agentConcurrency passes the
reader; surface.window has no effect, and the two agent keys are validated and preserved.
A manifest declaring an unknown key still fails, so the allowlist has not become a passthrough.
The repository's file-level and source gates pass.
What is omitted is shipped lines 966-1267: the argv surface id, the surface.window whitelist and
the page's getState/update/focus handle.
One correction to the ticket's premise, measured rather than assumed. The tail is not purely
window code. isPlainRecord is declared at shipped line 1156 — inside the window block — and the
agent parsers above use it nine times (shipped lines 419, 436, 448, 456, 474, 488, 497, 509, 514).
Truncating at 964 without it does not compile: pnpm typecheck reported TS2304: Cannot find name 'isPlainRecord' at 474, 488, 497, 509, 514 plus the resulting TS18046/TS2339 cascade. The five lines are therefore hoisted verbatim to the seam, and diff <(sed -n '1156,1160p' <shipped>) <(tail -5 packages/shared/src/miniapp-surface.ts) is empty.
That is the port's only divergence from a pure prefix, and ADR 0020 now states it.
The same measurement also disproved the ADR's claim that "the first 54 lines of the shipped file
reproduce this repository's file exactly". It does not: the shipped file opens with a six-line
type-only import, and it adds detached/presentationRevision and detach_failed/attach_failed, which moves MiniAppOpenResponse/MiniAppControlResponse below the
new start and page-open types. The shipped leading part is a strict superset of the old 54 lines, not
a line-identical prefix. ADR 0020 §"The contract baseline" is corrected in this PR — the decision is
unchanged, only the wording that implementation disproved.
2. The type surface compiles with no new workspace dependency, and no existing consumer needs a change
No manifest or lockfile change: the diff touches no package.json and no pnpm-lock.yaml. The only
import added by the contract is ./questionnaire.js, which was already exported and byte-identical
(diff empty).
Consumers of the response types were checked rather than assumed — the only two are process-local-application-contract.ts:26,43,134 and process-local-miniapp-application.ts:1,93,116,
and both use MiniAppSurfaceSummary, whose shape did not change. MiniAppSurfaceTabSummary, MiniAppListResponse, MiniAppOpenResponse and MiniAppControlResponse
still have no consumer, so the added required fields and error codes break no call site.
3. A manifest declaring surface.window, agentAccess and agentConcurrency passes the reader
New suite packages/local-runtime-v2/test/unit/plugin-system/miniapp-manifest.test.ts,
registered in test/vitest-suites.json (capability group):
$ pnpm run test:capabilities
Test Files 235 passed (235)
Tests 5811 passed | 18 skipped (5829)
The cases that answer this criterion:
reads a manifest written for the shipped client — one manifest declaring all three keys; the
contribution carries agentAccess: ['session.run'] and agentConcurrency: 4.
gives surface.window no effect (three rows: a desktop declaration, a declaration the dropped rule
set would reject, and a value of the wrong type) — surface reads back as { path: '/dashboard' }
in every case. Accepting the key is not supporting it: nothing in this repository reads the value.
deduplicates agentAccess — ['session.run', 'session.run'] reads back as ['session.run'].
omits both agent keys when the manifest does not declare them.
fails closed for agentAccess / fails closed for agentConcurrency — the allowlist is session.run only, and the bound is an integer in 1..MINIAPP_AGENT_MAX_CONCURRENCY (32, declared
in service/miniapp/contracts.ts and referenced by the reader). Codes: MINIAPP_AGENT_ACCESS_INVALID, MINIAPP_AGENT_CONCURRENCY_INVALID.
Both keys are preserved on MiniAppContribution (agentAccess?, agentConcurrency?) so the agent
service can enforce them when it lands; no runtime behaviour changes in this PR.
The suite was proven red before green: against the previous reader 13 of 16 cases fail
(expected PluginReaderError: MINIAPP_MANIFEST_SCHEMA_INVALID ... to match object { code: ... }), and
16 of 16 pass here.
4. A manifest declaring an unknown key still fails
fails a manifest with an unknown top-level key → MINIAPP_MANIFEST_SCHEMA_INVALID
fails an unknown key beside surface.window → MINIAPP_SURFACE_INVALID
SURFACE_FIELDS and MINIAPP_FIELDS stay hard Set allowlists, so the three new keys are enumerated
explicitly rather than a wildcard opening the reader up.
5. The repository's file-level and source gates pass
$ node scripts/source-inventory.mjs --write
Recorded 5451 reviewed source paths.
$ pnpm check:source
Public source check passed: 5451 files, workspace exports and native helper integrity verified.
$ git diff --check # clean
$ pnpm build
Built MiniMax Code 0.6.5 from 6290 source files.
The inventory gained exactly one path — the new test file — and no path was removed or renamed.
Not verified:pnpm verify in full. Its test:webui-browser and release-package steps were not
run locally; the change is content-only and touches no client behaviour and no export path, so those
are left to CI on PR #261.
Activity
Fectivnfy112357 commentedon Oct 26, 2026
Acceptance evidence. Branch
feat/miniapp-contract-forward-port, commit2ee6a830, PR #261.1. The contract matches the shipped generation's leading part and omits the window block as one contiguous tail
The file is a byte-for-byte copy of the shipped leading part, then the helper noted below:
What is omitted is shipped lines 966-1267: the argv surface id, the
surface.windowwhitelist andthe page's
getState/update/focushandle.One correction to the ticket's premise, measured rather than assumed. The tail is not purely
window code.
isPlainRecordis declared at shipped line 1156 — inside the window block — and theagent parsers above use it nine times (shipped lines 419, 436, 448, 456, 474, 488, 497, 509, 514).
Truncating at 964 without it does not compile:
pnpm typecheckreportedTS2304: Cannot find name 'isPlainRecord'at 474, 488, 497, 509, 514 plus the resultingTS18046/TS2339cascade. The five lines are therefore hoisted verbatim to the seam, anddiff <(sed -n '1156,1160p' <shipped>) <(tail -5 packages/shared/src/miniapp-surface.ts)is empty.That is the port's only divergence from a pure prefix, and ADR 0020 now states it.
The same measurement also disproved the ADR's claim that "the first 54 lines of the shipped file
reproduce this repository's file exactly". It does not: the shipped file opens with a six-line
type-only import, and it adds
detached/presentationRevisionanddetach_failed/attach_failed, which movesMiniAppOpenResponse/MiniAppControlResponsebelow thenew start and page-open types. The shipped leading part is a strict superset of the old 54 lines, not
a line-identical prefix. ADR 0020 §"The contract baseline" is corrected in this PR — the decision is
unchanged, only the wording that implementation disproved.
2. The type surface compiles with no new workspace dependency, and no existing consumer needs a change
No manifest or lockfile change: the diff touches no
package.jsonand nopnpm-lock.yaml. The onlyimport added by the contract is
./questionnaire.js, which was already exported and byte-identical(
diffempty).Consumers of the response types were checked rather than assumed — the only two are
process-local-application-contract.ts:26,43,134andprocess-local-miniapp-application.ts:1,93,116,and both use
MiniAppSurfaceSummary, whose shape did not change.MiniAppSurfaceTabSummary,MiniAppListResponse,MiniAppOpenResponseandMiniAppControlResponsestill have no consumer, so the added required fields and error codes break no call site.
3. A manifest declaring
surface.window,agentAccessandagentConcurrencypasses the readerNew suite
packages/local-runtime-v2/test/unit/plugin-system/miniapp-manifest.test.ts,registered in
test/vitest-suites.json(capability group):The cases that answer this criterion:
reads a manifest written for the shipped client— one manifest declaring all three keys; thecontribution carries
agentAccess: ['session.run']andagentConcurrency: 4.gives surface.window no effect(three rows: a desktop declaration, a declaration the dropped ruleset would reject, and a value of the wrong type) —
surfacereads back as{ path: '/dashboard' }in every case. Accepting the key is not supporting it: nothing in this repository reads the value.
deduplicates agentAccess—['session.run', 'session.run']reads back as['session.run'].omits both agent keys when the manifest does not declare them.fails closed for agentAccess/fails closed for agentConcurrency— the allowlist issession.runonly, and the bound is an integer in1..MINIAPP_AGENT_MAX_CONCURRENCY(32, declaredin
service/miniapp/contracts.tsand referenced by the reader). Codes:MINIAPP_AGENT_ACCESS_INVALID,MINIAPP_AGENT_CONCURRENCY_INVALID.Both keys are preserved on
MiniAppContribution(agentAccess?,agentConcurrency?) so the agentservice can enforce them when it lands; no runtime behaviour changes in this PR.
The suite was proven red before green: against the previous reader 13 of 16 cases fail
(
expected PluginReaderError: MINIAPP_MANIFEST_SCHEMA_INVALID ... to match object { code: ... }), and16 of 16 pass here.
4. A manifest declaring an unknown key still fails
fails a manifest with an unknown top-level key→MINIAPP_MANIFEST_SCHEMA_INVALIDfails an unknown key beside surface.window→MINIAPP_SURFACE_INVALIDSURFACE_FIELDSandMINIAPP_FIELDSstay hardSetallowlists, so the three new keys are enumeratedexplicitly rather than a wildcard opening the reader up.
5. The repository's file-level and source gates pass
The inventory gained exactly one path — the new test file — and no path was removed or renamed.
Not verified:
pnpm verifyin full. Itstest:webui-browserand release-package steps were notrun locally; the change is content-only and touches no client behaviour and no export path, so those
are left to CI on PR #261.