Calculating Texas Public Information Act Deadlines with Attorney-General Tolling
Within State Law Compliance Frameworks, the Texas Public Information Act (PIA) sets a deadline that has no counterpart in most other state acts: to withhold information it believes is excepted from disclosure, a governmental body must ask the Texas Attorney General for a ruling within a fixed business-day window, and blowing that window generally forfeits the exception. This page builds a Python module that models the PIA’s core clocks — the “promptly produce” standard, the 10-business-day Attorney-General ruling-request deadline under Gov’t Code § 552.301, and the tolling that a clarification request triggers — using holiday-aware business-day math and an audit-ready record for every calculation.
The PIA Statutory Clock
The Texas Public Information Act (Gov’t Code ch. 552) begins from a strong presumption of openness: § 552.221 requires a governmental body to “promptly produce” public information in response to a request, meaning as soon as possible under the circumstances, without delay. “Promptly” is a standard, not a fixed count, so an automation cannot pin it to a single date; instead it tracks it as an obligation that begins at receipt and is measured for reasonableness.
The fixed clock the automation can compute is the one that governs withholding. Under § 552.301, if a governmental body wishes to withhold information it considers excepted, and there has been no prior determination that the information is excepted, it must request an Attorney General ruling within 10 business days of receiving the request. Miss that deadline and § 552.302 provides that the information is presumed public and must be released absent a compelling reason to withhold. The 10th-business-day clock is therefore the single most consequential deadline in a Texas records workflow, and it is counted in business days — weekends and legal holidays do not count.
Two events move the start of that clock. A request that is unclear or overbroad lets the governmental body seek clarification or a narrowing under § 552.222; when it does, the request is treated as received on the date the requester’s clarification arrives, effectively tolling and restarting the count. Because that toll shifts every downstream date, the automation must record whether a clarification occurred and which effective receipt date the clock ran from. Escalation built on top of these dates lives in Deadline Tracking & Escalation.
Prerequisites & Environment Setup
The module is standard-library only, so it carries no third-party runtime dependency and is safe to run inline in the request path.
- Python 3.11+ — for
datetime.date,frozenset[date]typing, and frozen slotted dataclasses. - Standard library only:
dataclasses,datetime,json,logging. - A version-controlled holiday set — Texas skip-days for the business-day count are the national and state holidays a governmental body observes; pin one
frozensetper year and review it, as you would any statutory artifact. - A structured log sink — stdout JSON in development, forwarded to an append-only store or SIEM in production so every deadline is reconstructable if the Attorney General or a court later reviews it.
Keep the holiday set and the code together under version control. A single dropped holiday shortens the business-day count by a day and can turn a timely ruling request into a presumptively-public disclosure under § 552.302.
Modeling the Withholding Clock
The diagram shows the branch that defines a Texas workflow: on receipt, information is either produced promptly, or — if the body intends to withhold — an Attorney General ruling must be requested within 10 business days, with a clarification request tolling the clock.
Because the toll restarts the count, the module records the effective receipt date the clock ran from — not merely the deadline — so the audit trail explains why a ruling request that looks late against the original request was in fact timely.
Step-by-Step Implementation
The module defines a business-day helper, a frozen result record, a state holiday set, and the deadline function with explicit tolling. The comments cite the governing PIA sections.
from __future__ import annotations
import json
import logging
from dataclasses import dataclass
from datetime import date, datetime, timedelta, timezone
class JsonAuditFormatter(logging.Formatter):
"""Emit one structured JSON object per audit event (NIST SP 800-53 AU-3)."""
def format(self, record: logging.LogRecord) -> str:
payload = {
"ts": datetime.now(timezone.utc).isoformat(),
"level": record.levelname,
"event": record.getMessage(),
}
for key in ("request_id", "statute", "effective_receipt", "deadline"):
if hasattr(record, key):
payload[key] = getattr(record, key)
return json.dumps(payload)
logger = logging.getLogger("pia_deadline")
logger.setLevel(logging.INFO)
_handler = logging.StreamHandler()
_handler.setFormatter(JsonAuditFormatter())
logger.addHandler(_handler)
# Texas skip-days for the PIA business-day count (2026 instances). Under Gov't Code
# ch. 552, the 10-day AG-ruling window is counted in business days, which exclude
# weekends and observed national/state holidays.
TX_STATE_HOLIDAYS_2026: frozenset[date] = frozenset({
date(2026, 1, 1), # New Year's Day
date(2026, 1, 19), # Dr. Martin Luther King Jr. Day
date(2026, 5, 25), # Memorial Day
date(2026, 6, 19), # Emancipation Day (Juneteenth)
date(2026, 7, 3), # Independence Day (observed)
date(2026, 9, 7), # Labor Day
date(2026, 11, 11), # Veterans Day
date(2026, 11, 26), # Thanksgiving Day
date(2026, 11, 27), # Friday after Thanksgiving
date(2026, 12, 25), # Christmas Day
})
@dataclass(frozen=True, slots=True)
class PiaDeadline:
"""Immutable record of one PIA Attorney-General ruling-request calculation."""
request_id: str
original_receipt: date
effective_receipt: date # equals original unless a clarification tolled it
statute: str
ag_ruling_due: date
tolled: bool
def add_business_days(start: date, n: int, holidays: frozenset[date]) -> date:
"""Add n business days, skipping weekends and holidays.
Tex. Gov't Code § 552.301 counts the AG-ruling window in business days; a day
is a business day only if it is a weekday and not an observed holiday.
"""
day = start
counted = 0
while counted < n:
day += timedelta(days=1)
if day.weekday() < 5 and day not in holidays:
counted += 1
return day
def pia_ag_ruling_deadline(
request_id: str,
received: date,
holidays: frozenset[date] = TX_STATE_HOLIDAYS_2026,
clarification_received: date | None = None,
) -> PiaDeadline:
"""Compute the deadline to request an Attorney General ruling to withhold.
Tex. Gov't Code § 552.301(b): to withhold information believed to be excepted,
the governmental body must request an AG ruling within 10 business days of
receiving the request. § 552.302: missing that window presumes the information
public. § 552.222: a request for clarification tolls the clock, and the request
is treated as received when the requester's clarification arrives.
"""
try:
if not isinstance(received, date):
raise TypeError("received must be a datetime.date")
# Tolling: the clock runs from the clarification date if one was sought.
effective = clarification_received or received
if effective < received:
raise ValueError("clarification date cannot predate the original request")
# § 552.301: 10 *business* days from the effective receipt date.
ag_ruling_due = add_business_days(effective, 10, holidays)
record = PiaDeadline(
request_id=request_id,
original_receipt=received,
effective_receipt=effective,
statute="Tex. Gov't Code § 552.301",
ag_ruling_due=ag_ruling_due,
tolled=clarification_received is not None,
)
logger.info(
"pia_deadline_computed",
extra={
"request_id": request_id,
"statute": record.statute,
"effective_receipt": effective.isoformat(),
"deadline": ag_ruling_due.isoformat(),
},
)
return record
except Exception:
# Fail loud: a miscomputed § 552.301 clock risks a forced disclosure under § 552.302.
logger.error("pia_deadline_failed", extra={"request_id": request_id})
raise
The record carries both the original and effective receipt dates so an auditor can see, at a glance, whether the clock was tolled and why the ruling-request deadline sits where it does.
Validation & Verification
Assert the business-day count and the tolling restart. A request received Monday, June 1, 2026, has its 10th business day on Monday, June 15; a clarification received Monday, June 8, restarts the count, which then crosses Emancipation Day (June 19) and lands on June 23.
if __name__ == "__main__":
base = pia_ag_ruling_deadline("TX-2026-0507", date(2026, 6, 1))
# 10 business days from Mon 2026-06-01, skipping two weekends, lands on 2026-06-15.
assert base.ag_ruling_due == date(2026, 6, 15)
assert base.tolled is False
tolled = pia_ag_ruling_deadline(
"TX-2026-0507", date(2026, 6, 1), clarification_received=date(2026, 6, 8)
)
# § 552.222: the clock runs from the clarification date, so 10 business days
# from Mon 2026-06-08 — skipping Emancipation Day 2026-06-19 — lands on 2026-06-23.
assert tolled.effective_receipt == date(2026, 6, 8)
assert tolled.ag_ruling_due == date(2026, 6, 23)
assert tolled.tolled is True
print("PIA deadline checks passed")
Because PiaDeadline is frozen, replaying a request during recovery reproduces the exact deadline and never double-counts the toll. Replay a corpus of historical requests, including some that span Emancipation Day and the Thanksgiving pair, and diff the results against a verified table before deploying. The resulting trail feeds the Audit Logging Architecture that a ruling review may later read.
Troubleshooting & Edge Cases
- Counting the AG-ruling window in calendar days. The § 552.301 window is business days; calendar-day math understates the deadline and can trigger a premature “missed” flag. Diagnosis: Texas deadlines matching a calendar-day jurisdiction like the California Public Records Act model. Fix: use the business-day helper and a reviewed holiday set.
- Ignoring the § 552.302 consequence. Treating a missed ruling request as a soft warning understates the stakes. Diagnosis: information withheld after the 10-business-day window without a compelling-reason analysis. Fix: gate withholding on a timely, logged ruling request and surface the § 552.302 presumption when the deadline passes.
- Losing the toll. Computing the deadline from the original receipt after a clarification overstates lateness. Diagnosis: a ruling request that looks late but was timely against the clarification date. Fix: record both receipt dates and run the clock from the effective one, exactly as the module does.
- A holiday missing from the set. A dropped Emancipation Day or day-after-Thanksgiving shortens the count. Diagnosis: a deadline one business day early. Fix: pin and review the holiday
frozensetyearly and assert coverage in tests. - Confusing the ruling request with production. The § 552.301 deadline governs asking the Attorney General, not producing records; production is the separate “promptly” standard of § 552.221. Fix: model the two obligations distinctly.
Compliance Verification Checklist
FAQ
What is the 10-business-day deadline under the Texas Public Information Act?
Under Gov’t Code § 552.301, when a governmental body wants to withhold information it believes is excepted from disclosure — and no prior determination covers it — the body must request an Attorney General ruling within 10 business days of receiving the request. The count excludes weekends and observed holidays. It is the pivotal Texas deadline because § 552.302 provides that missing it presumes the information public, so an accurate business-day calculation is directly tied to whether the body can lawfully withhold.
How does requesting clarification affect the deadline?
Section 552.222 lets a governmental body ask the requester to clarify an unclear request or narrow an overbroad one. When it does, the request is treated as received on the date the clarification arrives, which tolls the business-day clock and restarts the 10-day count from that later date. The module captures this by running the count from an effective_receipt date and flagging tolled, so the audit trail shows why a ruling request is timely even when it postdates the original request by more than 10 business days.
Is "promptly produce" a fixed number of days?
No. Section 552.221 requires a governmental body to produce public information “promptly” — as soon as possible under the circumstances — which is a reasonableness standard rather than a fixed count, so an automation tracks it as an obligation beginning at receipt rather than pinning it to a single date. The fixed, computable Texas clock is the § 552.301 window for requesting an Attorney General ruling to withhold, which is what this module calculates.
Related
- State Law Compliance Frameworks — the jurisdiction-rule layer this calculation plugs into
- Calculating California Public Records Act Deadlines — the calendar-day determination-window counterpart
- Calculating New York FOIL Deadlines — the 5-business-day acknowledgment counterpart
- Deadline Tracking & Escalation — consumes these deadlines to drive reminders and escalation
- Computing Business-Day FOIA Deadlines with Federal Holiday Calendars — the general business-day engine behind this count