Skip to content

jq: two path() shapes still collect after #2908 — the reindex-bridge route and a generator in index position #2925

Description

@newhoggy

Severity: Low (side-effect count under a bound; delivered values are correct)

Summary

#2908 made path(f) stream its
results, so a bound outside path(...) stops the generator inside it. Two shapes still
collect, both found by /code-review on PR #2923 and both unchanged from before that PR
— it did not introduce either, it just did not reach them.

1. The reindex-bridge route

eval_each_generic's new arm mirrors the eager arm's own two gates, one of which sends a
document the reindex bridge would not round-trip identically (any Float, or a number literal
too large to survive the trip) to eval_on_owned — which collects.

$ python3 -c "print('{\"a\":1,\"b\":2,\"n\":' + '9'*300 + '}')" | jq -c \
    '[limit(1; path((.a|stderr),(.b|stderr)))]'
1
[["a"]]
# succinctly: 12

Drop the 9*300 and the same filter writes 1, matching jq — the document, not the filter,
is what selects the route.

2. A generator in index position

The stop reaches the branch producer but not a generator supplying an index key:

$ echo '{"a":1,"b":2}' | jq -c '[limit(1; path(.[("a"|stderr),("b"|stderr)]))]'
a
[["a"]]
# succinctly: ab

resolve_index_expr evaluates the key generator eagerly, so this is adjacent to
#2032 (E[K] evaluates its target
once where jq re-runs it per key) — same function, different axis.

Fix direction

  1. is a routing question: either give the bridge route a streaming entry (it re-enters the
    full evaluator, which now has a lazy Builtin::Path arm — the entry point
    eval_on_owned is what collects), or narrow reindex_bridge_is_identity so fewer
    documents need the bridge at all.
  2. needs the key generator driven by demand inside resolve_index_expr, which is where jq: E[K] evaluates its target once where jq re-runs it per key (side-effect count) #2032
    already sits.

Both need live-oracle differential verification against jq 1.7.1 per ADR-0018. The rows above
are the regression guards, and both are pinned by
path_results_stream_to_their_consumer_2908's residual block, which asserts they still differ
so closing either trips the test.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    SonnetSuitable for a Sonnet-class model to implementTriagedIssue has been read, planned, and its model-class label verified

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions