Module:StraitsDaily: Difference between revisions

From MicrasWiki
Jump to navigationJump to search
NewZimiaGov (talk | contribs)
No edit summary
NewZimiaGov (talk | contribs)
No edit summary
Line 1: Line 1:
-- Module: StraitsDaily
-- Module: StraitsDaily
-- Purpose: Daily, in-world report of Strait of Haifa enforcement (White-Lane + WL-03 aware, tied to Corum districts)
-- Purpose: Daily, in-world report of Strait of Haifa enforcement


local p = {}
local p = {}
Line 109: Line 109:
-- White-Lane corridors tied to districts
-- White-Lane corridors tied to districts
local wlCorridors = {
local wlCorridors = {
     {
     { code="WL-NZ-1", name="New Zimian Humanitarian Belt", win="0700–1100", kind="NZ",
        code="WL-NZ-1", name="New Zimian Humanitarian Belt", win="0700–1100", kind="NZ",
      districts={"Lyvian Zones","Lucinarian Zones","Brentonian Zones","Ossyani Zones"} },
        districts={"Lyvian Zones","Lucinarian Zones","Brentonian Zones","Ossyani Zones"}
     { code="WL-GM-2", name="Bayen Relief Spur", win="0900–1300", kind="GM",
    },
      districts={"Sinclarian Zones","Nortonian Zones","Wallisian Zones","Alindan Zones","Aijiac Zones"} },
     {
     { code="WL-SEA-3", name="Corum Coastal Shuttle", win="0600–1800", kind="Mixed",
        code="WL-GM-2", name="Bayen Relief Spur", win="0900–1300", kind="GM",
      districts={"Wallisian Zones","Nortonian Zones","Lyvian Zones"} }
        districts={"Sinclarian Zones","Nortonian Zones","Wallisian Zones","Alindan Zones","Aijiac Zones"}
    },
     {
        code="WL-SEA-3", name="Corum Coastal Shuttle", win="0600–1800", kind="Mixed",
        districts={"Wallisian Zones","Nortonian Zones","Lyvian Zones"} -- mixed coastal touchpoints
    }
}
}


Line 256: Line 250:
             q = q + (partner and partner.risk or 0)
             q = q + (partner and partner.risk or 0)
             if wlEligible then q = math.max(q - 0.06, 0.10) end
             if wlEligible then q = math.max(q - 0.06, 0.10) end
            -- M-AMBER risk tag for Matamoros without WL-03 pledge (only affects non-WL)
             if flag.name:match("Matamoros") and wl03note == "WL-03 not signed (M-AMBER)" then
             if flag.name:match("Matamoros") and wl03note == "WL-03 not signed (M-AMBER)" then
                 q = q + 0.08
                 q = q + 0.08
            end
            -- >>> Bassaridian-flag 90%+ compliance: cap enforcement very low
            if flag.name == "Bassaridian-flag" then
                q = q - 0.18                -- cultural/compliance training effect
                if wlEligible then q = q - 0.04 end -- even smoother on WL
                if q < 0.02 then q = 0.02 end
                if q > 0.08 then q = 0.08 end -- <=8% chance of enforcement => >=92% clear
             end
             end
             return math.min(q, 0.72)
             return math.min(q, 0.72)
Line 290: Line 292:
             outcome = wlEligible and "WL reconciliation check; monitoring" or "Administrative notice issued; monitoring"
             outcome = wlEligible and "WL reconciliation check; monitoring" or "Administrative notice issued; monitoring"


            -- push to hold if multiple risk factors present
             local riskPush = 0
             local riskPush = 0
             if flag.name:match("Imperial Federation") or flag.name:match("Matamoros") then riskPush = riskPush + 1 end
             if flag.name:match("Imperial Federation") or flag.name:match("Matamoros") then riskPush = riskPush + 1 end
Line 304: Line 307:
             end
             end


             appealCol = appealsStatus(sector, wlEligible, tag, cargo)
            -- >>> Bassaridian-flag safeguard: downgrade any hold to admin reconciliation (keeps rare issues non-violative)
            if flag.name == "Bassaridian-flag" and outcome:match("hold") then
                outcome  = wlEligible and "WL reconciliation complete; cleared same window" or "Administrative reconciliation complete; cleared"
                appealCol = wlEligible and "N/A (WL cleared)" or "N/A"
            end
 
             appealCol = appealCol or appealsStatus(sector, wlEligible, tag, cargo)
         end
         end



Revision as of 00:42, 12 September 2025

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

-- Module: StraitsDaily
-- Purpose: Daily, in-world report of Strait of Haifa enforcement

