44
55import datetime
66import json
7+ import logging
78from typing import Any
89
910from ..models import (
1718from .redaction import redact
1819from .summarize import summarize
1920
21+ logger = logging .getLogger (__name__ )
22+
2023
2124class Firewall :
2225 """Transforms :class:`RawResult` objects into LLM-safe :class:`Frame` objects.
@@ -90,18 +93,49 @@ def transform(
9093 data , redact_warnings = redact (data , max_depth = self ._budgets .max_depth )
9194 warnings .extend (redact_warnings )
9295
96+ logger .debug (
97+ "firewall_redaction" ,
98+ extra = {
99+ "action_id" : action_id ,
100+ "capability_id" : raw .capability_id ,
101+ "principal_id" : principal_id ,
102+ "redaction_warnings" : len (redact_warnings ),
103+ "needs_redaction" : needs_redaction ,
104+ },
105+ )
106+
93107 # ── Raw mode (admin only) ──────────────────────────────────────────────
94108 if response_mode == "raw" :
95109 if "admin" not in principal_roles :
96110 warnings .append ("raw mode requires admin role; falling back to summary." )
97111 response_mode = "summary"
112+ logger .debug (
113+ "firewall_mode_fallback" ,
114+ extra = {
115+ "action_id" : action_id ,
116+ "capability_id" : raw .capability_id ,
117+ "requested_mode" : "raw" ,
118+ "effective_mode" : "summary" ,
119+ "reason" : "principal lacks admin role" ,
120+ },
121+ )
98122 else :
99123 raw_size = len (json .dumps (data , default = str ))
100124 if raw_size > self ._budgets .max_chars :
101125 warnings .append (
102126 f"raw output ({ raw_size } chars) exceeds budget "
103127 f"({ self ._budgets .max_chars } chars); data returned untruncated."
104128 )
129+ logger .debug (
130+ "firewall_transform" ,
131+ extra = {
132+ "action_id" : action_id ,
133+ "capability_id" : raw .capability_id ,
134+ "response_mode" : "raw" ,
135+ "raw_size_chars" : raw_size ,
136+ "budget_chars" : self ._budgets .max_chars ,
137+ },
138+ )
105139 return Frame (
106140 action_id = action_id ,
107141 capability_id = raw .capability_id ,
@@ -114,6 +148,14 @@ def transform(
114148
115149 # ── Handle only ───────────────────────────────────────────────────────
116150 if response_mode == "handle_only" :
151+ logger .debug (
152+ "firewall_transform" ,
153+ extra = {
154+ "action_id" : action_id ,
155+ "capability_id" : raw .capability_id ,
156+ "response_mode" : "handle_only" ,
157+ },
158+ )
117159 return Frame (
118160 action_id = action_id ,
119161 capability_id = raw .capability_id ,
@@ -126,6 +168,16 @@ def transform(
126168 # ── Table mode ────────────────────────────────────────────────────────
127169 if response_mode == "table" :
128170 table_preview = self ._make_table (data , max_rows = max_rows )
171+ logger .debug (
172+ "firewall_transform" ,
173+ extra = {
174+ "action_id" : action_id ,
175+ "capability_id" : raw .capability_id ,
176+ "response_mode" : "table" ,
177+ "rows_returned" : len (table_preview ),
178+ "max_rows" : max_rows ,
179+ },
180+ )
129181 return Frame (
130182 action_id = action_id ,
131183 capability_id = raw .capability_id ,
@@ -140,6 +192,16 @@ def transform(
140192 facts = summarize (data , max_facts = 20 )
141193 # Enforce char budget across all facts
142194 facts = _cap_facts (facts , self ._budgets .max_chars )
195+ logger .debug (
196+ "firewall_transform" ,
197+ extra = {
198+ "action_id" : action_id ,
199+ "capability_id" : raw .capability_id ,
200+ "response_mode" : "summary" ,
201+ "facts_count" : len (facts ),
202+ "budget_chars" : self ._budgets .max_chars ,
203+ },
204+ )
143205 return Frame (
144206 action_id = action_id ,
145207 capability_id = raw .capability_id ,
0 commit comments