Skip to content

M2-11: Create Web/API baseline and strict request contracts #32

Closed

Description

@pillowtalk-Qy
Type: App Skeleton/API Contract
Priority: P0
Initial status: Blocked
Owner: App/API
Depends on: accepted M2-01
Blocks: M2-12, M3-01
Writable: approved app/server skeleton, app metadata and contract tests

唯一目标

建立 Node 22 可 production build/start 的应用、strict request/health contracts 和 Fake service boundary;不接真实 orchestration。

验收

[ ] framework exact versions locked
[ ] production build 和 start 成功
[ ] POST /api/preflight strict schema
[ ] mode 仅 LIVE/FIXTURE;scenario allowlist
[ ] body/response size limits
[ ] runId contract
[ ] GET /api/health 不泄露 secret/RPC URL
[ ] server-only Moss code 不进 browser bundle
[ ] Fake service 支持 UI 并与正式 contract 相同
[ ] 无 Clear402 behavior
[ ] 最小 preview/production start smoke 可重复,降低最后部署风险

验证

pnpm --filter @moss-mini-demo/web build
pnpm vitest run apps/web/test
pnpm check
pnpm start

另开 Terminal:

curl -fsS http://127.0.0.1:3000/api/health | jq

Codex 指令

只建框架、strict request/health contracts、fake boundary 和 production smoke。
不要接 Moss、Decision 或 Clear402,不把 server-only package 引入 client graph。

