test: verify packaged game audio and skill-only resources

This commit is contained in:
2026-09-21 12:57:05 +08:00
parent 09e0ce5cf3
commit 938c4b1ed3
3 changed files with 42 additions and 13 deletions

View File

@@ -29,23 +29,30 @@
- New adapter + one official optional bundled game-audio plugin expose music full, explicit music preview, sound single/pack/variants, cancel. Native price/release/project/request authority stays in Main. Four static tool-operation mappings, project-wide parent availability and empty child scope; no new picker/store/partner gate or provider secrets.
- Result card displays saved relative paths/MIME/bytes and loads local audio only after a click, with native controls/no autoplay. Reuses bounded project media reader through a receipt/account-owned Host route; no Provider URL or audio payload enters model messages. Composition shares leases/tracker and resumes receipts. Registry manifest duplicate checks now use plugin/capability/operation identity (global tool names remain unique), permitting two distinct audio capabilities to both name operation generate.
- Additional owned paths beyond the initial outline: read-only saved-audio Host route and composition service port, export of existing media reader, Chat progress/preview component and test, relevant effective-resolver/manifest/Registry/artifact assertions, one synthetic-audio Electron case reusing the existing first-chat fixture, README and package version 2.0.1. No plugin navigation/store authority changes.
- Packaged continuation corrected two actual pre-existing artifact-check assumptions in the already-owned verifier: schema-2 skill_only project-scaffold legitimately has no adapter/tools, while hosted plugins still require tools; current Renderer uses plugin-tab-available/plugin-tab-installed rather than deleted introductory copy. Tests cover the real shipped scaffold and negative hosted-without-tools case. No application/Plugin UI code changed in this continuation.
## Verification
- 2026-09-21 continuation: same task start/status PASS, original base/branch/ownership retained. Reused unchanged project context and audio design, re-read AGENTS/own record and active peer scopes (read-only/undefined reviews and WeChat diagnosis). Planning Gate Passed for local packaged artifact verification only. Build output remains ignored and unpublished; no root workspace, user installation, production API or paid-generation changes.
- TDD RED→GREEN at transport, delivery, adapter/Registry seams; tests cover literal confirmation, fixed mode/pricing/identity, streamed bounds, account change, lost response, automatic recovery without repeat POST, partial restart, owner-only local preview, no fake not_started after submission and nullable receipt normalization.
- Final focused set before the normalization refinement: 7 files / 45 passed. Final refined transport/adapter/delivery slice: 3 files / 13 passed. Typecheck PASS. Full lint PASS (0 errors, 8 existing CloudAgents/CloudCosts/Home/Makelore warnings); final scoped ESLint includes the added Electron test, PASS.
- Full initial unit run: 2,133 passed / 2 skipped / 1 failed (unchanged pi-managed-worker-opener test expects runtime-v6, unchanged runtime is v7). Subsequent broad run excluding only that stale test file and isolated pressure: 244 files / 2,136 passed / 2 skipped; pressure 1/1 PASS. Later additions tested in focused runs; no false full-clean claim.
- Vite Renderer/Main/Preload/utility build PASS. Artifact verifier now requires game-audio ID and hosted route; artifact contract tests PASS. No Windows installer or signed app.asar was produced, so packaged GA-04 acceptance remains open.
- Initial Vite Renderer/Main/Preload/utility build PASS. Artifact verifier requires game-audio ID and hosted route. The continuation below builds and checks a Windows installer; real-provider GA-04 acceptance remains open.
- Actual built Electron synthetic-audio test PASS 1/1 (2.5s): saved result→expand process/tool→explicit preview→native audio duration 0.25s and paused/no autoplay; screenshot visually inspected. It mocks the existing Host seam with a synthetic PCM WAV, not Meowa generation or live billing. First run only needed opening the existing collapsed process group in the test.
- Existing plugin-marketplace/project-plugins Electron diagnostics 4/4 FAIL on stale assertions (removed introductory copy, old local/bundled buttons, old scope=project URL). Those test files and Plugins/ProjectConfiguration product modules have no task diff; current base uses 可选/已安装 tabs and scope=all. These failures are recorded, not hidden or repaired as part of audio.
- Windows continuation: `corepack pnpm run package:win` PASS with --publish never; installer release/Makelore-2.0.1-win-x64.exe (212375107 bytes) and win-unpacked/Makelore.exe produced locally. Product source is committed 09e0ce5cf3d113b3bb7b128b2b04bc355d16173b; at build time only this task record was dirty. Later continuation changes are verifier/test/documentation only. Packaged metadata has no embedded gitCommit; the runtime verifier reports source HEAD as fallback, so this is not represented as embedded commit attestation.
- `node scripts/verify-packaged-electron-runtime.mjs --allow-dirty --manifest release/game-audio-artifact-verification.json` PASS: Electron 43.4.0 / Node 24.18.1, native/Unicode-copy checks, self-contained Python/uv/npm and installer existence. --allow-dirty covered the owned task record only at that time. Existing verifier SHA256 output for the installer: 27741ADBD9CFD45C10701D1146A88866CAF7ED2F6B541EA41AED54FC849C9F32. No new checksum mechanism was added.
- `node scripts/verify-pi-product-artifact.mjs --report release/game-audio-pi-verification.json` PASS on that actual unpacked product after the two verifier corrections: shipped audio manifest/Skill/four tools, main-reachable hosted route, all bundled resources and pinned Pi 0.84.2 closure/worker/session tests. Its global cross-platform runtime aggregation remains partial (no Linux run here; macOS/prior Provider waivers are not new acceptance). `node scripts/verify-publish-runtime.mjs` PASS for packaged npm 11.6.2; this command verifies only and does not publish.
- Final verifier unit tests 18/18 PASS; scoped ESLint and final typecheck PASS; task-aware doc drift and diff-check PASS. Raw artifact reports stay under ignored release/. Paired server task separately verified real PostgreSQL 16.13 migrations and concurrent billing with synthetic Meowa responses. No real Meowa generation, user-machine install, signing/distribution claim, merge, push or production activation occurred.
## Follow-ups
- GA-00/GA-04 HOLD: real Meowa final result shape, MIME/size/count/expiry/charge and PostgreSQL concurrency not verified. No new fee/rate invented and no live generation, publication, install, push, deploy or merge.
- GA-00/GA-04 HOLD: real Meowa final result shape, MIME/size/count/expiry/charge and paired live accepted-generation journey remain unverified. Scoped PostgreSQL concurrency and Windows packaging are now verified separately, not substitutes for that journey. No new fee/rate invented and no live generation, publication, install, push, deploy or merge.
- A real accepted generation using the paired server and packaged client still requires separately bounded paid-canary authorization, plus actual price activation by Operations. The playable synthetic Electron fixture is not a substitute.
- Unrelated base runtime-v6 and old plugin-page E2E assertions need their own maintenance task; no source reset/stash/clean or root worktree writes performed.
## Promotion Candidates
- Target: current-state/module-map/domain rules at integration. Add project-wide Game Audio >=2.0.1, single confirmation→internal polling→all-file auto-save, separate job/delivery/billing phases and receipt-owned local preview. Evidence: public seams, actual built Electron test and paired server record. No conflict with image delivery, Data Service or selected-model Web Search; shared IDs and protocol remain unchanged.
- Target: evidence/commitments. Preserve real-provider/PG/packaged activation holds and exact baseline diagnostic failures. Human confirmation required for paid canary/activation; no canonical promotion in this feature worktree.
- Target: evidence/commitments. Promote scoped Windows package and paired PostgreSQL evidence; preserve real-provider/end-to-end activation holds and exact baseline diagnostic failures. Human confirmation required for paid canary/activation; no canonical promotion in this feature worktree.

