[GH-ISSUE #8404] [Bug] Provider-wide startup failure leaves stale per-operation unavailability after recovery #6586

Closed
opened 2026-11-01 21:12:28 +00:00 by bsakaguchi · 6 comments
Owner

Originally created by @morluto on GitHub (Nov 1, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/8404

Originally assigned to: @kaoru0822-kitauji on GitHub.

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Provider or capability discovery

Observed behavior

After a Ghidra startup failure, binary_session marked all its routed operations unavailable. Once I repaired the deliberately missing installation path, the first retried operation succeeded and became available, but other operations remained marked unavailable even though subsequent direct retries of those operations also succeeded. Their stale remediation cited the earlier startup failure.

Reproduction

With main 6e9ee97a69cb16c7150d8b550e705cba055ee4f0, real Ghidra 12.1.4 and stdio MCP on macOS arm64:

  1. Configure GHIDRA_INSTALL_DIR as an owned symlink to the installed distribution. Open a self-built Mach-O with provider_id: "ghidra", before making any Ghidra analysis request.
  2. Remove only that temporary symlink. procedure_address and procedure_assembly each return execution_failure with missing-installation diagnostics; REA's session marks the provider's operations unavailable.
  3. Restore the symlink. Before retrying, binary_session reports procedure_address, procedure_assembly, and list_procedures unavailable. Retry procedure_address: it succeeds. Session discovery now marks that operation available but continues to mark the other two unavailable.
  4. Retry procedure_assembly: it succeeds and its availability clears; list_procedures is still reported unavailable. Retry list_procedures: it succeeds and becomes available. The calls above were made within the same open session, without reopening the target.

Afterward explicit same-target/provider reopen and close also succeeded. The target and installed Ghidra files were not modified; the target digest stayed unchanged. Successful MCP calls used SDK validation against fetched compact-profile schemas. This sequence ran in controlled temporary paths; it does not establish failure frequency.

Expected behavior

Distinguish a historical provider-wide startup failure from an independently observed current per-operation failure, and expose that the former may be retried after recovery. A successful operation is evidence the provider can answer that request, not automatic proof that every capability is healthy. Preserve genuine operation-specific refusals and active session state.

Impact and scope

An agent that trusts discovery can avoid list_procedures even though it succeeds after the startup issue is repaired. I did not measure agent behavior. This test covers one Ghidra version, one host and a deliberately removed/restored path; other errors, providers, and lifecycle stages are untested.

REA version

6e9ee97a69cb16c7150d8b550e705cba055ee4f0 (built source).

Runtime and platform

Node 24.22.1, MCP SDK 2.3.1, macOS arm64, Ghidra 12.1.4 and JDK 21.

Target and artifact context

Self-built thin arm64 Mach-O, SHA-256 ffad1b70c6a5a7ef3f7c3f59126be516520210777d949b35e97c9067f272aa2d; static analysis only, never executed.

Interface

MCP

Earliest failure stage

Transport or result projection

Relevant output or evidence

After the repair, before retries: all three operations above were available: false, reason: provider_unavailable. After address success: address became available but assembly and inventory remained unavailable. After assembly success: inventory remained unavailable. After the inventory succeeded it became available. The first failure included executable_missing in Ghidra installation diagnostics.

Typed outcome or recovery expected

Represent the scope and freshness of the last failure, with a safe way to re-evaluate or retry. Do not silently turn unrelated operation failures into confirmed successes merely because one request worked.

Analysis or suspected cause

Source-derived: BinarySession.#observeRuntimeAvailability marks all operations owned by the provider unavailable on a ProviderAdapterError, but successful requests clear only the requested operation. A provider-wide startup failure therefore creates per-operation-looking retained failures with no freshness marker. This explains the observed status pattern, not the correct general recovery policy.

Additional context

Related #8403 concerns selection-time candidate readiness after repair; this report concerns active-route runtime unavailability projected after an observed failure and partial recovery. #8402 concerns connecting tool recovery to candidate facts. Last known good: NOT_ENOUGH_INFO. Proposed controls: genuinely operation-specific failure, repeat startup failure, cancellation, failed cleanup, retained session edits, full MCP schema profile and other providers.

Looping in @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0.

Originally created by @morluto on GitHub (Nov 1, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8404 Originally assigned to: @kaoru0822-kitauji on GitHub. ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Provider or capability discovery ### Observed behavior After a Ghidra startup failure, `binary_session` marked all its routed operations unavailable. Once I repaired the deliberately missing installation path, the first retried operation succeeded and became available, but other operations remained marked unavailable even though subsequent direct retries of those operations also succeeded. Their stale remediation cited the earlier startup failure. ### Reproduction With main `6e9ee97a69cb16c7150d8b550e705cba055ee4f0`, real Ghidra 12.1.4 and stdio MCP on macOS arm64: 1. Configure `GHIDRA_INSTALL_DIR` as an owned symlink to the installed distribution. Open a self-built Mach-O with `provider_id: "ghidra"`, before making any Ghidra analysis request. 2. Remove only that temporary symlink. `procedure_address` and `procedure_assembly` each return `execution_failure` with missing-installation diagnostics; REA's session marks the provider's operations unavailable. 3. Restore the symlink. Before retrying, `binary_session` reports `procedure_address`, `procedure_assembly`, and `list_procedures` unavailable. Retry `procedure_address`: it succeeds. Session discovery now marks that operation available but continues to mark the other two unavailable. 4. Retry `procedure_assembly`: it succeeds and its availability clears; `list_procedures` is still reported unavailable. Retry `list_procedures`: it succeeds and becomes available. The calls above were made within the same open session, without reopening the target. Afterward explicit same-target/provider reopen and close also succeeded. The target and installed Ghidra files were not modified; the target digest stayed unchanged. Successful MCP calls used SDK validation against fetched compact-profile schemas. This sequence ran in controlled temporary paths; it does not establish failure frequency. ### Expected behavior Distinguish a historical provider-wide startup failure from an independently observed current per-operation failure, and expose that the former may be retried after recovery. A successful operation is evidence the provider can answer that request, not automatic proof that every capability is healthy. Preserve genuine operation-specific refusals and active session state. ### Impact and scope An agent that trusts discovery can avoid `list_procedures` even though it succeeds after the startup issue is repaired. I did not measure agent behavior. This test covers one Ghidra version, one host and a deliberately removed/restored path; other errors, providers, and lifecycle stages are untested. ### REA version `6e9ee97a69cb16c7150d8b550e705cba055ee4f0` (built source). ### Runtime and platform Node 24.22.1, MCP SDK 2.3.1, macOS arm64, Ghidra 12.1.4 and JDK 21. ### Target and artifact context Self-built thin arm64 Mach-O, SHA-256 `ffad1b70c6a5a7ef3f7c3f59126be516520210777d949b35e97c9067f272aa2d`; static analysis only, never executed. ### Interface MCP ### Earliest failure stage Transport or result projection ### Relevant output or evidence After the repair, before retries: all three operations above were `available: false`, `reason: provider_unavailable`. After address success: address became available but assembly and inventory remained unavailable. After assembly success: inventory remained unavailable. After the inventory succeeded it became available. The first failure included `executable_missing` in Ghidra installation diagnostics. ### Typed outcome or recovery expected Represent the scope and freshness of the last failure, with a safe way to re-evaluate or retry. Do not silently turn unrelated operation failures into confirmed successes merely because one request worked. ### Analysis or suspected cause Source-derived: [`BinarySession.#observeRuntimeAvailability`](https://github.com/morluto/rea/blob/6e9ee97a69cb16c7150d8b550e705cba055ee4f0/src/application/binary/BinarySession.ts) marks all operations owned by the provider unavailable on a `ProviderAdapterError`, but successful requests clear only the requested operation. A provider-wide startup failure therefore creates per-operation-looking retained failures with no freshness marker. This explains the observed status pattern, not the correct general recovery policy. ### Additional context Related #8403 concerns selection-time candidate readiness after repair; this report concerns active-route runtime unavailability projected after an observed failure and partial recovery. #8402 concerns connecting tool recovery to candidate facts. Last known good: NOT_ENOUGH_INFO. Proposed controls: genuinely operation-specific failure, repeat startup failure, cancellation, failed cleanup, retained session edits, full MCP schema profile and other providers. Looping in @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0.
bsakaguchi 2026-11-01 21:12:28 +00:00
  • closed this issue
  • added the
    bug
    triage
    labels
Author
Owner

@morluto commented on GitHub (Nov 1, 2026):

Real Ghidra negative controls

On clean main 6e9ee97a, Ghidra 12.1.4 / SDK 2.3.1 on macOS arm64, I exercised a fresh import and a deliberately unanalyzed, caller-selected read-only project in separate MCP sessions under both compact and full output-schema profiles.

  • Looking up a syntactically valid but nonexistent procedure name returned invalid_request; procedure_address stayed advertised available and a subsequent list_procedures succeeded in every session. This request error did not become a provider-wide availability failure.
  • In the selected project, annotate_native_function was already advertised unavailable with the specific read-only-project reason and correctly returned capability_unavailable. A later successful list_procedures did not change that restriction. The selected project's original analysis-history caveat remains applicable.

All successful calls were checked against the SDK's fetched advertised schemas; the target and original project file hashes remained unchanged. These are controls for an eventual #8404 fix: clearing a stale provider-wide startup observation must not erase an independent declared authority restriction or promote a bad selector into provider unavailability. They do not exercise a genuine operation-specific adapter failure, cancellation, or other hosts.

<!-- gh-comment-id:6551118058 --> @morluto commented on GitHub (Nov 1, 2026): ### Real Ghidra negative controls On clean main `6e9ee97a`, Ghidra 12.1.4 / SDK 2.3.1 on macOS arm64, I exercised a fresh import and a deliberately unanalyzed, caller-selected read-only project in separate MCP sessions under both compact and full output-schema profiles. - Looking up a syntactically valid but nonexistent procedure name returned `invalid_request`; `procedure_address` stayed advertised available and a subsequent `list_procedures` succeeded in every session. This request error did not become a provider-wide availability failure. - In the selected project, `annotate_native_function` was already advertised unavailable with the specific read-only-project reason and correctly returned `capability_unavailable`. A later successful `list_procedures` did not change that restriction. The selected project's original analysis-history caveat remains applicable. All successful calls were checked against the SDK's fetched advertised schemas; the target and original project file hashes remained unchanged. These are controls for an eventual #8404 fix: clearing a stale provider-wide startup observation must not erase an independent declared authority restriction or promote a bad selector into provider unavailability. They do not exercise a genuine operation-specific adapter failure, cancellation, or other hosts.
Author
Owner

@morluto commented on GitHub (Nov 1, 2026):

SDK catalog and live-availability control

I repeated the real Ghidra pre-start failure and repair on main 6e9ee97a with an SDK 2.3.1 stdio client listening for notifications/tools/list_changed. I fetched tools/list before target open, after open, after the provider failure, after the tested retries succeeded, and after close. All five catalogs were exactly equal (234 tools); no list-changed notification was observed. At each tested status stage the union of binary_session.tool_availability.groups[].names exactly matched the fetched tool names. Successful tool responses used the fetched compact output schemas.

This agrees with the documented design: catalog identity is stable, while binary_session carries current route and operation availability. It also means re-fetching tools/list is not a recovery mechanism for the stale availability described above. After repairing the configured Ghidra path, successful direct retries cleared the tested operations individually; an untried list_procedures remained advertised unavailable until it too succeeded. Original target digest was unchanged, and close succeeded. This is one controlled failure on one host, not a claim about external client notification handling or every operation.

<!-- gh-comment-id:6551128910 --> @morluto commented on GitHub (Nov 1, 2026): ### SDK catalog and live-availability control I repeated the real Ghidra pre-start failure and repair on main `6e9ee97a` with an SDK 2.3.1 stdio client listening for `notifications/tools/list_changed`. I fetched `tools/list` before target open, after open, after the provider failure, after the tested retries succeeded, and after close. All five catalogs were exactly equal (234 tools); no list-changed notification was observed. At each tested status stage the union of `binary_session.tool_availability.groups[].names` exactly matched the fetched tool names. Successful tool responses used the fetched compact output schemas. This agrees with the documented design: catalog identity is stable, while `binary_session` carries current route and operation availability. It also means re-fetching `tools/list` is not a recovery mechanism for the stale availability described above. After repairing the configured Ghidra path, successful direct retries cleared the tested operations individually; an untried `list_procedures` remained advertised unavailable until it too succeeded. Original target digest was unchanged, and close succeeded. This is one controlled failure on one host, not a claim about external client notification handling or every operation.
Author
Owner

@morluto commented on GitHub (Nov 1, 2026):

Scoped catalog: recovery through composed tools

On clean main 6e9ee97a, real Ghidra 12.1.4 and SDK 2.3.1 stdio MCP on macOS arm64, I repeated the controlled pre-start path failure with REA_MCP_TOOL_FAMILIES=session,enhanced (39 advertised tools):

  1. analyze_function failed while the temporary Ghidra path was absent. After restoring it, retrying analyze_function succeeded, but binary_session still advertised trace_feature and get_call_graph unavailable with the earlier adapter failure.
  2. The direct tools such as list_procedures, procedure_address, and procedure_callees were outside the caller-selected scope. An explicit list_procedures request received the SDK's disabled-tool error.
  3. Calling the advertised trace_feature despite its unavailable status succeeded with matches and references; discovery then marked that workflow available. Calling the still-unavailable forward get_call_graph also succeeded; afterward its forward mode was available while its untested backward mode remained unavailable due to its own retained prerequisite status.
  4. Exported the resulting Evidence and imported it into a fresh target-free scoped server. The retained trace and graph normalized results and limitations matched the live results. The SDK validated successful responses against fetched compact schemas, the status group names matched the scoped catalog, and the target hash was unchanged.

This illustrates the agent-facing consequence of the stale provider-wide status in a registration where the direct prerequisites cannot be called individually. It does not show an actual agent choosing a fallback, prove all untested modes work, or mean that a successful forward graph validates backward coverage. No target was executed.

<!-- gh-comment-id:6551140915 --> @morluto commented on GitHub (Nov 1, 2026): ### Scoped catalog: recovery through composed tools On clean main `6e9ee97a`, real Ghidra 12.1.4 and SDK 2.3.1 stdio MCP on macOS arm64, I repeated the controlled pre-start path failure with `REA_MCP_TOOL_FAMILIES=session,enhanced` (39 advertised tools): 1. `analyze_function` failed while the temporary Ghidra path was absent. After restoring it, retrying `analyze_function` succeeded, but `binary_session` still advertised `trace_feature` and `get_call_graph` unavailable with the earlier adapter failure. 2. The direct tools such as `list_procedures`, `procedure_address`, and `procedure_callees` were outside the caller-selected scope. An explicit `list_procedures` request received the SDK's disabled-tool error. 3. Calling the advertised `trace_feature` despite its unavailable status succeeded with matches and references; discovery then marked that workflow available. Calling the still-unavailable forward `get_call_graph` also succeeded; afterward its forward mode was available while its untested backward mode remained unavailable due to its own retained prerequisite status. 4. Exported the resulting Evidence and imported it into a fresh target-free scoped server. The retained trace and graph normalized results and limitations matched the live results. The SDK validated successful responses against fetched compact schemas, the status group names matched the scoped catalog, and the target hash was unchanged. This illustrates the agent-facing consequence of the stale provider-wide status in a registration where the direct prerequisites cannot be called individually. It does not show an actual agent choosing a fallback, prove all untested modes work, or mean that a successful forward graph validates backward coverage. No target was executed.
Author
Owner

@morluto commented on GitHub (Nov 1, 2026):

Exploratory ownership split

I tested an uncommitted prototype against clean main 6e9ee97a in a separate checkout. It distinguishes an operation's directly observed runtime failure from unavailability inferred for sibling operations when a provider adapter fails. A successful provider call clears that call's failure and the provider-inferred sibling flags, while retaining separately observed operation refusals.

  • In the real Ghidra 12.1.4 scoped session,enhanced recovery, after the path was restored and analyze_function succeeded, trace_feature and forward/backward call-graph modes returned to their provider-declared availability. Feature tracing and the forward call graph then succeeded, and their Evidence round-tripped through a fresh scoped server. Backward execution was not tested, so the available status is not proof that mode works.
  • In the real unscoped control, address lookup and assembly had both directly failed during the startup interruption. After address lookup succeeded, it and the never-called inventory returned to declared availability; assembly remained unavailable until its own successful retry. Target digest stayed unchanged.
  • Fresh and selected-project real Ghidra controls passed under compact and full SDK profiles: a missing name did not mark the provider unavailable, and a selected read-only project's annotation restriction remained unavailable after successful calls.
  • One in-memory MCP boundary test injected both an adapter error and a distinct operation-specific capability refusal. Another operation's success cleared inferred flags while keeping both observed failures; the first failure cleared only on its own success. The four-test boundary file passed on the prototype and the new test failed on main at the intended stale sibling status. This is a simulated-provider control, not proof of real behavior for other providers.
  • A real Kuna missing-path/restoration control retained its earlier behavior: the tested operations continued to fail until explicit reopen. This experiment does not address #8403.

This is not a submitted fix. In particular, returning siblings to their declared availability after one successful call is a design choice, not evidence each sibling is currently healthy. The prototype needs a decision on whether that is the right public meaning of available versus an explicit unknown/stale state, and further checks for other providers, overlapping failures, concurrency, cancellation, lifecycle transitions and cleanup. It does not automatically reselect a provider or alter targets.

<!-- gh-comment-id:6551171225 --> @morluto commented on GitHub (Nov 1, 2026): ### Exploratory ownership split I tested an uncommitted prototype against clean main `6e9ee97a` in a separate checkout. It distinguishes an operation's directly observed runtime failure from unavailability inferred for sibling operations when a provider adapter fails. A successful provider call clears that call's failure and the provider-inferred sibling flags, while retaining separately observed operation refusals. - In the real Ghidra 12.1.4 scoped `session,enhanced` recovery, after the path was restored and `analyze_function` succeeded, `trace_feature` and forward/backward call-graph modes returned to their provider-declared availability. Feature tracing and the forward call graph then succeeded, and their Evidence round-tripped through a fresh scoped server. Backward execution was **not** tested, so the available status is not proof that mode works. - In the real unscoped control, address lookup and assembly had both directly failed during the startup interruption. After address lookup succeeded, it and the never-called inventory returned to declared availability; assembly remained unavailable until its own successful retry. Target digest stayed unchanged. - Fresh and selected-project real Ghidra controls passed under compact and full SDK profiles: a missing name did not mark the provider unavailable, and a selected read-only project's annotation restriction remained unavailable after successful calls. - One in-memory MCP boundary test injected both an adapter error and a distinct operation-specific capability refusal. Another operation's success cleared inferred flags while keeping both observed failures; the first failure cleared only on its own success. The four-test boundary file passed on the prototype and the new test failed on main at the intended stale sibling status. This is a simulated-provider control, not proof of real behavior for other providers. - A real Kuna missing-path/restoration control retained its earlier behavior: the tested operations continued to fail until explicit reopen. This experiment does not address #8403. This is **not a submitted fix**. In particular, returning siblings to their declared availability after one successful call is a design choice, not evidence each sibling is currently healthy. The prototype needs a decision on whether that is the right public meaning of `available` versus an explicit unknown/stale state, and further checks for other providers, overlapping failures, concurrency, cancellation, lifecycle transitions and cleanup. It does not automatically reselect a provider or alter targets.
Author
Owner

@morluto commented on GitHub (Nov 1, 2026):

Additional prototype boundary checks

I extended the uncommitted prototype with in-memory MCP tests using simulated providers:

  • A refusal observed for one operation remained attached to it when a later adapter error affected sibling operations. A successful call on a different provider cleared that provider's inferred flags without clearing the first provider's failures. These controls passed on the prototype.
  • An earlier in-flight success completed after a newer provider failure. The first prototype incorrectly cleared the newer inferred state. A revision-aware experiment preserved the newer failure; a fresh subsequent success cleared it. A separate same-operation control showed that current main also clears a newer explicit operation refusal when an older success arrives later. These are deliberately ordered simulated-provider results, not a real Ghidra/Kuna concurrency reproduction.
  • The revision-aware experiment then failed a different controlled case: a request admitted before the failure was queued, actually executed after the failure, and succeeded. Its admission-time revision was old, so the prototype incorrectly retained unavailable sibling status. REA's Ghidra request queue serializes Program requests, so admission order cannot by itself establish provider execution order. The queued case is an in-memory model of that distinction, not a claim that the exact interleaving was reproduced against Ghidra.

After adding the revision guard, the seven-test MCP boundary file and the associated session liveness/status files passed (30 tests), and check:fast passed. Real scoped Ghidra recovery and the Kuna failure/reopen control also still behaved as in the previous comment. The added queued-execution test then failed the prototype as described. The first overlap-test run failed earlier because its synthetic health response was missing; that setup was corrected before the reported results.

This counterexample reinforces that the prototype is not PR-ready. A proper design needs owner-provided ordering or an honest unknown/stale representation; it must not infer execution timing from when the application dispatched the request, clear real operation-specific refusals, or claim all operations healthy from one success. No target or user worktree was modified.

<!-- gh-comment-id:6551209155 --> @morluto commented on GitHub (Nov 1, 2026): ### Additional prototype boundary checks I extended the uncommitted prototype with in-memory MCP tests using simulated providers: - A refusal observed for one operation remained attached to it when a later adapter error affected sibling operations. A successful call on a different provider cleared that provider's inferred flags without clearing the first provider's failures. These controls passed on the prototype. - An earlier in-flight success completed after a newer provider failure. The first prototype incorrectly cleared the newer inferred state. A revision-aware experiment preserved the newer failure; a fresh subsequent success cleared it. A separate same-operation control showed that current main also clears a newer explicit operation refusal when an older success arrives later. These are deliberately ordered simulated-provider results, not a real Ghidra/Kuna concurrency reproduction. - The revision-aware experiment then failed a different controlled case: a request admitted before the failure was queued, actually executed after the failure, and succeeded. Its admission-time revision was old, so the prototype incorrectly retained unavailable sibling status. REA's [Ghidra request queue](https://github.com/morluto/rea/blob/6e9ee97a69cb16c7150d8b550e705cba055ee4f0/src/ghidra/GhidraRequestQueue.ts) serializes Program requests, so admission order cannot by itself establish provider execution order. The queued case is an in-memory model of that distinction, not a claim that the exact interleaving was reproduced against Ghidra. After adding the revision guard, the seven-test MCP boundary file and the associated session liveness/status files passed (30 tests), and `check:fast` passed. Real scoped Ghidra recovery and the Kuna failure/reopen control also still behaved as in the previous comment. The added queued-execution test then failed the prototype as described. The first overlap-test run failed earlier because its synthetic health response was missing; that setup was corrected before the reported results. This counterexample reinforces that the prototype is **not PR-ready**. A proper design needs owner-provided ordering or an honest unknown/stale representation; it must not infer execution timing from when the application dispatched the request, clear real operation-specific refusals, or claim all operations healthy from one success. No target or user worktree was modified.
Author
Owner

@morluto commented on GitHub (Nov 1, 2026):

Existing contract constraint on an unknown state

I checked the real binary_session schemas fetched from clean main 6e9ee97a with SDK 2.3.1. Starting from a valid captured recovery-status response, I changed one unavailable tool group in local copies and validated them with Ajv 2020 plus formats and the server's canonical Zod contract:

Local hypothetical change Compact advertised schema Full advertised schema Canonical server contract
available: null, reason: "unknown" Accepted Rejected Rejected
available: false, reason: "provider_unknown" Accepted Rejected Rejected
Add availability_freshness: "stale" to the group Accepted Rejected Rejected
Keep available: false, reason: "provider_unavailable"; change remediation text Accepted Accepted Accepted

Compact output intentionally advertises a reduced schema whose result is just an object; acceptance there does not establish that the server would emit an invalid canonical result. The full group schema has a boolean discriminant, a closed reason enum, and strict properties. Therefore an explicit machine-readable unknown/freshness state needs a deliberate schema and client-contract change; text alone fits the existing shape but retains the available: false / provider_unavailable classification. These were local validation experiments, not changes sent to a production server or measurements of external client behavior.

Any design should also account for the queued-versus-in-flight ordering counterexample above. The initial compact-only probe incorrectly expected its reduced schema to reject the hypothetical unknown; the full-schema and canonical checks above are the corrected result.

In the earlier real Ghidra startup-failure and Kuna missing-path controls, every sampled binary_session.provider_operation_health was null, including after the observed failures and recovery attempts. Thus that field did not supply the missing live readiness state in these runs; this is not a claim about every provider or configuration.

Follow-up: I captured both summary and complete session results from a new real-Ghidra recovery run and repeated all four hypothetical mutations against both fetched schema profiles and the canonical contract (16 combinations). The same acceptance pattern held for both detail levels; the original unmodified outputs validated in all three checks. The temporary target and installation symlink were restored/unchanged at cleanup.

<!-- gh-comment-id:6551222685 --> @morluto commented on GitHub (Nov 1, 2026): ### Existing contract constraint on an unknown state I checked the real `binary_session` schemas fetched from clean main `6e9ee97a` with SDK 2.3.1. Starting from a valid captured recovery-status response, I changed one unavailable tool group in local copies and validated them with Ajv 2020 plus formats and the server's canonical Zod contract: | Local hypothetical change | Compact advertised schema | Full advertised schema | Canonical server contract | | --- | --- | --- | --- | | `available: null`, `reason: "unknown"` | Accepted | Rejected | Rejected | | `available: false`, `reason: "provider_unknown"` | Accepted | Rejected | Rejected | | Add `availability_freshness: "stale"` to the group | Accepted | Rejected | Rejected | | Keep `available: false`, `reason: "provider_unavailable"`; change remediation text | Accepted | Accepted | Accepted | Compact output intentionally advertises a reduced schema whose `result` is just an object; acceptance there does **not** establish that the server would emit an invalid canonical result. The full group schema has a boolean discriminant, a closed reason enum, and strict properties. Therefore an explicit machine-readable unknown/freshness state needs a deliberate schema and client-contract change; text alone fits the existing shape but retains the `available: false` / `provider_unavailable` classification. These were local validation experiments, not changes sent to a production server or measurements of external client behavior. Any design should also account for the queued-versus-in-flight ordering counterexample above. The initial compact-only probe incorrectly expected its reduced schema to reject the hypothetical unknown; the full-schema and canonical checks above are the corrected result. In the earlier real Ghidra startup-failure and Kuna missing-path controls, every sampled `binary_session.provider_operation_health` was `null`, including after the observed failures and recovery attempts. Thus that field did not supply the missing live readiness state in these runs; this is not a claim about every provider or configuration. Follow-up: I captured both summary and complete session results from a new real-Ghidra recovery run and repeated all four hypothetical mutations against both fetched schema profiles and the canonical contract (16 combinations). The same acceptance pattern held for both detail levels; the original unmodified outputs validated in all three checks. The temporary target and installation symlink were restored/unchanged at cleanup.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#6586
No description provided.