{"openapi":"3.1.0","info":{"title":"Neumann","description":"Neumann is an agent-accessible Monte Carlo simulation service. This is the platform spine: zero-context self-registration, API-key / JWT / anonymous auth, and a credit ledger. The run and MCP surfaces are mounted by later lanes.\n\n## Authentication\n\nPass your API key as the `X-API-Key` header. `Authorization: Bearer` is reserved for JWTs (REST) and opaque `nmn_oat_`/`nmn_pat_` tokens (MCP). The agent surface is mounted at `/mcp` with a REST mirror at `/mcp/tools`.","version":"0.1.0"},"paths":{"/api/v1/accounts":{"post":{"tags":["Accounts"],"summary":"Self-register an account","description":"Zero-context signup: no request body. Mints an account, a first API key, and starter credits. Send the returned key as the X-API-Key header on subsequent calls.","operationId":"create_account_api_v1_accounts_post","responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccountResponse"}}}}}}},"/api/v1/accounts/me":{"get":{"tags":["Accounts"],"summary":"Get your account info","operationId":"get_account_me_api_v1_accounts_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountMeResponse"}}}}}}},"/api/v1/accounts/me/ledger":{"get":{"tags":["Accounts"],"summary":"Read your credit ledger","description":"Recent credit-ledger entries (signup grants, run debits).","operationId":"get_account_ledger_api_v1_accounts_me_ledger_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LedgerResponse"}}}}}}},"/api/v1/contract":{"get":{"tags":["Contract","Contract"],"summary":"Get Contract","operationId":"get_contract_api_v1_contract_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContractInfoResponse"}}}}}}},"/api/v1/runs":{"post":{"tags":["Runs"],"summary":"Run a Monte Carlo simulation on an inline graph","description":"Executes a run on the supplied graph. The graph is the public contract (root_nodes, calc_nodes, edges, run_params) — the same shape the MCP run_simulation tool accepts — and is lowered to the engine via the shared adapter. The legacy internal engine dict (nodes + simulation_params) is also accepted for backward compatibility. Small runs return the summary inline as JSON; large runs (or stream=true) return text/event-stream with simulation_started -> batch_progress* -> simulation_completed.","operationId":"create_run_api_v1_runs_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Runs"],"summary":"List persisted runs for the caller's tenant (paginated)","operationId":"list_runs_api_v1_runs_get","parameters":[{"name":"graph_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Graph Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoredRunListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/runs/{run_id}":{"get":{"tags":["Runs"],"summary":"Get a run's status and result","description":"Retrieve the status/aggregate for a previously-submitted run.","operationId":"get_run_api_v1_runs__run_id__get","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/graphs":{"get":{"tags":["Graphs"],"summary":"List stored graphs for the caller's tenant","operationId":"list_graphs_api_v1_graphs_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoredGraphListResponse"}}}}}},"post":{"tags":["Graphs"],"summary":"Create a stored graph (tenant-scoped)","operationId":"create_graph_api_v1_graphs_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoredGraphBody"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoredGraphResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/graphs/{graph_id}":{"get":{"tags":["Graphs"],"summary":"Get a stored graph (tenant-scoped; 404 cross-tenant)","operationId":"get_graph_api_v1_graphs__graph_id__get","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoredGraphResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Graphs"],"summary":"Replace a stored graph (tenant-scoped; 404 cross-tenant)","operationId":"update_graph_api_v1_graphs__graph_id__put","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoredGraphBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoredGraphResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Graphs"],"summary":"Write the sim subset and return the per-element version delta","description":"Write the sim subset and return the WRITE-LEADER DELTA (neumann#2, X1b).\n\nPATCH vs PUT — distinct, intentional semantics:\n  * ``PUT /graphs/{id}`` is the full-replace write that returns the whole\n    ``StoredGraphResponse`` (the materialized graph with every node/edge).\n  * ``PATCH /graphs/{id}`` performs the SAME full-replace write of the sim\n    subset (it reuses ``update_graph_with_delta`` — identical persistence,\n    same FOR UPDATE lock, same per-element + downstream version bumps) but\n    returns ONLY the per-element version DELTA, not the materialized graph.\n\nThe delta is returned VERBATIM from ``update_graph_with_delta`` wrapped with\nthe graph's externally-meaningful id. It lists the elements whose authoritative\n``version`` bumped on THIS write — directly-edited nodes/edges/graph-field PLUS\nrecompute-driven downstream calc nodes — each as ``{id, kind, version}`` keyed\nby ``external_id`` (the graph's krobar id for the ``graph-field`` entry).\n\nCarries VERSIONS ONLY — no recomputed values, by design (the front does not\nconsume live values on edit; it diffs versions and re-fetches lazily). This\nroute runs NO Monte Carlo recompute. DELETIONS ARE NOT IN THE DELTA: a\nconsumer derives them by diffing the next GET against its last-known set.\n\nAlso carries the write's ``validation`` report (neumann#153). The gateway\nonly ever PATCHes, so this is the channel a krobar save learns that its graph\nstored fine but is not simulation-ready — instead of the write being rejected\nand the local-first resync silently dropping the graph.\n\nTenant-scoped via the gateway principal; cross-tenant resolves to 404.","operationId":"patch_graph_delta_api_v1_graphs__graph_id__patch","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoredGraphBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphWriteDeltaResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Graphs"],"summary":"Delete a stored graph (tenant-scoped; 404 cross-tenant)","operationId":"delete_graph_api_v1_graphs__graph_id__delete","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/graphs/{graph_id}/versions":{"post":{"tags":["Graphs"],"summary":"Snapshot a graph as a version (autosave or named)","operationId":"create_version_api_v1_graphs__graph_id__versions_post","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateVersionBody"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphVersionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Graphs"],"summary":"List a graph's versions (newest first; tenant-scoped)","operationId":"list_versions_api_v1_graphs__graph_id__versions_get","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}},{"name":"correlation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"KB4 (krobar-back#411) restore-by-correlation: when set, return only the version a krobar envelope mapped to via this correlation_id (at most one, unique per graph), so krobar can reassemble sim(neumann@correlation). Tenant-scoped via the parent graph (404 cross-tenant).","title":"Correlation Id"},"description":"KB4 (krobar-back#411) restore-by-correlation: when set, return only the version a krobar envelope mapped to via this correlation_id (at most one, unique per graph), so krobar can reassemble sim(neumann@correlation). Tenant-scoped via the parent graph (404 cross-tenant)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphVersionListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Graphs"],"summary":"Delete a version by correlation_id (KB4 compensation; tenant-scoped)","operationId":"delete_version_by_correlation_api_v1_graphs__graph_id__versions_delete","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}},{"name":"correlation_id","in":"query","required":true,"schema":{"type":"string","description":"KB4 (krobar-back#411) version-envelope compensation: delete the single snapshot a krobar envelope mapped to via this correlation_id (unique per graph). REQUIRED — a correlation-less DELETE is ambiguous and rejected (400 validation_error), never a mass-delete. Tenant-scoped via the parent graph (404 cross-tenant). 204 on delete; 404 when none mapped (idempotent: a re-DELETE 404s and the caller treats it as no-op success).","title":"Correlation Id"},"description":"KB4 (krobar-back#411) version-envelope compensation: delete the single snapshot a krobar envelope mapped to via this correlation_id (unique per graph). REQUIRED — a correlation-less DELETE is ambiguous and rejected (400 validation_error), never a mass-delete. Tenant-scoped via the parent graph (404 cross-tenant). 204 on delete; 404 when none mapped (idempotent: a re-DELETE 404s and the caller treats it as no-op success)."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/solve":{"post":{"tags":["Solve"],"summary":"Solve distribution parameters from a min/max range (gateway)","description":"Turns a human-style 'between X and Y, N% confident' estimate into engine-ready distribution_params. Delegates to the same core function the MCP solve_distribution_parameters tool calls, so REST and MCP cannot drift. Requires a tenant-scoped gateway principal.","operationId":"solve_distribution_api_v1_solve_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SolveRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SolveResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/graphs/{graph_id}/runs":{"post":{"tags":["Runs"],"summary":"Run a stored graph and persist the run (tenant-scoped)","operationId":"run_stored_graph_api_v1_graphs__graph_id__runs_post","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StoredRunRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoredRunSummary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/graphs/{graph_id}/runs/stream":{"post":{"tags":["Runs"],"summary":"Run a stored graph as an SSE stream (tenant-scoped)","operationId":"run_stored_graph_stream_api_v1_graphs__graph_id__runs_stream_post","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StoredRunRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/runs/{run_id}/summary":{"get":{"tags":["Runs"],"summary":"Get a persisted run's summary (tenant-scoped; 404 cross-tenant)","operationId":"get_run_summary_api_v1_runs__run_id__summary_get","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoredRunSummary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/runs/{run_id}/trials":{"get":{"tags":["Runs"],"summary":"Paginated trial-level data for a run (tenant-scoped; nodes only)","operationId":"get_run_trials_api_v1_runs__run_id__trials_get","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":100,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrialsDataResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/runs/{run_id}/detailed-percentiles":{"get":{"tags":["Runs"],"summary":"1st-99th percentiles per node / time-period (tenant-scoped)","operationId":"get_run_detailed_percentiles_api_v1_runs__run_id__detailed_percentiles_get","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":50,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetailedPercentilesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/runs/{run_id}/goal-probability":{"get":{"tags":["Runs"],"summary":"Goal achievement probability for a run (tenant-scoped)","operationId":"get_run_goal_probability_api_v1_runs__run_id__goal_probability_get","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoalProbabilityResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/runs/{run_id}/download":{"get":{"tags":["Runs"],"summary":"XLSX export of a run (presigned S3 URL or streamed bytes)","operationId":"get_run_download_api_v1_runs__run_id__download_get","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}},{"name":"expiration","in":"query","required":false,"schema":{"type":"integer","maximum":86400,"minimum":300,"default":3600,"title":"Expiration"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/graphs/{graph_id}/oat_sensitivity":{"post":{"tags":["Sensitivity"],"summary":"Run OAT sensitivity over a stored graph and persist it (tenant-scoped)","operationId":"run_stored_oat_sensitivity_api_v1_graphs__graph_id__oat_sensitivity_post","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StoredSensitivityRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoredSensitivityResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Sensitivity"],"summary":"List a stored graph's OAT sensitivity analyses (tenant-scoped)","operationId":"list_stored_oat_sensitivity_api_v1_graphs__graph_id__oat_sensitivity_get","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}},{"name":"graph_version","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"title":"Graph Version"}},{"name":"skip","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Skip"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/StoredSensitivitySummary"},"title":"Response List Stored Oat Sensitivity Api V1 Graphs  Graph Id  Oat Sensitivity Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/graphs/{graph_id}/oat_sensitivity/{analysis_id}":{"get":{"tags":["Sensitivity"],"summary":"Get one stored OAT sensitivity analysis (tenant-scoped; 404 cross-tenant)","operationId":"get_stored_oat_sensitivity_api_v1_graphs__graph_id__oat_sensitivity__analysis_id__get","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}},{"name":"analysis_id","in":"path","required":true,"schema":{"type":"string","title":"Analysis Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoredSensitivityDetail"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/graphs/{graph_id}/templates":{"post":{"tags":["Sub-resources"],"summary":"Create a graph template (tenant-scoped; 404 cross-tenant)","operationId":"create_template_api_v1_graphs__graph_id__templates_post","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphTemplateBody"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphTemplateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Sub-resources"],"summary":"List a graph's templates (newest first; tenant-scoped)","operationId":"list_templates_api_v1_graphs__graph_id__templates_get","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphTemplateListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/graphs/{graph_id}/templates/{template_id}":{"get":{"tags":["Sub-resources"],"summary":"Get a graph template (tenant-scoped; 404 cross-tenant)","operationId":"get_template_api_v1_graphs__graph_id__templates__template_id__get","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}},{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphTemplateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Sub-resources"],"summary":"Delete a graph template (tenant-scoped; 404 cross-tenant)","operationId":"delete_template_api_v1_graphs__graph_id__templates__template_id__delete","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}},{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/graphs/{graph_id}/observed-data":{"post":{"tags":["Sub-resources"],"summary":"Create an observed-data series (validates node_id; tenant-scoped)","operationId":"create_observed_data_api_v1_graphs__graph_id__observed_data_post","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObservedDataBody"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObservedDataResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Sub-resources"],"summary":"List a graph's observed-data series (newest first; tenant-scoped)","operationId":"list_observed_data_api_v1_graphs__graph_id__observed_data_get","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObservedDataListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/graphs/{graph_id}/observed-data/{observed_id}":{"get":{"tags":["Sub-resources"],"summary":"Get an observed-data series (tenant-scoped; 404 cross-tenant)","operationId":"get_observed_data_api_v1_graphs__graph_id__observed_data__observed_id__get","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}},{"name":"observed_id","in":"path","required":true,"schema":{"type":"string","title":"Observed Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObservedDataResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Sub-resources"],"summary":"Replace an observed-data series (validates node_id; tenant-scoped)","operationId":"update_observed_data_api_v1_graphs__graph_id__observed_data__observed_id__put","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}},{"name":"observed_id","in":"path","required":true,"schema":{"type":"string","title":"Observed Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObservedDataBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObservedDataResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Sub-resources"],"summary":"Delete an observed-data series (tenant-scoped; 404 cross-tenant)","operationId":"delete_observed_data_api_v1_graphs__graph_id__observed_data__observed_id__delete","parameters":[{"name":"graph_id","in":"path","required":true,"schema":{"type":"string","title":"Graph Id"}},{"name":"observed_id","in":"path","required":true,"schema":{"type":"string","title":"Observed Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/portfolios":{"get":{"tags":["Sub-resources"],"summary":"List portfolios for the caller's tenant","operationId":"list_portfolios_api_v1_portfolios_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioListResponse"}}}}}},"post":{"tags":["Sub-resources"],"summary":"Create a portfolio (tenant-scoped)","operationId":"create_portfolio_api_v1_portfolios_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioBody"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/portfolios/{portfolio_id}":{"get":{"tags":["Sub-resources"],"summary":"Get a portfolio with its items (tenant-scoped; 404 cross-tenant)","operationId":"get_portfolio_api_v1_portfolios__portfolio_id__get","parameters":[{"name":"portfolio_id","in":"path","required":true,"schema":{"type":"string","title":"Portfolio Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Sub-resources"],"summary":"Replace a portfolio (tenant-scoped; 404 cross-tenant)","operationId":"update_portfolio_api_v1_portfolios__portfolio_id__put","parameters":[{"name":"portfolio_id","in":"path","required":true,"schema":{"type":"string","title":"Portfolio Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Sub-resources"],"summary":"Delete a portfolio (tenant-scoped; 404 cross-tenant)","operationId":"delete_portfolio_api_v1_portfolios__portfolio_id__delete","parameters":[{"name":"portfolio_id","in":"path","required":true,"schema":{"type":"string","title":"Portfolio Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/portfolios/{portfolio_id}/items":{"post":{"tags":["Sub-resources"],"summary":"Add an item to a portfolio (tenant-scoped graph/run refs)","operationId":"add_portfolio_item_api_v1_portfolios__portfolio_id__items_post","parameters":[{"name":"portfolio_id","in":"path","required":true,"schema":{"type":"string","title":"Portfolio Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioItemBody"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioItemResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/portfolios/{portfolio_id}/items/{item_id}":{"delete":{"tags":["Sub-resources"],"summary":"Delete a portfolio item (tenant-scoped; 404 cross-tenant)","operationId":"delete_portfolio_item_api_v1_portfolios__portfolio_id__items__item_id__delete","parameters":[{"name":"portfolio_id","in":"path","required":true,"schema":{"type":"string","title":"Portfolio Id"}},{"name":"item_id","in":"path","required":true,"schema":{"type":"string","title":"Item Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/tokens":{"post":{"tags":["Tokens"],"summary":"Mint an opaque MCP bearer token","description":"Mint a static `nmn_pat_` / `nmn_oat_` opaque token for use as the `Authorization: Bearer` credential on the `/mcp` transport. Requires an authenticated account (send your `X-API-Key`). The plaintext token is returned ONCE and only its hash is stored — save it now.","operationId":"mint_opaque_mcp_token_api_v1_tokens_post","requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/MintTokenRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintTokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/pricing":{"get":{"tags":["Billing","Billing"],"summary":"Get credit pricing","description":"Per-credit price. No authentication required.","operationId":"get_pricing_billing_pricing_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingResponse"}}}}}}},"/mcp/tools":{"get":{"tags":["MCP"],"summary":"List the agent tools (MCP/REST parity descriptors)","description":"Returns the same tool descriptors the MCP server advertises via tools/list: name, description, and input/output JSON schema (single-sourced from the N-1.3 contract).","operationId":"list_tools_mcp_tools_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"type":"object","title":"Response List Tools Mcp Tools Get"}}}}}}},"/mcp/tools/{name}":{"get":{"tags":["MCP"],"summary":"Show one agent tool's descriptor (friendly GET twin)","description":"A GET on a single tool returns that tool's descriptor (name, description, input/output JSON schema) instead of the noisy 406 the MCP streamable-http transport returns. To *invoke* the tool, POST to this same path; to list every tool, GET /mcp/tools (neumann#42).","operationId":"get_tool_mcp_tools__name__get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Tool Mcp Tools  Name  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["MCP"],"summary":"Invoke an agent tool over REST (mirrors the MCP tools/call)","description":"Runs the named tool with the JSON body as its arguments, delegating to the same core function the MCP server calls. Authenticate via the api_key body field or the X-API-Key header.","operationId":"call_tool_mcp_tools__name__post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Call Tool Mcp Tools  Name  Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AccountMeResponse":{"properties":{"account_id":{"type":"string","title":"Account Id"},"credit_balance":{"type":"integer","title":"Credit Balance"},"is_unlimited":{"type":"boolean","title":"Is Unlimited"},"created_at":{"type":"string","title":"Created At"}},"type":"object","required":["account_id","credit_balance","is_unlimited","created_at"],"title":"AccountMeResponse"},"BasicStats":{"properties":{"mean":{"type":"number","title":"Mean"},"std":{"type":"number","title":"Std"},"min":{"type":"number","title":"Min"},"max":{"type":"number","title":"Max"}},"type":"object","required":["mean","std","min","max"],"title":"BasicStats","description":"Summary statistics for one element at one time period."},"CalcNode":{"properties":{"id":{"type":"string","title":"Id","description":"Unique node id within the graph."},"name":{"type":"string","title":"Name","description":"Human-readable label.","default":""},"formula":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Formula","description":"Optional expression over incoming edge ids, e.g. '{e1} * 0.5 + {e2}'. To sum incoming edges write '{e1}+{e2}'; for pass-through use '{e1}'. If omitted/empty the node is treated as a constant 0 (sum-of-incoming is not implied); validate_graph reports this as a warning."}},"additionalProperties":false,"type":"object","required":["id"],"title":"CalcNode","description":"A computed node. ``formula`` is OPTIONAL.\n\nA null/empty/whitespace formula is allowed: the node is treated as a\nconstant ``0`` every period/trial (incoming edges are ignored — there is no\nimplicit \"sum of incoming edges\"). ``validate_graph`` surfaces this as a\nWARNING, not an error. To sum incoming edges, write the sum explicitly,\ne.g. ``{e1}+{e2}``; for pass-through use ``{e1}``."},"ContractInfoResponse":{"properties":{"contract_version":{"type":"string","title":"Contract Version"},"distributions":{"additionalProperties":{"$ref":"#/components/schemas/DistributionSpec"},"type":"object","title":"Distributions"},"formula_functions":{"additionalProperties":{"$ref":"#/components/schemas/FormulaFunctionSpec"},"type":"object","title":"Formula Functions"},"time_period_indexing":{"type":"string","title":"Time Period Indexing"}},"type":"object","required":["contract_version","distributions","formula_functions","time_period_indexing"],"title":"ContractInfoResponse"},"CreateAccountResponse":{"properties":{"account_id":{"type":"string","title":"Account Id"},"api_key":{"type":"string","title":"Api Key","description":"Raw API key — shown once. Send as the X-API-Key header."},"credit_balance":{"type":"integer","title":"Credit Balance"},"created_at":{"type":"string","title":"Created At"}},"type":"object","required":["account_id","api_key","credit_balance","created_at"],"title":"CreateAccountResponse"},"CreateVersionBody":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"is_autosave":{"type":"boolean","title":"Is Autosave","default":false},"correlation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Correlation Id"}},"type":"object","title":"CreateVersionBody","description":"Request to snapshot the current graph state as a version.\n\nMirrors krobar version semantics: ``is_autosave`` distinguishes an automatic\ncheckpoint from a user-named version."},"DetailedPercentilesResponse":{"properties":{"run_id":{"type":"string","title":"Run Id"},"detailed_percentiles":{"additionalProperties":{"additionalProperties":{"additionalProperties":{"type":"number"},"type":"object"},"type":"object"},"type":"object","title":"Detailed Percentiles","description":"{node_id: {time_period: {'Nth': value}}} for 1st-99th."},"page":{"type":"integer","title":"Page"},"page_size":{"type":"integer","title":"Page Size"},"total_nodes":{"type":"integer","title":"Total Nodes"}},"type":"object","required":["run_id","detailed_percentiles","page","page_size","total_nodes"],"title":"DetailedPercentilesResponse","description":"1st-99th percentiles per node / per time-period."},"DistributionParamSpec":{"properties":{"type":{"type":"string","title":"Type","description":"JSON type, e.g. 'float', 'int', 'list[float]'."},"description":{"type":"string","title":"Description"},"constraints":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Constraints","description":"Human-readable constraint, e.g. 'positive', 'between 0 and 1'."}},"type":"object","required":["type","description"],"title":"DistributionParamSpec","description":"One parameter of a distribution."},"DistributionSpec":{"properties":{"name":{"type":"string","title":"Name","description":"The distribution_type value to use in a root node."},"description":{"type":"string","title":"Description"},"parameters":{"additionalProperties":{"$ref":"#/components/schemas/DistributionParamSpec"},"type":"object","title":"Parameters"}},"type":"object","required":["name","description","parameters"],"title":"DistributionSpec","description":"A supported distribution and the parameters it accepts."},"Edge":{"properties":{"id":{"type":"string","title":"Id","description":"Unique edge id within the graph."},"source":{"type":"string","title":"Source","description":"id of the source node."},"target":{"type":"string","title":"Target","description":"id of the target node."},"delay":{"type":"integer","minimum":0.0,"title":"Delay","description":"Periods the value is delayed in transit.","default":0},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Optional label."}},"additionalProperties":false,"type":"object","required":["id","source","target"],"title":"Edge","description":"A directed connection carrying a value from source to target."},"FormulaFunctionSpec":{"properties":{"name":{"type":"string","title":"Name","description":"The function name as written in a formula/aggregation."},"kind":{"type":"string","title":"Kind","description":"'formula' for a per-period calc-node function (used inside a calc_node formula), or 'aggregation' for a post-simulation, series-aware metric (requested via output_request.aggregations)."},"description":{"type":"string","title":"Description"},"arity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Arity","description":"Human-readable argument shape, e.g. '2', '1..N', '(rate, value, period)'."}},"type":"object","required":["name","kind","description"],"title":"FormulaFunctionSpec","description":"One callable usable in a graph — a per-period formula function or a\npost-simulation aggregation metric."},"GoalProbabilityResponse":{"properties":{"run_id":{"type":"string","title":"Run Id"},"graph_id":{"type":"string","title":"Graph Id"},"goal_node":{"type":"string","title":"Goal Node"},"goal_value":{"type":"number","title":"Goal Value"},"goal_direction":{"type":"string","title":"Goal Direction"},"goal_time_period":{"type":"integer","title":"Goal Time Period"},"probability_percentage":{"type":"number","title":"Probability Percentage","description":"Probability of achieving the goal, as a percentage (0-100)."},"calculation_method":{"type":"string","title":"Calculation Method","default":"exact"}},"type":"object","required":["run_id","graph_id","goal_node","goal_value","goal_direction","goal_time_period","probability_percentage"],"title":"GoalProbabilityResponse","description":"Probability of meeting the graph's goal node value/direction."},"GraphElementDelta":{"properties":{"id":{"type":"string","title":"Id"},"kind":{"type":"string","enum":["node","edge","graph-field"],"title":"Kind"},"version":{"type":"integer","title":"Version"}},"type":"object","required":["id","kind","version"],"title":"GraphElementDelta","description":"One bumped element in a write-leader delta (neumann#2, X1b wire contract).\n\nEmitted by ``PATCH /graphs/{id}``. ``id`` is the element's externally-meaningful\nid (node/edge ``external_id``, or the graph's krobar id for a ``graph-field``\nentry). ``version`` is the authoritative monotonic per-element version AFTER\nthis write. Carries VERSIONS ONLY — no recomputed values, by design (the front\ndoes not consume live values on edit). A consumer derives \"what changed\" from\nthe version bump and re-fetches values lazily if needed."},"GraphTemplateBody":{"properties":{"template_metadata":{"additionalProperties":true,"type":"object","title":"Template Metadata"}},"type":"object","title":"GraphTemplateBody","description":"The mutable body of a graph template (neumann#75).\n\nA template is a thin reusable marker over an existing graph; its only mutable\npayload is the free-form ``template_metadata`` blob (category / tags / etc.)."},"GraphTemplateListResponse":{"properties":{"templates":{"items":{"$ref":"#/components/schemas/GraphTemplateResponse"},"type":"array","title":"Templates"}},"type":"object","required":["templates"],"title":"GraphTemplateListResponse"},"GraphTemplateResponse":{"properties":{"id":{"type":"string","title":"Id"},"graph_id":{"type":"string","title":"Graph Id"},"actor_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Actor Id"},"template_metadata":{"additionalProperties":true,"type":"object","title":"Template Metadata"},"created_at":{"type":"string","title":"Created At"}},"type":"object","required":["id","graph_id","actor_id","template_metadata","created_at"],"title":"GraphTemplateResponse"},"GraphValidationIssue":{"properties":{"element_type":{"type":"string","enum":["node","edge","graph"],"title":"Element Type"},"element_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Element Id"},"field":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Field"},"rule":{"type":"string","title":"Rule","description":"Machine-readable validation rule that fired."},"ruleset":{"type":"string","title":"Ruleset","description":"Engine ruleset the rule belongs to."},"severity":{"type":"string","enum":["error","warning","info"],"title":"Severity"},"message":{"type":"string","title":"Message"}},"type":"object","required":["element_type","rule","ruleset","severity","message"],"title":"GraphValidationIssue","description":"One strict-tier (simulation-readiness) finding, attributed to an element.\n\nEmitted on the WRITE responses (neumann#153): a save is validated leniently\n(structure only) and succeeds, but the strict simulate-tier findings are\nreported here so a caller learns what is wrong in the SAME round-trip\ninstead of discovering it at ``/run`` time.\n\n``element_id`` is the node/edge ``external_id`` the finding is attributed to\n(``None`` for a whole-graph finding, where ``element_type`` is ``graph``).\n``field`` names the element field at fault when the rule implies one\n(``formula`` / ``distribution_params`` / ``name``); it is ``None`` when the\nrule is not about one specific field — ``rule`` is the machine-readable key,\n``field`` is a convenience for pointing an editor at the right input.\n\nOne engine finding that names several elements is expanded into one issue\nPER element (same ``rule``/``message``), so a consumer can attach every\nissue to exactly one element without re-parsing."},"GraphValidationReport":{"properties":{"simulation_ready":{"type":"boolean","title":"Simulation Ready"},"issues":{"items":{"$ref":"#/components/schemas/GraphValidationIssue"},"type":"array","title":"Issues"}},"type":"object","required":["simulation_ready"],"title":"GraphValidationReport","description":"Strict-tier validation results attached to a stored-graph WRITE response.\n\n``simulation_ready`` is the answer to \"would ``/run`` accept this graph as\nsaved\" — ``False`` exactly when at least one ``error``-severity issue is\npresent. A save is NEVER blocked by this report (neumann#153): the write\npath enforces only the lenient storage tier, so an accept-with-errors save\nreturns 201/200 with ``simulation_ready: false`` and the issues below."},"GraphVersionListResponse":{"properties":{"versions":{"items":{"$ref":"#/components/schemas/GraphVersionResponse"},"type":"array","title":"Versions"}},"type":"object","required":["versions"],"title":"GraphVersionListResponse"},"GraphVersionResponse":{"properties":{"id":{"type":"string","title":"Id"},"graph_id":{"type":"string","title":"Graph Id"},"correlation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Correlation Id"},"version":{"type":"integer","title":"Version"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"is_autosave":{"type":"boolean","title":"Is Autosave"},"nodes":{"items":{},"type":"array","title":"Nodes"},"edges":{"items":{},"type":"array","title":"Edges"},"graph_metadata":{"additionalProperties":true,"type":"object","title":"Graph Metadata"},"created_at":{"type":"string","title":"Created At"}},"type":"object","required":["id","graph_id","correlation_id","version","name","description","is_autosave","nodes","edges","graph_metadata","created_at"],"title":"GraphVersionResponse"},"GraphWriteDeltaResponse":{"properties":{"id":{"type":"string","title":"Id"},"delta":{"items":{"$ref":"#/components/schemas/GraphElementDelta"},"type":"array","title":"Delta"},"validation":{"anyOf":[{"$ref":"#/components/schemas/GraphValidationReport"},{"type":"null"}]}},"type":"object","required":["id","delta"],"title":"GraphWriteDeltaResponse","description":"Response of ``PATCH /graphs/{id}`` — the write-leader delta envelope.\n\nThe wire contract krobar-back (KB2 gateway, #408) relays over SSE and the\nfront compares against its last-known element set. ``id`` is the graph's\nexternally-meaningful id (the krobar ``client_graph_id`` the client edits by).\n``delta`` is the list of elements whose authoritative ``version`` bumped on\nTHIS write — directly-edited elements PLUS recompute-driven downstream calc\nnodes — returned VERBATIM from ``update_graph_with_delta``. Carries VERSIONS\nONLY (no recomputed values). DELETIONS ARE NOT REPRESENTED: a consumer derives\ndeletions by diffing the next GET against its last-known set."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"Histogram":{"properties":{"counts":{"items":{"type":"integer"},"type":"array","title":"Counts"},"bins":{"items":{"type":"number"},"type":"array","title":"Bins"}},"type":"object","required":["counts","bins"],"title":"Histogram","description":"Optional histogram of the trial values for one element."},"LedgerEntry":{"properties":{"entry_type":{"type":"string","title":"Entry Type"},"amount":{"type":"integer","title":"Amount"},"request_id":{"type":"string","title":"Request Id"},"created_at":{"type":"string","title":"Created At"}},"type":"object","required":["entry_type","amount","request_id","created_at"],"title":"LedgerEntry"},"LedgerResponse":{"properties":{"account_id":{"type":"string","title":"Account Id"},"transactions":{"items":{"$ref":"#/components/schemas/LedgerEntry"},"type":"array","title":"Transactions"}},"type":"object","required":["account_id","transactions"],"title":"LedgerResponse"},"MintTokenRequest":{"properties":{"kind":{"type":"string","enum":["pat","oat"],"title":"Kind","default":"pat"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Optional human label for the token (not persisted yet)."}},"type":"object","title":"MintTokenRequest","description":"Optional body for ``POST /api/v1/tokens``."},"MintTokenResponse":{"properties":{"token":{"type":"string","title":"Token","description":"The plaintext opaque token. Shown ONCE."},"prefix":{"type":"string","title":"Prefix","description":"The token prefix: 'nmn_pat_' or 'nmn_oat_'."},"created_at":{"type":"string","title":"Created At","description":"ISO-8601 creation timestamp."}},"type":"object","required":["token","prefix","created_at"],"title":"MintTokenResponse","description":"The minted token. ``token`` is the one-time plaintext bearer."},"ObservedDataBody":{"properties":{"node_id":{"type":"string","minLength":1,"title":"Node Id","description":"External id of a parent-graph node."},"name":{"type":"string","minLength":1,"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"data_source_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Data Source Id"},"start_date":{"type":"string","format":"date","title":"Start Date"},"end_date":{"type":"string","format":"date","title":"End Date"},"time_period":{"type":"string","minLength":1,"title":"Time Period"},"observations":{"additionalProperties":true,"type":"object","title":"Observations"},"observeddata_metadata":{"additionalProperties":true,"type":"object","title":"Observeddata Metadata"}},"type":"object","required":["node_id","name","start_date","end_date","time_period"],"title":"ObservedDataBody","description":"The mutable body of an observed-data series (neumann#75).\n\n``node_id`` is the external id of a node on the PARENT graph; the write path\nvalidates it against the parent graph's nodes (a ``node_id`` that is not a\nnode on the graph is rejected 400). The shape mirrors the #12 ``ObservedData``\nmodel: a named time-series with a date range and a free-form observations map."},"ObservedDataListResponse":{"properties":{"observed_data":{"items":{"$ref":"#/components/schemas/ObservedDataResponse"},"type":"array","title":"Observed Data"}},"type":"object","required":["observed_data"],"title":"ObservedDataListResponse"},"ObservedDataResponse":{"properties":{"id":{"type":"string","title":"Id"},"graph_id":{"type":"string","title":"Graph Id"},"node_id":{"type":"string","title":"Node Id"},"actor_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Actor Id"},"data_source_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Data Source Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"start_date":{"type":"string","title":"Start Date"},"end_date":{"type":"string","title":"End Date"},"time_period":{"type":"string","title":"Time Period"},"observations":{"additionalProperties":true,"type":"object","title":"Observations"},"observeddata_metadata":{"additionalProperties":true,"type":"object","title":"Observeddata Metadata"},"created_at":{"type":"string","title":"Created At"}},"type":"object","required":["id","graph_id","node_id","actor_id","data_source_id","name","description","start_date","end_date","time_period","observations","observeddata_metadata","created_at"],"title":"ObservedDataResponse"},"Percentiles":{"properties":{"p10":{"type":"number","title":"P10"},"p25":{"type":"number","title":"P25"},"p50":{"type":"number","title":"P50"},"p75":{"type":"number","title":"P75"},"p90":{"type":"number","title":"P90"}},"type":"object","required":["p10","p25","p50","p75","p90"],"title":"Percentiles","description":"Distribution percentiles for one element at one time period."},"PortfolioBody":{"properties":{"name":{"type":"string","minLength":1,"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"is_public":{"type":"boolean","title":"Is Public","default":false},"portfolio_metadata":{"additionalProperties":true,"type":"object","title":"Portfolio Metadata"}},"type":"object","required":["name"],"title":"PortfolioBody","description":"The mutable body of a portfolio (shared by create + update; neumann#75)."},"PortfolioItemBody":{"properties":{"graph_id":{"type":"string","minLength":1,"title":"Graph Id"},"simulation_run_id":{"type":"string","minLength":1,"title":"Simulation Run Id"},"calc_node_id":{"type":"string","minLength":1,"title":"Calc Node Id"},"color":{"type":"string","maxLength":7,"minLength":1,"title":"Color"},"time_period":{"type":"integer","minimum":0.0,"title":"Time Period","default":0},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Name"},"order_index":{"type":"integer","minimum":0.0,"title":"Order Index","default":0},"element_names":{"additionalProperties":true,"type":"object","title":"Element Names"},"item_metadata":{"additionalProperties":true,"type":"object","title":"Item Metadata"}},"type":"object","required":["graph_id","simulation_run_id","calc_node_id","color"],"title":"PortfolioItemBody","description":"A single graph/run selection within a portfolio (neumann#75).\n\n``graph_id`` / ``simulation_run_id`` are resolved TENANT-SCOPED on write: a\nreference to another tenant's graph or run is rejected 404 (no cross-tenant\nleak), so a portfolio can only ever hold the caller-tenant's own graphs/runs."},"PortfolioItemResponse":{"properties":{"id":{"type":"string","title":"Id"},"portfolio_id":{"type":"string","title":"Portfolio Id"},"graph_id":{"type":"string","title":"Graph Id"},"simulation_run_id":{"type":"string","title":"Simulation Run Id"},"calc_node_id":{"type":"string","title":"Calc Node Id"},"color":{"type":"string","title":"Color"},"time_period":{"type":"integer","title":"Time Period"},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Name"},"order_index":{"type":"integer","title":"Order Index"},"element_names":{"additionalProperties":true,"type":"object","title":"Element Names"},"item_metadata":{"additionalProperties":true,"type":"object","title":"Item Metadata"},"created_at":{"type":"string","title":"Created At"}},"type":"object","required":["id","portfolio_id","graph_id","simulation_run_id","calc_node_id","color","time_period","display_name","order_index","element_names","item_metadata","created_at"],"title":"PortfolioItemResponse"},"PortfolioListResponse":{"properties":{"portfolios":{"items":{"$ref":"#/components/schemas/PortfolioSummary"},"type":"array","title":"Portfolios"}},"type":"object","required":["portfolios"],"title":"PortfolioListResponse"},"PortfolioResponse":{"properties":{"id":{"type":"string","title":"Id"},"tenant_id":{"type":"string","title":"Tenant Id"},"actor_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Actor Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"is_public":{"type":"boolean","title":"Is Public"},"portfolio_metadata":{"additionalProperties":true,"type":"object","title":"Portfolio Metadata"},"items":{"items":{"$ref":"#/components/schemas/PortfolioItemResponse"},"type":"array","title":"Items"},"created_at":{"type":"string","title":"Created At"}},"type":"object","required":["id","tenant_id","actor_id","name","description","is_public","portfolio_metadata","items","created_at"],"title":"PortfolioResponse","description":"A persisted portfolio with its expanded items, tenant-scoped (neumann#75)."},"PortfolioSummary":{"properties":{"id":{"type":"string","title":"Id"},"tenant_id":{"type":"string","title":"Tenant Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"is_public":{"type":"boolean","title":"Is Public"},"created_at":{"type":"string","title":"Created At"}},"type":"object","required":["id","tenant_id","name","description","is_public","created_at"],"title":"PortfolioSummary","description":"A lighter list-row (no item expansion)."},"PricingResponse":{"properties":{"unit_price_cents":{"type":"integer","title":"Unit Price Cents"},"currency":{"type":"string","title":"Currency"}},"type":"object","required":["unit_price_cents","currency"],"title":"PricingResponse"},"ResponseCurvePoint":{"properties":{"quantile":{"type":"number","title":"Quantile"},"input_value":{"type":"number","title":"Input Value"},"output_value":{"type":"number","title":"Output Value"},"delta_output":{"type":"number","title":"Delta Output"},"sensitivity":{"type":"number","title":"Sensitivity"}},"type":"object","required":["quantile","input_value","output_value","delta_output","sensitivity"],"title":"ResponseCurvePoint","description":"One point of a variable's response curve (krobar parity)."},"RunRequest":{"properties":{"graph":{"additionalProperties":true,"type":"object","title":"Graph","description":"Public simulation graph: root_nodes, calc_nodes, edges, run_params (trials, time_periods, optional output_request). The legacy engine dict (nodes, edges, simulation_params) is also accepted."},"stream":{"type":"boolean","title":"Stream","description":"Force SSE streaming transport regardless of run tier.","default":false},"seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seed","description":"Optional RNG seed; reproducible only on the inline path."}},"type":"object","required":["graph"],"title":"RunRequest","description":"Inline run request (SPEC §1/§3 — graph is passed by value).\n\n``graph`` is the **public contract** (``root_nodes``, ``calc_nodes``,\n``edges``, ``run_params``) — the same shape the MCP ``run_simulation`` tool\naccepts; see ``contracts.example.EXAMPLE_GRAPH``. The legacy internal engine\ndict (``nodes``, ``edges``, ``simulation_params``) is also accepted for\nbackward compatibility. ``stream`` forces SSE transport; otherwise the tier\ndecides. ``seed`` makes the single-process inline path reproducible."},"RunStatusResponse":{"properties":{"run_id":{"type":"string","title":"Run Id"},"status":{"type":"string","title":"Status"},"tier":{"type":"string","title":"Tier"},"total_trials":{"type":"integer","title":"Total Trials"},"trials_completed":{"type":"integer","title":"Trials Completed"},"created_at":{"type":"string","title":"Created At"},"summary":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Summary"},"result":{"anyOf":[{"$ref":"#/components/schemas/SimulationResult"},{"type":"null"}]},"error":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Error"}},"type":"object","required":["run_id","status","tier","total_trials","trials_completed","created_at"],"title":"RunStatusResponse","description":"Result/status for a previously-submitted run (``get_results``).\n\n``result`` carries the canonical ``SimulationResult`` once the run is\ncomplete (None while queued/running/failed); ``summary`` is the legacy raw\naggregate dict kept for backward compatibility (neumann#49)."},"SensitivityInputVariable":{"properties":{"type":{"type":"string","title":"Type"},"id":{"type":"string","title":"Id"},"baseline_value":{"type":"number","title":"Baseline Value"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},"type":"object","required":["type","id","baseline_value"],"title":"SensitivityInputVariable","description":"The perturbed input variable (krobar parity)."},"SensitivityTargetOutput":{"properties":{"node_id":{"type":"string","title":"Node Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"time_period":{"type":"integer","title":"Time Period"},"baseline_value":{"type":"number","title":"Baseline Value"},"response_curve":{"items":{"$ref":"#/components/schemas/ResponseCurvePoint"},"type":"array","title":"Response Curve"},"elasticity":{"type":"number","title":"Elasticity"},"rank":{"type":"integer","title":"Rank"}},"type":"object","required":["node_id","time_period","baseline_value","response_curve","elasticity","rank"],"title":"SensitivityTargetOutput","description":"The measured target output for one input variable (krobar parity)."},"SimulationResult":{"properties":{"contract_version":{"type":"string","const":"1.0","title":"Contract Version","default":"1.0"},"trials":{"type":"integer","title":"Trials"},"time_periods":{"type":"integer","title":"Time Periods"},"summary_statistics":{"items":{"$ref":"#/components/schemas/SummaryTimePeriod"},"type":"array","title":"Summary Statistics"},"aggregations":{"additionalProperties":{"$ref":"#/components/schemas/SummaryElement"},"type":"object","title":"Aggregations","description":"Post-simulation series metrics, keyed by the request id. Each is the per-trial distribution (percentiles + basic stats) of NPV/IRR/etc. Undefined trials (e.g. non-convergent IRR) are dropped from the distribution, so basic_stats reflect only the finite trials."}},"type":"object","required":["trials","time_periods"],"title":"SimulationResult","description":"The agent-facing result of a simulation run.\n\n``summary_statistics`` carries one entry per requested time period. Each\nelement is reduced to percentiles + basic stats, with optional histogram and\nraw per-trial arrays."},"SolveRequest":{"properties":{"distribution_type":{"type":"string","minLength":1,"title":"Distribution Type","description":"A catalog distribution, e.g. 'normal', 'triangle', 'beta'."},"min_estimate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Estimate","description":"Low end of the range (required for most types)."},"max_estimate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Estimate","description":"High end of the range (required for most types)."},"percentile_range":{"type":"number","exclusiveMaximum":1.0,"exclusiveMinimum":0.0,"title":"Percentile Range","description":"Confidence the [min,max] interval covers, e.g. 0.9 for 90%.","default":0.9},"mode_estimate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Mode Estimate","description":"Most-likely value; required for constant/bernoulli/binomial."}},"type":"object","required":["distribution_type"],"title":"SolveRequest","description":"Solve distribution parameters from a min/max range + confidence.\n\nTurns a human-style \"between X and Y, 90% confident\" estimate into\nengine-ready ``distribution_params``. Field semantics mirror the MCP\n``solve_distribution_parameters`` tool exactly; only the ``api_key`` field is\ndropped because gateway callers authenticate via signed headers."},"SolveResponse":{"properties":{"distribution_type":{"type":"string","title":"Distribution Type"},"parameters":{"additionalProperties":true,"type":"object","title":"Parameters"},"input":{"additionalProperties":true,"type":"object","title":"Input"}},"type":"object","required":["distribution_type","parameters","input"],"title":"SolveResponse","description":"Solved parameters, ready to drop into a root node's distribution_params.\n\nIdentical shape to the MCP tool's ``SolveDistributionResult`` (the handler\nreturns that model's fields verbatim): ``distribution_type`` echoes the\nsolved/requested type, ``parameters`` is the engine-ready distribution_params,\nand ``input`` is the normalized solver input the engine echoed back."},"StorageRootNode":{"properties":{"id":{"type":"string","title":"Id","description":"Unique node id within the graph."},"name":{"type":"string","title":"Name","description":"Human-readable label.","default":""},"distribution_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Distribution Type","description":"One of the catalog distributions (GET /api/v1/contract), or null for a root whose distribution was never solved. A null type stores fine but cannot simulate: /run rejects the graph."},"distribution_params":{"additionalProperties":true,"type":"object","title":"Distribution Params","description":"Params for the chosen distribution, e.g. {'mean': 100, 'std': 15}."},"interval":{"type":"integer","minimum":0.0,"title":"Interval","description":"Sample every N periods (1 = every period).","default":1},"delay":{"type":"integer","minimum":0.0,"title":"Delay","description":"Periods to wait before the first sample.","default":0},"sampling_frequency":{"type":"string","enum":["per_period","once"],"title":"Sampling Frequency","description":"'once' draws a single value reused across periods.","default":"per_period"}},"additionalProperties":false,"type":"object","required":["id","distribution_params"],"title":"StorageRootNode","description":"A root node as accepted by the STORAGE tier (neumann#167).\n\nField-for-field identical to ``RootNode`` except that ``distribution_type``\nis OPTIONAL. That single difference is the whole point: krobar's local-first\nsave (krobar-back#463) produces \"estimate-only\" roots — the user entered\n``estimate``/min/max/mode but the solve that materializes a concrete\ndistribution never ran — and neumann#153's lenient write tier promises those\nstill SAVE (flagged not-simulatable) rather than silently dropping the\nuser's data.\n\n``StoredGraphBody`` typed ``root_nodes`` as ``list[RootNode]``, so\n``RootNode``'s required ``distribution_type`` was enforced at FastAPI\nrequest-body parsing time — a 422 on the whole write, before the lenient\nstorage tier (``graph_validation.storage_valid_graph``) ever ran. This model\nmoves that check to where #153 said it belongs: the write stores the node,\n``simulation_readiness`` reports the missing type as a structured finding,\nand ``/run`` still refuses to simulate it.\n\nThis is deliberately NOT a subclass of (or base for) ``RootNode``: pydantic\nfields are mutable attributes, so mypy correctly rejects widening\n``str`` -> ``str | None`` across an inheritance edge. ``tests/\ntest_public_contract.py`` pins the two field sets together instead, so the\nduplication cannot drift silently.\n\nA PRESENT ``distribution_type`` is still validated against the catalog — a\ntypo'd type is a payload bug, not an unsolved estimate, and must not be\nstored as though it were meaningful."},"StoredEdgeResponse":{"properties":{"external_id":{"type":"string","title":"External Id"},"source":{"type":"string","title":"Source"},"target":{"type":"string","title":"Target"},"order_index":{"type":"integer","title":"Order Index"},"cfg":{"additionalProperties":true,"type":"object","title":"Cfg"},"version":{"type":"integer","title":"Version"}},"type":"object","required":["external_id","source","target","order_index","cfg","version"],"title":"StoredEdgeResponse"},"StoredGraphBody":{"properties":{"id":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Id","description":"Optional client-supplied graph id (neumann#81). When set, the graph is stored under it and a repeat create with the same id in the same tenant is an idempotent upsert. Omit to let the server generate a uuid. The whole graph-domain split keys the neumann graph id on the krobar graph id, so the gateway supplies it here."},"name":{"type":"string","minLength":1,"title":"Name","description":"Human-readable graph name."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"root_nodes":{"items":{"$ref":"#/components/schemas/StorageRootNode"},"type":"array","title":"Root Nodes"},"calc_nodes":{"items":{"$ref":"#/components/schemas/CalcNode"},"type":"array","title":"Calc Nodes"},"edges":{"items":{"$ref":"#/components/schemas/Edge"},"type":"array","title":"Edges"},"graph_metadata":{"additionalProperties":true,"type":"object","title":"Graph Metadata"},"time_period_unit":{"type":"string","title":"Time Period Unit","default":"month"},"simulation_trials":{"type":"integer","exclusiveMinimum":0.0,"title":"Simulation Trials","default":1000},"simulation_time_periods":{"type":"integer","exclusiveMinimum":0.0,"title":"Simulation Time Periods","default":12},"tags":{"items":{},"type":"array","title":"Tags"},"simulation_goal_node":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Simulation Goal Node","description":"Node id the goal is measured on."},"simulation_goal_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Simulation Goal Value","description":"Threshold the goal node is compared against."},"simulation_goal_direction":{"anyOf":[{"type":"string","enum":["MAXIMIZE","MINIMIZE"]},{"type":"null"}],"title":"Simulation Goal Direction","description":"MAXIMIZE counts trials >= value; MINIMIZE counts <= value."},"simulation_goal_time_period":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Simulation Goal Time Period","description":"0-based period to measure the goal at (defaults to last)."}},"type":"object","required":["name"],"title":"StoredGraphBody","description":"The mutable body of a stored graph (shared by create + update).\n\n``calc_nodes`` / ``edges`` reuse the canonical public contract models, so the\nsame reference-integrity rules that gate inline runs gate stored graphs on\nwrite. ``simulation_trials`` / ``simulation_time_periods`` synthesise the\n``run_params`` used to lower the graph through the shared engine validators.\n\n``root_nodes`` uses ``StorageRootNode``, NOT the simulate-tier ``RootNode``\n(neumann#167). Typing it as ``RootNode`` put that model's required\n``distribution_type`` in front of the lenient storage tier: because the field\nis typed, FastAPI validates it while parsing the request body, so an\nestimate-only root (never solved into a concrete distribution) 422'd the\nwhole write before ``GraphStoreService._validate_for_storage`` — the lenient\ntier neumann#153 added — ever ran. That contradicted #153's own acceptance\ncriterion that such a graph \"still saves, but still cannot simulate\". The\nstorage shape relaxes exactly one field; everything else, including a\nPRESENT ``distribution_type`` being a known catalog value, is unchanged."},"StoredGraphListResponse":{"properties":{"graphs":{"items":{"$ref":"#/components/schemas/StoredGraphSummary"},"type":"array","title":"Graphs"}},"type":"object","required":["graphs"],"title":"StoredGraphListResponse"},"StoredGraphResponse":{"properties":{"id":{"type":"string","title":"Id"},"surrogate_id":{"type":"string","title":"Surrogate Id"},"client_graph_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Graph Id"},"tenant_id":{"type":"string","title":"Tenant Id"},"actor_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Actor Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"graph_metadata":{"additionalProperties":true,"type":"object","title":"Graph Metadata"},"time_period_unit":{"type":"string","title":"Time Period Unit"},"simulation_trials":{"type":"integer","title":"Simulation Trials"},"simulation_time_periods":{"type":"integer","title":"Simulation Time Periods"},"tags":{"items":{},"type":"array","title":"Tags"},"simulation_goal_node":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Simulation Goal Node"},"simulation_goal_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Simulation Goal Value"},"simulation_goal_direction":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Simulation Goal Direction"},"simulation_goal_time_period":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Simulation Goal Time Period"},"sim_fields_version":{"type":"integer","title":"Sim Fields Version"},"nodes":{"items":{"$ref":"#/components/schemas/StoredNodeResponse"},"type":"array","title":"Nodes"},"edges":{"items":{"$ref":"#/components/schemas/StoredEdgeResponse"},"type":"array","title":"Edges"},"created_at":{"type":"string","title":"Created At"},"updated_at":{"type":"string","title":"Updated At"},"validation":{"anyOf":[{"$ref":"#/components/schemas/GraphValidationReport"},{"type":"null"}]}},"type":"object","required":["id","surrogate_id","client_graph_id","tenant_id","actor_id","name","description","graph_metadata","time_period_unit","simulation_trials","simulation_time_periods","tags","simulation_goal_node","simulation_goal_value","simulation_goal_direction","simulation_goal_time_period","sim_fields_version","nodes","edges","created_at","updated_at"],"title":"StoredGraphResponse","description":"A persisted graph with its normalized nodes/edges, tenant-scoped.\n\n``id`` is the externally-meaningful id the client round-trips by (neumann#81):\nthe krobar ``client_graph_id`` when one was supplied at create, else the\nserver surrogate id for id-less creates. ``surrogate_id`` is always the\nserver-generated PK (the internal FK target); ``client_graph_id`` echoes the\nsupplied krobar id (NULL for id-less creates). GET/PUT/DELETE by ``id`` are\ntenant-scoped: the client supplies its own krobar id and never the surrogate."},"StoredGraphSummary":{"properties":{"id":{"type":"string","title":"Id"},"surrogate_id":{"type":"string","title":"Surrogate Id"},"client_graph_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Graph Id"},"tenant_id":{"type":"string","title":"Tenant Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"time_period_unit":{"type":"string","title":"Time Period Unit"},"simulation_trials":{"type":"integer","title":"Simulation Trials"},"simulation_time_periods":{"type":"integer","title":"Simulation Time Periods"},"tags":{"items":{},"type":"array","title":"Tags"},"created_at":{"type":"string","title":"Created At"},"updated_at":{"type":"string","title":"Updated At"}},"type":"object","required":["id","surrogate_id","client_graph_id","tenant_id","name","description","time_period_unit","simulation_trials","simulation_time_periods","tags","created_at","updated_at"],"title":"StoredGraphSummary","description":"A lighter list-row (no node/edge expansion)."},"StoredNodeResponse":{"properties":{"external_id":{"type":"string","title":"External Id"},"kind":{"type":"string","title":"Kind"},"name":{"type":"string","title":"Name"},"order_index":{"type":"integer","title":"Order Index"},"cfg":{"additionalProperties":true,"type":"object","title":"Cfg"},"version":{"type":"integer","title":"Version"}},"type":"object","required":["external_id","kind","name","order_index","cfg","version"],"title":"StoredNodeResponse"},"StoredRunListResponse":{"properties":{"runs":{"items":{"$ref":"#/components/schemas/StoredRunSummary"},"type":"array","title":"Runs"},"total":{"type":"integer","title":"Total"},"limit":{"type":"integer","title":"Limit"},"offset":{"type":"integer","title":"Offset"}},"type":"object","required":["runs","total","limit","offset"],"title":"StoredRunListResponse"},"StoredRunRequest":{"properties":{"seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seed"}},"type":"object","title":"StoredRunRequest","description":"Optional body for a stored-graph run (neumann#69).\n\n``seed`` makes the inline single-process path reproducible. The SSE variant\nis a dedicated route (``POST /graphs/{graph_id}/runs/stream``)."},"StoredRunSummary":{"properties":{"id":{"type":"string","title":"Id"},"graph_id":{"type":"string","title":"Graph Id"},"tenant_id":{"type":"string","title":"Tenant Id"},"status":{"type":"string","title":"Status"},"requested_trials":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Requested Trials"},"completed_trials":{"type":"integer","title":"Completed Trials"},"progress_percentage":{"type":"number","title":"Progress Percentage"},"num_iterations":{"type":"integer","title":"Num Iterations"},"s3_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"S3 Key"},"result_size_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Result Size Bytes"},"summary_statistics":{"additionalProperties":true,"type":"object","title":"Summary Statistics"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"created_at":{"type":"string","title":"Created At"},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At"}},"type":"object","required":["id","graph_id","tenant_id","status","requested_trials","completed_trials","progress_percentage","num_iterations","s3_key","result_size_bytes","summary_statistics","error_message","created_at","completed_at"],"title":"StoredRunSummary","description":"A persisted SimulationRun row, tenant-scoped (neumann#69).\n\nDetailed trials / percentiles / goal-probability / XLSX are #70 — this is\nthe persisted-run header: lifecycle status, progress, the S3 pointer, and\nthe summary statistics that live on the DB row."},"StoredSensitivityDetail":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"graph_id":{"type":"string","title":"Graph Id"},"created_at":{"type":"string","title":"Created At"},"analysis_type":{"type":"string","title":"Analysis Type"},"target_node_id":{"type":"string","title":"Target Node Id"},"time_period":{"type":"integer","title":"Time Period"},"graph_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Graph Version"},"node_names":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Node Names"},"results":{"items":{},"type":"array","title":"Results"},"analysis_metadata":{"additionalProperties":true,"type":"object","title":"Analysis Metadata"}},"type":"object","required":["id","name","graph_id","created_at","analysis_type","target_node_id","time_period","results","analysis_metadata"],"title":"StoredSensitivityDetail","description":"Get-by-id response for one stored analysis (krobar parity)."},"StoredSensitivityParams":{"properties":{"target_node_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Node Id","description":"Output node to measure. Defaults to the graph's last calc node."},"time_period":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Time Period","description":"0-based period to analyse. Defaults to the last period."},"quantiles":{"anyOf":[{"items":{"type":"number"},"type":"array"},{"type":"null"}],"title":"Quantiles","description":"Explicit quantiles to sweep (0..1). Mutually exclusive with num_quantiles. Default: [0.05, 0.5, 0.95]."},"num_quantiles":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Quantiles","description":"Even count (2-10) of symmetrical quantiles around the 0.5 baseline. Mutually exclusive with quantiles."}},"type":"object","title":"StoredSensitivityParams","description":"OAT sensitivity tuning for a stored-graph run (krobar parity)."},"StoredSensitivityRequest":{"properties":{"sensitivity_params":{"anyOf":[{"$ref":"#/components/schemas/StoredSensitivityParams"},{"type":"null"}]},"analysis_metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Analysis Metadata"}},"type":"object","title":"StoredSensitivityRequest","description":"Body for a stored-graph OAT sensitivity run (krobar parity).\n\nAll fields optional: ``sensitivity_params`` carries the analysis tuning;\n``analysis_metadata`` is stored alongside the results.\n\nThere is intentionally no ``seed``: OAT sensitivity is NOT bit-reproducible.\nEach input's quantiles are read from an UNSEEDED empirical sample of its\ndistribution, so a seed could not make the output reproducible and would\nmislead. This matches the MCP ``oat_sensitivity`` tool (also seedless)."},"StoredSensitivityResponse":{"properties":{"results":{"items":{"$ref":"#/components/schemas/StoredSensitivityResult"},"type":"array","title":"Results"},"sensitivity_analysis_id":{"type":"string","title":"Sensitivity Analysis Id"},"graph_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Graph Version"},"node_names":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Node Names"}},"type":"object","required":["results","sensitivity_analysis_id"],"title":"StoredSensitivityResponse","description":"POST response — mirrors krobar's ``SensitivityResponse`` (neumann#79)."},"StoredSensitivityResult":{"properties":{"input_variable":{"$ref":"#/components/schemas/SensitivityInputVariable"},"target_output":{"$ref":"#/components/schemas/SensitivityTargetOutput"}},"type":"object","required":["input_variable","target_output"],"title":"StoredSensitivityResult","description":"One input variable's tornado entry (krobar parity)."},"StoredSensitivitySummary":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"graph_id":{"type":"string","title":"Graph Id"},"created_at":{"type":"string","title":"Created At"},"analysis_type":{"type":"string","title":"Analysis Type"},"target_node_id":{"type":"string","title":"Target Node Id"},"time_period":{"type":"integer","title":"Time Period"},"graph_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Graph Version"},"node_names":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Node Names"}},"type":"object","required":["id","name","graph_id","created_at","analysis_type","target_node_id","time_period"],"title":"StoredSensitivitySummary","description":"List item for a stored graph's analyses (krobar parity)."},"SummaryElement":{"properties":{"percentiles":{"$ref":"#/components/schemas/Percentiles"},"basic_stats":{"$ref":"#/components/schemas/BasicStats"},"histogram":{"anyOf":[{"$ref":"#/components/schemas/Histogram"},{"type":"null"}]},"raw":{"anyOf":[{"items":{"type":"number"},"type":"array"},{"type":"null"}],"title":"Raw","description":"Per-trial values; only present when raw output is requested."}},"type":"object","required":["percentiles","basic_stats"],"title":"SummaryElement","description":"Summarised result for a single node or edge at a single time period."},"SummaryTimePeriod":{"properties":{"time_period":{"type":"integer","title":"Time Period"},"nodes":{"additionalProperties":{"$ref":"#/components/schemas/SummaryElement"},"type":"object","title":"Nodes"},"edges":{"additionalProperties":{"$ref":"#/components/schemas/SummaryElement"},"type":"object","title":"Edges"}},"type":"object","required":["time_period"],"title":"SummaryTimePeriod","description":"All summarised nodes/edges for a single time period."},"TrialsDataResponse":{"properties":{"run_id":{"type":"string","title":"Run Id"},"trials_data":{"additionalProperties":{"additionalProperties":{"items":{"type":"number"},"type":"array"},"type":"object"},"type":"object","title":"Trials Data","description":"Per node, per time-period REAL per-trial values."},"page":{"type":"integer","title":"Page"},"page_size":{"type":"integer","title":"Page Size"},"total_trials":{"type":"integer","title":"Total Trials"}},"type":"object","required":["run_id","trials_data","page","page_size","total_trials"],"title":"TrialsDataResponse","description":"Paginated trial-level data per node / per time-period (nodes only).\n\nValues are the REAL engine draws, paginated by trial index, with cross-node\nrow alignment preserved (the k-th value of every node is the k-th trial)."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}