feat: wire --analyzer to gaze quality for external test_mapping - #242
Conversation
yvonnedevlinrh
left a comment
There was a problem hiding this comment.
Review: PR #242 — feat: wire --analyzer to gaze quality for external test_mapping
Thanks for this — the core feature is well-structured, spec-backed, and CI-green, reusing existing session/adapter/coverage infrastructure cleanly. Two review passes (general + deep correctness) surfaced findings below. Verdict: REQUEST CHANGES, driven by one HIGH correctness bug and one HIGH scope issue.
Findings summary
| # | Severity | Category | Location | Finding | Suggested resolution |
|---|---|---|---|---|---|
| 1 | HIGH | Correctness (Constitution I: Accuracy) | internal/adapter/quality.go:60-119 |
BuildQualityFromMappings keys the effect set off only the first mapping's target (testMappings[0]). When one test asserts on 2+ distinct target functions, contract-coverage/over-specification metrics are silently wrong and the second target is dropped from the report. Untested. |
Sub-group each test's mappings by target (one report per test,target), or union effects across all referenced targets; add a multi-target test. |
| 2 | MEDIUM | Spec drift (Constitution III: Actionable Output) | cmd/gaze/main.go:1244, :1264 |
Degraded handlers emit bare &taxonomy.PackageSummary{}. Spec (specs/quality-external-analyzer.md) mandates a reason of "test_mapping_unavailable" / "test_mapping_error", but PackageSummary has no reason field, so neither string appears in text or JSON. Observable degradation (stderr warning + zero coverage + exit code) is correct and tested. |
Add a reason field to PackageSummary (and schema), or amend the spec scenarios to drop it. |
| 3 | MEDIUM | Test coverage gap | internal/adapter/quality_internal_test.go:14-448 |
Every TestBuildQualityFromMappings subtest uses a single target per test, so the multi-target path (finding #1) is never exercised — which is why the bug shipped CI-green. |
Add a subtest with one test function mapping to two distinct targets; assert both targets' effects count. |
| 4 | LOW | Scope noise | .uf/dewey/learnings/*.md (×4) |
Four draft learning notes (author jay-flowers) bundled into a feature PR — harmless/additive but unrelated; different author suggests a separate workflow. |
Optional: strip from this PR. |
| 5 | LOW | Process (AGENTS.md Website Documentation Gate) | — | New user-facing CLI capability (gaze quality --analyzer) requires a tracking issue in unbound-force/website; #229 calls out website#227/#165 as inaccurate. No website issue referenced. |
Create the website tracking issue before merge. |
Positives
- Security: no findings — no new
exec/shell construction;--analyzer/--languagereach subprocess via pre-existinginitExternalSession/Discover;FetchTestMappingsuses JSON-RPC over stdin with a boundedcontext.WithTimeout(protocol.AnalysisTimeout);moduleDirfromos.Getwd(); errors wrapped without secret exposure. - Caller impact: none —
runQualitysignature unchanged; external path is a pure early-return branch gated onanalyzerFlag != "".Providers/Sessionadditions are additive. - Branch reachability: all new branches (flag rejections, both degradation handlers under both threshold conditions, happy path) are reachable and tested.
- Constitution: I Accuracy — now questioned by #1; II Minimal Assumptions PASS (Go-native path untouched, opt-in); III Actionable Output PARTIAL (#3); IV Testability PASS (pure functions, table-driven tests, GoDoc present).
Blocking items before merge
…pings BuildQualityFromMappings previously keyed the effect set off only the first mapping's target, causing data loss when a test exercises multiple target functions (e.g., integration tests). Contract coverage was computed against a subset of effects, producing false metrics. The fix collects all distinct target funcKeys from the test's mappings, unions their side effects with deduplication by effect ID, and passes the full effect surface to ComputeContractCoverage. The first target is retained as the primary for display metadata only. Adds a multi-target subtest exercising the union path with two targets (db.Save + cache.Invalidate) and three contractual effects. Addresses PR unbound-force#242 review feedback from @yvonnedevlinrh. Signed-off-by: Jason Flowers <jason@unboundforce.com> Assisted-by: claude-opus-4-6
Design decision D5 specifies that degraded quality results should carry a clear reason explaining why metrics are unavailable. The Reason field was missing from PackageSummary, causing bare empty summaries to be emitted by handleQualityNoTestMapping and handleQualityTestMappingError. Adds Reason string field (json:"reason,omitempty") to taxonomy.PackageSummary. Populates it with "test_mapping unavailable" or "test_mapping error: <detail>" in the two degraded handlers. Updates QualitySchema with the new field. Addresses PR unbound-force#242 review feedback from @yvonnedevlinrh. Signed-off-by: Jason Flowers <jason@unboundforce.com> Assisted-by: claude-opus-4-6
|
Addressing the remaining review body items: Item 4 (learning files): The Item 5 (website documentation gate): Created tracking issue: unbound-force/website#280 All three code findings have been addressed:
|
…pings BuildQualityFromMappings previously keyed the effect set off only the first mapping's target, causing data loss when a test exercises multiple target functions (e.g., integration tests). Contract coverage was computed against a subset of effects, producing false metrics. The fix collects all distinct target funcKeys from the test's mappings, unions their side effects with deduplication by effect ID, and passes the full effect surface to ComputeContractCoverage. The first target is retained as the primary for display metadata only. Adds a multi-target subtest exercising the union path with two targets (db.Save + cache.Invalidate) and three contractual effects. Addresses PR unbound-force#242 review feedback from @yvonnedevlinrh. Signed-off-by: Jason Flowers <jason@unboundforce.com> Assisted-by: claude-opus-4-6
Design decision D5 specifies that degraded quality results should carry a clear reason explaining why metrics are unavailable. The Reason field was missing from PackageSummary, causing bare empty summaries to be emitted by handleQualityNoTestMapping and handleQualityTestMappingError. Adds Reason string field (json:"reason,omitempty") to taxonomy.PackageSummary. Populates it with "test_mapping unavailable" or "test_mapping error: <detail>" in the two degraded handlers. Updates QualitySchema with the new field. Addresses PR unbound-force#242 review feedback from @yvonnedevlinrh. Signed-off-by: Jason Flowers <jason@unboundforce.com> Assisted-by: claude-opus-4-6
580534e to
88e0a00
Compare
…pings BuildQualityFromMappings previously keyed the effect set off only the first mapping's target, causing data loss when a test exercises multiple target functions (e.g., integration tests). Contract coverage was computed against a subset of effects, producing false metrics. The fix collects all distinct target funcKeys from the test's mappings, unions their side effects with deduplication by effect ID, and passes the full effect surface to ComputeContractCoverage. The first target is retained as the primary for display metadata only. Adds a multi-target subtest exercising the union path with two targets (db.Save + cache.Invalidate) and three contractual effects. Addresses PR unbound-force#242 review feedback from @yvonnedevlinrh. Signed-off-by: Jason Flowers <jason@unboundforce.com> Assisted-by: claude-opus-4-6
Design decision D5 specifies that degraded quality results should carry a clear reason explaining why metrics are unavailable. The Reason field was missing from PackageSummary, causing bare empty summaries to be emitted by handleQualityNoTestMapping and handleQualityTestMappingError. Adds Reason string field (json:"reason,omitempty") to taxonomy.PackageSummary. Populates it with "test_mapping unavailable" or "test_mapping error: <detail>" in the two degraded handlers. Updates QualitySchema with the new field. Addresses PR unbound-force#242 review feedback from @yvonnedevlinrh. Signed-off-by: Jason Flowers <jason@unboundforce.com> Assisted-by: claude-opus-4-6
88e0a00 to
2e9a630
Compare
PR Cost Report: #242Session: Change proposal workflowID:
Timeline: 2026-08-31 15:48:38 — 2026-08-31 17:20:19 Child sessions: 3 — additional cost: $1.81 Child session breakdown
Session: uf.unleash autonomous pipelineID:
Timeline: 2026-08-31 17:23:15 — 2026-08-31 18:41:54 Child sessions: 6 — additional cost: $14.46 Child session breakdown
Session: Address GitHub PR feedbackID:
Timeline: 2026-09-01 11:31:48 — 2026-09-01 14:20:44 Child sessions: 5 — additional cost: $7.61 Child session breakdown
Session: Sync fork with upstream, rebase mainID:
Timeline: 2026-09-02 09:30:09 — 2026-09-02 13:22:51 Session total: $8.40 Session: Propose changes with artifactsID:
Timeline: 2026-09-02 13:23:33 — 2026-09-02 15:19:31 Child sessions: 15 — additional cost: $19.46 Child session breakdown
Grand Total: $99.52 across 5 session tree(s) (34 sessions) |
em-redhat
left a comment
There was a problem hiding this comment.
PR #242 Review: feat: wire --analyzer to gaze quality for external test_mapping
Branch: opsx/quality-external-analyzer → main | Closes: #229 | Diff: +1901 / -196, 20 files
Pre-flight
| Mode | Result |
|---|---|
| ci-aware | PASS — all 5 CI checks pass (MegaLinter, Unit+Integration Go 1.24/1.25, E2E Go 1.24/1.25). All local tools covered by CI. No local execution needed. |
Prior Review Status
yvonnedevlinrh filed CHANGES_REQUESTED with 5 findings. All have been addressed by 3 fix commits:
- HIGH (multi-target data loss) → Fixed in
048242dwithseenmap dedup - MEDIUM (spec drift — missing
Reasonfield) → Fixed in686c0ac - MEDIUM (test coverage gap) → Fixed in
2e96309with multi-target dedup + Reason tests - LOW (dewey files, website issue) → Scope noise / process items
Constitution Alignment
| Principle | Verdict | Notes |
|---|---|---|
| I. Accuracy | PASS | BuildQualityFromMappings reuses quality.ComputeContractCoverage — the same metric engine as native Go. Multi-target effect union with dedup-by-ID prevents double-counting. |
| II. Minimal Assumptions | PASS | External analyzer provides all data; no Go-specific assumptions. Flag validation correctly rejects --target and --ai-mapper (Go SSA/AST features). |
| III. Actionable Output | PASS | Reports include contract coverage %, over-specification ratio, worst coverage tests, ambiguous effects, unmapped assertions. Reason field explains zero-coverage causes. |
| IV. Testability | PASS | 14+ new tests. All graceful degradation handlers directly testable via synthetic params. No subprocess needed for handler tests. |
Findings
MEDIUM: Dual fetchTestMappings implementations — maintenance divergence risk
Files: internal/adapter/contract.go:93 (private) and internal/adapter/quality.go (exported FetchTestMappings)
Two functions that do essentially the same thing — call test_mapping and return mappings — but with different patterns:
- Private: manual
Call → Error check → Unmarshal, usesp.warn()for stderr logging - Exported: uses
callAndUnmarshalgeneric helper, no logging (caller handles)
Both are intentional — private serves the crap provider pipeline (needs p.warn() for graceful degradation within the provider), exported serves the quality CLI path (returns error to caller). However, any future change to the test_mapping protocol (new fields, error handling changes) must be applied to both implementations or they will silently diverge.
Recommendation: Add a comment cross-referencing the two implementations, or consider refactoring the private method to delegate to the exported function with a p.warn() wrapper. Not blocking since both are tested independently.
Convention: DR-003 (Document Why Not What)
LOW: AssertionDetectionConfidence hardcoded to 0
File: internal/adapter/quality.go (within BuildQualityFromMappings)
Every QualityReport produced by the external path sets AssertionDetectionConfidence: 0. This is documented in the design (D5 in design.md) as a conscious trade-off — external analyzers provide assertion mappings directly rather than detecting them mechanically. However, downstream consumers (like the gaze-reporter agent) interpret this field as a signal of mapping quality. A value of 0 may mislead consumers into thinking assertions were not detected at all.
Recommendation: Consider using a sentinel value like -1 for "not applicable" vs 0 for "detected but none found", or add a comment in the agent prompt explaining that external analyzer reports always have confidence 0. This is informational — the current approach is functional and documented.
LOW: 4 dewey learning files in PR scope
Files: .uf/dewey/learnings/quality-external-analyzer-*.md
These are draft learnings about testing patterns and GoDoc gotchas discovered during development. While they contain useful context, they add 4 files of noise to a feature PR. The yvonnedevlinrh review flagged this as scope noise.
Recommendation: Consider moving dewey learnings to separate commits or a housekeeping PR. Not blocking.
INFO: Website documentation gate
Per AGENTS.md "Website Documentation Gate", changes affecting user-facing CLI commands require a GitHub issue in unbound-force/website. The --analyzer flag on gaze quality is now visible and documented in README. yvonnedevlinrh flagged this as a LOW finding. Confirm whether a website issue has been filed.
Walkthrough
Architecture: The PR separates concerns cleanly between the adapter layer (internal/adapter/quality.go — protocol-to-taxonomy conversion) and the CLI layer (cmd/gaze/main.go — flag validation, graceful degradation orchestration, output formatting). FetchTestMappings is a standalone function rather than a method, enabling direct testing without constructing a full Session.
Data flow: runQualityWithExternalAnalyzer → validates flags (D6/D7) → providers.SideEffects.AllResults() → adapter.FetchTestMappings() → adapter.BuildQualityFromMappings() → quality.WriteText/WriteJSON. Two graceful degradation branches handle no-capability and fetch-error cases, producing zero-coverage reports with explanatory Reason fields.
Key design decisions: D1 (reuse quality.ComputeContractCoverage), D4 (composition via SideEffects field), D5 (AssertionDetectionConfidence: 0), D6/D7 (reject Go-specific flags), D8 (threshold evaluation on zero-coverage reports).
Verdict
APPROVE — The implementation is well-structured, thoroughly tested, and addresses all prior review findings. The single MEDIUM finding (dual implementation divergence risk) is a maintenance observation, not a correctness issue. All CI checks pass. Constitution principles satisfied.
…pings BuildQualityFromMappings previously keyed the effect set off only the first mapping's target, causing data loss when a test exercises multiple target functions (e.g., integration tests). Contract coverage was computed against a subset of effects, producing false metrics. The fix collects all distinct target funcKeys from the test's mappings, unions their side effects with deduplication by effect ID, and passes the full effect surface to ComputeContractCoverage. The first target is retained as the primary for display metadata only. Adds a multi-target subtest exercising the union path with two targets (db.Save + cache.Invalidate) and three contractual effects. Addresses PR unbound-force#242 review feedback from @yvonnedevlinrh. Signed-off-by: Jason Flowers <jason@unboundforce.com> Assisted-by: claude-opus-4-6
Design decision D5 specifies that degraded quality results should carry a clear reason explaining why metrics are unavailable. The Reason field was missing from PackageSummary, causing bare empty summaries to be emitted by handleQualityNoTestMapping and handleQualityTestMappingError. Adds Reason string field (json:"reason,omitempty") to taxonomy.PackageSummary. Populates it with "test_mapping unavailable" or "test_mapping error: <detail>" in the two degraded handlers. Updates QualitySchema with the new field. Addresses PR unbound-force#242 review feedback from @yvonnedevlinrh. Signed-off-by: Jason Flowers <jason@unboundforce.com> Assisted-by: claude-opus-4-6
2e9a630 to
dc03527
Compare
|
🤖 Review · ❌ Terminated · Started 4:20 PM UTC · Ended 4:40 PM UTC Commit: |
|
Addressed the remaining round-2 review body items: Reason tokens (HIGH) — Documentation (MEDIUM)
|
|
Two findings reviewed and intentionally not actioned: AGENTS.md modification (protected-path) — Report structure per-test-function (scope-alignment) — the per-test-function structure of |
|
🤖 Finished Review · ✅ Success · Started 4:20 PM UTC · Completed 4:40 PM UTC Commit: Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $11.36 |
…CRAP + contract coverage) Add BuildQualityFromMappings in internal/adapter/quality.go that converts []protocol.AssertionMappingData + []taxonomy.AnalysisResult into []taxonomy.QualityReport + *taxonomy.PackageSummary, reusing quality.ComputeContractCoverage for metric computation. Add FetchTestMappings standalone function for direct test_mapping protocol calls. Add computeOverSpecification for incidental-effect assertion counting. Add Session.Client() accessor. Expose SideEffects on Providers struct. In cmd/gaze/main.go: replace --analyzer rejection block with runQualityWithExternalAnalyzer following runCrapWithExternalAnalyzer pattern. Add handleQualityNoTestMapping and handleQualityTestMappingError for graceful degradation. Unhide --analyzer/--language flags. Flag validation: --target and --ai-mapper rejected with --analyzer (Go-specific SSA/AST features). 14 new tests across internal/adapter/ and cmd/gaze/. Closes unbound-force#229
- Fix FetchTestMappings GoDoc to accurately describe error propagation - Remove double-logging by eliminating stderr param from FetchTestMappings - Add happy-path integration test for quality with external analyzer - Add unit tests for FetchTestMappings (success + protocol error) - Add tests for graceful degradation handlers (no test_mapping, error) - Add buildQualitySummary truncation test with 6+ test functions - Add findSideEffectID direct test with 4 table-driven cases - Add computeOverSpecification edge case for empty SideEffectID - Update README with --language example and flag incompatibility note Closes unbound-force#229 Assisted-by: claude-opus Generated with AI assistance (claude-opus)
…pings BuildQualityFromMappings previously keyed the effect set off only the first mapping's target, causing data loss when a test exercises multiple target functions (e.g., integration tests). Contract coverage was computed against a subset of effects, producing false metrics. The fix collects all distinct target funcKeys from the test's mappings, unions their side effects with deduplication by effect ID, and passes the full effect surface to ComputeContractCoverage. The first target is retained as the primary for display metadata only. Adds a multi-target subtest exercising the union path with two targets (db.Save + cache.Invalidate) and three contractual effects. Addresses PR unbound-force#242 review feedback from @yvonnedevlinrh. Signed-off-by: Jason Flowers <jason@unboundforce.com> Assisted-by: claude-opus-4-6
Design decision D5 specifies that degraded quality results should carry a clear reason explaining why metrics are unavailable. The Reason field was missing from PackageSummary, causing bare empty summaries to be emitted by handleQualityNoTestMapping and handleQualityTestMappingError. Adds Reason string field (json:"reason,omitempty") to taxonomy.PackageSummary. Populates it with "test_mapping unavailable" or "test_mapping error: <detail>" in the two degraded handlers. Updates QualitySchema with the new field. Addresses PR unbound-force#242 review feedback from @yvonnedevlinrh. Signed-off-by: Jason Flowers <jason@unboundforce.com> Assisted-by: claude-opus-4-6
Add multi-target dedup test case with shared effect IDs (se-shared) across targets to exercise the seen[e.ID] deduplication path. Add Reason field JSON assertions to NoTestMapping and TestMappingError handler tests verifying the quality_summary.reason value. Addresses review-council iteration 1 blocking findings. Signed-off-by: Jason Flowers <jason@unboundforce.com> Assisted-by: claude-opus-4-6
Change the JSON quality_summary.reason from human-readable "test_mapping unavailable"/"test_mapping error: %v" to the spec-mandated stable machine-readable tokens "test_mapping_unavailable"/"test_mapping_error". Operational error detail remains in the stderr warning. Addresses PR unbound-force#242 review feedback from @yvonnedevlinrh. Signed-off-by: jflowers Assisted-by: deepseek-v4-pro
…ch behavior Add cross-reference comments between the standalone FetchTestMappings (quality CLI path) and the private ExternalContractCoverageProvider .fetchTestMappings (crap path), and document the deterministic first-match semantics of findSideEffectID. Addresses PR unbound-force#242 review feedback from @fullsend-ai-review[bot] and @em-redhat. Signed-off-by: jflowers Assisted-by: deepseek-v4-pro
…quality Add --analyzer/--language flags and Go-specific flag incompatibility note to the quality CLI reference, document the PackageSummary.reason field in the JSON schema reference, and update the protocol lifecycle and degradation notes to reflect gaze quality's test_mapping behavior. Addresses PR unbound-force#242 review feedback from @yvonnedevlinrh and @fullsend-ai-review[bot]. Signed-off-by: jflowers Assisted-by: deepseek-v4-pro
…able tokens Addresses PR unbound-force#242 review-council finding: the embedded JSON Schema still described PackageSummary.reason as "human-readable" after the reason field was changed to carry stable machine-readable degradation tokens (test_mapping_unavailable / test_mapping_error). Addresses PR unbound-force#242 review feedback from @yvonnedevlinrh. Signed-off-by: jflowers Assisted-by: deepseek-v4-pro
cadc735 to
7cb85fc
Compare
|
🤖 Finished Review · ✅ Success · Started 4:47 PM UTC · Completed 5:24 PM UTC Commit: Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $9.71 |
| // Design decisions D6/D7: --target and --ai-mapper are rejected because | ||
| // they depend on Go-specific SSA target inference and AST assertion | ||
| // detection that external analyzers cannot provide. | ||
| func runQualityWithExternalAnalyzer(p qualityParams) error { |
There was a problem hiding this comment.
[medium] doc-code-mismatch
README.md and docs/reference/cli/quality.md document that --include-unexported is rejected when --analyzer is set, but runQualityWithExternalAnalyzer only validates --target and --ai-mapper. The flag is silently ignored instead of rejected, contradicting user-facing documentation.
Suggested fix: Add a validation check for p.includeUnexported in runQualityWithExternalAnalyzer, or remove --include-unexported from the documented rejection list in README.md and docs/reference/cli/quality.md.
| return reports, summary | ||
| // writeQualityEmptyOutput writes an empty quality report in the | ||
| // requested format. Used by degraded/error paths. | ||
| func writeQualityEmptyOutput(p qualityParams, summary *taxonomy.PackageSummary) error { |
There was a problem hiding this comment.
[low] naming-consistency
writeQualityEmptyOutput is a thin wrapper around writeQualityEmptyResults that adapts qualityParams fields. A brief comment documenting its purpose would clarify the indirection.
Suggested fix: Add a comment explaining the wrapper serves as parameter adaptation from qualityParams to the lower-level function signature, or inline the call.
…pings BuildQualityFromMappings previously keyed the effect set off only the first mapping's target, causing data loss when a test exercises multiple target functions (e.g., integration tests). Contract coverage was computed against a subset of effects, producing false metrics. The fix collects all distinct target funcKeys from the test's mappings, unions their side effects with deduplication by effect ID, and passes the full effect surface to ComputeContractCoverage. The first target is retained as the primary for display metadata only. Adds a multi-target subtest exercising the union path with two targets (db.Save + cache.Invalidate) and three contractual effects. Addresses PR #242 review feedback from @yvonnedevlinrh. Signed-off-by: Jason Flowers <jason@unboundforce.com> Assisted-by: claude-opus-4-6
Design decision D5 specifies that degraded quality results should carry a clear reason explaining why metrics are unavailable. The Reason field was missing from PackageSummary, causing bare empty summaries to be emitted by handleQualityNoTestMapping and handleQualityTestMappingError. Adds Reason string field (json:"reason,omitempty") to taxonomy.PackageSummary. Populates it with "test_mapping unavailable" or "test_mapping error: <detail>" in the two degraded handlers. Updates QualitySchema with the new field. Addresses PR #242 review feedback from @yvonnedevlinrh. Signed-off-by: Jason Flowers <jason@unboundforce.com> Assisted-by: claude-opus-4-6
Change the JSON quality_summary.reason from human-readable "test_mapping unavailable"/"test_mapping error: %v" to the spec-mandated stable machine-readable tokens "test_mapping_unavailable"/"test_mapping_error". Operational error detail remains in the stderr warning. Addresses PR #242 review feedback from @yvonnedevlinrh. Signed-off-by: jflowers Assisted-by: deepseek-v4-pro
…ch behavior Add cross-reference comments between the standalone FetchTestMappings (quality CLI path) and the private ExternalContractCoverageProvider .fetchTestMappings (crap path), and document the deterministic first-match semantics of findSideEffectID. Addresses PR #242 review feedback from @fullsend-ai-review[bot] and @em-redhat. Signed-off-by: jflowers Assisted-by: deepseek-v4-pro
…quality Add --analyzer/--language flags and Go-specific flag incompatibility note to the quality CLI reference, document the PackageSummary.reason field in the JSON schema reference, and update the protocol lifecycle and degradation notes to reflect gaze quality's test_mapping behavior. Addresses PR #242 review feedback from @yvonnedevlinrh and @fullsend-ai-review[bot]. Signed-off-by: jflowers Assisted-by: deepseek-v4-pro
|
🤖 Finished Retro · ✅ Success · Started 5:43 PM UTC · Completed 5:54 PM UTC Commit: Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $7.03 |
Retro: PR #242 — Wire
|
Summary
Wires
--analyzerand--languageflags togaze qualityfor externaltest_mappingsupport, lifting the D12 deferral from #95.Changes
New:
internal/adapter/quality.goBuildQualityFromMappings— converts[]protocol.AssertionMappingData+[]taxonomy.AnalysisResultinto[]taxonomy.QualityReport+*taxonomy.PackageSummary, reusingquality.ComputeContractCoveragefor metric computationFetchTestMappings— standalone function for directtest_mappingprotocol callscomputeOverSpecification— counts assertions targeting incidental side effectsbuildQualitySummary— aggregates reports into PackageSummaryModified:
internal/adapter/session.goSideEffects *ExternalSideEffectAnalyzerfield toProvidersstructSession.Client()accessor for direct protocol callsModified:
cmd/gaze/main.go--analyzerrejection block withrunQualityWithExternalAnalyzer(followsrunCrapWithExternalAnalyzerpattern)handleQualityNoTestMappingandhandleQualityTestMappingErrorfor graceful degradation--analyzer/--languageflags innewQualityCmd--targetand--ai-mapperrejected with--analyzer(Go-specific SSA/AST features)Tests
internal/adapter/quality_internal_test.go(BuildQualityFromMappings + computeOverSpecification)cmd/gaze/external_analyzer_test.go(CLI flag validation)Documentation
gaze quality --analyzerusage exampleVerification
go test -race -count=1 -short ./...— all passgolangci-lint run— 0 issuesgaze quality --helpshows--analyzerand--languageflagsSpec Artifacts
openspec/changes/quality-external-analyzer/— proposal, design, specs, tasksCloses #229