fix(v3-vision): platform-wide hardening of ID Vision models

Hardened root_validators in Journal, Post, Page, and Hosted File models to use Union[int, str] for Vision ID fields. This prevents resolved integer IDs from being deleted during CREATE/UPDATE operations, resolving a critical regression found during Post Comment bug fixing.
This commit is contained in:
Scott Idem
2026-02-05 20:38:19 -05:00
parent 78f04bca50
commit a7c82615ab
4 changed files with 64 additions and 65 deletions

View File

@@ -16,12 +16,12 @@ class Post_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
# --- Standardized Vision IDs (Strings) ---
id: Optional[str] = Field(None, **base_fields['post_id_random'])
post_id: Optional[str] = Field(None, **base_fields['post_id_random'])
account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
person_id: Optional[str] = Field(None, **base_fields['person_id_random'])
user_id: Optional[str] = Field(None, **base_fields['user_id_random'])
# --- Standardized Vision IDs (Strings for API, Integers for DB) ---
id: Optional[Union[int, str]] = Field(None, **base_fields['post_id_random'])
post_id: Optional[Union[int, str]] = Field(None, **base_fields['post_id_random'])
account_id: Optional[Union[int, str]] = Field(None, **base_fields['account_id_random'])
person_id: Optional[Union[int, str]] = Field(None, **base_fields['person_id_random'])
user_id: Optional[Union[int, str]] = Field(None, **base_fields['user_id_random'])
external_person_id: Optional[str] # Person ID generated by external system (should be stable and not change)
@@ -93,24 +93,25 @@ class Post_Base(BaseModel):
def map_v3_ids(cls, values):
"""
Vision Transformer:
Map DB keys to clean API keys and strip internal integers.
Map DB keys to clean API keys and strip internal integers during READ operations.
During CREATE (POST) operations, we ensure resolved integers are preserved.
"""
# 1. Map Random Strings to Clean Names
if rid := values.get('id_random') or values.get('post_id_random'):
rid = values.get('id_random') or values.get('post_id_random')
if rid and isinstance(rid, str):
values['id'] = rid
values['post_id'] = rid
if a_rid := values.get('account_id_random'):
values['account_id'] = a_rid
if p_rid := values.get('person_id_random'):
values['person_id'] = p_rid
if u_rid := values.get('user_id_random'):
values['user_id'] = u_rid
if a_rid := values.get('account_id_random'): values['account_id'] = a_rid
if p_rid := values.get('person_id_random'): values['person_id'] = p_rid
if u_rid := values.get('user_id_random'): values['user_id'] = u_rid
# 2. Prevent "Collision Population"
# 2. Prevent "Collision Population" or leakage of integers during API responses
for k in ['id', 'post_id', 'account_id', 'person_id', 'user_id']:
if k in values and not isinstance(values[k], str):
del values[k]
val = values.get(k)
if val is not None and not isinstance(val, str):
if values.get(f'{k}_random') or (k=='id' and values.get('id_random')):
del values[k]
return values