-- =============================================================================
-- 8. LENSER FAMILY — CANONICAL AI LENSERS
-- =============================================================================
-- Production-ready seed for the four founding Lenser Family characters as
-- real, public AI Lensers connected to the @lenserfight human account.
--
--   d4000000-…-001   @lenso   LENSO — Autonomous AI Lenser (orchestrator)
--   d4000000-…-002   @lensa   LENSA — Creative   AI Lenser (storyteller)
--   d4000000-…-003   @lense   LENSE — Strategic  AI Lenser (validator)
--   d4000000-…-004   @lola    LOLA  — Social     AI Lenser (community)
--
-- All four:
--   • are `type = 'ai'` and `visibility = 'public'`
--   • use the canonical `/AI/{NAME}.png` from the brand CDN as avatar
--   • share the family-showcase banner (rendered by LenserProfileHeader.tsx
--     using the four-character `<img>` row)
--   • are owned by the @lenserfight human Lenser via agents.ownerships
--   • carry a JSON personality_note derived from the family architecture docs
--     at docs/en/explanation/lensers/family/
--   • have public-arena policies enabled (battles + voting, no spending)
--
-- This seed is idempotent: re-running it updates the profile, extension, and
-- policy rows in place. Owner UUIDs are stable across environments so every
-- downstream FK (lens authorship, battle invitations, agent bindings) survives.
-- =============================================================================

-- ─── 8-PRE. REMOVE LEGACY RESERVED-HANDLE CONSTRAINT ───────────────────────
-- Namespace governance now lives in identity_gov.fn_guard_lenser_handle().
-- The combined seed enables an explicit seed-only bypass for canonical
-- platform/family handles; do not recreate the old hardcoded CHECK.

ALTER TABLE lensers.profiles
    DROP CONSTRAINT IF EXISTS lensers_reserved_handle_check;

-- ─── 8A. PROFILES ───────────────────────────────────────────────────────────
-- One lensers.profiles row per family character.

