fix(plugins): preserve unavailable release failures
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
# Task: Diagnose Web Search runtime stale after reinstall
|
||||
|
||||
## Identity
|
||||
|
||||
- Task ID: 20260901-web-search-runtime-stale-r2-6f4a2d91
|
||||
- Mode: Feature
|
||||
- Branch: codex/20260901-web-search-runtime-stale-r2-6f4a2d91-web-search-runtime-stale-r2
|
||||
- Worktree: D:\Datas\OthersProjects\makelore-web-search-runtime-stale-r2-6f4a2d91
|
||||
- Base commit: 2c5b60ea78e014a712a47bdbb9efd156f52f3a1d
|
||||
- Owner: codex-root
|
||||
- Status: Ready for Integration
|
||||
|
||||
## Scope
|
||||
|
||||
- Diagnose the installed-client `plugin_runtime_stale` failure after reinstall and a
|
||||
newly created Conversation, using the latest Pi session, installed artifact metadata,
|
||||
Main log, frozen worker manifest, and server Admission response as evidence.
|
||||
- Establish a deterministic read-only reproduction/inspection loop before reading or
|
||||
changing product code. If the fault is client-owned, make the smallest correction in
|
||||
the Marketplace/effective-resolver/hosted-admission/Web Search invocation seam with
|
||||
focused regressions. If evidence locates a deployed server-state problem, stop client
|
||||
mutation and report the exact server prerequisite instead.
|
||||
- Preserve the user root worktree and its two unrelated untracked package records. All
|
||||
product, test, and task-record writes remain in this isolated worktree.
|
||||
|
||||
## Intent And Constraints
|
||||
|
||||
- Concurrent Task Gate: Passed. Task `20260901-web-search-runtime-stale-r2-6f4a2d91`
|
||||
owns this worktree/branch at exact base
|
||||
`2c5b60ea78e014a712a47bdbb9efd156f52f3a1d`; the dirty root was not adopted,
|
||||
stashed, reset, cleaned, or modified.
|
||||
- Planning Gate: Passed after reading the project-memory startup set, current state,
|
||||
decisions, architecture/module/data-flow, business rules, success criteria,
|
||||
glossary, evidence/reflection/commitment/stale indexes, the prior assignment and
|
||||
frozen-worker corrections, official bundled-plugin integration, Web Search main
|
||||
merge, and the only active Web Search peer record.
|
||||
- The old coordinator task `20260831-web-search-client-5b9d2e63` remains at base
|
||||
`0a86ec825...` with no live ownership of this post-merge runtime failure. No semantic
|
||||
or write-scope conflict was found.
|
||||
- Confirmed product invariants: a new parent worker must freeze an acquired, enabled,
|
||||
assigned, exact official bundled Release; child workers receive no hosted tool;
|
||||
invocation still requires current account/project/policy and exact server-owned
|
||||
Release Admission; Renderer/Pi must not receive credentials or Provider authority.
|
||||
- The previous source correction permits only a verified frozen worker to survive a
|
||||
transient stale Library projection. The user's fresh reinstall/new Conversation
|
||||
disproves that correction as a complete explanation, so it will not be broadened
|
||||
without new evidence.
|
||||
- Do not restart or terminate the running client, invoke paid Web Search/OpenAI, alter
|
||||
Account Library/project/Agent state, package, push, deploy, publish, or touch server
|
||||
state without a separately evidenced need and authority.
|
||||
|
||||
## Project Context Loaded
|
||||
|
||||
- Project goal: keep Electron Main as the authenticated Marketplace/hosted-Plugin
|
||||
authority while exposing only frozen, admitted parent tools to Pi.
|
||||
- Current integrated focus: Web Search is an official bundled optional hosted Plugin;
|
||||
assignment discovery and frozen-worker stale-Library fixes are already on `main`.
|
||||
- Active task scope: isolate the remaining installed-client `plugin_runtime_stale`
|
||||
boundary and correct only the proven owner.
|
||||
- Decisions affecting this task: ADR-006 single Pi runtime and frozen logical-thread
|
||||
ownership; distinct Library, project, Agent, runtime Admission, confirmation, and
|
||||
billing states; no hot-swap and no child inheritance.
|
||||
- Evidence/commitments: installed artifacts must be verified rather than inferred from
|
||||
source; live paid Provider and production activation remain out of scope.
|
||||
- Likely modules if client-owned: `electron/coding-plugins/registry.ts`,
|
||||
`effective-resolver.ts`, `hosted-admission.ts`, `marketplace-client.ts`, Web Search
|
||||
adapter, and their focused tests.
|
||||
- Unknowns to resolve first: exact installed source/verification head; exact newest Pi
|
||||
tool event and frozen manifest; whether failure occurs before or inside hosted
|
||||
Admission; whether `/resolve` reports stale, mismatched request identity, or a
|
||||
different exact Release.
|
||||
- Gate result: Passed.
|
||||
|
||||
## Diagnosis Evidence
|
||||
|
||||
- The newest Pi session deterministically reproduces two non-billing
|
||||
`plugin_runtime_stale` results for `makelore_web_search`; both stop before Provider
|
||||
dispatch or Token Point reservation.
|
||||
- The new worker manifest is current and correct: parent-only Web Search Skill/tool,
|
||||
Release `00000000-0000-4000-8000-000000000204`, version `1.0.0`, contract v1,
|
||||
exact project/account snapshot, and platform-metered policy are frozen.
|
||||
- The installed `app.asar` is version `1.2.4` and contains the prior
|
||||
`resolveForInvocation` fix, disproving missing installation, stale conversation,
|
||||
missing Agent assignment, and missing prior product code.
|
||||
- Live anonymous Marketplace detail returns `stable_release=null` and
|
||||
`stable_version=null`. The server task history confirms `0077` lists metadata only;
|
||||
`0078` creates the exact bundled stable Release and has not been deployed.
|
||||
- The integrated `0078` migration additionally declares `min_makelore_version=2.0.0`,
|
||||
while the complete compatible runtime is demonstrably present in installed
|
||||
MakeLore `1.2.4`. Once `0078` is deployed this would become the next Admission
|
||||
blocker.
|
||||
- The remaining client-owned defect is diagnostic fidelity: an explicit Marketplace
|
||||
`action=unavailable` result is currently folded into `plugin_runtime_stale` instead
|
||||
of the existing typed `plugin_release_unavailable` failure.
|
||||
|
||||
## Outcome
|
||||
|
||||
- Corrected the hosted Admission boundary so an explicit Marketplace
|
||||
`action='unavailable'` becomes the existing typed
|
||||
`plugin_release_unavailable` failure instead of being folded into the unrelated
|
||||
`plugin_runtime_stale` worker-snapshot error.
|
||||
- Added regressions for both currently reachable unavailable reasons:
|
||||
`plugin_release_not_ready` and `plugin_client_incompatible`.
|
||||
- The fix is deliberately diagnostic, not a client-side bypass: exact frozen Release,
|
||||
Account, project, policy, Admission, Provider, and billing validation remain intact.
|
||||
The actual production prerequisite is the server's missing `0078` Release migration
|
||||
followed by the `0079` compatibility correction.
|
||||
|
||||
## Verification
|
||||
|
||||
- Deterministic installed-client evidence: newest Pi session reproduced two
|
||||
`plugin_runtime_stale` Web Search calls; the frozen parent manifest and installed
|
||||
`1.2.4` app contained the expected Skill, tool, Release, account/project snapshot,
|
||||
and prior resolver implementation.
|
||||
- TDD RED: both explicit unavailable-reason cases returned
|
||||
`plugin_runtime_stale`; GREEN after the boundary correction.
|
||||
- `pnpm exec vitest run tests/unit/hosted-admission.test.ts
|
||||
tests/unit/web-search-plugin-adapter.test.ts
|
||||
tests/unit/game-resource-plugin-adapter.test.ts`: 3 files, 25 tests passed.
|
||||
- `pnpm exec tsc --noEmit`: passed.
|
||||
- Scoped ESLint for the changed implementation and test: passed.
|
||||
- `git diff --check`: passed. No installed client, user root worktree, Account/Library,
|
||||
project/Agent assignment, Provider, billing, or production state was mutated.
|
||||
|
||||
## Follow-ups
|
||||
|
||||
- Integrate this small diagnostic correction into the next MakeLore build so future
|
||||
Release availability failures remain truthful. It is not required to make the
|
||||
current installed runtime compatible once the server Release/migration gate is fixed.
|
||||
- Deploy/apply server `0078` and `0079`, reopen the worker, then verify Provider
|
||||
readiness before performing an explicitly authorized paid Web Search smoke.
|
||||
|
||||
## Promotion Candidates
|
||||
|
||||
- None recorded.
|
||||
@@ -192,6 +192,9 @@ export class MarketplaceHostedAdmissionResolver {
|
||||
throw stale('Hosted Plugin worker admission is stale');
|
||||
}
|
||||
const item = resolved.items.find(({ pluginId: candidate }) => candidate === plugin);
|
||||
if (item?.action === 'unavailable') {
|
||||
throw unavailable('Hosted Plugin Release is unavailable');
|
||||
}
|
||||
const matches = item && (bundled
|
||||
? matchesBundledFrozenRelease(item, bundled, plugin)
|
||||
: matchesFrozenRelease(item, installed, plugin));
|
||||
|
||||
@@ -122,6 +122,33 @@ describe('MarketplaceHostedAdmissionResolver', () => {
|
||||
expect(error).toMatchObject({ code: 'plugin_runtime_stale', status: 409, retryable: false });
|
||||
});
|
||||
|
||||
it.each([
|
||||
'plugin_release_not_ready',
|
||||
'plugin_client_incompatible',
|
||||
])('preserves an explicit unavailable Release as plugin_release_unavailable (%s)', async (reason) => {
|
||||
const marketplace = {
|
||||
resolve: vi.fn(async () => resolved({
|
||||
action: 'unavailable',
|
||||
releaseAdmissionId: null,
|
||||
reason,
|
||||
})),
|
||||
} as unknown as Pick<MarketplacePackageClientPort, 'resolve'>;
|
||||
const unavailableResolver = new MarketplaceHostedAdmissionResolver({
|
||||
packageStore: { getInstalledRelease: vi.fn(async () => installed()) } as unknown as Pick<PluginPackageStore, 'getInstalledRelease'>,
|
||||
marketplace,
|
||||
makeloreVersion: '1.2.4',
|
||||
});
|
||||
|
||||
await expect(unavailableResolver.resolve({
|
||||
pluginId: PLUGIN_ID,
|
||||
workerSnapshot: { requestId: REQUEST_ID, pluginReleaseId: RELEASE_ID },
|
||||
})).rejects.toMatchObject({
|
||||
code: 'plugin_release_unavailable',
|
||||
status: 409,
|
||||
retryable: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('projects an account change as a typed non-retryable worker failure', async () => {
|
||||
const { resolver, resolve } = resolverFixture();
|
||||
resolve.mockRejectedValueOnce({ code: 'marketplace_account_changed' });
|
||||
|
||||
Reference in New Issue
Block a user