Skip to content

Fix GraphQL resolver for JSONObject/[JSONObject] fields instead of hiding behind standalone fallback#130

Merged
aarne merged 7 commits intomainfrom
copilot/finish-testing-harness-migration
Mar 14, 2026
Merged

Fix GraphQL resolver for JSONObject/[JSONObject] fields instead of hiding behind standalone fallback#130
aarne merged 7 commits intomainfrom
copilot/finish-testing-harness-migration

Conversation

Copy link
Contributor

Copilot AI commented Mar 13, 2026

Three bugs in ExecutionTree.response() caused incorrect data materialisation for scalar-typed GraphQL fields (JSONObject, [JSONObject]). The test harness was masking these by forcing standalone execution mode whenever JSONObject schema replacement was needed.

Bugs fixed in ExecutionTree.response()

  • [JSONObject] passthrough arrays — shadow tree creation caused collectOutput() to resolve root-level output wires instead of returning element data. Fix: skip shadow trees for pure passthrough scalar arrays (no element-level mappings).
  • [JSONObject] in array-mapped output — shadow fallback wrapped plain data in new shadow trees that couldn't resolve fields, producing {}. Fix: return plain array data when scalar=true.
  • JSONObject structured sub-fieldsresponse() for path ["legs"] with deeper wires at ["legs","duration"] fell through to return this, then collectOutput() materialised all output fields. Fix: eagerly resolve via resolveNestedField(cleanPath).
// Before: legs: JSONObject returned { id: 42, legs: { duration: "2h", distance: 150 } }
//         (entire output instead of just the legs sub-field)
// After:  legs: JSONObject returns { duration: "2h", distance: 150 }

Test harness

  • Removed executeBridge standalone fallback from regression.ts — JSONObject scenarios now exercise the full GraphQL resolver path
  • Added sparseObjPassthrough / sparseObjStructured regression scenarios covering legs: JSONObject (non-array)
  • Added jsonobject-fields.test.ts with 4 focused tests: single object passthrough, array passthrough, structured output, and array-mapped output
Original prompt

finish the testing harness Migration in Bridge metapackage.

we have some graphql tests disabled as it's hard the deduct the schema from for partial results

we need to replace the actual return type with JsonObject when user asks for a filed that can have subfields

and we need to generate a correct fields query in case the field is selected as legal.*

so one case needs a custom query generation and one also needs custom schema for the test case

after this is done we can delete the disabled field from the test runner harness.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@changeset-bot
Copy link

changeset-bot bot commented Mar 13, 2026

⚠️ No Changeset found

Latest commit: afccf1e

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

- Handle wildcard paths (e.g. "legs.*") in mergeObservedSelection so the
  schema observer sees the full field data
- Add resolveSelectionsAgainstSchema to expand wildcards and bare leaf
  selections on object-typed fields in the generated GraphQL query
- Remove disable: ["graphql"] from both sparse fieldset test scenarios

Co-authored-by: aarne <82001+aarne@users.noreply.github.com>
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Mar 13, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
bridge afccf1e Commit Preview URL

Branch Preview URL
Mar 14 2026, 08:50 AM

Copilot AI changed the title [WIP] Finish the testing harness migration in Bridge metapackage Enable GraphQL replay for wildcard and bare leaf field selections Mar 13, 2026
Copilot AI requested a review from aarne March 13, 2026 20:07
@aarne aarne marked this pull request as ready for review March 14, 2026 06:47
@github-actions
Copy link
Contributor

github-actions bot commented Mar 14, 2026

🐰 Bencher Report

