Repository navigation
fix(environment): match served items whose route repeats a separator - #6876
gensokyo-dev merged 3 commits into
Conversation
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
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: 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".
[Medium impact] The PR appears safe to merge; no actionable correctness, security, or repository-rule issues were found. SummaryMakes state-backed reads and creates preserve repeated path separators.
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 |
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
left a comment
There was a problem hiding this comment.
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.
|
CI run 40018253228 failed Source tests (job 120636486717) with 11 failures. I reran the affected four files on clean current base Command: The PR-specific 310 tests and complete |
|
CI run 40018253228 is complete with failure. All 14 reported test failures reproduced on its clean base 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 Applying the maintainer’s explicit authorization to bypass proven pre-existing/unrelated CI failures and merge reviewed head |
|
Post-merge verification on actual merged commit 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. |
Summary
Fixes #6847. A served item read whose captured route repeats a path separator, such as
GET /api//books/1, returnedAnalysisInputError("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/1succeeds, 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//booksbecomes["api", "", "books"].callSegmentsinstead split the tool'spath_templateitself and dropped empty literal segments withif (text !== "") …, producing["api", "books", value].collectionMatchcompares 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
callSegmentsnow splits the template throughsegmentsOf, 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.segmentsOf(path_template)(seeenvironmentStateCheckedLines.ts, which builds param index sets withsegmentsOf(tool.path_template).flatMap(...)), and the reproduction confirms the/api//books/{numeric}param index is3, matchingsegmentsOf.segmentsOfand the previous raw split agree.createdCollection's missing-argument guard, which rejected any empty segment. A generated create to a repeated-separator collection, such asPOST /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.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 bycollectionMatchat 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:/api/books/1and/api//books/1, and asserts the double-separator item answers from/api//bookswhile the single-separator item stays distinct under/api/books./api//booksreturns 201 from state instead of a missing-argument refusal.Base reproduction (executed): with only
environmentStateCallLines.tsreverted, the item test fails with the issue'sAnalysisInputError. With only theenvironmentStateCollections.tsguard change reverted, the create test fails withneeds every path argument to be non-empty.Reproduction of the reported issue (executed): the issue's synthetic HAR probe returned
answer.ok: falsefor/api//books/1before the change andanswer.ok: trueafter, with/api/books/1succeeding 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,segmentsOfordyldPaths(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.knipreports nothing for the touched module.Compatibility, safety, and release
Independent verification on updated main
Head
c4631987integrates mainaf3b039d. Independent Linux validation passed 310 targeted domain/service/CLI/MCP tests and fullnpm 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 to0929fa42: 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
Before merge
type(scope): outcome.