fix(plugins): preserve unavailable release failures
This commit is contained in:
1 parent
2c5b60ea78
commit
93e3143573
3 files changed
+165
No files matched your search
@@ -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');
|
throw stale('Hosted Plugin worker admission is stale');
|
||||||
}
|
}
|
||||||
const item = resolved.items.find(({ pluginId: candidate }) => candidate === plugin);
|
const item = resolved.items.find(({ pluginId: candidate }) => candidate === plugin);
|
||||||
|
if (item?.action === 'unavailable') {
|
||||||
|
throw unavailable('Hosted Plugin Release is unavailable');
|
||||||
|
}
|
||||||
const matches = item && (bundled
|
const matches = item && (bundled
|
||||||
? matchesBundledFrozenRelease(item, bundled, plugin)
|
? matchesBundledFrozenRelease(item, bundled, plugin)
|
||||||
: matchesFrozenRelease(item, installed, plugin));
|
: matchesFrozenRelease(item, installed, plugin));
|
||||||
|
|||||||
@@ -122,6 +122,33 @@ describe('MarketplaceHostedAdmissionResolver', () => {
|
|||||||
expect(error).toMatchObject({ code: 'plugin_runtime_stale', status: 409, retryable: false });
|
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 () => {
|
it('projects an account change as a typed non-retryable worker failure', async () => {
|
||||||
const { resolver, resolve } = resolverFixture();
|
const { resolver, resolve } = resolverFixture();
|
||||||
resolve.mockRejectedValueOnce({ code: 'marketplace_account_changed' });
|
resolve.mockRejectedValueOnce({ code: 'marketplace_account_changed' });
|
||||||
|
|||||||
Reference in new issue
Block a user