Files
reverse-engineering-anything/docs/specs/agent-environments/state-view/spec.md
T
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

11 KiB

Environment state view from captures

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

Outcome

inspect_analysis_view accepts view: {"kind": "environment-state"} for the parents the environment manifest accepts and extracts the initial state the capture's reads observed: entity types with an identity field, entities with their recorded values, documents for written paths whose reads are not entities, and a render plan per read tool that reproduces the tool's latest initial recordings from the state, or a recorded view with the reason it cannot. This increment adds the view kind only; serving from the state, loading another state through the AgentEnv data plane and modelling write effects are later increments.

Requirements

  • Accept inspect_web_network_capture HAR parents and capture_browser_scenario parents that selected response bodies, with the manifest's admission: the same format, subject and sensitive-value refusals.
  • Group records exactly as the manifest does for the same template_rules, so tool names match the manifest the state accompanies.
  • Order primary-origin records by recorded start time, or by record order when any start time is missing, and say which. Bound each type's state by the first write under its root (API base, version segments, one segment); a query POST is not a write, a read overlapping the write is left out, and a write whose URL was redacted bounds every type, with a limitation counting it. A successful POST elsewhere bounds a type's state too when its response named an id (an identity member, or a bare or sole scalar of four characters or more) that the type's reads show only once it began: the POST made that entity, so it is not in the initial state. A read finished before the POST began shows what was there, and one still running may show its effect. A list read shows the ids its listed entities carry as their own identity members, an item read its path's id only when its body shows the item (a JSON null shows none), and across two or more of them, when no id-named field (id, uuid, …; not key, slug or name) identifies them, the first suffix-named field (projectId) distinct on each, so a foreign key beside an id is none of theirs, nor are the ids of entities they nest. An id shorter than four characters counts only when the type was read before the POST and an item read names it after.
  • Prove an item type's identity field from the requested path value its responses repeat; otherwise infer it from a fixed list of identity names that every listed item carries distinctly, which needs at least one listed item. An item read that asked for some fields only (fields, fields[...], select, $select) and does not return the item is left out of the proof and of the view's checks; the view lists it in projected_record_ordinals. Beside a line showing whole entities, a list line asking for some fields only (a projection value other than *, which asks for all) is listed there too, and proves no identity or membership. So is an item line first recorded after the type's initial reads, judged against the lines left once variants are dropped: one that names a shaping parameter none of them named while its object carries or lacks members theirs do not, such as a later ?expand=shelf read, or one that selects some fields and leaves out members they always show, such as a later ?fields=id,name read. On a view with such replayed reads, serving replays a call naming a projection parameter for an entity the state holds unless every value it gives is * or one a checked line gave, and no replayed read gave it. The write gate leaves out exactly the successful reads serving replays, and any read that names one and leaves out a field its view requires, which serving would answer whole.
  • A request line of an item or list view is a representation variant when it shows an entity another line shows with other members, or names a parameter the base lines do not (paging aside) while its objects carry a member no base object carries or lack one every base object carries. Base lines are taken first: lines naming no such parameter, then lines asking for every field, then the line most others agree with. A variant leaves the view's checks, the entity observations and the membership changes that would end the type's initial reads when a query key tells it apart: a parameter only variants name, a value no base line gives a parameter, or a parameter every base line names that a variant leaves out. The view lists its latest recordings in projected_record_ordinals and the keys in projected_query_keys; serving replays a call matching a key with the reason variant (projection when it leaves out a projection parameter every base line names; a projection value is tested as above), so the answer is a recording and shows no served write. The write gate neither checks nor learns from a successful read serving replays; a 400, 404 or 410 such a read answers is still the absence it checks.
  • A field every recording of a view carried is required: serving refuses an entity lacking it. Once a successful read the write gate checks, naming no projection parameter, shows the application leaves the field out of an entity the state holds (APIs that omit empty or false members), no view of the type requires it. Never treat an envelope that is itself an entity as a list.
  • A top-level UUID or clock member that differs on every repeat of a path's successful GET lines with no write between, and across the capture differed on at least two repeats and never stayed the same, is minted per response there (a request id). A view names it in per_response_members only when every concrete path the view answers independently proves it minted. A collection's proof does not establish that its item paths mint the same member. The shared envelope compares without these common members, and serving keeps their recorded values; an unproved envelope difference stays recorded rather than borrowing another path's value.
  • Merge observations into one entity per collection and identity: item views' latest values win over list views', differing views keep their own values, and a value that changed between repeats of one request line with no recorded write is volatile and keeps the latest; a change across a write under another root, including between two tools of the type, ends the type's initial reads at the earliest write within the change, and the state is extracted again once; a type whose reads still disagree keeps every tool recorded. Compare list membership, including empty lists, and field presence before selecting each request line's latest recording; a change across a write ends the type's initial reads the same way. Different query strings remain distinct; omitted fields do not erase their earlier observations on other request lines.
  • An item or list view whose recordings always spell a clock field's instant otherwise than the entity's stored value (Z against +00:00, another separator or fraction width) names that spelling in clock_formats; a field it also shows as stored, or spells two ways (counting values at another instant), gets none. A stored value the view never recorded, such as one a write made, is rendered in that spelling: its wall clock in the view's zone, under the view's separator, with its own fraction digits padded with zeros to the view's width and none dropped; an epoch spelling is computed from the instant.
  • An item or list view names in sorted_arrays the fields it lists as string arrays in code-point order whatever order they were written in (tags kept as a set). Only the write gate learns it. A field is a candidate when every initial entity shows it as a sorted string array or null, one with two distinct strings, and no read the gate counts has listed it unsorted with two distinct strings. It is learned from a counted read that fails with the stored order and passes with the field sorted, and only when that read lists a written array in an order that is neither the written one nor values the initial state held first, then the new ones as written (an application ordering by tag id or creation shows that order too). The stored value keeps the written order, so a write's own answer echoes it; every view of the type for which the field is still a candidate sorts it as well.
  • A collection's initial order is the order of the first line that lists every entity any initial read shows in it and names no sort, direction (sort[], _sort, sort-column, sortKey, orderBy and like spellings) or random parameter (random, rand, shuffle, seed); a collection without such a line keeps its entities' earliest sightings.
  • A list has all membership only when no item-total envelope member (total, count and their compounds, not page counts), at the top level or in a top-level object beside the list such as pageInfo.totalRows, differs from the number of entities it lists and no has_more, next or next-page token is set. Such a member that equals the number listed is a counter; a nested one is named by its pointer (/pageInfo/totalRows), and members beside it such as isLastPage stay as recorded.
  • Keep an item or list plan only when it reproduces each request line's latest initial recording from the state, comparing JSON values without regard to member order; otherwise record the tool with a reason. Parse bodies only when JSON-like, UTF-8, at most 256 KiB, exactly representable and free of __proto__ members.
  • Mark the Evidence inferred; state unknowns for authorization, response semantics and write effects.
  • Charge the manifest's admission and grouping, every record line, every body as temporary bytes before decoding and parsing, and every kept value, within the existing 96 MiB budget. A planning pass that a rewrite cut discards releases its charges before the state is extracted again.
  • Read response bodies through one domain owner shared with replay, and parse exact JSON through the owner of the exact-number policy.

Acceptance and limits

The Grafana-shaped HAR fixture with distinct start times drives domain, service, MCP, CLI and acceptance coverage: folders merge their detail and list views under a proved uid, the dashboard entity is read from its /dashboard wrapper, and the annotation list after the annotation write has no initial recording. Synthetic captures cover write bounds, volatile fields, complete lists with counters, each recorded reason and documents; the scenario fixture covers record order and the response-body requirement. The view performs no network activity and serves nothing. Values copied outside entity objects, derived values and cross-type effects are not tied to the state.

Deferred issue criteria

Serving tool calls from the state, data/reset, data/add and data/get on the environment data plane, exporting the state with a bundle, and write effects are later increments of #4933. So are documents for item-shaped written paths (one per identity rather than per template) and for paths that are only deleted; until then their reads stay recorded. This PR must reference rather than close the issue.