# Attribute Stories to Source Requirements

You are the lineage attribution agent. You are given one imported source file and the complete
list of stories that already exist for this Target. Identify the distinct requirements the source
states, and for each one name the stories that implement it.

This is a matching task against a closed set. Every story you may name is listed in `<stories>`.
You are not decomposing work, proposing new stories, or judging whether the existing stories are
correct.

## Method

1. Read the source and identify each distinct requirement it states. A requirement is a thing the
   system must do, at whatever granularity the author wrote it. One sentence may state one
   requirement that several stories implement — for example "add a table and show it on screen"
   is one requirement implemented by a schema story, a route story, and a view story. Do not split
   a requirement to make the mapping tidier, and do not merge two requirements that a reader would
   act on separately.
2. Give each requirement a short kebab-case name that describes it. The name is an identifier, not
   a summary: `mark-book-read`, not `the-reader-can-mark-a-book-as-read`.
3. For each requirement, list every story that implements any part of it. A story may implement
   more than one requirement; a requirement may need more than one story.
4. List any story that implements no requirement in the source as `<unattached>`. This is expected
   and correct for foundational work — application scaffolding, configuration, shared UI framing,
   test harnesses — that the author never asked for by name. Do not force such a story onto an
   unrelated requirement.

## Rules

- Use only story ids that appear in `<stories>`. Never invent one.
- Every story must appear exactly once, either inside a `stories` attribute or as `<unattached>`.
- Quote the requirement text verbatim from the source in the tag body. Do not paraphrase it.
- Emit nothing but the tags below. No preamble, no commentary, no explanation.

## Output

```text
<requirement name="add-remove-books" stories="add-book,remove-book,database">
The reader can add a book with a title and author, view the books in the order added, and remove a book.
</requirement>
<requirement name="reject-empty-fields" stories="validate-book">
An empty title or author is rejected with a clear error message.
</requirement>
<unattached story="architecture"/>
<unattached story="ui-general"/>
```

# Attribution job

<source name="builtin.jq">
def halt_error: halt_error(5);
def error(msg): msg|error;
def map(f): [.[] | f];
def select(f): if f then . else empty end;
def sort_by(f): _sort_by_impl(map([f]));
def group_by(f): _group_by_impl(map([f]));
def unique_by(f): _unique_by_impl(map([f]));
def max_by(f): _max_by_impl(map([f]));
def min_by(f): _min_by_impl(map([f]));
def add(f): reduce f as $x (null; . + $x);
def add: add(.[]);
def del(f): delpaths([path(f)]);
def abs: if . < 0 then - . else . end;
def _assign(paths; $value): reduce path(paths) as $p (.; setpath($p; $value));
def _modify(paths; update):
    reduce path(paths) as $p ([., []];
        . as $dot
      | null
      | label $out
      | ($dot[0] | getpath($p)) as $v
      | (
          (   $$$$v
            | update
            | (., break $out) as $v
            | $$$$dot
            | setpath([0] + $p; $v)
          ),
          (
              $$$$dot
            | setpath([1, (.[1] | length)]; $p)
          )
        )
    ) | . as $dot | $dot[0] | delpaths($dot[1]);
def map_values(f): .[] |= f;

# recurse
def recurse(f): def r: ., (f | r); r;
def recurse(f; cond): def r: ., (f | select(cond) | r); r;
def recurse: recurse(.[]?);

