diff --git a/internal/catalogd/subject.go b/internal/catalogd/subject.go index 35e3e70..fbf8b65 100644 --- a/internal/catalogd/subject.go +++ b/internal/catalogd/subject.go @@ -37,19 +37,35 @@ const GenesisHash = "GENESIS" // SubjectManifest mirrors crates/shared/src/types.rs::SubjectManifest. // Keep field tags byte-identical so manifest JSON written by Rust round-trips. +// +// Vertical: omitempty matches Rust's serde-default deserializer accepting +// missing field (default Unknown). For the OTHER fields we deliberately +// avoid omitempty since Rust always emits them. type SubjectManifest struct { - Schema string `json:"schema"` - CandidateID string `json:"candidate_id"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - Status string `json:"status"` - Vertical string `json:"vertical,omitempty"` - Consent SubjectConsent `json:"consent"` - Retention SubjectRetention `json:"retention"` - Datasets []SubjectDatasetRef `json:"datasets"` - SafeViews []string `json:"safe_views"` - AuditLogPath string `json:"audit_log_path"` - AuditLogChainRoot string `json:"audit_log_chain_root"` + Schema string `json:"schema"` + CandidateID string `json:"candidate_id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Status string `json:"status"` + Vertical string `json:"vertical,omitempty"` + Consent SubjectConsent `json:"consent"` + Retention SubjectRetention `json:"retention"` + Datasets []SubjectDatasetRef `json:"datasets"` + SafeViews []string `json:"safe_views"` + AuditLogPath string `json:"audit_log_path"` + AuditLogChainRoot string `json:"audit_log_chain_root"` + BiometricCollection *BiometricCollection `json:"biometric_collection,omitempty"` +} + +// BiometricCollection mirrors crates/shared/src/types.rs::BiometricCollection. +// Written by the Phase 1.6 Gate 3 photo-upload endpoint. None until the +// first biometric upload; cleared on BIPA erasure. +type BiometricCollection struct { + DataPath string `json:"data_path"` + TemplateHash string `json:"template_hash"` + CollectedAt time.Time `json:"collected_at"` + ConsentVersionHash string `json:"consent_version_hash,omitempty"` + Classifications json.RawMessage `json:"classifications,omitempty"` } type SubjectConsent struct {