[GH-ISSUE #7574] [Bug] Environment coverage asks for reads already captured when a literal DELETE has no modelled target #4514

Closed
opened 2026-10-31 00:50:25 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 27, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/7574

Before submitting

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

Area

MCP or agent integration

Observed behavior

node scripts/rea.mjs environment-build "$d/capture.json" "$d/bundle" --json returns a withheld-write hint saying the capture does not read the collection or item changed by DELETE /api/folders/f1. Its advice is to add that read. The capture already contains both reads before the delete and both reads after it: the item changes from a successful response to 404, and the collection changes from one entity to an empty array.

The separate inspect-analysis-view CLI projection recognizes the initial collection read as a list view and the initial same-path read as a document view. The missing mutation target comes from the unsupported literal route, rather than an absence of recordings of those URLs. This report concerns the explanation and recording advice. Withholding this literal DELETE follows the documented mutation model.

Reproduction

  1. Use the baseline below with its built runtime and locked dependencies, Node v24.22.1 on PATH, and TMPDIR pointing to an existing scratch directory outside the checkout. From the checkout root, run:
set -eu
d=$(mktemp -d "${TMPDIR%/}/rea-verify.XXXXXX")
export HOME="$d/home" XDG_CONFIG_HOME="$d/config" XDG_DATA_HOME="$d/data"
export XDG_CACHE_HOME="$d/cache" XDG_STATE_HOME="$d/state" TMPDIR="$d/tmp"
mkdir -p "$HOME" "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_CACHE_HOME" "$XDG_STATE_HOME" "$TMPDIR"
epoch=$(TZ=America/Los_Angeles date +%s)
node - "$d/capture.har" "$epoch" <<'JS'
const fs = require('node:fs');
const rows = [
  ['GET', '/api/folders', 200, [{uid:'f1', title:'General'}]],
  ['GET', '/api/folders/f1', 200, {uid:'f1', title:'General'}],
  ['DELETE', '/api/folders/f1', 204, undefined],
  ['GET', '/api/folders/f1', 404, {message:'not found'}],
  ['GET', '/api/folders', 200, []],
];
const entries = rows.map(([method, path, status, body], i) => {
  const text = body === undefined ? undefined : JSON.stringify(body);
  return {
    startedDateTime: new Date((Number(process.argv[3])+i)*1000).toISOString(), time:5,
    request:{method, url:'http://127.0.0.1:5230'+path, httpVersion:'HTTP/1.1',
      cookies:[], headers:[], queryString:[], headersSize:-1, bodySize:0},
    response:{status, statusText:'fixture', httpVersion:'HTTP/1.1', cookies:[],
      headers:[{name:'Content-Type',value:'application/json'}],
      content:{size:text?.length ?? 0, mimeType:'application/json', ...(text === undefined ? {} : {text})},
      redirectURL:'', headersSize:-1, bodySize:-1},
    cache:{}, timings:{send:0, wait:5, receive:0},
  };
});
fs.writeFileSync(process.argv[2], JSON.stringify({log:{version:'1.2',
  creator:{name:'fixture',version:'1'}, entries}}));
JS
node scripts/rea.mjs inspect-web-network-capture "$d/capture.har" har --format json > "$d/capture.json"
node scripts/rea.mjs environment-build "$d/capture.json" "$d/bundle" --json > "$d/build.json"
node - "$d" <<'JS'
const fs = require('node:fs');
const d = process.argv[2];
fs.writeFileSync(d+'/state-input.json', JSON.stringify({
  source:{kind:'evidence-file',path:d+'/capture.json'},
  view:{kind:'environment-state',template_rules:[
    'after-uid-literal','opaque-token','sibling-variance','prefix-variance']}
}));
console.log(JSON.stringify(JSON.parse(fs.readFileSync(d+'/build.json')).coverage.writes,null,2));
JS
node scripts/rea.mjs inspect-analysis-view "$d/state-input.json" --format json > "$d/state.json"
node - "$d/state.json" <<'JS'
const fs = require('node:fs');
const state = JSON.parse(fs.readFileSync(process.argv[2])).normalized_result;
console.log(JSON.stringify(state.views.map(({tool,shape,checked_record_ordinals}) =>
  ({tool,shape,checked_record_ordinals})),null,2));
JS
printf '%s\n' "$d"
  1. Observe coverage.writes.withheld[0].hint, then the two recognized read views printed by the same script. The capture has only one literal item identifier, so the default build template rules leave f1 literal.

The hint appeared in three successful CLI build executions across two independently constructed HAR fixtures; the reduced shell fixture above was executed twice. The retained final execution used an explicitly selected scratch directory. These commands inspect synthetic files; the loopback URL does not require a running application.

Expected behavior

Withheld-write hints are documented as guidance about what to record next. When the requested reads are already in the capture and a literal route cannot be modelled as an entity delete, the hint should describe the unrecognized mutation target or unsupported route form. It should not claim that the recording lacks the reads or direct the caller to obtain the reads already shown.

The existing no-state-target reason code can remain: it correctly describes the absence of a recognized mutation target. This expectation does not require literal-ID inference or enabling the DELETE tool.

Impact and scope

P3: the caller receives misleading recording advice for this five-record capture. The verification establishes an inaccurate explanation; it does not establish a change in served behavior, data loss, or a failed supported mutation. The capture and its read views remain available. Other literal-path write methods were not exercised, and prevalence across real application captures was not measured.

REA version

Exact node scripts/rea.mjs --version output:

6.8.0

Source commit: 65f1c447344a423fa2785847dbcea1e9a9e2454a.

Runtime and platform

Node v24.22.1; macOS 27.0.1; Darwin arm64. Built-in HAR decoder only; no external analysis provider or live application was used.

Target and artifact context

A synthetic five-entry HAR: list one folder, read it, delete it, read its 404 response, and list the now-empty collection. The fixtures contain no credentials.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

The build command in the reproduction printed:

{
  "served": [],
  "withheld": [{
    "tool": "delete_folders_f1",
    "effect": "none",
    "reason": "no-state-target",
    "hint": "The write's path names no collection or item the capture reads. Read the collection or item it changes.",
    "exemplar_ordinal": null,
    "contradicted_by": null
  }]
}

The state-view command printed:

[
  {"tool":"get_folders","shape":"list","checked_record_ordinals":[0]},
  {"tool":"get_folders_f1","shape":"document","checked_record_ordinals":[1]}
]

At the stated baseline:

  • docs/agent-environments.md:172-177 promises hints about what to record next and publishes this hint.
  • src/domain/analysisView/environmentCoverageView.ts:29-32 supplies that fixed text for every no-state-target result.
  • docs/web-network-captures.md:626-628 defines an item tool using a trailing template parameter; :730-737 assigns unsupported write forms effect: none with no-state-target.
  • docs/specs/agent-environments/state-targets/verification.md:93-98 explicitly defers templating literal IDs by value. This supports withholding the literal DELETE; it does not make the hint's assertion about absent reads true.

Typed outcome or recovery expected

Retain the withheld write and its no-state-target reason, but explain that no supported mutation target was inferred. Any suggested recording step should distinguish a missing read from a read whose route the current model does not recognize as an item.

Analysis or suspected cause

Source-derived: src/domain/analysisView/environmentStateWriteRules.ts:309-332 recognizes entity DELETE through a trailing parameter and document writes only for PUT/PATCH/POST. The literal DELETE therefore reaches the none result; src/domain/analysisView/EnvironmentStateWriteSimulation.ts:192-212 preserves no-state-target. Coverage attaches one generic hint without distinguishing missing evidence from an unsupported address form.

Additional context

Searched open/closed issues and PRs, including issue and review comments. Related merged PRs #5664 and #6385 discuss the literal-route limitation, while #5600 defines the write gate; none identified the inaccurate hint as its reported defect. Issue #7387 concerns omitted HEAD/OPTIONS read counts and #7388 concerns a prefix-variance segment limit, with different closure conditions.

Triage assessment

  • Impact level: P3
  • Assessment status: supported
  • Impact basis: The verified defect is inaccurate recording advice. The unavailable literal DELETE follows the documented restriction and is not counted as additional defect impact.
  • Workaround status: available
  • Workaround basis: The caller can inspect the state view and documented route requirements to identify that reads exist but the literal route has no supported mutation target. This bypasses the misleading explanation without changing runtime behavior.
Originally created by @coygeek on GitHub (Oct 27, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7574 ### 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 MCP or agent integration ### Observed behavior `node scripts/rea.mjs environment-build "$d/capture.json" "$d/bundle" --json` returns a withheld-write hint saying the capture does not read the collection or item changed by `DELETE /api/folders/f1`. Its advice is to add that read. The capture already contains both reads before the delete and both reads after it: the item changes from a successful response to 404, and the collection changes from one entity to an empty array. The separate `inspect-analysis-view` CLI projection recognizes the initial collection read as a list view and the initial same-path read as a document view. The missing mutation target comes from the unsupported literal route, rather than an absence of recordings of those URLs. This report concerns the explanation and recording advice. Withholding this literal DELETE follows the documented mutation model. ### Reproduction 1. Use the baseline below with its built runtime and locked dependencies, Node v24.22.1 on PATH, and TMPDIR pointing to an existing scratch directory outside the checkout. From the checkout root, run: ```sh set -eu d=$(mktemp -d "${TMPDIR%/}/rea-verify.XXXXXX") export HOME="$d/home" XDG_CONFIG_HOME="$d/config" XDG_DATA_HOME="$d/data" export XDG_CACHE_HOME="$d/cache" XDG_STATE_HOME="$d/state" TMPDIR="$d/tmp" mkdir -p "$HOME" "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_CACHE_HOME" "$XDG_STATE_HOME" "$TMPDIR" epoch=$(TZ=America/Los_Angeles date +%s) node - "$d/capture.har" "$epoch" <<'JS' const fs = require('node:fs'); const rows = [ ['GET', '/api/folders', 200, [{uid:'f1', title:'General'}]], ['GET', '/api/folders/f1', 200, {uid:'f1', title:'General'}], ['DELETE', '/api/folders/f1', 204, undefined], ['GET', '/api/folders/f1', 404, {message:'not found'}], ['GET', '/api/folders', 200, []], ]; const entries = rows.map(([method, path, status, body], i) => { const text = body === undefined ? undefined : JSON.stringify(body); return { startedDateTime: new Date((Number(process.argv[3])+i)*1000).toISOString(), time:5, request:{method, url:'http://127.0.0.1:5230'+path, httpVersion:'HTTP/1.1', cookies:[], headers:[], queryString:[], headersSize:-1, bodySize:0}, response:{status, statusText:'fixture', httpVersion:'HTTP/1.1', cookies:[], headers:[{name:'Content-Type',value:'application/json'}], content:{size:text?.length ?? 0, mimeType:'application/json', ...(text === undefined ? {} : {text})}, redirectURL:'', headersSize:-1, bodySize:-1}, cache:{}, timings:{send:0, wait:5, receive:0}, }; }); fs.writeFileSync(process.argv[2], JSON.stringify({log:{version:'1.2', creator:{name:'fixture',version:'1'}, entries}})); JS node scripts/rea.mjs inspect-web-network-capture "$d/capture.har" har --format json > "$d/capture.json" node scripts/rea.mjs environment-build "$d/capture.json" "$d/bundle" --json > "$d/build.json" node - "$d" <<'JS' const fs = require('node:fs'); const d = process.argv[2]; fs.writeFileSync(d+'/state-input.json', JSON.stringify({ source:{kind:'evidence-file',path:d+'/capture.json'}, view:{kind:'environment-state',template_rules:[ 'after-uid-literal','opaque-token','sibling-variance','prefix-variance']} })); console.log(JSON.stringify(JSON.parse(fs.readFileSync(d+'/build.json')).coverage.writes,null,2)); JS node scripts/rea.mjs inspect-analysis-view "$d/state-input.json" --format json > "$d/state.json" node - "$d/state.json" <<'JS' const fs = require('node:fs'); const state = JSON.parse(fs.readFileSync(process.argv[2])).normalized_result; console.log(JSON.stringify(state.views.map(({tool,shape,checked_record_ordinals}) => ({tool,shape,checked_record_ordinals})),null,2)); JS printf '%s\n' "$d" ``` 2. Observe `coverage.writes.withheld[0].hint`, then the two recognized read views printed by the same script. The capture has only one literal item identifier, so the default build template rules leave `f1` literal. The hint appeared in three successful CLI build executions across two independently constructed HAR fixtures; the reduced shell fixture above was executed twice. The retained final execution used an explicitly selected scratch directory. These commands inspect synthetic files; the loopback URL does not require a running application. ### Expected behavior Withheld-write hints are documented as guidance about what to record next. When the requested reads are already in the capture and a literal route cannot be modelled as an entity delete, the hint should describe the unrecognized mutation target or unsupported route form. It should not claim that the recording lacks the reads or direct the caller to obtain the reads already shown. The existing `no-state-target` reason code can remain: it correctly describes the absence of a recognized mutation target. This expectation does not require literal-ID inference or enabling the DELETE tool. ### Impact and scope P3: the caller receives misleading recording advice for this five-record capture. The verification establishes an inaccurate explanation; it does not establish a change in served behavior, data loss, or a failed supported mutation. The capture and its read views remain available. Other literal-path write methods were not exercised, and prevalence across real application captures was not measured. ### REA version Exact `node scripts/rea.mjs --version` output: ```text 6.8.0 ``` Source commit: `65f1c447344a423fa2785847dbcea1e9a9e2454a`. ### Runtime and platform Node v24.22.1; macOS 27.0.1; Darwin arm64. Built-in HAR decoder only; no external analysis provider or live application was used. ### Target and artifact context A synthetic five-entry HAR: list one folder, read it, delete it, read its 404 response, and list the now-empty collection. The fixtures contain no credentials. ### Interface CLI ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence The build command in the reproduction printed: ```json { "served": [], "withheld": [{ "tool": "delete_folders_f1", "effect": "none", "reason": "no-state-target", "hint": "The write's path names no collection or item the capture reads. Read the collection or item it changes.", "exemplar_ordinal": null, "contradicted_by": null }] } ``` The state-view command printed: ```json [ {"tool":"get_folders","shape":"list","checked_record_ordinals":[0]}, {"tool":"get_folders_f1","shape":"document","checked_record_ordinals":[1]} ] ``` At the stated baseline: - `docs/agent-environments.md:172-177` promises hints about what to record next and publishes this hint. - `src/domain/analysisView/environmentCoverageView.ts:29-32` supplies that fixed text for every `no-state-target` result. - `docs/web-network-captures.md:626-628` defines an item tool using a trailing template parameter; `:730-737` assigns unsupported write forms `effect: none` with `no-state-target`. - `docs/specs/agent-environments/state-targets/verification.md:93-98` explicitly defers templating literal IDs by value. This supports withholding the literal DELETE; it does not make the hint's assertion about absent reads true. ### Typed outcome or recovery expected Retain the withheld write and its `no-state-target` reason, but explain that no supported mutation target was inferred. Any suggested recording step should distinguish a missing read from a read whose route the current model does not recognize as an item. ### Analysis or suspected cause Source-derived: `src/domain/analysisView/environmentStateWriteRules.ts:309-332` recognizes entity DELETE through a trailing parameter and document writes only for PUT/PATCH/POST. The literal DELETE therefore reaches the `none` result; `src/domain/analysisView/EnvironmentStateWriteSimulation.ts:192-212` preserves `no-state-target`. Coverage attaches one generic hint without distinguishing missing evidence from an unsupported address form. ### Additional context Searched open/closed issues and PRs, including issue and review comments. Related merged PRs #5664 and #6385 discuss the literal-route limitation, while #5600 defines the write gate; none identified the inaccurate hint as its reported defect. Issue #7387 concerns omitted HEAD/OPTIONS read counts and #7388 concerns a prefix-variance segment limit, with different closure conditions. ## Triage assessment - Impact level: P3 - Assessment status: supported - Impact basis: The verified defect is inaccurate recording advice. The unavailable literal DELETE follows the documented restriction and is not counted as additional defect impact. - Workaround status: available - Workaround basis: The caller can inspect the state view and documented route requirements to identify that reads exist but the literal route has no supported mutation target. This bypasses the misleading explanation without changing runtime behavior.
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#4514
No description provided.