UpdateWithSource applies partial updates to the profile, recording per-field provenance and freshness in FieldMeta. Scalar fields overwrite. List fields (certifications/skills/goals/interests/ directives) default to UPSERT — new items append, and an item whose stem matches an existing entry superse
(updates map[string]string, source string)
| 95 | // ConfirmedAt is bumped so freshness reflects "recently confirmed", not just |
| 96 | // "recently changed". |
| 97 | func (ps *UserProfileStore) UpdateWithSource(updates map[string]string, source string) bool { |
| 98 | ps.mu.Lock() |
| 99 | defer ps.mu.Unlock() |
| 100 | |
| 101 | changed, metaDirty := false, false |
| 102 | for key, value := range updates { |
| 103 | res := ps.applyUpdate(key, strings.TrimSpace(value)) |
| 104 | if res.changed { |
| 105 | changed = true |
| 106 | } |
| 107 | if ps.touchFieldMeta(res, key, source) { |
| 108 | metaDirty = true |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | if changed { |
| 113 | ps.profile.LastUpdated = time.Now() |
| 114 | } |
| 115 | if changed || metaDirty { |
| 116 | ps.persist() |
| 117 | } |
| 118 | return changed |
| 119 | } |
| 120 | |
| 121 | // updateResult describes one applied key/value: which canonical field it |
| 122 | // touched (empty when nothing applies), whether data changed, and whether an |