Add bounded diagnostic prefix encoding
This commit is contained in:
@@ -492,6 +492,11 @@ invalid-byte runs, empty/small budgets, and truncation boundaries. Wiring into
|
|||||||
the public repair workflow follows in Stage 19; no interim alternative formatter
|
the public repair workflow follows in Stage 19; no interim alternative formatter
|
||||||
is exposed or new contract created for a helper's exact allocation count.
|
is exposed or new contract created for a helper's exact allocation count.
|
||||||
|
|
||||||
|
Completion: bounded UTF-8 normalization and JSON-prefix encoding retain only
|
||||||
|
the useful candidate prefix and report complete versus truncated results.
|
||||||
|
Focused encoding and existing formatter tests pass on Go 1.27.3; formatter
|
||||||
|
wiring remains in the next unit.
|
||||||
|
|
||||||
## Stage 19: Construct Repair Feedback Without Whole-Input Serialization
|
## Stage 19: Construct Repair Feedback Without Whole-Input Serialization
|
||||||
|
|
||||||
**Catalog:** 17, completion. **Files:** `formatRepairDiagnostics` and repair tests.
|
**Catalog:** 17, completion. **Files:** `formatRepairDiagnostics` and repair tests.
|
||||||
|
|||||||
48
internal/usecase/repair_prefix.go
Normal file
48
internal/usecase/repair_prefix.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package usecase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// boundedDiagnosticJSON returns a JSON string prefix and whether it represents
|
||||||
|
// the complete normalized input. It retains at most the useful prefix.
|
||||||
|
func boundedDiagnosticJSON(value string, maxBytes int) ([]byte, bool) {
|
||||||
|
if maxBytes < 2 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
limit := maxBytes - 2
|
||||||
|
var prefix strings.Builder
|
||||||
|
used := 0
|
||||||
|
more := false
|
||||||
|
for i := 0; i < len(value); {
|
||||||
|
r, size := utf8.DecodeRuneInString(value[i:])
|
||||||
|
piece := value[i : i+size]
|
||||||
|
if r == utf8.RuneError && size == 1 {
|
||||||
|
piece = "\uFFFD"
|
||||||
|
i++
|
||||||
|
for i < len(value) {
|
||||||
|
r, size = utf8.DecodeRuneInString(value[i:])
|
||||||
|
if r != utf8.RuneError || size != 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i += size
|
||||||
|
}
|
||||||
|
if used+len(piece) > limit {
|
||||||
|
more = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
prefix.WriteString(piece)
|
||||||
|
used += len(piece)
|
||||||
|
}
|
||||||
|
normalized := prefix.String()
|
||||||
|
encoded, _ := json.Marshal(normalized)
|
||||||
|
if len(encoded) > maxBytes {
|
||||||
|
return truncateDiagnosticJSONValue(normalized, maxBytes), false
|
||||||
|
}
|
||||||
|
return encoded, !more
|
||||||
|
}
|
||||||
33
internal/usecase/repair_prefix_test.go
Normal file
33
internal/usecase/repair_prefix_test.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package usecase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBoundedDiagnosticJSON(t *testing.T) {
|
||||||
|
for _, input := range []string{"", "plain", "<&>\n\"", "雪☃", "a\xff\xfe\xffb", "\xff\xfe" + strings.Repeat("z", 100)} {
|
||||||
|
for budget := 0; budget <= 30; budget++ {
|
||||||
|
encoded, complete := boundedDiagnosticJSON(input, budget)
|
||||||
|
if budget < 2 {
|
||||||
|
if encoded != nil || complete {
|
||||||
|
t.Fatalf("budget %d: %q %v", budget, encoded, complete)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(encoded) > budget || !utf8.Valid(encoded) {
|
||||||
|
t.Fatalf("budget %d: %q", budget, encoded)
|
||||||
|
}
|
||||||
|
var decoded string
|
||||||
|
if err := json.Unmarshal(encoded, &decoded); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
normalized := strings.ToValidUTF8(input, "\uFFFD")
|
||||||
|
if !strings.HasPrefix(normalized, decoded) || complete != (decoded == normalized) {
|
||||||
|
t.Fatalf("input %q budget %d: %q complete=%v normalized=%q", input, budget, decoded, complete, normalized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user