Files
reverse-engineering-anything/docs/specs/agent-environments/environment-build/spec.md
T
41cf869949 fix(environment): bound create learning and invalidate stale write proofs (#6929)
* feat(environment): report what an environment serves with an environment-coverage view

A new inspect_analysis_view kind over capture Evidence. It projects the
state an environment derives with the given template rules and reports
each tool as answered from state, replayed with its view reason, a served
write, or a withheld write with its reason, the records behind it and a
hint about what to record next. The hints cover every write reason, so a
new reason without one fails to compile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(environment): build an environment bundle in one command

rea environment-build <capture> [directory] inspects a HAR (or reads
capture Evidence), projects the environment manifest from the in-memory
Evidence, authenticates the pair, prepares the state and writes the bundle
environment-export writes. Every bundle file is byte-identical to the
three-step path for the same capture and options.

The report adds the capture and manifest identities, the coverage summary,
warnings (a loopback capture named after its file, credential-named body
members by pointer) and the next command. --dry-run writes nothing. The
default template rules are the four the published environments use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(environment): cover environment-build and the coverage view

Domain tests check the hint table against the state view's reasons, the
summary, and the view against the environment-state view it summarizes.
Service tests build the fixture capture and compare every file with the
three-step path, a dry run, loopback naming and the refusals. A CLI test
compares a HAR built in one step with the three CLI steps byte for byte,
and an MCP test projects the view from every source kind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(environment): build the real-agentenv lane's bundle with environment-build

The lane now runs the command users run: it builds the Grafana-shaped HAR
with environment-build and the packed checkout, checks the report, then
runs the bundle with agent-env as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(environment): document environment-build and the coverage view

The agent environments guide opens with the one-step build: the report,
the hint for each withheld write reason, and what a bundle ships. The CLI
guide, the capture guide and the skill reference name the command and the
environment-coverage view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(environment): harden environment-build after review

- The credential scan walks with its own stack, so a deeply nested body
  cannot crash the build, and it also reports credential-named header
  names, query names, form body members and string arrays.
- The build checks SIGINT between stages: cancelled before the bundle
  stage it writes nothing, during the write it names the written bundle.
- A dry run opens the package tarball, so it refuses what a build refuses.
- Repeated template rules are refused, a HAR saved as .json gets a hint,
  file-derived names follow the bundle name rules, `localhost.` counts as
  a loopback origin, and the next command is shell-quoted.
- --capture-timeout-ms passes through to the HAR inspection, and a
  missing directory is refused before inspection.
- The no-observation hint covers updates and deletes of entities the state
  never held; the coverage view states that it does not apply the
  serve-time admission checks; the inspect_analysis_view description
  names the view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(environment): state the build's conditions and record its verification

The guides now state when the one-step bundle equals the three-step one,
which headers inspection excludes, what the credential warning scans, how
cancellation behaves, and that the coverage view does not apply the
serve-time admission checks. The spec folder records the census, the end
to end runs, the gates and the review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(environment): dispatch a pending interrupt before each build stage check

The manifest, state and coverage stages run synchronously, so a SIGINT
that arrived during them was only dispatched once the bundle write had
begun. Each check now yields first, so an interrupt before the bundle
stage cancels the build with nothing written.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(environment): scan scenario credentials, own the dry-run tarball and serialize Evidence once

A browser scenario's retained header values and the query parameters of its recorded URLs are scanned for credential
names as a HAR's are, through a review projection of its records. A dry run admits and releases the package tarball
through the export's regular-file scope, so a close it cannot confirm keeps its owner, and checks for cancellation
after that last await. Evidence is written into one exactly sized buffer instead of chunks joined by a copy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(environment): record the review round's checks

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* style(environment): format the build spec

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(environment): scan every form occurrence and MIME-less scenario bodies

The build's credential scan collapsed form bodies with Object.fromEntries, so a
repeated field kept only its last occurrence: `api_key=secret&api_key=` warned
about nothing although the Evidence ships the value, and repeated values were
undercounted. Form fields are now scanned as ordered name/value pairs, as
headers and query strings already are.

The review projection of a capture_browser_scenario dropped a request body
recorded without a media type, so the scan never saw it. Review keeps such a
body's text with an empty media type; the manifest projection still reads only
bodies it can classify.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(environment): scan structured HAR form params and the request side of unattributed scenario transactions

A HAR request recorded with postData.params and no text is scanned by those parameters, each occurrence counting, and
the review projection keeps the request side of a scenario transaction whose response cannot be attributed, so the
credential warning covers what evidence.json ships in both cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(environment): validate build paths and read dry-run tarballs

* fix(environment): report bodies too large for the credential scan

Text bodies over the scan's 4 MiB limit, including a response decoded only as a prefix, are reported as a
credential-scan-incomplete warning by record and side, never by content, so an absent credential-named-members
warning no longer reads as a complete check. The spec and agent-environments guide also state the path validation and
dry-run tarball read that e52ae1cd added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(verification): release cold source transform services

* fix(javascript): retain capture context along covered mutation paths

* fix(environment): admit serialized exports and scan HAR form fallbacks

* fix(environment): admit in-memory build inputs against heap headroom and scan SaveHar null-text forms

The inspected HAR's Evidence and the projected manifest are checked against live heap headroom before they are
serialized, with the same check the file route uses, so a capture too large to parse and seal is refused as
resource_constraint before anything is written. A request whose postData text is SaveHar's null is scanned by its
structured params.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(environment): measure the credential scan limit in UTF-8 bytes

A body counts against the 4 MiB limit by its UTF-8 length, not its UTF-16 code units, so multibyte text over the
limit is reported as unscanned instead of parsed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(javascript): erase inline type imports before binding values

* fix(environment): parse credential form bodies by their media type

* fix(environment): review untyped retained form fields

* fix(environment): bound request comparisons and preserve write proofs

* fix(environment): keep write proofs and bundle review complete

* fix(environment): finalize entity overrides with simulated views

* test(environment): restore 0895c89b's untyped form tests and hint

Integrating main took main's credential scan and coverage view, which
dropped 0895c89b's tests and its body-unusable hint. Main's scan passes
the tests, now reading the scenario by event. The hint names the
response too, since extraction and serving also withhold a write as
body-unusable when its recorded response cannot be read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(environment): scan a scenario content event recorded twice

Main's event scan reads both content events of a transaction whose
content the capture recorded twice; the test fails on 0895c89b, whose
review projection dropped that transaction's response. The spec names
event pointers among the first 20.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(environment): record the review round's checks

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(environment): retain contradictions and trim retired state

* fix(environment): distinguish mixed array order from changed values

* fix(environment): keep dependent create state pinned

* fix(environment): keep checking retired view observations

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
2026-10-24 23:57:30 +08:00

6.0 KiB

Build an environment in one step

Issue: https://github.com/morluto/rea/issues/4933

Outcome

Building an agent environment bundle takes three commands and a hand-written view request that embeds the whole capture inline, so large captures hit inline input accounting. The views apply no opt-in template rules by default, while the published capture-built environments all use the same four, and a local capture is named after its origin host (127-0-0-1-3105). Nothing reports which tools an environment serves from its state, or why a write tool is withheld.

rea environment-build <capture> [directory] builds the bundle in one offline step and reports what it serves. A new environment-coverage analysis view reports the same summary for any capture, so an agent can check a recording before building.

Requirements

  • The capture is a .har file, inspected as inspect-web-network-capture inspects it, or capture Evidence JSON from inspect_web_network_capture or capture_browser_scenario; any other extension is refused before it is read, and a HAR document saved as .json is refused with a hint.
  • The manifest is projected from the in-memory capture as retained Evidence, with the default rules after-uid-literal, opaque-token, sibling-variance and prefix-variance unless --template-rule or --format-rules-only selects others; rules apply in the views' order and a repeated rule is refused, as the views refuse it.
  • For the same capture path, every bundle file is byte-identical to what inspect-web-network-capture --format json, inspect-analysis-view --format json (the same rules in the views' order) and environment-export (the build's name) write, Evidence ids included. The Evidence is serialized once into one exactly sized buffer, whose bytes are both authenticated and shipped.
  • The name is --name, else the manifest's, unless the origin is a loopback name or IP literal: then the capture file's name, with a warning; a file name that yields no portable bundle name is refused, asking for --name.
  • The report carries the export's tool count, state, package source and files, plus the capture and manifest identities, coverage, warnings and the next command, shell-quoted. coverage counts read tools answered from the state and replayed (per view reason), and lists write tools as served or withheld with their reason, plan record, the contradicting read and a hint; it is null when the state is unavailable.
  • Every write reason has a hint; a reason without one fails to compile.
  • Credential-named header names, query parameter names and JSON or form body members that hold a value are reported as a count and the first 20 record or event pointers, never values, and never refuse a build; the scan cannot overflow the stack on deeply nested bodies. A body is read as a form (application/x-www-form-urlencoded, by URLSearchParams) or as JSON (the media types replay parses as JSON) by its recorded media type; a body with none, or one naming neither, is JSON when it starts with { or [ and a form when it contains = and no whitespace, so plain text and empty bodies yield no pointers. A browser scenario is scanned by event rather than by record: every retained request and response network-content event's header values and body, including a response whose request began before the browser was attached and a transaction that cannot be attributed to one request and response, and each transaction URL's query parameters once; its pointers name the event's index in events.items (event 4 response /token). Each occurrence of a repeated form field counts, as each repeated header or query parameter does. A HAR request recorded with structured form parameters and no text, or the null text mitmproxy's SaveHar records, is scanned by those parameters. Text bodies over the 4 MiB scan limit, measured in UTF-8 bytes, including a response body decoded only as a prefix, are not scanned; they are reported as a credential-scan-incomplete warning with a count and the first 20 record or event and side pointers (record 3 response, event 4 response), never contents, and never refuse a build. Binary bodies hold no JSON or form text and are neither scanned nor reported.
  • The inspected HAR's Evidence and the projected manifest are admitted against the live heap headroom for parsing and sealing before either is serialized, as a capture Evidence file is before it is read; one that does not fit is refused as resource_constraint before anything is written.
  • An empty or NUL-containing capture, directory or package tarball argument is refused as invalid input; it is never resolved to the working directory.
  • Nothing is written before the bundle stage; --dry-run writes nothing, reports the files a build would write and refuses the package tarballs a build refuses, admitting, reading and hashing, and releasing the tarball as a build does before copying it, so a tarball whose contents cannot be read is refused: a close it cannot confirm is reported as incomplete cleanup that keeps its owner. The directory must be absent or empty.
  • SIGINT is checked between stages and after a dry run's last step: a build cancelled before the bundle stage writes nothing, and one cancelled during the write names the written bundle.
  • The environment-coverage view summarizes the environment-state view with the same rules, refuses what it refuses and is inferred. It does not apply the serve-time catalog and state admission checks, and says so in a limitation.
  • The real-agentenv lane builds its bundle with environment-build.

Non-goals

  • No change to the three existing commands' contracts, or to what any view derives or any environment serves.
  • No browser launch or network access: scenarios are recorded with capture-browser-scenario first.
  • No --replace, no refusal on credential names, and no rewriting of the capture's absolute path, which Evidence identity includes.
  • No MCP export tool; that is a separate change.