Handbook
Studio app logic
Internal logic map of 360 Insights Studio (feedback360/app_server.py plus the PDP engine). Capablio (capablio.com) is the user-facing SaaS; Studio is the operator back-office for KB corpus management, ingestion…
Updated
The HTTP contract lives in app-api.md; this page explains
the state machines, invariants, and gates behind those endpoints, and pairs with
the reader-facing wiki page report/wiki/studio.html emitted by the render stage.
State model (AppState)
One process-wide AppState instance owns:
| Field | Type | Lifetime | Notes |
|---|---|---|---|
settings_store |
SettingsStore |
disk (settings.json) |
Merge-on-PUT; reports_root must be absolute; unknown ai.* keys preserved. |
credentials |
CredentialStore |
memory only | Provider API keys are never written to disk; cleared on process exit. |
jobs |
JobRegistry |
memory | Generate jobs by hex id; stage list is fixed. |
enrich_progress |
EnrichmentProgress |
memory | Single in-flight enrichment run; second start returns busy. |
active |
ActiveWorkspace \| None |
memory, lock-guarded | Loaded data.json + metrics.json + pre-rendered app page. |
ActiveWorkspace caches parsed JSON and the rendered dynamic page
(render_app_page) so legacy routes (/, /api/data, /api/metrics, /report,
/wiki/*) serve without re-reading disk. Selecting a workspace fails fast:
404 when sources/thomas.pdf is missing (_is_workspace), 409 when report JSON
artifacts are absent.
Workspace invariants
- A folder is a workspace iff
sources/thomas.pdfexists. Everything else (report, verify.json, PDP files) is derived state. - Slug format
<subject-slug>-<YYYYMMDD-HHMMSS>— one workspace per generate run; workspaces are never mutated in place by later runs. list_workspacesis a pure scan ofreports_root:verify_statusis read defensively (Noneon unreadable JSON) and never blocks listing.
Generate job state machine
POST /api/generate creates a JobRecord with four fixed stages —
parse → analyze → render → verify — each pending | running | done | failed,
then runs AppState.run_generate_job on a background thread:
- Copy inputs into
<workspace>/sources/(Thomas required, snapshot optional). - parse —
parse_360.parse→data.json. - analyze —
analyze.analyze→metrics.json. - render —
render_html.render→360-report.html+wiki/*.html(includingwiki/studio.html, the reader half of this dual doc). - verify —
verify_extraction.run_verificationagainst the copied PDF; writesverify.jsonwith verdict, summary counts, and up to 50 errors.
Failure rules:
- Verify failure is a soft stop: stage
failed, jobdonewitherrorset, artifacts kept for inspection, workspace not activated, export blocked. - Any exception is a hard stop: the currently-
runningstage flips tofailed, the job finishesfailed. Nothing is retried automatically. - Only a fully verified run auto-activates its workspace
(
set_active_from_pathat the end of stage 5).
Verify-gated export
export_active enforces the single export invariant: verify.json must exist,
parse, and carry "verdict": "pass" — otherwise RuntimeError (surfaced as 409).
The zip is built by the shared export_snapshot.write_report_zip (same code path
as website snapshots) from report/, flat layout, including pdp.json /
pdp_checklist.json when present.
PDP engine flow (pdp/engine.py, pdp/compose.py)
Session state is a JSON document (pdp_session.json) in the active workspace's
report/ dir; the finalized plan is pdp.json. Core rules:
build_question_plan(data, metrics)is pure: same inputs → byte-identical steps. Stages 1–3 (orient, blindspot-*, focus) exist at session start; stages 4–7 (goal-<i>,actions-<i>,support,review) are appended by_append_dynamic_stepsafter focus is accepted, ordered by CTA rank.apply_answerdispatches per-step validators returning one of five statuses; onlyaccepted,accepted_with_warning, andpushbackadvance the cursor.pushback(disagree + robust significance) recordscontested: truebut the user's answer stands. Full per-step matrix: pdp.md.- Focus selections outside the top-3 CTA require
override_reason(needs_overrideotherwise — cursor does not advance). - AI is optional and non-blocking:
draft_goal/review_custom_actionfall back to deterministic templates on provider error; the fallback is recorded in validation metadata, never raised to HTTP. finalize_sessionrequires thereviewstep confirmed, composespdp.jsonviacompose_pdp, and derivespdp_checklist.json(goals, actions, training steps, assignments, checkpoints) with per-itemtodo | in_progress | done.data.jsonandmetrics.jsonare read-only to all PDP code paths.
Enrichment concurrency
EnrichmentProgress.start is the mutex: it refuses a second run while one is
running (409 at the API layer). Progress callbacks update per-section status
(pending → writing → ok | rejected | failed), token estimates, and ETA;
snapshot() is what GET /api/ai/enrich/progress returns. Enrichment re-renders
360-report.html but never touches the JSON artifacts.
Live controls (/api/metrics)
Dynamic recomputation calls the same compute_metrics(data, params) pure function
as the analyze stage — one code path for disk output and API recomputation.
Default params reproduce metrics.json byte-identically; invalid
importance_source values are a 400, unknown keys are ignored.
Dual wiki pairing
| Audience | Artifact | Source |
|---|---|---|
| Engineers | this file (docs/app-logic.md) |
hand-maintained Markdown |
| Report readers | report/wiki/studio.html |
emitted by render_html._wiki_studio on every render |
When Studio behavior changes (stages, gates, PDP validation, export rules), update
both: this page for the code-level mechanism, and _wiki_studio in
feedback360/render_html.py for the reader-facing explanation. The generated page
survives clean regeneration of report/; this page is version-controlled directly.
Related docs
- Studio HTTP API — endpoint contract for everything above.
- Feature status — implemented capability flags (
IMP-*/PLN-*) plus Adaptive Feedback Framework track pointer (AFF-*). - AFF implementation status — production-scale targets marked Unimplemented / Partial.
- Engineering map — one-page system layers.
- Pipeline — parse/analyze/render internals and verification harness.
- Personal Development Plan — interview stages, validation, schemas.
- AI providers — provider adapters and key handling.