local p = {}

-------------------------------------------------------------------------------
-- (A) PSSC DATE
-------------------------------------------------------------------------------
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 = {
    "Strait South Inbound","Strait South Outbound","Strait North Inbound","Strait North Outbound",
    "Archipelago Zone","Sacred Buffer Approaches","Environmental Buffer","Northern Approach TSS","Southern Approach TSS"
}

local flags = {
    {name="Bassaridian-flag", weight=6, risky=false},
    {name="Moorland", weight=2, risky=false},
    {name="Imperial Federation", weight=5, risky=true},
    {name="Matamoros (IF)", weight=2, risky=true}, -- subject to WL-03 conditions
    {name="Neutral Merchant", weight=4, risky=false},
    {name="Diaspora Stakeholders- Euranidom", weight=3, risky=true},
    {name="Diaspora Stakeholders- Corumia", weight=3, risky=true},
    {name="Diaspora Stakeholders- South Keltiania", weight=3, risky=true},
    {name="Consortium Registry", weight=2, risky=true},
    {name="Independent Coastal State", weight=7, risky=false}
}

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

local cargoTypes = {
    {name="Medical reagents (dual-use precursors)", weight=3, risk=0.14, dual=true},
    {name="Industrial oxidizers / nitrates (dual-use)", weight=2, risk=0.16, dual=true},
    {name="Precision machine tools & CNC spares (dual-use)", weight=3, risk=0.15, dual=true},
    {name="Encrypted electronics & comms modules (dual-use)", weight=2, risk=0.17, dual=true},
    {name="Satellite components / sensors (dual-use)", weight=1, risk=0.18, dual=true},
    {name="Industrial fasteners (coded)", weight=2, risk=0.12, dual=true},
    {name="Hydraulic lubricants (dual-use)", weight=2, risk=0.13, dual=true},
    {name="High-frequency alloys (coded)", weight=1, risk=0.14, dual=true},
    {name="Aviation fuels & additives", weight=3, risk=0.12, dual=false},
    {name="Refined petroleum products", weight=4, risk=0.08, dual=false},
    {name="Relief supplies (mixed pallets)", weight=5, risk=0.06, dual=false},
    {name="Agricultural commodities", weight=5, risk=0.04, dual=false},
    {name="Finished consumer goods", weight=6, risk=0.03, dual=false}
}

local cargoTags = {
    {name="standard",  weight=6, risk=0.00},
    {name="expedited", weight=3, risk=0.05},
    {name="emergency", weight=2, risk=0.07},
    {name="perishable",weight=2, risk=0.06}
}

-- Partner profiles (WL-03 90-day cooldown flag example)
local partnerProfiles = {
    {code="P-07", weight=4, risk=0.00, recentLift=false},
    {code="P-12", weight=3, risk=0.03, recentLift=false},
    {code="P-17", weight=3, risk=0.12, recentLift=true},
    {code="P-22", weight=3, risk=0.14, recentLift=true},
    {code="P-31", weight=3, risk=0.05, recentLift=false},
    {code="P-38", weight=2, risk=0.10, recentLift=false},
    {code="P-44", weight=4, risk=0.02, recentLift=false},
    {code="P-53", weight=3, risk=0.04, recentLift=false}
}

-- Corum districts (match MissionaryDaily "Zones")
local corumDistricts = {
    {name="Lyvian Zones",     kind="NZ"},
    {name="Lucinarian Zones", kind="NZ"},
    {name="Brentonian Zones", kind="NZ"},
    {name="Ossyani Zones",    kind="NZ"},
    {name="Sinclarian Zones", kind="GM"},
    {name="Nortonian Zones",  kind="GM"},
    {name="Wallisian Zones",  kind="GM"},
    {name="Alindan Zones",    kind="GM"},
    {name="Aijiac Zones",     kind="GM"},
}
local districtKindByName = {}
for _,d in ipairs(corumDistricts) do districtKindByName[d.name] = d.kind end

-- White-Lane corridors tied to districts
local wlCorridors = {
    { code="WL-NZ-1", name="New Zimian Humanitarian Belt", win="0700–1100", kind="NZ",
      districts={"Lyvian Zones","Lucinarian Zones","Brentonian Zones","Ossyani Zones"} },
    { code="WL-GM-2", name="Bayen Relief Spur", win="0900–1300", kind="GM",
      districts={"Sinclarian Zones","Nortonian Zones","Wallisian Zones","Alindan Zones","Aijiac Zones"} },
    { code="WL-SEA-3", name="Corum Coastal Shuttle", win="0600–1800", kind="Mixed",
      districts={"Wallisian Zones","Nortonian Zones","Lyvian Zones"} }
}