Branchcopilot/finish-testing-harness-migration
Testbedubuntu-latest
Click to view all benchmark results
BenchmarkLatencyBenchmark Result
nanoseconds (ns)
(Result Δ%)
Upper Boundary
nanoseconds (ns)
(Limit %)
compiled: absolute baseline (passthrough, no tools)📈 view plot
🚷 view threshold
0.00 ns
(+3.32%)Baseline: 0.00 ns
0.00 ns
(94.52%)
compiled: array + SYNC tool-per-element 10📈 view plot
🚷 view threshold
0.01 ns
(+1.38%)Baseline: 0.01 ns
0.01 ns
(89.22%)
compiled: array + SYNC tool-per-element 100📈 view plot
🚷 view threshold
0.02 ns
(-1.39%)Baseline: 0.02 ns
0.03 ns
(77.14%)
compiled: array + tool-per-element 10📈 view plot
🚷 view threshold
0.01 ns
(+10.51%)Baseline: 0.01 ns
0.01 ns
(89.97%)
compiled: array + tool-per-element 100📈 view plot
🚷 view threshold
0.04 ns
(+14.62%)Baseline: 0.04 ns
0.05 ns
(87.60%)
compiled: chained 3-tool fan-out📈 view plot
🚷 view threshold
0.01 ns
(+15.27%)Baseline: 0.00 ns
0.01 ns
(96.78%)
compiled: flat array 10 items📈 view plot
🚷 view threshold
0.01 ns
(+11.59%)Baseline: 0.01 ns
0.01 ns
(92.78%)
compiled: flat array 100 items📈 view plot
🚷 view threshold
0.02 ns
(+25.78%)Baseline: 0.01 ns
0.02 ns
(82.74%)
compiled: flat array 1000 items📈 view plot
🚷 view threshold
0.12 ns
(+35.98%)Baseline: 0.09 ns
0.16 ns
(77.38%)
compiled: nested array 10x10📈 view plot
🚷 view threshold
0.03 ns
(+20.66%)Baseline: 0.02 ns
0.03 ns
(87.67%)
compiled: nested array 20x10📈 view plot
🚷 view threshold
0.05 ns
(+22.88%)Baseline: 0.04 ns
0.05 ns
(86.96%)
compiled: nested array 5x5📈 view plot
🚷 view threshold
0.01 ns
(+14.24%)Baseline: 0.01 ns
0.01 ns
(90.54%)
compiled: short-circuit (overdefinition bypass)📈 view plot
🚷 view threshold
0.00 ns
(+2.85%)Baseline: 0.00 ns
0.00 ns
(94.15%)
compiled: simple chain (1 tool)📈 view plot
🚷 view threshold
0.00 ns
(+7.03%)Baseline: 0.00 ns
0.00 ns
(96.15%)
exec: absolute baseline (passthrough, no tools)📈 view plot
🚷 view threshold
0.01 ns
(+44.00%)Baseline: 0.00 ns
0.01 ns
(94.13%)
exec: array + SYNC tool-per-element 10📈 view plot
🚷 view threshold
0.11 ns
(+8.56%)Baseline: 0.10 ns
0.13 ns
(82.23%)
exec: array + SYNC tool-per-element 100📈 view plot
🚷 view threshold
0.97 ns
(+7.29%)Baseline: 0.90 ns
1.19 ns
(81.59%)
exec: array + tool-per-element 10📈 view plot
🚷 view threshold
0.13 ns
(+37.75%)Baseline: 0.09 ns
0.14 ns
(89.63%)
exec: array + tool-per-element 100📈 view plot
🚷 view threshold
1.09 ns
(+35.79%)Baseline: 0.80 ns
1.23 ns
(88.69%)
exec: chained 3-tool fan-out📈 view plot
🚷 view threshold
0.05 ns
(+105.54%)Baseline: 0.03 ns
0.07 ns
(81.12%)
exec: flat array 10 items📈 view plot
🚷 view threshold
0.02 ns
(+26.51%)Baseline: 0.02 ns
0.02 ns
(93.95%)
exec: flat array 100 items📈 view plot
🚷 view threshold
0.10 ns
(+22.50%)Baseline: 0.08 ns
0.11 ns
(93.21%)
exec: flat array 1000 items📈 view plot
🚷 view threshold
0.88 ns
(+20.59%)Baseline: 0.73 ns
0.95 ns
(92.08%)
exec: nested array 10x10📈 view plot
🚷 view threshold
0.15 ns
(+18.34%)Baseline: 0.13 ns
0.16 ns
(93.42%)
exec: nested array 20x10📈 view plot
🚷 view threshold
0.30 ns
(+19.56%)Baseline: 0.25 ns
0.32 ns
(95.45%)
exec: nested array 5x5📈 view plot
🚷 view threshold
0.06 ns
(+20.53%)Baseline: 0.05 ns
0.06 ns
(94.53%)
exec: short-circuit (overdefinition bypass)📈 view plot
🚷 view threshold
0.01 ns
(+70.09%)Baseline: 0.00 ns
0.01 ns
(95.10%)
exec: simple chain (1 tool)📈 view plot
🚷 view threshold
0.01 ns
(+44.09%)Baseline: 0.01 ns
0.01 ns
(92.21%)
parse: large bridge (20 handles x 5 wires)📈 view plot
🚷 view threshold
1.33 ns
(+16.24%)Baseline: 1.14 ns
1.60 ns
(83.23%)
parse: simple bridge📈 view plot
🚷 view threshold
0.04 ns
(+8.44%)Baseline: 0.04 ns
0.05 ns
(81.81%)
🐰 View full continuous benchmarking report in Bencher

