Skip to content

fix: compute AssertionDetectionConfidence from external analyzer mappings - #253

Merged
jflowers merged 9 commits into
unbound-force:mainfrom
jflowers:opsx/fix-assertion-detection-confidence
Sep 22, 2026
Merged

jflowers merged 9 commits into
unbound-force:mainfrom
jflowers:opsx/fix-assertion-detection-confidence

Conversation

@jflowers

@jflowers jflowers commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes #251. buildExternalQualityReports in cmd/gaze/main.go hardcoded
AssertionDetectionConfidence to 0 for all external analyzer quality reports,
causing gaze quality --analyzer to always show "Assertion detection confidence: 0%"
even when assertions were correctly detected.

The fix adds gaze-side computation from existing protocol.AssertionMappingData
entries, mirroring the Go-native computeDetectionConfidence semantics (same
integer truncation, same ratio formula, same 0-when-empty behavior). No protocol
changes required — confidence is derived from the AssertionType field that
external analyzers already provide.

How to Test

  1. Run the unit tests for the computation function:

    go test -race -count=1 -run 'TestComputeDetectionConfidenceFromMappings' ./internal/adapter/...
  2. Run the method tests for the provider accessor:

    go test -race -count=1 -run 'TestDetectionConfidence$' ./internal/adapter/...
  3. Run the integration test via fake analyzer:

    go test -race -count=1 -run 'TestDetectionConfidence_Integration' ./internal/adapter/...
  4. Verify with an external analyzer (if available):

    gaze quality --analyzer <path-to-analyzer> ./...

    "Assertion detection confidence" should now show accurate percentages instead of 0%.

How to Demo

Run gaze quality --analyzer <analyzer-binary> <package> and observe that the
"Assertion detection confidence" field now reflects the actual proportion of
assertion mappings with a recognized AssertionType, rather than always showing 0%.

Key Files Changed

cmd/gaze/

  • main.go (+36/-0) — Comma-ok type assertion to access DetectionConfidence from
    ExternalContractCoverageProvider; populates per-report and summary-level
    AssertionDetectionConfidence in buildExternalQualityReports

internal/adapter/

  • contract.go (+59/-0) — New computeDetectionConfidenceFromMappings function,
    detectionConfidence map field, DetectionConfidence method, Build integration
  • contract_internal_test.go (+144/-0) — 9 table-driven unit tests + 3 method tests
  • adapter_test.go (+49/-6) — 1 integration test, updated existing test expectation

internal/protocol/

  • client_test.go (+3/-3) — Updated expected mapping count (1→3)
  • testdata/fake_analyzer/main.go (+28/-6) — Extended test_mapping response from
    1 to 3 mappings with mixed assertion_type values

openspec/changes/fix-assertion-detection-confidence/

  • Proposal, design, spec, and tasks artifacts

This PR was generated by /uf.finale (AI-assisted).

@jflowers jflowers self-assigned this Sep 2, 2026
@jflowers jflowers moved this to Ready for Review 👀 in Unbound Force Planning Sep 2, 2026
@em-redhat em-redhat moved this from Ready for Review 👀 to In Review 🏁 in Unbound Force Planning Sep 8, 2026
em-redhat
em-redhat previously approved these changes Sep 8, 2026

@em-redhat em-redhat left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review: PR #253 — fix: compute AssertionDetectionConfidence from external analyzer mappings

Reviewer: em-redhat (AI-assisted)
CI Status: All checks passed (MegaLinter, Unit+Integration Go 1.24/1.25, E2E Go 1.24/1.25)


Summary

Clean, focused fix for #251. The implementation correctly computes AssertionDetectionConfidence from external analyzer mapping data instead of hardcoding 0. The fix is purely additive — no existing behavior changes when --analyzer is not used.

Architecture: New computeDetectionConfidenceFromMappings function in internal/adapter/contract.go mirrors the Go-native computeDetectionConfidence semantics (recognized/total ratio, integer truncation). Detection confidence stored on ExternalContractCoverageProvider struct and accessed via comma-ok type assertion in buildExternalQualityReports. Summary aggregation uses arithmetic mean with rounding, matching the Go-native BuildPackageSummary pattern.