-- Neutral observer pool (invitees added only after acceptance)
local observers = {
    "Neutral temple auditor","Independent port compliance inspector",
    "Community elder (witness)","Straits Convention monitor (civilian)"
}

-- WL-03 participation pledge registry (true = signed; false = unsigned)
local wl03Signers = {
    ["Matamoros (IF)"] = false,        -- M-AMBER until pledge signed
    ["Imperial Federation"] = false,   -- adjust if needed
    ["Bassaridian-flag"] = true,
    ["Neutral Merchant"] = true,
    ["Moorland"] = true,
    ["Independent Coastal State"] = true
}

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

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

-- WL eligibility (Annex G) + WL-03 participation + 90-day cooldown
local function wlEligibility(cargo, tag, flag, partner)
    if not cargo or not tag then return false, "n/a" end
    local green = (cargo.name == "Relief supplies (mixed pallets)" or cargo.name == "Agricultural commodities")
    local amber = (tag.name == "expedited" or tag.name == "emergency" or tag.name == "perishable")
    local baseEligible = ((green or amber) and not cargo.dual)

    local signed = wl03Signers[flag.name]
    if signed == nil then signed = true end
    local cooling = (partner and partner.recentLift) or false

    if not baseEligible then
        return false, "Not eligible cargo/tag"
    elseif not signed then
        return false, "WL-03 not signed (M-AMBER)"
    elseif cooling then
        return false, "WL-03 cooldown (90 days)"
    else
        return true, "WL-03 compliant"
    end
end

-- Legal basis per Conventions
local function legalBasis(sector, wl, wl03note)
    if wl then
        return "Art III.5 (White-Lane); Annex G; Art X.3 (expedited remedies); HCE Circular WL-03 (" .. wl03note .. ")"
    end
    if sector == "Sacred Buffer Approaches" or sector == "Environmental Buffer" then
        return "Art III.2.3 (Sacred quiet zones); Annex A (delims); Art VII; Annex D"
    end
    return "Art IV.1–1.2 (PSC); Annex F (SCT/SAC procedures)"
end

-- Appeals column
local function appealsStatus(sector, wl, tag, cargo)
    if wl then
        local relief = 0.60
        if tag and (tag.name=="emergency" or tag.name=="perishable") then relief = relief + 0.12 end
        if cargo and cargo.dual then relief = relief - 0.15 end
        local r = math.random()
        local outcome = (r <= relief * 0.6) and "clearance granted"
                      or (r <= relief)       and "expedited with conditions"
                      or "conditions imposed"
        return string.format("HCE Review → SCT (72h) → SAC (≤5d) — %s (Art X.3; Annex G; WL-03 liaison)", outcome)
    else
        local level = (sector=="Sacred Buffer Approaches" or sector=="Environmental Buffer") and "SAC Referral"
                      or ((math.random()<0.5) and "SCT Admin Review" or "PSC reconciliation")
        local outcome = (level=="PSC reconciliation") and "notice acknowledged"
                        or ((math.random()<0.5) and "clearance granted" or "conditions imposed")
        local cite = (level=="SAC Referral") and "Annex F (SAC)" or "Annex F (SCT)"
        return string.format("%s — %s (%s)", level, outcome, cite)
    end
end

-- HCE reference for WL notes
local function hceRef(dateInfo, corridor)
    return string.format("HCE-%03d.%03d-%s", dateInfo.year, dateInfo.dayOfYear, corridor.code)
end

