Acceptance Criteria
July 10, 2026 · View on GitHub
Current milestone definition of "done" for the build loop. The agent may create
.loop/COMPLETEonly when every criterion below is true and the gate is green. Reference:docs/DESIGN.mdsections 6 (API contract), 7 (pinned semantics), 8 (refusals).
Functional
-
query(source)returns aQuery<T>; the engine NEVER mutates the source array or its rows (proven by tests that snapshot and re-compare the source after execute). -
where(key, op, value): full operator set (==,!=,<,<=,>,>=,in) with DESIGN 6 semantics — deep structural type-sensitive equality for==/!=/in; relational ops onnumber | stringonly;NaNcomparisons false. -
where(predicate)overload works and is typed ((row: T) => boolean). -
sort(key, direction?): stable; chained calls compose as tie-breakers (first call primary);null/undefinedsort last regardless of direction. -
limit(n): applies at its pipeline position; throwsTypeErrorat call time for negative or non-integer n;limit(0)yields empty. - Ops apply in CALL order (e.g.
limitbeforewheretruncates first) andexplain()returns serializable op descriptions in exactly that order. -
select(...keys): projects rows to exactly the named keys; result type isPick<T, K>; querying a selected-away key afterwards does not compile. -
groupBy(key).execute():Map<T[K], T[]>, SameValueZero grouping, first-seen group order, pipeline order within groups. -
groupBy(key).aggregate(spec)withagg.count/sum/avg/min/max: result rows{ key } & { [name]: number }, names and types inferred from the spec. - Ungrouped aggregates
count/sum/avg/min/maxonQuery<T>; number-keyed only; empty-set semantics per DESIGN 7 (count/sum-> 0;avg/min/maxthrowRangeErrornaming the aggregate and key). - Branching works: two queries extended from one shared prefix are independent.
Type-level (checked by tsc --noEmit on src/type-tests.ts)
- Positive:
select->Pick,groupBy().execute()->Map<T[K], T[]>,aggregate-> inferred named numbers,wherevalue locked toT[K](in->readonly T[K][]) — asserted with anExpect<Equal<...>>helper. - Negative (each with
@ts-expect-error): unknown key; relational op on boolean/null/object field; value type mismatch (where("name", ">", 5)); non-number key passed tosum/avg/min/max; sorting a non-sortable key;whereon a selected-away key.
Quality
- Built test-first; every new behavior has tests derived from the criteria above
- Full gate green on a clean working tree:
./loop/scripts/gate.sh - 100% line + function coverage across all
src/runtime files (bunfig threshold) - No placeholder/stub implementations in shipped code paths
- Zero runtime dependencies (
dependenciesempty in package.json) - "Readable in one sitting" verdict PASS from a fresh-context judge over
src/(see.claude/agents/judge.md); verdict and applied findings recorded inloop/PROGRESS.md
Documentation
-
README.mdusage examples match the actual API and were executed before being written down (measured, not aspirational) -
docs/DESIGN.mdopen questions updated for anything resolved -
loop/PROGRESS.mdandloop/HANDOFF.mdreflect actual state
Process
- All tasks in
loop/IMPLEMENTATION_PLAN.mdfor this milestone are[x] - Decisions made autonomously during the loop are recorded in
loop/PROGRESS.mdwith reasoning, flagged for human review where non-obvious
Completion signal
When all above are satisfied:
- Update
loop/HANDOFF.md - Create file
.loop/COMPLETE - Print sentinel (informational only):
JSONQ-M1-DONE
The marker file is the only machine-detected stop signal.