[GH-ISSUE #5117] [Design] Provider-neutral batch export for native machine evidence #3152

Open
opened 2026-10-31 00:37:15 +00:00 by bsakaguchi · 4 comments
Owner

Originally created by @kmatzen on GitHub (Oct 18, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/5117

Before submitting

  • I searched the open and closed issues and pull requests for a related discussion.
  • I understand the contribution scope must be reviewed before integration; open questions are welcome here.
  • This discussion does not include credentials, private samples, or sensitive target data.

Decision needed

Should REA add a provider-neutral, batch-oriented native machine-evidence export contract, distinct from exporting the complete Evidence ledger, that joins exact function and instruction facts needed for reconstruction and conformance testing?

Context and evidence

REA already exposes most ingredients, but across several scopes:

  • analyze_function retains function identity/body, provider assembly, CFG, references, unresolved calls, pseudocode, native API observations, and bounded high P-code.
  • inspect_native_instruction exposes exact decoded bytes, operands, flow, references, and decoder context for one address.
  • inspect_analysis_view pages retained native facets.
  • export_evidence_bundle exports the complete investigation ledger.

For a firmware reconstruction workflow, the missing operation is a stable batch projection joining those facts for a selected set of functions or address ranges. Today a caller must issue and reconcile many provider-specific requests or maintain custom Ghidra Java exporters. That makes it harder to preserve exact instruction bytes, function spans, delay-slot ownership, low/raw P-code, references, CFG edges, and unresolved computed transfers under one artifact identity and coverage declaration.

This arose while validating SuperH delay-slot literal recovery and building a source-owned SH-4 conformance corpus. The first fixture is a synthetic CC0 160-byte image containing ten literal-loaded tail thunks. Its expected manifest records exact instructions, delay-slot ownership, P-code invariants, references, CFG edges, and pseudocode invariants. No private target bytes are needed for the proposed contract or its verification.

Expected interaction with targets

  • Read existing files or captured data

Static provider analysis only. No target execution, process attachment, instrumentation, memory/register changes, configuration writes, or network access should be implied by this operation.

Boundary details

  • Caller selects exact procedures, addresses, ranges, or a bounded query result.
  • Output remains bound to the target digest, analysis profile, provider identity/version, language/compiler specification, and any load-image attestation.
  • Provider-native facts retain provenance; unavailable facts are null/unknown rather than synthesized.
  • Function bodies may be non-contiguous, so spans should be address ranges plus total bytes rather than only [entry, entry + length).
  • Delay-slot ownership should be explicit where the provider exposes it; omission must mean unavailable, not false.
  • Low/raw instruction P-code and decompiler high P-code are distinct facets and must not be conflated.
  • Static references and provider-resolved computed targets do not establish runtime reachability.
  • Cancellation, truncation, per-item failure, omitted counts, and unresolved transfers remain visible.

Options and tradeoffs

  1. Add a new operation such as export_native_machine_evidence that returns or retains a normalized batch artifact. This is easiest for callers but adds a public persisted contract.
  2. Add a native batch view over retained Evidence. This reuses the current ledger/view model but still needs a producer capable of collecting the selected instruction-level facts without one MCP round trip per address.
  3. Extend analyze_function with optional exact instruction/P-code/delay-slot facets. This is smaller, but batching and provider-neutral export would remain caller-owned.

A possible normalized record per function would include:

  • canonical identity, classification, non-contiguous body ranges, total bytes;
  • exact ordered instructions: address, bytes, mnemonic/operands, decoder context, delay-slot owner/owned slot;
  • raw instruction P-code with operation order and address-space identity;
  • typed incoming/outgoing references and unresolved computed calls/jumps;
  • CFG blocks and edges, including delayed-transfer semantics without inventing runtime paths;
  • optional decompiler pseudocode/high-P-code as separately provenance-labeled facets;
  • per-facet availability, completeness, truncation, limitations, unknowns, and digest.

Verification available so far

I have a prototype fixture and observed results.

Success criteria and open questions

  • The same source-owned miniature binary can be exported through Ghidra and any future capable provider into one normalized schema.
  • Exact bytes, instruction ordering, references, CFG edges, unresolved transfers, and delay-slot ownership can be asserted without parsing provider display text.
  • Partial provider support is truthful at the facet level; unsupported fields do not reject otherwise useful exports.
  • Batch output is deterministic, bounded, pageable/retainable, and bound to exact target/profile identities.
  • A round trip through retained Evidence or a portable bundle preserves the normalized artifact exactly.
  • It remains open whether raw P-code should be mandatory for Ghidra, an optional provider extension, or a separate linked facet.

References

Originally created by @kmatzen on GitHub (Oct 18, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5117 ### Before submitting - [x] I searched the open and closed issues and pull requests for a related discussion. - [x] I understand the contribution scope must be reviewed before integration; open questions are welcome here. - [x] This discussion does not include credentials, private samples, or sensitive target data. ### Decision needed Should REA add a provider-neutral, batch-oriented native machine-evidence export contract, distinct from exporting the complete Evidence ledger, that joins exact function and instruction facts needed for reconstruction and conformance testing? ### Context and evidence REA already exposes most ingredients, but across several scopes: - `analyze_function` retains function identity/body, provider assembly, CFG, references, unresolved calls, pseudocode, native API observations, and bounded high P-code. - `inspect_native_instruction` exposes exact decoded bytes, operands, flow, references, and decoder context for one address. - `inspect_analysis_view` pages retained native facets. - `export_evidence_bundle` exports the complete investigation ledger. For a firmware reconstruction workflow, the missing operation is a stable batch projection joining those facts for a selected set of functions or address ranges. Today a caller must issue and reconcile many provider-specific requests or maintain custom Ghidra Java exporters. That makes it harder to preserve exact instruction bytes, function spans, delay-slot ownership, low/raw P-code, references, CFG edges, and unresolved computed transfers under one artifact identity and coverage declaration. This arose while validating SuperH delay-slot literal recovery and building a source-owned SH-4 conformance corpus. The first fixture is a synthetic CC0 160-byte image containing ten literal-loaded tail thunks. Its expected manifest records exact instructions, delay-slot ownership, P-code invariants, references, CFG edges, and pseudocode invariants. No private target bytes are needed for the proposed contract or its verification. ### Expected interaction with targets - [x] Read existing files or captured data Static provider analysis only. No target execution, process attachment, instrumentation, memory/register changes, configuration writes, or network access should be implied by this operation. ### Boundary details - Caller selects exact procedures, addresses, ranges, or a bounded query result. - Output remains bound to the target digest, analysis profile, provider identity/version, language/compiler specification, and any load-image attestation. - Provider-native facts retain provenance; unavailable facts are null/unknown rather than synthesized. - Function bodies may be non-contiguous, so spans should be address ranges plus total bytes rather than only `[entry, entry + length)`. - Delay-slot ownership should be explicit where the provider exposes it; omission must mean unavailable, not false. - Low/raw instruction P-code and decompiler high P-code are distinct facets and must not be conflated. - Static references and provider-resolved computed targets do not establish runtime reachability. - Cancellation, truncation, per-item failure, omitted counts, and unresolved transfers remain visible. ### Options and tradeoffs 1. Add a new operation such as `export_native_machine_evidence` that returns or retains a normalized batch artifact. This is easiest for callers but adds a public persisted contract. 2. Add a native batch view over retained Evidence. This reuses the current ledger/view model but still needs a producer capable of collecting the selected instruction-level facts without one MCP round trip per address. 3. Extend `analyze_function` with optional exact instruction/P-code/delay-slot facets. This is smaller, but batching and provider-neutral export would remain caller-owned. A possible normalized record per function would include: - canonical identity, classification, non-contiguous body ranges, total bytes; - exact ordered instructions: address, bytes, mnemonic/operands, decoder context, delay-slot owner/owned slot; - raw instruction P-code with operation order and address-space identity; - typed incoming/outgoing references and unresolved computed calls/jumps; - CFG blocks and edges, including delayed-transfer semantics without inventing runtime paths; - optional decompiler pseudocode/high-P-code as separately provenance-labeled facets; - per-facet availability, completeness, truncation, limitations, unknowns, and digest. ### Verification available so far I have a prototype fixture and observed results. ### Success criteria and open questions - The same source-owned miniature binary can be exported through Ghidra and any future capable provider into one normalized schema. - Exact bytes, instruction ordering, references, CFG edges, unresolved transfers, and delay-slot ownership can be asserted without parsing provider display text. - Partial provider support is truthful at the facet level; unsupported fields do not reject otherwise useful exports. - Batch output is deterministic, bounded, pageable/retainable, and bound to exact target/profile identities. - A round trip through retained Evidence or a portable bundle preserves the normalized artifact exactly. - It remains open whether raw P-code should be mandatory for Ghidra, an optional provider extension, or a separate linked facet. ### References - Existing native contracts: `docs/native-investigation.md`, `docs/ghidra-provider.md`, `src/domain/native/nativeInstruction.ts`, and `src/ghidra/GhidraFunctionValues.ts`. - Ghidra SuperH delay-slot issue: https://github.com/NationalSecurityAgency/ghidra/issues/9589 - Raw SH-4 admission implementation: https://github.com/morluto/rea/pull/4678
Author
Owner

@Vinay-patle commented on GitHub (Oct 18, 2026):

Solution Summary

This change adds a provider-neutral, batch-oriented native machine-evidence export contract, export_native_machine_evidence. It joins exact function and instruction facts (bytes, ordering, delay-slot ownership, references, CFG edges, unresolved transfers, and optional raw P-code) for a caller-selected set of functions or address ranges into one normalized artifact. The artifact is static-analysis only and is bound to the target digest, analysis profile, provider identity/version, language/compiler specification, and any load-image attestation.

Callers no longer need to issue and reconcile many provider-specific requests, or maintain custom Ghidra Java exporters, to reconstruct firmware functions or run conformance tests.

Closes #5117

What Was Done

  • Chose Option 1 from the design discussion: a new operation rather than extending analyze_function (which leaves batching with the caller) or a view over retained Evidence (which still needs a batch producer).
  • Defined a normalized per-function record with per-facet availability, so partial provider support yields a truthful export instead of a rejection.
  • Implemented a single-pass batch collector in the Ghidra provider.
  • Added deterministic ordering, bounds, and retention so the artifact round-trips through Evidence and the portable bundle.
  • Added verification against the synthetic CC0 160-byte SH-4 fixture (ten literal-loaded tail thunks) and its expected manifest.

Key Changes

  1. New schema and contract (src/domain/native/): Adds the NativeMachineEvidenceExport artifact with schemaVersion, a binding block (target digest, analysis profile, provider id/version, language and compiler spec, load-image attestation), a selection, a coverage summary, address-sorted functions, and a canonical-JSON digest.

  2. Per-facet status model: Every facet (instructions, cfg, references, unresolvedTransfers, rawPcode, decompiler) carries a status of available, unavailable, truncated, or failed, plus omittedCount, limitations, and provenance. Unavailable data is null, never synthesized, and omission never means "false".

  3. Non-contiguous function bodies: Function spans are recorded as a list of address ranges plus totalBytes, instead of assuming [entry, entry + length).

  4. Explicit delay-slot ownership: Each instruction records delaySlot as an owner/owned pair with its partner address. null means the provider did not expose it, not that there is no delay slot. CFG edges represent delayed-transfer semantics without inventing runtime paths.

  5. Raw P-code as a separate linked facet: Low/raw instruction P-code (with operation order and address-space identity) is distinct from decompiler pseudocode and high P-code, and the two are never conflated. Raw P-code is optional for providers, which resolves the open question in the issue.

  6. Ghidra batch producer: Collects instruction bytes, mnemonics/operands, decoder context, flow, references, CFG, and delay-slot data for all selected functions in one pass, avoiding one MCP round trip per address.

  7. Determinism and bounds: Output is sorted by address and capped by function, instruction, and byte limits. Truncation, cancellation, per-item failures, omitted counts, and unresolved computed transfers are all reported in coverage and per-function error fields rather than aborting the export.

  8. Retention and portability: The artifact is stored as Evidence, supports paging, and is included in export_evidence_bundle. A round trip through retained Evidence or the bundle preserves it byte for byte.

  9. Safety guarantees: The operation performs static provider analysis only: no target execution, process attachment, instrumentation, memory or register changes, configuration writes, or network access. References and provider-resolved computed targets do not establish runtime reachability.

  10. Tests and fixtures: Adds tests that assert exact instruction bytes and order, delay-slot ownership, CFG edges, references, and P-code invariants from structured fields only (never provider display text). Also covers digest stability across repeated runs, byte-identical round trips, a partial-support stub provider, and truncation, cancellation, and failing-function cases.

  11. Documentation: Updates docs/native-investigation.md and docs/ghidra-provider.md to describe the contract, facet semantics, bounds, and static-only guarantee.

Verification

  • The CC0 SH-4 fixture exports through Ghidra into the normalized schema and matches its expected manifest.
  • Running the same export twice yields an identical digest.
  • Retained Evidence and bundle round trips are byte-identical.
  • A stub provider supporting only some facets still produces a valid export with truthful per-facet status.

Notes

  • No private target bytes, credentials, or sensitive data are required for the contract or its verification.
  • Future capable providers can emit the same schema, so the fixture can be exported through multiple providers and compared.
<!-- gh-comment-id:6255753225 --> @Vinay-patle commented on GitHub (Oct 18, 2026): ## Solution Summary This change adds a provider-neutral, batch-oriented native machine-evidence export contract, `export_native_machine_evidence`. It joins exact function and instruction facts (bytes, ordering, delay-slot ownership, references, CFG edges, unresolved transfers, and optional raw P-code) for a caller-selected set of functions or address ranges into one normalized artifact. The artifact is static-analysis only and is bound to the target digest, analysis profile, provider identity/version, language/compiler specification, and any load-image attestation. Callers no longer need to issue and reconcile many provider-specific requests, or maintain custom Ghidra Java exporters, to reconstruct firmware functions or run conformance tests. ## Related Issue Closes #5117 ## What Was Done - Chose Option 1 from the design discussion: a new operation rather than extending `analyze_function` (which leaves batching with the caller) or a view over retained Evidence (which still needs a batch producer). - Defined a normalized per-function record with per-facet availability, so partial provider support yields a truthful export instead of a rejection. - Implemented a single-pass batch collector in the Ghidra provider. - Added deterministic ordering, bounds, and retention so the artifact round-trips through Evidence and the portable bundle. - Added verification against the synthetic CC0 160-byte SH-4 fixture (ten literal-loaded tail thunks) and its expected manifest. ## Key Changes 1. **New schema and contract (`src/domain/native/`)**: Adds the `NativeMachineEvidenceExport` artifact with `schemaVersion`, a `binding` block (target digest, analysis profile, provider id/version, language and compiler spec, load-image attestation), a `selection`, a `coverage` summary, address-sorted `functions`, and a canonical-JSON `digest`. 2. **Per-facet status model**: Every facet (`instructions`, `cfg`, `references`, `unresolvedTransfers`, `rawPcode`, `decompiler`) carries a status of `available`, `unavailable`, `truncated`, or `failed`, plus `omittedCount`, `limitations`, and provenance. Unavailable data is `null`, never synthesized, and omission never means "false". 3. **Non-contiguous function bodies**: Function spans are recorded as a list of address ranges plus `totalBytes`, instead of assuming `[entry, entry + length)`. 4. **Explicit delay-slot ownership**: Each instruction records `delaySlot` as an owner/owned pair with its partner address. `null` means the provider did not expose it, not that there is no delay slot. CFG edges represent delayed-transfer semantics without inventing runtime paths. 5. **Raw P-code as a separate linked facet**: Low/raw instruction P-code (with operation order and address-space identity) is distinct from decompiler pseudocode and high P-code, and the two are never conflated. Raw P-code is optional for providers, which resolves the open question in the issue. 6. **Ghidra batch producer**: Collects instruction bytes, mnemonics/operands, decoder context, flow, references, CFG, and delay-slot data for all selected functions in one pass, avoiding one MCP round trip per address. 7. **Determinism and bounds**: Output is sorted by address and capped by function, instruction, and byte limits. Truncation, cancellation, per-item failures, omitted counts, and unresolved computed transfers are all reported in `coverage` and per-function `error` fields rather than aborting the export. 8. **Retention and portability**: The artifact is stored as Evidence, supports paging, and is included in `export_evidence_bundle`. A round trip through retained Evidence or the bundle preserves it byte for byte. 9. **Safety guarantees**: The operation performs static provider analysis only: no target execution, process attachment, instrumentation, memory or register changes, configuration writes, or network access. References and provider-resolved computed targets do not establish runtime reachability. 10. **Tests and fixtures**: Adds tests that assert exact instruction bytes and order, delay-slot ownership, CFG edges, references, and P-code invariants from structured fields only (never provider display text). Also covers digest stability across repeated runs, byte-identical round trips, a partial-support stub provider, and truncation, cancellation, and failing-function cases. 11. **Documentation**: Updates `docs/native-investigation.md` and `docs/ghidra-provider.md` to describe the contract, facet semantics, bounds, and static-only guarantee. ## Verification - The CC0 SH-4 fixture exports through Ghidra into the normalized schema and matches its expected manifest. - Running the same export twice yields an identical digest. - Retained Evidence and bundle round trips are byte-identical. - A stub provider supporting only some facets still produces a valid export with truthful per-facet status. ## Notes - No private target bytes, credentials, or sensitive data are required for the contract or its verification. - Future capable providers can emit the same schema, so the fixture can be exported through multiple providers and compared.
Author
Owner

@XinwangTao commented on GitHub (Oct 19, 2026):

I think this design direction is right. The join you're describing (function spans + exact bytes + delay-slot ownership + raw P-code + CFG/references in one stable projection) is exactly what makes conformance corpora reproducible — today's per-provider reconciliation is both error-prone and hard to audit.

Two things I'd ask the contract to nail down before implementation: 1) define an explicit schema version field and a cursor/paging model, because large firmware batches will otherwise blow up a single response and force callers to re-request; 2) decide the failure semantics — should a batch export be all-or-nothing, or may it return partial results with per-item error markers? For reconstruction pipelines, partial-with-markers is often more useful, but it needs to be explicit rather than accidental.

<!-- gh-comment-id:6260077453 --> @XinwangTao commented on GitHub (Oct 19, 2026): I think this design direction is right. The join you're describing (function spans + exact bytes + delay-slot ownership + raw P-code + CFG/references in one stable projection) is exactly what makes conformance corpora reproducible — today's per-provider reconciliation is both error-prone and hard to audit. Two things I'd ask the contract to nail down before implementation: 1) define an explicit schema version field and a cursor/paging model, because large firmware batches will otherwise blow up a single response and force callers to re-request; 2) decide the failure semantics — should a batch export be all-or-nothing, or may it return partial results with per-item error markers? For reconstruction pipelines, partial-with-markers is often more useful, but it needs to be explicit rather than accidental.
Author
Owner

@Vinay-patle commented on GitHub (Oct 26, 2026):

Thanks for the review. Both points are now decided in the contract.

1. Schema version and cursor/paging model

Schema version

  • Every export and every page carries an integer schemaVersion, starting at 1.
  • Adding optional fields or new facet kinds does not change the version. Removing a field or changing its meaning does.
  • Consumers must reject an unknown major schemaVersion and must ignore unknown optional fields.

Paging

  • An export is a retained snapshot with a stable exportId. Pages are slices of that snapshot, so large firmware batches are never re-collected or re-requested.
  • Functions are ordered by entry address. The request takes a limit, which is capped by server-side maximums on functions, instructions, and bytes per page.
  • Each response includes page (index and function count) and nextCursor, which is null on the last page.
  • The cursor is opaque. It encodes the exportId, the binding digest, and a position (function index, facet, offset).
  • A cursor used against a different exportId or binding returns cursor_stale instead of silently returning mismatched data.
  • A single function whose facet exceeds the page cap continues across pages through the same cursor. It is marked truncated with omittedCount until the final slice.
  • The artifact digest covers the whole snapshot. Each page also carries its own digest, so callers can verify pages as they arrive and the reassembled result matches the full digest.
{
  "schemaVersion": 1,
  "exportId": "exp_...",
  "page": { "index": 0, "functionCount": 25 },
  "nextCursor": "opaque-token-or-null",
  "outcome": "partial",
  "coverage": { "requested": 200, "exported": 190, "failed": 8, "notAttempted": 2, "truncated": false, "cancelled": false }
}

2. Failure semantics

Partial results with explicit per-item markers is the default behavior. It is declared in the contract, not left to chance.

  • Whole-request failures fail the call with no artifact: unknown target digest, binding mismatch, provider unavailable, or malformed selection.
  • Per-function failures return a function record with error: { code, message, retryable }. The rest of the batch is still returned.
  • Per-facet failures set status: "failed" and data: null on that facet only. Other facets on the same function remain usable.
  • Top-level outcome is complete, partial, or failed. coverage reports requested, exported, failed, not-attempted, and truncated counts.
  • Cancellation returns outcome: "partial" with cancelled: true, the not-attempted count, and a cursor to resume.
  • Strict mode (strict: true) is an opt-in all-or-nothing option. Any per-function or per-facet failure fails the whole request and no artifact is retained.
  • Retry: a caller can re-request only the failed function ids. The retry is a new export with its own exportId, linked to the original so the audit trail shows what was recovered.
  • Failure markers are part of the digest, so a partial export is reproducible and auditable like a complete one.

Tests covering these decisions

  • Paging a large synthetic batch with a small limit and reassembling the pages reproduces the full-snapshot digest.
  • A stale or foreign cursor returns cursor_stale.
  • Default mode returns partial with per-item error markers for an injected failing function. strict: true fails the whole request with no retained artifact.
  • Cancelling mid-batch returns partial with cancelled: true and a resumable cursor.
  • An unknown major schemaVersion is rejected, and unknown optional fields are ignored.
<!-- gh-comment-id:6412331680 --> @Vinay-patle commented on GitHub (Oct 26, 2026): Thanks for the review. Both points are now decided in the contract. ## 1. Schema version and cursor/paging model **Schema version** - Every export and every page carries an integer `schemaVersion`, starting at `1`. - Adding optional fields or new facet kinds does not change the version. Removing a field or changing its meaning does. - Consumers must reject an unknown major `schemaVersion` and must ignore unknown optional fields. **Paging** - An export is a retained snapshot with a stable `exportId`. Pages are slices of that snapshot, so large firmware batches are never re-collected or re-requested. - Functions are ordered by entry address. The request takes a `limit`, which is capped by server-side maximums on functions, instructions, and bytes per page. - Each response includes `page` (index and function count) and `nextCursor`, which is `null` on the last page. - The cursor is opaque. It encodes the `exportId`, the binding digest, and a position (function index, facet, offset). - A cursor used against a different `exportId` or binding returns `cursor_stale` instead of silently returning mismatched data. - A single function whose facet exceeds the page cap continues across pages through the same cursor. It is marked `truncated` with `omittedCount` until the final slice. - The artifact `digest` covers the whole snapshot. Each page also carries its own digest, so callers can verify pages as they arrive and the reassembled result matches the full digest. ```jsonc { "schemaVersion": 1, "exportId": "exp_...", "page": { "index": 0, "functionCount": 25 }, "nextCursor": "opaque-token-or-null", "outcome": "partial", "coverage": { "requested": 200, "exported": 190, "failed": 8, "notAttempted": 2, "truncated": false, "cancelled": false } } ``` ## 2. Failure semantics Partial results with explicit per-item markers is the default behavior. It is declared in the contract, not left to chance. - **Whole-request failures** fail the call with no artifact: unknown target digest, binding mismatch, provider unavailable, or malformed selection. - **Per-function failures** return a function record with `error: { code, message, retryable }`. The rest of the batch is still returned. - **Per-facet failures** set `status: "failed"` and `data: null` on that facet only. Other facets on the same function remain usable. - **Top-level `outcome`** is `complete`, `partial`, or `failed`. `coverage` reports requested, exported, failed, not-attempted, and truncated counts. - **Cancellation** returns `outcome: "partial"` with `cancelled: true`, the not-attempted count, and a cursor to resume. - **Strict mode** (`strict: true`) is an opt-in all-or-nothing option. Any per-function or per-facet failure fails the whole request and no artifact is retained. - **Retry**: a caller can re-request only the failed function ids. The retry is a new export with its own `exportId`, linked to the original so the audit trail shows what was recovered. - Failure markers are part of the digest, so a partial export is reproducible and auditable like a complete one. ## Tests covering these decisions - Paging a large synthetic batch with a small `limit` and reassembling the pages reproduces the full-snapshot digest. - A stale or foreign cursor returns `cursor_stale`. - Default mode returns `partial` with per-item error markers for an injected failing function. `strict: true` fails the whole request with no retained artifact. - Cancelling mid-batch returns `partial` with `cancelled: true` and a resumable cursor. - An unknown major `schemaVersion` is rejected, and unknown optional fields are ignored. -
Author
Owner

@XinwangTao commented on GitHub (Oct 27, 2026):

Both points landed exactly the way the reconstruction pipeline needs. The retained-snapshot paging model with a per-page digest alongside the whole-snapshot digest is the right shape — callers can verify incrementally and still prove the reassembled artifact matches the exportId binding. Partial-with-markers as the declared default, with per-facet failure isolation, keeps a large firmware batch usable instead of all-or-nothing. One implementation note: since the cursor encodes the binding digest, make sure a cursor whose snapshot has been evicted/regenerated server-side also resolves to cursor_stale (rather than silently re-serving slices from a different snapshot) — the opaque cursor already makes that cheap to detect, and it closes the last way a stale cursor could yield mismatched data.

<!-- gh-comment-id:6431401146 --> @XinwangTao commented on GitHub (Oct 27, 2026): Both points landed exactly the way the reconstruction pipeline needs. The retained-snapshot paging model with a per-page digest alongside the whole-snapshot digest is the right shape — callers can verify incrementally and still prove the reassembled artifact matches the exportId binding. Partial-with-markers as the declared default, with per-facet failure isolation, keeps a large firmware batch usable instead of all-or-nothing. One implementation note: since the cursor encodes the binding digest, make sure a cursor whose snapshot has been evicted/regenerated server-side also resolves to cursor_stale (rather than silently re-serving slices from a different snapshot) — the opaque cursor already makes that cheap to detect, and it closes the last way a stale cursor could yield mismatched data.
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#3152
No description provided.