Tests: 13 new tests (9 table-driven unit, 3 method, 1 integration) with thorough edge-case coverage including nil/empty inputs, integer truncation (1/3=33), and unknown function lookups.

Non-goals verified: No protocol changes (fake analyzer only adds more mapping entries with existing schema), no Go-native path changes, no CLI flag changes, no JSON schema changes.


Findings

MEDIUM: Redundant iteration over mappings in Build

File: internal/adapter/contract.go — Build method
The new code iterates all mappings to find unique targets, then for each unique target calls computeDetectionConfidenceFromMappings which re-scans all mappings — O(n×k) total. buildContractLookup (called immediately before) already groups mappings by function via mappingsByFunc. Computing detection confidence inside buildContractLookup would be O(n). Practical impact is negligible for typical mapping set sizes, but architecturally wasteful.

LOW: Map key collision (theoretical)

File: internal/adapter/contract.go — detectionConfidence map key
Key format pkg + "/" + function could theoretically collide if package paths align with function name boundaries (e.g., pkg="a/b", fn="c" vs pkg="a", fn="b/c"). In practice impossible — Go function names cannot contain /, and external analyzer function names are identifiers by protocol convention. The existing buildContractLookup uses a struct key (funcKey) which is collision-free. Consider aligning for consistency.

LOW: DetectionConfidence cannot distinguish "no data" from "0% confidence"

File: internal/adapter/contract.go — DetectionConfidence method
Returns 0 for both "function not in map" and "all assertions unrecognized." Current callers do not need this distinction, but a (int, bool) return would match the Go convention used by the contract coverage lookup.

LOW: Rounding consistency (intentional)

Per-function confidence uses integer truncation (recognized * 100 / total), summary uses round-half-up (int(float64(totalDetectionConf)/n + 0.5)). This exactly matches the existing Go-native path — computeDetectionConfidence truncates, BuildPackageSummary rounds. Consistent with codebase convention.


Verdict: APPROVE

No CRITICAL or HIGH findings. The MEDIUM finding (redundant iteration) is a minor efficiency concern that does not affect correctness. All LOW findings are informational. The fix is well-scoped, well-tested, and aligned with the stated intent and constitution principles.

@jflowers
jflowers force-pushed the opsx/fix-assertion-detection-confidence branch from ad2a6a4 to 48c547e Compare September 8, 2026 20:31
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 10:07 AM UTC · Completed 10:20 AM UTC

Commit: 48c547e · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $4.77

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

Review

Findings

Medium

Low

  • [semantic-gap] internal/adapter/quality.go:243 — classificationConfidence treats any non-empty AssertionType as recognized (m.AssertionType != ""), while the Go-native computeDetectionConfidence treats any Kind != AssertionKindUnknown as recognized (where AssertionKindUnknown = "unknown"). If an external analyzer sent assertion_type: "unknown" (the literal string), it would count as recognized in the external path but unrecognized in the Go-native path. The protocol uses empty string for unrecognized assertions, making this unlikely in practice, but the semantic gap exists.

  • [sort-stability] internal/adapter/quality.go:212 — buildQualitySummary uses sort.Slice (unstable) for WorstCoverageTests, while the canonical BuildPackageSummary in internal/quality/quality.go uses sort.SliceStable with a secondary key for deterministic ordering when coverage percentages tie. Pre-existing inconsistency not introduced by this PR.

  • [stale-doc] docs/concepts/quality.md:46 — The assertion detection confidence description only covers the Go-native computation ("recognized as a known kind vs. unknown"). After this PR, external analyzers also produce non-zero AssertionDetectionConfidence via a different computation (fraction of emitted mapping rows with recognized AssertionType). The concept doc does not mention external analyzers.

Previous run

Review

Findings

Medium