-- Pick a served district for a corridor and annotate with kind
local function pickServedDistrict(corr)
    local dname = corr.districts[math.random(#corr.districts)]
    local kind  = districtKindByName[dname] or "NZ"
    return dname, kind
end

-------------------------------------------------------------------------------
-- (D) MAIN GENERATION
-------------------------------------------------------------------------------
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 = {}
    table.insert(out, "{| class='wikitable sortable'")
    table.insert(out, "! Date !! Sector !! Vessel/Flag !! Action !! Legal Basis !! Outcome !! Appeals/Review (Straits Conventions) !! Notes")

    for _ = 1, rows do
        local sector  = pick(sectors)
        local flag    = pickWeighted(flags)
        local vessel  = pick(vessels)
        local cargo   = pickWeighted(cargoTypes)
        local tag     = pickWeighted(cargoTags)
        local partner = pickWeighted(partnerProfiles)

        local wlOK, wl03note = wlEligibility(cargo, tag, flag, partner)
        local wlEligible = wlOK
        local corridor = wlEligible and wlCorridors[math.random(#wlCorridors)] or nil
        local obs = wlEligible and observers[math.random(#observers)] or nil

        -- Base enforcement probability
        local function baseProb()
            local q = 0.28
            if flag.risky then q = q + 0.06 end
            if sector == "Sacred Buffer Approaches" or sector == "Environmental Buffer" then q = q + 0.08 end
            q = q + (cargo and cargo.risk or 0)
            if cargo and cargo.dual then q = q + 0.03 end
            q = q + (tag and tag.risk or 0)
            q = q + (partner and partner.risk or 0)
            if wlEligible then q = math.max(q - 0.06, 0.10) end
            -- M-AMBER risk tag for Matamoros without WL-03 pledge (only affects non-WL)
            if flag.name:match("Matamoros") and wl03note == "WL-03 not signed (M-AMBER)" then
                q = q + 0.08
            end
            -- >>> Bassaridian-flag 90%+ compliance: cap enforcement very low
            if flag.name == "Bassaridian-flag" then
                q = q - 0.18                -- cultural/compliance training effect
                if wlEligible then q = q - 0.04 end -- even smoother on WL
                if q < 0.02 then q = 0.02 end
                if q > 0.08 then q = 0.08 end -- <=8% chance of enforcement => >=92% clear
            end
            return math.min(q, 0.72)
        end

        local enforce = baseProb()
        local action, legal, outcome, notes, appealCol

        if wlEligible then
            local dname, dkind = pickServedDistrict(corridor)
            action = "WL transit / pilotage verification"
            legal  = legalBasis(sector, true, wl03note)
            notes  = string.format(
                "WL %s (%s) | window %s | District: %s [%s] | Observer: %s | %s | Cargo: %s [%s]; Partner: %s | WL-03: %s",
                corridor.code, corridor.name, corridor.win, dname, dkind, (obs or "n/a"),
                hceRef(dateInfo, corridor), cargo.name, tag.name, partner.code, wl03note
            )
        else
            action = (wl03note == "WL-03 not signed (M-AMBER)" or wl03note == "WL-03 cooldown (90 days)")
                     and "WL-ineligible: standard PSC applied"
                     or  "Cargo manifest reconciliation audit"
            legal  = legalBasis(sector, false, wl03note)
            local mAmber = (flag.name:match("Matamoros") and wl03note == "WL-03 not signed (M-AMBER)") and " | Risk tag: M-AMBER" or ""
            notes  = string.format("Cargo: %s [%s]; Partner: %s | WL-03: %s%s",
                                   cargo.name, tag.name, partner.code, wl03note, mAmber)
        end

        if math.random() > enforce then
            outcome  = wlEligible and "Cleared WL window" or "No reports"
            appealCol = wlEligible and "N/A (WL cleared)" or "N/A"
        else
            outcome = wlEligible and "WL reconciliation check; monitoring" or "Administrative notice issued; monitoring"

            -- push to hold if multiple risk factors present
            local riskPush = 0
            if flag.name:match("Imperial Federation") or flag.name:match("Matamoros") then riskPush = riskPush + 1 end
            if cargo.dual or (cargo.risk or 0) >= 0.12 then riskPush = riskPush + 1 end
            if tag.name ~= "standard" then riskPush = riskPush + 1 end
            if (partner.risk or 0) >= 0.09 then riskPush = riskPush + 1 end
            if wlEligible then riskPush = math.max(riskPush - 1, 0) end

            if riskPush >= 2 and math.random() < 0.65 then
                outcome = (wlEligible and "WL hold; clearance pending expedited review" or "Random audit hold; clearance pending")
                if flag.name == "Imperial Federation" or flag.name == "Matamoros (IF)" then
                    outcome = outcome .. " [Extended regulatory review]"
                end
            end

            -- >>> Bassaridian-flag safeguard: downgrade any hold to admin reconciliation (keeps rare issues non-violative)
            if flag.name == "Bassaridian-flag" and outcome:match("hold") then
                outcome  = wlEligible and "WL reconciliation complete; cleared same window" or "Administrative reconciliation complete; cleared"
                appealCol = wlEligible and "N/A (WL cleared)" or "N/A"
            end

            appealCol = appealCol or appealsStatus(sector, wlEligible, tag, cargo)
        end

        table.insert(out, "|-")
        table.insert(out, string.format("| %s || %s || %s (%s) || %s || %s || %s || %s || %s",
            dateInfo.text, sector, vessel, flag.name, action, legal, outcome, appealCol, notes))
    end

    table.insert(out, "|}")
    return table.concat(out, "\n")
end

return p