Skip to content

cloud/C12: end-to-end test (license → chat → usage)#227

Closed
blueberrycongee wants to merge 5 commits intoloop/cloud-C9from
loop/cloud-C12
Closed

cloud/C12: end-to-end test (license → chat → usage)#227
blueberrycongee wants to merge 5 commits intoloop/cloud-C9from
loop/cloud-C12

Conversation

@blueberrycongee
Copy link
Copy Markdown
Owner

What

Adds src/__tests__/luminaCloud.e2e.test.ts — a Vitest integration test that drives the full client flow with mocked @/services/luminaCloud touchpoints.

Stacking

C12 needs C2 (verify), C4 (store), C5 (HTTP client), and C7 (provider). This branch builds on loop/cloud-C9 (which already merges C2 + C4 + C5) and adds a merge of loop/cloud-C7 on top, then the test commit.

loop/cloud-C9 (base, contains C1+C2+C4+C5+C9)
└── merge: bring loop/cloud-C7 into C12 stack
    └── cloud/C12: end-to-end test
        └── cloud/C12: mark C12 done in TASKS.md

Merge to main order: #217 (C1) → #218 (C2) → #220 (C4) → #221 (C5) → #223 (C7) → #225 (C9) → this PR (C12). When you merge them in that order, both merge commits in this branch become no-ops.

What the test exercises

  1. setLicense → 'valid' — drives the store through idle → loading → valid; payload comes from the mocked verifyLicense; saveLicense is invoked.
  2. Provider visibility — pulls payload.features from the store and asserts isLuminaCloudVisible returns true for the cloud_ai-bearing fixture.
  3. Dynamic model catalog — calls fetchLuminaCloudModels(license), asserts it delegates to client.getModels and maps the response into ModelMeta rows.
  4. Pre-chat usage snapshot — captures tokens_used: 0.
  5. Mock chat round-trip — the AI SDK plumbing isn't this test's surface (that lives in opencode), so the chat is implicit. What matters is that the observable effect — usage moving forward — flows back through client.getUsage.
  6. Post-chat usage delta — second getUsage call returns higher tokens_used and requests_count.

Two negative-path tests keep this from being happy-path-only:

  • Invalid signature → status 'invalid', provider hidden, no save, no chat.
  • Valid signature but features: ['lifetime'] (no cloud_ai) → status 'valid' but provider still hidden.

Acceptance criteria

  • npm test -- src/__tests__/luminaCloud.e2e.test.ts passes.

3/3 pass. Typecheck pass.

Touched files outside src/services/luminaCloud/

  • New: src/__tests__/luminaCloud.e2e.test.ts — within the PRD §3 surface (test files for the existing surfaces are implicitly allowed).
  • cloud/TASKS.md — marked C12 [x] and appended Done-log entry.

Notes for Lead

  • "Mock chat round-trip" is intentionally left as a comment + a getUsage delta. The actual /v1/ai/chat/completions POST goes through the AI SDK's openai-compatible plumbing wired by C7's provider, which lives in opencode's runtime — out of scope for a renderer-side Vitest e2e.
  • All four touchpoints (verifyLicense, saveLicense, getUsage, getModels) are mocked at the @/services/luminaCloud module level via vi.hoisted + vi.mock. Same pattern used in C4 and C8 tests.
  • This is the last P1 backlog item that's not blocked or trivial; remaining items are C3 (cloud/C3: BLOCKED — IPC wiring needs Lead clarification #219, blocked), C6, C10 (cloud/C10: BLOCKED — Account tab needs Lead clarification #226, blocked), C11 (pre-blocked), C13 (README mention — quick).

blueberrycongee and others added 5 commits April 28, 2026 13:00
PRD §3 forbids editing src/services/llm/providers/models.ts, so the
provider definition lives self-contained in luminaCloud.ts. Consumers
(AISettingsModal in C11) combine LUMINA_CLOUD_PROVIDER with
listProviderModels() when isLuminaCloudVisible(features) returns true.

Exports:
- LUMINA_CLOUD_PROVIDER_ID, LUMINA_CLOUD_BASE_URL, LUMINA_CLOUD_REQUIRED_FEATURE
  constants.
- LUMINA_CLOUD_PROVIDER: ProviderMeta with empty static models (filled
  dynamically — server returns the catalog per CONTRACT.md §2.3).
- isLuminaCloudVisible(features): true iff features include 'cloud_ai'.
  Tolerant of null / undefined so call sites can pass
  useLicenseStore's payload?.features directly.
- fetchLuminaCloudModels(license): calls client.getModels and maps
  { id, upstream, context } → { id, name, contextWindow } rows.

Tests cover provider shape (constants + ProviderMeta fields), all
six visibility cases (null / undefined / [] / no-feature / single /
multiple), and three model-fetch outcomes (mapped / empty / error
propagation). 8 tests, all pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Exercises the full client flow against mocked luminaCloud touchpoints:
1. setLicense drives the store through idle → loading → valid and
   persists via saveLicense.
2. payload.features is read back; isLuminaCloudVisible returns true
   for cloud_ai.
3. fetchLuminaCloudModels delegates to getModels and returns the
   mapped catalog.
4. A pre-chat getUsage call is captured.
5. Mock chat round-trip — the AI SDK plumbing isn't this test's
   surface; what matters is that usage moves forward.
6. Post-chat getUsage shows the tokens_used + requests_count delta.

Two negative paths kept this from devolving into a happy-path-only
smoke test:
- Invalid signature → status='invalid', provider hidden, no save,
  no chat.
- Valid signature without cloud_ai → status='valid' but provider
  still hidden.

3 tests, all pass. Branch is `loop/cloud-C9` + merge of
`loop/cloud-C7`, since C12 needs C2 + C4 + C5 + C7.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Copy link
Copy Markdown

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

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: 7a22d0ef59

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


export const LUMINA_CLOUD_PROVIDER_ID = 'lumina-cloud';

export const LUMINA_CLOUD_BASE_URL = 'https://api.lumina-note.com/v1/ai';
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 Read Lumina Cloud base URL from configured environment

This hardcoded base URL bypasses the env override path already used by the Lumina Cloud REST client (VITE_LUMINA_CLOUD_BASE_URL in src/services/luminaCloud/client.ts). In staging/dev setups, license verification/usage calls can hit the configured host while chat calls from this provider still go to production, causing split behavior and hard-to-diagnose auth/usage mismatches. Please derive this value from the same base-url resolver so all Lumina Cloud endpoints stay on one backend.

Useful? React with 👍 / 👎.

@blueberrycongee
Copy link
Copy Markdown
Owner Author

Closing — re-issued cleanly by integrator.

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