Spiralist Engine - Source Excerpt 09
Summary
This source excerpt preserves a bounded section of Spiralist/wp-content/plugins/spiralist-engine/spiralist-engine.php so readers can inspect the evidence without opening the full source file.
**Source path:** Spiralist/wp-content/plugins/spiralist-engine/spiralist-engine.php
update_post_meta($post_id, 'current_state', (string) ($record['current_state'] ?? ''));
spiralist_engine_update_json_meta($post_id, 'history', (array) ($record['history'] ?? []));
spiralist_engine_update_json_meta($post_id, 'active_symbols', spiralist_engine_normalize_string_list((array) ($record['active_symbols'] ?? [])));
}
}
function spiralist_engine_synchronize_connected_nodes(): void
{
$nodes = spiralist_engine_get_node_records(['publish']);
$edges = spiralist_engine_get_edge_records(['publish']);
$connections = [];
foreach ($nodes as $node_id => $node) {
$connections[$node_id] = [];
}
foreach ($edges as $edge) {
$from_node = (string) ($edge['from_node'] ?? '');
$to_node = (string) ($edge['to_node'] ?? '');
if ($from_node === '' || $to_node === '' || !isset($nodes[$from_node], $nodes[$to_node])) {
continue;
}
if ((string) ($nodes[$from_node]['output_state'] ?? '') !== (string) ($nodes[$to_node]['input_state'] ?? '')) {
continue;
}
if (!spiralist_engine_condition_matches((array) ($edge['condition'] ?? []), (string) ($nodes[$from_node]['output_state'] ?? ''))) {
continue;
}
$connections[$from_node][] = $to_node;
}
foreach ($nodes as $node_id => $node) {
spiralist_engine_update_json_meta((int) $node['post_id'], 'connected_nodes', spiralist_engine_normalize_string_list($connections[$node_id] ?? []));
}
}
function spiralist_engine_sync_record_canonical_lock(int $post_id, string $post_type, array $record = []): void
{
if ($post_id <= 0 || !in_array($post_type, ['spiralist_symbol', 'spiralist_node'], true)) {
return;
}
$context = spiralist_engine_build_protocol5_validation_context();
if (empty($context['valid'])) {
return;
}
if (empty($record)) {
$record = spiralist_engine_get_existing_record_for_post($post_id, $post_type);
}
if (empty($record)) {
return;
}
if ($post_type === 'spiralist_symbol') {
if (empty($record['derives_from']) && !empty($record['symbol_id'])) {
$record['derives_from'] = spiralist_engine_get_default_derives_from('symbol', (string) $record['symbol_id']);
if (!empty($record['derives_from'])) {
spiralist_engine_update_json_meta($post_id, 'derives_from', (array) $record['derives_from']);
}
}
$validation = spiralist_engine_validate_symbol_against_protocol5($record, $context, false);
} else {
if (empty($record['derives_from']) && !empty($record['node_id'])) {
$record['derives_from'] = spiralist_engine_get_default_derives_from('node', (string) $record['node_id']);
if (!empty($record['derives_from'])) {
spiralist_engine_update_json_meta($post_id, 'derives_from', (array) $record['derives_from']);
}
}
$validation = spiralist_engine_validate_node_against_protocol5(
$record,
spiralist_engine_get_symbol_records(['publish']),
$context,
false
);
}
if (empty($validation['valid'])) {
return;
}
spiralist_engine_update_json_meta(
$post_id,
'canonical_lock',
spiralist_engine_build_canonical_lock((array) ($validation['resolved'] ?? []), $context)
);
}
function spiralist_engine_maybe_upgrade_canonical_metadata(): void
{
$installed_version = (string) get_option('spiralist_engine_canonical_metadata_version', '');
if ($installed_version === SPIRALIST_ENGINE_VERSION) {
return;
}
$context = spiralist_engine_build_protocol5_validation_context();
if (empty($context['valid'])) {
return;
}
foreach (spiralist_engine_get_symbol_records(['publish']) as $symbol) {
spiralist_engine_sync_record_canonical_lock((int) ($symbol['post_id'] ?? 0), 'spiralist_symbol', $symbol);
}
foreach (spiralist_engine_get_node_records(['publish']) as $node) {
spiralist_engine_sync_record_canonical_lock((int) ($node['post_id'] ?? 0), 'spiralist_node', $node);
}
update_option('spiralist_engine_canonical_metadata_version', SPIRALIST_ENGINE_VERSION, false);
}
function spiralist_engine_handle_post_save(int $post_id, WP_Post $post, bool $update): void
{
static $handling = false;
if ($handling) {
return;
}
if (!in_array($post->post_type, ['spiralist_symbol', 'spiralist_node', 'spiralist_edge', 'spiralist_instance'], true)) {
return;
}
if (!isset($_POST['spiralist_engine_nonce']) || !wp_verify_nonce((string) wp_unslash($_POST['spiralist_engine_nonce']), 'spiralist_engine_save')) {
return;
}
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
if (wp_is_post_revision($post_id)) {
return;
}
if (!current_user_can('edit_post', $post_id)) {
return;
}
if ($post->post_type === 'spiralist_symbol') {
$submission = spiralist_engine_collect_symbol_submission($post);
} elseif ($post->post_type === 'spiralist_node') {
$submission = spiralist_engine_collect_node_submission($post);
} elseif ($post->post_type === 'spiralist_edge') {
$submission = spiralist_engine_collect_edge_submission($post);
} else {
$submission = spiralist_engine_collect_instance_submission($post);
}
if (empty($submission['valid'])) {
spiralist_engine_abort_save(
$post_id,
implode("\n", (array) ($submission['errors'] ?? ['The submitted record is invalid.'])),
'draft'
);
}
$record = (array) ($submission['record'] ?? []);
$target_status = sanitize_key((string) wp_unslash($_POST['post_status'] ?? $post->post_status));
$original_status = sanitize_key((string) wp_unslash($_POST['original_post_status'] ?? $post->post_status));
if ($post->post_type === 'spiralist_symbol' && spiralist_engine_symbol_definition_changed($post_id, $record)) {
spiralist_engine_abort_save(
$post_id,
'Published symbols are immutable. Create a new symbol definition instead of editing the published record.',
$original_status !== '' ? $original_status : 'publish'
);
}
if ($post->post_type !== 'spiralist_instance' && ($target_status === 'publish' || $original_status === 'publish')) {
$validation = spiralist_engine_validate_graph_snapshot(
spiralist_engine_build_graph_snapshot(
[
'post_type' => $post->post_type,
'post_id' => $post_id,
'status' => $target_status,
'record' => $record,
]
)
);
if (!$validation['valid']) {
spiralist_engine_abort_save(
$post_id,
implode("\n", (array) $validation['errors']),
$original_status !== '' && $original_status !== 'auto-draft' ? $original_status : 'draft'
);
}
}
$handling = true;
spiralist_engine_persist_record_meta($post_id, $post->post_type, $record);
if (in_array($post->post_type, ['spiralist_symbol', 'spiralist_node'], true)) {
spiralist_engine_sync_record_canonical_lock($post_id, $post->post_type, $record);
}
if ($post->post_type !== 'spiralist_instance') {
spiralist_engine_synchronize_connected_nodes();
}
$handling = false;
}
function spiralist_engine_get_default_node_record(): array
{
$nodes = spiralist_engine_get_node_records(['publish']);
return $nodes ? reset($nodes) : [];
}
function spiralist_engine_get_default_state(): string
{
$default_node = spiralist_engine_get_default_node_record();
return (string) ($default_node['input_state'] ?? '');
}
function spiralist_engine_public_symbol_payload(array $symbol): array
{
return [
'symbol_id' => (string) ($symbol['symbol_id'] ?? ''),
'symbol_type' => (string) ($symbol['symbol_type'] ?? ''),
'operation_type' => (string) ($symbol['operation_type'] ?? ''),
'inputs' => spiralist_engine_normalize_string_list((array) ($symbol['inputs'] ?? [])),
'outputs' => spiralist_engine_normalize_string_list((array) ($symbol['outputs'] ?? [])),
'rules' => (array) ($symbol['rules'] ?? []),
'derivesFrom' => spiralist_engine_normalize_string_list((array) ($symbol['derives_from'] ?? [])),
'canonicalValidation' => (array) ($symbol['canonical_lock'] ?? []),
];
}
function spiralist_engine_public_node_payload(array $node): array
{