review: only bridge model component spans across a numeric version boundary · Entire
review: only bridge model component spans across a numeric version boundary
9d2b78f→main·
dipree·1mo ago·2 files·+61 added/-11 removed
The boundary-padded containment still matched variant suffixes: "gpt-4o" matched "gpt-4o-mini" because gpt-4o is a clean component prefix. Distinguish a version boundary from a variant one: a shorter id matches a longer one only when the component immediately after the matched span is purely numeric (a version/date). So "claude-sonnet" -> "claude-sonnet-4-5" and "sonnet" -> "claude-sonnet-4-20250514" still match, but "gpt-4o" -> "gpt-4o-mini", "gpt-4" -> "gpt-4-turbo", and bare fragments like "4-5" do not. Extends the table tests accordingly.
Sessions
4ddfc23385b7View 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-4ddfc23385b7/index.html)
Changes
2
cmd/entire/cli/review
Mmanifest.go+53/-9
Mmanifest_test.go+8/-2
434 unmodified lines
if want == got {
return true
}
// Boundary-aware containment: a less-specific id matches a more-specific one
// only when it aligns on "-"-delimited component boundaries. Padding both
// ends with "-" makes the substring test respect those boundaries, so a
// configured alias ("sonnet") or family ("claude-sonnet") still matches the
// resolved session model ("claude-sonnet-4-5"), while "gpt-4" does NOT match
// "gpt-4o-mini" (the partial "4"/"4o" component no longer counts).
wantPadded := "-" + want + "-"
gotPadded := "-" + got + "-"
return strings.Contains(gotPadded, wantPadded) || strings.Contains(wantPadded, gotPadded)
wantParts := strings.Split(want, "-")
gotParts := strings.Split(got, "-")
// A less-specific id matches a more-specific one only across a *version*
// boundary, not a *variant* one. This distinguishes "claude-sonnet" ->
// "claude-sonnet-4-5" (extra "4" is a version, so they are the same model)
// from "gpt-4o" -> "gpt-4o-mini" (extra "mini" is a variant word, so they are
// distinct models). Checked both directions so it does not matter whether
// the configured or the recorded model is the more specific one.
return modelComponentsMatch(wantParts, gotParts) || modelComponentsMatch(gotParts, wantParts)
}
// modelComponentsMatch reports whether the shorter component list `short`
// identifies the same model as the longer `long`: `short` must appear as a
// contiguous run of whole components in `long`, and the component immediately
// after that run must be purely numeric (a version or date). Requiring a
// numeric boundary is what lets "sonnet"/"claude-sonnet" match
// "claude-sonnet-4-5" while rejecting variant suffixes like "gpt-4o-mini" and
// bare version fragments like "4-5".
func modelComponentsMatch(short, long []string) bool {
if len(short) == 0 || len(short) >= len(long) {
return false
}
for i := 0; i+len(short) <= len(long); i++ {
if !componentsEqualAt(long, short, i) {
continue
}
end := i + len(short)
if end < len(long) && isNumericComponent(long[end]) {
return true
}
}
}
return false
}
func componentsEqualAt(long, short []string, i int) bool {
for k := range short {
if long[i+k] != short[k] {
return false
}
}
return true
}
func isNumericComponent(s string) bool {
if s == "" {
return false
}
for _, r := range s {
if r < '0' || r > '9' {
return false
}
}
return true
}
// normalizeReviewModelID canonicalizes a model string for boundary-aware
Mcmd/entire/cli/review/manifest.go+53/-9
761 unmodified lines
{"family matches resolved", "claude-sonnet", "claude-sonnet-4-5", true},
{"provider prefix and thinking suffix stripped", "anthropic/claude-sonnet:high", "claude-sonnet-4-5", true},
{"separator-insensitive", "claude_sonnet", "claude-sonnet-4-5", true},
{"same family more specific", "gpt-4", "gpt-4-turbo", true},
// The bug this guards against: partial component must not match.
{"numeric version suffix matches", "gpt-4o", "gpt-4o-2024-08-06", true},
{"minor version suffix matches", "claude-sonnet-4", "claude-sonnet-4-5", true},
// Partial component must not match.
{"gpt-4 must NOT match gpt-4o-mini", "gpt-4", "gpt-4o-mini", false},
// Variant suffix (a word, not a version) must not match.
{"gpt-4o must NOT match gpt-4o-mini", "gpt-4o", "gpt-4o-mini", false},
{"gpt-4 must NOT match gpt-4-turbo", "gpt-4", "gpt-4-turbo", false},
// Bare version fragments must not match a model that merely ends in them.
{"version fragment does not match", "4-5", "claude-sonnet-4-5", false},
{"different families do not match", "gpt-4o-mini", "claude-sonnet-4-5", false},
{"opus does not match sonnet", "opus", "claude-sonnet-4-5", false},
}
Mcmd/entire/cli/review/manifest_test.go+8/-2