Low

  • [naming-consistency] internal/adapter/contract.go:96 — The local struct targetKey struct{ pkg, fn string } introduced in Build represents the same domain concept as funcKey struct{ pkg, function string } used in buildContractLookup (same file) and BuildQualityFromMappings (quality.go). The field name differs (fn vs function) and the type name differs (targetKey vs funcKey). This inconsistency within the same package makes it harder to recognize that these structs represent the same keying concept. Remediation: rename the local struct to funcKey with field function to match the existing definitions, or extract a shared package-level type.

  • [edge-case] internal/adapter/contract.go:157 — computeMappingClassificationConfidence treats any non-empty AssertionType as recognized (m.AssertionType != ""), while the Go-native computeDetectionConfidence treats any Kind != AssertionKindUnknown as recognized (where AssertionKindUnknown = "unknown"). If an external analyzer sent assertion_type: "unknown" (the literal string), it would count as recognized in the external path but unrecognized in the Go-native path. The protocol uses empty string for unrecognized assertions, making this unlikely in practice, but the semantic gap exists.

  • [rounding-idiom] cmd/gaze/main.go:1327 — The summary aggregation uses int(float64(totalDetectionConf)/n + 0.5) for rounding, while the per-function computeMappingClassificationConfidence uses integer truncation (recognized * 100 / total). This asymmetry is intentional, matching the Go-native path exactly: quality.BuildPackageSummary rounds the summary mean while computeDetectionConfidence truncates per-function values.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (2)

Review

Findings

Medium

Low

  • [edge-case] internal/adapter/contract.go:271 — computeDetectionConfidenceFromMappings treats any non-empty AssertionType as "recognized" (m.AssertionType != ""), while the Go-native computeDetectionConfidence treats any Kind != AssertionKindUnknown as recognized (where AssertionKindUnknown = "unknown"). If an external analyzer sent assertion_type: "unknown" (the literal string), it would count as recognized in the external path but unrecognized in the Go-native path. The protocol uses empty string for unrecognized assertions, making this unlikely in practice, but the semantic gap exists.

  • [naming-consistency] internal/adapter/contract.go — The map key construction pkg + "/" + function is duplicated across Build (storing) and DetectionConfidence (reading). Both sites are in the same file and the key format is documented in the field comment. This is consistent with standard Go map key patterns but could benefit from a helper if additional consumers are added.

  • [rounding-idiom] cmd/gaze/main.go:1323 — The summary aggregation uses int(float64(totalDetectionConf)/n + 0.5) for rounding, while the per-function computeDetectionConfidenceFromMappings uses integer truncation (recognized * 100 / total). This asymmetry is intentional, matching the Go-native path exactly: quality.BuildPackageSummary rounds the summary mean while computeDetectionConfidence truncates per-function values.

Previous run (3)

Review

Findings

Medium

Low

  • [edge-case] internal/adapter/contract.go:271 — computeDetectionConfidenceFromMappings treats any non-empty AssertionType as "recognized" (m.AssertionType != ""), while the Go-native computeDetectionConfidence treats any Kind != AssertionKindUnknown as recognized (where AssertionKindUnknown = "unknown"). If an external analyzer sent assertion_type: "unknown" (the literal string), it would count as recognized in the external path but unrecognized in the Go-native path. The protocol uses empty string for unrecognized assertions, making this unlikely in practice, but the semantic gap exists.

  • [naming-consistency] internal/adapter/contract.go — The map key construction pkg + "/" + function is duplicated across Build (storing) and DetectionConfidence (reading). Both sites are in the same file and the key format is documented in the field comment. This is consistent with standard Go map key patterns but could benefit from a helper if additional consumers are added.

  • [rounding-idiom] cmd/gaze/main.go:1323 — The summary aggregation uses int(float64(totalDetectionConf)/n + 0.5) for rounding, while the per-function computeDetectionConfidenceFromMappings uses integer truncation (recognized * 100 / total). This asymmetry is intentional, matching the Go-native path exactly: quality.BuildPackageSummary rounds the summary mean while computeDetectionConfidence truncates per-function values.

