chore: checkpoint 第一版
ci / verify (push) Canceled after 0s

This commit is contained in:
Codex Local
2026-09-06 17:04:11 +08:00
parent a8cdec98d1
commit 0c2151ace9
659 changed files with 185855 additions and 554 deletions
@@ -21,6 +21,7 @@ import (
"data-terminal-cloud/internal/ratelimit"
"data-terminal-cloud/internal/rtc"
"data-terminal-cloud/internal/voiceprovider"
"data-terminal-cloud/internal/volcsubtitle"
"github.com/jackc/pgx/v5/pgxpool"
)
@@ -207,6 +208,120 @@ func TestServiceIdempotentlyCreatesConversationWithoutPersistingToken(t *testing
t.Fatal(err)
}
}
// A power loss changes the session outcome, not the validity of an already
// prepared summary. Active sessions and other subjects remain excluded.
for _, priorStatus := range []string{"COMPLETED", "FAILED", "ACTIVE"} {
t.Run("continuity_"+priorStatus, func(t *testing.T) {
tx, err := pool.Begin(ctx)
if err != nil {
t.Fatal(err)
}
defer tx.Rollback(context.Background())
if _, err = tx.Exec(ctx, `UPDATE conversation SET status=$2 WHERE id=$1::uuid`, testPriorConversationID, priorStatus); err != nil {
t.Fatal(err)
}
summaries, err := selectRecentConversationSummaries(ctx, tx, "10000000-0000-0000-0000-000000000001", testSubjectID, 3)
if err != nil {
t.Fatal(err)
}
want := 1
if priorStatus == "ACTIVE" {
want = 0
}
if len(summaries) != want {
t.Fatalf("status=%s summaries=%d want=%d", priorStatus, len(summaries), want)
}
summaries, err = selectRecentConversationSummaries(ctx, tx, "10000000-0000-0000-0000-000000000001", "90000000-0000-0000-0000-000000009999", 3)
if err != nil || len(summaries) != 0 {
t.Fatalf("unrelated subject summaries=%d err=%v", len(summaries), err)
}
})
}
t.Run("hardware_terminal_extracts_latest_turns_once", func(t *testing.T) {
tx, err := pool.Begin(ctx)
if err != nil {
t.Fatal(err)
}
defer tx.Rollback(context.Background())
if _, err = tx.Exec(ctx, `INSERT INTO conversation_turn(tenant_id,subject_id,conversation_id,turn_key,sequence_no,speaker,start_at,end_at,final_text,source_type)
VALUES('10000000-0000-0000-0000-000000000001',$1::uuid,$2::uuid,'prior-agent-2',2,'agent','2026-08-23T10:01:06Z','2026-08-23T10:01:08Z','明白了。','device')`, testSubjectID, testPriorConversationID); err != nil {
t.Fatal(err)
}
for i := 0; i < 2; i++ {
if err := enqueueHardwareContentExtraction(ctx, tx, outbox.NewStore(pool), "10000000-0000-0000-0000-000000000001", testPriorConversationID); err != nil {
t.Fatal(err)
}
}
var count, version int
if err := tx.QueryRow(ctx, `SELECT count(*),COALESCE(max((payload->>'generation_version')::int),0) FROM outbox_event WHERE aggregate_id=$1::uuid AND deduplication_key LIKE 'content-extraction-v1:%:hardware-terminal:%'`, testPriorConversationID).Scan(&count, &version); err != nil {
t.Fatal(err)
}
if count != 1 || version != 2 {
t.Fatalf("events=%d generation=%d; want 1 and 2", count, version)
}
})
t.Run("native_subtitles_probe_then_primary_dedup_consent", func(t *testing.T) {
tx, err := pool.Begin(ctx)
if err != nil {
t.Fatal(err)
}
defer tx.Rollback(context.Background())
_, err = tx.Exec(ctx, `INSERT INTO hardware_agent_session(tenant_id,conversation_id,provider_session_ref,bot_id,transport,session_nonce_digest,config_digest,status,capability_snapshot)
VALUES('10000000-0000-0000-0000-000000000001',$1::uuid,'native-subtitle-fixture','bot','low_load',repeat('a',64),repeat('b',64),'COMPLETED','{"subtitle_device_user_id":"device","subtitle_agent_user_id":"bot","native_subtitle_primary":false}')`, testPriorConversationID)
if err != nil {
t.Fatal(err)
}
_, err = tx.Exec(ctx, `INSERT INTO consent_record(tenant_id,subject_id,consent_type,policy_version,notice_digest,actor_user_id) VALUES('10000000-0000-0000-0000-000000000001',$1::uuid,'transcript_storage','native-fixture',repeat('a',64),'10000000-0000-0000-0000-000000000101')`, testSubjectID)
if err != nil {
t.Fatal(err)
}
var publicID string
if err = tx.QueryRow(ctx, `SELECT public_id::text FROM conversation WHERE id=$1::uuid`, testPriorConversationID).Scan(&publicID); err != nil {
t.Fatal(err)
}
zero, one := int64(0), int64(1)
packet := volcsubtitle.Packet{Type: "subtitle", Data: []volcsubtitle.Segment{
{UserID: "device", RoundID: &zero, Sequence: &zero, Definite: true, Text: "第一句"},
{UserID: "bot", RoundID: &zero, Sequence: &one, Definite: true, Paragraph: true, Text: "第二句"},
}}
svc := NewNativeSubtitleService(pool)
result, err := svc.processNativeSubtitleTx(ctx, tx, publicID, packet)
if err != nil || result.Mode != "probe" || result.Accepted != 0 {
t.Fatalf("probe %+v %v", result, err)
}
_, err = tx.Exec(ctx, `UPDATE hardware_agent_session SET capability_snapshot=jsonb_set(capability_snapshot,'{native_subtitle_primary}','true') WHERE conversation_id=$1::uuid`, testPriorConversationID)
if err != nil {
t.Fatal(err)
}
result, err = svc.processNativeSubtitleTx(ctx, tx, publicID, packet)
if err != nil || result.Accepted != 2 {
t.Fatalf("primary %+v %v", result, err)
}
result, err = svc.processNativeSubtitleTx(ctx, tx, publicID, packet)
if err != nil || result.Accepted != 0 || result.Duplicates != 2 {
t.Fatalf("duplicate %+v %v", result, err)
}
var count, version int
if err = tx.QueryRow(ctx, `SELECT count(*),max((payload->>'generation_version')::int) FROM outbox_event WHERE aggregate_id=$1::uuid AND deduplication_key LIKE 'content-extraction-v1:%:hardware-terminal:%'`, testPriorConversationID).Scan(&count, &version); err != nil || count != 1 || version != 3 {
t.Fatalf("extraction count=%d version=%d err=%v", count, version, err)
}
packet.Data[0].UserID = "unknown"
if _, err = svc.processNativeSubtitleTx(ctx, tx, publicID, packet); !errors.Is(err, ErrNativeSubtitleSpeaker) {
t.Fatalf("unknown speaker: %v", err)
}
packet.Data[0].UserID = "device"
packet.Data[0].Text = "conflicting final"
if _, err = svc.processNativeSubtitleTx(ctx, tx, publicID, packet); !errors.Is(err, ErrHardwareEventConflict) {
t.Fatalf("conflict: %v", err)
}
_, err = tx.Exec(ctx, `UPDATE consent_record SET withdrawn_at=now() WHERE subject_id=$1::uuid AND consent_type='transcript_storage'`, testSubjectID)
if err != nil {
t.Fatal(err)
}
if _, err = svc.processNativeSubtitleTx(ctx, tx, publicID, packet); !errors.Is(err, ErrTranscriptStorageNotAllowed) {
t.Fatalf("withdrawal: %v", err)
}
})
configService, err := opsconfig.NewService(pool, audit.NewRepository())
if err != nil {
t.Fatal(err)