Skip to content

fix(environment): match served items whose route repeats a separator - #6876

Merged
gensokyo-dev merged 3 commits into
morluto:mainfrom
mhamzasakhi:fix/environment-repeated-separator-item
Oct 23, 2026
Merged

gensokyo-dev merged 3 commits into
morluto:mainfrom
mhamzasakhi:fix/environment-repeated-separator-item

Conversation

@mhamzasakhi

@mhamzasakhi mhamzasakhi commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes #6847. A served item read whose captured route repeats a path separator, such as GET /api//books/1, returned AnalysisInputError ("The state holds no /api//books entity 1 in /api/books.") even though the entity was correctly extracted into collection /api//books. The single-separator route /api/books/1 succeeds, and direct recorded replay of the double-separator route also succeeds.

Problem and expected behavior

segmentsOf (the owner used to split the held collection path) preserves internal empty segments, so /api//books becomes ["api", "", "books"]. callSegments instead split the tool's path_template itself and dropped empty literal segments with if (text !== "") …, producing ["api", "books", value]. collectionMatch compares by position, so the lengths matched but the segments did not, and the item was reported as missing.

Expected: a state item view finds the entity it extracted from the same recorded path, preserving the empty internal segment when matching.

Change and scope

  • callSegments now splits the template through segmentsOf, the same owner that splits the held collection path, instead of re-implementing a split that dropped empty segments. A repeated separator is preserved identically on both sides.
  • Param positions are unchanged: param indices are already defined over segmentsOf(path_template) (see environmentStateCheckedLines.ts, which builds param index sets with segmentsOf(tool.path_template).flatMap(...)), and the reproduction confirms the /api//books/{numeric} param index is 3, matching segmentsOf.
  • Single-separator routes are unaffected: with no empty segment, segmentsOf and the previous raw split agree.
  • Create path (review follow-up): preserving empty literal segments exposed createdCollection's missing-argument guard, which rejected any empty segment. A generated create to a repeated-separator collection, such as POST /api//books, was refused. The guard now rejects only an empty supplied parameter segment, so an empty literal (the repeated separator) stays writable while a missing path argument is still refused. Recorded-replay creates were never affected.
  • Not included: the broader path-handling findings tracked in [Bug] Source-map tracing collapses distinct source URLs with repeated slashes #6726 and [Bug] Empty URL path segments collapse distinct environment collections and couple their writes #6696 (closed). This change addresses only the call-side split that diverged from segmentsOf.

Contribution scope: an ordinary correctness fix within existing boundaries; a maintainer scope decision is not applicable.

Contract and boundary impact

  • Semantic owner and earliest changed stage: call-path segmentation in callSegments, consumed by collectionMatch at the state-answer boundary.

  • CLI and MCP/tool-catalog contract: no schema change. A served item whose route repeats a separator now returns its entity instead of a not-found refusal.

  • Provider, bridge, target-format, or platform compatibility: none.

  • Evidence, artifact, provenance, or reconstruction contract: unchanged; state extraction already stored these collections distinctly.

  • Generated metadata, package, or installation impact: none.

  • Read existing files or captured data.

  • Launch or attach to a process.

  • Inject instrumentation or run scripts/code.

  • Change process memory, registers, files, or configuration.

  • Contact network services.

  • Recover protected code or work around protections.

  • Documentation or usability only; no target interaction.

  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

  • Tests added to src/application/environment/environmentStateAnswer.test.ts:

    • "answers a state item whose route has a repeated path separator": serves two captured items, /api/books/1 and /api//books/1, and asserts the double-separator item answers from /api//books while the single-separator item stays distinct under /api/books.
    • "creates into a collection whose route has a repeated path separator" (review follow-up): a generated create to /api//books returns 201 from state instead of a missing-argument refusal.
  • Base reproduction (executed): with only environmentStateCallLines.ts reverted, the item test fails with the issue's AnalysisInputError. With only the environmentStateCollections.ts guard change reverted, the create test fails with needs every path argument to be non-empty.

  • Reproduction of the reported issue (executed): the issue's synthetic HAR probe returned answer.ok: false for /api//books/1 before the change and answer.ok: true after, with /api/books/1 succeeding throughout.

  • Observed, derived, and inferred claims remain distinguishable.

  • Artifact identity, source provenance, and failed attempts remain preserved.

  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