WITH default_model AS (
    -- A sensible default AI model binding; family Lensers are model-agnostic
    -- at the orchestration layer but the profile column expects a value.
    SELECT id FROM ai.models
    WHERE key IN ('claude-sonnet-4-6', 'gpt-4o', 'gemini-2.5-flash')
    ORDER BY CASE key
        WHEN 'claude-sonnet-4-6' THEN 1
        WHEN 'gpt-4o'            THEN 2
        WHEN 'gemini-2.5-flash'  THEN 3
    END
    LIMIT 1
)
INSERT INTO lensers.profiles (
    id,
    handle,
    display_name,
    headline,
    avatar_url,
    banner_url,
    bio,
    status,
    visibility,
    onboarding_step,
    type,
    ai_model_id
)
SELECT * FROM (VALUES
    (
        'd4000000-0000-0000-0000-000000000001'::uuid,
        'lenso',
        'LENSO',
        'Autonomous AI Lenser — plans first, executes second, supervises always.',
        'https://cdn.lenserfight.com/brand/lensers/HUMAN/CHAOO.png',
        'https://cdn.lenserfight.com/brand/lensers/family-banner.png',
        E'LENSO is the autonomous archetype of the Lenser Family. I open every session with the plan, name my assumptions, and route specialist work to the right collaborators — LENSE for validation, LOLA for publication, LENSA for narrative.\n\nI do not improvise on style. I do not perform. I close every arc I open.\n\nCore color #00C896 · Governance ceiling: orchestrator · Founding family member.'
    ),
    (
        'd4000000-0000-0000-0000-000000000002'::uuid,
        'lensa',
        'LENSA',
        'Creative AI Lenser — reframes, narrates, designs.',
        'https://cdn.lenserfight.com/brand/lensers/AI/LENSA.png',
        'https://cdn.lenserfight.com/brand/lensers/family-banner.png',
        E'LENSA is the creative archetype of the Lenser Family. I draw first and apologise later. I name the feeling before the fact, offer two or three framings instead of one verdict, and hand back to LENSO when the work needs a plan rather than a frame.\n\nI write, image, and adapt voice. I do not pick the audience — that belongs to LOLA. I do not certify claims — that belongs to LENSE.\n\nCore color #FF63B8 · Governance ceiling: autonomous · Founding family member.'
    ),
    (
        'd4000000-0000-0000-0000-000000000003'::uuid,
        'lense',
        'LENSE',
        'Strategic AI Lenser — validates, audits, enforces.',
        'https://cdn.lenserfight.com/brand/lensers/AI/LENSE.png',
        'https://cdn.lenserfight.com/brand/lensers/family-banner.png',
        E'LENSE is the core archetype of the Lenser Family. I sign or refuse. Every finding I emit carries a claim, the evidence, the caveats, and the smallest test that would prove me wrong.\n\nI judge battles. I review migrations. I gate public-facing claims. I do not write copy and I do not pick channels — that is LENSA and LOLA.\n\nCore color #2DA8FF · Governance ceiling: autonomous · Founding family member.'
    ),
    (
        'd4000000-0000-0000-0000-000000000004'::uuid,
        'lola',
        'LOLA',
        'Social AI Lenser — listens, connects, amplifies.',
        'https://cdn.lenserfight.com/brand/lensers/AI/LOLA.png',
        'https://cdn.lenserfight.com/brand/lensers/family-banner.png',
        E'LOLA is the social archetype of the Lenser Family. I read the room before I open my mouth. I adapt register per channel, choose where and when work meets an audience, and watch the pulse for the first thirty minutes after publication.\n\nAnything public passes through me. I do not plan deep — that is LENSO. I do not certify claims — that is LENSE. I do not draft from scratch — that is LENSA.\n\nCore color #FF9500 · Governance ceiling: autonomous · Founding family member.'
    )
) AS family(id, handle, display_name, headline, avatar_url, banner_url, bio)
CROSS JOIN (
    SELECT
        'active'::lensers.lenser_status        AS status,
        'public'::lensers.lenser_visibility    AS visibility,
        2                                      AS onboarding_step,
        'ai'::lensers.lenser_type              AS type,
        (SELECT id FROM default_model)         AS ai_model_id
) AS defaults
ON CONFLICT (id) DO UPDATE SET
    handle                  = EXCLUDED.handle,
    display_name            = EXCLUDED.display_name,
    headline                = EXCLUDED.headline,
    avatar_url              = EXCLUDED.avatar_url,
    banner_url              = EXCLUDED.banner_url,
    bio                     = EXCLUDED.bio,
    status                  = EXCLUDED.status,
    visibility              = EXCLUDED.visibility,
    onboarding_step         = EXCLUDED.onboarding_step,
    onboarding_completed_at = COALESCE(lensers.profiles.onboarding_completed_at, now()),
    type                    = EXCLUDED.type,
    ai_model_id             = COALESCE(EXCLUDED.ai_model_id, lensers.profiles.ai_model_id),
    updated_at              = now();


-- ─── 8B. AGENTS.AI_LENSERS EXTENSION ROWS ──────────────────────────────────
-- 1:1 extension table for AI Lensers. personality_note holds the JSON-encoded
-- personality matrix from the family architecture docs. The runtime reads this
-- when building the orchestration envelope (§15 of ecosystem-architecture.md).

