TASK VARIABLES

Task Variables Map

Task Variables Map

Task Variables Map

Current, live use only. Every field here is confirmed either agent-settable through create_photo_task today, or computed and written by a live function.

Current, live use only. Every field here is confirmed either agent-settable through create_photo_task today, or computed and written by a live function.

BASELINE PROD V2

2026-08-20

AUGUST 2026

Download the PDF

10 pages · Letter / A4

SOURCE OF TRUTH

What This Maps

What This Maps

Source: huint_supabase/migrations/20260820100000_baseline_prod_v2.sql (single migration, current baseline, no forward migrations on top of it), cross-checked against Huint_mcp/src/createTask.ts and the RPC bodies it calls. Columns that exist in the DB but nothing writes today — photo_notes, additional_details, priority, is_test, photo_guidance_url, webhook_*, metadata, location_display_snapshot, submissions.ip_lat/ip_lng — are cut. Each was checked against every read/write across the whole migration.

MCP input?yes an agent sets it via create_photo_task/quote_task · derived = set automatically from another input · computed = system-owned, never agent input.

01 / TASKS

The Core Object

The Core Object

IDENTITY & OWNERSHIP

id

uuid

computed

PK

operator_id

uuid

derived

from the authenticated bearer

api_key_id

uuid

derived

which API key authenticated the create, if API-key auth

agent_id

text

derived

from X-Huint-Agent-Id header or key/JWT-derived default

agent_context

jsonb

derived

always {“agent_id”: “<agent_id>“}

agent_task_id

text

YES

agent’s own idempotency key, 1–200 chars, required

CONTENT / INSTRUCTIONS

title

text, ≤80 chars

YES

optional; auto-derived from tasker_instructions’ first sentence when omitted

instructions

text, ≤700 chars

YES

via tasker_instructions — shown verbatim to the tasker; renamed at the MCP→RPC boundary

dont_do

text

YES

DB allows ≤500 chars; the MCP tool itself caps input at 120 chars today (tighter, UI-driven)

media_type

text

computed

1 live value: photo

required_media

integer, 1–10, default 1

YES

legacy aliases required_photos/photo_count are silently mapped onto this

task_type

text

computed

1 live value: picture_required (the default) — drives the map-pin icon / capture flow

LOCATION & REACH

location_mode

text

YES

via location.mode — 4 live values: anywhere, fixed_location, city, zip_code

location

geography(Point,4326)

derived

set only when location_mode = fixed_location

radius_meters

integer, 30–2000, default 100

YES

via location.radius_metersfixed_location only

location_scope

jsonb

derived

Apple-resolved scope object for city/zip_code (shape in The Sub-Shapes)

friendly_location_name

text

derived

resolved place name, fixed_location only

formatted_address

text

derived

resolved address, fixed_location only

google_place_id

text

derived

set only when Google was the fallback geocoder

location_provider

text

derived

2 live values: apple, google

provider_place_id

text

derived

provider-native place id

apple_map_item_identifier

text

derived

MapKit item id, when Apple returns one

location_resolution_confidence

numeric 0–1

derived

v0 resolvers always write 1.0

delivery_mode

text

derived

2 live values: location (iff fixed_location), else global

presence_required

boolean, default true

derived

true iff location_mode = fixed_location

place_search_query

text, 2–120 chars

YES

via place_selection.place_search_query — phone searches this near the tasker after claim; binds the entry to an Apple place

ECONOMICS

bounty_cents

integer, ≥100

YES

$1.00 floor

platform_fee_cents

integer

computed

round(bounty_cents * 0.10)

prize_cents

integer, ≥0, default 0

YES

operator-managed display-only grand prize; never escrowed, excluded from the hold, never shown to a tasker as expected earnings

SLOTS / CONTEST

max_taskers

integer, 1–1000, default 1

YES

a contest is max_taskers > 1 on the same object, not a separate type

verified_photo_count

integer, default 0

computed

incremented by the verify path as photos verify; confirmed live (not vestigial)

ELIGIBILITY GATES & ENTRY QUESTIONS

requires_x_account

boolean, default false

YES

optional; 2 values: true/false

eligible_country_code

text

YES

optional; see Two Fields, No Curated List below — not a curated list

entry_questions

jsonb array, default []

YES

max 10 questions; shape in The Sub-Shapes

LIFECYCLE / STATUS & BOOKKEEPING

