feat(ai): add Jev shadow gates (triage before, review after the LLM diagnosis)

TypeSafe System One(Jev)への最小クライアントと、診断ループに並走する
shadow ゲート 2 つを追加した。triage はアラートと事前取得サンプルからラベル・
回復中か・層を判定し、review は診断の根拠・ランブック・target を検証して
best_action を選ぶ。JEV_MODE=shadow のときだけ動き、答えは ai.jev_shadow と
診断結果の jev フィールドに記録するだけで、処理の分岐は一切変えない。
This commit is contained in:
seon committed 2026-10-08 15:10:07 +09:00
1 parent af1cb4f6dc
commit 91cdd9ada5
6 files changed
+479 -19

No files matched your search

+51
View File
@@ -68,6 +68,22 @@ CREATE TABLE IF NOT EXISTS ai.hitl_messages (
result jsonb,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS ai.jev_shadow (
id bigserial PRIMARY KEY,
session_id text,
run_id text,
scenario_id text,
gate text NOT NULL,
model text,
state jsonb NOT NULL,
questions jsonb NOT NULL,
answers jsonb,
llm jsonb,
latency_ms bigint,
input_tokens integer,
error text,
created_at timestamptz NOT NULL DEFAULT now()
);
-- additive migrations (CREATE TABLE IF NOT EXISTS leaves existing tables untouched; seen 2026-10-08 on the AI VM)
ALTER TABLE ai.hitl_messages ADD COLUMN IF NOT EXISTS diagnosis jsonb NOT NULL DEFAULT '{}'::jsonb;`
@@ -371,3 +387,38 @@ func (s *Store) Pending(ctx context.Context) ([]HitlMessage, error) {
}
return out, rows.Err()
}
// ---- Jev shadow gates (2026-10-08) ----
type JevShadow struct {
SessionID string
RunID *string
ScenarioID *string
Gate string
Model string
State any
Questions any
Answers any
LLM any
LatencyMs int64
InputTokens int
Error string
}
func (s *Store) SaveJev(ctx context.Context, r JevShadow) error {
st, _ := json.Marshal(r.State)
q, _ := json.Marshal(r.Questions)
an, _ := json.Marshal(r.Answers)
llm, _ := json.Marshal(r.LLM)
_, err := s.pool.Exec(ctx, `INSERT INTO ai.jev_shadow (session_id,run_id,scenario_id,gate,model,state,questions,answers,llm,latency_ms,input_tokens,error)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,NULLIF($12,''))`,
nullIfEmpty(r.SessionID), r.RunID, r.ScenarioID, r.Gate, nullIfEmpty(r.Model), st, q, an, llm, r.LatencyMs, r.InputTokens, r.Error)
return err
}
func nullIfEmpty(s string) *string {
if s == "" {
return nil
}
return &s
}