Module:StraitsDaily: Difference between revisions
From MicrasWiki
Jump to navigationJump to search
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 = {} ---..." |
NewZimiaGov (talk | contribs) No edit summary |
||
| Line 1: | Line 1: | ||
------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||
-- Module: StraitsDaily | -- Module: StraitsDaily | ||
-- Purpose: Daily report of | -- Purpose: Daily, in-world report of Strait of Haifa enforcement | ||
-- | -- Changes in this version: | ||
-- | -- • No mention of Florian cargo or the Imperial Federation. | ||
-- | -- • Explicit inclusion of Moorland and Bassaridian-flag vessels. | ||
-- • Frequency smoothing + per-flag caps to avoid over-mentioning any registry. | |||
-- • Non-escalatory language, outcome caps, and balance guardrails retained. | |||
------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||
| Line 10: | Line 12: | ||
------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||
-- (A) PSSC DATE | -- (A) PSSC DATE | ||
------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||
local function getPSSCDate() | local function getPSSCDate() | ||
| Line 44: | Line 46: | ||
} | } | ||
-- | -- Registries / flags: | ||
-- - Explicit: Moorland, Bassaridian-flag | |||
-- - Generic/neutral: Neutral Merchant, Distant Partner, Consortium Registry, Other Coastal State | |||
-- Per-flag 'risky' toggles are modest, to stay non-escalatory. | |||
local flags = { | local flags = { | ||
{name=" | {name="Bassaridian-flag", weight=3, risky=false}, | ||
{name=" | {name="Moorland", weight=3, risky=false}, | ||
{name="Neutral Merchant", weight=3}, | {name="Neutral Merchant", weight=4, risky=false}, | ||
{name=" | {name="Distant Partner", weight=3, risky=true}, | ||
{name="Other Coastal State", weight=2} | {name="Consortium Registry", weight=2, risky=true}, | ||
{name="Other Coastal State", weight=2, risky=false}, | |||
} | } | ||
| Line 60: | Line 66: | ||
local clauses = { | local clauses = { | ||
{key="Pilotage & Traffic Scheme", cite="SC §A2–A4"}, | {key="Pilotage & Traffic Scheme", cite="SC §A2–A4"}, | ||
{key="Tonnage & Warship Limits", cite="SC §B1–B4"}, | {key="Tonnage & Warship Limits", cite="SC §B1–B4"}, | ||
{key="Submarine Surface/Declare", cite="SC §C2–C3"}, | {key="Submarine Surface/Declare", cite="SC §C2–C3"}, | ||
{key="Environmental Buffer", cite="SC §D1–D3"}, | {key="Environmental Buffer", cite="SC §D1–D3"}, | ||
{key="Sacred Site Stand-off", cite="SC §E1–E2"}, | {key="Sacred Site Stand-off", cite="SC §E1–E2"}, | ||
{key="Emergency/Leviathan | {key="Emergency/Leviathan", cite="SC §L1–L4"}, | ||
{key="Right-of-Visit (Suspicion)", cite="SC §R1–R3"} | {key="Right-of-Visit (Suspicion)",cite="SC §R1–R3"} | ||
} | } | ||
local actions = { | local actions = { | ||
{name="Documents & pilotage verification", weight=5, basis="Pilotage & Traffic Scheme"}, | {name="Documents & pilotage verification", weight=5, basis="Pilotage & Traffic Scheme"}, | ||
{name="Tonnage/armament declaration check", weight=4, basis="Tonnage & Warship Limits"}, | {name="Tonnage/armament declaration check", weight=4, basis="Tonnage & Warship Limits"}, | ||
{name="Environmental reroute order", weight=3, basis="Environmental Buffer"}, | {name="Environmental reroute order", weight=3, basis="Environmental Buffer"}, | ||
{name="Sacred buffer stand-off adjustment", weight=3, basis="Sacred Site Stand-off"}, | {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="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="Right-of-visit boarding (lawful suspicion)", weight=2, basis="Right-of-Visit (Suspicion)"}, | ||
{name="SAR escort under Leviathan Protocol", weight=2, basis="Emergency/Leviathan | {name="SAR escort under Leviathan Protocol", weight=2, basis="Emergency/Leviathan"} | ||
} | } | ||
local outcomes = { | local outcomes = { | ||
"Compliant; cleared","Minor non-compliance; corrected; cleared", | "Compliant; cleared", | ||
"Rerouted; passage maintained","Inspection completed; cargo intact", | "Minor non-compliance; corrected; cleared", | ||
"Rerouted; passage maintained", | |||
"Inspection completed; cargo intact", | |||
"Administrative notice issued; monitoring", | "Administrative notice issued; monitoring", | ||
"Escorted to anchorage for formal review","Denied entry pending documents", | "Escorted to anchorage for formal review", | ||
"SAR/aid rendered; voyage resumed" | "Denied entry pending documents", | ||
"SAR/aid rendered; voyage resumed", | |||
"No reports" | |||
} | } | ||
| Line 99: | Line 109: | ||
return list[#list] | return list[#list] | ||
end | end | ||
local function pick(list) return list[math.random(#list)] end | local function pick(list) return list[math.random(#list)] end | ||
local clauseIndex = (function() | |||
local | local t={} for _,c in ipairs(clauses) do t[c.key]=c.cite end; return t | ||
end)() | |||
------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||
-- (D) PROBABILITY & | -- (D) ENFORCEMENT PROBABILITY & FLAG SMOOTHING | ||
------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||
local function | local function baseProb(flag, sector) | ||
local | local p = 0.30 | ||
if flag.risky then | if flag.risky then p = p + 0.10 end -- mild, non-accusatory bias | ||
if sector=="Sacred Buffer Approaches" or sector=="Environmental Buffer" then | if sector=="Sacred Buffer Approaches" or sector=="Environmental Buffer" then | ||
p = p + 0.10 | |||
end | end | ||
if | if p>0.60 then p=0.60 end | ||
return | return p | ||
end | end | ||
local function | -- To avoid over-mentioning, impose per-flag cap and discourage repeats. | ||
local | local function pickFlagWithCaps(flagCounts, maxPerFlag, lastFlagName) | ||
local | local tries = 0 | ||
while tries < 20 do | |||
local f = pickWeighted(flags) | |||
if (flagCounts[f.name] or 0) < maxPerFlag then | |||
-- discourage immediate repeats 50% of the time | |||
if lastFlagName and f.name == lastFlagName and math.random() < 0.5 then | |||
tries = tries + 1 | |||
else | |||
return f | |||
end | |||
else | |||
tries = tries + 1 | |||
end | |||
end | |||
-- fallback to any with room | |||
for _,f in ipairs(flags) do | |||
if (flagCounts[f.name] or 0) < maxPerFlag then return f end | |||
end | |||
return flags[#flags] | |||
end | |||
local | ------------------------------------------------------------------------------- | ||
if math.random()> | -- (E) EVENT GENERATION | ||
return {date=dateText,sector=sector,vessel=vessel.." ("..flag.name..")", | ------------------------------------------------------------------------------- | ||
action="Routine transit",legal="N/A",outcome="No reports",notes="Compliant passage"} | local function makeEvent(dateText, state) | ||
local sector = pick(sectors) | |||
local flag = pickFlagWithCaps(state.flagCounts, state.maxPerFlag, state.lastFlag) | |||
local vessel = pick(vessels) | |||
state.flagCounts[flag.name] = (state.flagCounts[flag.name] or 0) + 1 | |||
state.lastFlag = flag.name | |||
local pEnf = baseProb(flag, sector) | |||
if math.random() > pEnf then | |||
return { | |||
date=dateText, sector=sector, | |||
vessel=vessel.." ("..flag.name..")", | |||
action="Routine transit", legal="N/A", | |||
outcome="No reports", notes="Compliant passage" | |||
} | |||
end | end | ||
local act=pickWeighted(actions) | local act = pickWeighted(actions) | ||
local cite=clauseIndex[act.basis] or "SC §—" | local cite = clauseIndex[act.basis] or "SC §—" | ||
local | local out = pick(outcomes) | ||
-- Guardrail: cap strong outcomes (denied/anchorage review) total per day | |||
if (out=="Denied entry pending documents" or out=="Escorted to anchorage for formal review") | |||
and state.strongCount >= state.strongCap then | |||
out = "Administrative notice issued; monitoring" | |||
elseif out=="Denied entry pending documents" or out=="Escorted to anchorage for formal review" then | |||
state.strongCount = state.strongCount + 1 | |||
end | |||
-- | -- Sub rules & notes | ||
if | local notes = "—" | ||
if vessel=="Undeclared submarine" then | |||
act = {name="Submarine declare signal issued", basis="Submarine Surface/Declare"} | |||
cite = clauseIndex[act.basis] | |||
notes= "Undeclared contact directed to surface and declare per procedure" | |||
if out=="No reports" then out="Administrative notice issued; monitoring" end | |||
elseif vessel=="Declared submarine" then | |||
notes = "Declared sub transited in daylight per SC §C2–C3" | |||
elseif sector=="Sacred Buffer Approaches" then | |||
notes = "Stand-off distance verified for sacred sites" | |||
elseif sector=="Environmental Buffer" then | |||
notes = "Sensitive habitat protection enforced during passage" | |||
end | end | ||
return {date=dateText,sector=sector,vessel=vessel.." ("..flag.name..")", | -- Count enforcement share for later balancing | ||
action=act.name,legal=act.basis.." — "..cite,outcome= | if out~="No reports" then state.enfCount = state.enfCount + 1 end | ||
return { | |||
date=dateText, sector=sector, | |||
vessel=vessel.." ("..flag.name..")", | |||
action=act.name, legal=(act.basis.." — "..cite), | |||
outcome=out, notes=notes | |||
} | |||
end | end | ||
------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||
-- ( | -- (F) PUBLIC: makeTable | ||
------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||
function p.makeTable(frame) | function p.makeTable(frame) | ||
local dateInfo=getPSSCDate() | local dateInfo = getPSSCDate() | ||
math.randomseed(dateInfo.year*1000+dateInfo.dayOfYear) | math.randomseed(dateInfo.year*1000 + dateInfo.dayOfYear) | ||
local ROWS=tonumber(frame and frame.args and frame.args.rows) or 18 | local ROWS = tonumber(frame and frame.args and frame.args.rows) or 18 | ||
local out={ | local out = {} | ||
table.insert(out, '{| class="wikitable sortable"') | |||
table.insert(out, '! Date !! Sector !! Vessel/Flag !! Action !! Legal Basis !! Outcome !! Notes') | |||
local | -- Per-flag cap: ~35% of rows per registry max (rounded up) | ||
local maxPerFlag = math.max(1, math.ceil(ROWS * 0.35)) | |||
for i=1,ROWS do | local state = { | ||
local ev=makeEvent(dateInfo.text, | strongCount = 0, -- denied/anchorage combined | ||
strongCap = 3, -- daily cap | |||
flagCounts = {}, | |||
lastFlag = nil, | |||
enfCount = 0 | |||
table.insert(events,ev) | } | ||
local events = {} | |||
for i=1, ROWS do | |||
local ev = makeEvent(dateInfo.text, state) | |||
table.insert(events, ev) | |||
end | end | ||
-- | -- Balance guardrail: keep total enforcement ≤ 40% of rows | ||
local maxEnf=math.floor(ROWS*0.40) | local maxEnf = math.floor(ROWS * 0.40) | ||
if | if state.enfCount > maxEnf then | ||
local | local toReduce = state.enfCount - maxEnf | ||
for _,ev in ipairs(events) do | for _,ev in ipairs(events) do | ||
if | if toReduce <= 0 then break end | ||
if ev.outcome~="No reports" and ev.outcome~="Compliant; cleared" then | if ev.outcome ~= "No reports" and ev.outcome ~= "Compliant; cleared" then | ||
ev.outcome="Compliant; cleared" | ev.outcome = "Compliant; cleared" | ||
ev.notes = (ev.notes=="—" and "Auto-balanced for daily transparency") or (ev.notes.."; auto-balanced") | |||
toReduce = toReduce - 1 | |||
end | end | ||
end | end | ||
| Line 178: | Line 252: | ||
for _,ev in ipairs(events) do | for _,ev in ipairs(events) do | ||
table.insert(out,"|-") | table.insert(out, "|-") | ||
table.insert(out,"| "..ev.date.." || "..ev.sector.." || "..ev.vessel.." || "..ev.action.." || "..ev.legal.." || "..ev.outcome.." || "..ev.notes) | table.insert(out, "| "..ev.date.." || "..ev.sector.." || "..ev.vessel.." || "..ev.action.." || "..ev.legal.." || "..ev.outcome.." || "..ev.notes) | ||
end | end | ||
table.insert(out, | table.insert(out, '|}') | ||
table.insert(out, | table.insert(out, '<!-- StraitsDaily v3.0 (no explicit IF/Floria; Moorland+Bassaridian included; per-flag cap & smoothing) -->') | ||
return table.concat(out,"\n") | return table.concat(out, "\n") | ||
end | end | ||
return p | return p | ||
Revision as of 23:43, 5 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
-- Changes in this version:
-- • No mention of Florian cargo or the Imperial Federation.
-- • Explicit inclusion of Moorland and Bassaridian-flag vessels.
-- • Frequency smoothing + per-flag caps to avoid over-mentioning any registry.
-- • Non-escalatory language, outcome caps, and balance guardrails retained.
-------------------------------------------------------------------------------
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 = {
"Haifa West Inbound","Haifa East Outbound","Mid-Strait Separation Zone",
"Sacred Buffer Approaches","Environmental Buffer","Northern Approach TSS","Southern Approach TSS"
}
-- Registries / flags:
-- - Explicit: Moorland, Bassaridian-flag
-- - Generic/neutral: Neutral Merchant, Distant Partner, Consortium Registry, Other Coastal State
-- Per-flag 'risky' toggles are modest, to stay non-escalatory.
local flags = {
{name="Bassaridian-flag", weight=3, risky=false},
{name="Moorland", weight=3, risky=false},
{name="Neutral Merchant", weight=4, risky=false},
{name="Distant Partner", weight=3, risky=true},
{name="Consortium Registry", weight=2, risky=true},
{name="Other Coastal State", weight=2, risky=false},
}
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", 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"}
}
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",
"No reports"
}
-------------------------------------------------------------------------------
-- (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 = (function()
local t={} for _,c in ipairs(clauses) do t[c.key]=c.cite end; return t
end)()
-------------------------------------------------------------------------------
-- (D) ENFORCEMENT PROBABILITY & FLAG SMOOTHING
-------------------------------------------------------------------------------
local function baseProb(flag, sector)
local p = 0.30
if flag.risky then p = p + 0.10 end -- mild, non-accusatory bias
if sector=="Sacred Buffer Approaches" or sector=="Environmental Buffer" then
p = p + 0.10
end
if p>0.60 then p=0.60 end
return p
end
-- To avoid over-mentioning, impose per-flag cap and discourage repeats.
local function pickFlagWithCaps(flagCounts, maxPerFlag, lastFlagName)
local tries = 0
while tries < 20 do
local f = pickWeighted(flags)
if (flagCounts[f.name] or 0) < maxPerFlag then
-- discourage immediate repeats 50% of the time
if lastFlagName and f.name == lastFlagName and math.random() < 0.5 then
tries = tries + 1
else
return f
end
else
tries = tries + 1
end
end
-- fallback to any with room
for _,f in ipairs(flags) do
if (flagCounts[f.name] or 0) < maxPerFlag then return f end
end
return flags[#flags]
end
-------------------------------------------------------------------------------
-- (E) EVENT GENERATION
-------------------------------------------------------------------------------
local function makeEvent(dateText, state)
local sector = pick(sectors)
local flag = pickFlagWithCaps(state.flagCounts, state.maxPerFlag, state.lastFlag)
local vessel = pick(vessels)
state.flagCounts[flag.name] = (state.flagCounts[flag.name] or 0) + 1
state.lastFlag = flag.name
local pEnf = baseProb(flag, sector)
if math.random() > pEnf 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 out = pick(outcomes)
-- Guardrail: cap strong outcomes (denied/anchorage review) total per day
if (out=="Denied entry pending documents" or out=="Escorted to anchorage for formal review")
and state.strongCount >= state.strongCap then
out = "Administrative notice issued; monitoring"
elseif out=="Denied entry pending documents" or out=="Escorted to anchorage for formal review" then
state.strongCount = state.strongCount + 1
end
-- Sub rules & notes
local notes = "—"
if vessel=="Undeclared submarine" then
act = {name="Submarine declare signal issued", basis="Submarine Surface/Declare"}
cite = clauseIndex[act.basis]
notes= "Undeclared contact directed to surface and declare per procedure"
if out=="No reports" then out="Administrative notice issued; monitoring" end
elseif vessel=="Declared submarine" then
notes = "Declared sub transited in daylight per SC §C2–C3"
elseif sector=="Sacred Buffer Approaches" then
notes = "Stand-off distance verified for sacred sites"
elseif sector=="Environmental Buffer" then
notes = "Sensitive habitat protection enforced during passage"
end
-- Count enforcement share for later balancing
if out~="No reports" then state.enfCount = state.enfCount + 1 end
return {
date=dateText, sector=sector,
vessel=vessel.." ("..flag.name..")",
action=act.name, legal=(act.basis.." — "..cite),
outcome=out, notes=notes
}
end
-------------------------------------------------------------------------------
-- (F) PUBLIC: makeTable
-------------------------------------------------------------------------------
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 !! Notes')
-- Per-flag cap: ~35% of rows per registry max (rounded up)
local maxPerFlag = math.max(1, math.ceil(ROWS * 0.35))
local state = {
strongCount = 0, -- denied/anchorage combined
strongCap = 3, -- daily cap
flagCounts = {},
lastFlag = nil,
enfCount = 0
}
local events = {}
for i=1, ROWS do
local ev = makeEvent(dateInfo.text, state)
table.insert(events, ev)
end
-- Balance guardrail: keep total enforcement ≤ 40% of rows
local maxEnf = math.floor(ROWS * 0.40)
if state.enfCount > maxEnf then
local toReduce = state.enfCount - maxEnf
for _,ev in ipairs(events) do
if toReduce <= 0 then break end
if ev.outcome ~= "No reports" and ev.outcome ~= "Compliant; cleared" then
ev.outcome = "Compliant; cleared"
ev.notes = (ev.notes=="—" and "Auto-balanced for daily transparency") or (ev.notes.."; auto-balanced")
toReduce = toReduce - 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 v3.0 (no explicit IF/Floria; Moorland+Bassaridian included; per-flag cap & smoothing) -->')
return table.concat(out, "\n")
end
return p