35 Commits
Author SHA1 Message Date
Dery Ferdikaandgensokyo-dev aa6c1d49fd fix(mcp)!: require allowed hosts for non-loopback HTTP binds (#7172)
Require operator-declared hostnames before serving MCP HTTP outside loopback, preserving Host/Origin gates. Parse hostname identities once, share typed startup recovery across CLI/MCP, and announce an admitted client URL. Generated AgentEnv bundles declare their client/service names and validate DNS/HTTP name identity before export.

Validated through real packaged HTTP requests, direct SDK connection, compiled export refusals, 184 focused tests, static and documentation checks on the refreshed main integration. Final CI and review evidence is recorded in the PR body.

BREAKING CHANGE: non-loopback deployments require MCP_ALLOWED_HOSTS or rea mcp --http --allowed-hosts; bundle names must be unchanged HTTP hostnames within the 63-octet DNS label bound.

Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
2026-10-26 22:55:10 +08:00
morluto e54bf1006e fix(environment): own JSON fields across capture, state and replay 2026-10-26 18:27:30 +08:00
morluto 447907f280 docs(environments): explain building RL environments with REA 2026-10-26 00:16:52 +08:00
aba487eec0 feat(environment): learn creates from every call, with sorted arrays and referenced entities (#7034)
* feat(environment): explain values an application derives from other fields

Prompt-built environments withheld creates whose responses carry values the
application derives deterministically, which the write model kept as
constants or could not match across calls:

- A composed string is literal text plus parts read from the fields other
  rules write: a field's value, its slug, or a clock's calendar digits. A
  create composes a string only when another entity of the type spells it
  the same way and none spells it otherwise, and never from two sources
  serving could tell apart; an update composes an unsent change from members
  stored as sent and unchanged fields that also spell its value before the
  call. A composed field no longer pins the members it reads.
- A trimmed clock format drops trailing fraction zeros, as Go spells
  nanoseconds. It is learned from the type's values, a later create or a
  later update, and spreads to the plan's other clocks unless a value shows
  a fixed width.
- A large integer no entity of the type holds, among distinct ones of the
  same length and kind, is a generated unique value, served as a seeded
  integer.

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

* docs(environment): record the derived-values verification

Gates, tests, write plans over 69 recorded captures and served write tasks on the baseline and on this branch.

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

* feat(environment): learn a create plan from every call

A later create the plan does not take is explained on its own and merged when both calls show the same fields, every field both rule they rule alike, and a field neither rules holds one value: members either call sent are accepted, only those every call sent are required, and an echoed member a call left out takes the value that call stored, kept in the body's defaults.

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

* feat(environment): sorted arrays, referenced entities and nested view keys

- An echo is `sorted` when the application stored the sent strings in
  code-point order; serving stores them sorted, and a plain echo and a
  sorted one agree in update and create plans.
- A `reference` is an object field holding fields of the entity a sent
  member names, as the state holds it. The member is accepted with any
  value; replay and serving look the entity up, and serving refuses a call
  naming one the environment does not hold.
- A view names in `nested_fields` the keys it always shows of objects it
  shows with fewer keys than an entity stores; a stored object it never
  recorded renders with them. The view spelling learner moves to its own
  module.
- Every later create, not only one the plan refuses, is merged into its
  plan when it agrees, keeping the plan's rule order.

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

* fix(environment): keep clock spellings, linked ids and word boundaries honest

- A later update's clocks take the plan's spelling, sibling-trimmed
  clocks included, wherever the call's values fit it, so an update whose
  later call trims only one of two clocks is served.
- A held value that ends its fraction in a zero keeps a create's clock
  at a fixed width, whatever order the held spellings come in.
- A large integer that another field of the created entity also holds
  is linked, as a repeated token is: it is never unique, and the create
  is withheld as unexplained-change.
- Composed parts are delimited by whole characters through the shared
  joinsBefore/joinsAfter, so an astral letter joins a match to its word.

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

* test(environment): keep a same-width fixed clock out of trimming

A held .123456780 beside a held .12345678 keeps the create's clock at
nine digits in either order; the cases fail on 8ce1127b5.

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

* docs(environment): record the create-calls verification

Gates, tests, write plans over 69 recorded captures and served write tasks on the derived-values baseline and on this branch.

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

* docs(environment): note the create-calls census on current main

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

* fix(environment): check composed parts and clock fits before they shape a plan

- A composed string whose part has nothing to spell refuses the create
  or update through the apply Result instead of keeping a stale value.
- A composition learned on a later call is rebuilt from each earlier
  call's fields, so an earlier call that left the value otherwise
  contradicts it.
- An update adopts its fitted clock spellings only after the
  unknown-entity and contradiction checks, so a call on an entity an
  unmodelled write left unknown no longer trims a served plan's clock.
- Sibling trimming on a later create also checks that call's fields,
  so a sibling clock it shows with a trailing zero stays fixed-width.

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

* test(environment): split the derived-values view tests by rule

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

* fix(environment): keep fixed-width, zone and generated-integer evidence through a plan

- A plan keeps the first value that showed each clock at a fixed width,
  from held entities and every accepted create or update. No later fit
  or sibling trim widens that field, and a later call that shows it
  shorter is withheld.
- Two stamped clocks are one composed source only when they share a
  zone offset. A held entity that holds the target field as anything
  the parts do not spell, a non-string included, vetoes the
  composition. The token index is built once, and only when a string is
  left to compose.
- A generated integer that another field repeats as a number at any
  depth is linked. Compare treats two integers of one JSON kind and
  length under a unique rule as generated values.

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

* fix(environment): keep optional references across create calls and in answers

- A reference a later create added stays while further creates leave its
  member out, and agrees with a later call that shows it again.
- A create's answer shows optional reference and echo fields only when the
  call wrote them, whichever recorded call the answer came from.
- An update that re-sends the id of the entity a field already repeats keeps
  the plan's reference instead of pinning the member.
- An id naming entities of one type in several collections teaches no
  reference, and serving or replay refuses a call that names one.
- An echo is not promoted to sorted once a call stored its strings out of
  code-point order as sent.
- Nested view keys compare as sets and keep the first recording's order.

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

* test(setup): share registration prewarm host preparation

* fix(environment): retain write evidence and match trimmed response clocks

* fix(environment): withhold creates whose generated integer another string repeats

A unique integer whose digits show in another top-level string that no
template or composed rule rebuilds from it (an echoed serialText, or a
token like folder-<id>) withholds the create as unexplained-change,
since serving would seed the integer and keep the string. A templated
copy is still served.

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

* fix(environment): respect earlier clock widths and left-out members in later creates

- The create merge widens a clock to trimmed only against the value that
  showed its width: a held entity or accepted call at a fixed width keeps it
  untrimmed.
- A later create that left out a member the plan fills, with a default or a
  reference's absence, while its observation shows that field otherwise is
  unexplained-change, so the plan cannot serve the stale value.

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

* fix(environment): hold later creates and compare to the composed and integer forms

- A later create whose response spells a composed field otherwise than
  the plan rebuilds it is withheld as unexplained-change.
- A unique field learned from a generated integer accepts only an
  integer of the same length and kind from a later create, as serving
  seeds one.
- Compare counts a composed field as equal when each side's response
  spells it from its own fields, which compare under their own rules.

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

* fix(environment): preserve composed parts and unique generator families

* fix(environment): reject contradictory create references

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-25 05:31:46 +08:00
38719a6fa9 feat(environment): explain values an application derives from other fields (#7025)
* feat(environment): explain values an application derives from other fields

Prompt-built environments withheld creates whose responses carry values the
application derives deterministically, which the write model kept as
constants or could not match across calls:

- A composed string is literal text plus parts read from the fields other
  rules write: a field's value, its slug, or a clock's calendar digits. A
  create composes a string only when another entity of the type spells it
  the same way and none spells it otherwise, and never from two sources
  serving could tell apart; an update composes an unsent change from members
  stored as sent and unchanged fields that also spell its value before the
  call. A composed field no longer pins the members it reads.
- A trimmed clock format drops trailing fraction zeros, as Go spells
  nanoseconds. It is learned from the type's values, a later create or a
  later update, and spreads to the plan's other clocks unless a value shows
  a fixed width.
- A large integer no entity of the type holds, among distinct ones of the
  same length and kind, is a generated unique value, served as a seeded
  integer.

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

* docs(environment): record the derived-values verification

Gates, tests, write plans over 69 recorded captures and served write tasks on the baseline and on this branch.

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

* fix(environment): keep clock spellings, linked ids and word boundaries honest

- A later update's clocks take the plan's spelling, sibling-trimmed
  clocks included, wherever the call's values fit it, so an update whose
  later call trims only one of two clocks is served.
- A held value that ends its fraction in a zero keeps a create's clock
  at a fixed width, whatever order the held spellings come in.
- A large integer that another field of the created entity also holds
  is linked, as a repeated token is: it is never unique, and the create
  is withheld as unexplained-change.
- Composed parts are delimited by whole characters through the shared
  joinsBefore/joinsAfter, so an astral letter joins a match to its word.

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

* test(environment): keep a same-width fixed clock out of trimming

A held .123456780 beside a held .12345678 keeps the create's clock at
nine digits in either order; the cases fail on 8ce1127b5.

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

* fix(environment): check composed parts and clock fits before they shape a plan

- A composed string whose part has nothing to spell refuses the create
  or update through the apply Result instead of keeping a stale value.
- A composition learned on a later call is rebuilt from each earlier
  call's fields, so an earlier call that left the value otherwise
  contradicts it.
- An update adopts its fitted clock spellings only after the
  unknown-entity and contradiction checks, so a call on an entity an
  unmodelled write left unknown no longer trims a served plan's clock.
- Sibling trimming on a later create also checks that call's fields,
  so a sibling clock it shows with a trailing zero stays fixed-width.

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

* test(environment): split the derived-values view tests by rule

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

* fix(environment): keep fixed-width, zone and generated-integer evidence through a plan

- A plan keeps the first value that showed each clock at a fixed width,
  from held entities and every accepted create or update. No later fit
  or sibling trim widens that field, and a later call that shows it
  shorter is withheld.
- Two stamped clocks are one composed source only when they share a
  zone offset. A held entity that holds the target field as anything
  the parts do not spell, a non-string included, vetoes the
  composition. The token index is built once, and only when a string is
  left to compose.
- A generated integer that another field repeats as a number at any
  depth is linked. Compare treats two integers of one JSON kind and
  length under a unique rule as generated values.

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

* test(setup): share registration prewarm host preparation

* fix(environment): retain write evidence and match trimmed response clocks

* fix(environment): withhold creates whose generated integer another string repeats

A unique integer whose digits show in another top-level string that no
template or composed rule rebuilds from it (an echoed serialText, or a
token like folder-<id>) withholds the create as unexplained-change,
since serving would seed the integer and keep the string. A templated
copy is still served.

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

* fix(environment): hold later creates and compare to the composed and integer forms

- A later create whose response spells a composed field otherwise than
  the plan rebuilds it is withheld as unexplained-change.
- A unique field learned from a generated integer accepts only an
  integer of the same length and kind from a later create, as serving
  seeds one.
- Compare counts a composed field as equal when each side's response
  spells it from its own fields, which compare under their own rules.

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

* fix(environment): preserve composed parts and unique generator families

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-25 05:06:21 +08:00
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
69f99c5198 feat(environment): time browser scenario records so scenario environments learn a write clock (#6967)
* feat(browser): record when scenario requests were observed and how long they took

Request events carry observed_at, the wall-clock time the provider observed
the request start, and finished or failed events carry the browser's
elapsed_ms when it reports one. Both are optional, so earlier captures still
parse, and scenario comparisons leave them out as a committed built-in rule.
The real-Chrome network lane checks every request and finished response is
timed.

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

* feat(environment): time browser scenario records so their state learns a write clock

Scenario records take startedDateTime from when each request was observed and
time from the browser's duration, as HAR entries are timed. A timed scenario
of the book session learns the same clock and serves the same writes as its
HAR; an untimed one keeps record order and learns no clock, as before.

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

* docs(environment): document scenario request times and timed scenario records

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

* fix(environment): start scenario records at the browser's own request start

The provider observes a request up to tens of milliseconds after the browser
starts it while it reads other responses, so a record starting then and
ending after the browser's duration mixed two clocks. Finished and failed
events now carry the browser's started_at, records prefer it and fall back to
observed_at, and comparisons drop it too. Tests cover the fallback for a
request that never ended or ended twice, a partly untimed capture keeping
record order, comparing an untimed capture with a timed one, and the
real-Chrome lane checks every finished request carries the browser's start
and duration.

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

* docs(environment): document the browser start time, its fallback lag and older readers

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

* docs(environment): record the scenario timing verification

Gates, the real-Chrome lane, prompt-recorded and re-recorded published
scenario captures built with and without their times, the stale published
environments left unrepublished, and the review.

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

* test(browser): compare timed completion events in the request-time comparison test

The comparison test's captures had no finished or failed events, so dropping
started_at and elapsed_ms from them went untested. The captures now end one
request and fail the other, the test asserts both carry times, compares them
shifted by seven seconds and against an untimed capture, and a control shows
a changed failure on a timed completion is still reported.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-24 22:48:50 +08:00
02e049744f feat(environment): build agent environments from a prompt (#6946)
* 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>

* feat(browser): send declared requests from a scenario page with a request step

A capture_browser_scenario step `request` sends one declared HTTP request
through the page's own fetch, with its cookies and session, the way the
application's frontend would, and reads the whole response so the capture
records the transaction like any other. The path must resolve to the start
URL's origin, and the page must be on that origin when the step runs.
Query values and header values may be literals or declared secrets, and a
header may read its value from a cookie or a local storage entry, which is
then redacted from later records like a declared secret. `expected_status`
fails the step on any other status. Scenarios without a request step are
unchanged.

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

* test(browser): verify request steps in a real browser through to a built environment

verify:browser:request records a write session against a fixture item API
that refuses writes without its CSRF cookie header and stored bearer
token. It checks that every request lands in its own step, that the page
values authenticated each write and appear in no record, header or body,
that an unexpected status fails the step and cancels the rest, and that
environment-build serves the recorded create, update and delete.

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

* feat(environment): export environment bundles over MCP

export_environment_bundle writes the bundle environment-build writes, from
capture Evidence retained in the session or one capture Evidence file,
into an absolute output directory that must not exist and whose parent
must exist, as extract_firmware and export_web_scripts require; it never
creates the parent or reuses a directory. It returns the same report,
whose schema now lives in the domain so the CLI and the tool share it, and
dry_run reports without writing. A loopback capture without a file needs a
name. The build's refusal messages no longer name CLI flags.

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>

* docs(skill): build agent environments from a prompt with request steps and the bundle tool

Add the environments reference to the skill and install it with setup: record
against a disposable instance, sign in through the UI, write with request
steps and read each write back, check coverage, re-record by withheld reason
and export the bundle. Route it from SKILL.md, name agent environments in the
skill description, and document the request step, the export tool and
recording writes.

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

* refactor(browser): split the request lane and header resolution into smaller functions

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): say when an untimed capture learns no write clock

Coverage of a capture whose records are not all timed, which includes every
browser scenario capture, now states that the state learns no clock, so an
update stamped with a server-set modification time stays unexplained-change
however often it is recorded.

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

* docs(skill): give agents a whole scenario shape with step timeouts

Agents guessed the scenario schema field by field and two hung on steps
without timeout_ms. The reference now starts from a complete scenario with a
timeout on every step, and says a scenario capture cannot serve updates the
application stamps with a modification time.

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

* fix(browser): keep request steps on their origin and their page values redacted

- Follow no redirects: a redirect fails the step and nothing reaches the
  location it names (checked in real Chrome), and check the page's origin
  again in the page as the request is sent.
- Send nothing once the step's time has run out or it was cancelled while
  header values were read; the in-page deadline is what remains of the step's.
- Keep every page value redacted under a repeated or colliding label, keep a
  value's first marker when it is read again, and leave values shorter than
  8 characters unredacted rather than rewriting ids, ports and hosts.
- Refuse a header name given twice, User-Agent (Chrome drops it) and line
  breaks in literal values and prefixes; fail before sending when a secret or
  page value holds them.
- Append query entries after the path's literal query without re-encoding it.

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

* docs(environment): document request step limits and word bundle refusals for both surfaces

Document redirects, timeouts, page value redaction, HttpOnly cookie sources
and header refusals for request steps. Refusals shared by environment-build
and export_environment_bundle no longer name CLI flags, and the retained
loopback refusal no longer prints an empty file name. The skill reference
asks for read-backs after each write, shows the coverage view's source, names
package_tarball for unreleased builds and the browser path a scenario ships.

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(browser): close request step edge cases from the second review

- Append query entries correctly after a path ending in "?", "&" or "#".
- Refuse 3xx expected statuses, which an unfollowed redirect can never
  report, and say a redirected write may already have been applied.
- Redact a page value also as fetch sends it, without surrounding spaces
  and tabs.

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

* docs(environment): document page value body costs, redirects and MCP dry runs

Document that reading a page value shrinks the bodies a capture keeps under
the default allocation limit, that redirected writes may have landed, that
the MCP dry_run still checks its output directory and which refusals name
the tool, and keep the .har hint in the HAR-as-JSON refusal for both
surfaces.

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

* docs(environment): record the prompt-to-environment verification

Gates, the real-browser lanes, five environments built from prompts by an
agent on disposable VMs and evaluated with two models, and the two reviews.

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

* test(skill): count rollback failures from the managed skill files

The environments reference made the skill eight files, so the recovery tests now derive the counts they expect from
MANAGED_SKILL_FILES instead of fixing them at six and seven.

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

* fix(adb): restore the portable Java float pattern a merge rewrote

A lint autofix during a merge unescaped the hyphens in javaFloatValuePattern, which is invalid in a v-mode character
class, so the advertised start_adb_activity schema failed to compile in every JS regex mode. The file now matches main.

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

* docs(browser): show the request step inside a whole scenario

Every JSON example in the browser scenario guide is a capture_browser_scenario input the catalog test parses, so the
request step example now sits in a launch scenario instead of standing alone.

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): guard request dispatch and report export limits

* 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(browser): send request steps only before their deadline and keep page reads on the start origin

The page receives the step's absolute deadline and a one-second start window, so a busy page that runs the request
late, or after the step is cancelled, sends nothing; local storage is read only on the start origin; the response is
drained without keeping its body; an unparseable path is a field issue; retained Evidence is refused for heap headroom
before it is serialized; and the skill says how to reach server-assigned ids.

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

* style: format integrated export admission

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

* fix(browser): run the request lane under the shared verifier command owner

The browser request lane runs each CLI call through createPackageVerifierCommands on a private runtime root, so a
timeout, output overflow or failure stops the CLI and the browser it launched before the root is removed, and a failed
stop is reported with the root retained. The verification record states the lane's current counts.

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

* fix(environment): scan scenario content by event and read bodies by their media type

A browser scenario's credential scan reads every retained network-content event, including a response attached
mid-flight and a transaction no record represents, with event pointers, and each transaction URL's query once; the
review record projection it replaces is removed. A body is parsed as a form or as JSON by its recorded media type,
falling back to its shape, so valid forms such as `password=x&` are scanned and sentences are not read as forms.

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

---------

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>
2026-10-24 21:51:41 +08:00
d361c53c50 feat(environment): serve writes by what their recordings show (#6897)
* fix(environment): keep read-only POSTs out of the write list

A POST that repeats the latest read of its path, tunnels only read
operations, names a lookup in its path's last meaningful word, or renews
a session no longer counts as a state write: it is replayed, does not cut
initial windows, and does not end observation searches. A tool stays a
write when a related read line changes across one of its calls.

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

* fix(environment): take an entity an unplanned write made when a read first shows it

A successful item read of an entity the gate's copy never held, after a
write no built plan models, puts the entity into the copy instead of
failing the read, so later writes to it are checked as usual. An entity a
modelled write touched is never taken back.

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

* fix(environment): plan a create into the type its returned id is read under

A POST whose path names no state type becomes a create into the type
whose item read first names an id its response returned, when the id is
new to the state; serving creates in that read's collection. A successful
POST that returned an id a type's reads only show after it also ends that
type's initial window, so entities a capture created stay out of the
initial state.

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

* fix(environment): end a type's initial reads at the write its reads disagree across

When a type's reads disagree across a write under another root, the
type's initial window now ends at the earliest write within that change
and the state is extracted again, instead of leaving every view of the
type replayed. The cut composes with the creation cut; the earlier wins.

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

* fix(environment): replay request lines that show entities in another form

A read line that shows the same entities in another form, by an extra
query parameter that adds or drops members, or conflicts with a base
line on a shared entity, is a variant: it leaves the view's checks and
the entity observations, the view names it with the query keys that pick
it out, and a call matching those keys replays its recording. A filter
role whose name matches no field needs two agreeing values.

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

* docs(environment): specify and record the state-target changes

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

* fix(environment): keep a read-only POST a write when its evidence is incomplete

Body-level container operations are skipped like query ones, a lookup is named only
by the path's last literal segment and never alongside a write word, a tool with a
redirected or unanswered call is not reclassified, and the mutation veto is resolved
over all candidates at once so another read-only call cannot explain a read change.

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

* fix(environment): answer a field selection only when the state shows it exactly

Serving tests a field selection before any variant key: a projection value a replayed
read gave, or one no checked line gave other than `*`, replays. A list sets aside a
line asking for some fields only before the identity proof, and a dropped variant's
membership change no longer rewrites the type.

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

* fix(environment): hold adopted entities and linked creates to what the recording shows

An adopted entity is charged against the view's budget like a created one. A linked
create holds only for its exemplar's path arguments: serving refuses others and the
gate counts such a call as unmodelled. A response's identity-named id links at any
length, but a short one only to a type read before the call.

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

* docs(environment): record the review fixes' measurements

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

* fix(environment): release a discarded planning pass before planning again

A rewrite cut clears the first pass, so the budget rewinds to a checkpoint taken after
the write cutoffs and created ids before the state is extracted again. Rewrite spans are
charged and appended without spreading them into an argument list.

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

* fix(environment): link no create whose id an earlier read showed, and read only whole batches

A linked create is rejected when an earlier list of its type or read of its collection
showed the returned id. Body ids are walked without spreading children into an argument
list. An RPC call reads only when every operations entry names an operation of its own.

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

* fix(environment): let the gate skip exactly the reads serving replays

Serving's replay decision moves to the domain as replayReason, and the write gate uses it:
a read serving replays can neither approve nor veto a write, and a read of every field
beside a replayed selection is checked. A selection read missing a required field is
still skipped, since part of an entity can neither confirm nor check it.

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

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

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

* fix(environment): read writes, links and creation cuts only from evidence that rules out other causes

- A read-only POST repeats only a read that finished before it began; the veto compares
  the latest read finished before a call with the first begun after it, and counts a
  recorded absence on one side as a change. `modify` and `replace` are write words.
- A redirected or unanswered write lets a later item read adopt the entity it may have made.
- A creation cut counts a read still running when the POST began as after it, and a list
  read shows its listed entities' own ids, not those they nest.
- A linked create's item read must come before any other tool's write.
- Line shapes are charged to the budget as they are built.
- A `fields=*` list line is whole, not a field selection.

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

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

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

* fix(environment): tie linked creates to their returned ids and order state by the lines left

- A linked create is observed only in a read of an id its response returned,
  envelopes included, and serving takes its recorded path values in either spelling.
- A list read shows a suffix-named identity (`projectId`) distinct across its entities.
- A read-only POST compares the read that finished last before it began.
- An entity's first sighting comes from the lines left after variant lines are dropped.
- The pairwise variant pass stops at a work limit, leaving every line checked.

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

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

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

* fix(environment): keep foreign keys, stale reads and double decoding out of write evidence

- A list read counts a suffix-named field as its entities' ids only when no
  id-named field identifies them, so an `ownerId` beside `id` cuts no window.
- A read-only POST is compared with the read that finished last among those no
  other write follows, so a consuming call stays a write.
- A linked create's source path values compare as spelled on both sides, so no
  spelling is decoded twice.

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

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

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

* fix(environment): compare linked sources by position, decode path fields once and bound read and variant scans

- A linked create's source values compare segment by segment, so a template
  naming two parameters alike cannot accept a changed first one.
- Serving fills a linked create's path fields with its arguments decoded once,
  as the gate learned them.
- The read-only check reads each related line's records once per call, between
  the nearest other writes.
- Member signatures are JSON arrays, so a name holding the separator still
  conflicts; the variant work limit counts line pairs as well as entities.

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

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

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

* fix(environment): replay late and variant-only items, fill linked path fields from the exemplar and charge membership spans

- An item line first recorded after the initial window that names a new shaping
  parameter and shows other members is a replayed variant, like an initial one.
- An item only a replayed line showed, which the state never started with,
  answers with its own recording; one the state held and lost stays missing.
- A linked create fills its path fields from its exemplar's path decoded once,
  whichever accepted spelling the call sends.
- Each membership change span is charged against the budget before it is kept.

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

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

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

* fix(environment): blame a failed read on the writes whose fields it disagrees on

A failed item read with no interfering unmodelled write contradicts its creates and
deletes, and an update only when a field the update wrote or its response showed
differs. A create is contradicted when a later read embeds it elsewhere and the state
does not. A create member is fixed to its recorded value when a constant it would
have to change derives from it: its text inside a constant, a referenced entity's name,
or an instant beside a sent date, matched by related field names.

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

* fix(environment): explain unsent update changes and nested clocks by what the recording shows

An update's unsent change can be a modified-by stamp beside a created-by counterpart, a
value derived from the one sent member stored nowhere (accepted only while the target
holds the recorded before-value), or a sent clock the call left in its own second.
Objects whose clocks all moved with the request are nested clocks, opaque tokens of a
type's own length are generated, and an enveloped body is learned as its one object.
A write takes only its recorded query, an echoed reference to a nested object and a
state word paired with other fields stay at their recorded values, and a slug is tried
before a token.

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

* fix(environment): order collections by whole lines and sort only arrays a read-back proves sorted

A collection's initial order comes from the first list line that shows every entity its
type's sightings do and applies no order. A view renders a string-array field sorted
only after a counted read-back shows the written values in an order that neither the
written order nor existing-values-first explains, and never once a read showed it
unsorted. Sort and direction parameters share one vocabulary and are never learned as
inert, and a create placed by disagreeing sorts or a random id falls back to last.

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

* feat(environment): serve bulk writes at a collection and target item actions

A DELETE, PUT or PATCH at a collection, or a POST at its delete path, whose body names
held entities by id is applied to each named entity, and serving refuses it unless every
id is held. A POST to an entity's action path that answers nothing or the entity is an
update of it; it is served only when a recorded call found each scalar it sets already
at that value. Served bulk bodies advertise their items, and compare probes pass them.

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

* fix(environment): decide late item lines against the lines left, charge replay keys and bisect rewrite cuts

- Item lines first recorded after the initial reads are decided once variants
  are dropped, against the lines left: a new shaping parameter showing other
  members, or a selection of some fields leaving members out, replays.
- Each replay key is charged against the budget before it is kept.
- A rewrite span's earliest write is found by bisection over the writes.

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

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

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

* fix(environment): set aside response members a path mints anew on every read

A top-level UUID or clock that differs on every repeat of one path's successful reads,
with no write between, is left out of that path's item, list and document comparisons
and named in the view's per_response_members. Serving keeps the recorded value.

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

* fix(environment): count only reads finished before a linked create began as showing its id held

A list still running when the call began may show what the call made, as the
creation cut already decides, so it no longer refuses the link.

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

* fix(environment): count a list total nested in a paging object

An item total in a top-level object beside the list, such as pageInfo.totalRows, is a
counter on the same evidence as a top-level one: it must equal the number listed, and
one that differs marks the line partial. Serving and the gate render it from the state
through its JSON pointer and leave the object's other members as recorded.

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

* fix(environment): take a created entity's nested clocks from its read-back

After a create's generated values pass, its stored nested clocks take the instants the
first later read of the entity shows, as an update's already do, so a create whose
response and read spell the clock differently is confirmed.

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

* fix(environment): import the compare tool definition as a type

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

* docs(environment): describe the new write rules and trim repeated parsing

The environment and capture docs describe sorted arrays, per-response members, nested
counters, item actions, bulk writes, the new write rules and refusals, and their known
limits. `_order` is a direction only. Sorted-array retries and the per-response scan
parse only the reads they need, and identifier words come from one helper.

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

* fix(environment): confirm no update whose clocks or fields the evidence cannot show it writing

An unsent clock an update left in the second it ran keeps the update unconfirmed until
another call shows the clock stamped. A field the state lacks that the read and the
update's response both show is the update's change, so without a rule for it the read
confirms nothing. A modified-by name stamp brings its id sibling along, and created
entities are indexed by id when a failed read is checked for embeds.

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

* fix(environment): show pinned query and body values in the served catalog and apply bulk writes atomically

A pinned query parameter is required with its recorded value as the only choice, and a
call that leaves it out takes that value. A fixed body member shows its recorded value,
and an enveloped body its wrapping, in the schema, the description and the refusal.
Bulk writes go through the same query pin and update or remove their entities at once.

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

* docs(environment): specify and record the write-rule changes

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

* fix(environment): keep served creates' items missing, check same-type earlier reads, and bound late lines and read-only stretches

- An item only a replayed line showed replays only while no served create has
  added to its type, so a created and deleted item stays missing.
- A linked create's earlier item-read veto checks only reads of the candidate's
  type or collection that show the item, so another type's id does not hide it.
- An item read answered with JSON null shows no id to a creation cut.
- Late lines' member names are charged before they are kept.
- The read-only check precomputes nearest writes and passes once over each
  write-free stretch per path, skipping lines whose reads all agree.

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

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

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

* fix(environment): link creates past empty item reads, sweep repeated reads once and keep only returned ids for creation cuts

- A linked create passes over a later item read naming its id whose body shows
  no item, such as JSON null, and links the next one.
- Read-only repeated reads are found in one sweep: each path's reads wait by
  end time until a call's start passes them, and a write clears them.
- A creation cut keeps, and charges, only the shown ids some creation returned.

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

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

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

* fix(environment): take bulk ids literally, check each recorded call's query once, and keep learned sorts open to contrary reads

Bulk writes take body ids as written, refuse a call naming one entity twice, size updates from the replacements
installed, generate each entity's values from that entity, and delete only with the members their exemplar sent
besides the ids. Comparison translates bulk body ids with the target collection's mapping.

Update rules echo a creation clock sent back unchanged, require every held clock, and refuse a nested clock once any
recorded call kept its object. A recorded call sent with another query than its exemplar's, including item actions,
documents and deletes, neither confirms nor teaches its plan, and only successful calls with that query relax a
create's guards.

A counted read listing a learned array unsorted drops the sort from its view, sort evidence comes only from the
entities the read covers, and a top-level counter whose name starts with a slash is named by its escaped pointer.

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

* docs(environment): record the review fixes' checks

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

* perf(environment): compare variant lines through shared entities and parse each compared body once

The variant pass indexes a tool's lines by the entities they show and compares only lines that share one, charging
the index to the budget while it is held; the pairwise work limit still decides when a tool keeps every line checked.
Read-only decisions keep each response body's canonical digest, taken once while its parse is charged, across calls
and veto passes. The creation cut no longer parses reads at or after the write that ends the initial reads, and reads
the ids a body shows inside its lease. Adoption looks up a read's target only after an unplanned write before it.

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

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

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

* perf(environment): list a type's collections only when the path's own holds no id, and parse variant base lines once

The write gate's item target lists the type's held collections, and the removed targets', only when the path's own
collection holds none of its ids, so a served item view's reads no longer walk every entity of the type. The variant
pass parses the base lines' queries once for all the variants they key, and not at all when it found none.

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

* docs(environment): record the twelfth review round's checks and the sweep's cost

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

* docs(environment): record the 50-capture sweep's wall, CPU and peak memory

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

* fix(environment): remove duplicate schema after main integration

* fix(environment): honor recorded bulk identity kinds

* fix(environment): retain scoped evidence and honor write defaults

* test(environment): keep SDK regressions independently scoped

* docs(environment): record scoped write verification and measured costs

* fix(environment): serve bulk writes whose response lists each entity they wrote

A bulk call answering an array with one element per entity its body names, in the body's order, is classified by
its elements, so the existing renderer serves it from the entities each call writes. Responses listing entities out
of order, with differing members or id spellings, wrapped elements or an envelope still refuse.

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

* docs(environment): measure the 50 captures at the scoped-envelope head

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

* fix(environment): classify bulk responses and release verifier transforms

* fix(environment): classify and verify complete bulk responses

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

* test(environment): verify bulk responses through the real MCP SDK

* test(environment): separate bulk response proof regressions

* fix(environment): preserve request absence and generated value relationships

* fix(environment): verify complete nested clocks on creates

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

* fix(environment): share complete generated value verification

* fix(verifiers): load the Windows source graph only when needed

* fix(environment): validate write responses before stored clock restamps

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-24 20:52:03 +08:00
977c9727e6 feat(environment): give more write tools a state target (#6385)
* fix(environment): keep read-only POSTs out of the write list

A POST that repeats the latest read of its path, tunnels only read
operations, names a lookup in its path's last meaningful word, or renews
a session no longer counts as a state write: it is replayed, does not cut
initial windows, and does not end observation searches. A tool stays a
write when a related read line changes across one of its calls.

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

* fix(environment): take an entity an unplanned write made when a read first shows it

A successful item read of an entity the gate's copy never held, after a
write no built plan models, puts the entity into the copy instead of
failing the read, so later writes to it are checked as usual. An entity a
modelled write touched is never taken back.

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

* fix(environment): plan a create into the type its returned id is read under

A POST whose path names no state type becomes a create into the type
whose item read first names an id its response returned, when the id is
new to the state; serving creates in that read's collection. A successful
POST that returned an id a type's reads only show after it also ends that
type's initial window, so entities a capture created stay out of the
initial state.

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

* fix(environment): end a type's initial reads at the write its reads disagree across

When a type's reads disagree across a write under another root, the
type's initial window now ends at the earliest write within that change
and the state is extracted again, instead of leaving every view of the
type replayed. The cut composes with the creation cut; the earlier wins.

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

* fix(environment): replay request lines that show entities in another form

A read line that shows the same entities in another form, by an extra
query parameter that adds or drops members, or conflicts with a base
line on a shared entity, is a variant: it leaves the view's checks and
the entity observations, the view names it with the query keys that pick
it out, and a call matching those keys replays its recording. A filter
role whose name matches no field needs two agreeing values.

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

* docs(environment): specify and record the state-target changes

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

* fix(environment): keep a read-only POST a write when its evidence is incomplete

Body-level container operations are skipped like query ones, a lookup is named only
by the path's last literal segment and never alongside a write word, a tool with a
redirected or unanswered call is not reclassified, and the mutation veto is resolved
over all candidates at once so another read-only call cannot explain a read change.

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

* fix(environment): answer a field selection only when the state shows it exactly

Serving tests a field selection before any variant key: a projection value a replayed
read gave, or one no checked line gave other than `*`, replays. A list sets aside a
line asking for some fields only before the identity proof, and a dropped variant's
membership change no longer rewrites the type.

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

* fix(environment): hold adopted entities and linked creates to what the recording shows

An adopted entity is charged against the view's budget like a created one. A linked
create holds only for its exemplar's path arguments: serving refuses others and the
gate counts such a call as unmodelled. A response's identity-named id links at any
length, but a short one only to a type read before the call.

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

* docs(environment): record the review fixes' measurements

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

* fix(environment): release a discarded planning pass before planning again

A rewrite cut clears the first pass, so the budget rewinds to a checkpoint taken after
the write cutoffs and created ids before the state is extracted again. Rewrite spans are
charged and appended without spreading them into an argument list.

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

* fix(environment): link no create whose id an earlier read showed, and read only whole batches

A linked create is rejected when an earlier list of its type or read of its collection
showed the returned id. Body ids are walked without spreading children into an argument
list. An RPC call reads only when every operations entry names an operation of its own.

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

* fix(environment): let the gate skip exactly the reads serving replays

Serving's replay decision moves to the domain as replayReason, and the write gate uses it:
a read serving replays can neither approve nor veto a write, and a read of every field
beside a replayed selection is checked. A selection read missing a required field is
still skipped, since part of an entity can neither confirm nor check it.

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

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

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

* fix(environment): read writes, links and creation cuts only from evidence that rules out other causes

- A read-only POST repeats only a read that finished before it began; the veto compares
  the latest read finished before a call with the first begun after it, and counts a
  recorded absence on one side as a change. `modify` and `replace` are write words.
- A redirected or unanswered write lets a later item read adopt the entity it may have made.
- A creation cut counts a read still running when the POST began as after it, and a list
  read shows its listed entities' own ids, not those they nest.
- A linked create's item read must come before any other tool's write.
- Line shapes are charged to the budget as they are built.
- A `fields=*` list line is whole, not a field selection.

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

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

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

* fix(environment): tie linked creates to their returned ids and order state by the lines left

- A linked create is observed only in a read of an id its response returned,
  envelopes included, and serving takes its recorded path values in either spelling.
- A list read shows a suffix-named identity (`projectId`) distinct across its entities.
- A read-only POST compares the read that finished last before it began.
- An entity's first sighting comes from the lines left after variant lines are dropped.
- The pairwise variant pass stops at a work limit, leaving every line checked.

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

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

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

* fix(environment): keep foreign keys, stale reads and double decoding out of write evidence

- A list read counts a suffix-named field as its entities' ids only when no
  id-named field identifies them, so an `ownerId` beside `id` cuts no window.
- A read-only POST is compared with the read that finished last among those no
  other write follows, so a consuming call stays a write.
- A linked create's source path values compare as spelled on both sides, so no
  spelling is decoded twice.

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

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

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

* fix(environment): compare linked sources by position, decode path fields once and bound read and variant scans

- A linked create's source values compare segment by segment, so a template
  naming two parameters alike cannot accept a changed first one.
- Serving fills a linked create's path fields with its arguments decoded once,
  as the gate learned them.
- The read-only check reads each related line's records once per call, between
  the nearest other writes.
- Member signatures are JSON arrays, so a name holding the separator still
  conflicts; the variant work limit counts line pairs as well as entities.

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

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

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

* fix(environment): replay late and variant-only items, fill linked path fields from the exemplar and charge membership spans

- An item line first recorded after the initial window that names a new shaping
  parameter and shows other members is a replayed variant, like an initial one.
- An item only a replayed line showed, which the state never started with,
  answers with its own recording; one the state held and lost stays missing.
- A linked create fills its path fields from its exemplar's path decoded once,
  whichever accepted spelling the call sends.
- Each membership change span is charged against the budget before it is kept.

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

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

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

* fix(environment): decide late item lines against the lines left, charge replay keys and bisect rewrite cuts

- Item lines first recorded after the initial reads are decided once variants
  are dropped, against the lines left: a new shaping parameter showing other
  members, or a selection of some fields leaving members out, replays.
- Each replay key is charged against the budget before it is kept.
- A rewrite span's earliest write is found by bisection over the writes.

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

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

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

* fix(environment): count only reads finished before a linked create began as showing its id held

A list still running when the call began may show what the call made, as the
creation cut already decides, so it no longer refuses the link.

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

* fix(environment): keep served creates' items missing, check same-type earlier reads, and bound late lines and read-only stretches

- An item only a replayed line showed replays only while no served create has
  added to its type, so a created and deleted item stays missing.
- A linked create's earlier item-read veto checks only reads of the candidate's
  type or collection that show the item, so another type's id does not hide it.
- An item read answered with JSON null shows no id to a creation cut.
- Late lines' member names are charged before they are kept.
- The read-only check precomputes nearest writes and passes once over each
  write-free stretch per path, skipping lines whose reads all agree.

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

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

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

* fix(environment): link creates past empty item reads, sweep repeated reads once and keep only returned ids for creation cuts

- A linked create passes over a later item read naming its id whose body shows
  no item, such as JSON null, and links the next one.
- Read-only repeated reads are found in one sweep: each path's reads wait by
  end time until a call's start passes them, and a write clears them.
- A creation cut keeps, and charges, only the shown ids some creation returned.

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

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

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

* perf(environment): compare variant lines through shared entities and parse each compared body once

The variant pass indexes a tool's lines by the entities they show and compares only lines that share one, charging
the index to the budget while it is held; the pairwise work limit still decides when a tool keeps every line checked.
Read-only decisions keep each response body's canonical digest, taken once while its parse is charged, across calls
and veto passes. The creation cut no longer parses reads at or after the write that ends the initial reads, and reads
the ids a body shows inside its lease. Adoption looks up a read's target only after an unplanned write before it.

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

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

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

* perf(environment): list a type's collections only when the path's own holds no id, and parse variant base lines once

The write gate's item target lists the type's held collections, and the removed targets', only when the path's own
collection holds none of its ids, so a served item view's reads no longer walk every entity of the type. The variant
pass parses the base lines' queries once for all the variants they key, and not at all when it found none.

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

* docs(environment): record the twelfth review round's checks and the sweep's cost

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
2026-10-24 15:58:32 +08:00
morluto 0f411508c3 fix(environment): decouple capture chronology from clock formats
Use exact recorded start facts for state extraction independently of derived clock formatting limits. Preserve millisecond interval policy, missing-time fallback, redacted-write cutoffs, and bounded timestamp retention; remove the superseded clock comparator.

Two source and two compiled CLI regressions reproduced post-write values being selected as initial state. State/clock/date, CLI/MCP view, and static checks passed after the fix.
2026-10-24 11:31:39 +08:00
morluto 53601d0bdf merge: consolidate upstream identity and representation owners 2026-10-24 05:13:41 +08:00
morluto 87a5be3000 fix(environment): normalize values from owned response facts
Require a real clock-field context for numeric time normalization and actual rendered write rules for generated strings. Preserve literal read, replay and missing-response values, and retain generated aliases and distinctness within each response.

Keep clock context separate from entity identity while traversing arrays. Add domain and public CLI controls for measurements, business strings, confirmed writes, missing responses and generated-value relationships, with documented inference limits.

Fixes #6878
Fixes #6837
2026-10-24 04:42:09 +08:00
morluto 8b7de17833 merge: reconcile upstream boundary and format fixes 2026-10-24 03:59:44 +08:00
morluto 0bbd635ab8 fix(environment): preserve clock years and exact probe chronology
Reuse the shared offset-instant owner for calendar validation and exact probe ordering. Preserve first-century years, arbitrary recorded fraction digits in the supported offset profile, ordinal ties and legacy native-Date fallback. Keep original clock spelling when conversion leaves the supported four-digit year range, and refuse unrepresentable generated clocks before committing state.

Validation: focused clock/comparison and public CLI regressions cover leap years, offset equivalence, precise DELETE/GET order, spelling classification and refusal atomicity. Replay/state compatibility checks pass. Numeric state intervals and generated-clock progression retain their documented millisecond limits.

Fixes #6835
Fixes #6643
2026-10-24 03:06:58 +08:00
morluto f49e2eeacc fix(environment): retain path segments counters and parent diagnostics 2026-10-24 02:50:16 +08:00
morluto 2596667baf docs: repair localized anchors and agent terminology 2026-10-24 02:40:21 +08:00
morluto 23ab2c4069 fix(environment): preserve literal values and recorded comparison chronology 2026-10-24 02:29:08 +08:00
morluto 5f702dd6cc fix(parsers): preserve format boundaries and query occurrence identity
Normalize parsed facts at their owning boundaries across PE exports and certificates, ELF section names, GPU bundles, IL2CPP generic types, dyld slice selection, source maps, environment replay, and JavaScript mapped arguments. Preserve partial facts and explicit unsupported cases; clarify the corresponding documentation.

Validation: 831 affected tests passed with one existing skip across 23 files; build, typecheck/lint, documentation, formatting, and 2133-file test discovery passed. Format controls are synthetic; real Unity, GPU, and ARM-device execution is unverified.

Fixes #6709
Fixes #6688
Fixes #6719
Fixes #6718
Fixes #6704
Fixes #6703
Fixes #6692
Fixes #6723
Fixes #6687
Fixes #6726
Fixes #6696
Fixes #6691
Fixes #6727
2026-10-23 22:01:16 +08:00
GamerDubzandgensokyo-dev 520f8e8042 fix(runtime): align remaining Node security pins and setup guidance (#6316)
Derive exported Docker image versions from .nvmrc through generated package metadata. Align active setup translations with patched Node release floors and verify actual CLI exports, real Docker/agentenv, package and website workflows.

Eight built-test shards pass; three unrelated managed source failures reproduce on clean main and remain tracked in #6650.

Refs #6480

Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
2026-10-23 11:03:03 +00:00
morluto 65168f77fb fix(environment): restrict epoch normalization to clock fields
Require a time-field token boundary before treating numeric values as epoch clocks, so identifiers such as media format codes remain literal. Clarify recognized field forms and clock offset and precision semantics in the fidelity guide.

Fixes #6551
2026-10-23 18:07:45 +08:00
morluto fe0325c6d1 fix(environment): scope fidelity ID normalization
Reserve equal global ID pairs and stop normalizing contested pairings. Keep numeric measurements literal, scope keyed collection identities through learning and comparison, and normalize string references only where learning established the same field as an ID.

Fixes #6565
Fixes #6550
Fixes #6557
2026-10-23 17:51:09 +08:00
Edgar Arakelyan 957bcfa149 feat(environment): preserve view-specific written clock spellings
Share clock rendering between analysis and local serving. Preserve exact sub-millisecond facts, bound learned format state per field, and charge retained output to the projection budget.

Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
2026-10-23 00:12:26 +08:00
Edgar Arakelyan 7ec9b6e56e feat(environment): model application-assigned write values
Serve renamed create members and evidence-gated UUID regeneration. Preserve every copied text occurrence and withhold cross-field scalar UUID relations the independent generators cannot reproduce.

Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
2026-10-22 23:57:36 +08:00
Edgar Arakelyan 5375ff0f9a feat(environment): extend evidence-gated write coverage
Retain bodiless writes, proven omitted fields, identity-free projections and digit-group sequences. Preserve late projection provenance and current omission facts, and check absence statuses before replay shortcuts.

Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
2026-10-22 23:46:52 +08:00
edccb430c4 feat(environment): compare an environment with probe captures of its application (#5699)
* chore: restack environment fidelity onto main

Keep probe comparison, paging, and tied-create behavior on main after #5600. Capture parsing keeps field-path errors and records whether a probe kept request and response bodies.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(environment): keep served collection order with the fidelity checks

The tied-create collection order lives with the checks that match encoded parents. The write simulation reads field checks from that attribution, and taint uses the same segment match.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(environment): translate an object's keys only when it is keyed by learned ids

Differ.object mapped every key through the probe's id map, so a field named
like a learned id was compared with another field, and a real rename could
pass as a mapped key. Keys now translate only for an object keyed by
learned ids as learning reads one: a key both sides share needs every key
evidently an id, and otherwise each entry is an entity or each key evidently
an id. Any other object compares field by field.

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

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-22 21:52:01 +08:00
Edgar Arakelyan 293832bafc feat(environment): answer list filters, search, sorting and paging from the state
Learn supported filters, plain search, sorting and paging from retained list recordings and evaluate them through shared local-state workflows.

Preserve whole-membership admission, Evidence, query normalization, counter representation and omission. Use successful retry coverage consistently for confirmation and pending-write cleanup. Unsupported semantics remain replayed or unknown.

Validated 623 adjacent source tests, exact-head CI, repeated regressions, real retained GitHub CLI/MCP pagination, actual owned HTTP fixture sessions and Codex task/review runs. Third-party application-write fidelity and exhaustive scale/provider qualification remain unverified; details and measurements are recorded in the PR.

Refs #4933, #6262.

Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
2026-10-22 12:41:32 +00:00
Edgar Arakelyan 4043e71f6c feat(environment): list every entity on a list's whole lines (#5787)
Derive whole-collection membership per checked list line while preserving
recorded membership, counters, source Evidence and independent write claims.

Integrate current main without losing its shared path decoder. Keep later or
ambiguously positioned pages recorded rather than inventing earlier entities.

Validation: 543 focused/adjacent tests, nine README checks, complete static/docs
checks, repeated regression runs, and real retained GitHub-label CLI/MCP
load/reset workflows. An actual Codex session returned the correct facts;
its over-strict grader failure and same-trace semantic verification are recorded.

Evidence and limitations:
https://github.com/morluto/rea/pull/5787#issuecomment-6338446674
Tracking: #6262; feature scope: #4933.

Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
2026-10-22 18:34:56 +08:00
538017d1d2 feat(environment): apply evidence-gated write effects to the served state (#5600)
* feat(environment): render more read tools from the state and describe responses

Keep main's environment serving and fold in coverage for non-entity reads,
response summaries, and MCP tool annotations.

Squashed rebase of #5352 onto main.

* fix(environment): keep rendered documents and quoted samples inside their budgets

A recorded body of exponential numbers can render past 256 KiB and turn a
working read into a state size error, so that document stays a recorded replay.
Description samples are measured after JSON quoting, and the replay-fallback
catalog check uses a tool count the longer response descriptions still separate.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* feat(environment): apply evidence-gated write effects to the served state

Serve write tools whose later reads confirm the effect, and keep main's
state-file ownership and part-wise reply measurement.

Squashed rebase of #5600 onto the rebased #5352 tip.

* fix(environment): bound and validate write state history

* feat(environment): render more read tools from the state and describe responses

Keep main's environment serving and fold in coverage for non-entity reads,
response summaries, and MCP tool annotations.

Squashed rebase of #5352 onto main.

* fix(environment): keep rendered documents and quoted samples inside their budgets

A recorded body of exponential numbers can render past 256 KiB and turn a
working read into a state size error, so that document stays a recorded replay.
Description samples are measured after JSON quoting, and the replay-fallback
catalog check uses a tool count the longer response descriptions still separate.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* feat(environment): apply evidence-gated write effects to the served state

Serve write tools whose later reads confirm the effect, and keep main's
state-file ownership and part-wise reply measurement.

Squashed rebase of #5600 onto the rebased #5352 tip.

* fix(environment): bound and validate write state history

* fix(environment): bound additional collection history

* fix(environment): credit sent fields, negative sequences, and encoded targets

A later overwrite copied surviving derived fields into the sent-member
claim, so a members-only check rejected an update whose sent field still
matched. Serving floored sequences at zero and stored missing history as
zero, so a collection sequence learned from negative ranks skipped the
next value. An absence after a delete forgot the resolved collection, and
an encoded read could not observe an update spelled with another
collection encoding.

Regression tests cover each case.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* test(environment): cover resolved encoded update identities

* fix: validate timed update observations

* fix(environment): share write overlap and check clocks on earlier calls

Observation search skips a read begun before the write ended. That
comparison now uses the same overlap as the check path.

A clock learned on a later call was not checked against earlier calls
that kept the field. Serving would stamp those calls too, so the plan
stays unserved. A clock learned earlier is still refused when a later
call does not advance it.

Regression tests cover an overlapping empty update and a published_at
clock that one recorded call leaves unchanged.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix: preserve partial update evidence

* fix(environment): let an unmodelled write explain only the list members that differ

A failed whole-list read now reports which members alone account for the
difference. An unmodelled write excuses the read's writes only when it came
after each such member's last check and pending writes, so an older change
elsewhere no longer hides a newer write the list shows undone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 7b6aab9d7191e600051693f2c192afcfc743d083)

* fix(environment): explain added fields, tie creates to serving's collection, and bound write descriptions

An update explains a field the entity lacked before when the observing
view had shown the entity, so a server-filled field is not dropped. A
create is tied to the held collection serving picks for its path. Write
descriptions and body refusals quote member names and sample them within
a byte bound. The request body is indexed once per explanation, so copied
and slugged fields no longer rescan it.

Replays 07aca54e onto the restacked branch. Its rule that a read begun
before a write ended teaches nothing is already here (fb6785dc), so only
its test is kept.

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

* docs(environment): state how list reads weigh unmodelled writes, added update fields and quoted members

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

* refactor(environment): keep the observing view helpers with the observations

shownBefore and the item-or-list fields check move to the observe module,
keeping the write effects within the line limit.

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

* fix(environment): resolve unmodelled writes onto the held collection

An unmodelled path kept the request's collection spelling. An archive under
the plain spelling of a collection held encoded marked only that plain
collection unknown, so a later update was blamed for the archive's fields
and dropped. Name that entity the way a modelled write does.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(environment): confirm no write through volatile fields or overwritten replacements, and bound the served clock

A members-only check no longer compares volatile fields, which render
from the read itself. A document replacement credits the members it
wrote or removed at its object, so a later merge that overwrites them
takes its confirmation away. A recorded time past the range of a date
gives no served clock instead of throwing.

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

* fix(environment): leave unknown entities unchecked by failed reads, volatile fields and unchecked calls

A failed item read that is no absence leaves an unknown entity unknown, so
a later usable read still checks its writes. A read showing an unknown
entity again checks no write on a volatile field. An update of an unknown
entity takes its recorded outcome and adds nothing to a built plan. A later
update that does not answer with its entity is observed only by a read
whose view shows every learned clock; without one it is unmodelled.

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

* fix(environment): fill a create's path fields from the collection serving selects

The gate built a later create's path fields from the recorded request path,
while serving fills them from the held collection it selects for that path,
so a read showing the other spelling's parent could confirm a create serving
cannot reproduce. Rules still learn from the recorded path.

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

* fix(environment): name unmodelled writes as modelled ones, count fields updates write, and keep later members' types

An unmodelled write below an item path names its entity through itemTarget,
and one at or above a collection resolves the held collection, as modelled
writes do, so an encoded spelling no longer hides the entity it changed.
An update's answer counts the fields its rules write, other than increments,
as available, so a field only the update writes no longer makes it
incomplete-entities. A member a later call first stores keeps that call's
JSON type in the body's kinds, which the body check falls back to.

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

* fix(environment): let a document replacement overwrite everything under its object

A replacement claims only the members it wrote or removed, but it now
overwrites every earlier effect under its object, so a merge that wrote
the object it replaces loses its confirmation.

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

* fix(environment): start the served clock from the records whose times a date can hold

A record timed past the range of a date no longer leaves the served clock
without a start, which the store read as zero and stamped writes in 1970;
the clock starts after the latest record a date can hold.

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

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 14:15:35 +08:00
2e6b38cef0 feat(environment): render more read tools from the state and describe responses (#5352)
* feat(environment): render more read tools from the state and describe responses

Keep main's environment serving and fold in coverage for non-entity reads,
response summaries, and MCP tool annotations.

Squashed rebase of #5352 onto main.

* fix(environment): keep rendered documents and quoted samples inside their budgets

A recorded body of exponential numbers can render past 256 KiB and turn a
working read into a state size error, so that document stays a recorded replay.
Description samples are measured after JSON quoting, and the replay-fallback
catalog check uses a tool count the longer response descriptions still separate.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* test(environment): pin the replay card this branch serves

The replay-only card test pinned main's 11,131-byte card. This branch's descriptions name each tool's recorded responses, so the card it serves is 12,818 bytes; the pin and its name follow.

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

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 07:08:44 +08:00
166fb0820f feat(environment)!: serve the environment state by default (#5351)
* feat(environment): extract the initial state a capture's reads observed

Add the environment-state analysis view. From the parents the environment
manifest accepts, it extracts the data the capture's reads observed before
the first related write: entity types with an identity field (proved by a
path parameter or inferred from an identity name), entities with their
recorded values and provenance, documents for written non-entity paths, and
a render plan per read tool that is kept only when it reproduces the tool's
latest initial recordings from the state; every other read tool is a
recorded view with the reason. The Evidence is always inferred.

Response-body decoding moves to a domain owner shared with replay, exact
JSON parsing moves to the owner of the exact-number policy, the manifest and
state views share parent admission and record grouping, and
projectAnalysisView takes its accumulators as one object.

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

* fix(environment): bound state at redacted writes; infer identity only from items

A scenario write whose URL was redacted has no request line, so it was
dropped and reads after it counted as initial state. Such a successful
write now joins the timeline with an empty path, whose root relates to
every type, so it ends every type's state; a limitation counts them.

A list whose recordings were all empty passed the "every listed item
carries it" check vacuously and published an identity field nothing
showed; it now needs at least one item, else the view stays recorded
as no-identity.

A value that differed between two request lines of one item tool, such
as a query variant, was called volatile, and the gate then substituted
each recording's own value; only repeats of one request line now show
volatility, so differing lines go through fields-differ.

List membership is compared only while a list can still be the whole
collection, and merged entities are indexed by type and collection once,
so paged captures no longer cost pages times entities (8,000 pages of
40,000 entities: 5.7 s to 0.23 s).

Docs and the tool contract say scenario state keeps the capture's
redaction markers and how redacted writes bound it.

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

* fix(environment): keep first sightings, one list pointer and linear field unions

Entities took the order of the first plan observed, and item plans run
before list plans, so a complete list read before its detail reads came
out reordered and lost "all" membership; each entity now keeps its
earliest recorded sighting.

A list plan reused the first recording's pointer for later recordings,
so a later response that was itself an entity wrapping a list was read
as that list; every recording must now locate the same list.

The field union scanned its ordered list for every key, quadratic in an
object's width; a set now answers membership.

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

* fix(environment): keep post-write values and partial lists out of the initial state

A value that changed between repeats of one request line was named
volatile whenever no write under the type's own root lay between, so a
write under another root (for example POST /api/dashboards/db before a
second GET /api/search) left its effect in the initial state. Any
recorded write between the two observations now leaves every tool of the
type recorded with reason fields-differ instead.

A list was published with membership "all" even when a total or count
envelope member exceeded the number it listed. Such a counter now makes
the membership "recorded".

Also drop a stale doc comment on ObservedEntity.order.

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

* docs(environment): scope item-shaped and deleted written paths out of documents

State documents are held only for list-shaped paths a POST, PUT or PATCH
tool writes. Reads of item-shaped written paths and of paths that are only
deleted stay recorded views; the guide now says so and the spec defers them
to a later increment of #4933.

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

* fix(environment): count writes in flight when a value changes between reads

The volatility check compared write start positions with the two reads,
so a write already in flight when the earlier read started was missed and
its effect was named volatile. A write now counts when its interval
overlaps the span from the earlier read's start to the later read's end.

The check also ran once per changed field and scanned every write. It now
runs once per pair of observations, answered by a binary search over the
writes in timeline order and the latest end among each prefix.

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

* fix(environment): catch cross-tool changes across writes; read only item totals

A value that changed across a write was caught only between repeats of
one tool's request line, so a list read before a write and an item read
after it put the post-write value into the initial state. Changes are
now classified per entity in timeline order after observation: across
any recorded write, a change between repeats of a line or between two
lines of the type rewrites the type (every tool recorded as
fields-differ); with no write between, a repeat's change is volatile.
The classification lives in environmentStateMerge.ts.

Any numeric member whose name contained "total" or "count" counted as
an item total, so total_pages, account_id or page_count made complete
lists partial. Item totals are now members whose name tokens include
total or count and none of page, pages or per; a string of digits counts
as a number; and a set has_more, next or next-page token member also
marks the list partial.

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

* fix(environment): keep post-write observations out of initial state

* fix(environment): retain field provenance and bound state inference work

* feat(environment): serve tool calls from the environment state

`environment-serve --state <state.json>` serves an environment from the
initial state an environment-state view extracted. Read tools whose views
are state-backed answer from a live state store: item views render the held
entity into the recorded envelope, list views render the collection or the
recorded members, and document views return the held value; a missing entity
or one lacking a required field is refused, and requests the state cannot
answer fall back to their recordings with the reason. The /agentenv data
plane implements data/reset, data/add (a rea-state/v1 document as a data
part, base64 bytes, a file:// path or an https URL, validated and replaced
atomically) and data/get, and the card advertises those operations and an
intake declaration. Stage 1 is read-only: write tools are not served in
state mode. Without --state nothing changes.

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

* docs(environment): record verification after merging the state view's review fixes

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

* feat(environment)!: serve the environment state by default

environment-serve derives the environment state at startup by running the
environment-state view in-process on the capture with the manifest's
template rules, so an environment comes with its state and a user supplies
nothing extra. The derived Evidence is the same one inspect-analysis-view
produces by hand. --state is removed; --replay-only serves exactly the
stateless replay of main. When the state cannot be derived, or its catalog
does not fit the discovery budget, the server starts in replay mode, logs
the reason and reports it in the stop summary's `state`. Exported bundles
serve the state by default too: export derives it the same way, so the
verifier's tool count and checked answer match what is served, and the
README describes the served mode.

BREAKING CHANGE: environment-serve answers read tools from the derived
state and does not serve write tools unless --replay-only is given; the
stop summary reports `state` instead of `state_evidence_id`.

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

* fix(environment): bound data-plane replies, keep batch order, cancel intake on stop

- One /agentenv response is held to 64 MiB: replies are measured as they
  are produced and one past the budget becomes a -32000 error stating it.
- Every message of a batch enters the arrival-order queue on arrival, so
  another request's reset never lands between them.
- Stopping the server, or a caller leaving, cancels the active download
  and answers queued calls `cancelled` without running them.
- file:// URIs name only this host: another host or a network share is
  refused before anything is opened.
- A loaded view value may not give an entity another identity.
- List answers refuse a member lacking a field every recording carried,
  as item answers do.

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

* fix(environment): keep bodies too deep for the state's nesting out of the state

A recorded body at the JSON depth limit was accepted by extraction, then
nested a few levels deeper as a document or entity value, so sealing the
state Evidence threw and environment-serve and environment-export stopped
instead of falling back. stateBodyJson, the one rule extraction and
serving share, now treats a body nesting deeper than the limit minus 16
levels as unusable, so its tool stays a recorded view.

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

* fix(environment): measure data-plane replies before building them

83fcc739 bounded one /agentenv response to 64 MiB, but it still
serialized each reply whole before measuring it, so a batch of data/get
calls on a large state built every refused reply in full only to drop
it. Each reply is now measured in bounded JSON parts (the shared
jsonParts encoder), its parts kept only while it fits; a reply past the
budget is counted for its exact reply_bytes but never assembled. A test
checks that a refused read is never handed to JSON.stringify whole and
that its reply_bytes is exact.

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

* fix(environment): release batch replies as they are encoded; judge exact numbers by value

answerBatch kept every settled reply in its pending array until the
batch ended, so a batch alternating data/add and data/get held each
loaded state alive; each reply now leaves the queue as it is encoded.

The exact-number policy judged a number by its recorded spelling, so a
state loaded with 1e20 came back from data/get as
100000000000000000000, which data/add refused, breaking the promise
that data/get output loads back unchanged. A number is exact only when
both its recorded spelling and the one serialization writes are safe,
so integers from 2^53 below 1e21 are refused in any spelling; replay
keeps such bodies as recorded text. A domain test checks that every
accepted number is accepted again once written back.

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

* fix(environment): keep room for refusals and framing in the reply budget

The response budget counted accepted replies only: a budget error that
replaced a reply, and a batch's brackets and commas, were not charged,
so near 64 MiB later refusals pushed the body past the advertised
limit. Every reply still to come now keeps room for its own budget
error, and a batch keeps room for its framing, so a refusal always fits
and the body never passes the budget. Reply ids and which messages are
answered come from one place shared by the replies and the reserve.

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

* fix(environment): refuse a loaded state that data/get would write past the intake limit

data/add measured only the document it was given, while data/get
writes the state back with the members a document may omit (types, the
state Evidence id, view fields and record citations). A document just
under 32 MiB could therefore load and be reported larger than any intake
accepts, breaking the data/get then data/add round trip. replace now
measures the state as data/get writes it, part by part, and refuses it
past the limit, leaving the state unchanged. The limit moves to the
state document module, so the application store can read it; the
intake re-exports it.

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

* fix(environment): keep merged export checks on the shared test graph

Main's export tests installed module mocks for the whole services
project, which reuses one module graph. A tarball read failure then
missed its importer, and a one-shot heap mock could be taken by another
file. Read those through bindings the tests replace for one case.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(environment): keep a state file whose close failed owned until it closes

A file:// data/add that could not close its descriptor dropped the handle,
and an admission failure whose cleanup close failed dropped its owner, so
nothing could retry the close or report it.

The read now runs through withOwnedRegularFile, and a failed close is
retained in a server-lifetime ArtifactResourceScope. The next file read
retries it first and answers -32000 while it is still open; inline and
https documents still load. Closing the served environment retries it again
and rejects with the unfinished close.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-22 05:04:57 +08:00
3fca2e0ca6 feat(environment): extract the initial state a capture's reads observed (#5319)
* feat(environment): extract the initial state a capture's reads observed

Add the environment-state analysis view. From the parents the environment
manifest accepts, it extracts the data the capture's reads observed before
the first related write: entity types with an identity field (proved by a
path parameter or inferred from an identity name), entities with their
recorded values and provenance, documents for written non-entity paths, and
a render plan per read tool that is kept only when it reproduces the tool's
latest initial recordings from the state; every other read tool is a
recorded view with the reason. The Evidence is always inferred.

Response-body decoding moves to a domain owner shared with replay, exact
JSON parsing moves to the owner of the exact-number policy, the manifest and
state views share parent admission and record grouping, and
projectAnalysisView takes its accumulators as one object.

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

* fix(environment): bound state at redacted writes; infer identity only from items

A scenario write whose URL was redacted has no request line, so it was
dropped and reads after it counted as initial state. Such a successful
write now joins the timeline with an empty path, whose root relates to
every type, so it ends every type's state; a limitation counts them.

A list whose recordings were all empty passed the "every listed item
carries it" check vacuously and published an identity field nothing
showed; it now needs at least one item, else the view stays recorded
as no-identity.

A value that differed between two request lines of one item tool, such
as a query variant, was called volatile, and the gate then substituted
each recording's own value; only repeats of one request line now show
volatility, so differing lines go through fields-differ.

List membership is compared only while a list can still be the whole
collection, and merged entities are indexed by type and collection once,
so paged captures no longer cost pages times entities (8,000 pages of
40,000 entities: 5.7 s to 0.23 s).

Docs and the tool contract say scenario state keeps the capture's
redaction markers and how redacted writes bound it.

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

* fix(environment): keep first sightings, one list pointer and linear field unions

Entities took the order of the first plan observed, and item plans run
before list plans, so a complete list read before its detail reads came
out reordered and lost "all" membership; each entity now keeps its
earliest recorded sighting.

A list plan reused the first recording's pointer for later recordings,
so a later response that was itself an entity wrapping a list was read
as that list; every recording must now locate the same list.

The field union scanned its ordered list for every key, quadratic in an
object's width; a set now answers membership.

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

* fix(environment): keep post-write values and partial lists out of the initial state

A value that changed between repeats of one request line was named
volatile whenever no write under the type's own root lay between, so a
write under another root (for example POST /api/dashboards/db before a
second GET /api/search) left its effect in the initial state. Any
recorded write between the two observations now leaves every tool of the
type recorded with reason fields-differ instead.

A list was published with membership "all" even when a total or count
envelope member exceeded the number it listed. Such a counter now makes
the membership "recorded".

Also drop a stale doc comment on ObservedEntity.order.

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

* docs(environment): scope item-shaped and deleted written paths out of documents

State documents are held only for list-shaped paths a POST, PUT or PATCH
tool writes. Reads of item-shaped written paths and of paths that are only
deleted stay recorded views; the guide now says so and the spec defers them
to a later increment of #4933.

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

* fix(environment): count writes in flight when a value changes between reads

The volatility check compared write start positions with the two reads,
so a write already in flight when the earlier read started was missed and
its effect was named volatile. A write now counts when its interval
overlaps the span from the earlier read's start to the later read's end.

The check also ran once per changed field and scanned every write. It now
runs once per pair of observations, answered by a binary search over the
writes in timeline order and the latest end among each prefix.

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

* fix(environment): catch cross-tool changes across writes; read only item totals

A value that changed across a write was caught only between repeats of
one tool's request line, so a list read before a write and an item read
after it put the post-write value into the initial state. Changes are
now classified per entity in timeline order after observation: across
any recorded write, a change between repeats of a line or between two
lines of the type rewrites the type (every tool recorded as
fields-differ); with no write between, a repeat's change is volatile.
The classification lives in environmentStateMerge.ts.

Any numeric member whose name contained "total" or "count" counted as
an item total, so total_pages, account_id or page_count made complete
lists partial. Item totals are now members whose name tokens include
total or count and none of page, pages or per; a string of digits counts
as a number; and a set has_more, next or next-page token member also
marks the list partial.

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

* fix(environment): keep post-write observations out of initial state

* fix(environment): retain field provenance and bound state inference work

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
2026-10-19 20:33:46 -07:00
bf1eeee94f feat(environment): build environments from browser scenario captures (#5182)
Build an agent environment directly from retained capture_browser_scenario Evidence through the existing manifest, serve and export commands. Preserve request ordinals, source pointers, redaction markers, unavailable bodies, provenance and the default stdio MCP transport.

Followups admit copied/transformed text before body validation or decoding, avoid request-text allocation in replay, normalize portable file inventories, select dependent CI lanes, retain the author's redaction/body-budget corrections, and count body coverage over represented requests.

Validation: full pinned-toolchain static gate, source and public CLI/MCP regressions, canonical catalog checks, actual Chromium interactive and live GitHub API captures with exact HTTP replay and stdio parity, the generated non-root Docker image, and its smoke task through real agent-env 0.9.1334. Verification scopes, resource measurements and platform limits are recorded in the PR and feature verification document.

Co-authored-by: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 06:07:15 +08:00
7a0c47bfa4 feat(environment): export an environment manifest as an agent environment bundle (#4999)
Export an authenticated capture and environment manifest as a pinned agentenv bundle with provenance, a replay verifier and smoke task.

Followups preserve immutable input ownership, bounded discovery, caller paths and numeric values; bind bundle writes and package copying to retained filesystem owners; verify POSIX modes; retain cleanup authority; and verify framework/npm executable selection. Default MCP remains stdio.

Validation: pinned Linux toolchain, typecheck/build/lint/format/docs/knip, 452 focused tests, ten product-catalog cases, real GitHub response replay in the generated non-root Docker image, and the real pinned agentenv framework smoke workflow. Platform and resource-measurement limits are recorded in the feature verification document.

Co-authored-by: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-20 05:29:43 +08:00
10f1994fe1 feat(environment): serve an environment manifest as a replay environment (#4975)
Serve retained capture Evidence as a bounded MCP replay environment with discovery.
Preserve default stdio, caller-selected facts and complete source Evidence.

Fix numeric fidelity, argument identity, startup cancellation and bounded discovery,
query/path matching and output metadata. Verify real recorded API data and public
CLI/MCP workflows; preserve explicit gaps for Windows and third-party hosts.

Co-authored-by: Edgar Arakelyan <edgar.arakelyan@scale.com>
Co-authored-by: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 03:06:29 +08:00