[GH-ISSUE #1723] [Bug] Contract-accepted residual questions with edge whitespace fail workflow unknown retention #578

Closed
opened 2026-10-15 18:26:22 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @N0zoM1z0 on GitHub (Oct 11, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/1723

Before submitting

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

Area

Evidence, artifacts, or reconstruction

Observed behavior

A provider-contract-accepted residual question with leading/trailing whitespace fails registration in the shared workflow path. recordWorkflowUnknowns returns UnknownRegistryError with reason invalid-transition; its cause is Residual unknown revision digest does not match. The equivalent trimmed question registers successfully. Spaces, LF/tab and U+FEFF all reproduced this behavior.

Reproduction

Build source revision below with the pinned toolchain, then run this reduced production application workflow from the repository root:

import { nativeApiBoundarySchema } from './dist/domain/native/nativeApiBoundary.js';
import { createWorkflowEvidence, recordWorkflowUnknowns } from './dist/application/WorkflowEvidence.js';
import { InvestigationRecords } from './dist/application/investigation/InvestigationRecords.js';

const records = new InvestigationRecords();
const boundary = nativeApiBoundarySchema.parse({
  available: false,
  reason: 'Synthetic provider unavailable boundary',
  residual_unknowns: ['  Which boundary?  '],
});
const result = { residual_unknowns: boundary.residual_unknowns };
const evidence = createWorkflowEvidence({
  target: undefined, operation: 'inspect_native_api', parameters: {},
  result, upstreamProfile: undefined,
});
const retained = records.recordEvidence(evidence);
if (!retained.ok) throw retained.error;
console.log(recordWorkflowUnknowns({
  name: 'inspect_native_api', result, evidenceId: evidence.evidence_id,
  recordUnknown: input => records.recordUnknown(input),
}));
console.log(records.listUnknowns());
records.clear();

Execute the snippet as an .mjs file or with node --input-type=module. Replace the question with 'Which boundary?' for the passing control, or '\nWhich boundary?\t' / '\uFEFFWhich boundary?\uFEFF' for the other failing controls.

The investigation also passed the boundary through the real projectNativeApiInspection projection before registration; it preserved the original question and produced the same failure.

Expected behavior

Normalize the registry question before deriving its stable identity and revision digest, so a valid provider result can retain its residual unknown. Preserve the caller/provider question verbatim in the original workflow Evidence. Digest authentication of arbitrary imported Unknown revisions must remain enabled.

Impact and scope

The shared workflow policy is used by inspect_native_api, trace_feature and trace_call_path. A contract-accepted residual question can cause the completed provider workflow to be presented as a registry failure. In the reduced reproducer, the original workflow Evidence remained intact, but no unknown was registered. This is not evidence that every provider currently emits such whitespace.

REA version

6.4.0 source build; commit 966dc3acde2880a0f94b2658e2a02180d505cafa

Runtime and platform

Node.js 24.18.0; Linux x64; bounded to one CPU. No real native provider required.

Target and artifact context

Synthetic native API unavailable-boundary result accepted by the production provider-neutral schema; no binary is executed.

Interface

Other — production shared application workflow; its consumers include CLI/MCP workflows.

Earliest failure stage

Artifact or evidence registration

Relevant output or evidence

Which boundary?                  accepted=true retained=true  unknowns=1
  Which boundary?                accepted=true retained=false unknowns=0
LF + Which boundary? + TAB       accepted=true retained=false unknowns=0
FEFF + Which boundary? + FEFF    accepted=true retained=false unknowns=0

UnknownRegistryError: invalid-transition
cause: at revision_digest: Residual unknown revision digest does not match

All four controls retained unchanged original workflow Evidence.

Typed outcome or recovery expected

Successful unknown retention for nonempty normalized questions; meaningful validation failure for a question that is empty after normalization. No false digest-integrity failure for whitespace around a valid question.

Analysis or suspected cause

Source-derived cause: createResidualUnknown collapses whitespace but does not trim before generating identity/digest. residualUnknownSchema trims question, then validates the digest against the changed value. recordWorkflowUnknowns passes provider strings directly, unlike MCP input schema parsing. Fix the producing representation before hashing rather than weakening digest verification or repairing imported records.

Additional context

The reproducer uses the production application, registry and native-boundary schema. It does not establish real Hopper/Ghidra/IDA behavior, live-model compatibility or Windows coverage. No related report was found in open/closed searches for unknown whitespace and digest failures.

Originally created by @N0zoM1z0 on GitHub (Oct 11, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/1723 ### 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 Evidence, artifacts, or reconstruction ### Observed behavior A provider-contract-accepted residual question with leading/trailing whitespace fails registration in the shared workflow path. `recordWorkflowUnknowns` returns `UnknownRegistryError` with reason `invalid-transition`; its cause is `Residual unknown revision digest does not match`. The equivalent trimmed question registers successfully. Spaces, LF/tab and U+FEFF all reproduced this behavior. ### Reproduction Build source revision below with the pinned toolchain, then run this reduced production application workflow from the repository root: ```js import { nativeApiBoundarySchema } from './dist/domain/native/nativeApiBoundary.js'; import { createWorkflowEvidence, recordWorkflowUnknowns } from './dist/application/WorkflowEvidence.js'; import { InvestigationRecords } from './dist/application/investigation/InvestigationRecords.js'; const records = new InvestigationRecords(); const boundary = nativeApiBoundarySchema.parse({ available: false, reason: 'Synthetic provider unavailable boundary', residual_unknowns: [' Which boundary? '], }); const result = { residual_unknowns: boundary.residual_unknowns }; const evidence = createWorkflowEvidence({ target: undefined, operation: 'inspect_native_api', parameters: {}, result, upstreamProfile: undefined, }); const retained = records.recordEvidence(evidence); if (!retained.ok) throw retained.error; console.log(recordWorkflowUnknowns({ name: 'inspect_native_api', result, evidenceId: evidence.evidence_id, recordUnknown: input => records.recordUnknown(input), })); console.log(records.listUnknowns()); records.clear(); ``` Execute the snippet as an `.mjs` file or with `node --input-type=module`. Replace the question with `'Which boundary?'` for the passing control, or `'\nWhich boundary?\t'` / `'\uFEFFWhich boundary?\uFEFF'` for the other failing controls. The investigation also passed the boundary through the real `projectNativeApiInspection` projection before registration; it preserved the original question and produced the same failure. ### Expected behavior Normalize the registry question before deriving its stable identity and revision digest, so a valid provider result can retain its residual unknown. Preserve the caller/provider question verbatim in the original workflow Evidence. Digest authentication of arbitrary imported Unknown revisions must remain enabled. ### Impact and scope The shared workflow policy is used by `inspect_native_api`, `trace_feature` and `trace_call_path`. A contract-accepted residual question can cause the completed provider workflow to be presented as a registry failure. In the reduced reproducer, the original workflow Evidence remained intact, but no unknown was registered. This is not evidence that every provider currently emits such whitespace. ### REA version 6.4.0 source build; commit `966dc3acde2880a0f94b2658e2a02180d505cafa` ### Runtime and platform Node.js 24.18.0; Linux x64; bounded to one CPU. No real native provider required. ### Target and artifact context Synthetic native API unavailable-boundary result accepted by the production provider-neutral schema; no binary is executed. ### Interface Other — production shared application workflow; its consumers include CLI/MCP workflows. ### Earliest failure stage Artifact or evidence registration ### Relevant output or evidence ```text Which boundary? accepted=true retained=true unknowns=1 Which boundary? accepted=true retained=false unknowns=0 LF + Which boundary? + TAB accepted=true retained=false unknowns=0 FEFF + Which boundary? + FEFF accepted=true retained=false unknowns=0 UnknownRegistryError: invalid-transition cause: at revision_digest: Residual unknown revision digest does not match ``` All four controls retained unchanged original workflow Evidence. ### Typed outcome or recovery expected Successful unknown retention for nonempty normalized questions; meaningful validation failure for a question that is empty after normalization. No false digest-integrity failure for whitespace around a valid question. ### Analysis or suspected cause Source-derived cause: `createResidualUnknown` collapses whitespace but does not trim before generating identity/digest. `residualUnknownSchema` trims `question`, then validates the digest against the changed value. `recordWorkflowUnknowns` passes provider strings directly, unlike MCP input schema parsing. Fix the producing representation before hashing rather than weakening digest verification or repairing imported records. ### Additional context The reproducer uses the production application, registry and native-boundary schema. It does not establish real Hopper/Ghidra/IDA behavior, live-model compatibility or Windows coverage. No related report was found in open/closed searches for unknown whitespace and digest failures.
Author
Owner

@014-code commented on GitHub (Oct 11, 2026):

I traced this through the shared workflow path. recordWorkflowUnknowns passes provider questions to the registry, and createResidualUnknown collapsed whitespace but did not trim the edges before deriving the unknown identity and revision digest. The residual-unknown schema trims the question during parsing, so digest validation compared the pre-trim digest with the trimmed value and rejected valid residual questions.

PR #1739 trims the normalized question before deriving both values. It does not weaken digest verification and leaves the original workflow Evidence unchanged. The new registry-backed tests cover spaces, LF/tab, U+FEFF, and whitespace-only input; blank questions remain rejected.

Verification passed: 6 focused tests, npm run check:fast, npm run build:cached, and a production-path reproduction using the compiled output. No real Hopper/Ghidra/IDA provider was needed or tested.

<!-- gh-comment-id:6106424338 --> @014-code commented on GitHub (Oct 11, 2026): I traced this through the shared workflow path. `recordWorkflowUnknowns` passes provider questions to the registry, and `createResidualUnknown` collapsed whitespace but did not trim the edges before deriving the unknown identity and revision digest. The residual-unknown schema trims the question during parsing, so digest validation compared the pre-trim digest with the trimmed value and rejected valid residual questions. PR #1739 trims the normalized question before deriving both values. It does not weaken digest verification and leaves the original workflow Evidence unchanged. The new registry-backed tests cover spaces, LF/tab, U+FEFF, and whitespace-only input; blank questions remain rejected. Verification passed: 6 focused tests, `npm run check:fast`, `npm run build:cached`, and a production-path reproduction using the compiled output. No real Hopper/Ghidra/IDA provider was needed or tested.
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#578
No description provided.