返回 DeepSeek-Reasonix
exact_index.go
根目录 / internal / sessioncatalog / exact_index.go
1 package sessioncatalog
2
3 import "context"
4
5 type sessionUpsertMode uint8
6
7 const (
8 upsertExactSource sessionUpsertMode = iota
9 upsertDirectoryProjection
10 )
11
12 // sessionProjectionFieldsBelongToDirectory reports whether an exact-path
13 // record must retain the last complete directory projection. A physical
14 // recovery file cannot prove its logical topic, canonical leaf, or ordinary
15 // visibility without seeing its siblings and ancestors.
16 func sessionProjectionFieldsBelongToDirectory(existing, incoming SessionRecord) bool {
17 return existing.Recovered || incoming.Recovered ||
18 existing.RecoveryGroupID != "" || incoming.RecoveryGroupID != "" ||
19 existing.RecoveryRole != "" && existing.RecoveryRole != RecoveryRoleNormal ||
20 incoming.RecoveryRole != "" && incoming.RecoveryRole != RecoveryRoleNormal
21 }
22
23 func preserveDirectoryProjection(existing SessionRecord, record *SessionRecord) {
24 record.RecoveryCopy = existing.RecoveryCopy
25 record.RecoveryGroupID = existing.RecoveryGroupID
26 record.RecoveryRole = existing.RecoveryRole
27 record.RecoveryCanonical = existing.RecoveryCanonical
28 record.LogicalTopicID = existing.LogicalTopicID
29 record.OrdinaryVisible = existing.OrdinaryVisible
30 if sessionProjectionFieldsBelongToDirectory(existing, *record) {
31 record.TopicID = existing.TopicID
32 record.TopicTitle = existing.TopicTitle
33 }
34 }
35
36 // prepareExactPathProjection avoids publishing unchanged snapshots while
37 // retaining known counts when only legacy sidecar metadata is stale.
38 func (c *Catalog) prepareExactPathProjection(ctx context.Context, raw SessionRecord) (record SessionRecord, skip, projectionDirty bool, err error) {
39 record = normalizeSessionRecord(raw)
40 if !c.opts.MetadataOnly {
41 record = classifyRecoveryLineage(record)
42 }
43 if record.LogicalTopicID == "" {
44 record.LogicalTopicID = record.TopicID
45 }
46 existing, ok, err := c.GetSession(ctx, record.Path)
47 if err != nil {
48 return SessionRecord{}, false, false, err
49 }
50 if !ok || existing.Path == "" || existing.MissingSince != 0 {
51 if c.opts.MetadataOnly {
52 record.OrdinaryVisible = true
53 return record, false, false, nil
54 }
55 if record.Recovered {
56 // A brand-new recovery file has no sibling-aware logical identity yet.
57 // Store a hidden physical shell and let the queued directory pass
58 // publish its final topic and representative atomically.
59 record.TopicID = ""
60 record.TopicTitle = ""
61 record.LogicalTopicID = ""
62 record.OrdinaryVisible = false
63 }
64 return record, false, record.Recovered, nil
65 }
66 projectionDirty = existing.TopicID != raw.TopicID ||
67 existing.Recovered != record.Recovered ||
68 existing.ParentID != record.ParentID ||
69 existing.RecoveryDigest != record.RecoveryDigest ||
70 existing.RecoveryReason != record.RecoveryReason
71 if sessionProjectionFieldsBelongToDirectory(existing, record) && existing.MetaFingerprint != record.MetaFingerprint {
72 // The persisted projection intentionally does not duplicate source and
73 // projected topic ids. A changed recovery sidecar may therefore have
74 // changed a lineage input that only a full directory pass can prove.
75 projectionDirty = true
76 }
77 preserveDirectoryProjection(existing, &record)
78 if sameSessionIndexInput(existing, record) {
79 return record, true, projectionDirty, nil
80 }
81 // A sidecar can be observed in an older, transient state while the
82 // transcript itself has not changed. Never let an exact-path refresh move a
83 // known conversation backwards in the activity-sorted sidebar.
84 if existing.ContentFingerprint == record.ContentFingerprint &&
85 existing.LastActivityAt > record.LastActivityAt {
86 record.LastActivityAt = existing.LastActivityAt
87 }
88 if existing.TurnsState != TurnsUnknown && record.TurnsState == TurnsUnknown {
89 if existing.ContentFingerprint == record.ContentFingerprint {
90 record.Preview = existing.Preview
91 record.Turns = existing.Turns
92 record.TurnsState = existing.TurnsState
93 } else {
94 fillKnownCountHints(&record, existing.Preview, existing.Turns)
95 }
96 }
97 return record, false, projectionDirty, nil
98 }
99
99 lines GO