test(form-field): pin conditional_logic activity log payload contract
ARCH §8.6 specifies a dual-event contract on logic changes — a
`field.updated` row carrying old/new diffs of the reconstructed JSON
shape, plus a semantic `field.conditional_logic_replaced` row from
inside `replaceLogic()`. The semantic event is already pinned by
`FormFieldConditionalLogicServiceTest`. The diff payload contract was
documented but unasserted.
Two new tests:
- `test_field_updated_activity_log_contains_conditional_logic_diff_when_tree_changes`
Pins old/new payload shapes via byte-equal `json_encode` comparison
(mirrors ConditionalLogicSnapshotAndResourceParityTest's
associative-array key-order trap). Both rows share the same
causer_id.
- `test_field_updated_without_logic_change_does_not_emit_conditional_logic_diff`
Pins the negative: bare label-only updates must NOT carry a
`conditional_logic` key in the field.updated payload, and must NOT
emit a semantic `field.conditional_logic_replaced` row.
The first test passed against the original implementation; the second
required `FormFieldService::update()` to filter `conditional_logic`
out of the activity-log payload when the reconstructed shape didn't
change between pre- and post-write. Adjustment lands in this commit:
the `$before` / `$new` arrays now only carry the key when
`$currentConditionalShape !== $newConditionalShape`.
Tests: 1148 → 1150 green (3099 → 3110 assertions).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -100,7 +100,6 @@ final class FormFieldService
|
||||
|
||||
$before = [
|
||||
'binding' => $currentBindingShape,
|
||||
'conditional_logic' => $currentConditionalShape,
|
||||
'is_filterable' => $field->is_filterable,
|
||||
'is_pii' => $field->is_pii,
|
||||
'field_type' => $field->field_type,
|
||||
@@ -123,15 +122,26 @@ final class FormFieldService
|
||||
|
||||
$this->schemaService->bumpVersion($schema);
|
||||
|
||||
$newConditionalShape = $this->conditionalLogicService->toJsonShape($field->fresh()?->rootConditionalLogicGroup());
|
||||
$new = [
|
||||
'binding' => $this->bindingService->toJsonShape($field->bindings()->first()),
|
||||
'is_filterable' => $field->is_filterable,
|
||||
'is_pii' => $field->is_pii,
|
||||
'field_type' => $field->field_type,
|
||||
];
|
||||
|
||||
// ARCH §8.6: include conditional_logic in the field.updated diff only
|
||||
// when the tree actually changed. Bare label/sort_order updates and
|
||||
// payloads that did not touch conditional_logic must not carry the
|
||||
// key — otherwise downstream activity-log consumers see noise.
|
||||
if ($currentConditionalShape !== $newConditionalShape) {
|
||||
$before['conditional_logic'] = $currentConditionalShape;
|
||||
$new['conditional_logic'] = $newConditionalShape;
|
||||
}
|
||||
|
||||
$field->logFieldChange('field.updated', [
|
||||
'old' => $before,
|
||||
'new' => [
|
||||
'binding' => $this->bindingService->toJsonShape($field->bindings()->first()),
|
||||
'conditional_logic' => $this->conditionalLogicService->toJsonShape($field->fresh()?->rootConditionalLogicGroup()),
|
||||
'is_filterable' => $field->is_filterable,
|
||||
'is_pii' => $field->is_pii,
|
||||
'field_type' => $field->field_type,
|
||||
],
|
||||
'new' => $new,
|
||||
]);
|
||||
|
||||
if ($before['is_filterable'] !== $field->is_filterable) {
|
||||
|
||||
Reference in New Issue
Block a user