feat: expand companion platform, device controls, and memoir workflows
ci / verify (push) Canceled after 0s

Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
This commit is contained in:
Codex Local
2026-10-08 10:06:44 +08:00
parent 98fb2965d0
commit bf1233d5df
861 changed files with 94614 additions and 3209 deletions
+64
View File
@@ -5,6 +5,10 @@ import (
"errors"
"strings"
"testing"
"time"
"unicode/utf8"
"data-terminal-cloud/internal/outbox"
)
func TestDeleteProcessorValidationAndSafeErrors(t *testing.T) {
@@ -29,3 +33,63 @@ func TestDeleteProcessorValidationAndSafeErrors(t *testing.T) {
t.Fatalf("truncated safe error length=%d", len(got))
}
}
func TestDeletionRetryCooldownMatchesReceipt(t *testing.T) {
cause := errors.New("temporary deletion dependency failure")
for _, test := range []struct {
name string
err error
want time.Duration
}{
{"no supplier delay", outbox.Retryable(cause), 30 * time.Second},
{"short supplier delay", outbox.RetryAfter(cause, time.Second), 30 * time.Second},
{"long supplier delay", outbox.RetryAfter(cause, 2*time.Minute), 2 * time.Minute},
} {
t.Run(test.name, func(t *testing.T) {
got := deletionRetryError(test.err)
if !outbox.IsRetryable(got) || outbox.RetryDelay(got) != test.want || !errors.Is(got, cause) {
t.Fatalf("retry metadata or cause changed: %v delay=%v", got, outbox.RetryDelay(got))
}
})
}
if got := deletionRetryError(cause); got != cause || outbox.IsRetryable(got) {
t.Fatalf("permanent failure became retryable: %v", got)
}
if got := deletionRetryError(nil); got != nil {
t.Fatalf("nil failure became non-nil: %v", got)
}
}
func TestSafeDeletionErrorRetainsValidUTF8(t *testing.T) {
// The former 450-byte slice cut the first Chinese character in this message.
message := strings.Repeat("x", 449) + "删除依赖暂不可用"
got := safeDeletionError(errors.New(message))
if !utf8.ValidString(got) || utf8.RuneCountInString(got) != 450 || !strings.HasSuffix(got, "删") {
t.Fatalf("failure receipt is not bounded valid text: bytes=%d runes=%d", len(got), utf8.RuneCountInString(got))
}
if got := safeDeletionError(errors.New("短错误")); got != "短错误" {
t.Fatalf("short Unicode error changed: %q", got)
}
}
func TestCallMemoryDeletionReportsOutstandingProofs(t *testing.T) {
if err := (callMemoryDeletionPending{}).err(); err != nil {
t.Fatalf("fully reconciled state was blocked: %v", err)
}
for _, test := range []struct {
pending callMemoryDeletionPending
want string
}{
{callMemoryDeletionPending{Projection: true}, "memory_projection"},
{callMemoryDeletionPending{Runtime: true}, "runtime_stop_confirmation"},
{callMemoryDeletionPending{Backup: true}, "backup_cleanup_evidence"},
{callMemoryDeletionPending{LegacyProjection: true}, "legacy_projection"},
{callMemoryDeletionPending{LegacyCleanup: true}, "legacy_cleanup_evidence"},
{callMemoryDeletionPending{Runtime: true, Backup: true}, "runtime_stop_confirmation, backup_cleanup_evidence"},
} {
err := test.pending.err()
if err == nil || err.Error() != "call memory deletion pending: "+test.want || !outbox.IsRetryable(err) || outbox.RetryDelay(err) != time.Minute {
t.Fatalf("missing cleanup evidence was hidden or acknowledged: want=%q error=%v", test.want, err)
}
}
}