@github-actions
Copy link
Contributor

🐰 Bencher Report

Branchcopilot/finish-testing-harness-migration
Testbedubuntu-latest
Click to view all benchmark results
BenchmarkLatencyBenchmark Result
nanoseconds (ns)
(Result Δ%)
Upper Boundary
nanoseconds (ns)
(Limit %)
compiled: absolute baseline (passthrough, no tools)📈 view plot
🚷 view threshold
0.00 ns
(+1.64%)Baseline: 0.00 ns
0.00 ns
(92.98%)
compiled: array + SYNC tool-per-element 10📈 view plot
🚷 view threshold
0.01 ns
(+3.47%)Baseline: 0.01 ns
0.01 ns
(91.06%)
compiled: array + SYNC tool-per-element 100📈 view plot
🚷 view threshold
0.02 ns
(+4.95%)Baseline: 0.02 ns
0.03 ns
(82.09%)
compiled: array + tool-per-element 10📈 view plot
🚷 view threshold
0.01 ns
(+11.81%)Baseline: 0.01 ns
0.01 ns
(91.03%)
compiled: array + tool-per-element 100📈 view plot
🚷 view threshold
0.04 ns
(+13.89%)Baseline: 0.04 ns
0.05 ns
(87.04%)
compiled: chained 3-tool fan-out📈 view plot
🚷 view threshold
0.01 ns
(+15.46%)Baseline: 0.00 ns
0.01 ns
(96.94%)
compiled: flat array 10 items📈 view plot
🚷 view threshold
0.01 ns
(+12.65%)Baseline: 0.01 ns
0.01 ns
(93.66%)
compiled: flat array 100 items📈 view plot
🚷 view threshold
0.02 ns
(+26.91%)Baseline: 0.01 ns
0.02 ns
(83.49%)
compiled: flat array 1000 items📈 view plot
🚷 view threshold
0.12 ns
(+37.14%)Baseline: 0.09 ns
0.16 ns
(78.04%)
compiled: nested array 10x10📈 view plot
🚷 view threshold
0.03 ns
(+20.47%)Baseline: 0.02 ns
0.03 ns
(87.53%)
compiled: nested array 20x10📈 view plot
🚷 view threshold
0.05 ns
(+23.43%)Baseline: 0.04 ns
0.05 ns
(87.35%)
compiled: nested array 5x5📈 view plot
🚷 view threshold
0.01 ns
(+15.15%)Baseline: 0.01 ns
0.01 ns
(91.26%)
compiled: short-circuit (overdefinition bypass)📈 view plot
🚷 view threshold
0.00 ns
(+1.53%)Baseline: 0.00 ns
0.00 ns
(92.94%)
compiled: simple chain (1 tool)📈 view plot
🚷 view threshold
0.00 ns
(+7.16%)Baseline: 0.00 ns
0.00 ns
(96.27%)
exec: absolute baseline (passthrough, no tools)📈 view plot
🚷 view threshold
0.01 ns
(+43.84%)Baseline: 0.00 ns
0.01 ns
(94.03%)
exec: array + SYNC tool-per-element 10📈 view plot
🚷 view threshold
0.11 ns
(+8.16%)Baseline: 0.10 ns
0.13 ns
(81.93%)
exec: array + SYNC tool-per-element 100📈 view plot
🚷 view threshold
0.97 ns
(+7.60%)Baseline: 0.90 ns
1.19 ns
(81.83%)
exec: array + tool-per-element 10📈 view plot
🚷 view threshold
0.12 ns
(+37.58%)Baseline: 0.09 ns
0.14 ns
(89.52%)
exec: array + tool-per-element 100📈 view plot
🚷 view threshold
1.15 ns
(+43.52%)Baseline: 0.80 ns
1.23 ns
(93.74%)
exec: chained 3-tool fan-out📈 view plot
🚷 view threshold
0.05 ns
(+108.95%)Baseline: 0.03 ns
0.07 ns
(82.47%)
exec: flat array 10 items📈 view plot
🚷 view threshold
0.02 ns
(+27.13%)Baseline: 0.02 ns
0.02 ns
(94.41%)
exec: flat array 100 items📈 view plot
🚷 view threshold
0.10 ns
(+21.13%)Baseline: 0.08 ns
0.11 ns
(92.16%)
exec: flat array 1000 items📈 view plot
🚷 view threshold
0.87 ns
(+19.62%)Baseline: 0.73 ns
0.95 ns
(91.34%)
exec: nested array 10x10📈 view plot
🚷 view threshold
0.16 ns
(+21.19%)Baseline: 0.13 ns
0.16 ns
(95.66%)
exec: nested array 20x10📈 view plot
🚷 view threshold
0.30 ns
(+20.18%)Baseline: 0.25 ns
0.32 ns
(95.94%)
exec: nested array 5x5📈 view plot
🚷 view threshold
0.06 ns
(+22.75%)Baseline: 0.05 ns
0.06 ns
(96.27%)
exec: short-circuit (overdefinition bypass)📈 view plot
🚷 view threshold
0.01 ns
(+71.58%)Baseline: 0.00 ns
0.01 ns
(95.94%)
exec: simple chain (1 tool)📈 view plot
🚷 view threshold
0.01 ns
(+48.96%)Baseline: 0.01 ns
0.01 ns
(95.33%)
parse: large bridge (20 handles x 5 wires)📈 view plot
🚷 view threshold
1.34 ns
(+16.94%)Baseline: 1.14 ns
1.60 ns
(83.74%)
parse: simple bridge📈 view plot
🚷 view threshold
0.04 ns
(+2.99%)Baseline: 0.04 ns
0.05 ns
(77.70%)
🐰 View full continuous benchmarking report in Bencher

