* 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>
77 KiB
Historical web network captures
Use inspect_web_network_capture / inspect-web-network-capture to inspect
retained producer evidence. This is an offline operation: recorded URLs are
never fetched, and no browser or proxy listener is started.
rea inspect-web-network-capture /absolute/session.har har --json
rea inspect-web-network-capture /absolute/session.har har --record 2 --record 0 --json
{
"name": "inspect_web_network_capture",
"arguments": {
"capture_path": "/absolute/session.har",
"format": "har",
"record_ordinals": [2, 0]
}
}
Omit ordinals to return every record. Explicit selection preserves caller order and original zero-based producer ordinals; duplicate or out-of-range selections are input errors. Every record is validated before selection, so selecting one entry does not hide a malformed entry elsewhere.
For agent discovery over MCP, request detail: "summary". REA retains the
complete selected Evidence in the session and returns identity and counts.
Use normalized_result.parent_evidence_id with inspect_analysis_view:
{
"source": {
"kind": "retained-evidence",
"evidence_id": "<parent_evidence_id>"
},
"view": { "kind": "capture", "detail": "preview", "offset": 0, "limit": 20 }
}
Preview pages select recorded HTTP headline fields, event names/times when
present, original locations and byte descriptors; they omit headers, XML and
payload content. Choose detail: "complete" in that view for exact record
pages, including all sidecars. Offsets follow the parent's selected record
order; producer ordinals remain unchanged. total_records counts the original
capture while retained_records and page coverage count records in the parent.
An exhausted page does not establish absence from unselected records.
Views do not reopen the file or rerun its decoder. They remain historical
Evidence if the source changes or disappears; inspect the capture again to
observe new bytes. The inspection tool's default detail: "complete" preserves
existing inline delivery. For CLI use, save complete inspection JSON and pass
it as inline Evidence to inspect-analysis-view; the same summary and capture
page contracts apply. Large complete records can still exceed MCP's response
budget; export the retained Evidence when a single record cannot fit.
If decoding completes before cancellation or private-root cleanup fails, the failure retains the completed capture as Evidence with the requested record selection and explicit sensitivity exclusions. Earlier decode failures remain primary. Failed cleanup stays linked to its exact owner, including through redaction, and its live status clears only after a confirmed retry.
Formats and upstream profiles
HAR uses har-schema@2.0.0 draft-06 schemas, ajv@8.20.0,
ajv-formats@3.0.1, jsonc-parser@3.3.1 JSON visitor, and
lossless-json@4.3.1 numeric representations, pinned in the npm lockfile.
Only the HAR 1.2 profile is supported. Unknown extensions remain reported
evidence. Duplicate object keys, including equal values and escaped spellings,
are rejected before materialization. Prototype-named members such as
__proto__ are preserved as ordinary own JSON members without prototype
mutation. Original capture files remain unchanged.
REA owns specific schema corrections because pinned upstream schemas omit
object types and use the unrecognized min keyword. Following
HAR 1.2,
timings must be an object with nonnegative send, wait and receive;
optional blocked, dns, connect and ssl may be absent, -1, or
nonnegative. Entry time must be nonnegative; page onContentLoad and onLoad
may be absent, -1, or nonnegative. cache must be an object, while its optional
beforeRequest and afterRequest retain their specified nullable forms.
Invalid values fail with their source JSON pointer before record selection or
sensitivity projection. Measurements are not invented or repaired. Decoder
provenance names these corrections as har-schema-corrections@1.
The observed mitmproxy 12.2.3 SaveHar profile can emit postData.text: null
for a missing request body. REA preserves that reported null, omitting the
optional field only from its validation copy for this exact producer profile;
it does not invent an empty string or body bytes.
The observed Playwright 1.58.2 profile can report a bracketed IPv6
serverIPAddress, forwarded from Chromium's remoteIPAddress through
Playwright's HAR tracer.
REA preserves the original spelling in reported Evidence and removes brackets
only from its validation copy, only for this declared producer and a valid IPv6
literal. Invalid addresses, bracketed IPv4, ports and zone identifiers remain
validation failures. Producer declarations do not authenticate origin.
Native mitmproxy decoding requires a caller-supplied mitmdump 12.2.3 on Linux. Set its absolute executable path:
REA_MITMDUMP_COMMAND=/absolute/mitmdump rea inspect-web-network-capture /absolute/session.mitm mitmproxy --json
REA does not install mitmproxy. Its owned process uses a private configuration
directory, --no-server, and the unchanged upstream mitmproxy.io.tnetstring
decoder. It does not run FlowReader migrations or convert native states to
HAR. Raw IDs, state versions, flow types, backup states and unknown extensions
are preserved without synthesizing connections, timestamps or content. The
tested upstream source is tag v12.2.3, commit
6c09d56e4c29a92f5ad01b03199977584b8ea14f; other native tool versions return
an explicit unsupported-profile diagnostic. Non-Linux native decoding is not
supported by this adapter.
Reading Fiddler captures (.saz)
Fiddler Everywhere saves traffic in Session Archive Zip (.saz) files.
Inspect native SAZ directly, without installing Fiddler or converting to HAR:
rea inspect-web-network-capture /absolute/session.saz saz --json
rea inspect-web-network-capture /absolute/session.saz saz --record 0 --json
MCP uses the same capture_path, format: "saz", and optional
record_ordinals fields as the examples above. REA pairs raw/<id>_c.txt
requests, _s.txt responses, and _m.xml metadata by filename stem. Archive
member names identify the source; zero-based ordinals follow each session's
first member in ZIP directory order, not its numeric ID or capture time.
HTTP fields and ordered duplicate headers are retained, with stored body bytes
in binary sidecars. Bodies are not dechunked or decompressed. Metadata is an
XML node tree; optional _w.txt and _g.txt files retain opaque WebSocket and
gRPC message bytes. Missing members remain null, distinct from empty bodies.
A zero-byte _c.txt or _s.txt member, which Fiddler writes for a session
without that message, is also null and adds a record limitation.
See Telerik's SAZ format reference.
Protobuf and gRPC bodies
Selecting record_ordinals (CLI --record) also decodes retained bodies with
recognized protobuf or gRPC content types. Whole-capture inspection does not
perform this extra work. The original binary sidecar, SHA-256 and producer
ordinal remain the source; decoding adds flat body, frame and field facts.
Automatic binary Protobuf admission validates reserved MIME parameters:
encoding may be binary, while charset and the reserved version must be
absent. Illegal profiles retain the source body, add a limitation, and leave
protobuf coverage partial. Ordinary non-encoding parameters remain accepted;
an explicit framing choice interprets bytes independently of the MIME profile.
Admission follows HTTP token and quoted-string syntax: unterminated quotes and
conflicting repeated reserved parameters remain invalid. Repeated headers with
implicit binary encoding and encoding=binary agree without rewriting either
header. Invalid declarations remain visible even with explicit framing, and
declared gRPC bodies still receive credential checks before a MIME refusal.
An excluded HAR mimeType remains unknown for automatic interpretation even
when a visible Content-Type header exists. That header can still identify the
transport for credential checks; explicit wire framing remains independent.
Native gRPC admits only data-frame flags 0/1; gRPC-web additionally admits its
terminal trailer frame. grpc-web-text supports independently padded base64
chunks. Its offsets refer to base64-decoded body bytes; other offsets refer
to retained body bytes. Every field has a body-scoped field_id derived from
its byte offset, a frame_index, and a parent_field_id for schema-driven
nested messages or groups. Repeated field numbers remain separate occurrences.
Trailer blocks are parsed as HTTP field bytes. Valid UTF-8 values are retained;
when a field contains opaque non-UTF-8 bytes, that field is omitted and the
trailer frame is partial, while other valid trailer fields remain available.
The retained body and frame byte range preserve the original opaque value.
Without a schema, varints and fixed-width values retain exact unsigned decimal representations. Length-delimited UTF-8, nested-message and packed readings are candidates; REA does not choose one or invent field names or signedness. Nested candidate ranges remain accessible without recursively expanding them. Malformed messages retain the parsed prefix and an exact error offset. Compressed frames and encoded HTTP bodies remain unknown; they are not silently treated as empty messages.
For schema interpretation, supply a local compiled FileDescriptorSet and its
fully qualified message type. All imports must be included. REA never fetches
schemas or executes the selected application. Descriptor identity and parser
version remain in the body facts. Scalars, repeated numeric packing and nested
messages are interpreted alongside the unchanged wire facts; disagreements
remain explicit. Descriptor admission rejects duplicate field numbers within
each message, including nested messages and oneof fields, before schema
annotation. This does not reject repeated occurrences in captured wire bytes
or reuse of a number in a different message. Fully qualified message, enum,
service and extension names must also identify one declaration across the
descriptor set, including nested and synthetic map-entry messages. Different
packages or enclosing messages may reuse a local type name. Schema-admission
failures retain the partial capture Evidence and its original artifact identity.
REA also requires an unambiguous descriptor file identity. Repeated exact file
names are coalesced only when protobuf-es equality confirms matching field
presence, declared values and retained opaque unknown/custom-option fields.
Opaque fields must match in their retained order and bytes; REA does not
interpret them. Conflicting definitions are refused rather than selecting a
file by its position. This is REA's supplied-schema admission policy, separate
from protobuf wire validity and the first-occurrence precedence in protoc v32.1.
The descriptor-set byte count and SHA-256 continue to identify the complete
original input, including repeated file facts.
Map semantics, extensions and required-field validation are
unsupported. A supplied schema does not establish the sender's actual schema.
An invalid nested interpretation records schema_status: "invalid-message"
and schema_error locally; later outer fields remain available. Valid string
contents, including a leading U+FEFF, are preserved. Descriptor wire failures
name protobuf.schema.descriptor_set_path with the wire reason and byte offset;
a missing selected type names protobuf.schema.message_type. Duplicate field
numbers in a message are refused before registry construction, independently of
declaration order. Resource exhaustion and cancellation keep their own outcomes
and previously admitted capture Evidence remains available.
# Compile your own schema with your existing protoc, including local imports:
protoc --include_imports --descriptor_set_out=/evidence/api.pb api.proto
rea inspect-web-network-capture /evidence/session.har har --record 3 \
--protobuf-schema /evidence/api.pb --protobuf-message example.Response \
--detail summary --evidence_output /evidence/session-evidence.json --json
MCP accepts the same choices as protobuf: {schema: {descriptor_set_path: "/evidence/api.pb", message_type: "example.Response"}}, with explicit
record_ordinals. Optional body_pointers batch-select exact binary pointers;
framing can explicitly select raw, grpc, grpc-web or grpc-web-text
when MIME metadata is unavailable. CLI exposes --protobuf-body-pointer and
--protobuf-framing. Filters never invent bytes excluded by source redaction. Decoding an extra
base64 layer also checks explicit exclusions; newly recognized trailer
credentials exclude the entire affected binary sidecar and its reported
encoding, preserving a redaction coordinate instead of a credential digest.
Credential inspection covers every selected body before descriptor reads or
field expansion. Later capacity or schema failures can therefore retain the
sanitized source even with explicit sensitivity options. If that source pass
is interrupted, unchecked bodies are not published as partial Evidence.
Framing overrides apply only to format-owned body coordinates and preserve
exclusions for the transport declared in MIME metadata.
Explicitly excluded or conflicting MIME metadata is not treated as absent:
automatic framing leaves such a non-empty body uninterpreted, adds a record
limitation and keeps protobuf_coverage partial unless framing is selected.
Unknown or explicitly excluded HTTP coding metadata is not treated as absent:
SAZ/native bodies remain opaque until identity coding is established. Raw
header values and retained body bytes remain available in source Evidence.
Skipping wire analysis still runs the independent credential check. If HTTP
coding metadata is unavailable and that check cannot complete, the operation
returns unavailable without publishing unchecked capture bodies as Evidence.
Use detail: "summary", then inspect_analysis_view with its retained parent:
{"kind":"protobuf","collection":"bodies","offset":0,"limit":16}
{"kind":"protobuf","collection":"frames","record_ordinals":[3],"offset":0,"limit":16}
{"kind":"protobuf","collection":"fields","record_ordinals":[3],"field_numbers":[1,4],"fields":["number","schema_name","schema_value"],"offset":0,"limit":32}
Filters intersect; an empty filter selects nothing. Field pages also accept
field_ids, frame_indices and schema_names. Default field pages omit text,
schema_value and enum alias inventories; select these columns when needed. Identity, source offset
basis and body status survive column selection. Complete Evidence retains
all decoded values, and ordinary capture previews expose counts. Page exhaustion
covers retained facts only; a partial source does not establish absence.
Authenticated immutable parents reuse validation and the most recent field
filter per capture. These caches live only with retained Evidence, hold references
to existing facts and never reopen either file. Cached selector text is bounded
by retained field cardinality; larger selections use an uncached scan. Mutable
input is revalidated.
The existing 96 MiB report budget includes the original decoder reply plus
conservative charges for new facts, strings and descriptor expansion. The explicit
protobuf_coverage reports selected and inspected record counts, preserving
partial decoding through composed views. Capacity failure retains the source
observation as partial Evidence; cancellation yields
between bounded work batches. Real elapsed time and process-family memory
still depend on the selected capture and schema.
Fiddler Everywhere MCP and public skills
For agent-driven traffic debugging, connect Everywhere's MCP server separately
from REA. Run a current Everywhere release with MCP access (Trial, Pro, or
higher), internet access, and a compatible MCP client. Use
Settings > MCP Server > Coding agent, or Manual setup with the generated
API key. The default endpoint is http://localhost:8868/mcp. See Telerik's
MCP setup guide
and agent-skills prerequisites.
Telerik's public skills cover
installation (fiddler-download-setup), connection setup, and traffic analysis:
npx skills add telerik/fiddler-agent-tools --skill fiddler-mcp-setup
npx skills add telerik/fiddler-agent-tools --skill fiddler-traffic-debugging
After setup, reload the agent client and use the connected server's advertised
tool names and schemas. Check status, list sessions, then inspect relevant
session IDs. Set sessionsSource to LiveTraffic for HTTP(S) traffic or
AgentCalls for enriched LLM calls; active filters affect the session list.
For an existing run, skip the skill's pre-capture steps that replace process
filters and clear sessions. The documented MCP session sources do not provide
a saved-snapshot selector; use the SAZ workflow above for saved files. REA does
not register or wrap the Fiddler MCP server.
Reading the evidence
artifactidentifies the caller-selected file and stable snapshot digest.recordspreserve producer order/ordinals and original JSON pointers, byte ranges, or SAZ member names. No live browser transaction or scenario IDs are invented.reportedretains the producer's fields. HAR container metadata is returned separately, withlog.entriesreplaced bynullandrecords_pointeridentifying the record collection. This is an inspection representation, not a reconstructed HAR file.numeric_literalspreserve HAR number lexemes and native integer/float representations, including unsafe integers and non-finite native floats. Values that cannot be safely represented as JSON numbers arenullin the reported view. Schema-valid HAR numbers are admitted even when they cannot be published safely as JSON numbers; their exact lexemes remain innumeric_literals. Standard numeric fields must still satisfy the pinned schema, including integer requirements judged from the numeric lexeme.binary_fieldsretain exposed bytes, base64 and SHA-256 independently of declared sizes. Valid HARcontent.encoding: "base64"is decoded exactly; producer-decoded Unicode text, missing text and unknown encodings do not establish original body bytes. Response readers expose decoded text only whenencodingis absent or supported base64 bytes decode as UTF-8. Other declared encodings remain opaque: original text and encoding stay in Evidence, while replay and state extraction treat the decoded body as unavailable. A redacted encoding declaration does not establish plain text. See the HAR content representation. Post-data parameters do not reconstruct a multipart body. Native byte fields also have an exact UTF-8 display view when valid; binary sidecars establish their actual representation. Native missing content and empty content remain distinct.redactionsidentify known transport authentication exclusions and explicit sensitive-value exclusions. Redacted byte fields retain neither original bytes nor their digest. Unknown extension names and token-looking query parameters do not establish sensitivity. HAR authentication fields, transport URLs and base64 content are interpreted only insidelog.entries. Similarly named unknown fields in the document container remain opaque evidence; explicit sensitive-value declarations still apply to both scopes.
Mark sensitive literal string/UTF-8 byte values with MCP sensitive_values, or
repeat CLI --sensitive-value. These declarations are never persisted in
Evidence parameters; the count is retained. Explicit text/UTF-8 byte matches
exclude the entire field with a reported null rather than substitute a text
marker or rewrite payload bytes. This prevents replacement markers from
reintroducing declared literals. The file digest identifies the original artifact
unless it matches an explicit declaration; in that case artifact.sha256 and
Evidence subject are null with an explanation. A sensitive property name excludes that
entire property and its sidecars; a scope: "property-name" redaction points
to its actual parent. No substitute property name or child pointer is invented.
Omitted subtrees are still validated, including canonical HAR base64. Explicitly sensitive artifact
paths are empty in Evidence and omitted from locations, while the original
SHA-256 and size remain available unless the digest itself is explicitly excluded. Failure messages, diagnostics and cleanup
resources follow the same explicit declarations without changing error types;
sensitive issue pointers identify a real ancestor instead of a fabricated
coordinate. Header/cookie authentication values and known
transport URL userinfo are excluded structurally, including native backups.
HAR redaction and API-surface projection share the same recorded-URL parser.
Canonical userinfo spans are removed without rewriting the remaining source
text. Credential-bearing spellings without a safe raw span, such as slashless
or extra-slash HTTP URLs, are excluded as a whole transport field. Ordinary
extension text and noncredential path/query values remain unchanged.
Generated free-text limitations follow the same literal declarations, including global, per-record and Evidence explanations added during projection. Contract field names, typed discriminators and exact decoder identities keep their canonical meanings; declarations do not rename formats or providers.
Historical evidence does not prove runtime attribution, execution or deployment authenticity. Mitmproxy messages are upstream-assembled messages, not recovered wire fragments. Native dictionary duplicate keys have the unchanged upstream decoder's last-value semantics; this adapter does not claim to recover discarded duplicates or the original numeric spelling of parsed native floats.
Derived API surface
Pass retained HAR Evidence to inspect_analysis_view with
view: {"kind":"api-surface","offset":0,"limit":50}. Omitted offset and limit
are 0 and 50. The view groups request lines by method, WHATWG URL origin and
path template, sorted by origin, template and method. Query strings, fragments,
credentials, headers and bodies are not copied into groups.
Select include_query_parameter_names: true in the view to include distinct
observed query names per group. The default and explicit false omit the
query_parameter_names field. Selected groups include an array of
{name, record_ordinals} entries, sorted by Unicode code point; each name's
ordinals follow the parent's selected record order and occur once per record.
For /products?category=books&page=1 and
/products?category=games&sort=price, names are category, page and sort.
Query values and fragments are not copied into this inventory.
Names use WHATWG URLSearchParams form-query decoding: literal + becomes
space, %2B becomes +, percent escapes decode as UTF-8, and empty names are
retained. Empty query pairs are ignored. Original URLs stay in parent Evidence;
name decoding does not normalize the recorded paths used for grouping.
The inventory describes observed names, without inferring required parameters,
value types or a complete API schema. Sensitive-parent refusals still apply.
| Rule | Exact segment format | Placeholder |
|---|---|---|
numeric |
ASCII digits only | {numeric} |
uuid |
RFC 9562 textual UUID, any version, case-insensitive | {uuid} |
hex |
At least 32 hexadecimal digits | {hex} |
iso-date |
Valid calendar date YYYY-MM-DD |
{iso-date} |
Rules apply in table order to the recorded, still-encoded request path, read
before WHATWG dot-segment removal, so /a/%2e%2e/admin and /admin stay distinct. Segment indexes start
at zero after the leading slash. Each matched segment lists its observed literals
and basis: "inferred". templated_groups counts templated groups across every
page. Because paging follows the full grouping, every page is inferred Evidence
when that count is nonzero, and derived Evidence only when no group was templated. Version prefixes, short opaque IDs
and digit-bearing route names stay literal. Samples merge only when method,
origin, and exact segment rules match. The view does not infer further
cross-sample patterns.
Groups cite parent record ordinals and distinct statuses and MIME types (lowercase
type/subtype without parameters). An invalid type/subtype essence is unknown;
parameters do not affect this projection. Flags report single samples, mixed
statuses or mixed content types.
coverage pages groups; records separately reports examined, total and excluded
parent records. Ordinal subsets carry a limitation. Null URLs are excluded as
url-redacted; unparseable URLs, URLs without an origin, spellings without
scheme://authority (such as https:host/path), and authorities containing a
tab or newline as url-unparseable.
Unavailable request objects or methods are explicitly excluded. Unavailable
response fields, including HAR's status: 0 and an empty mimeType, remain
unknown, not invented statuses or MIME types.
The view makes no handler-identity, schema or causality claim. It performs no
network activity. Native mitmproxy, SAZ and qlog captures return a typed unsupported error.
Parents inspected with sensitive_values, or whose Evidence does not record
sensitive_value_count, return a typed unsupported error whose reason is the
canonical token sensitive_values_unretained. The view would write path
templates and limitation text that it cannot check against declarations the
parent does not retain, so the refusal does not repeat declaration text.
One accumulator owns group identity, observed-value/status/MIME sets, ordinals,
exclusions and deduplicated limitations. It scans path spans without splitting
literal paths into arrays. Before schema parsing, it reserves the capture clone
and validation scratch by walking the parent without cloning it. Inline requests
borrow the Evidence value through CLI/MCP envelope validation; the application
admits the entire portable envelope before authenticated parsing or hashing. An
evidence-file source is read and authenticated first and then admitted like
retained Evidence, so its strings are not charged as inline envelope text: a
capture too large to project inline can be projected from its file. Before
authentication REA checks that live heap headroom holds its copies of the parsed
Evidence, and over MCP the read follows the request's cancellation.
An invalid Evidence file returns EvidenceFileError with the selected path
and content_issues relative to the file's JSON root; those locations do not
refer to the request's source.path string.
The envelope clone, hash scratch and capture clone stay charged during grouping.
Temporary URL/path/MIME/query work and retained state must
fit together within a 96 MiB projection representation budget. A whole group or
merge is admitted before allocating its retained sets, map entries or array
values. Fixed group storage, distinct text, exclusions and limitations count as
well as matched segments. Per-record reservations are released after each
record; repeated values do not accumulate another retained charge. Only the
requested page is materialized as output groups.
Opt-in query projection reserves parser tuples and the per-record name set
before decoding, then admits distinct retained names and source ordinals before
changing a group. Repeated names within a request retain that ordinal once.
The representation budget uses conservative storage and worst-case JSON-escaping
allowances; it is not an enforced V8 heap or process-memory limit. It is separate
from the decoder's actual reply-byte limit and MCP transport admission. Exceeding
it returns resource_constraint without a partial view. Limitations on the
parent envelope, capture and examined records are deduplicated onto the view.
Portable captures must retain unique ordinals within their declared total;
caller-selected subsets can preserve any requested ordinal order.
Environment manifest
Pass retained HAR Evidence to inspect_analysis_view with
view: {"kind":"environment-manifest"} to project one application's recorded
request lines into a replayable tool surface: the environment manifest that an
agent environment later serves from retained Evidence. The view reuses the
api-surface grouping, then keeps the groups on the primary origin, the origin
with the most JSON-like records (application/json, application/*+json,
text/plain, text/markdown), whose path starts with /api/ or /apis/ or
whose content types are JSON-like, and the write groups answered with no body
(a bodiless 204 DELETE). Empty retained response text establishes a bodiless
write only when its encoding is understood and unredacted; an opaque or hidden
encoding leaves the body unknown. Every other group is listed under
excluded with reason other-origin, ui-page-or-asset or non-json, and
retained records without a usable request line are counted in a limitation.
The parent may instead be capture_browser_scenario Evidence whose scenario
selected response bodies or header values: each network transaction is then
one record, in request order, and the result names
parent_operation: "capture_browser_scenario" with an empty artifact, since
a scenario records no file. See
agent environments.
{
"name": "inspect_analysis_view",
"arguments": {
"source": { "kind": "retained-evidence", "evidence_id": "ev_..." },
"view": {
"kind": "environment-manifest",
"template_rules": [
"after-uid-literal",
"opaque-token",
"sibling-variance"
],
"include_query_parameter_names": true
}
}
}
origin and name identify the environment; the name is the kebab-case
primary host with dots and ports replaced by hyphens, grafana-example for
http://grafana.example. Each tool carries a deterministic name, method,
path_template, api_surface_template (the four-rule template of its
earliest record), params, query_parameter_names, body_shape,
statuses, content_types and record_ordinals. records lists one pointer
{ordinal, method, path, status, content_type} per record a tool cites and
never a header, cookie or body. Tools sort by template then method.
Without template_rules, every path_template equals the api-surface
template and params carry the four format rules with names id, uuid,
hash and date; a repeated name gets a numeric suffix. Opt-in rules apply
only when listed, each at most once (a repeated rule is an invalid_request),
in this order:
| Rule | Applies to | Parameter |
|---|---|---|
after-uid-literal |
The literal segment right after a literal uid, unless it is a stop word |
uid |
opaque-token |
A lowercase alphanumeric segment of twelve or more characters mixing letters and digits that is not a v1-style version |
uid |
sibling-pair-variance |
Groups equal in method, origin and segment count that differ in two adjacent literals right after a plural literal at index 2 or later and followed by a literal, with at least three distinct pairs and both positions varying (/repos/{owner}/{repo}/issues); stop words and v1-style versions never qualify |
singular plural literal plus _namespace, then _name |
sibling-variance |
Groups equal in method, origin and segment count that differ in one literal at index 2 or later; the siblings whose literal is identifier-like (a digit or :, or three or more hyphenated names under a plural literal) merge, never a stop word, and the other literals stay their own tools |
singular previous literal plus _id, else id |
prefix-variance |
A literal at a position that another tool, of any method or segment count, templates by one of the rules above after the same preceding segments, when the literal is one of that parameter's observed values, carries a digit and has the length and character classes (digits, lower case, upper case, each other character) of one, or has the single length of eight or more characters every observed value has and only their character classes; stop words and v1-style versions never qualify, and tools that now match merge |
the name of the parameter it shares |
With sibling-variance selected, literal siblings within its comparison scope
fold into existing opt-in parameters as observed values unless they are stop words.
For example, select both opaque-token and sibling-variance so
/api/folders/{uid} lists general beside the recorded token. With only
opaque-token, /api/folders/general stays a separate literal tool.
A position templated by one of the four format rules
absorbs no literal, so /api/teams/{numeric} keeps its exact-format meaning
and /api/teams/search stays its own tool. Opt-in placeholders use the
parameter name; format-rule placeholders keep their api-surface spelling. Tool names are
<method>_<literals> with api, apis, namespaces, default, v-prefixed
version tokens and a uid literal before a parameter dropped, dotted literals
cut to their first label, _by_<params> appended when parameters exist,
sanitized to [a-z0-9_], at most 60 characters and made unique with numeric
suffixes: get_dashboards_by_uid, get_plugins_settings_by_plugin_id.
prefix-variance runs last so it can share the parameters the other rules
produce: with sibling-variance, a PATCH or DELETE of the one entity a
session edited, /api/v1/collections/0RZ576QZQA5KG, becomes
/api/v1/collections/{collection_id} beside the reads that varied there, and
so do deeper routes such as /api/v1/collections/{collection_id}/books. Its
parameter is labelled prefix-variance, unless a merged tool templated the
position by its own rule. When parameters of different rules share a position,
a literal shares the one that observed it, else the earliest one it is spelled
like.
sibling-variance, sibling-pair-variance and prefix-variance compare routes of at most 32 segments; longer routes keep
their grouped templates and the manifest says so in a limitation. body_shape
is derived for POST, PUT and PATCH from the tool's earliest record when it
carries an application/json or application/*+json request body: top-level
keys and their JSON type names, never values and never nested structure; a body
on a later record adds nothing. unknowns always states three facts: the authorization model, response
semantics and state transitions are not established by a capture.
templated_groups counts tools and excluded groups with a templated segment;
whenever it is nonzero the Evidence is inferred, otherwise derived. The view
performs no network activity and replays nothing. Native mitmproxy, SAZ and
qlog captures, and parents inspected with sensitive_values, return the same
typed unsupported errors as the api-surface view, including the canonical
token sensitive_values_unretained. A capture_browser_scenario parent is not
refused for declaring secrets: the capture redacted them as it recorded, a
transaction whose URL was redacted is left unrepresented, and a response body
keeps the capture's redaction markers, which a manifest limitation counts.
The manifest accumulator shares the api-surface admission model: the capture
clone, the inline envelope (for an inline source), record pointers, groups, every route part, observed
values, query names and body-shape keys are admitted before allocation, and each
recorded body is charged as temporary bytes before it is parsed. Retained state and
temporary work must fit together within the 96 MiB projection representation
budget; exceeding it returns resource_constraint without a partial manifest.
Name a large capture with {"kind": "evidence-file", "path": "/abs/capture.json"}
rather than inline: response bodies the manifest never reads are then charged
once per value in the capture clone, not per character. A
capture_browser_scenario parent is also charged, before validation, for
checking its largest body and for the decoded text of its request bodies.
Environment state
Pass the same parent to inspect_analysis_view with
view: {"kind":"environment-state"} to extract the initial state the
capture's reads observed, and a render plan per read tool that reproduces those
reads from it. Where the environment manifest names an application's tools, the
state holds its data: entities by type and identity, plus documents for reads
that are not entities. Use the template_rules of the manifest the state
accompanies so tool names match; the view groups records the same way.
{
"name": "inspect_analysis_view",
"arguments": {
"source": { "kind": "retained-evidence", "evidence_id": "ev_..." },
"view": {
"kind": "environment-state",
"template_rules": [
"after-uid-literal",
"opaque-token",
"sibling-variance"
]
}
}
}
Records on the primary origin are ordered by recorded start time, or by record
order when any start time is missing (timeline), as for a
capture_browser_scenario parent. A POST, PUT, PATCH or DELETE with a
2xx or 3xx status, or no status, may change state, unless it is a POST whose
path has a segment such as search, query, list, find, fuzzy,
count or stats, which queries state instead. A type's state comes from its
successful reads that finished before the first such write under the same root:
the path's API base (the literal segments every tool sharing its first segment
has), any v1-style version segments, then one more segment. A read that
overlaps that write in time is left out. A write whose URL a scenario redacted
has an unknown target, so it ends the state of every type, and a limitation
counts such writes. Values from a capture_browser_scenario parent keep the
capture's redaction markers in place of declared secrets; the state is not
refused for them, as the manifest is not.
Each GET tool whose template ends in a parameter is an item tool, and its
type's collection_template is the template without that parameter; any other
GET tool is a list tool of its own template. Empty segments are ignored, so a
trailing slash names the same collection. An item tool proves its type's
id_field when every initial response carries the requested path value in the
same field of one entity object (id_basis: "path-parameter"). The object is
the response itself or one wrapper member; failing both, it is the only element
of a one-element array at the root (pointer /0) or in one member
(/<member>/0), as in {"posts":[{...}]} or {"data":[{...}]}, provided one
of the identity names below repeats the value, since a filtered list may also
answer with one element that repeats its parent's value. Otherwise the field is
the first of id, uid, uuid, _id, ID, UID, Id, guid, key,
slug and name that every listed item carries as a distinct string or
number; when none does, it is the first key of the first listed item, in its
order, whose name ends in Id or _id (such as orgId or user_id), that
every item carries as a distinct string or number, and that at least one
initial response shows distinct across two or more items
(id_basis: "field-name"). A single listed item is distinct from nothing, and
its suffix-named fields are often foreign keys, so a list that only ever held
one item is left to a document. Empty initial lists constrain no field. A list
is the response array, or the one array of objects in an envelope that is not
itself an entity, preferring an array whose items an identity name identifies,
then an array of two or more items a suffix-named field identifies.
entities merge every initial observation of one identity within one
collection path: an item view's latest values win over a list view's, a view
whose latest values differ keeps them in view_fields, and a field whose value
changed between one tool's observations with no recorded write between is named
in the type's volatile_fields, keeping the latest value. A value that changed
across a write under another root may be that write's effect, so the type's
initial reads end at the earliest write within the change, reads that overlap
it are left out, and the state is extracted again once; the same holds for a
value one tool read before a write and another tool read after it, and for
repeated reads of one full request line whose list membership changes across a
write, including transitions to or from an empty list, or whose entity fields
are added or removed. A type whose reads still disagree keeps every tool a
recorded view with reason fields-differ. Different query strings remain distinct request lines. Sparse responses do not erase the last observation of a field supplied by another request line. Entities are ordered
by type and collection, and within a collection as the first line that lists
every entity any initial read shows in it and names no sort, direction or
random parameter (random, rand, shuffle, seed) lists them; a collection
without such a line keeps its entities' earliest sightings. That order is a
list's state order.
Every entity cites its record_ordinals.
views lists one plan per read tool in tool order:
| Shape | Plan |
|---|---|
item |
The entity object at pointer (the root, one member, or /0 or /<member>/0), the ordered fields the view shows and the required_fields every recording had, and envelope_ordinal: the recording whose response, with the entity replaced, every item response shares, leaving out the per_response_members each response there mints: a top-level UUID or clock that differed on every repeat of every concrete path the view answers, with no write between, and never stayed the same on a repeat elsewhere; list views name theirs too |
list |
The array at pointer, its fields, membership (all: every entity of the collection in state order, when each recording listed exactly that, had no query or only paging parameters (limit, offset, page, per_page, perpage, page_size, pagesize, size, start, _start, _end), no item-total member (total, count, totalCount, item_count, totalcount, itemcount, numberOfElements, but not total_pages or per_page; a number or a string of digits; top-level, or in a top-level object beside the list such as pageInfo.totalRows) differing from the number listed, and no has_more, next or next-page token member set; recorded: the entities each recording listed, except on the lines all_record_ordinals names, which each meet those conditions on their own and list every entity), and counters that equal the number listed |
document |
The latest initial value of a list tool whose responses hold no identified list, when its initial reads share one request line; held in documents with that path, whether or not the capture writes it, unless its value changed across any recorded write between those reads (fields-differ); its per_response_members are the members of the value each response on that path mints |
recorded |
A reason the tool replays its recordings instead |
An item or list plan is kept only when it reproduces the latest initial
recording of each request line from the state, comparing JSON values without
regard to member order; a volatile field compares its recorded value. Each
plan lists the checked_record_ordinals. A request line that shows the
entities in another representation (an expanding or reducing query, or one
asking for some fields only) is left out of those checks when a query key tells
it from the others: the plan lists its latest recordings in
projected_record_ordinals and the keys in projected_query_keys (name,
with a value or absent: true), and serving replays calls matching them and
calls asking for fields the checked lines do not show.
Otherwise the tool is a recorded view
with reason envelope-varies, fields-differ or list-differs; the other
reasons are query-body (a query POST, or one the capture shows only reading), no-init-recording,
body-unusable, no-identity (an item read without a proved identity),
path-varies (another read under more than one path, as a template with a
parameter before its end), query-varies (another read of one path under
more than one query) and rendered-oversize (a document value whose JSON
renders to more than 256 KiB). A document holds the value of its one path, so for such
a template it says nothing about the template's other paths. A body is usable
when its content type is
JSON-like, it is UTF-8 text of at most 256 KiB, every number survives native
conversion exactly, and no member is named __proto__.
A list view also learns, from its checked lines that do not list the whole
collection, what each query parameter does, and names the result in query.
Each such line is explained by the first combination of roles that lists
exactly what it recorded from the collection's initial entities:
| Role | Parameter | Effect |
|---|---|---|
filter |
any other, on a field every listed item holds the value in; one not named like the field (shelf, or shelf_id, for shelf) stands only when lines giving it two different values agree on it |
entities whose field equals the value as text, or whose array field holds it directly or as an object's id, slug or name |
search |
q, query, search, searchTerm, term, keyword(s) |
entities with one of fields containing the value, ignoring case; the fields are those it matched in the listed items, URLs only where nothing else matched; a term that matched no field leaves the parameter inert until another line's term does |
sort |
a name asking for an order in any common spelling: sort, _sort, sort[], sort[0][field], sorters[...], sortBy, sort-column, sortKey, order, orderBy, ordering |
ordered by the field the value names (name, -name, name:desc, name-ASC): numbers by value, text ignoring case, null last ascending, ties in state order |
direction |
a direction name (dir, direction, sortDir, sortOrder, sortDirection, order_direction, json-server's _order, and order) given asc, desc, ascending or descending; given anything else, order is a sort and the others are ordinary parameters |
the sort's direction |
limit |
limit, per_page, perPage, page_size, size, count, take, itemsPerPage |
page size; zero or a negative value lists every match |
offset |
offset, start, _start, skip |
matches skipped before the page |
page |
page |
page number, counted from first (1 or 0, whichever explains the line) |
inert |
any that names no order or direction; never a true reverse, or a paging value that is not a safe integer |
changes nothing for its recorded values; other values are not computed |
No two parameters of one call take the same sort, direction or paging role,
and a line with more than 12 query parameters is left unexplained. Lines that
disagree on a parameter's role drop it, inert values gather and search fields
unite. query.record_ordinals are the lines the merged roles
reproduce, envelope and fields included, and query.totals the envelope
members that count every match before paging on each of them, top-level or one
level down in a paging object (/pageInfo/totalRows); a number-of-items
member counts the page. The roles are inferences from the
recorded lines; a line they do not reproduce keeps its recorded members.
writes lists one plan per tool whose request may change state, in tool
order. Its effect is create for a POST to a type's
collection_template, update for a PUT, PATCH or POST to that template
plus one trailing parameter, or to that item path plus one action segment,
delete for a DELETE to it, document for a PUT, PATCH or POST to a
document's path, an update or delete of each entity a write at the
collection names by id in its body, and otherwise none with reason
no-state-target. A plan is built from the tool's first successful call: its
request body must be a usable JSON object (as response bodies are usable), and
the written entity must show in that call's response or in a later read before
the next write. Each field of a created entity gets the first rule that
explains it: generated identity (a sequence, UUID or token, by the recorded
value's shape), echo of a body member, copy of a body string of 8 or more
characters, a path value, a slug of a body member, a clock value within 10
minutes of the request in its recorded format, a sequence one past the
largest value of its collection or type, a unique UUID or opaque token, a
nested-clock object whose clocks the request stamped, or a template around
a generated value; other fields keep the observed value. A body that wraps one
object in a one-element array is that object, wrapped so on every call
(body.envelope). An update's members
echo when stored as sent; a member stored differently is accepted only with its
recorded value (body.fixed) and stores the value the call that showed it
recorded (the value of its constant rule), and a field it changed without
sending must be a clock, a nested clock, an increment, a slug, a fresh unique
value, a stamp of the acting user, a value derived from the one member it
stores nowhere, or for an item action a set of a scalar to the value it
showed, or the plan is unexplained-change; an increment, slug, stamp, derived
value or set must hold for every call of the tool, and an action is served
only once a call found what it sets already set. A write is served only
with the query its first call sent, which serving applies to a call that
leaves a parameter out and the catalog advertises as required. Every member the first call sent is required, except by PATCH and
POST updates.
A read on a line query answers is checked against the query evaluated over
the replayed state. It covers the collection only when every parameter sorts or
pages and the answer holds every match; otherwise it covers the entities it
lists, and those the line or the read listed that the state no longer holds.
The view then replays the timeline on a copy of the initial state. Modelled
writes apply their effect; only a 2xx write is modelled or an example, and
any other write (a redirect, an unanswered or unmodelled one) leaves the entity
below whose item path it wrote unknown until a read shows it again (a whole
collection when the path names no held entity), and taints what it wrote at or
above. A read the served environment would answer from the state is compared
with its recording as the read plans are, as the whole response it would serve:
the entity or list rendered into the envelope of the item view's or the line's
base recording, with the members the state still holds. A 400, 404 or 410 (or a
null body) agrees with an entity the copy does not hold. A match confirms
the writes that changed its entity or collection since it was last read, less
those whose entity a read since showed absent, which no longer count for the
collection; a mismatch contradicts them, or, when an unmodelled write came after them, is
checked only on the members they sent; a mismatch no write explains marks the related writes since as
side-effect. A plan is served when a read confirmed it and none
contradicted it; otherwise its reason is the first of its build reason
(no-call, body-unusable, no-observation, unexplained-change),
contradicted (with contradicted_by), side-effect, unconfirmed and incomplete-entities (an update or delete that answers with the entity, when no initial entity holds every field its recorded answer shows, counting for an update the fields its rules write, so it could answer only for entities the environment created).
checked_record_ordinals lists the confirming reads, insert places created
entities (sorted by a field the collection's recorded order shows, else last),
and write_clock is the end of the last timed record, to the next second.
Values in the state are recorded data, so the view refuses the same parents as
the manifest, including those inspected with sensitive_values, and a
capture_browser_scenario parent must have selected response bodies. Types and
identity are inferences, so the Evidence is always inferred. unknowns states
that the state establishes no authorization model, no way the application
computes responses or derived values, and write effects only as modelled from
recorded calls. The state
accumulator charges the manifest's admission and grouping, every record line,
each body as temporary bytes before it is decoded and parsed, and every value
it keeps, within the same 96 MiB budget. Documents hold whole recorded response
values whose recorded text and rendered JSON are each at most 256 KiB, so a
capture with many read-only paths yields a correspondingly larger state result.
The view performs no network activity and serves nothing; rea environment-serve
derives it from the capture at startup, serves read tools and the served write
plans from it and loads replacement states through the AgentEnv data plane, as
serve from the state describes.
Environment coverage
view: {"kind":"environment-coverage"} with the same template_rules reports
what the state an environment derives from the parent would serve, without the
state's entities: reads.state counts read tools answered from the state,
reads.recorded those that replay their recordings with
reads.recorded_reasons per view reason, writes.served lists the write tools
whose effect later reads confirmed, and writes.withheld lists every other
write tool with its reason, the record its plan was built from
(exemplar_ordinal), the read that disagreed (contradicted_by) and a hint
about what to record next. Hints are advice; they never change what is served.
The view projects the environment-state view and summarizes it, so it refuses
every parent that view refuses, with the same errors, and it is always
inferred. Call it after each recording to see which writes an environment
built from it would serve. It does not apply the serve-time admission checks:
an environment whose served catalog exceeds the discovery budget, or whose
state exceeds what data/add loads, serves replay, and rea environment-build
then reports coverage: null; otherwise the build prints this summary as its
coverage. See
Build a bundle in one step
for the hint per reason.
Resource and lifecycle boundaries
Complete evidence has a 32 MiB input, 96 MiB decoder reply and 64-level nesting
budget. Those budgets have no runtime override. capture_timeout_ms does not
raise them. Exceeding a budget returns no partial success.
Oversized selected captures return an input error identifying capture_path
and the byte budget; owned reply/output failures remain output or provider errors.
An explicit complete-reply refusal names the 100663296-byte allowance and its
lack of a runtime override. Record selection, paging, delivery mode and worker
memory do not increase that allowance; a smaller producer export is a narrower
observation, and the refusal leaves no completed capture Evidence to retrieve.
Cancellation during reply-file finalization retains validated completed capture
facts as partial observations. Malformed or unvalidated replies are not promoted.
HAR, SAZ and qlog run in an owned Node old-generation heap with one V8 worker.
REA_CAPTURE_DECODER_OLD_GENERATION_MIB is a decimal integer of mebibytes from
8 to 16384. Unset uses 192, the previous constant. Invalid values fail
configuration and name the setting; they do not fall back to 192. The setting
is read from the environment that starts REA, so a change needs a restart.
A memory failure names the effective mebibytes, whether they came from the
default or the setting, the default, the floor, and the maximum. The decoder
passes that value as --max-old-space-size and removes inherited
NODE_OPTIONS, so additional host memory and NODE_OPTIONS do not raise the
heap. The 8 MiB semi-space stays fixed; a smaller old generation aborts Node
during startup instead of enforcing a limit. Mitmproxy decoding applies
Linux limits of 768 MiB address space, 30 seconds CPU and 96 MiB file output;
both commands use capture_timeout_ms (default 30000) and independently supervised
process cleanup. Owned decoder diagnostics retain at most 1 MiB across stdout
and stderr; the collector drops overflow as it arrives, reports the limit
failure and verifies cleanup. Heap limits alone do not establish aggregate RSS limits.
SAZ and qlog refuse decoding when neither a Node heap limit nor a Windows Job Object bound can be enforced. Existing HAR availability is preserved.
When REA runs on Bun, the HAR/SAZ/qlog decoder runs on Bun, which ignores these V8 heap
flags; its limitations and resource failures then omit the V8 heap sizes. On
Windows, the decoder's owned Job Object instead limits its committed memory to
the effective REA_CAPTURE_DECODER_OLD_GENERATION_MIB value plus a 512 MiB
reserve for Bun itself. The default 192 MiB setting therefore yields 704 MiB.
The limitations state that limit, and reaching it returns resource_constraint
with process_memory_limit_bytes, whatever exit status Bun reports. Other Bun
hosts enforce no decoder heap limit, so raising the setting does not bound them.
Observed decoder memory exhaustion returns resource_constraint, with the
selected capture, applicable limits and retained process diagnostics. Raising
host memory or NODE_OPTIONS does not raise the old-generation heap. Set
REA_CAPTURE_DECODER_OLD_GENERATION_MIB and restart REA.
Record selection happens after complete decoding and does not reduce that
workload. Use a smaller capture exported by its producer or another decoder
with sufficient capacity, retaining the original for provenance. Subsets do
not establish complete-capture coverage. Repeating the same workload or
running provider health diagnostics does not resolve the heap constraint.
Stable regular-file reads reject symlinks, replacement and concurrent changes. Private snapshots, declarations and tool configuration are removed before the result returns. Cleanup uncertainty retains the selected capture, resource and original failure information. The original capture is never changed.
Excluded coordinates and read failures
Explicitly marked values also exclude matching source coordinates and their sidecars. A hidden record coordinate is reported as location.kind: "unknown"; REA does not invent a replacement pointer. Original record ordinals and artifact digests remain available.
Host filesystem read denials return code: "access_denied", category: "unavailable", the actual EACCES/EPERM code and read-access guidance. Missing files remain input failures. Cleanup failures retain the prior structured error, including its input constraints or provider diagnostics, with explicitly marked text excluded.
An observed replacement or in-place change during stable artifact acquisition
returns code: "artifact_changed", category: "integrity_mismatch" and
retryable: true, retaining the selected path and reader's reason. Wait until
the capture file is stable before retrying. No unstable snapshot is decoded.
Command cleanup failures retain the original status and both diagnostic streams;
the decoder's ownership preparation receives the same cancellation signal.
MCP advertises the same strict named input contract used by the application. Historical inspection delegates argument validation to that shared application boundary so accepted explicit-sensitive declarations also cover invalid argument names and other correction details. The SDK receives raw arguments through its Standard Schema interface; malformed inputs still fail before decoder or filesystem effects and return the normal structured REA error. Protocol-envelope validation remains owned by MCP.
Retained aioquic qlog
Select format: "qlog" through inspect_web_network_capture, or:
rea inspect-web-network-capture /absolute/origin.qlog qlog --json
rea inspect-web-network-capture /absolute/origin.qlog qlog --record 95 --record 0 --json
The initial profile is aioquic 1.5.0, JSON qlog 0.3: one JSON object with
qlog_format: "JSON", qlog_version: "0.3", traces containing object events
with name, finite numeric time and object data. JSON-SEQ, JSONL, columnar
array events and other versions are unsupported. Duplicate JSON members,
malformed UTF-8, invalid interpreted QUIC integers and excessive nesting fail
without partial success, including in events outside the selected ordinals.
Well-formed event subsets and missing frame metadata remain inspectable.
Unknown extensions are retained; this is not validation of every qlog schema.
Choosing the format selects the interpretation profile; the file does not
necessarily report or authenticate an aioquic version. The profile's clock
uses Unix-epoch milliseconds, verified in aioquic 1.5.0's QuicLoggerTrace
log_event/encode_time. The qlog.clock.basis and Evidence analysis profile
state that assumption explicitly. Numeric lexemes survive independently of
safe JSON-number projections; decimal spelling does not establish physical
clock precision or monotonicity.
Every event has a global ordinal from trace/event source traversal and its
original /traces/T/events/E pointer. This order is not a global time sort.
Trace index and the selected artifact identify a connection observation;
reported ODCID is preserved without claiming global uniqueness. Streams are
scoped by trace, stream ID and sent/received direction. Control/QPACK streams
are retained, so counting streams does not count HTTP requests.
qlog is a typed facet required exactly for this format. Its scope is
all-recorded-events-before-selection: selection changes returned event
records while facts cite the original ordinals across the entire recorded
file. The container retains trace metadata with each events array replaced
by null; there is no single events pointer shared by all traces.
| Fact | Basis and limits |
|---|---|
| Original event and loss declaration | Observed endpoint report; recovery:packet_lost does not prove actual network loss. Missing packet number/type remains unknown. |
| STREAM ranges and byte totals | Derived per trace and direction from reported offsets and lengths using exact integer arithmetic. unique_bytes unions intervals; frame_length_sum includes overlaps; repeated_bytes is their difference. Overlap alone does not prove retransmission or equal contents. |
| FIN final sizes | Reported offset plus length where FIN is true; multiple conflicting sizes remain visible. A final size does not establish complete coverage or a received body. |
| Incomplete fact records | Ordinals with omitted/redacted interpretable frame metadata, including an unknown STREAM FIN; usable fields such as known ranges in that record survive. An empty list does not establish complete logging or capture. |
| HTTP bodies and causality | body_bytes: "not-reported"; lengths and headers are metadata, with no reconstructed body, hash, timing causality or live process attribution. |
QUIC integer fields interpreted here accept exact nonnegative JSON integer
values through 2^62 - 1, including equivalent exponent notation. Offsets plus
lengths must fit that range. Derived sums are decimal strings and are not
rounded to JavaScript numbers. A missing offset is unknown, never defaulted to
zero. Ranges can start above zero or contain gaps. Packet headers, HTTP events,
raw lengths and unknown extensions remain producer evidence rather than being
normalized into invented HAR requests.
The adapter excludes authorization/proxy authorization/cookie/set-cookie values in known HTTP frame events, reset tokens in transport parameters and NEW_CONNECTION_ID frames, and NEW_TOKEN frame tokens. Known URL header userinfo and explicit sensitive values follow the shared exclusions. Ordinary extension fields and token-looking query text remain retained. Explicit declarations also cover normalized numeric projections, derived totals and trace pointers; facts that cannot be safely shown are omitted with incomplete-record coordinates. No keylog, PCAP, live URL or recorded target is opened by the qlog decoder.
To repeat the real-provider lane with local caller-supplied evidence from the educational aioquic 1.5.0 experiment (one origin trace, known 32,803-byte stream coverage and one 1,169-byte repeated range in the loss case):
npm run verify:web:qlog -- /absolute/control/origin.qlog /absolute/loss/origin.qlog /absolute/new-report.json
This lane checks built CLI/stdio MCP parity, SDK-converted JSON Schemas, artifact digests, original event count, selection scope, retained parent lookup, credential exclusions and the known control/loss facts. The report is created exclusively and contains no keys or captured credential values. It is a fixture-specific verification, not a general loss detector. CI uses synthetic format inputs for malformed cases and limits; those tests do not establish producer provenance. PCAP parsing and correlation remain outside this stage.
Focused qlog views
Use MCP inspect_web_network_capture with format: "qlog", detail: "summary"
for identity, profile, scope and retained-fact counts. Then pass its
normalized_result.parent_evidence_id to inspect_analysis_view as a
retained-evidence source.
{"kind":"qlog","facet":"traces","offset":0,"limit":10}
{"kind":"qlog","facet":"streams","trace_index":0,"offset":0,"limit":10}
{"kind":"qlog","facet":"contributions","trace_index":0,"stream_id":"0","direction":"sent","offset":0,"limit":20}
Trace pages omit nested lists and give their counts. Stream pages preserve
exact byte totals but omit contributions, ranges and final-size lists. For
those lists select contributions, ranges or final-sizes with all three
stream selectors. loss-declarations and incomplete-records need only
trace_index. Offsets count rows in that retained facet; defaults are 0 and 64. Missing or ambiguous selectors fail rather than choosing a connection.
These views page already interpreted facts without decoding again or opening
the source, and work after its deletion. Facts still cover all recorded events
before parent record selection. Their exhaustion does not prove logging or
network completeness. Event preview/complete pages remain available through
kind capture, with original numeric lexemes and producer ordinals preserved.