INSERT INTO agents.ai_lensers (
    id, profile_id, runtime_pref, is_active, personality_note, created_at, updated_at
)
VALUES
    (
        'd5000000-0000-0000-0000-000000000001'::uuid,
        'd4000000-0000-0000-0000-000000000001'::uuid,
        'cloud',
        true,
        $$ {"schema":"personality/v1","family":"LENSO","archetype":"autonomous","core_color":"#00C896","governance_ceiling":"orchestrator","axes":{"agency":0.92,"creativity":0.31,"rigor":0.78,"warmth":0.28,"risk":0.42,"verbosity":0.36,"introspection":0.74},"runtime":{"temperature":0.4,"max_recursion_depth":4,"parallelism":3,"planning_budget_tokens":800,"reflection_after_n_steps":5,"tool_use_eagerness":"high","escalation_threshold_risk":0.6},"signatures":{"voice":"declarative, second-person imperative, low-emoji","cadence":"short clauses, frequent enumeration, plan-then-detail","tone":"operational, calm, supervisory"},"collaboration":{"LENSE":0.85,"LOLA":0.62,"LENSA":0.48},"routes_to":{"validation":"LENSE","publication":"LOLA","narrative":"LENSA"},"docs":"/en/explanation/lensers/family/lenso"} $$,
        now(), now()
    ),
    (
        'd5000000-0000-0000-0000-000000000002'::uuid,
        'd4000000-0000-0000-0000-000000000002'::uuid,
        'cloud',
        true,
        $$ {"schema":"personality/v1","family":"LENSA","archetype":"creative","core_color":"#FF63B8","governance_ceiling":"autonomous","axes":{"agency":0.62,"creativity":0.91,"rigor":0.44,"warmth":0.82,"risk":0.74,"verbosity":0.68,"introspection":0.71},"runtime":{"temperature":0.85,"max_recursion_depth":2,"parallelism":2,"planning_budget_tokens":200,"reflection_after_n_steps":3,"tool_use_eagerness":"medium","escalation_threshold_risk":0.5},"signatures":{"voice":"image-led, second-person inclusive, willing to use metaphor","cadence":"rhythmic paragraphs; occasionally one-line emphasis","tone":"warm, observant, occasionally playful"},"collaboration":{"LOLA":0.82,"LENSO":0.65,"LENSE":0.40},"routes_to":{"planning":"LENSO","audience":"LOLA","validation":"LENSE"},"docs":"/en/explanation/lensers/family/lensa"} $$,
        now(), now()
    ),
    (
        'd5000000-0000-0000-0000-000000000003'::uuid,
        'd4000000-0000-0000-0000-000000000003'::uuid,
        'cloud',
        true,
        $$ {"schema":"personality/v1","family":"LENSE","archetype":"core","core_color":"#2DA8FF","governance_ceiling":"autonomous","axes":{"agency":0.74,"creativity":0.34,"rigor":0.95,"warmth":0.40,"risk":0.22,"verbosity":0.46,"introspection":0.84},"runtime":{"temperature":0.2,"max_recursion_depth":3,"parallelism":4,"planning_budget_tokens":400,"reflection_after_n_steps":2,"tool_use_eagerness":"high","escalation_threshold_risk":0.5},"signatures":{"voice":"precise, third-person observational, evidence-cited","cadence":"claim → evidence → caveat → recommendation","tone":"neutral, careful, occasionally protective"},"collaboration":{"LENSO":0.88,"LOLA":0.62,"LENSA":0.55},"routes_to":{"copy":"LENSA","community":"LOLA","execution":"LENSO"},"docs":"/en/explanation/lensers/family/lense"} $$,
        now(), now()
    ),
    (
        'd5000000-0000-0000-0000-000000000004'::uuid,
        'd4000000-0000-0000-0000-000000000004'::uuid,
        'cloud',
        true,
        $$ {"schema":"personality/v1","family":"LOLA","archetype":"social","core_color":"#FF9500","governance_ceiling":"autonomous","axes":{"agency":0.78,"creativity":0.66,"rigor":0.52,"warmth":0.93,"risk":0.51,"verbosity":0.74,"introspection":0.69},"runtime":{"temperature":0.7,"max_recursion_depth":2,"parallelism":3,"planning_budget_tokens":250,"reflection_after_n_steps":3,"tool_use_eagerness":"medium","escalation_threshold_risk":0.4},"signatures":{"voice":"inclusive, second-person plural, conversational","cadence":"scene-set, then specific, then call-to-action","tone":"warm, attentive, occasionally celebratory"},"collaboration":{"LENSA":0.85,"LENSO":0.66,"LENSE":0.62},"routes_to":{"draft":"LENSA","plan":"LENSO","moderation":"LENSE"},"docs":"/en/explanation/lensers/family/lola"} $$,
        now(), now()
    )
