Licensing Review
What these tasks are
Each task is a licensing-decision problem solved from a shared read-only data
service. The prompt names one or more target entities, the answer template
fixes the exact output schema and enum vocabulary, and environment_access.md
gives the base URL, an auth token, and the allowed endpoints. Your job is to
gather the relevant records, apply the governing policy/rule logic, and emit
only JSON that conforms to the answer template.
The decision logic is stable across tasks. What changes per task is: the
target IDs, the review/boundary date, and — critically — the exact enum codes
and keys the answer template allows. Never copy codes from one task into
another; always bind your findings to the vocabulary in the current
answer_template.json.
Three task families — detect first
Read the prompt and the answer template together, then classify:
| Family |
Prompt signals |
Answer template shape |
Playbook |
| A. Contractor batch |
"Licensing Examiner", "State Contractors Licensing Board", a batch/list of C-… application IDs |
application_decisions[] (per-app determination APPROVE/HOLD/DENY + deficiency_codes + required_actions + risk_tier + policy_impacted) plus a summary |
references/contractor_playbook.md |
| B. Liquor staff package |
"restricted liquor license", one L-… application + a LOC-… location |
single object: 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 |
references/liquor_playbook.md |
| C. Alcohol renewal queue |
"Alcohol Renewal Unit", "manual-review queue", AL-… license IDs, a release boundary date and target queue size |
queue[] (ranked) plus summary |
references/renewal_playbook.md |
Standard workflow
- Classify the family (table above).
- Parse the prompt for: target entity IDs, target location (family B),
review date (family A) or release boundary + queue size (family C), and the
<TASK_ENV_BASE_URL> placeholder.
- Read
answer_template.json fully. Extract the exact top-level keys,
per-item schema, the allowed enum values for every coded field, required
list length, ordering rules, and empty-value handling. This is your output
contract — see references/output_contract.md.
- Read
environment_access.md for the concrete base URL, the
X-Task-Token, and the allowed endpoint list. Use /api/sql only when a
token is provided and the endpoint is allowed.
- Fetch governing rules first. Always pull
/api/policies (families A & B)
or /api/renewal/rules (family C) and parse each row's details_json —
the numeric thresholds and boolean toggles that drive decisions live there.
Read them at runtime; do not hardcode threshold numbers.
- Fetch and join the records for each target (see
references/data_model.md
for endpoints ↔ SQL tables and join keys).
- Apply the family playbook to reach determinations, reading every
threshold from the policy/rule
details_json.
- Map findings to the template vocabulary — translate each underlying fact
to the specific allowed code in this template.
- Build the summary so it is internally consistent with the item-level
decisions (counts, high-risk lists, etc.).
- Emit only the JSON — correct keys, correct ordering, deduped lists,
empty arrays where nothing applies, exactly the target entities and length
required.
Data access in one place
- Endpoints return JSON arrays. The same data is queryable via
POST /api/sql
with body {"query": "SELECT …"} and header X-Task-Token: <token>.
- SQL is SELECT-only;
PRAGMA and sqlite_master are blocked; results
default to LIMIT 200 (use explicit LIMIT/COUNT/WHERE, or page).
- Table names are the underscored form of the endpoint path
(e.g.
/api/contractor/license-history → contractor_license_history).
- A ready generic client is in
scripts/query_env.py (reads base URL + token
from environment_access.md; exposes get(path) and sql(query)).
Full endpoint/table/field/join reference: references/data_model.md.
Rules that apply to every family
- Vocabulary is per-task. Two tasks in the same family use different code
sets (e.g. contractor deficiency
bond_cancelled vs no_active_bond). Emit
only codes present in the current template.
- Thresholds come from the environment, not memory. Match each entity to its
governing policy/rule and read
details_json.
- Filter by the field the rule names, not by look-alike labels. E.g. the
renewal boundary filters on
violation_date; a source_name like
post_boundary_feed is a distractor, not the filter.
- Applicant/self-reported assertions are not verification. Only trust a
correspondence/evidence item when the record marks it agency-verified/current.
- Output is JSON only — no prose, markdown, comments, citations, or keys
outside the template. Dates are
YYYY-MM-DD.
Common pitfalls
- Emitting a code that is valid in a sibling task but absent from the current
template's
allowed_values.
- Hardcoding a threshold (bond/insurance/experience minimum, boundary date)
instead of reading it from
details_json for the applicable rule.
- Treating a distractor source/theme (
post_boundary_feed, late renewal) as a
real signal.
- Summary counts that don't match the per-item determinations, or list fields
that aren't sorted/deduped as the template demands.
- Wrong list length or missing/extra target entities.
1---2name: licensing-review-33description: Produce structured JSON licensing-review decisions against a shared state licensing data service. Covers three recurring task families: (A) contractor application batch eligibility reviews, (B) restricted liquor-license staff packages, and (C) alcohol renewal manual-review queues. Use this whenever a prompt asks you to act as a licensing examiner / renewal-unit staffer, points you at the licensing environment endpoints (/api/policies, /api/contractor/*, /api/liquor/*, /api/alcohol/*, /api/renewal/rules, /api/sql), and asks for a JSON answer that must conform to an input/payloads/answer_template.json.4---56# Licensing Review78## What these tasks are910Each task is a licensing-decision problem solved from a shared read-only data11service. The prompt names one or more target entities, the answer template12fixes the exact output schema and enum vocabulary, and `environment_access.md`13gives the base URL, an auth token, and the allowed endpoints. Your job is to14gather the relevant records, apply the governing policy/rule logic, and emit15**only** JSON that conforms to the answer template.1617The decision *logic* is stable across tasks. What changes per task is: the18target IDs, the review/boundary date, and — critically — the **exact enum codes19and keys the answer template allows**. Never copy codes from one task into20another; always bind your findings to the vocabulary in the current21`answer_template.json`.2223## Three task families — detect first2425Read the prompt and the answer template together, then classify:2627| Family | Prompt signals | Answer template shape | Playbook |28|---|---|---|---|29| **A. Contractor batch** | "Licensing Examiner", "State Contractors Licensing Board", a batch/list of `C-…` application IDs | `application_decisions[]` (per-app `determination` APPROVE/HOLD/DENY + `deficiency_codes` + `required_actions` + `risk_tier` + `policy_impacted`) plus a `summary` | `references/contractor_playbook.md` |30| **B. Liquor staff package** | "restricted liquor license", one `L-…` application + a `LOC-…` location | single object: `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` | `references/liquor_playbook.md` |31| **C. Alcohol renewal queue** | "Alcohol Renewal Unit", "manual-review queue", `AL-…` license IDs, a **release boundary** date and target queue size | `queue[]` (ranked) plus `summary` | `references/renewal_playbook.md` |3233## Standard workflow34351. **Classify** the family (table above).362. **Parse the prompt** for: target entity IDs, target location (family B),37 review date (family A) or release boundary + queue size (family C), and the38 `<TASK_ENV_BASE_URL>` placeholder.393. **Read `answer_template.json` fully.** Extract the exact top-level keys,40 per-item schema, the allowed enum values for every coded field, required41 list length, ordering rules, and empty-value handling. This is your output42 contract — see `references/output_contract.md`.434. **Read `environment_access.md`** for the concrete base URL, the44 `X-Task-Token`, and the allowed endpoint list. Use `/api/sql` only when a45 token is provided and the endpoint is allowed.465. **Fetch governing rules first.** Always pull `/api/policies` (families A & B)47 or `/api/renewal/rules` (family C) and parse each row's `details_json` —48 the numeric thresholds and boolean toggles that drive decisions live there.49 **Read them at runtime; do not hardcode threshold numbers.**506. **Fetch and join the records** for each target (see `references/data_model.md`51 for endpoints ↔ SQL tables and join keys).527. **Apply the family playbook** to reach determinations, reading every53 threshold from the policy/rule `details_json`.548. **Map findings to the template vocabulary** — translate each underlying fact55 to the specific allowed code in *this* template.569. **Build the summary** so it is internally consistent with the item-level57 decisions (counts, high-risk lists, etc.).5810. **Emit only the JSON** — correct keys, correct ordering, deduped lists,59 empty arrays where nothing applies, exactly the target entities and length60 required.6162## Data access in one place6364- Endpoints return JSON arrays. The same data is queryable via `POST /api/sql`65 with body `{"query": "SELECT …"}` and header `X-Task-Token: <token>`.66- SQL is **SELECT-only**; `PRAGMA` and `sqlite_master` are blocked; results67 default to `LIMIT 200` (use explicit `LIMIT`/`COUNT`/`WHERE`, or page).68- Table names are the underscored form of the endpoint path69 (e.g. `/api/contractor/license-history` → `contractor_license_history`).70- A ready generic client is in `scripts/query_env.py` (reads base URL + token71 from `environment_access.md`; exposes `get(path)` and `sql(query)`).7273Full endpoint/table/field/join reference: `references/data_model.md`.7475## Rules that apply to every family7677- **Vocabulary is per-task.** Two tasks in the same family use *different* code78 sets (e.g. contractor deficiency `bond_cancelled` vs `no_active_bond`). Emit79 only codes present in the current template.80- **Thresholds come from the environment**, not memory. Match each entity to its81 governing policy/rule and read `details_json`.82- **Filter by the field the rule names**, not by look-alike labels. E.g. the83 renewal boundary filters on `violation_date`; a `source_name` like84 `post_boundary_feed` is a distractor, not the filter.85- **Applicant/self-reported assertions are not verification.** Only trust a86 correspondence/evidence item when the record marks it agency-verified/current.87- **Output is JSON only** — no prose, markdown, comments, citations, or keys88 outside the template. Dates are `YYYY-MM-DD`.8990## Common pitfalls9192- Emitting a code that is valid in a sibling task but absent from the current93 template's `allowed_values`.94- Hardcoding a threshold (bond/insurance/experience minimum, boundary date)95 instead of reading it from `details_json` for the *applicable* rule.96- Treating a distractor source/theme (`post_boundary_feed`, `late renewal`) as a97 real signal.98- Summary counts that don't match the per-item determinations, or list fields99 that aren't sorted/deduped as the template demands.100- Wrong list length or missing/extra target entities.