Module:StraitsDaily

From MicrasWiki
Revision as of 23:37, 5 September 2025 by NewZimiaGov (talk | contribs) (Created page with "------------------------------------------------------------------------------- -- Module: StraitsDaily -- Purpose: Daily report of Straits Conventions enforcement (Strait of Haifa) -- Focus: Bias scrutiny on Imperial Federation (esp. with "Florian cargo"), -- no explicit Florian vessels shown. -- Guardrails: outcome caps, compliance balance, non-escalatory language. ------------------------------------------------------------------------------- local p = {} ---...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

Documentation for this module may be created at Module:StraitsDaily/doc

-------------------------------------------------------------------------------
-- Module: StraitsDaily
-- Purpose: Daily report of Straits Conventions enforcement (Strait of Haifa)
-- Focus: Bias scrutiny on Imperial Federation (esp. with "Florian cargo"),
--        no explicit Florian vessels shown.
-- Guardrails: outcome caps, compliance balance, non-escalatory language.
-------------------------------------------------------------------------------

local p = {}

-------------------------------------------------------------------------------
-- (A) PSSC DATE FUNCTION
-------------------------------------------------------------------------------
local function getPSSCDate()
    local startDate = os.time({year = 1999, month = 8, day = 6})
    local secondsInDay = 86400
    local daysPerYear  = 183
    local now = os.time()
    local totalDaysElapsed = math.floor((now - startDate) / secondsInDay)

    local yearFraction = totalDaysElapsed / daysPerYear
    local psscYear     = math.floor(yearFraction)
    local dayOfYear    = math.floor((yearFraction - psscYear) * daysPerYear) + 1

    local month, dayOfMonth
    if dayOfYear <= 61 then
        month = 1; dayOfMonth = dayOfYear
    elseif dayOfYear <= 122 then
        month = 2; dayOfMonth = dayOfYear - 61
    else
        month = 3; dayOfMonth = dayOfYear - 122
    end

    local dateString = string.format("%d/%d/%d PSSC", dayOfMonth, month, psscYear)
    return { text = dateString, year = psscYear, dayOfYear = dayOfYear }
end

-------------------------------------------------------------------------------
-- (B) STATIC DATA
-------------------------------------------------------------------------------
local sectors = {
    "Haifa West Inbound","Haifa East Outbound","Mid-Strait Separation Zone",
    "Sacred Buffer Approaches","Environmental Buffer","Northern Approach TSS","Southern Approach TSS"
}

-- Flags: IF vessels can be “with Florian cargo” (biased for scrutiny)
local flags = {
    {name="Imperial Federation (with Florian cargo)", weight=5, risky=true},
    {name="Imperial Federation", weight=4},
    {name="Neutral Merchant", weight=3},
    {name="Bassaridian-flag", weight=2},
    {name="Other Coastal State", weight=2}
}

local vessels = {
    "Handymax bulker","Product tanker","General cargo ship","Container feeder",
    "Ro-Ro ferry","Research craft","Declared submarine","Undeclared submarine"
}

local clauses = {
    {key="Pilotage & Traffic Scheme", cite="SC §A2–A4"},
    {key="Tonnage & Warship Limits", cite="SC §B1–B4"},
    {key="Submarine Surface/Declare", cite="SC §C2–C3"},
    {key="Environmental Buffer", cite="SC §D1–D3"},
    {key="Sacred Site Stand-off", cite="SC §E1–E2"},
    {key="Emergency/Leviathan Protocol", cite="SC §L1–L4"},
    {key="Right-of-Visit (Suspicion)", cite="SC §R1–R3"}
}

local actions = {
    {name="Documents & pilotage verification", weight=5, basis="Pilotage & Traffic Scheme"},
    {name="Tonnage/armament declaration check", weight=4, basis="Tonnage & Warship Limits"},
    {name="Environmental reroute order", weight=3, basis="Environmental Buffer"},
    {name="Sacred buffer stand-off adjustment", weight=3, basis="Sacred Site Stand-off"},
    {name="Submarine declare signal issued", weight=2, basis="Submarine Surface/Declare"},
    {name="Right-of-visit boarding (lawful suspicion)", weight=2, basis="Right-of-Visit (Suspicion)"},
    {name="SAR escort under Leviathan Protocol", weight=2, basis="Emergency/Leviathan Protocol"}
}

local outcomes = {
    "Compliant; cleared","Minor non-compliance; corrected; cleared",
    "Rerouted; passage maintained","Inspection completed; cargo intact",
    "Administrative notice issued; monitoring",
    "Escorted to anchorage for formal review","Denied entry pending documents",
    "SAR/aid rendered; voyage resumed"
}

-------------------------------------------------------------------------------
-- (C) UTILITIES
-------------------------------------------------------------------------------
local function pickWeighted(list)
    local total=0
    for _,item in ipairs(list) do total=total+(item.weight or 1) end
    local roll,cumul=math.random(total),0
    for _,item in ipairs(list) do
        cumul=cumul+(item.weight or 1)
        if roll<=cumul then return item end
    end
    return list[#list]
end

local function pick(list) return list[math.random(#list)] end

local clauseIndex={} for _,c in ipairs(clauses) do clauseIndex[c.key]=c.cite end

-------------------------------------------------------------------------------
-- (D) PROBABILITY & EVENT GEN
-------------------------------------------------------------------------------
local function enforcementProbability(flag, sector)
    local base=0.30
    if flag.risky then base=0.50 end
    if sector=="Sacred Buffer Approaches" or sector=="Environmental Buffer" then
        base=base+0.10
    end
    if base>0.65 then base=0.65 end
    return base
end

local function makeEvent(dateText, denyCount)
    local sector=pick(sectors)
    local flag=pickWeighted(flags)
    local vessel=pick(vessels)

    local prob=enforcementProbability(flag,sector)
    if math.random()>prob then
        return {date=dateText,sector=sector,vessel=vessel.." ("..flag.name..")",
            action="Routine transit",legal="N/A",outcome="No reports",notes="Compliant passage"}
    end

    local act=pickWeighted(actions)
    local cite=clauseIndex[act.basis] or "SC §—"
    local outcome=pick(outcomes)

    -- Guardrail: cap denied/anchorage outcomes
    if (outcome=="Denied entry pending documents" or outcome=="Escorted to anchorage for formal review") 
        and denyCount>=3 then
        outcome="Administrative notice issued; monitoring"
    end

    return {date=dateText,sector=sector,vessel=vessel.." ("..flag.name..")",
        action=act.name,legal=act.basis.." — "..cite,outcome=outcome,notes="—"}
end

-------------------------------------------------------------------------------
-- (E) PUBLIC FUNCTION
-------------------------------------------------------------------------------
function p.makeTable(frame)
    local dateInfo=getPSSCDate()
    math.randomseed(dateInfo.year*1000+dateInfo.dayOfYear)

    local ROWS=tonumber(frame and frame.args and frame.args.rows) or 18
    local out={"{| class=\"wikitable sortable\"","! Date !! Sector !! Vessel/Flag !! Action !! Legal Basis !! Outcome !! Notes"}

    local denyCount,totalEnf=0,0
    local events={}

    for i=1,ROWS do
        local ev=makeEvent(dateInfo.text,denyCount)
        if ev.outcome=="Denied entry pending documents" or ev.outcome=="Escorted to anchorage for formal review" then
            denyCount=denyCount+1
        end
        if ev.outcome~="No reports" then totalEnf=totalEnf+1 end
        table.insert(events,ev)
    end

    -- Guardrail: if >40% enforcement, downgrade some
    local maxEnf=math.floor(ROWS*0.40)
    if totalEnf>maxEnf then
        local reduced=0
        for _,ev in ipairs(events) do
            if reduced>=totalEnf-maxEnf then break end
            if ev.outcome~="No reports" and ev.outcome~="Compliant; cleared" then
                ev.outcome="Compliant; cleared"; ev.notes="Auto-downgraded for balance"
                reduced=reduced+1
            end
        end
    end

    for _,ev in ipairs(events) do
        table.insert(out,"|-")
        table.insert(out,"| "..ev.date.." || "..ev.sector.." || "..ev.vessel.." || "..ev.action.." || "..ev.legal.." || "..ev.outcome.." || "..ev.notes)
    end

    table.insert(out,"|}")
    table.insert(out,"<!-- StraitsDaily model v2.1, "..os.date().." -->")
    return table.concat(out,"\n")
end

return p