WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
// Package chunker - validator.go inspects a tier's output and decides whether
|
||||
// it is good enough to ship or whether the strategy chain should fall through
|
||||
// to the next tier. The validator is intentionally permissive: a single
|
||||
// "obviously broken" output is rejected, but plausible-looking variation is
|
||||
// accepted so we don't oscillate between tiers.
|
||||
package chunker
|
||||
|
||||
import "math"
|
||||
|
||||
// ValidationResult captures the verdict and reason for a chunk-set.
|
||||
type ValidationResult struct {
|
||||
OK bool
|
||||
Reason string
|
||||
}
|
||||
|
||||
// ValidateChunks checks whether the given chunks form a usable result for a
|
||||
// document of totalChars characters with a target chunkSize. Returns OK=true
|
||||
// when no broken-output indicator triggers.
|
||||
func ValidateChunks(chunks []Chunk, totalChars, chunkSize int) ValidationResult {
|
||||
if len(chunks) == 0 {
|
||||
return ValidationResult{Reason: "no chunks produced"}
|
||||
}
|
||||
|
||||
// A single chunk for a document much larger than chunkSize means the
|
||||
// strategy did not actually split — fail so the next tier runs.
|
||||
if len(chunks) == 1 && totalChars > 2*chunkSize {
|
||||
return ValidationResult{Reason: "single chunk for large document"}
|
||||
}
|
||||
|
||||
// Compute size statistics.
|
||||
var sum, sumSq float64
|
||||
maxLen, minLen := 0, math.MaxInt32
|
||||
for _, c := range chunks {
|
||||
l := len([]rune(c.Content))
|
||||
sum += float64(l)
|
||||
sumSq += float64(l * l)
|
||||
if l > maxLen {
|
||||
maxLen = l
|
||||
}
|
||||
if l < minLen {
|
||||
minLen = l
|
||||
}
|
||||
}
|
||||
avg := sum / float64(len(chunks))
|
||||
|
||||
// All but the last chunk should carry meaningful content. We allow the
|
||||
// last chunk to be tiny because tail residue is normal.
|
||||
tinyCount := 0
|
||||
for i, c := range chunks {
|
||||
if i == len(chunks)-1 {
|
||||
continue
|
||||
}
|
||||
if len([]rune(c.Content)) < 50 {
|
||||
tinyCount++
|
||||
}
|
||||
}
|
||||
if tinyCount > len(chunks)/4 && tinyCount > 2 {
|
||||
return ValidationResult{Reason: "too many tiny chunks"}
|
||||
}
|
||||
|
||||
// Reject when no chunk reached at least 25% of the target — the splitter
|
||||
// is fragmenting too aggressively to be useful.
|
||||
if maxLen < chunkSize/4 && totalChars > chunkSize {
|
||||
return ValidationResult{Reason: "all chunks far below target size"}
|
||||
}
|
||||
|
||||
// Sanity check on absolute upper bound. Anything past 2x chunkSize is a
|
||||
// red flag — the splitter ignored its size budget.
|
||||
if maxLen > 2*chunkSize && chunkSize > 0 {
|
||||
return ValidationResult{Reason: "chunk exceeds 2x target size"}
|
||||
}
|
||||
|
||||
_ = avg
|
||||
return ValidationResult{OK: true}
|
||||
}
|
||||
Reference in New Issue
Block a user