Repository navigation
feat(browser): save values in browser scenarios and send them in later steps - #7162
earakely-scale wants to merge 28 commits into
Conversation
Request steps can save strings and numbers from their JSON responses and send them in path placeholders, query, headers and the JSON body; a header can send Basic credentials built from a username and password. The skill reference teaches both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- click and press steps take save_response {method, path, save}: the
recorder waits, before the step acts, for the 2xx JSON response to the
request it triggers and saves values from it
- {saved:name} sends a saved value in a request path (and its query), a goto
URL, and a request's JSON body, where a string that is only the
placeholder keeps the saved JSON type; header values and Basic
credentials parts take {source: "saved", name}
- Basic credentials take parts: [username, password], each a literal,
secret, saved, cookie or local storage value, so the schema repeats the
part union once; path_params and json_values are gone, which keeps the
compact MCP catalog under its 1 MiB frame
- validation refuses a saved value no earlier step saves; other braces are
sent as written
- Evidence records an empty save list as absent, so scenarios that save
nothing record the same parameters and scenario_sha256 as before
- environment-build warns about saved values named like credentials that
are not marked secret (credential-named-saved-values)
- the skill writes the way the UI does and falls back to request steps;
skill version 50
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The example created its object with a request step, and agents copied it even where the UI writes the fields the server needs (EspoCRM). It now fills a form and saves the id from the response the Save click triggers. A request-step write coverage withholds is recorded through the UI instead, and Basic credentials are no longer offered as a way around the UI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Outcome, plan, tasks and verification for saved values, save_response and Basic credentials, with the agent-built comparison against main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
[Medium impact] The PR appears safe to merge; no new actionable issue was established. SummaryAdds saved response values and Basic credentials to browser scenarios, then uses those values in later requests and navigation.
Review was source-only; no tests were run. Supersession status could not be checked because authenticated GitHub access was unavailable. DiagramsequenceDiagram
participant Step as Scenario step
participant Browser
participant Values as Saved values
participant Records as Capture
Step->>Browser: Request or UI action
Browser-->>Step: Matching response
Step->>Step: Check size, UTF-8, JSON and selected values
Step->>Values: Save typed values
Values->>Records: Register secret spellings
Step->>Values: Resolve later references within step budget
Step->>Browser: Send filled request or navigation
Browser->>Records: Record observations with redaction
Reviews (11) · Last reviewed commit: "test: assert the refused-slug plan has a..." · Reviewed by Greptile |
…templates on later creates Recording through the UI let Grafana generate folder uids, and three write model gaps then served folders whose address kept the first folder's slug: - a template around a generated value won over a composed string that also reads the title's slug; the composed string now wins when it reads a field besides the template's value - later creates checked composed strings against their own answers, but not templates, so coverage served a template a later folder contradicted; a template is now checked the same way - a slug dropped `&`, which Grafana's Go slugs spell as the word; a slug rule or part learns `ampersand: "and"` from the call that shows it, and calls that slugged no `&` agree with either spelling An address whose uid equals its title's slug could come from either field. The entities the type holds now pick the one reading they share, and when they cannot, a later create that tells the fields apart lends its composed rule to the first create, whose body contract is learned again with it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o clear earlier attempts The skill asks agents to delete what an earlier attempt created before recording again, since the environment holds a leftover as seeded data (EspoCRM's fresh run). The spec and verification record the write-model fixes, the same recordings rebuilt before and after them, and a fresh recording of every application. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 812f9ff2fa
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
- Basic credentials and values saved with `secret: true` are redacted however short, as declared secrets are; page values keep the 8-character floor - a literal Basic password other than empty is refused, since Evidence records literals as written - `save_response` takes only a request the step starts, so an earlier autosave cannot answer it, matches its path as the browser spells it, and stops watching requests when the step ends - saving reads are bounded: a request step streams its answer up to 4,000,000 characters; a UI step refuses a larger received size unread - goto placeholders fill the destination URL before structured query values join it - reading a composed string stops at the reading cap before comparing or allocating more - a slug's `&` spelling follows every create the plan accepted and every held entity; direct slug rules and composed strings take it from held entities when the create slugs none, and a slug rule they contradict is not learned Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
212063f addresses all eight Greptile findings and the three Codex findings; each thread has a reply naming the fix. Verified at 212063f:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 212063ff6c
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…alues # Conflicts: # src/domain/analysisView/environmentStateWriteApply.ts # src/domain/analysisView/environmentStateWriteChanges.ts # src/domain/analysisView/environmentStateWriteComposed.ts # src/domain/analysisView/environmentStateWriteCreate.ts # src/domain/analysisView/environmentStateWriteExplain.ts
… written
- a saved integer past 2^53, which JSON parsing would round to another id,
fails the step that saves it
- request paths and JSON strings read only `{saved:name}` as written; the
percent-encoded spelling is read only in a goto URL, whose parsed form
spells braces that way
- a held slug that neither `&` spelling gives counts as unknown: a create
whose slug spells `&` learns no slug rule beside it, and no later create
widens the spelling
- `save_response.path` takes the request path's portable pattern, shared as
START_ORIGIN_PATH, so JSON Schema clients compiling it with the `v` flag
read it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Second review round: e42362c fixes the three Codex findings on 212063f (replies in each thread), after merging main 2b84efe. The merge resolved one conflict with the JSON-field ownership refactor; this branch's new field reads now use Verified at e42362c on Node 24.22.1, with dependencies reinstalled for main's zod 4.6.6:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 98f18cc52c
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cannot carry - Each read of a saved response (the wait, sizes() and text()) races the step's deadline and abort signal, so a body still arriving when the step times out or is cancelled saves nothing, and the watcher detaches at once. - A UI step keeps the 4,000,000-character cap and refuses before reading only a response received as more than 12,000,000 bytes, three per character; the decoded text is then held to the character cap. - A Basic username with a colon fails the step before anything is sent. - A saved `.` or `..` that fills a whole URL path segment fails the step, since the URL would drop it. - Held entities that spell `&` both ways leave a create without `&` no slug rule. - The saved-values example in the browser scenario contract is a whole scenario, as the catalog test reads every documented example. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Third review round:
The saved-values example in the browser scenario contract is now a whole scenario, which fixes CI's Verified at
|
…gment Each filled path segment is checked after substitution, so a saved `.` that a literal dot or `%2e` beside it turns into `..` fails the step in a request path and a goto URL, before URL parsing drops it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7b2e780776
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
A saved number that is not finite, such as `1e400`, fails the step that saves it, since a later step would send it as null in JSON and as Infinity in a path or header. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A later update whose slug spells `&` as the word refines a slug rule an earlier update learned from a name without `&`, as creates do, unless an accepted call or a held entity dropped it. Every earlier retained update is rechecked under the refined rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d0d7c248ba
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…ter creates that omit derived fields - A later update whose slug slugs no `&` keeps the plan's `and` spelling; only a later rule that spells `&` as the word where the plan drops it is rechecked against earlier calls. - A later create whose response leaves out a `composed` or `template` field the plan rebuilds is withheld as `unexplained-change`, since serving would add the field; an omitted reference still passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A scenario keeps at most 4,000,000 characters of saved values at once, counting the current value of each name and the redaction spellings secret saves keep, and a save that would exceed it fails its step before anything is kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d39f386d20
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…e spellings a secret save adds - A UI step reads a saved response only once its decoded size is bounded before reading: the bytes received, or the declared length of one served from cache, times DEFLATE's 1,032 maximum expansion for gzip or deflate, must stay within 12,000,000 bytes. Another content coding (br, zstd) or an unknown size fails the step without reading. - The saved-value cap counts the redaction spellings a secret save actually adds, its trimmed spelling included and an already held one not again, so re-saving the same secret does not grow the total. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…held entities do - A saved number whose JSON spelling names another decimal than the parsed value, such as `1e-400` (parsed to 0) or `1.0000000000000001`, fails the step that saves it, checked against the number's source text through the `JSON.parse` reviver. - An update plan's slug rule takes the spelling of `&` that the entity's earlier value and the type's other entities show, as a create's does, and held entities that spell it both ways leave no slug rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 81a275b130
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…re building them A saving response is decoded as fatal UTF-8 in both the request step and a UI step's save_response, so a malformed byte fails the step instead of saving U+FFFD in its place. A secret save first counts a lower bound on its redaction spellings from the value alone (it and its longer percent-encoded spelling), and refuses there when that cannot fit, before any spelling is built. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lue fills, and pin a refused slug's source A secret's redaction spellings include the one a URL's query parser gives the percent-encoded value (`'` as `%27`), so a saved secret sent in a query is redacted from captured URLs. Saved values fill at most 4,000,000 characters into what one step sends, counted before each fill is built (percent-encoded in a path or goto URL, as text in a header or JSON body), so a value referenced many times fails the step instead of multiplying. A create whose slug the held entities' `&` spellings refuse keeps the recorded slug, so it now accepts the member slugged only as recorded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9f5191ab0f
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| url: request.url(), | ||
| }) | ||
| ) | ||
| started.add(request); |
There was a problem hiding this comment.
Tie saved responses to the dispatched UI action
When Playwright is still waiting for locator actionability, a periodic or background request with the same method and path can begin after this listener is installed but before the click or press is dispatched; watch adds it and waitForResponse can settle on its response first. The step then saves an unrelated ID under the caller's name, so a later request can edit or delete the wrong object. Tie candidate request identity to the actual input dispatch, or reject ambiguous matches, rather than treating every post-listener request as triggered by the action.
AGENTS.md reference: AGENTS.md:L21-L21
Useful? React with 👍 / 👎.
| ); | ||
| const pass = await credentialPart(step, password!, `${label}.password`); | ||
| const encoded = Buffer.from(`${user}:${pass}`).toString("base64"); | ||
| secrets.admitCredential(label, encoded); |
There was a problem hiding this comment.
Budget derived Basic credentials before retaining them
Fresh evidence beyond the aggregate saved-value fix is that one request can declare many Basic headers which share a large declared-secret username and use distinct short saved passwords, and every header is resolved before dispatch. This call permanently retains each distinct Base64 credential and recompiles all redaction patterns, while SavedFill charges only the short saved parts and MAX_RETAINED_SAVED_CHARACTERS does not charge these derived values, so a single admitted scenario can exhaust memory before fetch; preflight and account the encoded credential spellings in a retained-state budget.
AGENTS.md reference: AGENTS.md:L53-L54
Useful? React with 👍 / 👎.
| if (match === null) return undefined; | ||
| const [, sign = "", whole = "", fraction = "", exponent = "0"] = match; | ||
| const digits = `${whole}${fraction}`.replace(/^0+/u, ""); | ||
| if (digits === "") return "0"; |
There was a problem hiding this comment.
Preserve negative zero in saved numeric values
Fresh evidence after the numeric round-trip fixes is that a response number -0 reaches this branch with no significant digits, so decimalOf returns "0" and accepts it as equal to String(value). JSON.parse had preserved negative zero, but later path/header substitution and JSON.stringify emit positive 0, which changes the selected value for consumers that distinguish signed zero; reject -0 or retain its source representation.
AGENTS.md reference: AGENTS.md:L33-L33
Useful? React with 👍 / 👎.
| } | ||
| let spellings: { readonly tree: unknown } | undefined; | ||
| for (const { name, json_pointer, secret } of entries) { | ||
| const value = pointerValue(parsed, json_pointer); |
There was a problem hiding this comment.
Reject array metadata in saved JSON pointers
When a response is {"ids":["a","b"]} and a save uses /ids/length, pointerValue skips the numeric-index branch and then Object.hasOwn reads the JavaScript array's own length, so this new save path stores 2 even though the JSON contains no member at that pointer. A later write can therefore send computed runtime metadata as if it were response evidence; array traversal should reject every non-index token.
AGENTS.md reference: AGENTS.md:L19-L19
Useful? React with 👍 / 👎.
|
Thank you for the substantial saved-values work and the detailed review follow-ups. #7267 builds on this proposal and credits its original work, but says it compared changes through an earlier head; this PR has since moved. Could the contributors coordinate on one review path and check the later fixes here against #7267 before consolidating? I am leaving both open while that comparison is made. |
Save typed response fields and reuse generated IDs or authentication values across browser scenario requests, UI observations and navigation through the shared CLI/MCP workflow. Preserve exact numbers, retained Evidence, explicit source/coverage limits and prospective page-value semantics. Bound response decoding, retained spellings and request serialization before allocation, and protect marked response values across source records, follow-up text and planned screenshots. Integrates Edgar Arakelyan's #7162, including follow-ups through 9f5191a. Final local validation: 560 feature-branch tests and 561 current-main integration tests, static/build/docs checks and real PocketBase CLI/MCP privacy workflows. Whole-task comparison and verification limits are recorded in docs/verification/browser-saved-values-2026-10-26.md. Co-authored-by: Edgar Arakelyan <edgar.arakelyan@scale.com>
|
Thanks — compared #7162 at |
Summary
An agent that builds an environment from a prompt records the application with one browser scenario. Until now a
scenario could not carry a value from one step to a later one:
application assigned. Agents chose their own ids where the API allows it, or read lists back instead.
be sent. Miniflux's agent stopped and asked for an API key.
This PR lets steps save values and later steps send them:
requeststep saves[{name, json_pointer, secret}]from its JSON response. Aclickorpressstep saves fromthe response to the request it triggers, with
save_response: {method, path, save}, so a create made through theUI yields its id.
{saved:name}sends a saved value in a request path (and its query), a goto URL, and a JSON body, where a string thatis only the placeholder keeps the saved JSON type. Header values and Basic credential parts take
{"source": "saved", "name"}.{"source": "basic_credentials", "parts": [username, password]}, each part aliteral, declared secret, saved value, cookie or local storage entry.
folder uids, which exposed three gaps; this PR closes them (below).
Results, agents building seven applications from the same prompts, with main and with this branch:
environment to 3/3, and Vikunja from 0/5 to 3/5.
0/2 to 2/2.
Problem and expected behavior
URL, a JSON body or a header.
use it.
Change and scope
browserScenarioValues.ts,browserScenario.ts):saveon request steps,save_responseon click and press, thesavedvalue source in headers and credentialparts,
basic_credentialswith two parts, and{saved:name}(a parsed URL's percent-encoded form included).{id}, are sent as written.PlaywrightScenarioRequest.ts,PlaywrightScenarioActions.ts,BrowserScenarioSecrets.ts):save_responsestarts waiting before the step acts and fails the step unless a matching 2xx JSONresponse arrives before its timeout.
secret: trueis redacted from later records.BrowserScenarioEvidence.ts): an emptysaveis left out of the recorded step, so parameters andscenario_sha256are unchanged for scenarios that save nothing.(
credential-named-saved-values).src/domain/analysisView):composedstring that reads a field besides the generated value atemplatewould rebuild it around wins overthe template, so Grafana's
/dashboards/f/{uid}/{slug(title)}is composed when the uid is generated.templatefields against their answers, as they checkcomposedones, so coverage no longerserves a template a later create contradicts.
&:ampersand: "and"on aslugrule or composed part, learned from thecall that shows it. Calls that slugged no
&agree with either spelling.one reading they share. When they cannot, a later create that tells the fields apart lends its composed rule to
the first create, whose body contract is learned again with it.
holds a leftover as seeded data.
and
docs/specs/agent-environments/scenario-saved-values/.Not included:
fillandselect_option;Contract and boundary impact
src/domain/browserScenarioValues.ts)and its Playwright runtime.
capture_browser_scenarioacceptssave,save_response, thesavedsource,basic_credentialsand{saved:name}.outputSchemaProfile.test.tsmeasures. A first design withpath_paramsandjson_valuesfields failed that test.save_response.pathuses the request path's portable pattern, now shared asSTART_ORIGIN_PATH.scenario_sha256.environment-stateviews may carryampersandon slug rules and parts; earlier REA versions refuse views that do,as the schemas are strict. Earlier views parse unchanged.
save_responsewaits for a response on the start origin.Expected effects:
Evidence and regression coverage
Agent-built environments. Claude Code (
claude-sonnet-5-5) built each environment from the same prompt with mainff6d96b (skill 49) and with this branch, on freshly seeded instances. Each bundle's write tasks ran with
fireworks_ai/gpt-oss-120bandfireworks_ai/glm-5p3-flash, each checking the result from the environment's state.The branch's recordings, rebuilt before and after the write-model fixes (gpt-oss, GLM). Only Grafana's plans change:
Paperless's plans are identical in both builds; its GLM difference is the eval model's.
Fresh recordings, main and the final branch:
"Served" counts the write tools the final capture serves; tasks are gpt-oss then GLM. Paperless and Grafana were
recorded twice on main.
delete, and every category task passed in all three branch recordings.
save_responseon UI writes.example and wrote through the API, which EspoCRM answers in a shape the write model withholds (0/3); the example now
creates through the UI. The second showed Grafana's UI-made creates served with wrong addresses (0/2); the write-model
fixes above close that.
folders sorted by title, the recording renamed a folder to a title that sorts first, and REA keeps an updated entity
where it was in a list. Main's REA reads this recording the same way, and would serve its create with the template
that keeps the first folder's slug. Main's two recordings passed because their titles kept their order.
holds it as seeded data and the "nothing else changed" checks fail. The skill now asks agents to delete such objects
before recording again; that was not measured.
member its recorded calls sent, so a task sending a URL and a title is refused.
built by main and by this branch: 524 plans and 247 served on each. Three plans differ, all Grafana folder creates,
whose
urlthe branch composes from the uid and the title's slug.Real Chrome, a local application with a cookie-session UI and an API that takes only Basic auth:
/items/{saved:item1}.{"name": "Child of {saved:item1}", "ref": "{saved:item1}"}, which was sent as{"name":"Child of 101","ref":101}.Tests added:
credential part;
save_responsepaths and an empty save;save_responsewaiting before the click and matching method, origin and{*}segments, and failing without amatching or 2xx response;
credential-named-saved-valueswarning;&spelling is learned from a later create, a dropped&stays dropped and a create spelling it otherwise iswithheld;
Each fails on main.
save_responseignores a request already running when the step began, matchesMy ListagainstMy%20List,refuses a response whose received size is over the cap without reading it, and stops listening when the step
fails (passes on 812f9ff, which never listened);
&an accepted create showed, takesandfrom held tags, and learns no slug rulethey contradict; a composed address takes
andfrom held folders;unbounded work).
%7Bsaved:item%7Dneeds no save and is sent as written;&spelling gives keeps a create that slugs&from learning a slug rule, and leaves a createwithout
&its plain rule.For evidence-bearing changes:
Validation performed
Fifth review round at
9f5191ab0(mainca3fd7bamerged), on macOS with Node v24.22.1:6f6c61613fixes Greptile's three findings on22a93fadc: a saved secret is redacted as a URL's query spells it onceparsed (
'as%27); a step's saved-value fills are counted before each is built against a 4,000,000-character budget(percent-encoded in a path or
gotoURL), so repeated references fail the step before it sends; and a create whoseslug the held
&spellings refuse accepts the slugged member only as recorded. Its six tests fail on22a93fadc;9f5191ab0makes one of them check the plan's body is present first.3de21ef5dmerges mainca3fd7ba.typecheck,check:fast,format:check,knip,docs:check,mcp-catalog:check,verify:test-discoveryandscan:todos: passed.domain+services+adapters: 18,758 passed, with the same two failures as main. Browserboundary tests and
webArtifactReadOwnership: 1,223 passed, with the twosazWebCapturefailures main has.ca3fd7baand this head: 524 plans and 246 served on each (main's anchorless-clock change withholdsone Vikunja label update on both), with the same three Grafana creates differing.
Fourth review round at
22a93fadc(maindd7a2da5merged), on macOS with Node v24.22.1:81a275b13came from main as merged for that run:662ec2e45leftscripts/verify-apk-signature.mjsunformatted (main fixed it in
741f2de75), andwebArtifactReadOwnership.test.ts, which passes on this branch,failed only in that merge.
723fe02c8merges maindd7a2da5.22a93fadcdecodes a saving response as fatal UTF-8 in both save paths, so a malformed byte fails the step instead ofsaving U+FFFD, and bounds a secret save's spellings from the value before building any (Codex follow-ups). Its four
tests fail on
723fe02c8.typecheck,check:fast,format:check,knip,docs:check,mcp-catalog:check,verify:test-discoveryandscan:todos: passed.domain+services+adapters: 18,673 passed; the Inspector stat test andSetupRegistrationPrewarm's detached-descendant test fail, as they do on maindd7a2da5. Browser boundary tests andwebArtifactReadOwnership: 1,223 passed; twosazWebCapturetests fail, as they do on main.dd7a2da5and this head: 524 plans and 247 served on each, with the same three Grafana createsdiffering.
Third review round at
69f38a78b(maina30ffd27merged), on macOS with Node v24.22.1:7b2e78077then checks each filled path segment after substitution, so a saved.that the text beside it turns into adot segment fails the step (Greptile's follow-up); its tests fail on
69f38a78b,check:fastpasses andsrc/browser/passes 1,043 tests.
a712f52e2saves no number that is not finite (1e400), andd0d7c248blets a later update refine an ambiguous slugspelling as creates do (Codex follow-ups); their tests fail on
7b2e78077.check:fast,docs:checkand 2,852 browser,write-model and environment tests pass, and the 109-capture census stays at 524 plans and 247 served.
22ac315c3keeps an update's word spelling of&for a later name without one and withholds a later create that omitsa composed or templated field;
d39f386d2caps the saved values a scenario keeps at 4,000,000 characters. Their testsfail on
d0d7c248b;check:fast,docs:checkand 2,859 browser, write-model and environment tests pass, and the censusis unchanged at 524 plans and 247 served.
059322048reads a saved response only once its decoded size is bounded (gzip/deflate by DEFLATE's maximum expansion;br, zstd or an unknown size fail the step) and counts only the spellings a secret save adds;
81a275b13saves no numberJSON parsing changes (
1e-400,1.0000000000000001) and spells an update's&as held entities do. Their tests fail onthe head each thread was reported on;
check:fast,docs:checkand 2,880 browser, write-model and environment testspass, and the census is unchanged at 524 plans and 247 served.
98f18cc5: saved-response reads bounded by the step's deadline and abort signal; the4,000,000-character cap kept, with a 12,000,000-byte bound before reading; Basic usernames with a colon refused;
dot-only saved path segments refused; mixed held
&spellings leave no slug rule. It also makes the saved-valuesexample a whole scenario, as the product catalog test requires. Each new test fails on
98f18cc52.tsc,check:fast,format:check,docs:check,mcp-catalog:check,verify:test-discovery,scan:todosandjscpd: passed.knipreports onlyisToolFamilyId, as main does.domain+services+adapters: 18,201passed, with the Inspector stat test failing as on main. Product catalog, output schema profile, MCP schema
validation, tool schema validity, the environment build and serve CLI, served-writes MCP and analysis-view CLI
boundaries: 8 files, 75 passed.
a30ffd27and this head: 524 plans and 247 served on each, with the same three Grafana createsdiffering; none of this round's fixes changes a plan.
Earlier rounds:
Run on macOS with Node v24.22.1 at e42362c (main 2b84efe). Agent recordings ran on Ubuntu 24.04 VMs with snap
Chromium.
npm run typecheck,lint:built,format:check,metadata:check,verify:architecture-guards,knip:production,lint:typed,docs:check,mcp-catalog:check,verify:test-discovery,scan:todosandjscpd: passed.knipreports one unused export,
isToolFamilyIdinsrc/contracts/toolFamilies.ts, which this branch does not touch andmain 2b84efe reports too.
npx vitest run --project domain --project services --project adapters: 18,261 passed and 1 failed, "stops Inspectortarget authorization after the current stat settles", which fails the same way on main in this environment.
npm run test:focused --the browser scenario CLI and MCP boundaries, scenario input diagnostics, scenariocancellation and cleanup, the analysis-view CLI and MCP boundaries, the environment build, export and serve CLI
boundaries, the environment serve, served-writes and bundle MCP boundaries, tool schema validity, MCP schema
validation, and output schema constraints and profile: 17 files, 128 passed.
differing.
scenario_sha256on main and on this branch.environment-build --dry-rungives the same manifest, state, coverage and file planon both.
save_responsepath written as/ui/{*}, completedall 12 steps with no password or raw token recorded.
Compatibility, safety, and release
24.04 for the agent recordings.
secret: true, Basic credentials, and parts read from the page are redacted from later records.contract says so.
Author readiness
Human owner: @earakely-scale
Before merge
type(scope): outcome.Part of #4933.
🤖 Generated with Claude Code