Licensing-review structured decisions
You are given a licensing-review prompt plus an answer_template.json. Fetch records
from a shared licensing environment, apply the policy-driven rules, and return only a
JSON object that conforms exactly to the template. See reference/data_model.md for
full endpoint schemas, policy fields, and code-mapping tables.
0. Golden rules (apply to every task)
- The
answer_template.json is the contract. Output exactly its top-level keys and
item keys, use only enum values from its allowed_values, honour every ordering
note, and include nothing else — no prose, markdown, comments, citations, or extra
keys. Enum vocabularies differ between tasks; never carry codes over from another task.
- Read
environment_access.md for network access — base URL and the
X-Task-Token for POST /api/sql. Do not hard-code them.
- Filter hard to the prompt's targets. The environment is one shared pool holding
many unrelated rows (
*-DIS-*, *-TE2-*, other locations, INC-DIS-*, EV-DIS-*).
Work only the exact application/location/license IDs the prompt names.
- Pick the current record, drop the historical twin. Entities carry a current row
(
...-A, active, "Current …", controls_json.active=true) plus historical
distractors (...-OLD, cancelled/expired, active=false, past expires,
post-boundary -LATE). Use the current one for eligibility; use history only where a
rule explicitly needs it (suspension, successor, excluded lists).
- Empty list, not null/omit, when nothing applies. Deduplicate code lists.
Dates are
YYYY-MM-DD.
- Make the summary self-consistent with the item-level decisions (counts sum to the
required length; id lists are derived from the items).
- Parse from the prompt: target IDs, location/license IDs, the review/boundary date,
the queue/target size, and the license class. Confirm your item count equals the
template's
required_length/length.
1. Get the data
Prefer POST /api/sql (send {"query":"SELECT ..."} with the X-Task-Token header) to
filter and join straight to the target IDs — table name = endpoint path with /→_
(e.g. contractor_applications), results cap at 200 rows, SELECT-only. GET endpoints
return the full array if you'd rather filter in code. Always parse each policy's
details_json (it is a JSON string). Identify the task family from the endpoints/prompt.
2. Family A — Contractor batch eligibility review
Endpoints: policies + contractor/{applications,bonds,insurance,license-history, violations,correspondence,inspections}. Output: application_decisions[]
(application_id, determination, deficiency_codes[], required_actions[], risk_tier, policy_impacted) + summary.
For each target application:
- Map
(trade, requested_class) → its contractor policy standard; read
minimum_bond, minimum_insurance, minimum_years_experience,
required_endorsement, serious_open_violation_blocks.
- Bond (current =
active, cancel_date null, effective by the review date):
none current → bond_cancelled/no_active_bond; amount < minimum → bond_shortfall.
- Insurance (current =
active, expiration_date > review date): pending →
insurance_pending/insurance_not_current; expired/lapsed → insurance_expired;
amount < minimum → insurance_shortfall.
- Experience < minimum →
experience_shortfall.
- Endorsement required and status
missing/pending → endorsement_missing/
endorsement_pending/endorsement_not_verified (verified/not_required = ok; do
not treat as verified on the strength of unverified correspondence).
- License history
suspended → active_suspension (hard blocker).
- Violations (by
related_application_id): open + serious →
open_serious_violation/unresolved_serious_complaint (hard blocker when
serious_open_violation_blocks); open minor/medium → open_minor_violation.
- Inspections:
DOC_GAP → inspection_doc_gap; SAFETY_RECHECK →
inspection_safety_recheck (only if in this template's vocab).
- Correspondence:
verified_by_agency=0 or a "stale/predates" note → add its id to
stale_or_unverified_correspondence_ids.
required_actions pair 1:1 with the deficiencies (see the reference table).
Determination: hard blocker (active suspension / open serious violation) → most
restrictive posture (DENY, or HOLD escalated to board review) per the policy flag;
any fixable coverage gap → HOLD; clean file → APPROVE. risk_tier: hard
blockers/multiple serious gaps → high; a fixable gap or two → medium; clean/trivial →
low. policy_impacted = the deficiency exists only under the current 2025 standard
vs. POL-CON-LEGACY (specialty-endorsement now required; or bond short only after the
$10k legacy reduction). Summary: approve/hold/deny_count (sum = count),
high_risk_application_ids, policy_impacted_application_ids,
stale_or_unverified_correspondence_ids — each sorted per the template.
3. Family B — Restricted liquor-license staff package
Endpoints: policies + liquor/{applications,settlements,privileges,incidents, site-evidence}. One target application_id/location_id. Output keys:
recommended_posture, same_premises_basis_applies, covered_risk_codes, verification_gap_codes, standard_obligation_codes, location_specific_control_codes, first_90_day_plan, escalation_trigger_codes (+ application_id).
standard_obligation_codes = liquor_privileges for this license_class where
standard_required=1 (ordinary obligations — kept separate from controls).
location_specific_control_codes = the controls arrays of settlements at this
location whose controls_json.active=true (current, not expired).
same_premises_basis_applies = an active settlement at the location has
basis_code=SAME_PREMISES (historic/inactive ones do not count).
covered_risk_codes = risk bases addressed by those current active controls.
verification_gap_codes = from current site-evidence with status
missing/stale/conflicting, open incidents, and missing tax/neighbor items — map
evidence_code+status (and open TAX_HOLD/late-night context) to the template's gap
codes (see reference table). Only current evidence counts.
first_90_day_plan = {check_code, timing} objects pairing the identified gaps and
controls with first_30_days (urgent verification) → days_31_60 → days_61_90
(ongoing monitoring); dedupe pairs; order per template (by check_code, or operational
sequence).
escalation_trigger_codes = the template's triggers for the covered risks / controls
that could fail.
recommended_posture: unresolved major incident / board-review trigger / hard
disqualifier → deny; open verification gaps remain → request_follow_up; controls in
place and gaps minor/none → issue_restricted.
4. Family C — Alcohol renewal manual-review queue
Endpoints: alcohol/{licensees,violations} + renewal/rules (+ SQL). Output: queue[]
of the target size (rank, license_no, facility_name, violation_count, most_recent_violation_date, matched_violation_ids[], match_confidence, risk_tier, next_step_label) + summary.
- Take the boundary date and queue size from the prompt; find the matching
renewal_rules row (release_boundary).
- Per target license, match
alcohol_violations by license_no; keep only
violation_date <= boundary. Post-boundary rows (post_boundary_feed / -LATE) are
distractors → post_boundary_violation_ids_excluded.
violation_count = matched pre-boundary count; most_recent_violation_date = max of
those; matched_violation_ids sorted by (violation_date asc, violation_id asc).
match_confidence: exact (direct license match), uncertain (successor_to set),
close_address (matched by address, not exact license). Inactive predecessor permits
(active=0) are not queue rows — they only inform a successor's uncertain history.
risk_tier from severity/count/unpaid fines/alert flags; next_step_label =
manual_fine_check (unpaid fine_balance>0), manual_ALERT_check (alert_flag=1),
board_review (serious/major or unpaid-fine hold), additional_record_check
(close/uncertain match).
- Rank
1..N with no gaps (descending risk/severity/recency); queue length = target
size exactly. Summary: queue_size, boundary_date,
post_boundary_violation_ids_excluded (by violation_id),
close_or_uncertain_match_license_numbers, board_review_license_numbers — sorted.
5. Finish
Validate against the template: exact keys, allowed enum values, orderings, list dedupe,
empty-list handling, self-consistent summary, item count. Emit the single JSON object as
the answer (write it to the template's response_file if one is named, e.g.
answer.json); output nothing else.
1---2name: licensing-review-decisions3description: Produce structured JSON decisions for State licensing-board review tasks that read from a shared licensing-environment API and must conform exactly to a provided answer_template.json. Covers the three recurring task families: (A) contractor batch eligibility review, (B) restricted liquor-license staff package, (C) alcohol renewal manual-review queue. Use whenever a prompt casts you as a licensing examiner / renewal or staff reviewer, references a `<TASK_ENV_BASE_URL>` with `/api/...` endpoints, and asks for JSON matching `input/payloads/answer_template.json`.4---56# Licensing-review structured decisions78You are given a licensing-review prompt plus an `answer_template.json`. Fetch records9from a shared licensing environment, apply the policy-driven rules, and return **only** a10JSON object that conforms exactly to the template. See `reference/data_model.md` for11full endpoint schemas, policy fields, and code-mapping tables.1213## 0. Golden rules (apply to every task)14151. **The `answer_template.json` is the contract.** Output exactly its top-level keys and16 item keys, use only enum values from its `allowed_values`, honour every `ordering`17 note, and include nothing else — no prose, markdown, comments, citations, or extra18 keys. Enum vocabularies differ between tasks; never carry codes over from another task.192. **Read `environment_access.md` for network access** — base URL and the20 `X-Task-Token` for `POST /api/sql`. Do not hard-code them.213. **Filter hard to the prompt's targets.** The environment is one shared pool holding22 many unrelated rows (`*-DIS-*`, `*-TE2-*`, other locations, `INC-DIS-*`, `EV-DIS-*`).23 Work only the exact application/location/license IDs the prompt names.244. **Pick the current record, drop the historical twin.** Entities carry a current row25 (`...-A`, `active`, "Current …", `controls_json.active=true`) plus historical26 distractors (`...-OLD`, `cancelled`/`expired`, `active=false`, past `expires`,27 post-boundary `-LATE`). Use the current one for eligibility; use history only where a28 rule explicitly needs it (suspension, successor, excluded lists).295. **Empty list, not null/omit,** when nothing applies. **Deduplicate** code lists.30 Dates are `YYYY-MM-DD`.316. **Make the summary self-consistent** with the item-level decisions (counts sum to the32 required length; id lists are derived from the items).337. Parse from the prompt: target IDs, location/license IDs, the **review/boundary date**,34 the **queue/target size**, and the license class. Confirm your item count equals the35 template's `required_length`/`length`.3637## 1. Get the data3839Prefer `POST /api/sql` (send `{"query":"SELECT ..."}` with the `X-Task-Token` header) to40filter and join straight to the target IDs — table name = endpoint path with `/`→`_`41(e.g. `contractor_applications`), results cap at 200 rows, `SELECT`-only. GET endpoints42return the full array if you'd rather filter in code. Always parse each policy's43`details_json` (it is a JSON string). Identify the task family from the endpoints/prompt.4445## 2. Family A — Contractor batch eligibility review4647Endpoints: `policies` + `contractor/{applications,bonds,insurance,license-history,48violations,correspondence,inspections}`. Output: `application_decisions[]`49(`application_id, determination, deficiency_codes[], required_actions[], risk_tier,50policy_impacted`) + `summary`.5152For each target application:531. Map `(trade, requested_class)` → its contractor policy standard; read54 `minimum_bond`, `minimum_insurance`, `minimum_years_experience`,55 `required_endorsement`, `serious_open_violation_blocks`.562. **Bond** (current = `active`, `cancel_date` null, effective by the review date):57 none current → `bond_cancelled`/`no_active_bond`; amount < minimum → `bond_shortfall`.583. **Insurance** (current = `active`, `expiration_date` > review date): `pending` →59 `insurance_pending`/`insurance_not_current`; expired/lapsed → `insurance_expired`;60 amount < minimum → `insurance_shortfall`.614. **Experience** < minimum → `experience_shortfall`.625. **Endorsement** required and status `missing`/`pending` → `endorsement_missing`/63 `endorsement_pending`/`endorsement_not_verified` (`verified`/`not_required` = ok; do64 not treat as verified on the strength of unverified correspondence).656. **License history** `suspended` → `active_suspension` (hard blocker).667. **Violations** (by `related_application_id`): open + serious →67 `open_serious_violation`/`unresolved_serious_complaint` (hard blocker when68 `serious_open_violation_blocks`); open minor/medium → `open_minor_violation`.698. **Inspections**: `DOC_GAP` → `inspection_doc_gap`; `SAFETY_RECHECK` →70 `inspection_safety_recheck` (only if in this template's vocab).719. **Correspondence**: `verified_by_agency=0` or a "stale/predates" note → add its id to72 `stale_or_unverified_correspondence_ids`.7374`required_actions` pair 1:1 with the deficiencies (see the reference table).75**Determination**: hard blocker (active suspension / open serious violation) → most76restrictive posture (`DENY`, or `HOLD` escalated to board review) per the policy flag;77any fixable coverage gap → `HOLD`; clean file → `APPROVE`. **`risk_tier`**: hard78blockers/multiple serious gaps → `high`; a fixable gap or two → `medium`; clean/trivial →79`low`. **`policy_impacted`** = the deficiency exists only under the current 2025 standard80vs. `POL-CON-LEGACY` (specialty-endorsement now required; or bond short only after the81$10k legacy reduction). Summary: `approve/hold/deny_count` (sum = count),82`high_risk_application_ids`, `policy_impacted_application_ids`,83`stale_or_unverified_correspondence_ids` — each sorted per the template.8485## 3. Family B — Restricted liquor-license staff package8687Endpoints: `policies` + `liquor/{applications,settlements,privileges,incidents,88site-evidence}`. One target `application_id`/`location_id`. Output keys:89`recommended_posture, same_premises_basis_applies, covered_risk_codes,90verification_gap_codes, standard_obligation_codes, location_specific_control_codes,91first_90_day_plan, escalation_trigger_codes` (+ `application_id`).9293- **`standard_obligation_codes`** = `liquor_privileges` for this `license_class` where94 `standard_required=1` (ordinary obligations — kept separate from controls).95- **`location_specific_control_codes`** = the `controls` arrays of settlements at this96 location whose `controls_json.active=true` (current, not expired).97- **`same_premises_basis_applies`** = an active settlement at the location has98 `basis_code=SAME_PREMISES` (historic/inactive ones do not count).99- **`covered_risk_codes`** = risk bases addressed by those current active controls.100- **`verification_gap_codes`** = from **current** `site-evidence` with status101 `missing`/`stale`/`conflicting`, open incidents, and missing tax/neighbor items — map102 `evidence_code`+`status` (and open TAX_HOLD/late-night context) to the template's gap103 codes (see reference table). Only current evidence counts.104- **`first_90_day_plan`** = `{check_code, timing}` objects pairing the identified gaps and105 controls with `first_30_days` (urgent verification) → `days_31_60` → `days_61_90`106 (ongoing monitoring); dedupe pairs; order per template (by `check_code`, or operational107 sequence).108- **`escalation_trigger_codes`** = the template's triggers for the covered risks / controls109 that could fail.110- **`recommended_posture`**: unresolved major incident / board-review trigger / hard111 disqualifier → `deny`; open verification gaps remain → `request_follow_up`; controls in112 place and gaps minor/none → `issue_restricted`.113114## 4. Family C — Alcohol renewal manual-review queue115116Endpoints: `alcohol/{licensees,violations}` + `renewal/rules` (+ SQL). Output: `queue[]`117of the target size (`rank, license_no, facility_name, violation_count,118most_recent_violation_date, matched_violation_ids[], match_confidence, risk_tier,119next_step_label`) + `summary`.1201211. Take the boundary date and queue size from the prompt; find the matching122 `renewal_rules` row (`release_boundary`).1232. Per target license, match `alcohol_violations` by `license_no`; keep only124 `violation_date <= boundary`. Post-boundary rows (`post_boundary_feed` / `-LATE`) are125 distractors → `post_boundary_violation_ids_excluded`.1263. `violation_count` = matched pre-boundary count; `most_recent_violation_date` = max of127 those; `matched_violation_ids` sorted by (`violation_date` asc, `violation_id` asc).1284. `match_confidence`: `exact` (direct license match), `uncertain` (`successor_to` set),129 `close_address` (matched by address, not exact license). Inactive predecessor permits130 (`active=0`) are not queue rows — they only inform a successor's `uncertain` history.1315. `risk_tier` from severity/count/unpaid fines/alert flags; `next_step_label` =132 `manual_fine_check` (unpaid `fine_balance>0`), `manual_ALERT_check` (`alert_flag=1`),133 `board_review` (serious/major or unpaid-fine hold), `additional_record_check`134 (close/uncertain match).1356. Rank `1..N` with no gaps (descending risk/severity/recency); queue length = target136 size exactly. Summary: `queue_size`, `boundary_date`,137 `post_boundary_violation_ids_excluded` (by `violation_id`),138 `close_or_uncertain_match_license_numbers`, `board_review_license_numbers` — sorted.139140## 5. Finish141142Validate against the template: exact keys, allowed enum values, orderings, list dedupe,143empty-list handling, self-consistent summary, item count. Emit the single JSON object as144the answer (write it to the template's `response_file` if one is named, e.g.145`answer.json`); output nothing else.