fix: AUTO tier order ascending + stats/CSV export completeness + UI key-view toggle & exit affordance

- scheduler: BuildChain sorts tiers ascending so tier 1 (highest priority) is tried first; previously descending inverted the chain (P10-1..P10-5)
- stats/api: handleStatsAPI limit→20000; CSV reads full audit via new Stats.AuditRecords (includes *.old rotation); key_names mapped by keyID() masked key; non-admin filter and keys-csv use masked keys
- server: ring buffer NewStats(10000)
- ui: dash-row card scroll area moved to table container (fix overflow below card); key view toggle (re-click same key returns to global) + kpi-exit affordance; rec-exit span
- chat: chain-failure record now surfaces first failed tier; AUTO comment sync
This commit is contained in:
root
2026-08-11 13:36:23 +08:00
parent 32e2fd521a
commit 854b3e2e37
7 changed files with 104 additions and 43 deletions

View File

@ -97,12 +97,12 @@ func TestBuildChainTierOrdering(t *testing.T) {
if len(ch.Tiers) != 3 {
t.Fatalf("tiers = %d, want 3", len(ch.Tiers))
}
if ch.Tiers[0].Tier != 3 || ch.Tiers[1].Tier != 2 || ch.Tiers[2].Tier != 1 {
t.Fatalf("tier order = %d,%d,%d, want 3,2,1", ch.Tiers[0].Tier, ch.Tiers[1].Tier, ch.Tiers[2].Tier)
if ch.Tiers[0].Tier != 1 || ch.Tiers[1].Tier != 2 || ch.Tiers[2].Tier != 3 {
t.Fatalf("tier order = %d,%d,%d, want 1,2,3", ch.Tiers[0].Tier, ch.Tiers[1].Tier, ch.Tiers[2].Tier)
}
// same-tier slots keep configured order, unresolvable rule is dropped
if len(ch.Tiers[2].Slots) != 2 || ch.Tiers[2].Slots[0].Model != "a" || ch.Tiers[2].Slots[1].Model != "d" {
t.Fatalf("tier 1 slots = %+v", ch.Tiers[2].Slots)
if len(ch.Tiers[0].Slots) != 2 || ch.Tiers[0].Slots[0].Model != "a" || ch.Tiers[0].Slots[1].Model != "d" {
t.Fatalf("tier 1 slots = %+v", ch.Tiers[0].Slots)
}
}
@ -182,9 +182,9 @@ func TestChainAllBusyBoundedWaitThenNextTier(t *testing.T) {
a.busy.Store(true)
b.busy.Store(true)
ch := BuildChain([]Rule{
{Tier: 5, Model: "a", Source: "s1"},
{Tier: 5, Model: "b", Source: "s2"},
{Tier: 4, Model: "c", Source: "s3"},
{Tier: 1, Model: "a", Source: "s1"},
{Tier: 1, Model: "b", Source: "s2"},
{Tier: 2, Model: "c", Source: "s3"},
}, bySource(a, b, c))
s := New(0)
t0 := time.Now()