Run on Ubuntu 24.04 x64 with Node 24.22.1:

  • npm run test:focused -- with every test file referencing environment state, callSegments, collectionMatch, answerFromState, createdCollection, environment-serve, segmentsOf or dyldPaths (47 files): 992 passed, 1 skipped, 0 failed.
  • npm run test:local -- src/application/environment/environmentStateAnswer.test.ts: 21 passed. With either fix reverted, its corresponding test fails.
  • npm run check:fast: passed. knip reports nothing for the touched module.

Compatibility, safety, and release

  • Breaking changes or migration steps: none. Only a previously failing served-item read begins succeeding; its collection extraction was already correct.
  • Real Hopper/Ghidra, browser, or OS coverage: not applicable (synthetic capture; no provider). Linux only.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: no new reads, execution, or network access.

Independent verification on updated main

Head c4631987 integrates main af3b039d. Independent Linux validation passed 310 targeted domain/service/CLI/MCP tests and full npm run check. A real Chromium HAR of a local package-inventory application was imported through compiled CLI/stdio MCP, projected to state and served through HTTP MCP: repeated-separator item reads and generated creates succeeded, with ordinary-path collections isolated. Original capture/manifest/state Evidence remained identical. Review and measured resource observations include verification scope, timing variation and token-estimate limitations.

CI run 40018253228 failed with 14 test failures, all reproduced on its clean base af3b039d; seven remaining shards were cancelled. Static/build/native-package checks and the agentenv export/run lane passed. Main then advanced to 0929fa42: the unchanged PR was re-integrated there, and the same 310 tests, full check and real Chromium/CLI/MCP workflow passed again. Final baseline and latest-main verification.

Author readiness

Human owner: @mhamzasakhi

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

callSegments split the tool path template itself and dropped empty literal
segments, while the held collection is split by segmentsOf, which keeps an
internal empty segment. A captured item route such as /api//books/{id} was
stored under collection /api//books but searched with ["api","books"], so
collectionMatch rejected it and a served item read reported the extracted
entity as missing.

Split the call template through segmentsOf, the same owner used for the held
collection path, so a repeated separator is preserved on both sides and the
item answers from its extracted collection. Single-separator routes stay
distinct and param positions are unchanged.

Fixes morluto#6847
@mhamzasakhi
mhamzasakhi marked this pull request as ready for review October 23, 2026 17:39
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-23T20:22:54.137272Z c463198 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f894861f16

ℹ️ 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".

Comment thread src/application/environment/environmentStateCallLines.ts
@greptile-apps

greptile-apps Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no actionable correctness, security, or repository-rule issues were found.

Summary

Makes state-backed reads and creates preserve repeated path separators.

  • Item reads match captured routes with repeated separators.
  • Generated creates can write to repeated-separator collections.

The review used the full PR diff because the merge-base checks differed. No previous review threads were supplied. Tests were inspected but not run. GitHub authentication was unavailable, so whether another PR supersedes this one could not be checked.

Reviews (3) · Last reviewed commit: "Merge branch 'main' into fix/environment..." · Reviewed by Greptile

mhamzasakhi and others added 2 commits October 24, 2026 00:37
Preserving empty literal segments in callSegments made createdCollection's
missing-argument guard reject a create whose route repeats a separator, such
as POST /api//books: the empty literal segment tripped the
segments.some(text.length === 0) check and answerCreate refused the valid
route. Restrict the guard to empty supplied parameter segments, so a missing
path argument is still refused while a repeated-separator collection stays
writable as well as readable.

@gensokyo-dev gensokyo-dev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed updated head c463198726902753d79b8a8c2559dde27ef54af2; its tree matches my tested integration onto main af3b039d31d56017169608bb85ab65fde6a0aa0d.

The structural fix is at the producing boundary: callSegments now shares segmentsOf with checked-line parameter indexing and held collection matching. Its item/list/query/document consumers use those parsed facts directly. createdCollection correctly distinguishes an empty literal path segment from an empty supplied argument. The earlier automated finding is fixed, with its thread already resolved; I found no additional directly related cleanup.

Independent verification on Linux, Node 24.22.1/npm 11.16.0: 310 targeted domain/service/CLI/MCP tests passed across 11 files; full npm run check passed. Chromium 155 recorded 8 actual HTTP requests to a local mutable package-inventory application using installed zod/tsx/tokenx name/version data. The unchanged HAR was imported through the compiled CLI and stdio MCP (identical Evidence), projected to manifest/state, and served by the compiled CLI over HTTP MCP. Clean main refused the double-separator item and reported a generated create under the wrong /api/packages collection; this head served /api//packages items and created there successfully, with ordinary /api/packages rows remaining isolated. Original HAR digest and complete capture/manifest/state Evidence remained unchanged. This verifies a local application workflow; no external production deployment or provider is claimed.

