diff --git a/tools/Bounded-Results.ps1 b/tools/Bounded-Results.ps1 index 26f2078..6def944 100644 --- a/tools/Bounded-Results.ps1 +++ b/tools/Bounded-Results.ps1 @@ -98,7 +98,14 @@ function ConvertTo-BoundedPage { snapshot = $Header.snapshot } if ($page.returnedCount -eq 0) { - $identity = if ($row.path) { " at $($row.path)" } else { " at Offset=$Offset" } + $rowPath = $null + if ($row -is [Collections.IDictionary]) { + if ($row.Contains('path')) { $rowPath = $row['path'] } + } + elseif ($null -ne $row -and $row.PSObject.Properties['path']) { + $rowPath = $row.PSObject.Properties['path'].Value + } + $identity = if ($rowPath) { " at $rowPath" } else { " at Offset=$Offset" } throw "One complete $name row plus envelope exceeds MaxBytes=$MaxBytes$identity. No row was clipped." } return $json diff --git a/tools/Search-Knowledge.ps1 b/tools/Search-Knowledge.ps1 index bd53bbe..ade280e 100644 --- a/tools/Search-Knowledge.ps1 +++ b/tools/Search-Knowledge.ps1 @@ -142,12 +142,15 @@ foreach ($path in $paths) { $target = $context[$field] $matched = $false if ($field -eq 'bc-version') { + # Compare as bigint on both sides: metadata validation accepts bounds + # wider than Int32, and an int left operand would coerce them down. + $targetVersion = [bigint]$target if ($values.Count -eq 1 -and $values[0] -match '^(\d+)\.\.(\d+)?$') { - $matched = $target -ge [bigint]::Parse($Matches[1]) -and - (-not $Matches[2] -or $target -le [bigint]::Parse($Matches[2])) + $matched = $targetVersion -ge [bigint]::Parse($Matches[1]) -and + (-not $Matches[2] -or $targetVersion -le [bigint]::Parse($Matches[2])) } else { - $matched = @($values | Where-Object { [bigint]::Parse($_) -eq $target }).Count -gt 0 + $matched = @($values | Where-Object { [bigint]::Parse($_) -eq $targetVersion }).Count -gt 0 } } else { diff --git a/tools/Test-KnowledgeRetrieval.ps1 b/tools/Test-KnowledgeRetrieval.ps1 index abe9c81..ef65812 100644 --- a/tools/Test-KnowledgeRetrieval.ps1 +++ b/tools/Test-KnowledgeRetrieval.ps1 @@ -622,6 +622,21 @@ try { Assert-Sequence $versioned.countries @('dk') 'non-default country survives' Assert-Sequence $versioned.'application-area' @('finance') 'non-default application area survives' + # Metadata validation accepts range bounds wider than Int32, so version + # matching must compare as bigint rather than coercing the bound down. + $wideRoot = Join-Path $tmp 'wide-version' + New-NeutralArticle -FixtureRoot $wideRoot -Layer microsoft -Slug wide-closed -Version '"1..99999999999"' + New-NeutralArticle -FixtureRoot $wideRoot -Layer microsoft -Slug wide-open -Version '"99999999999.."' + $wideIndex = Join-Path $tmp 'wide-version-index.json' + & $generator -BCQualityRoot $wideRoot -IndexPath $wideIndex | Out-Null + $wide = Invoke-CatalogPages -Arguments @{ + BCQualityRoot = $wideRoot + IndexPath = $wideIndex + Domain = 'neutral' + BCVersion = 28 + } -MaxBytes 16000 + Assert-Sequence $wide.candidates.path @('microsoft/knowledge/neutral/wide-closed.md') 'bc-version bounds beyond Int32 compare without overflow' + $conditional = Invoke-CatalogPages -Arguments @{ BCQualityRoot = $fixtureRoot IndexPath = $fixtureIndex @@ -666,6 +681,20 @@ try { & $search -BCQualityRoot $largeRoot -IndexPath $largeIndex -Domain neutral -MaxBytes 1024 } 'One complete candidates row|Page envelope exceeds' 'oversized catalog row fails without clipping' + # The shared pager reports the oversized row's identity for any row shape; + # a row without a path must still reach its explicit offset-based failure. + . (Join-Path $Root 'tools/Bounded-Results.ps1') + $pagerHeader = [ordered]@{ version = 2; snapshot = ('0' * 64) } + foreach ($shape in @( + @{ name = 'dictionary'; row = [ordered]@{ blob = ('x' * 3000) } }, + @{ name = 'object'; row = [pscustomobject]@{ blob = ('x' * 3000) } } + )) { + Assert-Throws { + ConvertTo-BoundedPage -Header $pagerHeader ` + -Groups ([ordered]@{ rows = @($shape.row) }) -MaxBytes 1024 + } 'One complete rows row plus envelope exceeds MaxBytes=1024 at Offset=0' "oversized pathless $($shape.name) row fails with its offset identity" + } + $bodyRoot = Join-Path $tmp 'body-failures' New-NeutralArticle -FixtureRoot $bodyRoot -Layer microsoft -Slug huge-body -Description ('x' * 3000) New-NeutralArticle -FixtureRoot $bodyRoot -Layer microsoft -Slug broken-link