Activity

  1. pillowtalk-Qy commented on Jul 31, 2026

    @pillowtalk-Qy
    ContributorAuthor

    Dependency gate cleared - 2026-07-31

    M2-01 / #22 is Maintainer Accepted and closed. Its compatibility spike established:

    • Node 22.23.1 and pnpm 11.10.0;
    • Next.js 16.2.12 with React/React DOM 19.2.3;
    • production build and one-process next start;
    • server-only imports for the four tested Moss packages;
    • no Moss/Clear402 identifiers in browser static output;
    • CLEAR402_ENABLED absent/false returning an independent disabled path.

    #32 is released from Blocked to Ready.

    Implementation boundaries:

    • Build only the approved app skeleton, strict request/health contracts, Fake service boundary, contract tests, and reproducible production start.
    • No real Moss orchestration, Decision Engine orchestration, preflight-core business logic, or Clear402 behavior.
    • Pin exact framework versions.
    • Next resolved sharp@0.34.5; any build-script allowlist entry must be explicit, reviewed, pinned, and documented. Do not bypass pnpm supply-chain policy.
    • Moss-related modules remain server-only.
    • M2-03: Pin reproducible Moss dependency #24 owns dependency/submodule and overlapping workspace/lockfile changes first. M2-11: Create Web/API baseline and strict request contracts #32 may develop in parallel but must rebase onto merged M2-03: Pin reproducible Moss dependency #24 before final review.

    This record authorizes Ready status only; it does not approve a skeleton diff or production Gate.

  2. self-assigned this
    on Aug 5, 2026
  3. pillowtalk-Qy commented on Aug 5, 2026

    @pillowtalk-Qy
    ContributorAuthor

    M2_EXECUTION_SLOT_ASSIGNED

    Builder: pillowtalk-Qy
    Planning baseline: origin/main@93235e5c3ef531075c860beadc6ad2ce6b3dc8a0

    Upstream execution-slot evidence:

    Issue #32 is now the single active Builder slot and is moved to Project In Progress for planning.

    Planned branch name after scope confirmation: codex/issue-32-web-api-baseline
    Planned isolated worktree after scope confirmation: /Users/qy/Documents/moss-mini-demo-issue-32

    The first required evidence is a closed, path-specific Work Plan that freezes exact framework versions, writable paths, public/server boundaries, strict request and health contracts, Fake service contract, production build/start smoke, tests, and dependency changes.

    In Progress starts planning only. It is not SCOPE_CONFIRMED, implementation authorization, QA PASS, Review, Merge Gate, or merge authorization. No branch, worktree, file modification, dependency update, commit, push, or PR may begin before Maintainer scope confirmation.

    Issue #23 and newly released #25 remain Ready and unassigned. Other M2 Issues retain their existing blocked dependency gates.

  4. pillowtalk-Qy commented on Aug 5, 2026

    @pillowtalk-Qy
    ContributorAuthor

    Final Implementation Work Plan - Web/API Baseline and Strict Contracts - Awaiting Maintainer Scope Confirmation

    1. Planning control

    2. Goal and delivery boundary

    Build a production-buildable and production-startable Next.js App Router skeleton on the accepted Node runtime, with:

    • strict and versioned POST /api/preflight request/response contracts;
    • strict GET /api/health response fields;
    • fixed request and response byte limits;
    • server-generated run identifiers;
    • an offline Fake service implementing the same server service interface later used by real orchestration;
    • exact fixture scenario allowlisting;
    • explicit server-only ownership;
    • automated production start/health and browser-bundle leakage smoke tests.

    This issue creates an application/API baseline, not an integrated demo. It does not implement Moss orchestration, Quote collection, Capability construction, simulation, Alignment, Decision Engine orchestration, report assembly, Monad/RPC access, Clear402 behavior, wallet behavior, signing, or transaction submission.

    3. Frozen runtime and dependency set

    Runtime and package manager:

    Node: 22.23.1
    pnpm: 11.16.0
    Next.js: 16.2.12
    React: 19.2.3
    React DOM: 19.2.3
    

    The new apps/web/package.json dependency set is exact:

    {
      "dependencies": {
        "@moss-mini-demo/report-schema": "workspace:*",
        "next": "16.2.12",
        "react": "19.2.3",
        "react-dom": "19.2.3",
        "server-only": "0.0.1",
        "sharp": "0.34.5",
        "zod": "4.4.3"
      },
      "devDependencies": {
        "@types/node": "22.20.0",
        "@types/react": "19.2.18",
        "@types/react-dom": "19.2.4"
      }
    }

    No caret, tilde, tag, floating version, or additional dependency is authorized. The existing root TypeScript 7.0.2, Vitest 4.1.10, and Biome 2.5.5 remain the only compiler/test/format toolchain.

    sharp@0.34.5 is a reviewed direct runtime dependency because Next production image handling resolves it and its install script must not be silently blocked or broadly enabled. pnpm-workspace.yaml will contain exactly:

    packages:
      - "apps/*"
      - "packages/*"
    allowBuilds:
      sharp: true

    No dangerouslyAllowAllBuilds, wildcard build permission, ignored-build bypass, or second build-script allowlist entry is authorized. The lockfile must resolve Sharp exactly to 0.34.5 and retain package integrity metadata. A clean-store install must prove the reviewed Sharp script succeeds, and a Node import must report Sharp 0.34.5.

    4. Closed writable path list

    Exactly these 30 repository paths are writable:

    1. .gitignore - ignore Next build output only.
    2. package.json - add exact root web scripts/order; do not change existing dependency versions.
    3. pnpm-lock.yaml - generated frozen dependency graph and one apps/web importer only.
    4. pnpm-workspace.yaml - register apps/* and allow only the pinned Sharp build script.
    5. tsconfig.json - keep root strict checking but delegate apps/web to its own Next config.
    6. README.md - minimal stable current-state correction for the Web/API baseline.
    7. SECURITY.md - minimal stable boundary correction; no weakening of exclusions.
    8. docs/real-vs-mock.md - identify the Fake service and Fixtures as synthetic/non-evidence.
    9. apps/web/package.json
    10. apps/web/tsconfig.json
    11. apps/web/next-env.d.ts
    12. apps/web/next.config.ts
    13. apps/web/app/globals.css
    14. apps/web/app/layout.tsx
    15. apps/web/app/page.tsx
    16. apps/web/app/api/health/route.ts
    17. apps/web/app/api/preflight/route.ts
    18. apps/web/src/contracts/health.ts
    19. apps/web/src/contracts/preflight.ts
    20. apps/web/src/server/moss-build-info.ts
    21. apps/web/src/server/run-id.ts
    22. apps/web/src/server/http-json.ts
    23. apps/web/src/server/preflight-service.ts
    24. apps/web/src/server/fake-preflight-service.ts
    25. apps/web/src/server/preflight-handler.ts
    26. apps/web/test/contracts.test.ts
    27. apps/web/test/fake-preflight-service.test.ts
    28. apps/web/test/routes.test.ts
    29. apps/web/test/browser-bundle-leak.smoke.mjs
    30. apps/web/test/production-start.smoke.mjs

    There is no wildcard writable path. No generated asset, snapshot, public directory, fixture, application package, or 31st path may be added. In particular, this issue must not modify .github/workflows/quality-gate.yml, .gitmodules, vendor/moss, any packages/report-schema or packages/decision-engine file, any ADR, docs/architecture.md, docs/security-boundary.md, or STOP presentation rules.

    5. Workspace, build, and script contract

    .gitignore adds .next/. No source path is ignored.

    The root tsconfig.json continues strict no-emit validation for existing root/package code and excludes apps/**; apps/web/tsconfig.json owns DOM, JSX, Next plugin, JSON-module, incremental, and generated Next type settings. The committed next-env.d.ts uses only stable Next type references and does not import a missing .next artifact, so zero-artifact typecheck remains valid. Root typecheck must explicitly invoke the Web package typecheck so exclusion cannot become a coverage gap.

    Root scripts retain the existing gate and use these exact semantics:

    dev:
      pnpm --filter @moss-mini-demo/web dev
    
    start:
      pnpm --filter @moss-mini-demo/web start
    
    build:
      report-schema build
      -> decision-engine build
      -> @moss-mini-demo/web build
    
    typecheck:
      report-schema build
      -> root tsc --noEmit
      -> @moss-mini-demo/web typecheck
    
    test:
      root build
      -> Vitest all repository tests
    
    test:web:bundle:
      node apps/web/test/browser-bundle-leak.smoke.mjs
    
    test:web:production:
      node apps/web/test/production-start.smoke.mjs
    
    check:
      format:check
      -> lint
      -> typecheck
      -> build
      -> existing package-import smoke
      -> test
      -> test:web:bundle
      -> test:web:production
    

    The Web package scripts are fixed as:

    dev: next dev
    start: next start
    build: build @moss-mini-demo/report-schema, then next build
    typecheck: build @moss-mini-demo/report-schema, then tsc --noEmit
    

    The public report package is built first so pnpm --filter @moss-mini-demo/web build and Web typecheck work in a clean checkout with no pre-existing dist. No TypeScript path alias to package-private source, committed dist, hidden lifecycle script, or postinstall hook is permitted. Test code cannot invoke a build; the existing root test script keeps its explicit build prerequisite visible.

    pnpm-lock.yaml changes are limited to:

    • the new apps/web importer;
    • the exact direct dependencies listed above;
    • their pnpm-resolved transitive graph, platform-specific Next SWC packages, Sharp packages, peer links, and integrity metadata.

    The root importer and the two existing package importers must not gain unrelated dependencies. The lockfile is generated by pnpm 11.16.0, never manually edited.

    6. Strict POST /api/preflight request contract

    The route is a Next Route Handler with runtime = "nodejs", no Edge runtime, no Server Action, and no caching.

    Constants:

    contractVersion: "0.1"
    MAX_PREFLIGHT_REQUEST_BYTES: 65,536
    MAX_PREFLIGHT_RESPONSE_BYTES: 2,097,152
    size unit: UTF-8 bytes, not JavaScript string length
    accepted media type: application/json with optional charset=utf-8
    

    The request is a strict discriminated union. Every object uses Zod strictObject; unknown keys are rejected.

    LIVE request:

    {
      "contractVersion": "0.1",
      "mode": "LIVE",
      "intent": "<value accepted by public IntentSchema>"
    }

    FIXTURE request:

    {
      "contractVersion": "0.1",
      "mode": "FIXTURE",
      "scenario": "manual-review-success"
    }

    The exact fixture scenario allowlist is:

    manual-review-success
    token-out-mismatch
    amount-in-mismatch
    

    Rules:

    • LIVE requires intent parsed only through public @moss-mini-demo/report-schema IntentSchema; it forbids scenario.
    • FIXTURE requires one allowlisted scenario; it forbids caller-supplied intent because each reviewed Fixture owns its synthetic intent.
    • Both modes forbid caller-supplied runId, RPC URL, chain endpoint, credential, arbitrary fixture path, protocol-module name, or extra property.
    • Mode is case-sensitive and only LIVE | FIXTURE.
    • A claimed Content-Length above 65,536 bytes is rejected before reading. Missing or false-small Content-Length does not bypass the streaming byte counter.
    • The body reader stops and cancels when accumulated bytes exceed 65,536. It does not call an unbounded request.json() first.
    • Empty, malformed, non-object, array, prototype-sensitive, and strict-schema-invalid payloads are rejected without echoing input or Zod internals.

    7. runId ownership and format

    The server route generates one run identifier immediately on entry, before media-type/body/schema validation, so every success and structured error can be correlated.

    The format is:

    run_<lowercase UUID v4>
    pattern:
    ^run_[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
    example:
    run_018f4ca2-7a44-4b81-9d7d-a6d4508cf21e
    

    apps/web/src/server/run-id.ts is the only generator and uses Node crypto.randomUUID(). The route creates it once, passes it read-only to the service, and returns the same value. A client cannot choose or overwrite it. A runId is transport correlation metadata, not reportId, provenance, evidence, authorization, or a replay/security token.

    8. Strict POST response and HTTP contract

    All response objects are strict, versioned, schema-validated before serialization, measured as UTF-8 bytes, and emitted with:

    content-type: application/json; charset=utf-8
    cache-control: no-store
    

    Success is a strict mode-correlated union.

    LIVE success:

    {
      "contractVersion": "0.1",
      "ok": true,
      "runId": "run_<uuid-v4>",
      "mode": "LIVE",
      "report": "<public PreflightReportSchema value>"
    }

    LIVE success permits only report provenance LIVE_SOURCE | LOCAL_FORK.

    FIXTURE success:

    {
      "contractVersion": "0.1",
      "ok": true,
      "runId": "run_<uuid-v4>",
      "mode": "FIXTURE",
      "scenario": "manual-review-success",
      "report": "<public PreflightReportSchema value with provenance FIXTURE>"
    }

    The returned scenario must equal the requested allowlisted scenario. The Fake service maps the three scenario identifiers only to the three existing read-only Fixture files:

    manual-review-success
      -> packages/report-schema/fixtures/manual-review-success.v0.1.json
    
    token-out-mismatch
      -> packages/report-schema/fixtures/token-out-mismatch.v0.1.json
    
    amount-in-mismatch
      -> packages/report-schema/fixtures/amount-in-mismatch.v0.1.json
    

    Every Fixture is parsed through the public PreflightReportSchema before return. The Fake service does not copy, modify, repair, strengthen, or re-decide a Fixture.

    Structured error:

    {
      "contractVersion": "0.1",
      "ok": false,
      "runId": "run_<uuid-v4>",
      "error": {
        "code": "INVALID_REQUEST",
        "message": "Request does not match the preflight contract."
      }
    }

    The error code/status mapping is frozen:

    HTTP Code Condition
    400 INVALID_JSON Body is empty or not valid JSON
    400 INVALID_REQUEST Parsed JSON fails the strict request schema
    413 REQUEST_TOO_LARGE Declared or observed UTF-8 body exceeds 65,536 bytes
    415 UNSUPPORTED_MEDIA_TYPE Content-Type is absent or not accepted JSON
    503 LIVE_UNAVAILABLE Baseline Fake service receives a valid LIVE request
    500 RESPONSE_TOO_LARGE A schema-valid service result serializes above 2,097,152 bytes
    500 INTERNAL_ERROR Unexpected service/contract failure

    Error messages are fixed, non-sensitive strings of at most 256 characters. They do not include payloads, Zod issues, stack traces, filesystem paths, RPC data, environment values, or secrets. An HTTP error never includes a report or Decision and never masquerades as STOP. An oversized success is not truncated and is not returned as partial evidence.

    9. Fake service public contract

    apps/web/src/server/preflight-service.ts is the stable server-only interface owned by Web/API:

    type PreflightServiceInput = Readonly<{
      runId: RunId;
      request: PreflightRequest;
    }>;
    
    type PreflightServiceResult =
      | Readonly<{ status: "SUCCESS"; report: PreflightReport }>
      | Readonly<{
          status: "UNAVAILABLE";
          code: "LIVE_UNAVAILABLE";
          message: string;
        }>;
    
    interface PreflightService {
      run(input: PreflightServiceInput): Promise<PreflightServiceResult>;
    }

    The file imports server-only. Future #25-#31 packages do not modify this interface; Issue #33 (M2-12) later replaces/injects the orchestration implementation under its own Scope Gate.

    The baseline FakePreflightService:

    • is synchronous in evidence selection and returns a Promise only to match the future service boundary;
    • performs no network, RPC, Moss, Decision Engine, wallet, filesystem-path input, signing, or transaction behavior;
    • returns validated synthetic reports for allowlisted FIXTURE scenarios;
    • returns LIVE_UNAVAILABLE for LIVE and never falls back to FIXTURE;
    • preserves Fixture provenance and Decision exactly;
    • does not generate runId or own HTTP status/headers;
    • does not mutate request or Fixture input.

    apps/web/src/server/preflight-handler.ts owns HTTP parsing, limits, service invocation, response validation/size checking, and error mapping. The route file is a thin Node-runtime composition root. Tests may inject a contract-compatible service and runId generator into the handler factory; production uses the Fake service and real runId generator.

    10. GET /api/health contract

    GET /api/health returns HTTP 200, application/json; charset=utf-8, cache-control: no-store, and exactly:

    {
      "contractVersion": "0.1",
      "status": "ok",
      "app": {
        "name": "moss-mini-demo",
        "version": "0.0.0",
        "runtime": "nodejs",
        "nodeVersion": "22.23.1"
      },
      "moss": {
        "sourceMode": "INTEGRATION_FORK",
        "upstreamCommit": "1ae6b6322d51fae9104f047efb94e601050b967f",
        "integrationCommit": "1ae6b6322d51fae9104f047efb94e601050b967f",
        "officialRelease": false,
        "packages": {
          "@themoss/core": "0.1.0",
          "@themoss/simulator": "0.1.0",
          "@themoss/protocol-kuru": "0.1.0",
          "@themoss/protocol-pancakeswap": "0.1.0"
        }
      },
      "network": {
        "configured": false,
        "id": null
      },
      "clear402": {
        "enabled": false
      }
    }

    The health route validates this value through the strict public HealthResponseSchema. It returns no timestamp, hostname, IP, RPC URL/host, environment-variable name/value, credential, token, key, wallet, address, filesystem path, error detail, request data, or live network probe. configured: false is status metadata, not evidence that a network check ran.

    11. Server-only and browser boundary

    The accepted dependency direction remains:

    web/client -> client-safe Web contracts and report-schema contract only
    web/server -> Web contracts and server service boundary
    

    All files under apps/web/src/server begin with import "server-only". Both Route Handlers explicitly use Node runtime. No Client Component imports a server file, vendor/moss, Moss package, future moss-adapter, future preflight-core, server environment, or Clear402 module.

    The minimal page is a static, non-interactive application placeholder only. It does not present Fixture output as live evidence and does not claim that a runnable integrated demo exists.

    After production build, browser-bundle-leak.smoke.mjs recursively scans apps/web/.next/static. It fails on these case-insensitive markers:

    @themoss/
    @moss-mini-demo/moss-adapter
    vendor/moss
    MossBuildInfo
    INTEGRATION_FORK
    clear402
    MONAD_RPC
    RPC_URL
    PRIVATE_KEY
    

    The smoke also requires at least one static JS artifact and separately proves the server output contains the exact integration commit and @themoss/core marker. This makes the negative browser scan meaningful rather than passing because the server metadata was omitted.

    No clear402-profile dependency or import is added. The health response's server-side clear402.enabled=false is status only and cannot alter Core behavior or evidence.

    12. Tests and required coverage

    apps/web/test/contracts.test.ts covers:

    • strict LIVE and FIXTURE positive parses;
    • public IntentSchema validation;
    • all three scenarios and rejection of every other value/path;
    • invalid/lowercase mode, extra keys, runId input, scenario-on-LIVE, intent-on-FIXTURE;
    • RunId positive/negative patterns;
    • strict success/error response branches and provenance/mode correlation;
    • exact health keys and fixed values;
    • request/response byte constants.

    apps/web/test/fake-preflight-service.test.ts covers:

    • all three scenario-to-file mappings;
    • public PreflightReportSchema acceptance;
    • preserved provenance: FIXTURE and exact Fixture Decision;
    • LIVE produces LIVE_UNAVAILABLE with no Fixture fallback;
    • repeated calls do not mutate request or Fixture data;
    • caller runId is preserved and not regenerated by the service.

    apps/web/test/routes.test.ts covers:

    • health 200, headers, exact schema, and absence of secret/RPC/host material;
    • valid FIXTURE 200 response;
    • valid LIVE 503 without fallback;
    • unsupported media type 415;
    • invalid/empty JSON 400;
    • strict request error 400;
    • declared and streamed request overflow 413;
    • exact-boundary 65,536-byte handling;
    • oversized injected service response becomes small 500, never truncated;
    • unexpected service failure becomes redacted 500;
    • every response has one valid server-generated runId;
    • no request, error, stack, or environment echo.

    apps/web/test/browser-bundle-leak.smoke.mjs runs only after production build and applies the server/static assertions above.

    apps/web/test/production-start.smoke.mjs:

    1. requires an existing production .next build;
    2. allocates an available loopback port;
    3. starts the root pnpm start path with NEXT_TELEMETRY_DISABLED=1;
    4. waits no more than 30 seconds for GET /api/health;
    5. requires HTTP 200, JSON content type, no-store, and the exact Health schema values;
    6. terminates the one Next process with SIGTERM and allows 5 seconds for clean exit before failing and forcing cleanup;
    7. exits nonzero on early process exit, timeout, contract mismatch, leak, or orphaned process.

    The smoke binds only 127.0.0.1; it performs no external HTTP, RPC, protocol, wallet, or chain call.

    13. Documentation corrections

    The three authorized current-state documents receive minimal, stable facts:

    • the repository now contains a production-buildable/startable Web/API baseline and offline Fake service;
    • this is not the integrated demo, report orchestration, Moss/Monad/RPC/protocol behavior, or real backend evidence;
    • FIXTURE responses remain synthetic and visibly provenance: FIXTURE;
    • valid LIVE requests return LIVE_UNAVAILABLE in this baseline and never silently fall back;
    • no key, wallet, signing, transaction, secret, real address, or real-chain evidence is introduced;
    • MANUAL_REVIEW and STOP meanings are unchanged;
    • build, health, Fake service, and green CI are engineering evidence only, not safety guarantees.

    docs/architecture.md, docs/security-boundary.md, ADRs, M1 evidence, and #23 Scope Cut documentation are not changed.

    14. Implementation sequence after authorization

    1. Re-fetch and verify exact origin/main. If it differs from 93235e5c3ef531075c860beadc6ad2ce6b3dc8a0, stop, scan the new main, and request a refreshed Scope Gate before branching.
    2. Verify no open competing PR/worktree and create the planned branch in the planned isolated worktree.
    3. Add workspace registration, exact package metadata, strict app TypeScript config, ignored build output, and root script ordering.
    4. Generate the lockfile only with Node 22.23.1 and pnpm 11.16.0; audit the importer, exact versions, integrities, peer links, Sharp build permission, and unexpected package scripts.
    5. Implement client-safe contracts first.
    6. Implement server-only Moss build metadata, RunId generator, HTTP byte helpers, public service interface, Fake implementation, and injectable handler.
    7. Add thin Node Route Handlers and the minimal static App Router page/layout.
    8. Add contract, Fake, route, bundle, and production-start tests.
    9. Make only the three authorized stable documentation corrections.
    10. Inspect the exact diff. Any path outside the 30-path list, dependency outside the fixed set, workflow need, or contract ambiguity stops implementation.
    11. Run focused tests, clean production build/start/bundle smoke, full root quality gate, and exact diff checks.
    12. Commit and push one branch, then create a Draft PR titled feat: add Web API baseline and strict contracts with Closes #32 only.
    13. Wait for exact-Head quality-gate success, update the Implementation Report, add a Pre-PR QA handoff, freeze the head, and stop. Do not execute Review, Ready, Merge Gate, Merge, Issue/Project, permission, or protection operations.

    15. Verification commands

    Run from an isolated checkout with no node_modules, dist, .next, or untracked generated file. Keep the pinned Moss submodule unmodified; deinitialize it before the root Mini-Demo gate as established by #24.

    node --version
    pnpm --version
    git status --short --branch
    git submodule status --recursive
    git submodule deinit --force vendor/moss
    
    corepack enable
    corepack install --global pnpm@11.16.0
    pnpm install --frozen-lockfile
    
    pnpm --filter @moss-mini-demo/web exec node --input-type=module \
      -e 'const sharp = (await import("sharp")).default; if (sharp.versions.sharp !== "0.34.5") process.exit(1)'
    
    pnpm --filter @moss-mini-demo/web typecheck
    pnpm --filter @moss-mini-demo/web build
    pnpm vitest run apps/web/test
    pnpm test:web:bundle
    pnpm test:web:production
    pnpm check
    
    git diff --check origin/main...HEAD
    git diff --name-status origin/main...HEAD
    git status --short

    Manual production confirmation after build:

    NEXT_TELEMETRY_DISABLED=1 HOSTNAME=127.0.0.1 PORT=3000 pnpm start

    In a second terminal:

    curl -fsS -D - http://127.0.0.1:3000/api/health

    The response must match the frozen health object exactly and contain no RPC URL, host, secret, or credential.

    Before handoff, run a pushed-branch fresh-clone proof with a new local pnpm store, repeat frozen install/Web build/tests/smokes/pnpm check, and confirm the resulting worktree is clean apart from the reviewed 30-path commit diff.

    16. Acceptance and exit conditions

    Implementation is acceptable only when all are true:

    • exact Node, pnpm, Next, React, React DOM, Sharp, type, and server-only versions are locked;
    • frozen install succeeds from a clean store without an unapproved build script;
    • Sharp reports version 0.34.5;
    • standalone Web build/typecheck succeeds with no historical report-schema dist;
    • strict request, response, health, byte-limit, runId, allowlist, Fake, and no-fallback tests pass;
    • next build, one-process next start, loopback health smoke, browser leakage scan, and full pnpm check pass;
    • Next does not rewrite tsconfig.json, apps/web/tsconfig.json, next-env.d.ts, package manifests, or lockfile during build;
    • apps/web/.next/static contains no forbidden Moss/Clear402/server marker while server output contains the expected pinned metadata;
    • no Fixture is labeled LIVE and no HTTP/programming error is represented as a Decision;
    • exact diff contains only the 30 listed paths;
    • exact-Head CI uses the unchanged quality-gate job and succeeds;
    • PR remains Draft and is handed to Pre-PR QA.

    Stop without opening or updating a PR if:

    • main baseline changes before branching;
    • any contract field or semantic remains unresolved;
    • Next requires another dependency, config, generated tracked file, Edge runtime, or workflow change;
    • pnpm resolves a different direct version or an additional build-script permission;
    • Sharp install/import fails on Node 22.23.1;
    • public report-schema imports cannot be used without a private source path;
    • a Fixture fails public schema validation or Fake output would require mutation;
    • LIVE would need to fall back to FIXTURE;
    • response limiting would require truncating evidence;
    • browser leakage or production smoke cannot pass;
    • any 31st path is needed.

    A stop returns SCOPE_CHANGES_REQUESTED; it does not authorize a workaround.

    17. Non-goals and trust boundaries

    No implementation of:

    • real Moss package import or execution in app code;
    • moss-adapter, preflight-core, Quote/selection, Capability, simulation, Alignment, Decision orchestration, report generation, or presentation model;
    • Monad RPC, local fork, arbitrary endpoint input, Kuru/PancakeSwap calls, live Receipt/Outcome/Warning evidence;
    • Clear402 dependency, profile, route, credential, feature flag behavior, or UI;
    • wallet, address registry, key, API secret, signing, transaction broadcast, database, deployment, telemetry, analytics, auth, or rate limiting;
    • UI workflows beyond the static buildable placeholder;
    • changes to M2-02: Freeze scope, judge map and Gate contracts #23, M2-04: Create moss-adapter package and public ports #25 or any later Issue;
    • workflow, branch protection, required check, permission, Project, Milestone, Review, Ready, Merge Gate, or merge state.

    The Fake service and existing Fixtures are synthetic development tools. Production build/start, a health response, a strict API envelope, and green CI do not prove application correctness, protocol behavior, chain evidence, transaction safety, approval, authorization, execution, or permission to sign.

    18. Risks and rollback

    • Framework/config mutation: Next may propose generated TypeScript changes. All expected files are predeclared; any extra or rewritten contract stops implementation.
    • Sharp supply chain/native build: only exact 0.34.5 is allowed to run a build script. Failure or extra build permission stops the task.
    • Server/client leakage: server metadata intentionally contains Moss/Clear402 markers; static output must not.
    • Fake/live confusion: Fake output is always FIXTURE; LIVE is explicitly unavailable and never downgraded.
    • Oversized evidence: responses are measured and rejected, never truncated or partially presented.
    • Run correlation: runId is server-generated transport metadata; clients must use it to reject stale UI responses later, but this issue adds no client state machine.
    • Root gate duration: production build/start smoke increases CI time but remains in the existing single pnpm check entry.
    • Rollback: revert the single M2-11: Create Web/API baseline and strict request contracts #32 implementation commit/PR. This removes apps/web, its workspace importer, scripts, Sharp allowlist, dependency graph, ignored build output, and the three current-state corrections together. No database, deployment, external service, secret, or user data exists to migrate or delete.

    19. Requested Maintainer Scope Gate

    Please record one of:

    • SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED for the exact 30 paths, dependency set, package policy, request/response/health fields, sizes, runId, Fake service, server-only boundary, tests, and verification contract above; or
    • SCOPE_CHANGES_REQUESTED with the exact path, field, value, or ownership change required.

    Until that record exists:

    WORK_PLAN_SUBMITTED
    AWAITING_MAINTAINER_SCOPE_CONFIRMATION
    NO_IMPLEMENTATION_STARTED
    
  5. pillowtalk-Qy commented on Aug 5, 2026

    @pillowtalk-Qy
    ContributorAuthor

    SCOPE_CHANGES_REQUESTED

    Reviewed Work Plan: #32 (comment)

    Planning baseline: main@93235e5c3ef531075c860beadc6ad2ce6b3dc8a0

    Reviewed Work Plan body SHA-256: 6e2a8e412f3d889ec58acfd719be474f06cafb8365872c43c02d7e304a31cab6

    The 30-path boundary, strict/fail-closed API contracts, server-only ownership, production build/start smoke, browser-bundle leakage gate, and prohibition on real Moss, Decision orchestration, Clear402 behavior, RPC, wallet, signing, and chain evidence are otherwise coherent with #22 and #32.

    One supply-chain scope blocker prevents implementation authorization:

    • Section 3 proposes allowBuilds: { sharp: true } while claiming that build permission is limited to exact sharp@0.34.5. Under pnpm 11, an unversioned sharp: true matcher approves build scripts for the registry package name without fixing the version. It therefore does not implement the stated minimum, version-pinned permission boundary. pnpm supports version-qualified package matchers: https://pnpm.io/settings/build#allowbuilds

    Required Work Plan correction:

    1. Freeze the workspace permission as exactly 'sharp@0.34.5': true; do not authorize the unversioned sharp matcher.
    2. Update every plan, acceptance, audit, and rollback reference that currently describes allowBuilds.sharp so the version-qualified matcher is the normative value.
    3. Retain exact direct dependency sharp: "0.34.5", the frozen lockfile resolution and integrity metadata, and the prohibition on any second build-script permission.
    4. Keep the clean-store Node 22.23.1 / pnpm 11.16.0 install and Sharp import proof, and verify that no unreviewed build is reported or auto-added to pnpm-workspace.yaml.

    No implementation is authorized from the current Work Plan. Submit a revised, closed Work Plan for a new Maintainer Scope Gate. Until SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED is recorded, do not create the branch, worktree, commit, push, or PR.

    #32 remains Open, assigned to Qy, and Project In Progress for planning only. This is not QA, Review, READY_TO_MERGE, or merge authorization.

  6. pillowtalk-Qy commented on Aug 5, 2026

    @pillowtalk-Qy
    ContributorAuthor

    Revised Final Implementation Work Plan v2 - Version-Pinned Sharp Build Permission - Awaiting Maintainer Scope Confirmation

    This complete revised plan supersedes, but does not edit or delete, the original Work Plan. It responds only to the Maintainer's SCOPE_CHANGES_REQUESTED; both earlier comments remain immutable audit records.

    Unique revision delta

    1. The sole authorized allowBuilds key is now the version-qualified matcher 'sharp@0.34.5': true, replacing the unversioned sharp: true proposal.
    2. The writable-path description, supply-chain acceptance, implementation sequence, verification, stop conditions, risks, and rollback language now make that exact matcher normative.
    3. A second build-script permission is explicitly forbidden, and pnpm must not auto-add an unreviewed placeholder or any other matcher to pnpm-workspace.yaml.
    4. The exact 30 writable paths, dependencies, API/health/Fake contracts, tests, documentation scope, non-goals, and all other implementation boundaries are unchanged. There is no second revision axis.

    1. Planning control

    2. Goal and delivery boundary

    Build a production-buildable and production-startable Next.js App Router skeleton on the accepted Node runtime, with:

    • strict and versioned POST /api/preflight request/response contracts;
    • strict GET /api/health response fields;
    • fixed request and response byte limits;
    • server-generated run identifiers;
    • an offline Fake service implementing the same server service interface later used by real orchestration;
    • exact fixture scenario allowlisting;
    • explicit server-only ownership;
    • automated production start/health and browser-bundle leakage smoke tests.

    This issue creates an application/API baseline, not an integrated demo. It does not implement Moss orchestration, Quote collection, Capability construction, simulation, Alignment, Decision Engine orchestration, report assembly, Monad/RPC access, Clear402 behavior, wallet behavior, signing, or transaction submission.

    3. Frozen runtime and dependency set

    Runtime and package manager:

    Node: 22.23.1
    pnpm: 11.16.0
    Next.js: 16.2.12
    React: 19.2.3
    React DOM: 19.2.3
    

    The new apps/web/package.json dependency set is exact:

    {
      "dependencies": {
        "@moss-mini-demo/report-schema": "workspace:*",
        "next": "16.2.12",
        "react": "19.2.3",
        "react-dom": "19.2.3",
        "server-only": "0.0.1",
        "sharp": "0.34.5",
        "zod": "4.4.3"
      },
      "devDependencies": {
        "@types/node": "22.20.0",
        "@types/react": "19.2.18",
        "@types/react-dom": "19.2.4"
      }
    }

    No caret, tilde, tag, floating version, or additional dependency is authorized. The existing root TypeScript 7.0.2, Vitest 4.1.10, and Biome 2.5.5 remain the only compiler/test/format toolchain.

    sharp@0.34.5 is a reviewed direct runtime dependency because Next production image handling resolves it and its install script must not be silently blocked or broadly enabled. pnpm-workspace.yaml will contain exactly:

    packages:
      - "apps/*"
      - "packages/*"
    allowBuilds:
      'sharp@0.34.5': true

    The version-qualified matcher 'sharp@0.34.5' is the normative build-script permission and the only key permitted under allowBuilds. The unversioned matcher sharp: true, dangerouslyAllowAllBuilds, wildcard build permission, ignored-build bypass, and any second build-script permission are forbidden. pnpm must not automatically add an unreviewed placeholder, package matcher, or approval entry to pnpm-workspace.yaml; any such mutation stops implementation. The lockfile must resolve Sharp exactly to 0.34.5 and retain package integrity metadata. A clean-store install must prove the reviewed Sharp script succeeds, pnpm ignored-builds must report no unreviewed build requiring a new permission, and a Node import must report Sharp 0.34.5.

    4. Closed writable path list

    Exactly these 30 repository paths are writable:

    1. .gitignore - ignore Next build output only.
    2. package.json - add exact root web scripts/order; do not change existing dependency versions.
    3. pnpm-lock.yaml - generated frozen dependency graph and one apps/web importer only.
    4. pnpm-workspace.yaml - register apps/* and contain exactly one build-script permission: the version-qualified matcher 'sharp@0.34.5': true; no unversioned matcher, second permission, or pnpm-added placeholder.
    5. tsconfig.json - keep root strict checking but delegate apps/web to its own Next config.
    6. README.md - minimal stable current-state correction for the Web/API baseline.
    7. SECURITY.md - minimal stable boundary correction; no weakening of exclusions.
    8. docs/real-vs-mock.md - identify the Fake service and Fixtures as synthetic/non-evidence.
    9. apps/web/package.json
    10. apps/web/tsconfig.json
    11. apps/web/next-env.d.ts
    12. apps/web/next.config.ts
    13. apps/web/app/globals.css
    14. apps/web/app/layout.tsx
    15. apps/web/app/page.tsx
    16. apps/web/app/api/health/route.ts
    17. apps/web/app/api/preflight/route.ts
    18. apps/web/src/contracts/health.ts
    19. apps/web/src/contracts/preflight.ts
    20. apps/web/src/server/moss-build-info.ts
    21. apps/web/src/server/run-id.ts
    22. apps/web/src/server/http-json.ts
    23. apps/web/src/server/preflight-service.ts
    24. apps/web/src/server/fake-preflight-service.ts
    25. apps/web/src/server/preflight-handler.ts
    26. apps/web/test/contracts.test.ts
    27. apps/web/test/fake-preflight-service.test.ts
    28. apps/web/test/routes.test.ts
    29. apps/web/test/browser-bundle-leak.smoke.mjs
    30. apps/web/test/production-start.smoke.mjs

    There is no wildcard writable path. No generated asset, snapshot, public directory, fixture, application package, or 31st path may be added. In particular, this issue must not modify .github/workflows/quality-gate.yml, .gitmodules, vendor/moss, any packages/report-schema or packages/decision-engine file, any ADR, docs/architecture.md, docs/security-boundary.md, or STOP presentation rules.

    5. Workspace, build, and script contract

    .gitignore adds .next/. No source path is ignored.

    The root tsconfig.json continues strict no-emit validation for existing root/package code and excludes apps/**; apps/web/tsconfig.json owns DOM, JSX, Next plugin, JSON-module, incremental, and generated Next type settings. The committed next-env.d.ts uses only stable Next type references and does not import a missing .next artifact, so zero-artifact typecheck remains valid. Root typecheck must explicitly invoke the Web package typecheck so exclusion cannot become a coverage gap.

    Root scripts retain the existing gate and use these exact semantics:

    dev:
      pnpm --filter @moss-mini-demo/web dev
    
    start:
      pnpm --filter @moss-mini-demo/web start
    
    build:
      report-schema build
      -> decision-engine build
      -> @moss-mini-demo/web build
    
    typecheck:
      report-schema build
      -> root tsc --noEmit
      -> @moss-mini-demo/web typecheck
    
    test:
      root build
      -> Vitest all repository tests
    
    test:web:bundle:
      node apps/web/test/browser-bundle-leak.smoke.mjs
    
    test:web:production:
      node apps/web/test/production-start.smoke.mjs
    
    check:
      format:check
      -> lint
      -> typecheck
      -> build
      -> existing package-import smoke
      -> test
      -> test:web:bundle
      -> test:web:production
    

    The Web package scripts are fixed as:

    dev: next dev
    start: next start
    build: build @moss-mini-demo/report-schema, then next build
    typecheck: build @moss-mini-demo/report-schema, then tsc --noEmit
    

    The public report package is built first so pnpm --filter @moss-mini-demo/web build and Web typecheck work in a clean checkout with no pre-existing dist. No TypeScript path alias to package-private source, committed dist, hidden lifecycle script, or postinstall hook is permitted. Test code cannot invoke a build; the existing root test script keeps its explicit build prerequisite visible.

    pnpm-lock.yaml changes are limited to:

    • the new apps/web importer;
    • the exact direct dependencies listed above;
    • their pnpm-resolved transitive graph, platform-specific Next SWC packages, Sharp packages, peer links, and integrity metadata.

    The root importer and the two existing package importers must not gain unrelated dependencies. The lockfile is generated by pnpm 11.16.0, never manually edited. Build-script permission remains solely in pnpm-workspace.yaml as 'sharp@0.34.5': true; it must not be duplicated, generalized, or represented by a generated placeholder.

    6. Strict POST /api/preflight request contract

    The route is a Next Route Handler with runtime = "nodejs", no Edge runtime, no Server Action, and no caching.

    Constants:

    contractVersion: "0.1"
    MAX_PREFLIGHT_REQUEST_BYTES: 65,536
    MAX_PREFLIGHT_RESPONSE_BYTES: 2,097,152
    size unit: UTF-8 bytes, not JavaScript string length
    accepted media type: application/json with optional charset=utf-8
    

    The request is a strict discriminated union. Every object uses Zod strictObject; unknown keys are rejected.

    LIVE request:

    {
      "contractVersion": "0.1",
      "mode": "LIVE",
      "intent": "<value accepted by public IntentSchema>"
    }

    FIXTURE request:

    {
      "contractVersion": "0.1",
      "mode": "FIXTURE",
      "scenario": "manual-review-success"
    }

    The exact fixture scenario allowlist is:

    manual-review-success
    token-out-mismatch
    amount-in-mismatch
    

    Rules:

    • LIVE requires intent parsed only through public @moss-mini-demo/report-schema IntentSchema; it forbids scenario.
    • FIXTURE requires one allowlisted scenario; it forbids caller-supplied intent because each reviewed Fixture owns its synthetic intent.
    • Both modes forbid caller-supplied runId, RPC URL, chain endpoint, credential, arbitrary fixture path, protocol-module name, or extra property.
    • Mode is case-sensitive and only LIVE | FIXTURE.
    • A claimed Content-Length above 65,536 bytes is rejected before reading. Missing or false-small Content-Length does not bypass the streaming byte counter.
    • The body reader stops and cancels when accumulated bytes exceed 65,536. It does not call an unbounded request.json() first.
    • Empty, malformed, non-object, array, prototype-sensitive, and strict-schema-invalid payloads are rejected without echoing input or Zod internals.

    7. runId ownership and format

    The server route generates one run identifier immediately on entry, before media-type/body/schema validation, so every success and structured error can be correlated.

    The format is:

    run_<lowercase UUID v4>
    pattern:
    ^run_[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
    example:
    run_018f4ca2-7a44-4b81-9d7d-a6d4508cf21e
    

    apps/web/src/server/run-id.ts is the only generator and uses Node crypto.randomUUID(). The route creates it once, passes it read-only to the service, and returns the same value. A client cannot choose or overwrite it. A runId is transport correlation metadata, not reportId, provenance, evidence, authorization, or a replay/security token.

    8. Strict POST response and HTTP contract

    All response objects are strict, versioned, schema-validated before serialization, measured as UTF-8 bytes, and emitted with:

    content-type: application/json; charset=utf-8
    cache-control: no-store
    

    Success is a strict mode-correlated union.

    LIVE success:

    {
      "contractVersion": "0.1",
      "ok": true,
      "runId": "run_<uuid-v4>",
      "mode": "LIVE",
      "report": "<public PreflightReportSchema value>"
    }

    LIVE success permits only report provenance LIVE_SOURCE | LOCAL_FORK.

    FIXTURE success:

    {
      "contractVersion": "0.1",
      "ok": true,
      "runId": "run_<uuid-v4>",
      "mode": "FIXTURE",
      "scenario": "manual-review-success",
      "report": "<public PreflightReportSchema value with provenance FIXTURE>"
    }

    The returned scenario must equal the requested allowlisted scenario. The Fake service maps the three scenario identifiers only to the three existing read-only Fixture files:

    manual-review-success
      -> packages/report-schema/fixtures/manual-review-success.v0.1.json
    
    token-out-mismatch
      -> packages/report-schema/fixtures/token-out-mismatch.v0.1.json
    
    amount-in-mismatch
      -> packages/report-schema/fixtures/amount-in-mismatch.v0.1.json
    

    Every Fixture is parsed through the public PreflightReportSchema before return. The Fake service does not copy, modify, repair, strengthen, or re-decide a Fixture.

    Structured error:

    {
      "contractVersion": "0.1",
      "ok": false,
      "runId": "run_<uuid-v4>",
      "error": {
        "code": "INVALID_REQUEST",
        "message": "Request does not match the preflight contract."
      }
    }

    The error code/status mapping is frozen:

    HTTP Code Condition
    400 INVALID_JSON Body is empty or not valid JSON
    400 INVALID_REQUEST Parsed JSON fails the strict request schema
    413 REQUEST_TOO_LARGE Declared or observed UTF-8 body exceeds 65,536 bytes
    415 UNSUPPORTED_MEDIA_TYPE Content-Type is absent or not accepted JSON
    503 LIVE_UNAVAILABLE Baseline Fake service receives a valid LIVE request
    500 RESPONSE_TOO_LARGE A schema-valid service result serializes above 2,097,152 bytes
    500 INTERNAL_ERROR Unexpected service/contract failure

    Error messages are fixed, non-sensitive strings of at most 256 characters. They do not include payloads, Zod issues, stack traces, filesystem paths, RPC data, environment values, or secrets. An HTTP error never includes a report or Decision and never masquerades as STOP. An oversized success is not truncated and is not returned as partial evidence.

    9. Fake service public contract

    apps/web/src/server/preflight-service.ts is the stable server-only interface owned by Web/API:

    type PreflightServiceInput = Readonly<{
      runId: RunId;
      request: PreflightRequest;
    }>;
    
    type PreflightServiceResult =
      | Readonly<{ status: "SUCCESS"; report: PreflightReport }>
      | Readonly<{
          status: "UNAVAILABLE";
          code: "LIVE_UNAVAILABLE";
          message: string;
        }>;
    
    interface PreflightService {
      run(input: PreflightServiceInput): Promise<PreflightServiceResult>;
    }

    The file imports server-only. Future #25-#31 packages do not modify this interface; Issue #33 (M2-12) later replaces/injects the orchestration implementation under its own Scope Gate.

    The baseline FakePreflightService:

    • is synchronous in evidence selection and returns a Promise only to match the future service boundary;
    • performs no network, RPC, Moss, Decision Engine, wallet, filesystem-path input, signing, or transaction behavior;
    • returns validated synthetic reports for allowlisted FIXTURE scenarios;
    • returns LIVE_UNAVAILABLE for LIVE and never falls back to FIXTURE;
    • preserves Fixture provenance and Decision exactly;
    • does not generate runId or own HTTP status/headers;
    • does not mutate request or Fixture input.

    apps/web/src/server/preflight-handler.ts owns HTTP parsing, limits, service invocation, response validation/size checking, and error mapping. The route file is a thin Node-runtime composition root. Tests may inject a contract-compatible service and runId generator into the handler factory; production uses the Fake service and real runId generator.

    10. GET /api/health contract

    GET /api/health returns HTTP 200, application/json; charset=utf-8, cache-control: no-store, and exactly:

    {
      "contractVersion": "0.1",
      "status": "ok",
      "app": {
        "name": "moss-mini-demo",
        "version": "0.0.0",
        "runtime": "nodejs",
        "nodeVersion": "22.23.1"
      },
      "moss": {
        "sourceMode": "INTEGRATION_FORK",
        "upstreamCommit": "1ae6b6322d51fae9104f047efb94e601050b967f",
        "integrationCommit": "1ae6b6322d51fae9104f047efb94e601050b967f",
        "officialRelease": false,
        "packages": {
          "@themoss/core": "0.1.0",
          "@themoss/simulator": "0.1.0",
          "@themoss/protocol-kuru": "0.1.0",
          "@themoss/protocol-pancakeswap": "0.1.0"
        }
      },
      "network": {
        "configured": false,
        "id": null
      },
      "clear402": {
        "enabled": false
      }
    }

    The health route validates this value through the strict public HealthResponseSchema. It returns no timestamp, hostname, IP, RPC URL/host, environment-variable name/value, credential, token, key, wallet, address, filesystem path, error detail, request data, or live network probe. configured: false is status metadata, not evidence that a network check ran.

    11. Server-only and browser boundary

    The accepted dependency direction remains:

    web/client -> client-safe Web contracts and report-schema contract only
    web/server -> Web contracts and server service boundary
    

    All files under apps/web/src/server begin with import "server-only". Both Route Handlers explicitly use Node runtime. No Client Component imports a server file, vendor/moss, Moss package, future moss-adapter, future preflight-core, server environment, or Clear402 module.

    The minimal page is a static, non-interactive application placeholder only. It does not present Fixture output as live evidence and does not claim that a runnable integrated demo exists.

    After production build, browser-bundle-leak.smoke.mjs recursively scans apps/web/.next/static. It fails on these case-insensitive markers:

    @themoss/
    @moss-mini-demo/moss-adapter
    vendor/moss
    MossBuildInfo
    INTEGRATION_FORK
    clear402
    MONAD_RPC
    RPC_URL
    PRIVATE_KEY
    

    The smoke also requires at least one static JS artifact and separately proves the server output contains the exact integration commit and @themoss/core marker. This makes the negative browser scan meaningful rather than passing because the server metadata was omitted.

    No clear402-profile dependency or import is added. The health response's server-side clear402.enabled=false is status only and cannot alter Core behavior or evidence.

    12. Tests and required coverage

    apps/web/test/contracts.test.ts covers:

    • strict LIVE and FIXTURE positive parses;
    • public IntentSchema validation;
    • all three scenarios and rejection of every other value/path;
    • invalid/lowercase mode, extra keys, runId input, scenario-on-LIVE, intent-on-FIXTURE;
    • RunId positive/negative patterns;
    • strict success/error response branches and provenance/mode correlation;
    • exact health keys and fixed values;
    • request/response byte constants.

    apps/web/test/fake-preflight-service.test.ts covers:

    • all three scenario-to-file mappings;
    • public PreflightReportSchema acceptance;
    • preserved provenance: FIXTURE and exact Fixture Decision;
    • LIVE produces LIVE_UNAVAILABLE with no Fixture fallback;
    • repeated calls do not mutate request or Fixture data;
    • caller runId is preserved and not regenerated by the service.

    apps/web/test/routes.test.ts covers:

    • health 200, headers, exact schema, and absence of secret/RPC/host material;
    • valid FIXTURE 200 response;
    • valid LIVE 503 without fallback;
    • unsupported media type 415;
    • invalid/empty JSON 400;
    • strict request error 400;
    • declared and streamed request overflow 413;
    • exact-boundary 65,536-byte handling;
    • oversized injected service response becomes small 500, never truncated;
    • unexpected service failure becomes redacted 500;
    • every response has one valid server-generated runId;
    • no request, error, stack, or environment echo.

    apps/web/test/browser-bundle-leak.smoke.mjs runs only after production build and applies the server/static assertions above.

    apps/web/test/production-start.smoke.mjs:

    1. requires an existing production .next build;
    2. allocates an available loopback port;
    3. starts the root pnpm start path with NEXT_TELEMETRY_DISABLED=1;
    4. waits no more than 30 seconds for GET /api/health;
    5. requires HTTP 200, JSON content type, no-store, and the exact Health schema values;
    6. terminates the one Next process with SIGTERM and allows 5 seconds for clean exit before failing and forcing cleanup;
    7. exits nonzero on early process exit, timeout, contract mismatch, leak, or orphaned process.

    The smoke binds only 127.0.0.1; it performs no external HTTP, RPC, protocol, wallet, or chain call.

    13. Documentation corrections

    The three authorized current-state documents receive minimal, stable facts:

    • the repository now contains a production-buildable/startable Web/API baseline and offline Fake service;
    • this is not the integrated demo, report orchestration, Moss/Monad/RPC/protocol behavior, or real backend evidence;
    • FIXTURE responses remain synthetic and visibly provenance: FIXTURE;
    • valid LIVE requests return LIVE_UNAVAILABLE in this baseline and never silently fall back;
    • no key, wallet, signing, transaction, secret, real address, or real-chain evidence is introduced;
    • MANUAL_REVIEW and STOP meanings are unchanged;
    • build, health, Fake service, and green CI are engineering evidence only, not safety guarantees.

    docs/architecture.md, docs/security-boundary.md, ADRs, M1 evidence, and #23 Scope Cut documentation are not changed.

    14. Implementation sequence after authorization

    1. Re-fetch and verify exact origin/main. If it differs from 93235e5c3ef531075c860beadc6ad2ce6b3dc8a0, stop, scan the new main, and request a refreshed Scope Gate before branching.
    2. Verify no open competing PR/worktree and create the planned branch in the planned isolated worktree.
    3. Add workspace registration, exact package metadata, strict app TypeScript config, ignored build output, and root script ordering.
    4. Set the sole allowBuilds entry to the exact matcher 'sharp@0.34.5': true, then generate the lockfile only with Node 22.23.1 and pnpm 11.16.0; audit the importer, exact versions, integrities, peer links, unexpected package scripts, and pnpm ignored-builds. Confirm pnpm did not add an unreviewed placeholder or second permission to pnpm-workspace.yaml.
    5. Implement client-safe contracts first.
    6. Implement server-only Moss build metadata, RunId generator, HTTP byte helpers, public service interface, Fake implementation, and injectable handler.
    7. Add thin Node Route Handlers and the minimal static App Router page/layout.
    8. Add contract, Fake, route, bundle, and production-start tests.
    9. Make only the three authorized stable documentation corrections.
    10. Inspect the exact diff. Any path outside the 30-path list, dependency outside the fixed set, workflow need, contract ambiguity, unversioned Sharp permission, second build-script permission, or pnpm-added placeholder stops implementation.
    11. Run focused tests, clean production build/start/bundle smoke, full root quality gate, and exact diff checks.
    12. Commit and push one branch, then create a Draft PR titled feat: add Web API baseline and strict contracts with Closes #32 only.
    13. Wait for exact-Head quality-gate success, update the Implementation Report, add a Pre-PR QA handoff, freeze the head, and stop. Do not execute Review, Ready, Merge Gate, Merge, Issue/Project, permission, or protection operations.

    15. Verification commands

    Run from an isolated checkout with no node_modules, dist, .next, or untracked generated file. Keep the pinned Moss submodule unmodified; deinitialize it before the root Mini-Demo gate as established by #24.

    node --version
    pnpm --version
    git status --short --branch
    git submodule status --recursive
    git submodule deinit --force vendor/moss
    
    corepack enable
    corepack install --global pnpm@11.16.0
    sharp_policy_sha_before="$(shasum -a 256 pnpm-workspace.yaml | awk '{print $1}')"
    pnpm install --frozen-lockfile
    test "$sharp_policy_sha_before" = "$(shasum -a 256 pnpm-workspace.yaml | awk '{print $1}')"
    pnpm config get allowBuilds --json
    pnpm ignored-builds
    
    pnpm --filter @moss-mini-demo/web exec node --input-type=module \
      -e 'const sharp = (await import("sharp")).default; if (sharp.versions.sharp !== "0.34.5") process.exit(1)'
    
    pnpm --filter @moss-mini-demo/web typecheck
    pnpm --filter @moss-mini-demo/web build
    pnpm vitest run apps/web/test
    pnpm test:web:bundle
    pnpm test:web:production
    pnpm check
    
    git diff --check origin/main...HEAD
    git diff --name-status origin/main...HEAD
    git status --short

    Manual production confirmation after build:

    NEXT_TELEMETRY_DISABLED=1 HOSTNAME=127.0.0.1 PORT=3000 pnpm start

    In a second terminal:

    curl -fsS -D - http://127.0.0.1:3000/api/health

    The response must match the frozen health object exactly and contain no RPC URL, host, secret, or credential.

    Before handoff, run a pushed-branch fresh-clone proof with a new local pnpm store, repeat frozen install/Web build/tests/smokes/pnpm check, and confirm the resulting worktree is clean apart from the reviewed 30-path commit diff. In both isolated installs, pnpm config get allowBuilds --json must resolve semantically to exactly {"sharp@0.34.5":true}, pnpm ignored-builds must identify no unreviewed build requiring another permission, and the pre/post-install workspace-policy hashes must match so pnpm cannot silently add a placeholder.

    16. Acceptance and exit conditions

    Implementation is acceptable only when all are true:

    • exact Node, pnpm, Next, React, React DOM, Sharp, type, and server-only versions are locked, and the sole build-script permission is the version-qualified matcher 'sharp@0.34.5': true;
    • frozen install succeeds from a clean store without an unapproved build script, second permission, unversioned Sharp matcher, or pnpm-added placeholder;
    • Sharp reports version 0.34.5;
    • standalone Web build/typecheck succeeds with no historical report-schema dist;
    • strict request, response, health, byte-limit, runId, allowlist, Fake, and no-fallback tests pass;
    • next build, one-process next start, loopback health smoke, browser leakage scan, and full pnpm check pass;
    • pnpm and Next do not rewrite pnpm-workspace.yaml, tsconfig.json, apps/web/tsconfig.json, next-env.d.ts, package manifests, or lockfile during install/build;
    • apps/web/.next/static contains no forbidden Moss/Clear402/server marker while server output contains the expected pinned metadata;
    • no Fixture is labeled LIVE and no HTTP/programming error is represented as a Decision;
    • exact diff contains only the 30 listed paths;
    • exact-Head CI uses the unchanged quality-gate job and succeeds;
    • PR remains Draft and is handed to Pre-PR QA.

    Stop without opening or updating a PR if:

    • main baseline changes before branching;
    • any contract field or semantic remains unresolved;
    • Next requires another dependency, config, generated tracked file, Edge runtime, or workflow change;
    • pnpm resolves a different direct version, uses an unversioned Sharp matcher, reports an unreviewed build, or adds a placeholder or second build-script permission;
    • Sharp install/import fails on Node 22.23.1;
    • public report-schema imports cannot be used without a private source path;
    • a Fixture fails public schema validation or Fake output would require mutation;
    • LIVE would need to fall back to FIXTURE;
    • response limiting would require truncating evidence;
    • browser leakage or production smoke cannot pass;
    • any 31st path is needed.

    A stop returns SCOPE_CHANGES_REQUESTED; it does not authorize a workaround.

    17. Non-goals and trust boundaries

    No implementation of:

    • real Moss package import or execution in app code;
    • moss-adapter, preflight-core, Quote/selection, Capability, simulation, Alignment, Decision orchestration, report generation, or presentation model;
    • Monad RPC, local fork, arbitrary endpoint input, Kuru/PancakeSwap calls, live Receipt/Outcome/Warning evidence;
    • Clear402 dependency, profile, route, credential, feature flag behavior, or UI;
    • wallet, address registry, key, API secret, signing, transaction broadcast, database, deployment, telemetry, analytics, auth, or rate limiting;
    • UI workflows beyond the static buildable placeholder;
    • changes to M2-02: Freeze scope, judge map and Gate contracts #23, M2-04: Create moss-adapter package and public ports #25 or any later Issue;
    • workflow, branch protection, required check, permission, Project, Milestone, Review, Ready, Merge Gate, or merge state.

    The Fake service and existing Fixtures are synthetic development tools. Production build/start, a health response, a strict API envelope, and green CI do not prove application correctness, protocol behavior, chain evidence, transaction safety, approval, authorization, execution, or permission to sign.

    18. Risks and rollback

    • Framework/config mutation: Next may propose generated TypeScript changes. All expected files are predeclared; any extra or rewritten contract stops implementation.
    • Sharp supply chain/native build: only the exact version-qualified matcher 'sharp@0.34.5': true may authorize a build script. An unversioned matcher, install/import failure, ignored unreviewed build, or extra permission stops the task.
    • Server/client leakage: server metadata intentionally contains Moss/Clear402 markers; static output must not.
    • Fake/live confusion: Fake output is always FIXTURE; LIVE is explicitly unavailable and never downgraded.
    • Oversized evidence: responses are measured and rejected, never truncated or partially presented.
    • Run correlation: runId is server-generated transport metadata; clients must use it to reject stale UI responses later, but this issue adds no client state machine.
    • Root gate duration: production build/start smoke increases CI time but remains in the existing single pnpm check entry.
    • Automatic policy mutation: pnpm must not add an approval placeholder or matcher during install. The pre/post-install pnpm-workspace.yaml hash, structured config output, ignored-build report, and exact diff make any mutation a hard stop.
    • Rollback: revert the single M2-11: Create Web/API baseline and strict request contracts #32 implementation commit/PR. This removes apps/web, its workspace importer, scripts, the exact 'sharp@0.34.5': true permission, dependency graph, ignored build output, and the three current-state corrections together. No database, deployment, external service, secret, or user data exists to migrate or delete.

    19. Requested Maintainer Scope Gate

    Please record one of:

    • SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED for the exact 30 paths, dependency set, sole version-qualified 'sharp@0.34.5': true build permission, prohibition on any second permission or pnpm-added placeholder, request/response/health fields, sizes, runId, Fake service, server-only boundary, tests, and verification contract above; or
    • SCOPE_CHANGES_REQUESTED with the exact path, field, value, or ownership change required.

    Until that record exists:

    WORK_PLAN_SUBMITTED
    AWAITING_MAINTAINER_SCOPE_CONFIRMATION
    NO_IMPLEMENTATION_STARTED
    
  7. pillowtalk-Qy commented on Aug 5, 2026

    @pillowtalk-Qy
    ContributorAuthor

    SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED

    Authorized Work Plan: #32 (comment)

    Implementation baseline: main@93235e5c3ef531075c860beadc6ad2ce6b3dc8a0

    Authorized Work Plan body SHA-256: 9b950740ed7008f89c4801a02c80624892ea38c7ae34e4aa58283c1d97b14561

    Maintainer Scope Gate result: PASS.

    The revised Work Plan is authorized with these frozen boundaries:

    • exactly the 30 writable repository paths enumerated in the revised Work Plan; no wildcard or 31st path;
    • exactly the listed runtime, application, type, and workspace dependencies, with no additional dependency or package permission;
    • exactly one allowBuilds entry: 'sharp@0.34.5': true; the unversioned Sharp matcher, any second matcher, any pnpm-added placeholder, and any broader build-script permission are forbidden;
    • the strict and fail-closed request, response, health, byte-limit, runId, Fixture allowlist, Fake service, and server-only contracts recorded in the revised Work Plan;
    • the specified contract, route, Fake-service, production build/start/health, browser-bundle leakage, clean-store, package-policy, and full quality-gate verification matrix;
    • no real Moss execution, Decision orchestration, Clear402 behavior, RPC, wallet, signing, transaction submission, live-chain evidence, Schema/Engine/ADR change, workflow change, or protection/permission change.

    The original Work Plan remains an unchanged audit record. The revised plan is a separate comment and the only authorized implementation source.

    Builder Qy may now re-fetch and confirm the exact baseline, then create only the planned codex/issue-32-web-api-baseline branch and isolated worktree, implement the authorized scope, and open one Draft PR with Closes #32 only. If main changes before branching, or implementation needs another path, dependency, build permission, public contract, workflow, or scope, stop and request a new Maintainer Scope Gate.

    This record authorizes implementation only. It is not Pre-PR QA, an independent review, READY_TO_MERGE, Merge Gate, or merge authorization. The implementation PR must remain Draft until its exact-head QA handoff and subsequent Maintainer review.

    #32 remains Open, assigned to pillowtalk-Qy, and Project In Progress. No downstream Issue is released by this authorization.

  8. added a commit that references this issue on Aug 5, 2026
    1e42bab
  9. pillowtalk-Qy commented on Aug 5, 2026

    @pillowtalk-Qy
    ContributorAuthor

    POST_MERGE_AUDIT

    PR: #71

    The merged-main check ran against exact head 1e42babfa457ad20ac1efcecca227aceb4995c2b. Issue #32 is Closed / Completed and its Project status is Done.

    The merge used head-matched squash merge. No auto-merge or admin bypass was used. No protection, permission, Tag, or Release setting was changed.

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions