Class: IgniterLang::TemporalExecutor::Phase1

Inherits:
Object
  • Object
show all
Defined in:
lib/igniter_lang/temporal_executor.rb

Overview

Phase1 — proof-local History valid_time executor.

Responsibilities:

- Enforce approval_token before gate_state (AT-4/AT-5 order)
- Validate authority_ref exactly against GATE3_AUTHORITY_REF (AT-9)
- Enforce scope, cache-key, BiHistory, and CORE fragment guards
- Emit temporal_live_read_observation unconditionally (AT-10)
- Compose one CompatibilityReport-shaped hash per evaluation (AT-2)
- Guarantee operation_check flags false for all blocked paths

NOT responsible for: artifact loading, full CompatibilityReport composition pipeline, Ledger binding, production cache, production signing.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(backend:, gate3_authorized: false) ⇒ Phase1

gate3_authorized: caller honor-system. Pass true only when a valid Architect decision (gate3-live-read-decision-addendum-v0) authorizes non-proof live reads. The lib/ class cannot verify the addendum exists; the caller is responsible. Default false = live reads blocked at construction regardless of backend or token.



78
79
80
81
82
83
84
# File 'lib/igniter_lang/temporal_executor.rb', line 78

def initialize(backend:, gate3_authorized: false)
  @backend          = backend
  @gate3_authorized = gate3_authorized
  @backend_identity_check = check_backend_identity(backend)
  @observations     = []
  @last_compatibility_report = nil
end

Instance Attribute Details

#last_compatibility_reportObject (readonly)

Proof-local only. In-memory, not durable. Not an audit receipt. AT-10 emission is unconditional; persistence is deferred (see compatibility-report-persistence-audit-v0).



72
73
74
# File 'lib/igniter_lang/temporal_executor.rb', line 72

def last_compatibility_report
  @last_compatibility_report
end

#observationsObject (readonly)

Proof-local only. In-memory, not durable. Not an audit receipt. AT-10 emission is unconditional; persistence is deferred (see compatibility-report-persistence-audit-v0).



72
73
74
# File 'lib/igniter_lang/temporal_executor.rb', line 72

def observations
  @observations
end

Instance Method Details

#evaluate(contract, token:, inputs:, as_of:, requested_cache_key_fragment: "TEMPORAL") ⇒ Object

Evaluate a temporal contract.

contract: assembled contract Hash (fragment_class, temporal_nodes, contract_id) token: ExecutorApprovalToken Hash inputs: Hash of contract input values as_of: ISO8601 datetime string requested_cache_key_fragment: expected “TEMPORAL” for Phase 1

Returns a result Hash; never raises for guard failures.



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
# File 'lib/igniter_lang/temporal_executor.rb', line 95

def evaluate(contract, token:, inputs:, as_of:, requested_cache_key_fragment: "TEMPORAL")
  contract_id = contract.fetch("contract_id")

  # Step 1: approval_token (AT-4 + AT-9) — must fire before gate check
  token_check = check_approval_token(token, contract_id)
  if token_check[:blocked]
    return build_refusal(token_check, contract_id: contract_id, as_of: as_of,
                         blocked_stage: "approval_token",
                         gate_open: @gate3_authorized,
                         token_ok: false,
                         cache_key_fragment: requested_cache_key_fragment)
  end

  # Step 2: gate_state (AT-5) — independent of token
  unless @gate3_authorized
    gate_check = { blocked: true,
                   reason_code: ReasonCode::GATE3_CLOSED,
                   message: "Gate 3 is closed for TEMPORAL evaluation",
                   context: { "gate" => "tbackend_gate3" } }
    return build_refusal(gate_check, contract_id: contract_id, as_of: as_of,
                         blocked_stage: "gate_state",
                         gate_open: false,
                         token_ok: true,
                         cache_key_fragment: requested_cache_key_fragment)
  end

  # Step 2b: backend_identity — Phase 1 must not quietly bind Ledger
  if @backend_identity_check[:blocked]
    return build_refusal(@backend_identity_check, contract_id: contract_id, as_of: as_of,
                         blocked_stage: "backend_identity",
                         gate_open: true,
                         token_ok: true,
                         cache_key_fragment: requested_cache_key_fragment)
  end

  # Step 3: scope — TEMPORAL fragment only, before cache
  unless contract.fetch("fragment_class") == "temporal"
    scope_check = { blocked: true,
                    reason_code: ReasonCode::NON_TEMPORAL,
                    message: "Phase 1 executor handles only TEMPORAL fragment contracts",
                    context: { "expected_scope" => "history_valid_time",
                               "actual_fragment" => contract.fetch("fragment_class"),
                               "actual_surface" => contract.fetch("fragment_class") } }
    return build_refusal(scope_check, contract_id: contract_id, as_of: as_of,
                         blocked_stage: "scope",
                         gate_open: true,
                         token_ok: true,
                         cache_key_fragment: requested_cache_key_fragment)
  end

  # Step 4: cache_key schema (AT-6) — before any backend access
  unless requested_cache_key_fragment == "TEMPORAL"
    cache_check = { blocked: true,
                    reason_code: ReasonCode::CACHE_MISMATCH,
                    message: "TEMPORAL evaluation cannot use a #{requested_cache_key_fragment}-shaped cache key",
                    context: { "gate"               => "L-T5",
                               "expected_fragment"  => "TEMPORAL",
                               "requested_fragment" => requested_cache_key_fragment } }
    return build_refusal(cache_check, contract_id: contract_id, as_of: as_of,
                         blocked_stage: "cache_key",
                         gate_open: true,
                         token_ok: true,
                         cache_key_fragment: requested_cache_key_fragment)
  end

  # All preflight guards passed — compose report, run kernel
  report = compose_report(contract_id: contract_id, gate_open: true,
                          token_ok: true, cache_key_ok: true,
                          readiness: "ready")
  @last_compatibility_report = report

  kernel_result = run_execution_kernel(contract, inputs: inputs, as_of: as_of)
  kernel_result.merge("compatibility_report_id" => report.fetch("report_id"))
end