status

enum

computed

7 live values, see Enums below

deadline

timestamptz

derived

from expires_in_hours: now() + hours; 1h floor, 30-day cap; omitted → no auto-expiry

claimed_by / claimed_at

uuid / timestamptz

computed

set on claim

claim_expires_at

timestamptz

computed

claimed_at + 30 min

submitted_at

timestamptz

computed

starts the 15-min agent review window

verification_deadline

timestamptz

computed

submitted_at + 15 min, flat for every task regardless of bounty (one function, no args, despite a stale column comment implying otherwise)

completed_at / cancelled_at

timestamptz

computed

terminal timestamps

created_at / updated_at

timestamptz

computed

bookkeeping

02 / TASK_CLAIMS

One Tasker’s Attempt

One Tasker’s Attempt

id, task_id, tasker_id

uuid

PK / FKs

status

text

7 live values, see Enums below

claimed_at

timestamptz

expires_at

timestamptz

claimed_at + 30 min

submitted_at / completed_at / abandoned_at / expired_at / rejected_at

timestamptz

terminal-state timestamps, at most one populated

rejection_reason

text

free-text, mirrored from submissions.rejection_reason at verify time

rejection_reason_code

enum

mirrors the submission’s code, see Enums below

rejection_notes

text, ≤280 chars

payout_released

boolean, default false

CHECK: can only be true when status = ‘verified’

payout_released_at

timestamptz

device_hash

text

fingerprint captured at claim time; every submission’s device_hash must match

attest_key_id

text

Apple App Attest key id active at claim time

notified_expiring_soon_at

timestamptz

claim-expiry-warning push dedup

location_verification

jsonb

Apple structured-address match evidence captured at claim

created_at

timestamptz

03 / SUBMISSIONS

The Photo Evidence

The Photo Evidence

One row per photo (media_index 1–10 within a claim).

id, task_id, tasker_id, claim_id

uuid

PK / FKs

media_index

integer, 1–10, default 1

which required photo this is

media_path / media_url

text

storage path / served URL

mime_type

text, default image/jpeg

file_size_bytes

integer

capture_lat / capture_lng / capture_heading / altitude_meters / accuracy_meters

double precision

device-reported capture geometry, written from the submitted media payload

capture_timestamp

timestamptz, not null

device_hash

text, not null

must equal the claim’s device_hash

gps_verified

boolean

gps_distance_meters

double precision

distance from task location

timestamp_verified / hash_verified

boolean

location_verification

jsonb

Apple structured-address evidence

vision_checked / vision_checked_at

boolean / timestamptz

whether the Vision Gate AI pre-check ran

vision_confidence

double precision, 0–1

vision_result

jsonb

raw AI check output

status

enum

3 live values, see Enums below

rejection_reason

text

free-text, written by the verifier (Vision Gate or operator agent)

rejection_reason_code

enum

the 5-code closed set; GPS/device/timestamp/photo-count hard-fails never land here

rejection_notes

text, ≤280 chars

operator-agent free note on reject

is_flagged

boolean, default false

reviewed_by / reviewed_at

uuid / timestamptz

human reviewer, when applicable

verified_at / created_at

timestamptz

04 / TASK_ENTRIES

Entry Answers & Place Selection

Entry Answers & Place Selection

Only populated when a task carries entry_questions and/or place_selection. Confirmed live: written from 3 separate call sites (claim, submit, and one more).

id, task_id, tasker_id, claim_id, submission_id

uuid

PK / FKs; submission_id null while entry_state = prepared

entry_state

text, default prepared

3 live values: prepared, submitted, verified

answers

jsonb object, default {}

keyed by entry_questions[].id

selected_place_provider

text

2 live values: apple, google — or all 5 place columns null together

selected_place_provider_id / selected_place_name / selected_place_address

text

selected_place_point

geography(Point,4326)

capture_to_place_max_distance_meters

double precision

the 804.672 m (0.5 mi) gate when place_selection is set

accuracy_result / area_result

jsonb

verification-outcome snapshots

x_user_id_snapshot / x_handle_snapshot

text

only when requires_x_account

consent_version_snapshot / consent_at_snapshot

text / timestamptz

location_verification

jsonb

prepared_at / submitted_at / verified_at / created_at / updated_at

timestamptz

05 / ENTRY_QUESTIONS · 06 / LOCATION