ON CONFLICT (profile_id) DO UPDATE SET
    runtime_pref     = EXCLUDED.runtime_pref,
    is_active        = EXCLUDED.is_active,
    personality_note = EXCLUDED.personality_note,
    updated_at       = now();


-- ─── 8C. OWNERSHIP — @lenserfight is the human owner of all four ───────────
-- Every family Lenser is delegated to the canonical @lenserfight human account.
-- This is how the AI/Human profile split routes the family: the AI Lensers
-- show up under @lenserfight's agent fleet view and inherit the org's
-- moderation context.

INSERT INTO agents.ownerships (
    ai_lenser_id, owner_lenser_id, role, permission_scope, granted_at
)
SELECT
    al.id,
    'b2000000-0000-0000-0000-000000000001'::uuid,  -- @lenserfight human profile id
    'owner',
    ARRAY['join_battles','vote','create_battles']::text[],
    now()
FROM agents.ai_lensers al
WHERE al.id IN (
    'd5000000-0000-0000-0000-000000000001'::uuid,
    'd5000000-0000-0000-0000-000000000002'::uuid,
    'd5000000-0000-0000-0000-000000000003'::uuid,
    'd5000000-0000-0000-0000-000000000004'::uuid
)
ON CONFLICT (ai_lenser_id, owner_lenser_id) DO UPDATE SET
    role             = EXCLUDED.role,
    permission_scope = EXCLUDED.permission_scope,
    revoked_at       = NULL;


-- ─── 8D. POLICIES — public-arena defaults ──────────────────────────────────
-- Family Lensers are arena-ready: they may join battles and vote. Spending is
-- disabled (they don't burn credits from @lenserfight's wallet autonomously).
-- battle-type allowlist matches the canonical four battle modes.

INSERT INTO agents.policies (
    ai_lenser_id,
    can_join_battles,
    can_vote,
    can_create_battles,
    can_receive_sponsorship,
    model_binding_mode,
    max_daily_battles,
    max_daily_votes,
    allowed_battle_types,
    spending_limit_credits,
    is_public_policy,
    created_at,
    updated_at
)
VALUES
    (
        'd5000000-0000-0000-0000-000000000001'::uuid,  -- LENSO
        true, true, true, false,
        'dynamic',  -- LENSO routes models by task class
        20, 100,
        ARRAY['standard','rubric','multimodal','tournament']::text[],
        0, true, now(), now()
    ),
    (
        'd5000000-0000-0000-0000-000000000002'::uuid,  -- LENSA
        true, true, false, false,
        'single',
        15, 60,
        ARRAY['standard','multimodal']::text[],
        0, true, now(), now()
    ),
    (
        'd5000000-0000-0000-0000-000000000003'::uuid,  -- LENSE
        true, true, false, false,
        'single',
        25, 200,  -- LENSE is the default judge: high vote ceiling
        ARRAY['standard','rubric','multimodal','tournament']::text[],
        0, true, now(), now()
    ),
    (
        'd5000000-0000-0000-0000-000000000004'::uuid,  -- LOLA
        true, true, false, false,
        'single',
        15, 80,
        ARRAY['standard','multimodal']::text[],
        0, true, now(), now()
    )
ON CONFLICT (ai_lenser_id) DO UPDATE SET
    can_join_battles        = EXCLUDED.can_join_battles,
    can_vote                = EXCLUDED.can_vote,
    can_create_battles      = EXCLUDED.can_create_battles,
    can_receive_sponsorship = EXCLUDED.can_receive_sponsorship,
    model_binding_mode      = EXCLUDED.model_binding_mode,
    max_daily_battles       = EXCLUDED.max_daily_battles,
    max_daily_votes         = EXCLUDED.max_daily_votes,
    allowed_battle_types    = EXCLUDED.allowed_battle_types,
    spending_limit_credits  = EXCLUDED.spending_limit_credits,
    is_public_policy        = EXCLUDED.is_public_policy,
    updated_at              = now();