Performance observations for the same complete nine-call workflow (fresh processes, warm filesystem; no OS-cold run): first pair main/PR elapsed 8.08/15.78 s, CPU 12.26/23.00 s, sampled family RSS 650/644 MiB. Reversing order gave PR/main elapsed 15.43/15.18 s, CPU 21.60/21.81 s, RSS 624/646 MiB. These small shared-host samples do not establish a speedup; the repeat pair showed similar cost. Repeated served item calls took about 14 ms in both runs. Delivered-JSON heuristic token estimates were 55,147/55,822 (successful bodies replace errors); they exclude initialization, framing, model prompts and preknown source-tool schemas, so actual whole-model token use remains unmeasured. No schema or cache changes were introduced.

CI run 40018253228 is still running. Its 11 Source tests failures match the previously observed baseline failures; clean-current-base attribution is being checked separately. This approval does not claim failed or pending CI checks passed.

@gensokyo-dev

Copy link
Copy Markdown
Collaborator

CI run 40018253228 failed Source tests (job 120636486717) with 11 failures. I reran the affected four files on clean current base af3b039d31d56017169608bb85ab65fde6a0aa0d without PR changes: the same 11 failure titles matched exactly (155 passes).

Command: npm run test:local -- src/application/frida/FridaInstrumentationService.test.ts src/domain/javascript/javascriptStaticAnalysis.mapEndpoints.test.ts src/domain/javascript/javascriptStaticAnalysisReturnedInvocation.test.ts src/server/BundleResourcesMcp.test.ts. Failures are four Frida lifecycle cases, five Map-endpoint cases, the finite callable alias graph, and BundleResourcesMcp.

The PR-specific 310 tests and complete npm run check passed, as did the real Chromium HAR → compiled CLI/stdio MCP → state-serving HTTP MCP workflow documented in the review. Static checks, package build, Windows native controls, Linux native package baseline and the agentenv export/run lane passed. Sharded tests are still running; their result is not yet established.

@gensokyo-dev

Copy link
Copy Markdown
Collaborator

CI run 40018253228 is complete with failure. All 14 reported test failures reproduced on its clean base af3b039d31d56017169608bb85ab65fde6a0aa0d, with identical failure titles: 11 Source tests failures (4 files; 155 passes) and 3 shard-1 failures (httpCaptureComparison.test.ts, managedMemberComparison.test.ts; 28 passes). The other seven shards were cancelled by fail-fast; they did not pass. Portable tests and CI required failed as aggregates.

Static checks, package build, bundled Windows controls, Linux native package baseline, agentenv export/run, PR title/readiness and Greptile passed. The previous automated finding is resolved, and updated Codex review reports no outstanding findings.

Main advanced during CI. I re-integrated the unchanged PR onto latest fetched main 0929fa42098b1d8fb2276e66ebd4a46708faaaea, tree c0eee96a5132d3d42758cac62389ca1fb2a16a69: only this PR’s three environment files differ from that base. The same 310 tests and full npm run check passed again, followed by the complete real Chromium HAR → compiled CLI/stdio MCP → HTTP MCP state-serving workflow. This last fresh-process/warm-filesystem run took 7.46 s, 11.79 CPU-s, sampled family peak 647 MiB; input digest and complete source Evidence were preserved. Timing varies on this shared host, so no speedup is claimed.

Applying the maintainer’s explicit authorization to bypass proven pre-existing/unrelated CI failures and merge reviewed head c463198726902753d79b8a8c2559dde27ef54af2. Failed/cancelled checks remain recorded as such.

@gensokyo-dev
gensokyo-dev merged commit 9e6c624 into morluto:main Oct 23, 2026
34 of 45 checks passed
@gensokyo-dev

Copy link
Copy Markdown
Collaborator

Post-merge verification on actual merged commit 9e6c6241d7e595c6f3e90d23f30f3d43bc8c9527: 30 targeted state-answer/compiled CLI/MCP tests passed. Main had independently added decompile-directory functionality before the merge, so I checked the actual resulting tree rather than relying only on the earlier integration tree.

The same unchanged Chromium HAR completed the compiled CLI + stdio MCP import/projection + CLI-launched HTTP MCP state-serving workflow again: repeated-separator reads and generated creates succeeded, ordinary-path collections remained isolated, and the HAR digest stayed identical. This fresh-process/warm-filesystem observation took 7.58 s, 11.90 CPU-s, sampled process-family peak 649 MiB; all owned test services exited cleanly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] State-served item reads drop repeated path separators and cannot find extracted entities

2 participants