diff --git a/mafiabot_core/.gitignore b/mafiabot_core/.gitignore new file mode 100644 index 0000000..033cda1 --- /dev/null +++ b/mafiabot_core/.gitignore @@ -0,0 +1,11 @@ +# Build artifacts +/bin/ +/obj/ + +# Alire-generated config (regenerated by `alr build` / CI) +/config/*_config.gpr +/config/*_config.ads +/config/*_config.h + +# Alire workspace +/alire/ diff --git a/mafiabot_core/src/config_loader/config_loader.ads b/mafiabot_core/src/config_loader/config_loader.ads index 2bc3646..c0b0bcd 100644 --- a/mafiabot_core/src/config_loader/config_loader.ads +++ b/mafiabot_core/src/config_loader/config_loader.ads @@ -24,8 +24,10 @@ is type Entry_Index is range 1 .. Max_Keys; subtype Entry_Count is Natural range 0 .. Max_Keys; + type Entry_Array is array (Entry_Index) of Config_Entry; + type Config_Store is record - Entries : array (Entry_Index) of Config_Entry := + Entries : Entry_Array := (others => (Key => (others => ' '), Key_Len => 0, Val => (others => ' '), Val_Len => 0)); Count : Entry_Count := 0; diff --git a/mafiabot_core/src/organs/ada_medium/ada_medium.adb b/mafiabot_core/src/organs/ada_medium/ada_medium.adb index 6668b52..5a64860 100644 --- a/mafiabot_core/src/organs/ada_medium/ada_medium.adb +++ b/mafiabot_core/src/organs/ada_medium/ada_medium.adb @@ -168,7 +168,7 @@ is Msg : Organ_Message; Ref : Soul.State.Session_Ref := Soul.State.No_Session; begin - Output := (others => ' ', Length => 0); + Output := (Data => (others => ' '), Length => 0); Inference_Orchestrator.Reset; -- Resolve the session for this (uid, channel, server). The cross and @@ -304,7 +304,10 @@ is -- Step 20: sendAda Inference_Orchestrator.Advance (Phase_Send_Ada, S); if S /= OK then Status := S; return; end if; - Msg := Make_Internal_Msg (Ada_Medium, Ada_Medium, Accum); + -- Qualify the Organ_Id literal: the simple name Ada_Medium binds to + -- this package, shadowing the enum value of the same name. + Msg := Make_Internal_Msg + (Mafiabot_Types.Ada_Medium, Mafiabot_Types.Ada_Medium, Accum); -- Step 21: Ada routes (trust boundary outbound screen) Inference_Orchestrator.Advance (Phase_Route, S); diff --git a/mafiabot_core/src/organs/soul/soul-celtic_cross.adb b/mafiabot_core/src/organs/soul/soul-celtic_cross.adb index 4fab3f6..46c5971 100644 --- a/mafiabot_core/src/organs/soul/soul-celtic_cross.adb +++ b/mafiabot_core/src/organs/soul/soul-celtic_cross.adb @@ -2,6 +2,8 @@ package body Soul.Celtic_Cross with SPARK_Mode => On is + use type Soul.Tarot.Slot_State; + procedure Draw_Spread (D : in out Soul.Tarot.Deck; Spread : out CC_Spread; diff --git a/mafiabot_core/src/organs/soul/soul-state.adb b/mafiabot_core/src/organs/soul/soul-state.adb index 6dce3f3..d269c8c 100644 --- a/mafiabot_core/src/organs/soul/soul-state.adb +++ b/mafiabot_core/src/organs/soul/soul-state.adb @@ -157,7 +157,7 @@ is Sun_L : constant String := "## Sun: "; Moon_L : constant String := ASCII.LF & "## Moon: "; Asc_L : constant String := ASCII.LF & "## Ascendant: "; - Footer : constant String := ASCII.LF; + Footer : constant String := (1 => ASCII.LF); Total : constant Natural := Header'Length @@ -166,7 +166,7 @@ is + Asc_L'Length + Asc_T.Length + Footer'Length; begin - Buffer := (others => ' ', Length => 0); + Buffer := (Data => (others => ' '), Length => 0); if Total > Max_Text_Length then Status := Error_Overflow; return; diff --git a/mafiabot_core/src/organs/soul/soul-state.ads b/mafiabot_core/src/organs/soul/soul-state.ads index e2406c0..bafc188 100644 --- a/mafiabot_core/src/organs/soul/soul-state.ads +++ b/mafiabot_core/src/organs/soul/soul-state.ads @@ -43,24 +43,50 @@ is Channel : String; Server : String) return Bounded_Text; + -- Per-session storage types. These live in the visible part because the + -- Soul_State protected object (declared below) holds a Session_Table as a + -- private component, and a protected definition may only contain data + -- components — not type or constant declarations. + Max_Key : constant := 192; + subtype Key_Length is Natural range 0 .. Max_Key; + type Session_Key is record + Data : String (1 .. Max_Key) := (others => ' '); + Length : Key_Length := 0; + end record; + + type Layer_Flags is array (Soul.Celtic_Cross.CC_Layer) of Boolean; + + type Session_Slot is record + In_Use : Boolean := False; + Key : Session_Key; + Deck : Soul.Tarot.Deck := Soul.Tarot.Full_Deck; + Spread : Soul.Celtic_Cross.CC_Spread := + Soul.Celtic_Cross.Empty_Spread; + Layer_Done : Layer_Flags := (others => False); + Output_Counter : Natural := 0; + end record; + + type Session_Table is array (Valid_Session) of Session_Slot; + protected Soul_State is pragma Priority (System.Priority'Last - 2); -- Set the three immutable personality anchors. Fails if called twice. + -- (A protected operation may not reference its own protected functions + -- in pre/postconditions, so the Is_Initialized guard lives in the body.) procedure Initialize_Big_Three (B3 : in Soul.Tarot.Big_Three; - Status : out Operation_Status) - with Post => (if Status = OK then Is_Initialized); + Status : out Operation_Status); -- Resolve a session by key, allocating a fresh slot (with its own -- Big-3-pruned deck) on first sight. Returns No_Session + - -- Error_Overflow if the table is full. + -- Error_Overflow if the table is full. Callers must Initialize_Big_Three + -- first; Open_Session uses the global Big-3 to prune each new deck. procedure Open_Session (Key : in Bounded_Text; Ref : out Session_Ref; Status : out Operation_Status) - with Pre => Is_Initialized, - Post => (if Status = OK then Ref in Valid_Session); + with Post => (if Status = OK then Ref in Valid_Session); -- Accrete one cognitive layer of THIS session's cross from its pool. -- Idempotent per layer: re-forming an already-formed layer is a no-op @@ -79,10 +105,10 @@ is procedure Note_Output (Ref : in Valid_Session); -- Serialise the global identity into Bounded_Text for SOUL.md. + -- Caller must Initialize_Big_Three first (guard lives in the body). procedure Generate_Soul_MD (Buffer : out Bounded_Text; - Status : out Operation_Status) - with Pre => Is_Initialized; + Status : out Operation_Status); function Is_Initialized return Boolean; function Get_Big_Three return Soul.Tarot.Big_Three; @@ -96,30 +122,7 @@ is private Big_3 : Soul.Tarot.Big_Three; Initialized : Boolean := False; - - Max_Key : constant := 192; - subtype Key_Length is Natural range 0 .. Max_Key; - type Session_Key is record - Data : String (1 .. Max_Key) := (others => ' '); - Length : Key_Length := 0; - end record; - - type Layer_Flags is - array (Soul.Celtic_Cross.CC_Layer) of Boolean; - - type Session_Slot is record - In_Use : Boolean := False; - Key : Session_Key; - Deck : Soul.Tarot.Deck := Soul.Tarot.Full_Deck; - Spread : Soul.Celtic_Cross.CC_Spread := - Soul.Celtic_Cross.Empty_Spread; - Layer_Done : Layer_Flags := (others => False); - Output_Counter : Natural := 0; - end record; - - type Session_Table is array (Valid_Session) of Session_Slot; - - Sessions : Session_Table; + Sessions : Session_Table; end Soul_State; end Soul.State; diff --git a/mafiabot_core/src/organs/soul/soul.adb b/mafiabot_core/src/organs/soul/soul.adb deleted file mode 100644 index 766b87d..0000000 --- a/mafiabot_core/src/organs/soul/soul.adb +++ /dev/null @@ -1,4 +0,0 @@ -package body Soul - with SPARK_Mode => On -is -end Soul; diff --git a/mafiabot_core/src/protocol/hermes_protocol.adb b/mafiabot_core/src/protocol/hermes_protocol.adb index e91cf03..077535f 100644 --- a/mafiabot_core/src/protocol/hermes_protocol.adb +++ b/mafiabot_core/src/protocol/hermes_protocol.adb @@ -39,7 +39,7 @@ is when ASCII.LF => Append (Buf, "\n"); when ASCII.CR => Append (Buf, "\r"); when ASCII.HT => Append (Buf, "\t"); - when others => Append (Buf, (1 => S (I))); + when others => Append (Buf, String'(1 => S (I))); end case; end loop; end Append_Escaped; diff --git a/mafiabot_core/src/types/mafiabot_types.ads b/mafiabot_core/src/types/mafiabot_types.ads index 8385dbc..b7c4302 100644 --- a/mafiabot_core/src/types/mafiabot_types.ads +++ b/mafiabot_core/src/types/mafiabot_types.ads @@ -38,6 +38,11 @@ is type Ratio_Value is delta 0.001 range 0.0 .. 1.0; type Cost_Value is delta 0.001 range 0.0 .. 1000.0; type Axis_Value is delta 0.01 range -1.0 .. 1.0; + -- Pin 'Small to 0.01 so the bounds are +/-100 units (fits a byte) rather + -- than GNAT's default 2**-7 small, which would place 1.0 at exactly 128 -- + -- one past a signed-8-bit base range and rejected as "high bound outside + -- type range". + for Axis_Value'Small use 0.01; -- Provenance tags — trust boundary uses these to block reclassification type Provenance_Tag is ( diff --git a/mafiabot_core/tests/soul_tests.adb b/mafiabot_core/tests/soul_tests.adb index c376177..ce4e145 100644 --- a/mafiabot_core/tests/soul_tests.adb +++ b/mafiabot_core/tests/soul_tests.adb @@ -4,6 +4,8 @@ with Soul.Tarot; with Soul.Celtic_Cross; with Mafiabot_Types; use Mafiabot_Types; +use type Soul.Tarot.Slot_State; + procedure Soul_Tests is Fails : Natural := 0;