refactor(store/pg): rename mustParseUUID to parseUUIDOrNil (honest name)

Final step of Phase 4: rename the silently-nil-on-error helper so its
behavior is self-documenting at the call site. No behavior change — all
remaining call sites (~24) were already classified as WARN-acceptable
(read-only SELECT WHERE paths with validated inputs from cursor
pagination or WS boundary) during sub-step 4b migration.

The parseUUID error variant stays as-is for CRITICAL writes.

Also cleans up a now-stale comment in vault_handler_upload.go.

Phase 4 Step 4d of agent identity hardening (TD-1).
This commit is contained in:
viettranx committed 2026-04-11 21:22:23 +07:00
1 parent 5ff29d051d
commit d29c3dd943
7 files changed
+9 -28

No files matched your search

+1 -1
View File
@@ -43,7 +43,7 @@ func (h *VaultHandler) handleUpload(w http.ResponseWriter, r *http.Request) {
// Boundary UUID validation — Fix B (Phase 1, H9 mitigation).
// validateTeamMembership short-circuits on owner role + lite edition (nil teamAccess),
// leaving downstream `mustParseUUID(*doc.TeamID)` as a silent-nil trap. Validate at
// leaving downstream `parseUUIDOrNil(*doc.TeamID)` as a silent-nil trap. Validate at
// the HTTP boundary so bad form input is rejected before any store call or event publish.
// See docs/agent-identity-conventions.md.
if agentIDStr != "" {
+2 -2
View File
@@ -309,7 +309,7 @@ func ExportKGEntities(ctx context.Context, db *sql.DB, agentID uuid.UUID) ([]sto
break
}
// Advance cursor: last entity ID
lastID := mustParseUUID(batch[len(batch)-1].ID)
lastID := parseUUIDOrNil(batch[len(batch)-1].ID)
cursor = lastID
}
return result, nil
@@ -351,7 +351,7 @@ func ExportKGRelations(ctx context.Context, db *sql.DB, agentID uuid.UUID) ([]st
if len(batch) < exportBatchSize {
break
}
lastID := mustParseUUID(batch[len(batch)-1].ID)
lastID := parseUUIDOrNil(batch[len(batch)-1].ID)
cursor = lastID
}
return result, nil
@@ -121,7 +121,7 @@ func (s *PGKnowledgeGraphStore) EmbedEntity(ctx context.Context, entityID, name,
vecStr := vectorToString(embeddings[0])
if _, err := s.db.ExecContext(ctx,
`UPDATE kg_entities SET embedding = $1::vector WHERE id = $2`,
vecStr, mustParseUUID(entityID),
vecStr, parseUUIDOrNil(entityID),
); err != nil {
slog.Warn("kg entity embedding failed", "entity_id", entityID, "error", err)
}
@@ -12,7 +12,7 @@ import (
// ListEntitiesTemporal queries entities with temporal awareness.
// AsOf=nil: current facts only (valid_until IS NULL). AsOf set: facts valid at that time.
func (s *PGKnowledgeGraphStore) ListEntitiesTemporal(ctx context.Context, agentID, userID string, opts store.EntityListOptions, temporal store.TemporalQueryOptions) ([]store.Entity, error) {
aid := mustParseUUID(agentID)
aid := parseUUIDOrNil(agentID)
limit := opts.Limit
if limit <= 0 {
limit = 100
-7
View File
@@ -505,13 +505,6 @@ func parseUUIDOrNil(s string) uuid.UUID {
return id
}
// mustParseUUID is an alias for parseUUIDOrNil kept during the Phase 4
// migration window. Will be removed in sub-step 4d (single-commit rename).
// TODO(Phase 4 4d): remove after all call sites migrate.
func mustParseUUID(s string) uuid.UUID {
return parseUUIDOrNil(s)
}
func vectorToString(v []float32) string {
if len(v) == 0 {
return ""
-12
View File
@@ -70,15 +70,3 @@ func TestParseUUID_ErrorIsUnwrappable(t *testing.T) {
}
}
// TestMustParseUUID_AliasToParseUUIDOrNil verifies the transitional alias
// during Phase 4 migration — mustParseUUID must behave identically to
// parseUUIDOrNil so existing call sites are untouched until rename (4d).
func TestMustParseUUID_AliasToParseUUIDOrNil(t *testing.T) {
u := uuid.New()
if mustParseUUID(u.String()) != u {
t.Error("mustParseUUID should equal parseUUIDOrNil on valid input")
}
if mustParseUUID("garbage") != uuid.Nil {
t.Error("mustParseUUID should return uuid.Nil on invalid input (parseUUIDOrNil semantics)")
}
}
+4 -4
View File
@@ -21,14 +21,14 @@ func appendTeamFilter(q string, args []any, p int, teamID *string, teamIDs []str
ph := make([]string, len(teamIDs))
for i, id := range teamIDs {
ph[i] = fmt.Sprintf("$%d", p)
args = append(args, mustParseUUID(id))
args = append(args, parseUUIDOrNil(id))
p++
}
q += " AND (team_id IS NULL OR team_id IN (" + strings.Join(ph, ",") + "))"
} else if teamID != nil {
if *teamID != "" {
q += fmt.Sprintf(" AND team_id = $%d", p)
args = append(args, mustParseUUID(*teamID))
args = append(args, parseUUIDOrNil(*teamID))
p++
} else {
q += " AND team_id IS NULL"
@@ -495,13 +495,13 @@ func buildSearchTeamFilter(teamID *string, teamIDs []string) searchTeamFilter {
if len(teamIDs) > 0 {
uuids := make([]uuid.UUID, len(teamIDs))
for i, id := range teamIDs {
uuids[i] = mustParseUUID(id)
uuids[i] = parseUUIDOrNil(id)
}
return searchTeamFilter{teamIDs: uuids, active: true}
}
if teamID != nil {
if *teamID != "" {
t := mustParseUUID(*teamID)
t := parseUUIDOrNil(*teamID)
return searchTeamFilter{teamID: &t, active: true}
}
return searchTeamFilter{active: true} // personal-only