'; echo '
Walk a Demand through arbitration → plan_links → acceptance chain → closure verdicts.
'; // Picker form (replaces v0.6.x free-form text inputs). self::render_picker_form( $surface, $ref ); if ( $surface !== '' && $ref !== '' ) { // Reuse the REST handler. Bypasses URI routing (avoids URL-encoding fragility around `#`). $req = new WP_REST_Request( 'GET' ); $req->set_url_params( [ 'surface' => $surface, 'ref' => $ref ] ); $resp = SA_Orch_Rest::get_demand_trace( $req ); $data = $resp->get_data(); self::render_trace_results( $data ); } echo ''; } /* ---------- Demand Trace picker (v0.6.2) ---------- */ /** * Demand picker: * - surface dropdown (closed enumeration of 4) * - quick-select strip (SA-ORCH-TEST fixtures pinned + last-traced) * - searchable browser of candidates for the selected surface * - manual ref entry as fallback (validated against known per-surface patterns) * * No new schema; no new endpoints. All candidate data is rendered inline * as JSON for client-side filtering. */ private static function render_picker_form( $surface, $ref ) { $candidates = [ 'fluent-support' => self::candidates_fluent_support(), 'fluent-boards' => self::candidates_fluent_boards(), 'fluentcrm' => self::candidates_fluentcrm(), 'derived' => self::candidates_derived(), ]; $quick = self::quick_select_demands( 10 ); $surface_labels = [ 'fluent-support' => 'fluent-support — Fluent Support tickets', 'fluent-boards' => 'fluent-boards — Fluent Boards tasks', 'fluentcrm' => 'fluentcrm — FluentCRM subscribers', 'derived' => 'derived — rowless / inferred demands', ]; // Per-surface validation regex (mirrors SA_Orch_Bridge_Fluent::validate / resolve). $patterns = [ 'fluent-support' => '^ticket#\\d+$', 'fluent-boards' => '^task#\\d+$', 'fluentcrm' => '^subscriber#\\d+$', 'derived' => '^derived#[A-Za-z0-9_\\-]+$', ]; echo ''; } /** * Vanilla-JS controller for the picker. No jQuery dependency. * Wires: surface change → repopulate browser; filter input → live filter; * candidate click → fill ref input; ref input → pattern hint. */ private static function picker_inline_js() { return <<<'JS' (function () { var data = window.SA_ORCH_PICKER || { candidates: {}, patterns: {} }; var surfaceSel = document.getElementById('demand_surface_select'); var refInput = document.getElementById('demand_ref_input'); var filterInp = document.getElementById('sa-orch-filter'); var listEl = document.getElementById('sa-orch-candidate-list'); var helpEl = document.getElementById('sa-orch-candidate-help'); var statusEl = document.getElementById('sa-orch-ref-status'); if (!surfaceSel || !refInput || !listEl || !helpEl || !filterInp) return; function escapeHtml(s) { return String(s).replace(/[&<>"']/g, function (c) { return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]; }); } function renderCandidates() { var surface = surfaceSel.value; var query = (filterInp.value || '').trim().toLowerCase(); listEl.innerHTML = ''; if (!surface) { helpEl.textContent = 'Pick a surface to load candidates.'; filterInp.disabled = true; return; } filterInp.disabled = false; var pool = (data.candidates || {})[surface] || []; if (!pool.length) { helpEl.textContent = 'No candidates known for this surface.'; return; } var matches = pool; if (query) { matches = pool.filter(function (c) { return c.ref.toLowerCase().indexOf(query) !== -1 || (c.label || '').toLowerCase().indexOf(query) !== -1; }); } helpEl.textContent = matches.length + ' / ' + pool.length + ' candidate' + (pool.length === 1 ? '' : 's') + (query ? ' matching "' + query + '"' : ''); var frag = document.createDocumentFragment(); matches.slice(0, 200).forEach(function (c) { var li = document.createElement('li'); li.style.padding = '5px 8px'; li.style.cursor = 'pointer'; li.style.borderBottom = '1px solid #f0f0f1'; li.style.lineHeight = '1.4'; var tag = c.is_test ? 'TEST' : ''; li.innerHTML = tag + '' + escapeHtml(c.ref) + ''
+ (c.label ? ' — ' + escapeHtml(c.label) : '');
li.addEventListener('mouseover', function () { li.style.background = '#f6f7f7'; });
li.addEventListener('mouseout', function () { if (!li.classList.contains('selected')) li.style.background = ''; });
li.addEventListener('click', function () {
refInput.value = c.ref;
Array.prototype.forEach.call(
listEl.querySelectorAll('li.selected'),
function (e) { e.classList.remove('selected'); e.style.background = ''; }
);
li.classList.add('selected');
li.style.background = '#fff7c2';
validateRef();
refInput.focus();
});
frag.appendChild(li);
});
listEl.appendChild(frag);
}
function validateRef() {
var surface = surfaceSel.value;
var ref = refInput.value.trim();
if (!surface || !ref) {
statusEl.textContent = '';
return;
}
var pattern = (data.patterns || {})[surface];
if (!pattern) {
statusEl.textContent = '';
return;
}
if ((new RegExp(pattern)).test(ref)) {
statusEl.textContent = '✓ valid format';
statusEl.style.color = '#0a7d24';
} else {
statusEl.textContent = '✗ does not match expected pattern';
statusEl.style.color = '#a02b1f';
}
}
surfaceSel.addEventListener('change', function () {
filterInp.value = '';
renderCandidates();
validateRef();
});
filterInp.addEventListener('input', renderCandidates);
refInput.addEventListener('input', validateRef);
// Initial state (e.g. arrived via permalink with both fields preset).
renderCandidates();
validateRef();
})();
JS;
}
/* ---------- Candidate fetchers (per surface) ---------- */
/** Fluent Support tickets, SA-ORCH-TEST pinned first. Cap 50. */
private static function candidates_fluent_support() {
global $wpdb;
$rows = $wpdb->get_results(
"SELECT id, title FROM {$wpdb->prefix}fs_tickets
ORDER BY (title LIKE '[SA-ORCH-TEST]%') DESC, id DESC
LIMIT 50"
);
$out = [];
foreach ( (array) $rows as $r ) {
$title = (string) $r->title;
$out[] = [
'ref' => 'ticket#' . (int) $r->id,
'label' => self::truncate( $title, 80 ),
'is_test' => ( strpos( $title, '[SA-ORCH-TEST]' ) === 0 ),
];
}
return $out;
}
/** Fluent Boards tasks, most-recent first. Cap 50. */
private static function candidates_fluent_boards() {
global $wpdb;
// Defensive: Fluent Boards may not be installed.
$exists = $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $wpdb->prefix . 'fbs_tasks' ) );
if ( ! $exists ) return [];
$rows = $wpdb->get_results(
"SELECT id, title FROM {$wpdb->prefix}fbs_tasks
ORDER BY id DESC LIMIT 50"
);
$out = [];
foreach ( (array) $rows as $r ) {
$title = (string) ( $r->title ?? '' );
$out[] = [
'ref' => 'task#' . (int) $r->id,
'label' => self::truncate( $title, 80 ),
'is_test' => ( strpos( $title, '[SA-ORCH-TEST]' ) === 0 ),
];
}
return $out;
}
/** FluentCRM subscribers, most-recent first. Cap 50. Label = full_name|email. */
private static function candidates_fluentcrm() {
global $wpdb;
$exists = $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $wpdb->prefix . 'fc_subscribers' ) );
if ( ! $exists ) return [];
$rows = $wpdb->get_results(
"SELECT id, full_name, email FROM {$wpdb->prefix}fc_subscribers
ORDER BY id DESC LIMIT 50"
);
$out = [];
foreach ( (array) $rows as $r ) {
$name = trim( (string) ( $r->full_name ?? '' ) );
$email = (string) ( $r->email ?? '' );
$label = $name !== '' ? ( $name . ( $email ? " <{$email}>" : '' ) ) : $email;
$out[] = [
'ref' => 'subscriber#' . (int) $r->id,
'label' => self::truncate( $label, 80 ),
'is_test' => false,
];
}
return $out;
}
/**
* 'derived' surface has no underlying surface table — list every distinct
* derived demand_ref ever recorded in arbitrations or acceptance events.
*/
private static function candidates_derived() {
global $wpdb;
$arb = $wpdb->prefix . SA_ORCH_DB_PREFIX . 'arbitration';
$evt = $wpdb->prefix . SA_ORCH_DB_PREFIX . 'acceptance_event';
$rows = $wpdb->get_results(
"SELECT demand_ref, MAX(last_at) AS last_at FROM (
SELECT demand_ref, MAX(created_at) AS last_at FROM {$arb} WHERE demand_surface='derived' GROUP BY demand_ref
UNION ALL
SELECT demand_ref, MAX(observed_at) AS last_at FROM {$evt} WHERE demand_surface='derived' GROUP BY demand_ref
) sub
GROUP BY demand_ref
ORDER BY last_at DESC LIMIT 50"
);
$out = [];
foreach ( (array) $rows as $r ) {
$out[] = [
'ref' => (string) $r->demand_ref,
'label' => '(derived demand, no surface row)',
'is_test' => false,
];
}
return $out;
}
/**
* Quick-select list: SA-ORCH-TEST tickets pinned, then most-recently-traced
* demands across all surfaces (by max(arbitration.created_at, event.observed_at)).
*/
private static function quick_select_demands( $limit = 10 ) {
global $wpdb;
$arb = $wpdb->prefix . SA_ORCH_DB_PREFIX . 'arbitration';
$evt = $wpdb->prefix . SA_ORCH_DB_PREFIX . 'acceptance_event';
$rows = $wpdb->get_results(
"SELECT demand_surface, demand_ref, MAX(last_at) AS last_at FROM (
SELECT demand_surface, demand_ref, MAX(created_at) AS last_at FROM {$arb} GROUP BY demand_surface, demand_ref
UNION ALL
SELECT demand_surface, demand_ref, MAX(observed_at) AS last_at FROM {$evt} GROUP BY demand_surface, demand_ref
) sub
GROUP BY demand_surface, demand_ref
ORDER BY last_at DESC LIMIT 30"
);
if ( empty( $rows ) ) return [];
// Resolve labels + is_test per row.
$out = [];
foreach ( $rows as $r ) {
$surface = (string) $r->demand_surface;
$ref = (string) $r->demand_ref;
list( $label, $is_test ) = self::resolve_label( $surface, $ref );
$out[] = [
'surface' => $surface,
'ref' => $ref,
'label' => $label,
'is_test' => $is_test,
'last_at' => (string) $r->last_at,
];
}
// Pin SA-ORCH-TEST first; preserve last_at ordering within each group.
usort( $out, function ( $a, $b ) {
if ( $a['is_test'] !== $b['is_test'] ) return $a['is_test'] ? -1 : 1;
return strcmp( $b['last_at'], $a['last_at'] );
} );
return array_slice( $out, 0, (int) $limit );
}
/** Resolve a (surface, ref) to a human label + is_test flag. Best-effort, tolerant of missing tables. */
private static function resolve_label( $surface, $ref ) {
global $wpdb;
if ( $surface === 'fluent-support' && preg_match( '/^ticket#(\d+)$/', $ref, $m ) ) {
$title = (string) $wpdb->get_var( $wpdb->prepare(
"SELECT title FROM {$wpdb->prefix}fs_tickets WHERE id=%d", (int) $m[1]
) );
return [ self::truncate( $title, 80 ), strpos( $title, '[SA-ORCH-TEST]' ) === 0 ];
}
if ( $surface === 'fluent-boards' && preg_match( '/^task#(\d+)$/', $ref, $m ) ) {
if ( $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $wpdb->prefix . 'fbs_tasks' ) ) ) {
$title = (string) $wpdb->get_var( $wpdb->prepare(
"SELECT title FROM {$wpdb->prefix}fbs_tasks WHERE id=%d", (int) $m[1]
) );
return [ self::truncate( $title, 80 ), strpos( $title, '[SA-ORCH-TEST]' ) === 0 ];
}
}
if ( $surface === 'fluentcrm' && preg_match( '/^subscriber#(\d+)$/', $ref, $m ) ) {
if ( $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $wpdb->prefix . 'fc_subscribers' ) ) ) {
$row = $wpdb->get_row( $wpdb->prepare(
"SELECT full_name, email FROM {$wpdb->prefix}fc_subscribers WHERE id=%d", (int) $m[1]
) );
if ( $row ) {
$name = trim( (string) $row->full_name );
$email = (string) $row->email;
$label = $name !== '' ? ( $name . ( $email ? " <{$email}>" : '' ) ) : $email;
return [ self::truncate( $label, 80 ), false ];
}
}
}
if ( $surface === 'derived' ) {
return [ '(derived demand, no surface row)', false ];
}
return [ '', false ];
}
private static function truncate( $s, $n ) {
$s = (string) $s;
if ( function_exists( 'mb_strlen' ) && function_exists( 'mb_substr' ) ) {
return mb_strlen( $s ) > $n ? ( mb_substr( $s, 0, $n - 1 ) . '…' ) : $s;
}
return strlen( $s ) > $n ? ( substr( $s, 0, $n - 1 ) . '…' ) : $s;
}
private static function render_trace_results( array $data ) {
$arbs = $data['arbitrations'] ?? [];
$links = $data['plan_links'] ?? [];
$events = $data['acceptance'] ?? [];
echo '| closure_state_basic | ' . esc_html( (string) ( $data['closure_state_basic'] ?? '' ) ) . ' |
|---|---|
| closure_state_role_aware | ' . esc_html( (string) ( $data['closure_state_role_aware'] ?? '' ) ) . ' |
| closure_authority_valid | ' . esc_html( $auth_disp ) . ' |
No arbitrations recorded for this demand.
'; } else { echo '| ID | Hash | Projection Type | Truth Class | Actor | Correlation | Created (UTC) | Asterion | '; echo '
|---|---|---|---|---|---|---|---|
| ' . (int) $a->id . ' | '; echo '' . esc_html( substr( (string) $a->hash, 0, 12 ) ) . '… | ';
echo '' . esc_html( (string) $a->projection_type ) . ' | '; echo '' . esc_html( (string) $a->truth_class ) . ' | '; echo '' . esc_html( (string) ( $a->actor_user_id ?? '—' ) ) . ' | '; echo '' . esc_html( substr( (string) $a->correlation_id, 0, 8 ) ) . '… | ';
echo '' . esc_html( (string) $a->created_at ) . ' | '; echo '' . esc_html( (string) $a->asterion_path ) . ' | ';
echo '
| Rationale: ' . esc_html( (string) $a->rationale ) . ' | |||||||
No plan links — this Demand has no Plan refs (consistent with scope-direct-no-plan or no-plan arbitration).
| ID | Arbitration | Plan Surface | Plan Ref | Link Kind | Created (UTC) | '; echo '
|---|---|---|---|---|---|
| ' . (int) $l->id . ' | '; echo '' . (int) $l->arbitration_id . ' | '; echo '' . esc_html( (string) $l->plan_surface ) . ' | '; echo '' . esc_html( (string) $l->plan_ref ) . ' | ';
echo '' . esc_html( (string) $l->link_kind ) . ' | '; echo '' . esc_html( (string) $l->created_at ) . ' | '; echo '
No acceptance events.
'; } else { echo '| ID | Event Type | Actor Role | Actor | Truth Class | Prior | Observed (UTC) | Asterion | '; echo '
|---|---|---|---|---|---|---|---|
| ' . (int) $e->id . ' | '; echo '' . esc_html( (string) $e->event_type ) . ' | '; echo '' . esc_html( (string) $e->actor_role ) . ' | '; echo '' . esc_html( (string) ( $e->actor_user_id ?? '—' ) ) . ' | '; echo '' . esc_html( (string) $e->truth_class ) . ' | '; echo '' . esc_html( (string) ( $e->prior_event_id ?? '—' ) ) . ' | '; echo '' . esc_html( (string) $e->observed_at ) . ' | '; echo '' . esc_html( (string) $e->asterion_path ) . ' | ';
echo '
| Details: ' . esc_html( (string) $e->details ) . ' | |||||||
Local rules-based audit — repeatable, no API, no LLM. Computed on each page load. Floor of a four-layer stack: '; echo '(1) Trace data → (2) this Deterministic Trace Audit → (3) Strategy LLM Review (future) → (4) Human arbitration (final).
'; $color_map = [ 'high' => '#0a7d24', 'medium' => '#a76b00', 'low' => '#a02b1f', 'n/a' => '#666' ]; $color = $color_map[ $r['closure_confidence'] ] ?? '#666'; echo '| Summary | ' . esc_html( $r['summary'] ) . ' |
|---|---|
| Closure confidence | '; echo '' . esc_html( strtoupper( (string) $r['closure_confidence'] ) ) . ''; echo ' — ' . esc_html( $r['closure_confidence_explanation'] ); echo ' |
| Needs Human Arbitration | ';
if ( ! empty( $r['needs_human_arbitration'] ) ) {
echo '⚠ YES — ' . esc_html( (string) $r['human_arbitration_message'] ) . '';
echo ' Triggered by: '; echo '
|
| ' . esc_html( $label ) . ' | ';
if ( empty( $items ) ) {
echo '(none)';
} else {
echo '
|
Layer 3 — Strategy LLM Review — sits below this section. The audit remains as a sanity-check / fallback layer underneath any LLM verdict.
'; // --- Strategy Review (v0.5) --- self::render_strategy_review( $data, $r ); } /** * Strategy LLM Review block (layer 3). * * Consumes the trace + the deterministic audit; delegates to the active * provider via SA_Orch_Strategy::review(). Strategy Review is advisory: * it cannot override closure_state or needs_human_arbitration. */ private static function render_strategy_review( array $data, array $deterministic_audit ) { $strategy = SA_Orch_Strategy::review( $data, $deterministic_audit ); $provider_id = (string) ( $strategy['provider_id'] ?? 'simulated' ); $provider_name = (string) ( $strategy['provider_name'] ?? 'Simulated (no API call)' ); $configured_id = (string) ( $strategy['configured_provider_id'] ?? $provider_id ); $configured_name = (string) ( $strategy['configured_provider_name'] ?? $provider_name ); $fallback_used = ! empty( $strategy['fallback_used'] ); $provider_err = $strategy['provider_error'] ?? null; $heading_suffix = $fallback_used ? '(layer 3 — used: ' . esc_html( $provider_id ) . ', configured: ' . esc_html( $configured_id ) . ' — FALLBACK)' : '(layer 3 — provider: ' . esc_html( $provider_id ) . ')'; echo 'Layer 3 of the review stack. Provider in use: ' . esc_html( $provider_name ) . '. ';
if ( $fallback_used ) {
echo 'Configured provider (' . esc_html( $configured_name ) . ') failed and was replaced by the simulated fallback. ';
}
echo 'Compares its interpretation against the deterministic audit. ';
echo 'Strategy Review cannot override closure_state or the needs_human_arbitration flag — those remain governed by the deterministic audit and ultimately by human arbitration.
Provider error (configured: ' . esc_html( $configured_id ) . '): ' . esc_html( $provider_err ) . ' — fell back to simulated.
| Summary | ' . esc_html( (string) ( $strategy['summary'] ?? '' ) ) . ' |
|---|---|
| Agreement with Deterministic Audit | '; echo '' . esc_html( strtoupper( $strat_agree ) ) . ''; echo ' |
| Additional risks (not caught by audit) | ';
$risks = (array) ( $strategy['additional_risks'] ?? [] );
if ( empty( $risks ) ) {
echo '(none)';
} else {
echo '
|
| Suggested next action | ' . esc_html( (string) ( $strategy['suggested_next_action'] ?? '' ) ) . ' |
| Confidence | '; echo '' . esc_html( strtoupper( $strat_conf ) ) . ''; echo ' |
| '; echo ' | Deterministic Audit (layer 2) | '; echo 'Strategy Review (layer 3) | '; echo '
|---|---|---|
| Confidence | '; echo '' . esc_html( strtoupper( $audit_conf ) ) . ' | '; echo '' . esc_html( strtoupper( $strat_conf ) ) . ' | '; echo '
| Findings counted | '; echo '' . (int) $audit_inc . ' inconsistenc' . ( $audit_inc === 1 ? 'y' : 'ies' ) . ', ' . (int) $audit_drift . ' scope-drift indicator' . ( $audit_drift === 1 ? '' : 's' ) . ' | '; echo '' . (int) $strat_extra . ' additional risk' . ( $strat_extra === 1 ? '' : 's' ) . ' | '; echo '
| Closure authority | '; echo '' . ( $needs_hum ? 'flagged needs_human_arbitration = YES' : 'no escalation flag' ) . ' | '; echo 'cannot override the audit | '; echo '
| Mode / character | '; echo 'rules-based, repeatable | '; echo 'interpretive, narrative (' . esc_html( (string) ( $strategy['provider_id'] ?? 'simulated' ) ) . ') | '; echo '
Reminder: closure_state_basic, closure_state_role_aware, closure_authority_valid, and needs_human_arbitration are governed by the deterministic audit (layer 2) and ultimately by human arbitration (layer 4). Strategy Review is advisory.
Last 20 arbitration records, newest first. Click Trace to walk the full chain.
'; if ( empty( $rows ) ) { echo 'No arbitrations recorded yet.
'; } else { echo '| ID | Demand | Projection Type | Truth Class | Actor | Created (UTC) | Action | '; echo '
|---|---|---|---|---|---|---|
| ' . (int) $r->id . ' | '; echo '' . esc_html( $r->demand_surface . ' / ' . $r->demand_ref ) . ' | ';
echo '' . esc_html( (string) $r->projection_type ) . ' | '; echo '' . esc_html( (string) $r->truth_class ) . ' | '; echo '' . esc_html( (string) ( $r->actor_user_id ?? '—' ) ) . ' | '; echo '' . esc_html( (string) $r->created_at ) . ' | '; echo 'Trace | '; echo '
' . esc_html( $message ) . '
Configure the provider used by the Strategy Review (layer 3 of the review stack: trace data → deterministic audit → strategy review → human arbitration).
'; echo 'Local-dev posture: secrets are stored in wp_options. Tokens are never displayed back — saving with a blank token field preserves the existing value. This storage layer is the attachment seam for a future SA-Core key vault; replacing it later will not change the consumer surface.
| Active provider (resolved) | ' . esc_html( SA_Orch_LLM_Providers::get_active_provider()->id() ) . ' |
|---|---|
| Settings.enabled | ' . ( ! empty( $settings['enabled'] ) ? 'true' : 'false' ) . ' |
| Settings.provider | ' . esc_html( (string) $settings['provider'] ) . ' |
| Settings.model | ' . esc_html( (string) $settings['model'] ?: '—' ) . ' |
| Settings.api_base_url | ' . esc_html( (string) $settings['api_base_url'] ?: '—' ) . ' |
| Settings.api_token | ' . ( SA_Orch_LLM_Settings::has_token() ? '***** (set)' : '(not set)' ) . ' |
v0.5 ships with the simulated provider only — no external API call is made by this plugin under any settings configuration. Adding real providers (OpenAI, Anthropic, local model endpoint, custom HTTP) is a matter of implementing SA_Orch_LLM_Provider_Interface and adding a case to SA_Orch_LLM_Providers::instantiate().
Last 20 acceptance events, newest first. Append-only — these rows are never updated or deleted.
'; if ( empty( $rows ) ) { echo 'No acceptance events recorded yet.
'; } else { echo '| ID | Event Type | Actor Role | Actor | Demand | Truth Class | Observed (UTC) | Action | '; echo '
|---|---|---|---|---|---|---|---|
| ' . (int) $r->id . ' | '; echo '' . esc_html( (string) $r->event_type ) . ' | '; echo '' . esc_html( (string) $r->actor_role ) . ' | '; echo '' . esc_html( (string) ( $r->actor_user_id ?? '—' ) ) . ' | '; echo '' . esc_html( $r->demand_surface . ' / ' . $r->demand_ref ) . ' | ';
echo '' . esc_html( (string) $r->truth_class ) . ' | '; echo '' . esc_html( (string) $r->observed_at ) . ' | '; echo 'Trace | '; echo '