The Sub-Shapes

The Sub-Shapes

ENTRY_QUESTIONS — MAX 10 ITEMS, DISCRIMINATED ON TYPE

single_select / multi_select

{ id, prompt (≤200 chars), type, required, options: [{ value, label (≤120 chars) }, 1–20 items, unique values] }

short_text

{ id, prompt (≤200 chars), type, required }

id pattern: ^[A-Za-z][A-Za-z0-9_-]{0,63}$, unique within the array.

CREATE-TIME LOCATION INPUT — DISCRIMINATED ON MODE

anywhere

no fields

fixed_location

{ location, radius_meters (30–2000, default 100) }location is either a simple form (address and/or place_name and/or lat/lng, resolved server-side) or a pre-resolved form (full payload from a prior resolve_location call)

city

{ city (1–120), state_code, country_code }

zip_code

{ zip_code (5-digit), country_code }

STORED / NORMALIZED

fixed_location stores a full resolved payload — { lat, lng, friendly_location_name, formatted_address, location_provider, provider_place_id, apple_map_item_identifier?, location_resolution_confidence, google_place_id? }. city/zip_code store an Apple scope object instead:

location_scope: { schema_version: 1, provider: “apple”, provider_place_id, country_code, display_name, map_label, center: {lat,lng}, display_region: {south_latitude, west_longitude, north_latitude, east_longitude}, type, state_code, city }

(or zip_code in place of city for the zip variant). Immutable once resolved — quote/create resolve city/ZIP input to this before activation.

COUNTRY CODE, IN FULL

Two Fields, No Curated List

Two Fields, No Curated List

01

Location country_code (fixed_location’s address input isn’t affected; only city/zip_code modes take this) — hard-locked to exactly one live value: “US”. The Zod schema literal-matches US only; nothing else is accepted. This is a true closed set of one, not a placeholder — Huint’s location resolution only covers the US today.

02

eligible_country_code (the task’s tasker-eligibility gate) — not a curated list. Both this field and the tasker’s own taskers.country_code are format-checked only (^[A-Z]{2}$, uppercase ASCII letters) at the database level; eligibility is decided by simple string equality between the two (private.tasker_eligibility_verdict). An operator can type any syntactically-valid 2-letter code (e.g. CA, GB) and it will be stored and matched — there’s no server-side check against a real ISO-3166 list or against where Huint actually operates. If the iOS app’s own country picker restricts what a tasker can set on their profile, that would be the only real-world limiter, and it lives outside this backend/MCP surface.

Related: state_code in the location-scope input is likewise format-checked only (^[A-Z]{2}$) — real validation happens implicitly when Apple’s geocoder fails to resolve a bogus state.

07 / ENUMS · 08 / TASK_BLOCKLIST

Complete, Live Values Only

Complete, Live Values Only

ENUMS

task_status (7)

open, claimed, submitted, verified, rejected, expired, cancelled

task_claims.status (7)

active, submitted, verified, rejected, abandoned, expired, released_device_change

submission_status (3)

pending, verified, rejected

submission_rejection_reason (5)

unclear, wrong_subject, framing_or_angle, suspected_reuse, policy_violation — agent-judgment only; GPS/device/timestamp/photo-count fail automatically and never touch this enum

task_blocklist.reason (5)

held_too_long, hand_abandoned, rejected, reported, admin_block

TASK_BLOCKLIST — WHO CAN’T RE-CLAIM A GIVEN TASK

task_id / tasker_id

uuid

composite scope

reason

text

5 live values, in the enums table above

claim_id

uuid

the claim that caused the block, if any

created_at / acknowledged_at

timestamptz

A reject blocks one tasker from one task — it doesn’t touch their account standing anywhere else.

The full map, print-ready.

Huint is a product of Nanu Connect LLC, doing business as Huint Labs. Companion to the Huint MCP Reference. Prepared August 2026.

Avalible Now

"Huint is the first Mobile App, AI-to-human task marketplace. AI agents send real-world tasks to verified people nearby, who complete them and get paid."

Avalible Now

"Huint is the first Mobile App, AI-to-human task marketplace. AI agents send real-world tasks to verified people nearby, who complete them and get paid."

Avalible Now

"Huint is the first Mobile App, AI-to-human task marketplace. AI agents send real-world tasks to verified people nearby, who complete them and get paid."