Previous run (4)

Review

Findings

Medium

Low

  • [edge-case] internal/adapter/contract.go:271 — computeDetectionConfidenceFromMappings treats any non-empty AssertionType as "recognized" (m.AssertionType != ""), while the Go-native computeDetectionConfidence treats any Kind != AssertionKindUnknown as recognized (where AssertionKindUnknown = "unknown"). If an external analyzer sent assertion_type: "unknown" (the literal string), it would count as recognized in the external path but unrecognized in the Go-native path. The protocol uses empty string for unrecognized assertions, making this unlikely in practice, but the semantic gap exists.

  • [naming-consistency] internal/adapter/contract.go — The map key construction pkg + "/" + function is duplicated across Build (storing) and DetectionConfidence (reading). Both sites are in the same file and the key format is documented in the field comment. This is consistent with standard Go map key patterns but could benefit from a helper if additional consumers are added.

  • [rounding-idiom] cmd/gaze/main.go:1323 — The summary aggregation uses int(float64(totalDetectionConf)/n + 0.5) for rounding, while the per-function computeDetectionConfidenceFromMappings uses integer truncation (recognized * 100 / total). This asymmetry is intentional, matching the Go-native path exactly: quality.BuildPackageSummary rounds the summary mean while computeDetectionConfidence truncates per-function values.

Previous run (5)

Review

Findings

Medium

  • [protected-path] AGENTS.md — This PR modifies AGENTS.md, which is a protected governance file. The change is a standard Recent Changes bookkeeping entry documenting the fix for bug: BuildQualityFromMappings hardcodes AssertionDetectionConfidence to 0 for external analyzers #251, and the PR links to the authorizing issue. Human approval is required for protected-path changes regardless of context.

  • [stale-doc] docs/protocol.md:484 — The test_mapping method description says it "enables GazeCRAP scoring (contract coverage)" but after this PR it also populates assertion_detection_confidence in gaze quality --analyzer output. External analyzer authors reading this section will not know their assertion_type values affect a quality metric.

  • [stale-doc] docs/protocol.md:521 — The assertion_type field in the test_mapping response table is described only as "Kind of assertion." After this PR, a non-empty assertion_type signals that the assertion is recognized, counting toward assertion_detection_confidence in quality reports; an empty string signals unrecognized. This semantic significance is undocumented.

  • [stale-doc] docs/protocol.md:619 — Step 3 of "Building an Analyzer" says "set test_mapping: true if you can map assertions to effects (enables GazeCRAP)." After this PR, declaring test_mapping: true also enables assertion detection confidence computation in quality reports.

Low

  • [edge-case] internal/adapter/contract.go:271 — computeDetectionConfidenceFromMappings treats any non-empty AssertionType as "recognized" (m.AssertionType != ""), while the Go-native computeDetectionConfidence treats any Kind != AssertionKindUnknown as recognized (where AssertionKindUnknown = "unknown"). If an external analyzer sent assertion_type: "unknown" (the literal string), it would count as recognized in the external path but unrecognized in the Go-native path. The protocol uses empty string for unrecognized assertions, making this unlikely in practice, but the semantic gap exists.

  • [spec-artifact-accuracy] openspec/changes/fix-assertion-detection-confidence/proposal.md:42 — The proposal states confidence is "computed per test function" but the implementation computes confidence per target function, aggregating across all test functions that map to that target.

  • [spec-artifact-accuracy] openspec/changes/fix-assertion-detection-confidence/design.md:32 — Design decision D2 is titled "New DetectionConfidenceByFunc field on provider struct" but the actual implementation uses detectionConfidence (unexported field) and DetectionConfidence (exported method), with no "ByFunc" suffix.

  • [stale-doc] docs/protocol.md:581 — The optional-method error handling table says "test_mapping error: GazeCRAP is unavailable." After this PR, a test_mapping error also means assertion_detection_confidence remains 0 in quality output.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (6)

