Problem
SqliteDataLayer.create() stores a StorableRecord's data_ payload
verbatim, bypassing the wire→core normalisation that Record.from_obj /
object_to_record applies on every other write path.
vultron/adapters/driven/datalayer_sqlite/crud.py:50-53:
if isinstance(record, StorableRecord):
rec = Record(id_=record.id_, type_=record.type_, data_=record.data_)
Record.from_obj is where _project_shadowing_wire_obj / _normalize_to_core
live (vultron/adapters/driven/db_record.py, added in #2232). Handing
crud.create a StorableRecord skips them entirely, so a wire-shaped payload
(rm_state / vfd_state flat, or camelCase keys) can be persisted under a
core type_ such as "CaseParticipant" or "VulnerabilityCase".
save() and save_many() are unaffected — both go through
object_to_record.
Why it matters
A row written this way is a shape mismatch the read path then has to repair.
That repair now exists (_from_row projects wire-spelled rows back to core via
to_core(), #2278), but it is a read-side rescue for a write-side defect: the
canonical persisted shape is only canonical on the paths that normalise
(SDO-03-002, ADR-0036, ADR-0062, DL-05-002).
Known callers of the bypass
vultron/core/behaviors/helpers.py — UpdateObject and CreateObject both
build StorableRecord(data_=...) straight from blackboard dicts, so any BT
node writing through them inherits the bypass.
- Any direct
dl.create(StorableRecord(...)) call.
Suggested direction
Route StorableRecord payloads through the same normalisation as
Record.from_obj before insert — either by calling the normaliser on data_
in crud.create, or by having StorableRecord construction go through
Record.from_obj. Needs a decision about whether normalisation should be able
to reject a write (raise) or only rewrite it, which is why this is not folded
into #2278.
Discovered by
/pr-triage on PR #2278 (finding phase8-normalize-bypassed-by-crud-write-path-0).
Problem
SqliteDataLayer.create()stores aStorableRecord'sdata_payloadverbatim, bypassing the wire→core normalisation that
Record.from_obj/object_to_recordapplies on every other write path.vultron/adapters/driven/datalayer_sqlite/crud.py:50-53:Record.from_objis where_project_shadowing_wire_obj/_normalize_to_corelive (
vultron/adapters/driven/db_record.py, added in #2232). Handingcrud.createaStorableRecordskips them entirely, so a wire-shaped payload(
rm_state/vfd_stateflat, or camelCase keys) can be persisted under acore
type_such as"CaseParticipant"or"VulnerabilityCase".save()andsave_many()are unaffected — both go throughobject_to_record.Why it matters
A row written this way is a shape mismatch the read path then has to repair.
That repair now exists (
_from_rowprojects wire-spelled rows back to core viato_core(), #2278), but it is a read-side rescue for a write-side defect: thecanonical persisted shape is only canonical on the paths that normalise
(SDO-03-002, ADR-0036, ADR-0062, DL-05-002).
Known callers of the bypass
vultron/core/behaviors/helpers.py—UpdateObjectandCreateObjectbothbuild
StorableRecord(data_=...)straight from blackboard dicts, so any BTnode writing through them inherits the bypass.
dl.create(StorableRecord(...))call.Suggested direction
Route
StorableRecordpayloads through the same normalisation asRecord.from_objbefore insert — either by calling the normaliser ondata_in
crud.create, or by havingStorableRecordconstruction go throughRecord.from_obj. Needs a decision about whether normalisation should be ableto reject a write (raise) or only rewrite it, which is why this is not folded
into #2278.
Discovered by
/pr-triageon PR #2278 (findingphase8-normalize-bypassed-by-crud-write-path-0).