@github-actions
Copy link
Contributor

🐰 Bencher Report

Branchcopilot/finish-testing-harness-migration
Testbedubuntu-latest
Click to view all benchmark results
BenchmarkLatencyBenchmark Result
nanoseconds (ns)
(Result Δ%)
Upper Boundary
nanoseconds (ns)
(Limit %)
compiled: absolute baseline (passthrough, no tools)📈 view plot
🚷 view threshold
0.00 ns
(+4.26%)Baseline: 0.00 ns
0.00 ns
(95.38%)
compiled: array + SYNC tool-per-element 10📈 view plot
🚷 view threshold
0.01 ns
(+4.16%)Baseline: 0.01 ns
0.01 ns
(91.66%)
compiled: array + SYNC tool-per-element 100📈 view plot
🚷 view threshold
0.02 ns
(+3.46%)Baseline: 0.02 ns
0.03 ns
(80.93%)
compiled: array + tool-per-element 10📈 view plot
🚷 view threshold
0.01 ns
(+12.41%)Baseline: 0.01 ns
0.01 ns
(91.52%)
compiled: array + tool-per-element 100📈 view plot
🚷 view threshold
0.04 ns
(+15.30%)Baseline: 0.04 ns
0.05 ns
(88.12%)
compiled: chained 3-tool fan-out📈 view plot
🚷 view threshold
0.01 ns
(+17.13%)Baseline: 0.00 ns
0.01 ns
(98.34%)
compiled: flat array 10 items📈 view plot
🚷 view threshold
0.01 ns
(+12.65%)Baseline: 0.01 ns
0.01 ns
(93.66%)
compiled: flat array 100 items📈 view plot
🚷 view threshold
0.02 ns
(+27.27%)Baseline: 0.01 ns
0.02 ns
(83.72%)
compiled: flat array 1000 items📈 view plot
🚷 view threshold
0.12 ns
(+35.80%)Baseline: 0.09 ns
0.16 ns
(77.27%)
compiled: nested array 10x10📈 view plot
🚷 view threshold
0.03 ns
(+21.05%)Baseline: 0.02 ns
0.03 ns
(87.96%)
compiled: nested array 20x10📈 view plot
🚷 view threshold
0.05 ns
(+22.75%)Baseline: 0.04 ns
0.05 ns
(86.88%)
compiled: nested array 5x5📈 view plot
🚷 view threshold
0.01 ns
(+15.32%)Baseline: 0.01 ns
0.01 ns
(91.39%)
compiled: short-circuit (overdefinition bypass)📈 view plot
🚷 view threshold
0.00 ns
(+3.61%)Baseline: 0.00 ns
0.00 ns
(94.85%)
compiled: simple chain (1 tool)📈 view plot
🚷 view threshold
0.00 ns
(+9.50%)Baseline: 0.00 ns
0.00 ns
(98.37%)
exec: absolute baseline (passthrough, no tools)📈 view plot
🚷 view threshold
0.01 ns
(+42.00%)Baseline: 0.00 ns
0.01 ns
(92.83%)
exec: array + SYNC tool-per-element 10📈 view plot
🚷 view threshold
0.11 ns
(+7.82%)Baseline: 0.10 ns
0.13 ns
(81.67%)
exec: array + SYNC tool-per-element 100📈 view plot
🚷 view threshold
0.96 ns
(+6.59%)Baseline: 0.90 ns
1.19 ns
(81.05%)
exec: array + tool-per-element 10📈 view plot
🚷 view threshold
0.12 ns
(+37.55%)Baseline: 0.09 ns
0.14 ns
(89.50%)
exec: array + tool-per-element 100📈 view plot
🚷 view threshold
1.11 ns
(+38.36%)Baseline: 0.80 ns
1.23 ns
(90.37%)
exec: chained 3-tool fan-out📈 view plot
🚷 view threshold
0.05 ns
(+109.27%)Baseline: 0.03 ns
0.07 ns
(82.59%)
exec: flat array 10 items📈 view plot
🚷 view threshold
0.02 ns
(+31.43%)Baseline: 0.02 ns
0.02 ns
(97.61%)
exec: flat array 100 items📈 view plot
🚷 view threshold
0.10 ns
(+28.28%)Baseline: 0.08 ns
0.11 ns
(97.60%)
exec: flat array 1000 items📈 view plot
🚷 view threshold
0.91 ns
(+25.90%)Baseline: 0.73 ns
0.95 ns
(96.13%)
exec: nested array 10x10📈 view plot
🚷 view threshold
0.16 ns
(+22.23%)Baseline: 0.13 ns
0.16 ns
(96.48%)
exec: nested array 20x10📈 view plot
🚷 view threshold
0.31 ns
(+21.48%)Baseline: 0.25 ns
0.32 ns
(96.98%)
exec: nested array 5x5📈 view plot
🚷 view threshold
0.06 ns
(+23.75%)Baseline: 0.05 ns
0.06 ns
(97.06%)
exec: short-circuit (overdefinition bypass)📈 view plot
🚷 view threshold
0.01 ns
(+66.19%)Baseline: 0.00 ns
0.01 ns
(92.93%)
exec: simple chain (1 tool)📈 view plot
🚷 view threshold
0.01 ns
(+47.04%)Baseline: 0.01 ns
0.01 ns
(94.10%)
parse: large bridge (20 handles x 5 wires)📈 view plot
🚷 view threshold
1.33 ns
(+15.78%)Baseline: 1.14 ns
1.60 ns
(82.90%)
parse: simple bridge📈 view plot
🚷 view threshold
0.04 ns
(+4.02%)Baseline: 0.04 ns
0.05 ns
(78.47%)
🐰 View full continuous benchmarking report in Bencher