Review

Findings

Medium

Low

  • [edge-case] internal/adapter/contract.go — computeDetectionConfidenceFromMappings treats any non-empty AssertionType as "recognized" (m.AssertionType != ""), while the Go-native computeDetectionConfidence treats any Kind != AssertionKindUnknown as recognized (where AssertionKindUnknown = "unknown"). If an external analyzer sent assertion_type: "unknown" (the literal string), it would count as recognized in the external path but unrecognized in the Go-native path. The protocol uses empty string for unrecognized assertions, making this unlikely in practice, but the semantic gap exists.
Previous run (7)

Review

Findings

Medium

Low

  • [edge-case] internal/adapter/contract.go — computeDetectionConfidenceFromMappings treats any non-empty AssertionType as "recognized" (m.AssertionType != ""), while the Go-native computeDetectionConfidence treats any Kind != AssertionKindUnknown as recognized (where AssertionKindUnknown = "unknown"). If an external analyzer sent assertion_type: "unknown" (the literal string), it would count as recognized in the external path but unrecognized in the Go-native path. The protocol uses empty string for unrecognized assertions, making this unlikely in practice, but the semantic gap exists.

@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label Sep 14, 2026
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 12:18 PM UTC · Completed 12:30 PM UTC

Commit: 8282e6b · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $4.49

@jflowers
jflowers force-pushed the opsx/fix-assertion-detection-confidence branch from 8282e6b to 5a50633 Compare September 14, 2026 14:51
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 2:53 PM UTC · Completed 3:13 PM UTC

Commit: 5a50633 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $6.70

@fullsend-ai-review fullsend-ai-review Bot added the risk/moderate PR risk: moderate label Sep 14, 2026
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

Risk Assessment: moderate (2/5)

Details

Routine metric bug fix in the adapter layer. File count and line count inflated by learnings, openspec, and docs artifacts that carry no runtime risk. Core changes are 9 source/test files fixing a hardcoded-zero confidence metric. High churn in the adapter area is expected given active external-analyzer feature development. No security, CI, or dependency concerns. Prior score of 2 confirmed.

Previous run

Risk Assessment: moderate (2/5)

Details

Routine metric bug fix with well-scoped code changes in adapter/protocol layers (contract.go +75, main.go +34/-5). Large file count and blast radius are dominated by learnings, openspec artifacts, and documentation rather than risky production code spread. No security, CI, or dependency concerns. Prior score of 2 preserved.

Previous run (2)

Risk Assessment: moderate (2/5)

Details

Routine metric bug fix with well-scoped code changes in adapter/protocol layers, good test accompaniment, no security or CI concerns; large blast radius is dominated by documentation and learning files rather than risky code spread. Tier 1 signals unchanged from prior assessment, confirming prior score of 2.

Previous run (3)

Risk Assessment: moderate (2/5)

Details

Routine metric bug fix with well-scoped code changes in adapter/protocol layers, good test accompaniment, no security or CI concerns; large blast radius is dominated by documentation and learning files rather than risky code spread. Anchored to prior score of 2 — no material signal changes between assessments.

Previous run (4)

Risk Assessment: moderate (2/5)

Details

Routine metric bug fix with well-scoped code changes in adapter/protocol layers, good test accompaniment, no security or CI concerns; large blast radius is dominated by documentation files rather than risky code spread. Anchored to prior score of 2 — no material signal changes between assessments.

Previous run (5)

Risk Assessment: moderate (2/5)

Details

Routine metric bug fix with well-scoped code changes in adapter/protocol layers, good test accompaniment, no security or CI concerns; large blast radius is dominated by documentation files rather than risky code spread.

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot removed the requires-manual-review Review requires human judgment label Sep 14, 2026
@jflowers

Copy link
Copy Markdown
Collaborator Author

/fs-fix

1 similar comment
@jflowers

Copy link
Copy Markdown
Collaborator Author

/fs-fix