View File

@@ -69,7 +69,8 @@ const MARKETPLACE_ARTIFACT_MARKERS = Object.freeze({
renderer: Object.freeze([
'/api/coding/plugin-marketplace/catalog',
'/api/coding/plugin-marketplace/library',
'为你的智能体添加插件,拓展更多能力。',
'plugin-tab-available',
'plugin-tab-installed',
'acquire',
'install_stable',
'enable_project',
@@ -645,17 +646,18 @@ export async function verifyBundledCodingPluginResources({
if (packagedCapability.schemaVersion === 1 && sdkAssetPaths.length === 0) {
throw new Error(`Packaged schema-1 coding plugin has no SDK assets: ${packageName}`);
}
const adapterId = packagedCapability.schemaVersion === 2
const skillOnly = packagedCapability.schemaVersion === 2 && packagedCapability.runtime?.kind === 'skill_only';
const adapterId = skillOnly ? null : packagedCapability.schemaVersion === 2
? packagedCapability.pluginId
: packagedCapability.adapterId;
const tools = Array.isArray(packagedCapability.tools) ? packagedCapability.tools : [];
const toolNames = tools.map((tool) => tool?.name);
if (typeof adapterId !== 'string' || adapterId.length === 0 || tools.length === 0
if ((skillOnly ? tools.length !== 0 : typeof adapterId !== 'string' || adapterId.length === 0 || tools.length === 0)
|| toolNames.some((name) => typeof name !== 'string' || name.length === 0)
|| new Set(toolNames).size !== toolNames.length) {
throw new Error(`Packaged coding plugin adapter/tool catalog is invalid: ${packageName}`);
}
catalogMarkers.push(packagedManifest.name, adapterId, ...toolNames);
catalogMarkers.push(packagedManifest.name, ...(adapterId ? [adapterId] : []), ...toolNames);
packages.push({
id: packagedManifest.name,
version: packagedManifest.version,
@@ -690,7 +692,7 @@ export async function verifyBundledCodingPluginResources({
root: BUNDLED_CODING_PLUGIN_RESOURCE_ROOT,
packages,
catalog: {
adapters: [...new Set(packages.map(({ adapterId }) => adapterId))],
adapters: [...new Set(packages.map(({ adapterId }) => adapterId).filter(Boolean))],
tools: [...new Set(packages.flatMap(({ tools }) => tools))],
packagedInAsar: true,
},

View File

@@ -37,7 +37,7 @@ const MARKETPLACE_ARTIFACT_TEXT = [
'plugin-marketplace\\/install\\/', 'plugin-marketplace\\/update\\/',
'effectiveSkillIds', 'pluginReleaseIds',
'/api/coding/plugin-marketplace/catalog', '/api/coding/plugin-marketplace/library',
'为你的智能体添加插件,拓展更多能力。', 'acquire', 'install_stable', 'enable_project', '/project-config/plugins',
'plugin-tab-available', 'plugin-tab-installed', 'acquire', 'install_stable', 'enable_project', '/project-config/plugins',
].join('\n');
async function createAsarFixture(source: string, archive: string) {
@@ -76,7 +76,7 @@ function matchingMetadata() {
};
}
async function bundledResourceFixture({ schemaVersion = 1, includeSdkAssets = true } = {}) {
async function bundledResourceFixture({ schemaVersion = 1, includeSdkAssets = true, includeTools = true } = {}) {
const root = await mkdtemp(path.join(tmpdir(), 'makelore-bundled-plugin-'));
roots.push(root);
const projectRoot = path.join(root, 'project');
@@ -90,7 +90,7 @@ async function bundledResourceFixture({ schemaVersion = 1, includeSdkAssets = tr
? { runtime: { kind: 'platform_hosted', protocol: 'makelore-hosted.v1' } }
: {}),
skills: [{ id: 'example', entry: '../skills/example/SKILL.md', grants: [] }],
tools: [{ name: 'example_read' }],
tools: includeTools ? [{ name: 'example_read' }] : [],
};
await mkdir(path.join(pluginRoot, 'com.makelore'), { recursive: true });
await mkdir(path.join(pluginRoot, 'skills', 'example'), { recursive: true });
@@ -243,6 +243,26 @@ describe('final Pi product artifact verification', () => {
});
});
it('accepts the shipped skill-only scaffold without an adapter', async () => {
const fixture = await bundledResourceFixture({ schemaVersion: 2, includeSdkAssets: false });
const scaffold = path.resolve('resources/coding-plugins/project-scaffold');
await cp(scaffold, path.join(fixture.projectRoot, 'resources/coding-plugins/project-scaffold'), { recursive: true });
await cp(scaffold, path.join(fixture.resourcesDirectory, 'resources/coding-plugins/project-scaffold'), { recursive: true });
const result = await verifyBundledCodingPluginResources({
...fixture,
appAsarContents: Buffer.concat([fixture.appAsarContents, Buffer.from(' makelore.project-scaffold')]),
});
expect(result.packages).toEqual(expect.arrayContaining([
expect.objectContaining({ id: 'makelore.project-scaffold', tools: [] }),
]));
expect(result.catalog.adapters).toEqual(['example.plugin']);
});
it('still rejects a hosted plugin missing its tool catalog', async () => {
const fixture = await bundledResourceFixture({ schemaVersion: 2, includeSdkAssets: false, includeTools: false });
await expect(verifyBundledCodingPluginResources(fixture)).rejects.toThrow('adapter/tool catalog is invalid');
});
it('proves the packaged Marketplace trust, routes, effective snapshot, and Renderer assets', () => {
const artifact = Buffer.from(MARKETPLACE_ARTIFACT_TEXT);
@@ -405,7 +425,7 @@ describe('final Pi product artifact verification', () => {
'makelore-device-package.v1 /api/coding/device-packages device-parent-workers',
'/api/coding/plugin-marketplace plugin-marketplace\\/install\\/ plugin-marketplace\\/update\\/',
'effectiveSkillIds pluginReleaseIds',
'/api/coding/plugin-marketplace/catalog /api/coding/plugin-marketplace/library 为你的智能体添加插件,拓展更多能力。 acquire install_stable enable_project /project-config/plugins',
'/api/coding/plugin-marketplace/catalog /api/coding/plugin-marketplace/library plugin-tab-available plugin-tab-installed acquire install_stable enable_project /project-config/plugins',
].join('\n'));
const appAsar = path.join(root, 'app.asar');
await createAsarFixture(source, appAsar);
@@ -424,7 +444,7 @@ describe('final Pi product artifact verification', () => {
'makelore.game-audio /api/plugins/v1/hosted/game-audio/generations',
'/api/coding/plugin-marketplace plugin-marketplace\\/install\\/ plugin-marketplace\\/update\\/',
'effectiveSkillIds pluginReleaseIds',
'/api/coding/plugin-marketplace/catalog /api/coding/plugin-marketplace/library 为你的智能体添加插件,拓展更多能力。 acquire enable_project /project-config/plugins',
'/api/coding/plugin-marketplace/catalog /api/coding/plugin-marketplace/library plugin-tab-available plugin-tab-installed acquire enable_project /project-config/plugins',
].join('\n'));
const staleAsar = path.join(root, 'stale.asar');
await createAsarFixture(staleSource, staleAsar);