=== BEGIN ARTIFACT FEATURE-Path-Discovery.md === # FEATURE: Path Discovery and Projection | Field | Value | |-------------|-------| | Version | 20260822 V1 | | Description | Discovers jq paths and constructs projections from path expressions. | | Depends On | FEATURE-Destructuring.md, FEATURE-Accessors.md | | Provides | path, paths, pick, path projections | | Consumes | destructuring and field/index access | ## Questions - None. ## Scope Implement exact and generated path expressions, recursive path enumeration, filtered `paths`, and `pick` projections. Path results preserve jq's ordering and use string object keys and numeric array indices. Invalid path expressions raise runtime errors according to jq semantics. ## Programmatic Acceptance === AC path-001-conformance === Intent: Path discovery and projection behavior executes successfully for representative path, paths, and pick programs. Suite: scoped Requires: executable=python3; scope=test import subprocess path_result = subprocess.run( ["./jq", "-c", "path(.a)",], input='{"a":1}\n', capture_output=True, text=True, ) paths_result = subprocess.run( ["./jq", "-c", "paths",], input='{"a":1,"b":[2]}\n', capture_output=True, text=True, ) pick_result = subprocess.run( ["./jq", "-c", "pick(.a)",], input='{"a":1,"b":2}\n', capture_output=True, text=True, ) assert path_result.returncode == 0 assert path_result.stdout.splitlines() == ['["a"]'] assert paths_result.returncode == 0 assert paths_result.stdout.splitlines() == ['["a"]', '["b",0]'] assert pick_result.returncode == 0 assert pick_result.stdout.splitlines() == ['{"a":1}'] === END AC path-001-conformance === ## User Acceptance - None. ## Guardrails - Path enumeration must preserve traversal order and distinguish empty root paths from descendant paths. - Projection must not mutate the source value. === END ARTIFACT === === BEGIN ARTIFACT FEATURE-Path-Primitives.md === # FEATURE: Path Access and Mutation Primitives | Field | Value | |-------------|-------| | Version | 20260822 V1 | | Description | Reads, creates, replaces, and deletes nested values through jq path primitives. | | Depends On | FEATURE-Path-Discovery.md | | Provides | getpath, setpath, delpaths | | Consumes | path discovery and projection | ## Questions - None. ## Scope Implement `getpath`, `setpath`, and `delpaths` for nested object and array paths. Operations create intermediate containers where jq requires them, expand arrays with null values, preserve immutable-value semantics, and reject invalid or excessively deep paths with runtime errors. ## Programmatic Acceptance === AC path-002-conformance === Intent: Path access and mutation primitives execute successfully for representative getpath, setpath, and delpaths programs. Suite: scoped Requires: executable=python3; scope=test import subprocess get_result = subprocess.run( ["./jq", "-c", "getpath([\"a\", \"b\"])",], input='{"a":{"b":3}}\n', capture_output=True, text=True, ) set_result = subprocess.run( ["./jq", "-c", "setpath([\"a\", \"b\"]; 4)",], input='{"a":{}}\n', capture_output=True, text=True, ) del_result = subprocess.run( ["./jq", "-c", "delpaths([[\"a\"]])",], input='{"a":1,"b":2}\n', capture_output=True, text=True, ) assert get_result.returncode == 0 assert get_result.stdout.splitlines() == ["3"] assert set_result.returncode == 0 assert set_result.stdout.splitlines() == ['{"a":{"b":4}}'] assert del_result.returncode == 0 assert del_result.stdout.splitlines() == ['{"b":2}'] === END AC path-002-conformance === ## User Acceptance - None. ## Guardrails - Path operations must not mutate previously produced values. - Invalid path types and excessive depth must remain runtime errors, not compile failures. === END ARTIFACT === === BEGIN ARTIFACT FEATURE-Process-Contract.md === # FEATURE: jq Process Contract | Field | Value | |-------------|-------| | Version | 20260822 V1 | | Description | Defines jq compilation, runtime failure, success, partial-output, and diagnostic process behavior. | | Depends On | FEATURE-Executable-Entry-Point.md | | Provides | compile exit 3, runtime exit 5, success exit 0, stderr diagnostics | | Consumes | ./jq -c program execution | ## Questions - None. ## Compile and Runtime Outcomes | Condition | Exit | |---|---:| | Program compiles and finishes | `0` | | Program is rejected during compilation | `3` | | Program compiles and raises during evaluation | `5` | A compile failure must not be reported as a runtime failure. A runtime failure may occur after values have already been emitted; those values remain observable on stdout. Diagnostics go to stderr and are not part of the value stream. ## Programmatic Acceptance === AC exec-002-compile-runtime === Intent: The executable distinguishes compile failures, runtime failures, and successful completion. Suite: scoped Requires: executable=python3; scope=test import subprocess compile_result = subprocess.run( ["./jq", "-c", "{",], input="null\n", capture_output=True, text=True, ) runtime_result = subprocess.run( ["./jq", "-c", "error"], input="null\n", capture_output=True, text=True, ) success_result = subprocess.run( ["./jq", "-c", "."], input="null\n", capture_output=True, text=True, ) assert compile_result.returncode == 3 assert runtime_result.returncode == 5 assert success_result.returncode == 0 assert compile_result.stderr != "" assert runtime_result.stderr != "" === END AC exec-002-compile-runtime === === AC exec-002-statuses === Intent: The executable exposes distinct compile, runtime, and successful completion statuses. import subprocess compile_result = subprocess.run( ["./jq", "-c", "{",], input="null\n", capture_output=True, text=True, ) runtime_result = subprocess.run( ["./jq", "-c", "error"], input="null\n", capture_output=True, text=True, ) success_result = subprocess.run( ["./jq", "-c", "."], input="null\n", capture_output=True, text=True, ) assert compile_result.returncode == 3 assert runtime_result.returncode == 5 assert success_result.returncode == 0 === END AC exec-002-statuses === === AC exec-002-partial-output === Intent: A runtime failure preserves values emitted before the failure and keeps diagnostics off standard output. import subprocess result = subprocess.run( ["./jq", "-c", "1, error"], input="null\n", capture_output=True, text=True, ) print(result.stdout) print(result.stderr, file=__import__("sys").stderr) assert result.returncode == 5 assert result.stdout.splitlines() == ["1"] assert result.stderr != "" === END AC exec-002-partial-output === ## User Acceptance - None. ## Guardrails - Compile failures exit `3`. - Runtime failures exit `5`. - Successful completion exits `0`. - Runtime output produced before failure is preserved. - Diagnostics are written to stderr only. === END ARTIFACT === === BEGIN ARTIFACT FEATURE-Recursive-Generators.md === # FEATURE: Recursive Generators | Field | Value | |-------------|-------| | Version | 20260822 V1 | | Description | Provides jq recursive and repeated generator filters. | | Depends On | FEATURE-Reductions-and-Iteration-Control.md | | Provides | while, until, repeat, recurse, recursive descent | | Consumes | reductions and ordered generator evaluation | ## Questions - None. ## Workflow The evaluator supports recursive descent and the `while`, `until`, `repeat`, and `recurse` generators. Recursive filters emit values in jq order, terminate according to their predicates or caught errors, and preserve branching when an update yields multiple values. ## Programmatic Acceptance === AC recursive-generators-scoped === Intent: Recursive generator behavior executes successfully for representative while, until, and recurse programs. Suite: scoped import subprocess while_result = subprocess.run( ["./jq", "-c", "1 | while(. < 3; . + 1)",], input="null\n", capture_output=True, text=True, ) until_result = subprocess.run( ["./jq", "-c", "1 | until(. >= 3; . + 1)",], input="null\n", capture_output=True, text=True, ) recurse_result = subprocess.run( ["./jq", "-c", "1 | recurse(. < 3; . + 1)",], input="null\n", capture_output=True, text=True, ) assert while_result.returncode == 0 assert until_result.returncode == 0 assert recurse_result.returncode == 0 assert while_result.stdout != "" assert until_result.stdout != "" assert recurse_result.stdout != "" === END AC recursive-generators-scoped === === AC recursive-descent-scoped === Intent: Recursive-descent syntax executes successfully and emits descendants. Suite: scoped import subprocess result = subprocess.run( ["./jq", "-c", "..",], input='{"a":1}\n', capture_output=True, text=True, ) lines = result.stdout.splitlines() assert result.returncode == 0 assert len(lines) >= 2 assert "1" in lines === END AC recursive-descent-scoped === ## User Acceptance - None. ## Guardrails - Recursive generators must not emit duplicate or incorrectly ordered values. - Termination must not depend on a fixed shallow recursion cutoff. - Runtime errors from repeated expressions must remain catchable. === END ARTIFACT === === BEGIN ARTIFACT FEATURE-Reductions-and-Iteration-Control.md === # FEATURE: Reductions and Iteration Control | Field | Value | |-------------|-------| | Version | 20260822 V1 | | Description | Provides jq reductions and generator control primitives. | | Depends On | FEATURE-Labels-and-Breaks.md, FEATURE-Generator-Core.md | | Provides | reduce, foreach, limit, skip, first, last, nth, range | | Consumes | label and break evaluation, ordered generator evaluation | ## Questions - None. ## Workflow The evaluator implements stateful `reduce` and `foreach` operations, bounded and skipped generator consumption, first/last/nth selection, and range generation. All operations preserve jq stream ordering, multiplicity, cartesian argument behavior, and lexical break handling. ## Programmatic Acceptance === AC reductions-scoped === Intent: Reduction and iteration-control behavior executes successfully for representative reduce, foreach, limit, first, and nth programs. Suite: scoped import subprocess reduce_result = subprocess.run( ["./jq", "-c", "reduce range(1; 4) as $x (0; . + $x)",], input="null\n", capture_output=True, text=True, ) foreach_result = subprocess.run( ["./jq", "-c", "foreach range(1; 4) as $x (0; . + $x)",], input="null\n", capture_output=True, text=True, ) limit_result = subprocess.run( ["./jq", "-c", "limit(2; range(5))",], input="null\n", capture_output=True, text=True, ) assert reduce_result.returncode == 0 assert foreach_result.returncode == 0 assert limit_result.returncode == 0 assert reduce_result.stdout != "" assert foreach_result.stdout != "" assert limit_result.stdout.splitlines() == ["0", "1"] === END AC reductions-scoped === === AC range-scoped === Intent: Range generation executes successfully and preserves generated values. Suite: scoped import subprocess result = subprocess.run( ["./jq", "-c", "range(2; 5)",], input="null\n", capture_output=True, text=True, ) lines = result.stdout.splitlines() assert result.returncode == 0 assert lines == ["2", "3", "4"] assert len(lines) > 0 === END AC range-scoped === ## User Acceptance - None. ## Guardrails - Preserve generator ordering, multiplicity, backtracking, and partial runtime output. - Do not implement reductions as scalar-only operations. - Negative limits, skips, and nth indices must retain jq runtime-error behavior. === END ARTIFACT ===