feat(test-mapping): add test mapping pipeline and test_mapping method (#6) - #11
Conversation
jflowers
left a comment
There was a problem hiding this comment.
Council Verdict: APPROVE
Note: Could not post as APPROVE due to GitHub's self-review prohibition. Posted as COMMENT instead. Original verdict: APPROVE.
Reviewers: Adversary, Architect, Guard, Testing, SRE, Curator, Envoy, Herald, Scribe
Iterations: 1
Pre-flight: All CI gates PASS (95.75% coverage, 557 tests)
Adversary (APPROVE)
2 LOW findings omitted.
Architect (APPROVE)
2 LOW findings omitted.
Guard (APPROVE)
1 LOW finding omitted.
Testing (APPROVE)
3 LOW findings omitted.
SRE (APPROVE)
3 LOW findings omitted.
Curator (APPROVE)
1 LOW finding omitted. Blog milestone issue filed as #12.
Envoy (APPROVE)
No findings.
Herald (APPROVE)
2 LOW findings omitted.
Scribe (APPROVE)
- [MEDIUM]
_test_mappinghandler lacks docstring (server.py:136) - [MEDIUM]
_AssertionVisitorclass docstring minimal (assertions.py:251) - [MEDIUM]
_CallGraphBFS algorithm lacks inline docs (pairing.py:169) - 4 LOW findings omitted.
Linked Issues
- #6: snake-eyes: test mapping pipeline and test_mapping method (O1)
This review was generated by /review-council (AI-assisted).
| return {"signals": signals} | ||
|
|
||
|
|
||
| def _test_mapping(params: dict[str, Any] | None) -> dict[str, Any]: |
There was a problem hiding this comment.
[MEDIUM] Missing handler docstring (Scribe) -- All JSON-RPC handlers in this file lack docstrings (pre-existing pattern), but per TD-007 public-facing API handlers should document parameters, return values, and error conditions. Consider adding a one-liner, e.g.:
def _test_mapping(params: dict[str, Any] | None) -> dict[str, Any]:
"""Handle the ``test_mapping`` JSON-RPC method; wraps pipeline output in ``{"mappings": [...]}``."""| # --------------------------------------------------------------------------- | ||
|
|
||
|
|
||
| class _AssertionVisitor: |
There was a problem hiding this comment.
[MEDIUM] Minimal class docstring (Scribe) -- _AssertionVisitor constructor parameters (rel_path, skip_call_ids, max_depth) are undocumented. Per TD-007, non-trivial class parameters should be documented to help maintainers understand that rel_path formats assertion_location, skip_call_ids prevents with-item double-counting, and max_depth bounds traversal depth.
|
|
||
|
|
||
| @dataclass | ||
| class _CallGraph: |
There was a problem hiding this comment.
[MEDIUM] BFS algorithm lacks inline documentation (Scribe) -- The _CallGraph.reachable_files BFS has no inline comments explaining traversal semantics: visited includes the start file at depth 0, and depth > depth_limit is the termination condition. The module-level docstring mentions "BFS with depth_limit=5" but the implementation details are undocumented.
PR Cost Report: #11Session: Proposing changes with artifactsID:
Timeline: 2026-08-31 18:24:31 — 2026-09-01 09:03:33 Child sessions: 47 — additional cost: $107.85 Child session breakdown
Total: $294.67 (48 sessions) |
Summary
Adds a Python test-to-assertion mapping capability (issue #6). A new
src/snake_eyes/quality/package pairs test functions to the productionfunctions they exercise, classifies each assertion, and infers the
side-effect type each test targets — served over the Gaze analyzer
protocol via a new
test_mappingJSON-RPC method. Theinitializecapability flag
test_mappingflipsfalse → true. No CRAP/scoring math(Gaze owns scoring); no new runtime dependency (astroid already shipped).
quality/pairing.py, lifted+adapted from gaze-py): threefirst-match-wins strategies — name convention (90 exact / 70 case-only),
direct call (80), astroid transitive call-graph BFS depth 5 (75) with
graceful degradation.
quality/assertions.py, lifted+adapted): one rowper assertion; exhaustive pytest+unittest classification into
equality/comparison/identity/membership/error_check/generic.
quality/mapping.py, fresh): consumes detectorFunctionRecord.side_effects.quality/pipeline.py, fresh):run_test_mapping()—static-analysis-only, deterministic, targets restricted to source files.
_test_mappinghandler +DEFAULT_DISPATCH;protocol.pycapability flip.
How to Test
Expected: 557 passed, 95.75% coverage (per-file assertions 95 / mapping 100 /
pairing 93 / pipeline 91).
Stdio smoke:
Expected: capabilities include
"test_mapping": true; atest_mappingrequest over
tests/fixtures/sample_projectreturns 7 mapping rows.How to Demo
Point
test_mappingattests/fixtures/sample_projectand observe the 7rows: name-strategy (
test_add→add, 90), case-only (test_Add→add, 70),direct-call (
test_it_divides→divide, 80), error-check(
test_divide_error→divide,ErrorReturn), class-qualified unittestmethod (
TestCounter.test_inc→inc,ReceiverMutation), and amulti-assertion test emitting one row per assertion.
Key Files Changed
src/snake_eyes/quality/(new):__init__.py,pairing.py,assertions.py,mapping.py,pipeline.pysrc/snake_eyes/protocol.py,server.py: capability flip + handler/dispatchtests/test_test_mapping_method.py(new),tests/fixtures/sample_project/**(new),
tests/conftest.py(fixture collection-ignore), + capability-assertionupdates in
test_protocol.py/test_discover_method.py/test_classify_signals_method.py/test_server.pyopenspec/changes/test-mapping/: proposal, design, tasks, 5 capability specsREADME.md,AGENTS.md,pyproject.toml(docs +slowmarker)Known Issues
Non-blocking LOW advisories accepted by the unanimous code-review council
(tracked for optional follow-up; none affect correctness):
quality/pairing.pyexceptsites are silent/defensive(the
nodes_of_class(Call)guard and thefinallycache-clear) — couldadd a stderr diagnostic for consistency.
_STRATEGY3_DEGRADEomitsInferenceError/OSError(cosmeticdiagnostic-label parity;
OSErrorintentionally excluded soFileNotFoundErrorre-raises cleanly to -32602).defined_namesname-collision residual (an external callee whosename collides with an in-project function can still trigger
.infer()) —identical accepted residual as
analysis/inference.py, bounded by theMemoryErrordegrade.or rows == []escapes and a few strategy-3smoke tests assert only
graph is not None; optional BFS memoization pertest file.
This PR was generated by /uf.finale (AI-assisted).