What this tab is for: a PlanOmatic admin assigns people to roles and decides which tabs each role can see, across BOTH agent boards. Roles are fully configurable here — create, rename, delete, and re-grant. Access is enforced on the server per role; hiding a tab in the UI is not access control.
Roles & page accessi
Fully configurable. Add a role, rename or delete one, and tick to grant a page. Roles are referenced internally by a stable ID, so a rename only changes the label.
GET/api/roles · /api/pages
CRUDPOST /api/roles · PUT /api/roles/{role_id} · DELETE /api/roles/{role_id}
GRANTGET/PUT /api/roles/{role_id}/tabs (stable ID, never a name)
Sourceroles, role_tab_grants (config)
Effectserver-side gates each route per role, every request, FAIL-CLOSED
Statepending
Peoplei
Add a user, assign a role, or deactivate. Access follows from the assigned role.
GET/api/users
CRUDPOST /api/users · PUT /api/users/{id}/role · POST /api/users/{id}/deactivate
Sourceusers, roles (config)
Effectsets the user's role; tab access derives from the grants
Statepending
What this tab is for: how the agent is performing — how much it processed, how good its QA calls turned out to be, and where it needs tuning. Everything here is read-only.
Agent verdict (cf 73) versus the operator's final action (cf 70). Green cells are agreement; red cells are the misses to watch.
GET/api/metrics/calibration?window=
Sourceqa_results.cf73 ⋈ jobs.cf70 (Order cf 2)
Effectrenders matrix + derived rates
Statepending
Lifecycle state (cf 70)i
Current distribution across the Floor Plan Status values.
GET/api/jobs?group=fp_status
Sourcejobs.cf70
Effectrenders counts
Statepending
What this tab is for: the settings that change how the agent behaves. A control marked not wired below is audited and confirmed inert (ROUTING 157): the round-trip may succeed, but no code the agent runs reads it back, so editing it changes nothing. Every other control here takes effect on the agent's next run and is the live source of truth, not just this screen.
Sourcenone; no config row exists under any of these three names (ROUTING 157 audit)
EffectNOT WIRED; see notice below
Statepending
Matching & timeoutsi
The address bridge and the two watchdogs. The matcher is deterministic: house number + street name must agree after normalization. There is no similarity score and no confidence threshold — the normalization tolerance table is the only matching tunable.
GET/PUT/api/controls/{address_normalization_tolerance NOT WIRED, timeout_hours NOT WIRED, marked_addressed_return_hours}
Sourcemarked_addressed_return_hours only → escalations view bucketing (§9a); the other two resolve no config row (ROUTING 157 audit)
Effectmarked_addressed_return_hours moves which HITL bucket an item shows in NOW, but not the agent's own automatic revert timer, which is separately configured; the other two controls are not wired
Statepending
QA check severity & enablementi
Set each check to Fail (marks the floorplan failed) or Review (sends it to a person), or switch it off. Human-only checks always go to a person — the agent can't judge them from the image — so their severity is locked at Review.
What this section is for: stop or start the agent's entire workflow. "Off" means the poller takes no new work, no Gmail is consumed, no vision spend and no PlanoQ write occurs, and in-flight work finishes its current unit before stopping. The webhook receiver keeps recording regardless -- off means the agent takes no action, not that it goes deaf. On resumption the backlog is processed, not skipped.
Agent run statei
Stopping and starting are each a deliberate second act: press once to arm, press again to confirm. A stray click, refresh or navigation cannot throw the switch.
Loading…
GET/api/run-state
PUT/api/run-state {enabled}
Sourceconfig_params (agent.run_state.enabled)
Effectthe agent's poller/extraction cycle reads this same key and refuses new work while it is false
Statepending
Change historyi
Who changed the run state, when, and to what. Newest first.
GET/api/run-state/history
Sourceaction_log (auth_agent_run_state_change)
Effectread-only; the audit row this tab's toggle already writes
Statepending
What this tab is for: every floorplan-eligible PlanoQ job as a thin line item with status and a link out. Read-only: nothing here writes to PlanoQ or the agent's own store. Click a job's issue number to open it in PlanoQ.
Issue ID
Address
Card status
Lifecycle
Updated
GET/api/jobs
Sourcejobs, joined with the agent-store fp_status projection
Effectrenders the real job list; PlanoQ link built client-side from issue_id, no write of any kind
Statepending
What this tab is for: one place to see everything the agent couldn't finish on its own, centralized across PlanOq and Zillow 3D. This board is read-only toward PlanOq — your team keeps working in PlanOq and the Zillow 3D dashboard exactly as today, and nothing here writes to PlanOq. Most items clear themselves once the agent sees the real status change. A tour with no address cannot: no signal will ever arrive for it, so it waits for a person.
How an item moves:Active→ a user taps Mark addressed →Marked addressed→ agent sees the real status change →Resolved· or after the configured window with no real resolution, it drops back to Active (only the agent confirms Resolved)
Issue queuei
Read-only toward PlanOq. Link out to do the actual work in PlanOq or Zillow 3D; the board updates itself when the status changes.
MARKPOST /api/escalations/{id}/addressed · POST /api/escalations/{id}/active — agent store ONLY (never PlanOq)
Sourcetour_items, jobs.cf70, qa_results — derived, read-only; re-derived from PlanOq saves + Zillow emails via receiver
Effectself-clears on status change; addressed auto-returns after marked_addressed_return_hours; agent sets Resolved; NO PlanOq write
Statepending
QA vieweri
Opened from any escalation or job.
GET/api/qa/{job_id}
Sourceqa_results, floorplans
Effectrenders image + per-check results
Statepending
What this tab is for: browse EVERY job's full agent result, beyond the aggregate calibration matrix and the escalations subset. Filter by agreement outcome (including the critical false-pass cell), by per-check firing, and by date window. Read-only: this table never writes, never mutates a job, and offers no approve or advance action of any kind.
Browse-all audit tablei
Rows reflect the derived, append-only source (action_log + the §5a closure tuples) exactly. Not-yet-closed rows are visible but unlabeled, never asserted resolved. Zero rows under a filter shows zero rows and the filter, never sample data. Rows deep-link to the per-job QA drill-in on the HITL tab.
GET/api/audit/orders?agreement&check&check_status&false_pass&from&to&date_field — the ONLY method under /api/audit
Sourceqa_results ⋈ qa_check_results ⋈ action_log ⋈ §5a closure tuples — derived, read-only; the closure tuple's self-label scores agreement, the run verdict governs the qa_review bar
Effectfilterable browse-all (client-side sort/page); bad filter → server 400 surfaced; ZERO writes by construction
Statepending
UI wiring ledger
0 wired · 0 dead
Every interactive element, traced element → endpoint → handler → data source → runtime effect → live round-trip state. State reflects the LAST real request, never a design-time assertion: live (data rendered), empty (endpoint returned nothing — honest empty-state), refused (server 401/403 reflected), pending (not yet exercised), not wired (the round-trip can succeed, but no code path this agent runs actually reads the key back, so editing it cannot change real behavior; ROUTING 157 audit).