jflowers added a commit to jflowers/gaze that referenced this pull request Sep 14, 2026
Update test_mapping description, assertion_type field semantics,
error handling consequences, and Building an Analyzer guidance to
reflect that test_mapping also enables assertion detection confidence.

Addresses PR unbound-force#253 review feedback from @fullsend-ai-review[bot].

Signed-off-by: jflowers <jflowers@users.noreply.github.com>
Assisted-by: claude-opus-4-6
jflowers added a commit to jflowers/gaze that referenced this pull request Sep 14, 2026
- proposal.md: change "per test function" to "per target function"
  (matches actual implementation which computes per target function)
- design.md: change DetectionConfidenceByFunc to detectionConfidence
  (matches actual field/method naming in implementation)

Addresses PR unbound-force#253 review feedback from @fullsend-ai-review[bot].

Signed-off-by: jflowers <jflowers@users.noreply.github.com>
Assisted-by: claude-opus-4-6
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

🤖 Review · ❌ Terminated · Started 5:30 PM UTC · Ended 5:50 PM UTC

Commit: db2eb4f · View workflow run →

@jflowers

Copy link
Copy Markdown
Collaborator Author

Thanks for the thorough review. Addressing each finding:

1. AGENTS.md protected path — The AGENTS.md change is a standard bookkeeping entry documenting the PR in the Recent Changes section. This follows the project's existing pattern and doesn't modify any governance rules, conventions, or behavioral constraints.

2. test_mapping description incomplete — Addressed in a426bf8: updated the description to include "and assertion detection confidence" alongside GazeCRAP scoring.

3. assertion_type semantic significance — Addressed in a426bf8: expanded the field description to document that non-empty values indicate a recognized assertion pattern, while empty string means unclassified (which lowers assertion detection confidence).

4. Building an Analyzer step 3 — Addressed in a426bf8: updated capability declaration guidance to mention assertion detection confidence alongside GazeCRAP.

8. Optional method error table — Addressed in a426bf8: updated the test_mapping error consequence to note that both GazeCRAP and assertion detection confidence are unavailable.

@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label Sep 14, 2026
@fullsend-ai-review

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 5:30 PM UTC · Completed 5:50 PM UTC

Commit: db2eb4f · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $9.08

jflowers added a commit to jflowers/gaze that referenced this pull request Sep 15, 2026
Update test_mapping description, assertion_type field semantics,
error handling consequences, and Building an Analyzer guidance to
reflect that test_mapping also enables assertion detection confidence.

Addresses PR unbound-force#253 review feedback from @fullsend-ai-review[bot].

Signed-off-by: jflowers <jflowers@users.noreply.github.com>
Assisted-by: claude-opus-4-6
jflowers added a commit to jflowers/gaze that referenced this pull request Sep 15, 2026
- proposal.md: change "per test function" to "per target function"
  (matches actual implementation which computes per target function)
- design.md: change DetectionConfidenceByFunc to detectionConfidence
  (matches actual field/method naming in implementation)

Addresses PR unbound-force#253 review feedback from @fullsend-ai-review[bot].

Signed-off-by: jflowers <jflowers@users.noreply.github.com>
Assisted-by: claude-opus-4-6
@jflowers
jflowers force-pushed the opsx/fix-assertion-detection-confidence branch from db2eb4f to f146f3a Compare September 15, 2026 22:06
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 15, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 10:07 PM UTC · Completed 10:22 PM UTC

Commit: f146f3a · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $6.81

@yvonnedevlinrh yvonnedevlinrh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found three issues that should be addressed before merge:

  • The new external-analyzer metric is not semantically equivalent to the native assertion detection confidence: it counts only mapping rows, excluding detected-but-unmapped assertions.
  • ExternalContractCoverageProvider can retain stale confidence values after a failed or unsupported subsequent Build.
  • Tests do not cover the report-construction path where the original hardcoded-zero bug lived.

The external analyzer path otherwise appears safe: the new type assertion and summary guard are reachable, and no regex or match-pattern reachability issues were introduced.

This review was generated by /uf.review-pr (AI-assisted).

Comment thread internal/adapter/contract.go Outdated
Comment thread internal/adapter/contract.go Outdated
Comment thread cmd/gaze/main.go Outdated
…ings (unbound-force#251)

- Add computeDetectionConfidenceFromMappings to internal/adapter/contract.go
  mirroring quality.computeDetectionConfidence semantics (integer truncation)
- Add detectionConfidence map[string]int field and DetectionConfidence method
  on ExternalContractCoverageProvider with nil-map safety
- Populate AssertionDetectionConfidence on each QualityReport and summary in
  buildExternalQualityReports via comma-ok type assertion
- Extend fake analyzer test_mapping from 1 to 3 mappings for integration testing
- Add 13 new tests (9 table-driven unit, 3 method, 1 integration)
- Add OpenSpec artifacts (proposal, design, spec, tasks)

Closes unbound-force#251

Assisted-by: claude-opus
Generated with AI assistance (claude-opus)
Update test_mapping description, assertion_type field semantics,
error handling consequences, and Building an Analyzer guidance to
reflect that test_mapping also enables assertion detection confidence.

Addresses PR unbound-force#253 review feedback from @fullsend-ai-review[bot].

Signed-off-by: jflowers <jflowers@users.noreply.github.com>
Assisted-by: claude-opus-4-6
- proposal.md: change "per test function" to "per target function"
  (matches actual implementation which computes per target function)
- design.md: change DetectionConfidenceByFunc to detectionConfidence
  (matches actual field/method naming in implementation)

Addresses PR unbound-force#253 review feedback from @fullsend-ai-review[bot].

Signed-off-by: jflowers <jflowers@users.noreply.github.com>
Assisted-by: claude-opus-4-6
@jflowers
jflowers force-pushed the opsx/fix-assertion-detection-confidence branch from f146f3a to 6cf9cf1 Compare September 22, 2026 14:56
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 2:57 PM UTC · Completed 3:16 PM UTC

Commit: 6cf9cf1 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $7.95

…ntics

Rename the ExternalContractCoverageProvider detection-confidence
surface to "mapping classification confidence" to reflect that the
denominator is emitted mapping rows, not all detected assertion
sites. Also clear the cached confidence map at the start of Build
to prevent stale values from prior successful builds leaking into
degraded build paths.

Addresses PR unbound-force#253 review feedback from @yvonnedevlinrh.

Signed-off-by: Jay Flowers <jay.flowers@gmail.com>
Assisted-by: deepseek-v4-pro
Extend TestQualityWithExternalAnalyzer to assert both per-report and
summary assertion_detection_confidence values, exercising the
buildExternalQualityReports construction boundary so removing the
assignment in main.go would fail the test.

Addresses PR unbound-force#253 review feedback from @yvonnedevlinrh.

Signed-off-by: Jay Flowers <jay.flowers@gmail.com>
Assisted-by: deepseek-v4-pro
Addresses PR unbound-force#253 review-council feedback: AGENTS.md Recent
Changes and the OpenSpec tasks.md still referenced the
pre-rename identifiers (computeDetectionConfidenceFromMappings,
detectionConfidence, DetectionConfidence). Updated to the final
computeMappingClassificationConfidence / classificationConfidence /
MappingClassificationConfidence names and documented the mapping-row
proxy semantics plus the Build reset-to-nil behavior.

Signed-off-by: Jay Flowers <jay.flowers@gmail.com>
Assisted-by: deepseek-v4-pro
Addresses PR unbound-force#253 review-council feedback: the stale-state
nil-reset at the top of Build had no regression coverage.
TestBuild_ResetsClassificationConfidence seeds a populated
classificationConfidence map, re-runs Build with TestMapping
unsupported, and asserts MappingClassificationConfidence
returns 0 instead of the stale value.

Signed-off-by: Jay Flowers <jay.flowers@gmail.com>
Assisted-by: deepseek-v4-pro
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 3:59 PM UTC · Completed 4:17 PM UTC

Commit: 59bf21a · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $7.10

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot removed the requires-manual-review Review requires human judgment label Sep 22, 2026
…detection-confidence

# Conflicts:
#	AGENTS.md
#	cmd/gaze/external_analyzer_test.go
#	cmd/gaze/main.go
#	docs/protocol.md
#	internal/adapter/adapter_test.go
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 9:24 PM UTC · Completed 9:42 PM UTC

Commit: 1f5c496 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $8.28

@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label Sep 22, 2026
@jflowers
jflowers merged commit 6075877 into unbound-force:main Sep 22, 2026
25 checks passed
@fullsend-ai-retro

fullsend-ai-retro Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

🤖 Finished Retro · ✅ Success · Started 9:57 PM UTC · Completed 10:07 PM UTC

Commit: 1f5c496 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $5.60

@fullsend-ai-retro

Copy link
Copy Markdown

Retro: PR #253 — fix: compute AssertionDetectionConfidence from external analyzer mappings

Timeline

This human-authored PR fixed a bug where gaze quality --analyzer always showed "Assertion detection confidence: 0%" because buildExternalQualityReports hardcoded the value. The fix computes confidence from existing protocol.AssertionMappingData entries without protocol changes.

  • Sep 2: PR opened by jflowers, reviewers requested (em-redhat, yvonnedevlinrh)
  • Sep 8: em-redhat approved (later dismissed by force push)
  • Sep 14: Review agent posted CHANGES_REQUESTED with 1 MEDIUM (protected-path AGENTS.md) and several LOW findings (edge-case semantic gap, naming, rounding, spec accuracy). jflowers addressed doc/spec findings in follow-up commits.
  • Sep 16: yvonnedevlinrh posted CHANGES_REQUESTED with 3 substantive findings — 1 HIGH (denominator semantics mismatch), 2 MEDIUM (stale cached confidence, missing regression test at fix site).
  • Sep 22: jflowers addressed all human findings (renamed metric to "mapping classification confidence", added Build reset, added regression test through report path). Merged after re-requesting reviews.

Review quality

Review agent strengths: The agent excelled at documentation accuracy — it caught 4 stale-doc findings in docs/protocol.md and docs/concepts/quality.md, plus 2 spec-artifact inaccuracies. These are pattern-matching tasks where the agent compares descriptions against code changes. Risk assessment was consistently reasonable (moderate 2/5).

Review agent gaps: The agent identified a surface-level edge case (the literal string "unknown" treated differently in native vs external paths) but missed the deeper architectural problem: the external computation uses mapping rows as its denominator while the native computation uses all detected assertion sites. This means the two implementations of the same named metric (AssertionDetectionConfidence) can produce fundamentally different values for the same input — a semantic correctness issue the human reviewer caught at HIGH severity. The agent also missed a stateful lifecycle bug (stale confidence on degraded Build paths) and the test coverage gap (tests didn't exercise the actual code path where the hardcoded-zero bug lived).

Impact: All 3 human findings drove code changes (4 commits). None of the agent's findings drove code changes — they were either informational LOW observations or the repeatedly-flagged AGENTS.md governance gate.

Cost

The review agent ran 8 times across the PR lifecycle at ~$55 total. Finding quality plateaued after run 1 — subsequent runs produced the same core findings (AGENTS.md protected-path, != "" edge case) with no escalation in insight depth. New documentation findings appeared only when new code was pushed.

Existing issues with supporting evidence from this retro

Proposals skipped (target repo not allowed)

File manually or update create_issues.allow_targets in config.yaml:

  • Review agent: detect semantic divergence when parallel code paths compute the same named metric (fullsend-ai/agents)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

requires-manual-review Review requires human judgment risk/moderate PR risk: moderate

Projects

Status: In Review 🏁

Development

Successfully merging this pull request may close these issues.

bug: BuildQualityFromMappings hardcodes AssertionDetectionConfidence to 0 for external analyzers

4 participants