@aarne
Copy link
Contributor

aarne commented Mar 14, 2026

@copilot

please add tests for the test harness also ... my undestanding of the field selector is

field or field.subfield - is full selector (cascades to full sub object) the only way to represent this in graphql is JSOBObject shema for this test this field

field.* or field.subfield.* - is shallow sub select of scalar values in this object

please make sure we have a regressions test specifically for field selections. to make sure we have the full behaviour documented

given this schema

  • id
  • legs
    • a
    • b
    • c
      • c.1
      • c.2

fields: ["id", "legs.*"]

will run a graphql query {id legs {a, b} } against the full generated schema

fields: ["id", "legs"]

will run a graphql query {id legs } against the schema where c output type is replaces with JSONObject

Copilot AI and others added 2 commits March 14, 2026 07:30
- Wildcard (field.*) now selects only scalar sub-fields, not object-typed
- Bare leaf (field) uses JSONObject schema replacement with standalone
  execution mode for correct pass-through behavior
- Add buildScalarOnlySelectionTreeFromType for wildcard expansion
- Add collectFieldsRequiringJSONObject and replaceFieldTypesWithJSONObject
  for per-scenario schema modification
- Add field-selection-harness.test.ts with 10 tests documenting semantics
- Include test/utils/*.test.ts in the test script

Co-authored-by: aarne <82001+aarne@users.noreply.github.com>
Co-authored-by: aarne <82001+aarne@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 14, 2026

@copilot

please add tests for the test harness also ... my undestanding of the field selector is
...

Implemented in ef0e9bc and d6606c6.

Field selection semantics are now:

  • field.* — shallow sub-select of scalar values only. Object-typed children are excluded via buildScalarOnlySelectionTreeFromType.
  • field (bare leaf) — full selector using JSONObject schema replacement per-scenario, with standalone execution mode forced via executeBridge.

Added test/utils/field-selection-harness.test.ts with 10 tests documenting the exact semantics using the schema shape you specified (id, legs: {a, b, c: {c1, c2}}):

  • fields: ["id", "legs.*"] → query { id legs { a b } } against full schema (c excluded)
  • fields: ["id", "legs"] → query { id legs } against schema with legs typed as JSONObject
  • Plus tests for collectFieldsRequiringJSONObject, replaceFieldTypesWithJSONObject, scalar leaf non-replacement, and nested dotted path non-replacement.

Also included test/utils/*.test.ts in the package test script so all harness tests run in CI.

Copilot AI and others added 2 commits March 14, 2026 07:47
Co-authored-by: aarne <82001+aarne@users.noreply.github.com>
Fix three bugs in ExecutionTree.response() for scalar-typed fields:

1. Array passthrough ([JSONObject]): skip shadow tree creation when
   the field is a pure passthrough with no element-level mappings.
   Shadow trees caused collectOutput() to materialise the wrong
   fields from the root bridge.

2. Shadow fallback ([JSONObject] in array-mapped output): return
   plain data instead of wrapping in shadow trees when scalar=true.

3. Structured sub-field (JSONObject): eagerly resolve nested field
   via resolveNestedField() instead of returning the ExecutionTree
   itself, which caused collectOutput() to materialise all output
   fields instead of just the sub-field.

Remove the standalone execution workaround from the test harness.
Add non-array object selection regression tests and focused
GraphQL unit tests for JSONObject / [JSONObject] fields.

Co-authored-by: aarne <82001+aarne@users.noreply.github.com>
Copilot AI changed the title Enable GraphQL replay for wildcard and bare leaf field selections Fix GraphQL resolver for JSONObject/[JSONObject] fields instead of hiding behind standalone fallback Mar 14, 2026
@aarne aarne merged commit 15ca618 into main Mar 14, 2026
8 checks passed
@aarne aarne deleted the copilot/finish-testing-harness-migration branch March 14, 2026 08:55
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.

2 participants