Skip to content

Mini App contract forward port and manifest compatibility #252

Closed

Description

@Fectivnfy112357

Parent

#251

What to build

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.

Activity

  1. added
    ready-for-agentFully specified, ready for an AFK agent
    miniappWebUI Mini App hosting programme (ADR 0020)
    on Oct 26, 2026
  2. Fectivnfy112357 commented on Oct 26, 2026

    @Fectivnfy112357
    Author

    Acceptance evidence. Branch feat/miniapp-contract-forward-port, commit 2ee6a830, 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:

    $ diff <(head -n 964 <shipped>/miniapp-surface.ts) <(head -n 964 packages/shared/src/miniapp-surface.ts)
    (no output)
    $ wc -l packages/shared/src/miniapp-surface.ts
    974
    

    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

    $ pnpm typecheck
    > tsc -p tsconfig.standalone.json          # passed
    $ pnpm typecheck:webui
    > typecheck:server && typecheck:client && typecheck:test   # passed, plus "WebUI host event catalogue matches host producers"
    

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    miniappWebUI Mini App hosting programme (ADR 0020)ready-for-agentFully specified, ready for an AFK agent

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions