inspect: clarify model component boundary matching · Entire

inspect: clarify model component boundary matching

b318a52→main·

dipree·4w ago·2 files·+35 added/-14 removed

Make modelComponentsMatch compute the following-component index explicitly so the last-component boundary case is obvious and in-bounds by construction. Clarify that follow == len(long)-1 is intentionally allowed because the span is still not a suffix and the last component can provide the numeric version/date boundary.

Add a direct helper regression for the largest valid offset, suffix rejection, and non-numeric last-boundary rejection.

Sessions

9e3910ab2382View transcript

[?
Checkout the hand off doc that I just added.Pi·Opus 4.8·1 step](/content/gh/entireio/cli/session/019eca64-8c2c-7b00-90c6-3aa49738c497#timeline-9e3910ab2382/index.html)

Changes

2

498 unmodified lines

499
500
501
502
503
504
505
502
503
504
505
506
507
508
507
508
509
510
511
512
513
514
515
516
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525

498 unmodified lines

return false
    }
    // Visit every start offset whose matched span still has a following
    // component. i+len(short) < len(long) keeps long[i+len(short)] in bounds, so
    // even at the largest offset the span is followed by long's LAST element —
    // the span is never a suffix. A match requires that following component to be
    // purely numeric (a version/date), the boundary that confirms the same model.
    // component. The computed follow index is both the bounds check and the
    // boundary component inspected below. At the largest valid offset,
    // follow == len(long)-1, so the following component is exactly long's last
    // element; that case is intentionally allowed because the span is still not a
    // suffix and the last element can supply the required numeric version/date
    // boundary.
    //
    // Suffix windows (i+len(short) == len(long)) are intentionally excluded: with
    // no following component there's no boundary to tell a real less-specific id
    // from a bare fragment, so allowing them would let "mini" match "gpt-4o-mini"
    // or "4-5" match "claude-sonnet-4-5". The cost is that a rare family+version
    // tail like "sonnet-4" won't match "claude-sonnet-4"; realistic configured
    // models (aliases like "sonnet", families like "claude-sonnet", or full names)
    // still match because the recorded model carries a trailing version (e.g.
    // "sonnet" matches "claude-sonnet-4-5").
    for i := 0; i+len(short) < len(long); i++ {
        if componentsEqualAt(long, short, i) && isNumericComponent(long[i+len(short)]) {
    // Suffix windows (follow == len(long)) are intentionally excluded: with no
    // following component there's no boundary to tell a real less-specific id from
    // a bare fragment, so allowing them would let "mini" match "gpt-4o-mini" or
    // "4-5" match "claude-sonnet-4-5". The cost is that a rare family+version tail
    // like "sonnet-4" won't match "claude-sonnet-4"; realistic configured models
    // (aliases like "sonnet", families like "claude-sonnet", or full names) still
    // match because the recorded model carries a trailing version (e.g. "sonnet"
    // matches "claude-sonnet-4-5").
    for i := 0; ; i++ {
        follow := i + len(short)
        if follow >= len(long) {
            break
        }
        if componentsEqualAt(long, short, i) && isNumericComponent(long[follow]) {
            return true
        }
    }

Mcmd/entire/cli/review/manifest.go+20/-14

801 unmodified lines

802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822

801 unmodified lines

}
}

func TestModelComponentsMatchLastComponentBoundary(t *testing.T) {
    t.Parallel()
    long := []string{"anthropic", "claude", "sonnet", "4"}

if !modelComponentsMatch([]string{"claude", "sonnet"}, long) {
        t.Fatal("span followed by long's last component should match when that component is numeric")
    }
    if modelComponentsMatch([]string{"sonnet", "4"}, long) {
        t.Fatal("suffix span should not match because it has no following boundary component")
    }
    if modelComponentsMatch([]string{"claude", "sonnet"}, []string{"anthropic", "claude", "sonnet", "mini"}) {
        t.Fatal("last-component boundary should not match when the following component is non-numeric")
    }
}

// TestBuildLocalReviewManifestFromSummary_DisambiguatesSameModelDifferentThinking
// pins the used-session tracking: two reviewers on the same agent whose models
// normalize identically (claude-sonnet:high / :low -> claude-sonnet), with