Implement integer source units and chunk payloads

This commit is contained in:
2026-07-07 18:34:23 +00:00
parent 4f057b99ac
commit 9e3f8809b3
45 changed files with 618 additions and 451 deletions

View File

@@ -10,7 +10,7 @@ type SourceDocument struct {
}
type SourceUnit struct {
ID string `json:"id"`
ID int `json:"id"`
Kind string `json:"kind"`
Text string `json:"text"`
Metadata map[string]any `json:"metadata,omitempty"`
@@ -18,6 +18,6 @@ type SourceUnit struct {
type SourceRef struct {
SourceID string `json:"source_id"`
StartUnitID string `json:"start_unit_id"`
EndUnitID string `json:"end_unit_id"`
StartUnitID int `json:"start_unit_id"`
EndUnitID int `json:"end_unit_id"`
}

View File

@@ -96,13 +96,8 @@ func TestValidateDocumentMissingUnitFields(t *testing.T) {
}{
{
name: "id",
mutate: func(doc *SourceDocument) { doc.Units[1].ID = "" },
wantErr: "source unit[1].id must not be empty",
},
{
name: "id surrounding whitespace",
mutate: func(doc *SourceDocument) { doc.Units[1].ID = " u2 " },
wantErr: "source unit[1].id \" u2 \" must not contain leading or trailing whitespace",
mutate: func(doc *SourceDocument) { doc.Units[1].ID = 0 },
wantErr: "source unit[1].id must be positive",
},
{
name: "kind",
@@ -135,14 +130,14 @@ func TestValidateDocumentMissingUnitFields(t *testing.T) {
func TestValidateDocumentDuplicateUnitIDs(t *testing.T) {
doc := validDocument()
doc.Units[1].ID = "u1"
doc.Units[1].ID = 1
err := ValidateDocument(doc)
if err == nil {
t.Fatal("ValidateDocument() error = nil, want error")
}
if err.Error() != "source unit id \"u1\" is duplicated" {
if err.Error() != "source unit id 1 is duplicated" {
t.Fatalf("ValidateDocument() error = %q", err.Error())
}
}
@@ -151,8 +146,8 @@ func TestValidateRefValid(t *testing.T) {
doc := validDocument()
ref := SourceRef{
SourceID: "source-1",
StartUnitID: "u1",
EndUnitID: "u2",
StartUnitID: 1,
EndUnitID: 2,
}
if err := ValidateRef(doc, ref); err != nil {
@@ -164,8 +159,8 @@ func TestValidateRefSourceIDMismatch(t *testing.T) {
doc := validDocument()
ref := SourceRef{
SourceID: "source-2",
StartUnitID: "u1",
EndUnitID: "u2",
StartUnitID: 1,
EndUnitID: 2,
}
err := ValidateRef(doc, ref)
@@ -186,43 +181,33 @@ func TestValidateRefMissingUnitIDs(t *testing.T) {
}{
{
name: "missing source id",
ref: SourceRef{StartUnitID: "u1", EndUnitID: "u2"},
ref: SourceRef{StartUnitID: 1, EndUnitID: 2},
wantErr: "source ref source_id must not be empty",
},
{
name: "source id surrounding whitespace",
ref: SourceRef{SourceID: " source-1 ", StartUnitID: "u1", EndUnitID: "u2"},
ref: SourceRef{SourceID: " source-1 ", StartUnitID: 1, EndUnitID: 2},
wantErr: "source ref source_id \" source-1 \" must not contain leading or trailing whitespace",
},
{
name: "missing start id",
ref: SourceRef{SourceID: "source-1", EndUnitID: "u2"},
wantErr: "source ref start_unit_id must not be empty",
},
{
name: "start id surrounding whitespace",
ref: SourceRef{SourceID: "source-1", StartUnitID: " u1 ", EndUnitID: "u2"},
wantErr: "source ref start_unit_id \" u1 \" must not contain leading or trailing whitespace",
ref: SourceRef{SourceID: "source-1", EndUnitID: 2},
wantErr: "source ref start_unit_id must be positive",
},
{
name: "missing end id",
ref: SourceRef{SourceID: "source-1", StartUnitID: "u1"},
wantErr: "source ref end_unit_id must not be empty",
},
{
name: "end id surrounding whitespace",
ref: SourceRef{SourceID: "source-1", StartUnitID: "u1", EndUnitID: " u2 "},
wantErr: "source ref end_unit_id \" u2 \" must not contain leading or trailing whitespace",
ref: SourceRef{SourceID: "source-1", StartUnitID: 1},
wantErr: "source ref end_unit_id must be positive",
},
{
name: "unknown start id",
ref: SourceRef{SourceID: "source-1", StartUnitID: "u9", EndUnitID: "u2"},
wantErr: "source ref start_unit_id \"u9\" was not found",
ref: SourceRef{SourceID: "source-1", StartUnitID: 9, EndUnitID: 2},
wantErr: "source ref start_unit_id 9 was not found",
},
{
name: "unknown end id",
ref: SourceRef{SourceID: "source-1", StartUnitID: "u1", EndUnitID: "u9"},
wantErr: "source ref end_unit_id \"u9\" was not found",
ref: SourceRef{SourceID: "source-1", StartUnitID: 1, EndUnitID: 9},
wantErr: "source ref end_unit_id 9 was not found",
},
}
@@ -244,8 +229,8 @@ func TestValidateRefReversedUnitOrder(t *testing.T) {
doc := validDocument()
ref := SourceRef{
SourceID: "source-1",
StartUnitID: "u2",
EndUnitID: "u1",
StartUnitID: 2,
EndUnitID: 1,
}
err := ValidateRef(doc, ref)
@@ -261,7 +246,7 @@ func TestValidateRefReversedUnitOrder(t *testing.T) {
func TestUnitIndex(t *testing.T) {
doc := validDocument()
index, ok := UnitIndex(doc, "u2")
index, ok := UnitIndex(doc, 2)
if !ok {
t.Fatal("UnitIndex() ok = false, want true")
}
@@ -269,7 +254,7 @@ func TestUnitIndex(t *testing.T) {
t.Fatalf("UnitIndex() index = %d, want 1", index)
}
index, ok = UnitIndex(doc, "u9")
index, ok = UnitIndex(doc, 9)
if ok {
t.Fatal("UnitIndex() ok = true, want false")
}
@@ -286,12 +271,12 @@ func validDocument() *SourceDocument {
Digest: "sha256:abc123",
Units: []SourceUnit{
{
ID: "u1",
ID: 1,
Kind: "paragraph",
Text: "First unit.",
},
{
ID: "u2",
ID: 2,
Kind: "paragraph",
Text: "Second unit.",
},

View File

@@ -28,13 +28,10 @@ func ValidateDocument(doc *SourceDocument) error {
return fmt.Errorf("source document units must not be empty")
}
seenUnitIDs := make(map[string]struct{}, len(doc.Units))
seenUnitIDs := make(map[int]struct{}, len(doc.Units))
for i, unit := range doc.Units {
if isBlank(unit.ID) {
return fmt.Errorf("source unit[%d].id must not be empty", i)
}
if hasSurroundingWhitespace(unit.ID) {
return fmt.Errorf("source unit[%d].id %q must not contain leading or trailing whitespace", i, unit.ID)
if unit.ID <= 0 {
return fmt.Errorf("source unit[%d].id must be positive", i)
}
if isBlank(unit.Kind) {
return fmt.Errorf("source unit[%d].kind must not be empty", i)
@@ -43,7 +40,7 @@ func ValidateDocument(doc *SourceDocument) error {
return fmt.Errorf("source unit[%d].text must not be empty", i)
}
if _, ok := seenUnitIDs[unit.ID]; ok {
return fmt.Errorf("source unit id %q is duplicated", unit.ID)
return fmt.Errorf("source unit id %d is duplicated", unit.ID)
}
seenUnitIDs[unit.ID] = struct{}{}
}
@@ -61,17 +58,11 @@ func ValidateRef(doc *SourceDocument, ref SourceRef) error {
if hasSurroundingWhitespace(ref.SourceID) {
return fmt.Errorf("source ref source_id %q must not contain leading or trailing whitespace", ref.SourceID)
}
if isBlank(ref.StartUnitID) {
return fmt.Errorf("source ref start_unit_id must not be empty")
if ref.StartUnitID <= 0 {
return fmt.Errorf("source ref start_unit_id must be positive")
}
if hasSurroundingWhitespace(ref.StartUnitID) {
return fmt.Errorf("source ref start_unit_id %q must not contain leading or trailing whitespace", ref.StartUnitID)
}
if isBlank(ref.EndUnitID) {
return fmt.Errorf("source ref end_unit_id must not be empty")
}
if hasSurroundingWhitespace(ref.EndUnitID) {
return fmt.Errorf("source ref end_unit_id %q must not contain leading or trailing whitespace", ref.EndUnitID)
if ref.EndUnitID <= 0 {
return fmt.Errorf("source ref end_unit_id must be positive")
}
if ref.SourceID != doc.ID {
return fmt.Errorf("source ref source_id %q does not match document id %q", ref.SourceID, doc.ID)
@@ -79,20 +70,20 @@ func ValidateRef(doc *SourceDocument, ref SourceRef) error {
startIndex, ok := UnitIndex(doc, ref.StartUnitID)
if !ok {
return fmt.Errorf("source ref start_unit_id %q was not found", ref.StartUnitID)
return fmt.Errorf("source ref start_unit_id %d was not found", ref.StartUnitID)
}
endIndex, ok := UnitIndex(doc, ref.EndUnitID)
if !ok {
return fmt.Errorf("source ref end_unit_id %q was not found", ref.EndUnitID)
return fmt.Errorf("source ref end_unit_id %d was not found", ref.EndUnitID)
}
if startIndex > endIndex {
return fmt.Errorf("source ref start_unit_id %q appears after end_unit_id %q", ref.StartUnitID, ref.EndUnitID)
return fmt.Errorf("source ref start_unit_id %d appears after end_unit_id %d", ref.StartUnitID, ref.EndUnitID)
}
return nil
}
func UnitIndex(doc *SourceDocument, unitID string) (int, bool) {
func UnitIndex(doc *SourceDocument, unitID int) (int, bool) {
if doc == nil {
return 0, false
}