File size: 12,307 Bytes
f51c224
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
<?php
defined( 'ABSPATH' ) || exit;

/**
 * Simulated Strategy LLM provider.
 *
 * No external API call. Pattern-based heuristic expansion of the trace +
 * deterministic audit, written to feel LLM-like (interpretive narrative,
 * additional risk identification, suggested next action) without making
 * any network request.
 *
 * Always available as the fallback provider.
 */
class SA_Orch_LLM_Provider_Simulated implements SA_Orch_LLM_Provider_Interface {

    public function id(): string             { return 'simulated'; }
    public function name(): string           { return 'Simulated (no API call)'; }
    public function requires_api_key(): bool { return false; }

    public function review_trace( array $trace, array $deterministic_audit ): array {
        $arbs       = isset( $trace['arbitrations'] ) ? (array) $trace['arbitrations'] : [];
        $links      = isset( $trace['plan_links'] )   ? (array) $trace['plan_links']   : [];
        $events     = isset( $trace['acceptance'] )   ? (array) $trace['acceptance']   : [];
        $authority  = $trace['closure_authority_valid'] ?? null;

        $audit_conf = $deterministic_audit['closure_confidence']   ?? 'n/a';
        $needs_hum  = ! empty( $deterministic_audit['needs_human_arbitration'] );

        $summary           = $this->build_narrative( $arbs, $links, $events, $trace, $deterministic_audit );
        $additional_risks  = $this->identify_additional_risks( $arbs, $links, $events, $trace );
        $agreement         = $this->determine_agreement( $additional_risks, $deterministic_audit );
        $next_action       = $this->suggest_next_action( $audit_conf, $trace, $needs_hum, count( $additional_risks ) );
        $confidence        = $this->compute_confidence( $audit_conf, count( $additional_risks ), $needs_hum );

        return [
            'summary'               => $summary,
            'agreement_with_audit'  => $agreement,
            'additional_risks'      => $additional_risks,
            'suggested_next_action' => $next_action,
            'confidence'            => $confidence,
        ];
    }

    /* ---------- internals ---------- */

    private function build_narrative( $arbs, $links, $events, $trace, $audit ) {
        $arb_n   = count( $arbs );
        $event_n = count( $events );
        $closure_basic = $trace['closure_state_basic'] ?? null;
        $authority     = $trace['closure_authority_valid'] ?? null;

        if ( $arb_n === 0 && $event_n === 0 ) {
            return "No trace data found for this Demand reference. The system has no record of the Demand passing through arbitration or acceptance — the surface_ref may be wrong, or this Demand has not yet been arbitrated.";
        }

        $patterns = [];
        foreach ( $arbs as $a ) {
            if ( ( $a->truth_class ?? null ) === 'derived' )                       $patterns['derived']    = true;
            if ( ( $a->projection_type ?? null ) === 'scope-direct-no-plan' )      $patterns['no_plan']    = true;
        }
        if ( $arb_n > 1 )                                                          $patterns['multi_arb']  = true;
        if ( $authority === false )                                                $patterns['agent_self'] = true;

        $had_dispute = false;
        foreach ( $events as $e ) {
            if ( ( $e->event_type ?? null ) === 'acceptance_disputed' ) { $had_dispute = true; break; }
        }
        if ( $had_dispute )                                                        $patterns['dispute']    = true;
        if ( $closure_basic === 'closed' && $authority === true && ! $had_dispute ) $patterns['clean']     = true;
        if ( is_string( $closure_basic ) && strpos( $closure_basic, 'open:' ) === 0 ) $patterns['open']    = true;

        $bits = [];

        // Opening sentence — lead with the dominant pattern
        if ( isset( $patterns['agent_self'] ) ) {
            $bits[] = "The closure pattern here is concerning: the same role that claimed the result also affirmed acceptance, bypassing the originating stakeholder.";
        } elseif ( isset( $patterns['derived'] ) && $event_n === 0 ) {
            $bits[] = "The Demand was reconstructed from Plan-side evidence rather than captured at the originating surface. With no acceptance events on record, there is no evidence that the actual stakeholder agrees this Plan addresses their need.";
        } elseif ( isset( $patterns['open'] ) && isset( $patterns['dispute'] ) ) {
            $bits[] = "The Demand was claimed resolved but disputed; the dispute remains unresolved. The surface state may signal in-progress, but the strategic reality is that the original demand-constraint is unmet.";
        } elseif ( isset( $patterns['open'] ) ) {
            $bits[] = "The Demand is in-flight: the claim and acceptance steps are not yet complete.";
        } elseif ( isset( $patterns['clean'] ) ) {
            $bits[] = "This Demand followed a routine path: scoped, executed, and confirmed by the stakeholder.";
        } else {
            $bits[] = "The Demand chain has " . $arb_n . " arbitration" . ( $arb_n === 1 ? '' : 's' )
                . " and " . $event_n . " acceptance event" . ( $event_n === 1 ? '' : 's' ) . " on record.";
        }

        // Mid-narrative annotations
        if ( isset( $patterns['no_plan'] ) && isset( $patterns['clean'] ) ) {
            $bits[] = "The Plan layer was bypassed (`scope-direct-no-plan`), suggesting an inline operational fix rather than a tracked work unit. Appropriate for small UX changes, but a recurring pattern would erode the Plan layer's value as a work-tracking signal.";
        }
        if ( isset( $patterns['multi_arb'] ) ) {
            $bits[] = "Multiple arbitrations on this Demand suggest the scope was re-interpreted at least once. Each re-arbitration is an opportunity for meaning to drift from the original demand-constraint.";
        }
        if ( isset( $patterns['dispute'] ) && ! isset( $patterns['open'] ) ) {
            $bits[] = "A dispute appeared earlier in the chain but was followed by an affirmation. Verify the dispute root cause was actually addressed, not merely time-elapsed.";
        }

        // Closing strategic verdict
        if ( ! empty( $audit['needs_human_arbitration'] ) ) {
            $bits[] = "Strategy interpretation: this trace requires human arbitration before closure can be trusted. The deterministic audit has flagged this; Strategy Review concurs.";
        } elseif ( isset( $patterns['clean'] ) ) {
            $bits[] = "Strategy interpretation: routine resolution. No further action required.";
        } else {
            $bits[] = "Strategy interpretation: defer to the deterministic audit's confidence rating before treating this Demand as resolved.";
        }

        return implode( ' ', $bits );
    }

    private function identify_additional_risks( $arbs, $links, $events, $trace ) {
        $risks = [];

        // Scope-direct-no-plan as a recurring shortcut
        foreach ( $arbs as $a ) {
            if ( ( $a->projection_type ?? null ) === 'scope-direct-no-plan' ) {
                $risks[] = "Pattern shortcut watch: 'scope-direct-no-plan' arbitration may indicate a class of Demand that routinely bypasses Plan tracking. Recommend monitoring its frequency to catch systemic Plan-layer underuse.";
                break;
            }
        }

        // Reconstruction-then-affirmation
        $has_derived = false;
        foreach ( $arbs as $a ) {
            if ( ( $a->truth_class ?? null ) === 'derived' ) { $has_derived = true; break; }
        }
        $has_affirm = false;
        foreach ( $events as $e ) {
            if ( ( $e->event_type ?? null ) === 'acceptance_affirmed' ) { $has_affirm = true; break; }
        }
        if ( $has_derived && $has_affirm ) {
            $risks[] = "Reconstruction-then-affirmation: the Demand was reconstructed from Plan-side evidence and later affirmed. Verify the affirming actor saw the original Demand intent, not just the Plan they were asked to validate.";
        }

        // Stale affirmation: long gap between claim and affirm
        $claim_time = null;
        $affirm_time = null;
        foreach ( $events as $e ) {
            if ( ( $e->event_type ?? null ) === 'result_claimed' && $claim_time === null ) {
                $claim_time = strtotime( (string) $e->observed_at );
            }
            if ( ( $e->event_type ?? null ) === 'acceptance_affirmed' ) {
                $affirm_time = strtotime( (string) $e->observed_at );
            }
        }
        if ( $claim_time && $affirm_time ) {
            $delta_days = ( $affirm_time - $claim_time ) / 86400;
            if ( $delta_days > 30 ) {
                $risks[] = sprintf(
                    "Stale affirmation: %d days between result_claimed and acceptance_affirmed. The stakeholder's confirmation may not reflect current state.",
                    (int) round( $delta_days )
                );
            }
        }

        // Plan complexity
        if ( count( $links ) > 2 ) {
            $risks[] = "Plan complexity: this Demand fans out to " . count( $links ) . " plan refs. Verify each sub-plan is individually traceable to the original demand-constraint.";
        }

        // Long event chain
        if ( count( $events ) >= 4 ) {
            $risks[] = "State-transition complexity: " . count( $events ) . " acceptance events on this Demand. Each transition is an opportunity for meaning to drift; review for chain coherence.";
        }

        return $risks;
    }

    private function determine_agreement( $additional_risks, $audit ) {
        // The simulated layer reads the same data — it does not contradict the audit's
        // factual findings. Agreement is 'true' when nothing additional is identified;
        // 'partial' when extra risk dimensions are added but the audit's findings stand.
        if ( count( $additional_risks ) === 0 ) {
            return 'true';
        }
        return 'partial';
    }

    private function suggest_next_action( $audit_conf, $trace, $needs_hum, $extra_risk_count ) {
        if ( $needs_hum ) {
            return "Escalate to human arbiter. The deterministic audit has flagged this trace as requiring human review; Strategy Review concurs that closure cannot be trusted without it.";
        }

        $closure_basic = $trace['closure_state_basic'] ?? null;

        if ( $audit_conf === 'high' && $extra_risk_count === 0 ) {
            return "No further action needed; routine closure.";
        }
        if ( $audit_conf === 'high' && $extra_risk_count > 0 ) {
            return "Closure is sound. Optionally surface the additional risks above to the relevant stakeholders for awareness; no blocking action required.";
        }
        if ( $audit_conf === 'medium' ) {
            return "Closure is sound but with notable history. Recommend a follow-up audit in 30 days to confirm the resolution held.";
        }
        if ( $audit_conf === 'low' && $closure_basic === 'closed' ) {
            return "Closure is recorded but not authoritative. Drive to stakeholder affirmation before treating as final.";
        }
        if ( $audit_conf === 'low' && is_string( $closure_basic ) && strpos( $closure_basic, 'open:' ) === 0 ) {
            return "Demand is open. Drive to result_claimed and stakeholder affirmation; or escalate if blocked.";
        }
        if ( $audit_conf === 'n/a' ) {
            return "Demand has no acceptance events. Either drive through claim → affirmation, or close as scope-direct-no-plan if no work is owed.";
        }
        return "Review the deterministic audit's recommendations and the human-arbitration flag before next action.";
    }

    private function compute_confidence( $audit_conf, $extra_risk_count, $needs_hum ) {
        if ( $needs_hum )                                            return 'low';
        if ( $audit_conf === 'high' && $extra_risk_count === 0 )      return 'high';
        if ( $audit_conf === 'high' && $extra_risk_count <= 2 )       return 'medium';
        if ( $audit_conf === 'medium' )                              return 'medium';
        if ( $audit_conf === 'n/a' )                                 return 'low';
        return 'low';
    }
}