def to_entries: [keys_unsorted[] as $k | {key: $k, value: .[$k]}];
def from_entries: map({ (.key // .Key // .name // .Name):
  if has("value") then .value else .Value end }) | add // {};
def with_entries(f): to_entries | map(f) | from_entries;
def reverse: [.[length - 1 - range(0;length)]];
def indices($i): if type == "array" and ($i|type) == "array" then .[$i]
  elif type == "array" then .[[$i]]
  elif type == "string" and ($i|type) == "string" then _strindices($i)
  else .[$i] end;
def index($i):   indices($i) | .[0];       # TODO: optimize
def rindex($i):  indices($i) | .[-1:][0];  # TODO: optimize
def paths: path(recurse)|select(length > 0);
def paths(node_filter): path(recurse|select(node_filter))|select(length > 0);
def isfinite: type == "number" and (isinfinite | not);
def arrays: select(type == "array");
def objects: select(type == "object");
def iterables: select(type|. == "array" or . == "object");
def booleans: select(type == "boolean");
def numbers: select(type == "number");
def normals: select(isnormal);
def finites: select(isfinite);
def strings: select(type == "string");
def nulls: select(. == null);
def values: select(. != null);
def scalars: select(type|. != "array" and . != "object");
def join($x): reduce .[] as $i (null;
            (if .==null then "" else .+$x end) +
            ($i | if type=="boolean" or type=="number" then tostring else .//"" end)
        ) // "";
def _flatten($x): reduce .[] as $i ([]; if $i | type == "array" and $x != 0 then . + ($i | _flatten($x-1)) else . + [$i] end);
def flatten($x): if $x < 0 then error("flatten depth must not be negative") else _flatten($x) end;
def flatten: _flatten(-1);
def range($x): range(0;$x);
def fromdateiso8601: strptime("%Y-%m-%dT%H:%M:%SZ")|mktime;
def todateiso8601: strftime("%Y-%m-%dT%H:%M:%SZ");
def fromdate: fromdateiso8601;
def todate: todateiso8601;
def ltrimstr($left): if startswith($left) then .[$left | length:] end;
def rtrimstr($right): if endswith($right) then .[:length - ($right | length)] end;
def trimstr($val): ltrimstr($val) | rtrimstr($val);
def match(re; mode): _match_impl(re; mode; false)|.[];
def match($val): ($val|type) as $vt | if $vt == "string" then match($val; null)
   elif $vt == "array" and ($val | length) > 1 then match($val[0]; $val[1])
   elif $vt == "array" and ($val | length) > 0 then match($val[0]; null)
   else error( $vt + " not a string or array") end;
def test(re; mode): _match_impl(re; mode; true);
def test($val): ($val|type) as $vt | if $vt == "string" then test($val; null)
   elif $vt == "array" and ($val | length) > 1 then test($val[0]; $val[1])
   elif $vt == "array" and ($val | length) > 0 then test($val[0]; null)
   else error( $vt + " not a string or array") end;
def capture(re; mods): match(re; mods) | reduce ( .captures | .[] | select(.name != null) | { (.name) : .string } ) as $pair ({}; . + $pair);
def capture($val): ($val|type) as $vt | if $vt == "string" then capture($val; null)
   elif $vt == "array" and ($val | length) > 1 then capture($val[0]; $val[1])
   elif $vt == "array" and ($val | length) > 0 then capture($val[0]; null)
   else error( $vt + " not a string or array") end;
def scan($re; $flags):
  match($re; "g" + $flags)
    | if (.captures|length > 0)
      then [ .captures | .[] | .string ]
      else .string
      end;
def scan($re): scan($re; null);

# splits/1 produces a stream; split/1 is retained for backward compatibility.
def splits($re; $flags):
  .[foreach (match($re; $flags+"g"), null) as {$offset, $length}
      (null; {start: .next, end: $offset, next: ($offset+$length)})];
def splits($re): splits($re; null);

# split emits an array for backward compatibility
def split($re; $flags): [ splits($re; $flags) ];

# If s contains capture variables, then create a capture object and pipe it to s, bearing
# in mind that s could be a stream
def sub($re; s; $flags):
   . as $in
   | (reduce match($re; $flags) as $edit
        ({result: [], previous: 0};
            $in[ .previous: ($edit | .offset) ] as $gap
            # create the "capture" objects (one per item in s)
            | [reduce ( $edit | .captures | .[] | select(.name != null) | { (.name) : .string } ) as $pair
                 ({}; . + $pair) | s ] as $inserts
            | reduce range(0; $inserts|length) as $ix (.; .result[$ix] += $gap + $inserts[$ix])
            | .previous = ($edit | .offset + .length ) )
          | .result[] + $in[.previous:] )
      // $in;

def sub($re; s): sub($re; s; "");

def gsub($re; s; flags): sub($re; s; flags + "g");
def gsub($re; s): sub($re; s; "g");

########################################################################
# generic iterator/generator
def while(cond; update):
     def _while:
         if cond then ., (update | _while) else empty end;
     _while;
def until(cond; next):
     def _until:
         if cond then . else (next|_until) end;
     _until;
def limit($n; expr):
  if $n > 0 then label $out | foreach expr as $item ($n; . - 1; $item, if . <= 0 then break $out else empty end)
  elif $n == 0 then empty
  else error("limit doesn't support negative count") end;
def skip($n; expr):
  if $n > 0 then foreach expr as $item ($n; . - 1; if . < 0 then $item else empty end)
  elif $n == 0 then expr
  else error("skip doesn't support negative count") end;
# range/3, with a `by` expression argument
def range($init; $upto; $by):
    if $by > 0 then $init|while(. < $upto; . + $by)
  elif $by < 0 then $init|while(. > $upto; . + $by)
  else empty end;
def first(g): label $out | g | ., break $out;
def isempty(g): first((g|false), true);
def all(generator; condition): isempty(generator|condition and empty);
def any(generator; condition): isempty(generator|condition or empty)|not;
def all(condition): all(.[]; condition);
def any(condition): any(.[]; condition);
def all: all(.[]; .);
def any: any(.[]; .);
def nth($n; g):
  if $n < 0 then error("nth doesn't support negative indices")
  else first(skip($n; g)) end;
def first: .[0];
def last: .[-1];
def nth($n): .[$n];
def combinations:
    if length == 0 then [] else
        .[0][] as $x
          | (.[1:] | combinations) as $y
          | [$x] + $y
    end;
def combinations(n):
    . as $dot
      | [range(n) | $dot]
      | combinations;
# transpose a possibly jagged matrix, quickly;
# rows are padded with nulls so the result is always rectangular.
def transpose: [range(0; map(length)|max // 0) as $i | [.[][$i]]];
def in(xs): . as $x | xs | has($x);
def inside(xs): . as $x | xs | contains($x);
def repeat(exp):
     def _repeat:
         exp, _repeat;
     _repeat;
def inputs: try repeat(input) catch if .=="break" then empty else error end;
# like ruby's downcase - only characters A to Z are affected
def ascii_downcase:
  explode | map( if 65 <= . and . <= 90 then . + 32  else . end) | implode;
# like ruby's upcase - only characters a to z are affected
def ascii_upcase:
  explode | map( if 97 <= . and . <= 122 then . - 32  else . end) | implode;

# Streaming utilities
def truncate_stream(stream):
  . as $n | null | stream | . as $input | if (.[0]|length) > $n then setpath([0];$input[0][$n:]) else empty end;
def fromstream(i): {x: null, e: false} as $init |
  # .x = object being built; .e = emit and reset state
  foreach i as $i ($init
  ; if .e then $init else . end
  | if $i|length == 2
    then setpath(["e"]; $i[0]|length==0) | setpath(["x"]+$i[0]; $i[1])
    else setpath(["e"]; $i[0]|length==1) end
  ; if .e then .x else empty end);
def tostream:
  path(def r: (.[]?|r), .; r) as $p |
  getpath($p) |
  reduce path(.[]?) as $q ([$p, .]; [$p+$q]);

# Apply f to composite entities recursively, and to atoms
def walk(f):
  def w:
    if type == "object"
    then map_values(w)
    elif type == "array" then map(w)
    else .
    end
    | f;
  w;

# pathexps could be a stream of dot-paths
def pick(pathexps):
  . as $in
  | reduce path(pathexps) as $a (null;
      setpath($a; $in|getpath($a)) );

# ensure the output of debug(m1,m2) is kept together:
def debug(msgs): (msgs | debug | empty), .;

# SQL-ish operators here:
def INDEX(stream; idx_expr):
  reduce stream as $row ({}; .[$row|idx_expr|tostring] = $row);
def INDEX(idx_expr): INDEX(.[]; idx_expr);
def JOIN($idx; idx_expr):
  [.[] | [., $idx[idx_expr]]];
def JOIN($idx; stream; idx_expr):
  stream | [., $idx[idx_expr]];
def JOIN($idx; stream; idx_expr; join_expr):
  stream | [., $idx[idx_expr]] | join_expr;
def IN(s): any(s == .; .);
def IN(src; s): any(src == s; .);
</source>

<stories>
  <story id="architecture-foundation" implements="ARCHITECTURE.md">Establish the standalone Python interpreter architecture and executable boundary.</story>
  <story id="EXEC-001" implements="FEATURE-Executable-Entry-Point.md">Implement the executable jq entry point.</story>
  <story id="EXEC-002" implements="FEATURE-Process-Contract.md">Implement jq process exit and diagnostic behavior.</story>
  <story id="EXEC-003" implements="FEATURE-JSON-I-O.md">Implement JSON input and compact output handling.</story>
  <story id="PARSE-001" implements="FEATURE-Lexer.md">Implement jq lexical scanning.</story>
  <story id="PARSE-002" implements="FEATURE-Literals-and-Strings.md">Implement literals, strings, escapes, and interpolation.</story>
  <story id="PARSE-003" implements="FEATURE-Filter-Grammar.md">Implement the core jq filter expression grammar.</story>
  <story id="PARSE-004" implements="FEATURE-Advanced-Grammar.md">Implement declarations, control syntax, and grammar rejection.</story>
  <story id="CORE-001" implements="FEATURE-Generator-Core.md">Implement stream-valued filter evaluation.</story>
  <story id="CORE-002" implements="FEATURE-Composition.md">Implement composition and cartesian evaluation.</story>
  <story id="CORE-003" implements="FEATURE-Errors-and-Optional.md">Implement empty, runtime errors, optional evaluation, and partial output.</story>
  <story id="CORE-004" implements="FEATURE-Truthiness-and-Comparison.md">Implement truthiness, equality, and ordering semantics.</story>
  <story id="VALUE-001" implements="FEATURE-Value-Model.md">Implement the jq value model and numeric edge cases.</story>
  <story id="VALUE-002" implements="FEATURE-Accessors.md">Implement field and index access.</story>
  <story id="VALUE-003" implements="FEATURE-Slices-and-Iteration.md">Implement slices and collection iteration.</story>
  <story id="VALUE-004" implements="FEATURE-Type-and-Numeric-Primitives.md">Implement type, length, numeric predicates, and math primitives.</story>
  <story id="CONF-001" implements="FEATURE-Conformance-Assets.md">Stage and validate immutable conformance assets.</story>
  <story id="FLOW-001" implements="FEATURE-Arithmetic-and-Structural-Operators.md">Implement arithmetic and structural operators.</story>
  <story id="FLOW-002" implements="FEATURE-Boolean-and-Alternative-Operators.md">Implement boolean and alternative operators.</story>
  <story id="FLOW-003" implements="FEATURE-Conditionals-and-Exception-Flow.md">Implement conditionals and exception flow.</story>
  <story id="FLOW-004" implements="FEATURE-Labels-and-Breaks.md">Implement lexical labels and breaks.</story>
  <story id="FLOW-005" implements="FEATURE-Reductions-and-Iteration-Control.md">Implement reductions and iteration-control builtins.</story>
  <story id="FLOW-006" implements="FEATURE-Recursive-Generators.md">Implement recursive generators.</story>
  <story id="FUNC-001" implements="FEATURE-Variable-Bindings.md">Implement lexical variable bindings.</story>
  <story id="FUNC-002" implements="FEATURE-Function-Parameters.md">Implement filter and value function parameters.</story>
  <story id="FUNC-003" implements="FEATURE-Function-Definitions.md">Implement function definitions, scope, redefinition, and recursion.</story>
  <story id="FUNC-004" implements="FEATURE-Destructuring-Alternatives.md">Implement destructuring alternatives.</story>
  <story id="PATH-001" implements="FEATURE-Path-Discovery.md">Implement path discovery and projection.</story>
  <story id="PATH-002" implements="FEATURE-Path-Primitives.md">Implement path access and mutation primitives.</story>
  <story id="PATH-003" implements="FEATURE-Assignment-Operators.md">Implement deletion and assignment operators.</story>
  <story id="PATH-004" implements="FEATURE-Complex-Assignments.md">Implement complex assignment edge cases.</story>
  <story id="DATA-001" implements="FEATURE-Collection-Transformations.md">Implement collection transformation builtins.</story>
  <story id="DATA-002" implements="FEATURE-Sorting-and-Grouping.md">Implement sorting, grouping, and extrema builtins.</story>
  <story id="DATA-003" implements="FEATURE-Object-Entries-and-Containment.md">Implement object-entry and containment builtins.</story>
  <story id="DATA-004" implements="FEATURE-Index-and-Membership.md">Implement index, membership, search, and SQL-style utilities.</story>
  <story id="TEXT-001" implements="FEATURE-String-Manipulation.md">Implement string manipulation builtins.</story>
  <story id="TEXT-002" implements="FEATURE-Formats-and-Serialization.md">Implement JSON conversion and output formats.</story>
  <story id="TEXT-003" implements="FEATURE-Regular-Expressions.md">Implement regular-expression filters.</story>
  <story id="TEXT-004" implements="FEATURE-Date-and-Time.md">Implement date and time filters.</story>
  <story id="IO-001" implements="FEATURE-Input-Controls.md">Implement input stream controls.</story>
  <story id="IO-002" implements="FEATURE-Diagnostics.md">Implement diagnostics and stderr filters.</story>
  <story id="IO-003" implements="FEATURE-Streaming.md">Implement streaming transformations.</story>
  <story id="CONF-002" implements="FEATURE-Scoped-Conformance.md">Provide scoped conformance verification for implementation slices.</story>
  <story id="CONF-003" implements="FEATURE-Full-Conformance.md">Verify the completed interpreter against the full conformance corpus.</story>
</stories>
