PMFlow/docs/architecture/API_CONTRACTS.md

100 KiB
Raw Blame History

API CONTRACTS

PMFlow OS

Client presentation boundary:

  • frontend/src/api/pmflowOs.ts and frontend/src/features/pmflow-os/store.tsx must convert auth/permission/access/server failures into customer-safe PMFlow OS messages. User-facing PMFlow OS pages must not expose raw provider, Axios, FastAPI credential, HTTP 401, or Could not validate credentials text.

POST /pmflow-os/projects/{project_id}/execution-progress-events

  • Purpose: record Codex / IDE / Local Bridge / GitHub agent execution results after an execution handoff has been consumed.
  • Auth: project member, OWNER, or REVIEWER; tenant comes from JWT.
  • Request body:
    • task_id: string required; must belong to the current project.
    • event_type: "branch_created" | "commit" | "pr_opened" | "pr_synced" | "test_passed" | "test_failed" | "checks_passed" | "failed" | "blocked" | "merged" | "accepted" | "manual_progress".
    • source?: "pmflow_os" | "local_bridge" | "codex" | "github_agent" | "manual".
    • repo_binding_id?: string | null.
    • branch_name?: string | null, commit_sha?: string | null, pr_number?: number | null.
    • test_summary?: string | null, blocker_summary?: string | null.
    • execution_status?: "queued" | "pushed" | "coding" | "pr_open" | "testing" | "synced" | "failed".
    • workflow_state?: string | null, summary?: string | null, delivery_id?: string | null, event_source_id?: string | null, occurred_at?: string | null.
    • delivery_artifacts?: { changed_files?: ChangedFile[], commands_run?: CommandRun[], test_outputs?: TestOutput[], screenshots?: Screenshot[], logs?: LogSnippet[], risk_notes?: RiskNote[], review_checklist?: ReviewChecklistItem[] } | null.
    • ChangedFile: { path, change_type?: "added" | "modified" | "deleted" | "renamed" | "unknown", summary?, risk_level?: "low" | "medium" | "high" }.
    • CommandRun / TestOutput: status 只允许 "passed" | "failed" | "skipped" | "blocked" | "unknown";命令输出只保存摘要或引用,不保存无限长日志。
  • Behavior:
    • Creates a ProgressEvent only; it does not run commands, push branches, create PRs, publish releases, or create formal tasks.
    • Stores a backward-compatible flat payload plus protocol_version: "execution_result_protocol_v1" and execution_result envelope with {eventType, source, status, branchName, commitSha, prNumber, testSummary, blockerSummary, repositoryFullName, delivery_artifacts}.
    • External runtimes should pass a stable delivery_id and/or event_source_id; PMFlow treats either value as an idempotency key within the same tenant/project/task and reuses the existing ProgressEvent on retry instead of creating duplicate evidence.
    • Returns the latest ExecutionSummaryProjection, allowing execution, deliveryArtifacts, artifactCompleteness, releaseGate, Team Feed, /space next action, and execution memory writeback projection to consume the same standardized result metadata.
    • artifactCompleteness is empty / incomplete / blocked / ready。缺 changed files、commands run、test outputs、UI 改动截图或 required review checklist 时保持 incomplete;failed/blocked command、test 或 checklist 进入 blocked。
    • failed / blocked / test_failed events fail-closed into releaseGate.status="blocked"; test_passed / checks_passed can only move the gate to needs_confirmation until human acceptance and execution_memory_writeback_v1 are both recorded.
    • Even after acceptance and execution memory writeback, release readiness requires artifactCompleteness.status="ready"; PMFlow does not treat a free-text test_summary alone as sufficient delivery evidence.
  • Failure semantics:
    • 404 task_not_found
    • 422 repo_binding_not_found

POST /pmflow-os/projects/{project_id}/execution-artifact-review-actions

  • Purpose: record a human or PMFlow-side review action for incomplete/blocked delivery artifacts.
  • Auth: project member, OWNER, or REVIEWER; tenant comes from JWT.
  • Request body:
    • task_id: string required.
    • action: "request_fix" | "record_fix" | "mark_recheck_ready".
    • review_item_ids?: string[], optional subset of current ExecutionSummaryProjection.artifactReview.items[].id.
    • note?: string | null.
  • Behavior:
    • Reads current artifactReview from ExecutionSummaryProjection.
    • Writes ProgressEvent(event_type="artifact_review_requested" | "artifact_fix_recorded" | "artifact_recheck_ready", payload.protocol_version="artifact_review_action_v1").
    • Returns latest ExecutionSummaryProjection; artifactReview.actionHistory restores the action from dev-sync summary.
    • This endpoint only records review/rework intent. It does not run commands, generate a branch, push code, open or merge PRs, deploy, publish, create formal tasks, or write Project Memory.
  • Failure semantics:
    • 404 task_not_found
    • 422 invalid_artifact_review_item_ids

POST /pmflow-os/projects/{project_id}/execution-artifact-rework-packages

  • Purpose: create a new runtime-pullable rework execution package from current artifact review items.
  • Auth: project member, OWNER, or REVIEWER; tenant comes from JWT.
  • Request body:
    • task_id: string required.
    • repo_binding_id?: string | null.
    • runtime_target?: "local_bridge" | "codex" | "github_agent", default local_bridge.
    • review_item_ids?: string[], optional subset of current ExecutionSummaryProjection.artifactReview.items[].id; empty means all open items.
    • note?: string | null.
  • Behavior:
    • Creates a new PromptPackage(package_kind="execution_handoff", package_payload.handoff_type="artifact_rework").
    • Package payload includes rework_contract, selected artifact_review items, current artifact_completeness, and previous delivery_artifacts.
    • Writes ProgressEvent(event_type="artifact_rework_package_created", payload.protocol_version="artifact_rework_package_v1").
    • Existing signed POST /pmflow-os/runtime/execution-packages can pull this package and returns package.reworkContract plus the usual callback contract.
    • When the runtime later posts signed /pmflow-os/runtime/execution-results with the same prompt_package_id, ExecutionSummaryProjection.artifactReview.closure links the package, pull event, result event, and current evidence coverage.
    • Closure uses latest same-name command/test/checklist evidence for blocking status, so a later passed result can close an earlier failed rework item without deleting historical evidence.
    • ExecutionSummaryProjection.releaseGate.releaseReadinessProof and acceptance.evidenceProof consume the same closure and artifact status. Once closure is resolved and artifacts are ready, historical failed artifact metadata no longer blocks release recheck, acceptance, or memory writeback; explicit failed / blocked / test_failed events remain release blocking.
    • execution_memory_writeback_v1 stores writeback_proof, release_readiness_proof, artifact_review, and artifact_completeness in Project Memory writeback metadata.
    • This endpoint creates context only. It does not execute commands, create branches, push, open or merge PRs, deploy, publish, create formal tasks, or write Project Memory.
  • Failure semantics:
    • 404 task_not_found
    • 409 artifact_review_empty
    • 422 repo_binding_not_found
    • 422 invalid_artifact_review_item_ids

POST /pmflow-os/projects/{project_id}/execution-handoffs/{prompt_package_id}/runtime-credential

  • Purpose: create a short-lived runtime ingest credential bound to one execution handoff package.
  • Auth: project member, OWNER, or REVIEWER; tenant comes from JWT.
  • Request body:
    • runtime_target?: "local_bridge" | "codex" | "github_agent", defaults from the handoff package when present.
    • allowed_sources?: ("pmflow_os" | "local_bridge" | "codex" | "github_agent" | "manual")[], defaults to the selected runtime target.
    • expires_in_seconds?: number, accepted range 300..604800, default 86400.
    • note?: string | null, audit/display hint only.
  • Behavior:
    • Loads the existing PromptPackage(package_kind="execution_handoff") and validates its project/task/repo binding.
    • Writes pmflow_execution_runtime_credentials with tenant_id / key_id / secret_hash / project_id / task_id / prompt_package_id / repo_binding_id / runtime_target / allowed_sources / status / expires_at.
    • Returns the raw secret only once. The database stores only secret_hash; runtime verification recomputes the server-side secret from SECRET_KEY + key_id and validates the stored hash.
    • Response includes keyId, secretPreview, packageEndpoint="/api/pmflow-os/runtime/execution-packages", ingestEndpoint="/api/pmflow-os/runtime/execution-results", signingAlgorithm="hmac-sha256", signatureBase="{timestamp}.{raw_body}", example headers, package pull payload, and result ingest payload.
    • Creating a credential does not execute commands, open branches, push code, create PRs, publish releases, or write Project Memory.
  • Failure semantics:
    • 404 prompt_package_not_found
    • 422 execution_handoff_required

POST /pmflow-os/runtime/execution-packages

  • Purpose: unauthenticated but signed runtime package pull for Codex / Local Bridge / GitHub agent before execution starts.
  • Auth: no JWT. The request must pass the same HMAC credential validation as runtime result ingest.
  • Required headers:
    • X-PMFlow-Key-Id
    • X-PMFlow-Timestamp, unix timestamp, accepted skew 300 seconds.
    • X-PMFlow-Signature, HMAC-SHA256 over "{timestamp}.{raw_body}"; sha256=<hex> and raw hex are both accepted.
    • X-PMFlow-Delivery-Id, optional stable idempotency key when body omits delivery_id.
  • Request body:
    • prompt_package_id: string
    • task_id: string
    • source: "local_bridge" | "codex" | "github_agent" | "manual"
    • delivery_id?: string | null
    • event_source_id?: string | null
  • Behavior:
    • Loads the runtime credential by key_id, recovers tenant/project/task/package binding from the credential, verifies status, expiry, source allowlist, handoff package and signature.
    • Returns a machine-readable package containing project, formal task, repo binding, PromptPackage, Project Memory context, quality contract, constraints, forbidden actions, callback contract, and audit metadata.
    • Records ProgressEvent(event_type="execution_package_pulled", payload.protocol_version="runtime_execution_package_pull_v1") and reuses the same D8 idempotency rule for delivery_id / event_source_id.
    • This endpoint only returns execution context and records package pickup. It never runs commands, writes host config, opens branches, pushes code, merges, deploys, publishes, or writes Project Memory.
  • Failure semantics:
    • 401 runtime_signature_invalid
    • 401 runtime_credential_expired
    • 401 runtime_source_not_allowed
    • 401 runtime_handoff_mismatch
    • 404 runtime_credential_not_found
    • 422 runtime_package_payload_invalid

POST /pmflow-os/runtime/execution-results

  • Purpose: unauthenticated but signed runtime ingress for Codex / Local Bridge / GitHub agent execution result metadata.
  • Auth: no JWT. The request must pass HMAC credential validation.
  • Required headers:
    • X-PMFlow-Key-Id
    • X-PMFlow-Timestamp, unix timestamp, accepted skew 300 seconds.
    • X-PMFlow-Signature, HMAC-SHA256 over "{timestamp}.{raw_body}"; sha256=<hex> and raw hex are both accepted.
    • X-PMFlow-Delivery-Id, optional stable idempotency key when body omits delivery_id.
  • Request body: same execution result payload as /execution-progress-events, including optional delivery_artifacts, plus required prompt_package_id.
  • Behavior:
    • Loads the runtime credential by key_id, recovers tenant/project/task/package binding from the credential, verifies status, expiry, source allowlist, repo binding, handoff package and signature.
    • Fills delivery_id from X-PMFlow-Delivery-Id when omitted, then delegates to the existing execution_result_protocol_v1 ProgressEvent write path.
    • Reuses the D8 idempotency rule: stable delivery_id or event_source_id under the same tenant/project/task returns the existing event instead of creating duplicate evidence.
    • Updates credential last_used_at/use_count; it still records metadata only and never executes code, deploys, merges, or writes Project Memory. delivery_artifacts must be metadata summaries or external artifact refs, not raw binary screenshots, unbounded logs, secrets, or host files.
  • Failure semantics:
    • 401 runtime_auth_missing
    • 401 runtime_signature_invalid
    • 401 runtime_credential_expired
    • 401 runtime_source_not_allowed
    • 401 runtime_handoff_mismatch
    • 404 runtime_credential_not_found
    • 422 invalid_runtime_result_payload

POST /pmflow-os/projects/{project_id}/extractions

  • Purpose: turn a project thread message into an open ChangeSet with pending_review ChangeItems.
  • Auth: project member, OWNER, or REVIEWER; tenant comes from JWT.
  • Request body:
    • thread_id: string
    • message_id: string
    • scope?: string, default latest_message
    • summary?: string, headline?: string
    • routing_meta?: object, audit/routing metadata only
    • llm_call_id?: string
    • proposed_items?: PMFlowProposedChangeItem[]
  • Behavior:
    • If proposed_items is present and non-empty, the endpoint preserves the existing explicit ChangeSet draft path.
    • If proposed_items is omitted or empty, the backend runs real structured AI extraction through llm_service.generate_structured_object using the dedicated change_review protected scene, pmflow_change_review_extraction_v1 Function Runtime Profile, and PROMPT_PMFLOW_CHANGE_REVIEW_EXTRACTION prompt asset, then normalizes requirements/tasks/risks/decisions into ChangeItems.
    • Success creates one pmflow_change_sets row with status=open, pending_review pmflow_change_items, and a pmflow_evidence_links row pointing to the source thread message.
    • Failure is fail-closed: no ChangeSet or ChangeItem is created. The API returns product-semantic errors such as ai_extraction_failed or extraction_evidence_insufficient.
    • This endpoint never commits Project Memory. ChangeReview remains responsible for accept/edit/defer and ChangeSet commit.
  • Response data: PMFlowChangeSetDetailResponse
    • changeSet: serialized open ChangeSet with routingMeta.aiExtraction when AI extraction was used.
    • items[]: pending_review ChangeItems.
    • evidence[]: source thread message evidence.
    • approvals[]: initially empty unless later review actions were recorded.
  • Failure semantics:
    • 404 message_not_found
    • 409 extraction_evidence_insufficient
    • 502 ai_extraction_failed

POST /pmflow-os/change-sets/{change_set_id}/commit

  • Purpose: commit reviewed ChangeSet items into the official project truth layer.
  • Auth: project member, OWNER, or REVIEWER; tenant comes from JWT.
  • Request body:
    • item_ids?: string[] optional; default commits all accepted / edited items.
    • mode: "atomic" required for C2 V1.
    • note?: string audit note only.
  • Behavior:
    • Processes only accepted / edited ChangeItems.
    • C2 V1 is atomic: any eligible item write failure rolls back the whole commit.
    • Required C2 objectType support: Requirement / Decision / Task / Risk.
    • Optional C2 objectType support: Release.
    • Unsupported for C2 V1: ModelDecision / MetricSignal, which must fail with 422 unsupported_object_type.
    • Requirement / Decision / Risk / Release write to truth_nodes.
    • Task writes truth_nodes(node_type='task') plus tasks.truth_node_id.
    • High-risk items require item-level approval with decision in ('approved','edited') and after_status in ('accepted','edited').
  • Response data:
    • changeSet: { id, status, rawStatus, committedAt, writebackAt, committedById, committedBy, committedItemIds, skippedItemIds, failedItemIds }
    • committedItems[]: { changeItemId, objectType, targetType, targetId, status, evidenceIds, semanticFactStatus, committedAt, committedById, committedBy }
    • skippedItems[]: { changeItemId, objectType, status, reason }
    • failedItems[]: { changeItemId, objectType, code, message }
    • projectTruthState?: optional backend projection after commit.
  • Failure semantics:
    • 404 changeset_not_found
    • 409 changeset_not_reviewed
    • 409 changeset_already_committed
    • 409 no_accepted_items
    • 409 high_risk_approval_required
    • 422 invalid_commit_item_ids
    • 422 unsupported_object_type
    • 422 invalid_change_payload
    • 500 commit_failed

PMFlow AI Dual-Brain Contracts

These contracts are the baseline for AI-Dual-00 and all later Space AI / Project Copilot work. PMFlow AI is one user-facing AI with two product work surfaces:

  • space_ai: the Space-level Operating Partner for cross-project attention, idea incubation, pending confirmation aggregation, AI work monitoring, and routing.
  • project_copilot: the project-level truth-bound copilot for ProjectTruthState explanation, candidate changes, evidence review, execution handoff preparation, and writeback guardrails.

Common envelope

  • Every user-facing AI answer must remain customer-safe and may expose only product-language sources, business object anchors, next actions, limitations, and process steps.
  • raw_question must stay separate from structured context. Frontends must not prepend hidden prompt text to the question.
  • Runtime payloads must carry surface_context or a stricter packet; answers must bind to visible objects whenever possible.
  • Responses should prefer answer_canvas, customer_interaction_context_packet, and answer_process_packet over free-text-only answers.
  • AI failures, insufficient evidence, structured parsing failures, and missing context must be explicit. No default objects, fake actions, or template success states are allowed.
  • Customer-facing AI surfaces must not expose provider, model, prompt body/key, raw trace, function name, table/field name, SQL, backend file path, raw source label, or platform diagnostics.

space_operating_packet v1

  • Producer: SpaceRuntimeContextBuilder plus controlled backend projections.
  • Scope: current tenant/user visible Space facts only.
  • Minimum shape:
    • packet_version: "space_operating_packet.v1"
    • visible_projects[]: {id, title, status, summary?, next_action?, health?, pending_count?, ai_work_status?}
    • saved_ideas[]: customer-safe idea seeds with {id, title, summary?, readiness?, status?, missing_questions?, recommended_next_action?}
    • pending_confirmations[]: customer-safe summaries, deep links and object_anchor; no ChangeSet commit authority.
    • ai_work_items[]: {object_ref, object_anchor?, status, summary, blocker?, next_action?}
    • drafts[]: Project Launch draft summaries; creation still requires human confirmation.
    • attention_queue[]: ordered items with {kind, object_ref, object_anchor?, reason, urgency, next_action, href?}
    • object_anchor: customer-safe object pointer {object_ref, object_type, object_id, surface, project_id, project_title, href, parent_object_ref?} used to route Space attention items back into Project Copilot surfaces without exposing raw tables, traces or backend internals.
    • automation_policy: policy_version="ai_dual_04_low_risk_proactive.v1", mode="suggest_only", low-risk levels suggest_only / prepare_only, and explicit confirmation requirements before project creation, Project Memory write, ChangeSet commit, execution handoff, external command execution, publish or deploy.
    • proactive_suggestions[]: low-risk suggestions derived from attention_queue, each with {title, reason, why_now, source_objects[], risk_level, required_confirmation, audit_event, action, href, object_ref, object_anchor?, automation_level, requires_user_confirm=true, blocked_automation[]}. These suggestions may rank, summarize, prepare navigation or prepare a preview, but they are not permission to write, publish or execute.
    • counts: project, saved idea, pending, draft, AI work, blocked/risk counts.
    • readiness: customer-visible AI availability and degradation state.
    • surface_hint?: frontend-only counts or UI hints that may supplement but must not override backend facts.
  • Allowed outputs:
    • read-only Space summary, today brief, attention ordering, idea readiness explanation, route-to-project/launch/review suggestions, AI work monitor explanation.
  • Forbidden outputs:
    • Project Memory write, ChangeSet commit, formal task creation, execution handoff, release/publish action, provider/model/prompt/platform diagnosis.
  • Audit:
    • Space AI turns must persist the final PMFlowAITurnState, runtime steps, evidence actions, model call count, and prompt attribution for every LLM call. Legacy source_strategy / allowed_executors / surface_direct_eligible fields may appear only in compatibility payloads or old logs and must not drive the Space API main chain.

project_copilot_context_packet v1

  • Producer: PMFlow OS projection layer and project copilot adapter.
  • Scope: exactly one current project plus the selected surface/object anchor.
  • Minimum shape:
    • packet_version: "project_copilot_context_packet.v1"
    • project_ref: {id, title, status, summary?}
    • surface: command_center | structured_extraction | change_review | project_memory | work_graph | execution_bridge | team_layer | release_growth
    • object_anchor?: current Requirement / ChangeItem / Task / Evidence / ExecutionPackage / ReleaseSignal / ProjectMemory node.
    • Project surfaces must restore object_anchor from customer-safe deep-link params when present: changeSetId + itemId, taskId, releaseId, or evidenceId.
    • truth_projection: customer-safe ProjectTruthState summary, not raw ORM rows.
    • change_context?: open ChangeSet, selected ChangeItem, evidence, approvals, risk and commit gate.
    • execution_context?: formal task, repo binding, prompt package, reviewer gate, artifact completeness, release readiness proof.
    • release_context?: release gate, validation, feedback, revenue/ROI/compliance/recommendation signals.
    • allowed_actions[]: answer | draft_change | review_explain | prepare_execution_handoff | route_to_surface.
    • forbidden_actions[]: explicit blocked actions and reasons.
    • automation_policy: the AI-Dual-04 low-risk proactive contract, always mode="suggest_only" for customer surfaces.
    • proactive_suggestions[]: customer-safe suggested next moves with why_now / source_objects / risk_level / required_confirmation / audit_event, automation_level=suggest_only|prepare_only, and requires_user_confirm=true.
    • limitations[]: evidence/context gaps and required human confirmations.
  • Allowed outputs:
    • project truth explanation, evidence/risk review, candidate ChangeSet draft, execution handoff preparation, release/growth fit analysis, route-to-surface suggestions.
  • Forbidden outputs:
    • cross-project portfolio ranking, platform provider/model/prompt diagnosis, ChangeSet commit, Project Memory write, external command execution, publish/deploy/delete/permission changes, or direct handoff from pending ChangeItem.
  • Audit:
    • every answer or action must preserve project_id, surface, object_anchor, action_ladder_level, allowed_actions, blocked_actions, prompt attribution, and customer-safe evidence packet references.

Prompt migration baseline

  • Runtime-migrated guarded/query/presentation prompts: PROMPT_CUSTOMER_ANSWER_COMPOSER, PROMPT_CUSTOMER_ANSWER_VERIFIER, PROMPT_RAG_QUERY_SEMANTICS, PROMPT_RAG_FOLLOWUP_ANCHOR_SEMANTICS, PROMPT_RAG_PENDING_CLARIFICATION_SELECTION_SEMANTICS, and PMFLOW_SEMANTIC_CONTEXT_DECISION_PROMPT. PROMPT_PMFLOW_AI_ROUTE_PLANNER is retained only as a legacy/deprecated prompt key placeholder for migration inventory and offline replay references; Space AI runtime must not call it for source, route, executor, analyzer, clarification, or answer-shape decisions.
  • Space AI prompt work for AI-Dual-01: Turn Runtime must understand attention, idea_incubation, route_to_project, ai_work_monitor, cross_project_summary, and external_research as goal/evidence states instead of route-planner enums; answer composer/renderers must consume final TurnState and customer-safe evidence packets.
  • Project Copilot prompt work for AI-Dual-02: prompts must consume project_copilot_context_packet, preserve action ladder boundaries, and return evidence, limitations, recommended actions, and blocked actions. Existing static frontend copilot copy is not a substitute for this contract.
  • Prompt release and replay remain platform-only. Customer Space, Project Launch, and project-level copilot surfaces must not expose prompt bodies or prompt keys.

Project Copilot

POST /pmflow-os/projects/{project_id}/project-copilot/ask

  • Purpose: project-level PMFlow AI copilot for one current project, one current surface, and one selected object anchor.
  • Auth: logged-in project member or manager; tenant comes from JWT and project membership check.
  • Request:
    • question: string is the raw user question only.
    • surface: command_center | structured_extraction | change_review | project_memory | work_graph | execution_bridge | team_layer | release_growth.
    • intent: ask | supplement | command.
    • object_anchor?: {type, id, title?} where type is project | change_set | change_item | task | release | evidence.
    • context_packet?: optional frontend packet hint. The backend must rebuild the authoritative project_copilot_context_packet.v1 from PMFlow OS projection and may only use this as a hint.
  • Behavior:
    • The backend rebuilds ProjectTruthState through PMFlowOSProjectionService, optionally reads execution-summary, resolves the requested object anchor against the current project, and returns a server-authored project_copilot_context_packet.v1.
    • The current implementation uses a deterministic renderer with model_calls=0 for low-risk truth-bound answers. It returns answer_canvas, customer_interaction_context_packet, answer_process_packet, allowed_actions, blocked_actions, and limitations.
    • AI-Dual-04 proactive behavior is represented only as automation_policy and proactive_suggestions[] in project_copilot_context_packet.v1 and response payload. Allowed levels are suggest_only and prepare_only; every suggestion carries requires_user_confirm=true. The service may prepare a navigation target, review explanation, candidate direction, or execution context preview, but may not commit ChangeSets, write Project Memory, trigger execution handoff, run external commands, publish/deploy, delete, or change permissions.
    • The route is read-only. It must not create thread messages, trigger extraction, commit ChangeSet, write Project Memory, create tasks, prepare real execution handoff, execute external commands, publish, deploy, delete, or modify permissions.
    • Frontend ProjectCopilot in real project mode must call this route instead of routing copilot questions through thread-message send + extraction. Demo mode may keep local simulated replies.
  • Failure semantics:
    • Missing project returns 404; non-member returns 403.
    • User-visible failure messages must be product semantic and must not expose traceback, prompt key, provider payload, function name, ORM rows, or raw source labels.
  • Next prompt step:
    • When model-composed project copilot answers are introduced, composer/verifier prompts must consume only project_copilot_context_packet.v1 and customer-safe evidence fields, record prompt attribution, and preserve the same action ladder and blocked action contract.

Personal Space

POST /space/pmflow-ai/threads

  • Purpose: create a user-visible PMFlow AI thread and send the first message for ordinary conversation, space/project inspection, project operating guidance, cross-project operating work, external research and AI capability status.
  • Auth: logged-in user; tenant comes from JWT.
  • Request body extends the existing Space ask body:
    • question: string is the raw user question only. Frontend must not prepend a prompt blob.
    • thinking_mode?: "auto" | "normal" | "deep".
    • action_mode?: "auto" | "standard" | "deep".
    • surface_context?: object, structured page/workbench/readiness context from the current surface.
  • Behavior:
    • The route creates or resolves a PMFlow AI thread/message projection and enters PMFlowAgentRuntimeService.run_space_turn() to create one internal pmflow_agent_runs execution record for the assistant turn.
    • Runtime executes Dynamic Agent Workspace -> LLM Step Planner -> typed read/probe/specialist tool -> Observation Ledger -> State Critic -> replan/continue/stop -> Terminal Answer Runtime.
    • PMFlowAgentRuntimeService then persists the real dynamic steps into pmflow_agent_steps / observations / artifacts / verifications / memories.
    • Runtime tools only produce observations/artifacts/deliverables. They do not directly write final customer answers.
    • Strong project operations read project world state only when explicit page/session/object anchors exist. Visible projects are candidates only.
    • Open external/market/opportunity questions must not be answered from PMFlow capability or space project list alone; the planner must use public-source tools and opportunity-discovery review or return a clear evidence boundary.
    • User-visible payloads must not expose internal labels such as project_object_required_for_world_state, world_state, packet, trace, prompt, function, route_plan, model/provider metadata, raw source labels or table/field names.
  • Response data must include:
    • thread_id
    • title
    • messages[]
    • assistant_message
  • Assistant message data may include:
    • content
    • run_id
    • work_log[] with customer-safe Chinese labels and summaries
    • artifacts[]
    • actions[]
    • confirmations[]
  • Failure semantics:
    • Upstream/runtime exceptions return a product-semantic failure message.
    • Failed steps are persisted as verifications when possible.
    • Raw traceback, prompt key, function name, provider payload, ORM row and route diagnostics must not appear in customer payloads.

POST /space/pmflow-ai/threads/stream

  • Purpose: create a PMFlow AI thread with the same business semantics as POST /space/pmflow-ai/threads, but stream customer-safe process events and final answer chunks to the workspace UI.
  • Transport: text/event-stream over authenticated POST; frontend uses fetch + ReadableStream so it can send JSON body and auth headers. This endpoint is not an unauthenticated EventSource URL.
  • Event contract:
    • run.started: PMFlow AI has accepted the turn.
    • step.started / step.completed: one customer-safe Agent OS process step. step contains id/key/label/status/status_label/display_summary/duration_ms/blocking and must not expose prompt key, provider/model, trace id, table/field names, function names or raw tool payload.
    • answer.started: final answer has passed customer payload gates and is ready to output.
    • answer.delta: one chunk of the final customer-safe answer.
    • answer.completed: complete final answer text.
    • thread.completed: authoritative persisted thread detail; frontend must replace local streaming state with this payload.
    • error: product-semantic failure message.
  • Behavior:
    • The same runtime and persistence path as the non-streaming endpoint is used. SSE is a projection of the real Agent OS execution, not a separate mock process.
    • Process events are emitted from PMFlowAIAgentRunService as the runtime completes real steps.
    • Final answer chunks are emitted only after the answer has been generated, sanitized, persisted and projected as customer-safe payload.

POST /space/pmflow-ai/threads/{thread_id}/messages

  • Purpose: continue the same PMFlow AI thread with a new user message.
  • Behavior: appends user/assistant messages to the same thread and creates a new internal Agent OS run for the assistant turn. It must not create a new visible conversation for every user message.
  • Response shape is the same thread detail shape as POST /space/pmflow-ai/threads.

POST /space/pmflow-ai/threads/{thread_id}/messages/stream

  • Purpose: continue an existing PMFlow AI thread with the same event contract as POST /space/pmflow-ai/threads/stream.
  • Behavior: preserves the existing thread/session anchor, emits customer-safe process events during the new assistant turn, and ends with thread.completed containing the updated persisted thread detail.

GET /space/pmflow-ai/threads

  • Purpose: list PMFlow AI threads for the current tenant/user.
  • Response data contains items[] with thread_id, title, message count, last message preview, current object refs and timestamps.

GET /space/pmflow-ai/threads/{thread_id}

  • Purpose: read one PMFlow AI thread with continuous messages and customer-safe per-assistant-message projections.

/space/pmflow-ai/runs*

  • Purpose: compatibility/debug read surface for durable internal Agent OS runs. Product UI must use /space/pmflow-ai/threads* as the primary conversation surface.

POST /space/ai-concierge/ask

  • Purpose: compatibility endpoint for older Space AI callers.
  • Behavior: must call the same PMFlowAgentRuntimeService.run_space_turn() path and return the same customer-safe Agent OS projection. It must not restore old route planner, task graph, executor enum, answer contract or presentation early-return as the main control path.

Saved Ideas

  • Purpose: keep pre-project idea seeds visible in /space without polluting Project Memory or PMFlow OS truth objects.
  • Boundary:
    • saved_ideas stores raw input, source, summary, readiness, missing questions, status, enrichment metadata, and optional Project Launch draft linkage.
    • Enrichment metadata is explicit: enrichment_status="ai_enriched" means the AI structured completeness pass succeeded; ai_failed means AI did not complete and the row is showing deterministic baseline fields; baseline means no AI enrichment is present.
    • Saving an idea never creates a project, task, ChangeSet, Project Memory entry, execution event, release signal, or capacity item.
    • Promoting an idea only generates a Project Launch draft and returns the user to human review. Project creation still requires POST /pmflow-launch/drafts/{draft_id}/confirm.

GET /space/saved-ideas

  • Auth: logged-in user; tenant comes from JWT.
  • Query:
    • limit?: number, default 20, max 100
    • include_archived?: boolean, default false
  • Response data: { items: SavedIdeaRead[] }. SavedIdeaRead includes id/title/raw_text/summary/source_type/source_ref/input_mode/attachments/status/status_label/ai_summary/missing_questions/readiness_score/enrichment_status/enrichment_payload/enrichment_error/enriched_at/launch_draft_id/promoted_project_id/created_at/updated_at/href.

POST /space/saved-ideas

  • Auth: logged-in user; tenant comes from JWT.
  • Request body:
    • raw_text: string
    • title?: string
    • summary?: string
    • source_type?: "project_launch" | "ai_concierge" | "logout_guard" | "feishu" | "upload" | "manual"
    • source_ref?: string
    • input_mode?: "idea" | "import" | "template"
    • attachments?: SavedIdeaAttachment[]
  • Behavior: writes one saved_ideas row for the current user and workspace. The service first tries space_saved_idea_enrichment_v1 structured AI enrichment for summary / target_user / problem / value_hypothesis / validation_signal / constraints / missing_questions / readiness_score / status / confidence; if AI is unavailable or parsing fails, it stores enrichment_status="ai_failed" with a deterministic system_baseline payload instead of pretending AI succeeded.
  • Response data: SavedIdeaRead.

PATCH /space/saved-ideas/{idea_id}

  • Purpose: update title/raw text/summary/status for the current user's own idea. When raw_text changes, the same structured enrichment attempt runs again and refreshes readiness, missing questions, status and enrichment metadata.
  • Response data: SavedIdeaRead.

POST /space/saved-ideas/{idea_id}/archive

  • Purpose: remove a saved idea from active Space lists while preserving audit/history.
  • Response data: SavedIdeaRead with status="archived".

POST /space/saved-ideas/{idea_id}/promote

  • Purpose: convert a saved idea into a reviewable Project Launch draft.
  • Behavior:
    • Calls the same structured draft generation path as POST /pmflow-launch/drafts.
    • Updates saved_ideas.status="promoted" and stores launch_draft_id.
    • Does not confirm the draft or create a project.
  • Response data: { idea: SavedIdeaRead, draft: PMFlowLaunchDraftResponse, redirect_url: "/project-launch?state=human_review" }.
  • POST /pmflow-launch/drafts rejects low-information launch input before calling the LLM with 422 and message prefix input_needs_more_info, so pure greetings or inputs without enough product/user/problem evidence stay in the supplement-input path instead of producing an empty draft.
  • Project Launch taskized generation:
    • POST /pmflow-launch/draft-jobs creates a pmflow_launch_draft_jobs row with job_id / revision_id / status=queued, supersedes active jobs for the same user, and starts the structured generation worker. Response returns job status only; clients must poll.
    • GET /pmflow-launch/draft-jobs/{job_id} returns queued | running | superseded | completed | failed | cancelled; completed includes the generated PMFlowLaunchDraftResponse and changed_fields.
    • POST /pmflow-launch/draft-jobs/{job_id}/cancel marks a queued/running job as cancelled. If the provider call already completed, workers must ignore non-running jobs before persisting a draft.
    • POST /pmflow-launch/drafts/{draft_id}/revise creates a new merge_supplement job using the parent draft plus the user's supplement; it does not confirm or write a project.
  • Project Launch draft generation uses the managed PROMPT_PMFLOW_LAUNCH_DRAFT active release when available. The expected structured draft is a monetizable MVP launch plan, targeting 7-10 requirements, 10-16 tasks, 4-7 risks and 3-6 decisions; count or business-loop gaps are surfaced in draft warnings instead of silently accepting a thin feature-demo plan.

AI Readiness

GET /ai-readiness/project-launch

  • Purpose: derive the customer-facing Project Launch AI readiness state from backend runtime facts, not from frontend local state.
  • Auth: logged-in user; tenant comes from JWT.
  • Behavior:
    • Reads platform runtime configuration from the platform runtime tenant, including integrations(type='llm_engine') and published integrations(type='ai_capability_slots').active.slots.
    • Verifies the Project Launch scene contract, the published structured slot, the bound runtime connection state, structured output / JSON Schema capability evidence, and the latest tenant-scoped ai_call_logs(function_name='pmflow_launch_draft_v1').
    • Returns customer-safe copy and actions by default. Supplier, slot, probe, recent call, raw status and platform repair actions are exposed only inside platform / platform_diagnostic for platform operations views.
    • can_generate_project_draft=true only when the required runtime, structured slot, capability evidence and latest draft smoke/call evidence are all healthy. Missing active structured slot, unavailable runtime or missing capability proof keeps Project Launch draft generation blocked.
  • Response data: AIReadiness
    • scene: "project_launch"
    • status: "ready" | "blocked" | "recovering" | "unknown"
    • customer_state, title, summary, short_label, updated_at_label
    • can_generate_project_draft: boolean
    • blockers[], customer_actions[], workspace_owner_actions[]
    • platform.checks, platform.blockers, platform.latest_call, platform.last_checked_at
    • platform_diagnostic

POST /ai-readiness/project-launch/check

  • Purpose: run a protected Project Launch smoke check without creating a draft or project.
  • Auth: platform AI operations capability, via platform.ai_routing.manage.
  • Behavior:
    • Calls the same pmflow_launch_draft_v1 structured generation path used by real Project Launch, with routing_meta.tier_alias="structured" and source="system_smoke".
    • Normalizes and validates the generated draft payload, but does not write pmflow_launch_drafts, projects, Project Memory, tasks, ChangeSet or semantic facts.
    • Updates the returned readiness payload from the fresh smoke result and latest ai_call_logs evidence.
  • Response data: same as GET /ai-readiness/project-launch, with platform.last_smoke_error when the smoke check fails.

Platform AI Operations

Provider code boundary

  • Runtime provider identity must come from configured integrations(type='llm_engine').config.engines[*].provider; UI, API, audit and routing code may display product labels, but must preserve the raw configured provider code separately.
  • DashScope/Qwen runtime provider code is dashscope. The old internal provider code glm has been removed and must not be reintroduced as an alias, fallback, display value or audit value. glm-5 may still appear only as a model name when a configured provider points to that model.
  • Historical integrations.config and ai_call_logs rows are migrated by backend/alembic/versions/20260429_rename_glm_provider_to_dashscope.py; new writes must persist dashscope for DashScope/Qwen suppliers and keep provider_label / runtime_label / engine_name as display-only fields.

Prompt operations center

  • Scope: /prompt-assets* is platform-only and requires platform.ai_routing.manage. It is not a customer workspace Prompt strategy surface and must not be exposed in Space, Project Launch or project-level AI copilot.
  • Main read endpoints:
    • GET /prompt-assets
    • GET /prompt-assets/{prompt_key}
    • GET /prompt-assets/{prompt_key}/quality-summary
    • GET /prompt-assets/{prompt_key}/golden-cases
    • GET /prompt-assets/{prompt_key}/releases/{release_id}/checks
    • GET /prompt-assets/{prompt_key}/releases/{release_id}/replay-runs
    • GET /prompt-assets/{prompt_key}/replay-runs/{run_id}
    • GET /prompt-assets/{prompt_key}/releases/{release_id}/watch-summary
  • Main write endpoints:
    • POST /prompt-assets/{prompt_key}/releases
    • POST /prompt-assets/{prompt_key}/releases/{release_id}/activate
    • POST /prompt-assets/{prompt_key}/releases/{release_id}/rollback
    • POST /prompt-assets/{prompt_key}/releases/{release_id}/checks/run
    • POST /prompt-assets/{prompt_key}/golden-cases
    • POST /prompt-assets/{prompt_key}/golden-cases/from-call/{ai_call_log_id}
    • POST /prompt-assets/{prompt_key}/releases/{release_id}/replay-runs
  • Golden case request supports case_type, priority, scenario_key and tags. priority=blocking failures block guarded release activation; important/observation failures are warning-only and require human review.
  • Replay request supports mode=contract_smoke|compare|llm_compare, include_llm, judge_enabled, case_status and max_cases. include_llm=true forces llm_compare and caps max cases. LLM replay must call llm_service with explicit routing_meta (prompt_key, prompt_release_id, prompt_source, tier_alias, scene_key, run_id) and must not hardcode provider/model.
  • Replay case results persist deterministic contract status plus optional baseline_ai_call_log_id, candidate_ai_call_log_id, judge_score, judge_label, judge_reason, risk_flags_json, latency and cost estimate. Judge rubric comes from backend/app/config/ai_prompt_eval_rubrics.py.
  • Release watch summary returns 24h/7d quality windows, structured_invalid_24h, fallback_rate_24h, recent failures and recommendation=healthy|watch|needs_review|rollback_suggested. It is advisory only and must not auto-rollback.
  • inline_discovered and needs_migration assets are read-only inventory until their runtime call sites are migrated to PromptRuntimeService / PromptReleaseService; UI and API copy must not imply these prompts are already configurable in production runtime.

Agent run full-chain audit

  • Scope: /agent-run-audits* is platform-only and requires platform.audit.view. It is not a customer workspace surface and must not be exposed in Space, Project Launch or project-level AI copilot.
  • Read endpoints:
    • GET /agent-run-audits
    • GET /agent-run-audits/{public_run_id}
  • Data sources:
    • pmflow_agent_runs for one user-triggered PMFlow AI turn.
    • pmflow_agent_steps / pmflow_agent_observations / pmflow_agent_artifacts / pmflow_agent_verifications / pmflow_agent_memories for Agent OS nodes, facts, gaps, deliverables and gates.
    • pmflow_ai_messages for the user/assistant transcript projection attached to the run.
    • ai_call_logs.agent_run_id / agent_step_key for external model/API calls made under the same run.
  • Runtime attribution:
    • PMFlowAgentRuntimeService.run_space_turn() binds the durable public_run_id into runtime audit context before delegating to PMFlowAIAgentRunService.
    • GoalFrame, Step Planner, Evidence Normalizer, State Critic and Answer Runtime bind their node key before calling llm_service.
    • llm_service._log_ai_call() persists agent_run_id, agent_step_key, latency, routing metadata and provider request/response/attempt payloads.
  • Response behavior:
    • List returns run summaries, status counts, step/observation/artifact/verification counts and linked AI-call counts.
    • Detail returns transcript messages, chronological timeline, node payloads, observations, artifacts, verifications, memories and linked AI-call details with redacted provider payloads.
    • Platform detail may expose provider/model/prompt/routing diagnostics and redacted API payloads. Customer payloads must not expose raw run ids, step ids, prompt keys, provider payloads, tool trace or internal exceptions.

Signal & SSTC

All /projects/{project_id}/... SSTC and model-capability context read endpoints must enforce project visibility before returning business data: project member, OWNER, or REVIEWER. This includes overview, stages, risks, governance, chain, charters, signals, tasks, releases, reviews, truth nodes, and experiments.

Workspace / Membership

Product language uses workspace/space; the compatibility table name remains tenants.

POST /auth/phone/send-code

  • Purpose: send an SMS-style verification code for phone login, self-registration, or invitation binding.
  • Request body:
    • phone_country_code: string, default +86
    • phone_number: string
    • purpose?: "login" | "bind_invitation" | "reset"
    • invite_token?: string
  • Behavior:
    • Phone is normalized to global users.phone_e164; duplicate accounts for the same verified phone are not allowed.
    • Development environments may return dev_code to keep local verification testable. Production must not expose the code to users.

POST /auth/phone/verify

  • Purpose: verify the phone code, log in the account, and create the account if it does not exist.
  • Request body:
    • phone_country_code: string, default +86
    • phone_number: string
    • code: string
    • purpose?: "login" | "bind_invitation" | "reset"
    • name?: string
    • invite_token?: string
  • Behavior:
    • If the phone has no existing account, the backend creates a global user account plus a personal workspace.
    • If invite_token is present and bound to the same verified phone, the backend accepts the team invitation and switches the active workspace to that team.
    • Existing users keep their personal workspace; joining or leaving a team never transfers ownership of the account itself.
  • Response data: regular login payload with access_token, token_type, user.workspace_context, and user.platform_context.
    • workspace_context describes the customer's active personal/team workspace membership.
    • platform_context is PMFlow-internal access only: { has_platform_access, roles, capabilities }. A customer workspace OWNER does not imply any platform capability.

POST /auth/register

  • Purpose: create a global account plus that user's personal workspace.
  • Behavior: compatibility username/password registration path. The preferred user-facing path is phone verification via /auth/phone/verify. The new user becomes OWNER of the personal workspace; this workspace is not removed when the user later leaves team workspaces.

Platform membership

  • Table/model: platform_memberships.
  • Purpose: grant PMFlow-internal operators access to the platform AI operations control plane.
  • Roles: PLATFORM_OWNER, PLATFORM_ADMIN, AI_OPS, SUPPORT, BILLING_OPS, SECURITY_AUDITOR.
  • Shape: one user may hold multiple platform roles; uniqueness is user_id + role, and platform_context.capabilities is the union of active roles.
  • Boundary: platform roles are not workspace roles. They never come from tenant_memberships.role or legacy users.role.
  • Bootstrap: PMFLOW_PLATFORM_ADMIN_USERS and PMFLOW_AI_OPS_USERS may grant temporary env-based platform access before DB grants exist.

GET /workspaces/me

  • Purpose: list all active workspaces for the current account.
  • Response data: { active_workspace, workspaces[] }; each workspace includes workspace_type (personal or team) and membership role.

POST /workspaces/teams

  • Purpose: create a small-team workspace from a solo account.
  • Behavior: current user becomes OWNER and the new team workspace becomes active.

POST /workspaces/invitations

  • Purpose: invite a member by phone into the current team workspace.
  • Auth: active workspace role must be OWNER or REVIEWER; only OWNER may invite REVIEWER.
  • Request body:
    • phone_country_code: string, default +86
    • phone_number: string
    • role: "OWNER" | "BUILDER" | "OPERATOR" | "REVIEWER"
    • email?: string, optional compatibility/contact field
    • project_ids?: number[]
  • Behavior: invite may include initial project_ids to create project membership after acceptance. Re-inviting the same pending tenant_id + phone_e164 refreshes the token and role instead of creating duplicate pending invitations.

POST /workspaces/invitations/accept

  • Purpose: accept a team invitation.
  • Behavior: legacy token acceptance remains supported. Phone-bound invitations require the accepting account's verified phone to match the invitation phone. Existing users keep their personal workspace; new users created from an invitation also receive a personal workspace before joining the team.

POST /workspaces/{tenant_id}/leave

  • Purpose: leave a team workspace.
  • Boundary: personal workspaces cannot be left; the last OWNER of a team must transfer ownership before leaving.

GET /projects/

  • Purpose: list project rows or summary rows for project index and personal Space aggregation.
  • Auth: logged-in user; tenant comes from JWT.
  • Query:
    • summary?: 0 | 1
    • status?: string
    • assigned_role?: string
  • Visibility:
    • OWNER and REVIEWER receive all non-filtered projects in the current tenant.
    • Other roles only receive projects they own (projects.owner_id) or projects linked through user_projects.
    • The same visibility rule applies to GET /projects/{project_id}; inaccessible projects return 404 rather than leaking existence.
  • Response data:
    • summary=1: { projects: ProjectSummary[] }
    • otherwise: Project[]

POST /projects/

  • Purpose: create a project shell/title and membership record. This endpoint does not generate requirements, tasks, risks, or Project Memory.
  • Auth: OWNER or REVIEWER; tenant comes from the active workspace membership.
  • Request body:
    • title: string
    • description?: string
    • status?: string, default active
    • domain_id?: number
    • assigned_role?: string
    • member_user_ids?: number[]
  • Behavior:
    • Project titles are compacted and must be unique per tenant_id across non-inactive projects.
    • A duplicate title returns 409 project title already exists.
    • The endpoint never calls AI and never writes truth_nodes, tasks, ChangeSets, or semantic facts.
  • Response data: serialized project row { id, title, description, status, domain_id, assigned_role, signal_count, created_at, updated_at }

GET /ai-pmo/work-items

  • Purpose: compatibility read model for Space legacy manual gates and draft confirmations.
  • Auth: logged-in user; tenant comes from JWT.
  • Visibility:
    • OWNER and REVIEWER may inspect tenant-level legacy work items.
    • Other roles only receive work items owned by themselves (work_items.owner_user_id) or bound to a project they can access through user_projects.
    • Unbound legacy work items without owner_user_id are hidden from non-manager users.
  • Boundary: this endpoint is not a team inbox product surface; Space consumes it only as a compatibility adapter.

GET /projects/{project_id}/signals

  • Response data:
    • items[] includes planner fields:
      • planner_status: "pending" | "completed" | "failed"
      • planner_analyzed_at: string | null
      • planner_assignee_user_id: string | null
      • strategic_analysis: object

Model Routing

GET /model-routing/functions/{function_name}

  • Purpose: query function-level routing diagnostics for hidden Route Lab. This is not shown in member, team-lead, or regular AI Ops navigation.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Response data:
    • function_name
    • tier
    • source: "default" | "override"

PUT /model-routing/functions/{function_name}

  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • UI exposure: hidden from the current Route Lab UI. Future exposure must add reason, TTL, dry-run, audit review, and auto-expiry controls before operators can edit function-level overrides.
  • Request body:
    • tier_alias: "low" | "high"
  • Side effects:
    • persist override into integrations(type='model_routing')
    • append audit to operation_logs
  • Boundary:
    • The API only accepts slot aliases, not provider/model/base URL strings; arbitrary model-name editing remains owned by provider connection setup.
    • Protected high-requirement functions such as requirement planning and assignee matching cannot be downgraded to low; the service returns a validation error instead of saving an override that would violate scene-slot capability requirements.

AI Routing & Providers

  • UI placement: split by control plane.
    • Customer workspace UI under /ai-config only shows AI usage settings: readiness, team policy, input sources, knowledge, MCP template use, and quotas.
    • PMFlow platform AI operations UI under /platform/* owns provider health, global routing, route/context governance, semantic facts, prompt/eval diagnostics, and cross-tenant operations metrics.
    • Project pages consume AI state only through AI 副驾 status and read-only inherited policy summaries.
  • Platform AI Ops UI is now menu-split under the AI runtime layer:
    • /platform: platform runtime overview, affected scenes, diagnostics, and next actions; old /platform/ai-routing-console redirects here for compatibility.
    • /platform/ai-routing-providers: provider/runtime connection, independent enable/disable state, masked credential state, connection test state, normalized capability matrix, executable capability probe evidence, and one global default fallback runtime.
    • /platform/ai-routing-slots: PMFlow capability slots; fast/deep are configurable now, structured is consumed by llm_service.generate_structured_object once published active, long-context is consumed only by explicit long-document/long-thread/cross-project-context calls, and tool is consumed only by explicit tool-calling or MCP execution-planning calls. External-query/private/multimodal remain reserved candidate slots. A slot consumes enabled supplier runtimes through primary runtime + fallback chain, publish validation checks provider capabilities and probe evidence, and business/runtime code consumes published active slots instead of hardcoded model names.
    • /platform/ai-routing-scenes: business-scene to capability-slot matrix; advanced function details are hidden by default.
    • /platform/ai-routing-costs: call cost, upgrade cost, quota/cache gaps, and provider usage integration gaps.
    • /platform/ai-routing-failures: sanitized risk diagnostics and recent failure samples.
    • /platform/ai-call-traces: AI call trace ledger for provider/model invocations, redacted prompt/response previews, routing metadata, slot evidence, latency/token/cost estimates, and trace detail drill-down.
    • /platform/prompt-assets: Prompt asset inventory and operation view; lists registry prompts, default seed prompt availability, active/draft prompt releases, call sites, risk level, release policy, and inline prompt migration gaps.
  • These platform menus consume GET /ai-routing/admin-console, GET/PUT/POST /ai-routing/capability-slots*, POST /ai-routing/diagnostics/run, GET /ai-call-traces*, and GET/POST /prompt-assets*; provider writes are owned by /ai-steward/llm-engines. Runtime route mutation remains restricted to platform AI Ops. Provider rows expose available_actions so the UI only renders operations that are valid for the saved connection state.

LLM Engine Provider Connections

  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Storage: integrations(type='llm_engine') under the platform AI Ops runtime scope. The database table remains tenant-scoped for compatibility, but platform supplier/runtime config is pinned to the internal platform runtime scope (PMFLOW_PLATFORM_RUNTIME_TENANT_ID, default 1) and is not a customer workspace setting. Existing active_engine_id is treated as legacy compatibility for default_fallback_engine_id.
  • Runtime semantics:
    • Multiple supplier connections may be enabled at the same time.
    • enabled=false connections are retained for editing/testing history but skipped by runtime routing, low/high tier selection, and low-to-high escalation.
    • default_fallback_engine_id is the global fallback when no function rule, capability slot, or tier route resolves. It is not a supplier enable switch.
    • Connection tests update connection_status, last_test_status, last_test_at, and last_error_summary; they do not by themselves make a connection the default fallback.
    • Each connection stores a normalized capabilities object inside integrations(type='llm_engine').config.engines[*]; legacy rows without capabilities are normalized at read time using provider/model defaults so UI and validation do not crash.
    • Capability fields currently include structured_output, json_schema, tool_calling, long_context, max_context_tokens, vision, audio, local_only, private_deployment, external_search_ready, avg_latency_ms, cost_tier, and reliability_tier.
    • Capability audit fields include the normalized nested capability_probe object plus backward-compatible flat fields capability_source, capability_probe_status, capability_last_verified_at, capability_blocking_reasons, and capability_evidence. capability_probe is stored inside the engine config and has {status, last_verified_at, verified_capabilities, evidence, source} where source is inferred | manual | probed; each evidence row records status/method/evidence_strength/request_summary/response_summary/failure_code/latency_ms and may carry operator evidence metadata (source_type/source_url/source_note/verified_by/verified_at/expires_at). Read responses also expose declared_capabilities and backend-derived effective_capabilities; legacy rows without capability_probe normalize to status=untested and do not crash old runtime reads.
  • Endpoints:
    • GET /ai-steward/llm-engines: list masked connections, settings, normalized capabilities, available_actions, and default_fallback_engine_id.
    • POST /ai-steward/llm-engines: create an enabled supplier connection; accepts optional capabilities; optional set_active remains accepted for backward compatibility and now means “set as default fallback”.
    • PUT /ai-steward/llm-engines/{engine_id}: update name/provider/model/base URL/key/capabilities and reset connection test state when runtime fields change.
    • PUT /ai-steward/llm-engines/{engine_id}/enabled: enable or disable a saved connection.
    • POST /ai-steward/llm-engines/{engine_id}/default-fallback: set the global fallback runtime; only enabled connections with connection_status=available can be selected.
    • POST /ai-steward/llm-engines/{engine_id}/test: test one enabled saved connection using its saved provider/model/base URL/key.
    • POST /ai-steward/llm-engines/{engine_id}/capability-probe: only runs for enabled connections that already passed connection test; accepts mode=quick|full|advanced, optional targets[], and allow_high_cost. The default full plan runs basic chat, a low-cost model self-report reference call, plus the declared capability scope: structured JSON parse, independent JSON Schema parameter, tool-calling, streaming observability, and long-context declared-window gates only when long-context is declared or explicitly targeted. Model self-report is stored as status=declared_only/evidence_strength=model_self_report; it is visible in provider evidence and AI call audit because it is a real upstream call, but it never counts as protected slot verified evidence or aggregate probe pass/partial/fail status. Provider UI must render model self-report only as a separate reference card, not as a probe-detail capability pill; the long-context probe-detail row is the single user-facing capability item for context window status. Streaming is a transport/runtime trait for stream=true incremental responses, not a declared model capability matrix item; provider UI may show it in probe detail and a separate runtime traits area, but must not mix it into the verified model capability list. Declared capabilities must be displayed without arbitrary truncation; if any declared capability lacks live/provider-contract/operator evidence, aggregate status cannot be passed and must stay partial or untested. Undeclared optional capabilities do not produce blocking failures or downgrade the aggregate probe status. Long-context gates read the configured max_context_tokens; provider/model specs that PMFlow knows from official contracts, such as DashScope qwen-plus, are stored as status=verified/evidence_strength=provider_contract without sending high-cost long text to the endpoint. Unknown provider declared windows remain declared_only and do not count as verified slot evidence. A verified higher long-context window covers lower threshold rows such as 32K/128K for aggregate status and UI display. Results write back into capabilities.capability_probe, capability_evidence, and derived effective_capabilities without adding a migration.
    • POST /ai-steward/llm-engines/{engine_id}/capability-attest: platform operator manually confirms a high-cost capability evidence item, currently scoped to capability_key=long_context. The request records tested_tokens, evidence source type, optional source URL/note, and optional expiry. It writes evidence_strength=operator_verified/method=operator_attestation into capability_probe.evidence and compatibility capability_evidence, updates derived effective_capabilities, and can satisfy long-context protected slot publishing until the evidence expires. This endpoint does not call the upstream provider endpoint and therefore does not create an ai_call_logs row; AI call audit continues to show only real upstream endpoint interactions.
    • DELETE /ai-steward/llm-engines/{engine_id}: delete a saved connection only after it is disabled and is not the default fallback.

Capability Slots

  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Storage: integrations(type='ai_capability_slots') under the same platform runtime scope as provider connections (PMFLOW_PLATFORM_RUNTIME_TENANT_ID, default 1).
  • Runtime semantics:
    • Provider connections are the runtime inventory; capability slots bind enabled provider connections into PMFlow ability abstractions.
    • Slot config is release-controlled: edits write draft.slots; only publish promotes the draft into active.slots. Runtime code reads active slots only and never consumes unpublished draft.
    • low/high tier resolution, control-plane rule resolution, function override resolution, and low-to-high escalation first consume active slot binding when present.
    • backend/.control_plane/pmflow-routing-rules.json remains the baseline/default rule pack and cold-start fallback, not the only live binding source once a slot is configured.
    • Disabled provider connections cannot be saved as primary or fallback slot runtimes.
    • Draft validation applies SLOT_REQUIREMENTS from backend/app/services/ai_routing_governance_service.py: high forbids local-only/Ollama, structured requires structured_output + json_schema, long-context requires long_context and max_context_tokens >= 32768, and tool requires tool_calling. Structured/tool/long-context are configurable draft slots; external/private/multimodal remain non-configurable candidate slots and cannot be saved as runtime bindings.
    • Provider capability probing treats long_context as the provider's configured max_context_tokens window, not as a hard-coded 32K test. A provider configured with 16K verifies that declared 16K window when the provider/model has a known official contract covering it, but it still cannot satisfy the long-context slot publish gate unless max_context_tokens >= 32768; long_context_32k/128k are explicit threshold probes and slot-publish gates only. Editing provider/model/base URL/API key or declared capabilities invalidates previous capability probe evidence and resets the engine to capability_probe_status=untested; name-only edits preserve evidence.
    • For structured/tool/long-context slots, validation distinguishes missing capability, missing probe evidence, and stale probe evidence: *_capability_missing means the normalized declared capability is false or below threshold; *_capability_evidence_missing means labels claim support but no verified capability_probe.evidence/compatibility capability_evidence with live, provider-contract, or operator-verified evidence strength exists; *_capability_evidence_stale means verified evidence is older than AI_CAPABILITY_PROBE_EVIDENCE_TTL_DAYS (default 90) or its explicit expires_at has passed. declared_only/manual/inferred/model_self_report evidence never satisfies protected slot publishing. low can publish without probe evidence but returns a warning.
    • Runtime effect is release-controlled: generate_structured_object only consumes the published active structured slot. Draft structured bindings are visible for validation/review but do not affect runtime until publish succeeds. When an active structured slot exists, runtime tries the structured primary first and then its fallback chain, skipping disabled/deleted runtimes and runtimes that do not satisfy structured_output + json_schema. If all configured structured slot runtimes fail after invocation, the call fails explicitly instead of falling back to templates or an unrelated low/high route. If the published active structured slot is configured but has no usable runtime before invocation, protected structured functions fail explicitly with a structured-slot runtime error; non-protected structured calls may fall back to the existing high/low/default path only with degraded routing metadata.
    • Long-context and tool runtime effects are narrower than structured: runtime consumes active long_context only when routing_meta explicitly requests slot_key/planned_tier/tier_alias=long_context, and consumes active tool only when routing_meta explicitly requests tool or uses MCP execution-planning modes execution_mode=local_planner|local_worker. These slots skip disabled/deleted runtimes and runtimes missing long_context + max_context_tokens >= 32768 or tool_calling. If the requested active slot is configured but has no usable runtime, the call fails with {slot}_slot_runtime_unavailable; if no active slot is published, the existing low/high/control-plane path remains in force. External-query/private/multimodal slots are not runtime consumers in this phase even if an active candidate binding exists.
    • Capability slot routing metadata includes slot_key, slot_version, slot_runtime_source=active_slot, slot_fallback_index, and slot_degraded=false; degraded non-protected structured fallback uses slot_runtime_source=active_slot_degraded and slot_degraded=true.
    • Slot detail payloads expose candidate_engines[] for runtimes satisfying the slot requirements and blocked_candidate_engines[] with product-level gap_reasons[] for enabled runtimes that are missing capability, missing probe evidence, or stale evidence.
    • Deep/high slot is protected and cannot enable customer-space downgrade; high slot cannot publish a local Ollama runtime.
    • Existing legacy {slots: ...} configs are read as both active and draft during normalization so upgrades do not drop live routing.
  • Endpoints:
    • GET /ai-routing/capability-slots: returns active_version, draft_version, dirty, validation, history, active_slots, draft_slots, configurable runtime slots, external-query provider-chain slots, and non-configurable candidate slots with masked runtime metadata.
    • PUT /ai-routing/capability-slots/{slot_key}/draft: update primary_engine_id, fallback_engine_ids, failure_policy, and allow_scene_downgrade for configurable low/high/structured/tool/long_context draft slots; for external_query, the same request fields carry primary_provider_id and fallback_provider_ids and are normalized into the slot binding as primary_provider_id / fallback_provider_ids / verifier_required=true / source_filtering_required=true / failure_policy=explicit_fail. The endpoint appends operation_logs(entity_type='ai_capability_slot', action='draft_update'). private/multimodal return a product error because they are candidate slots and do not consume runtime in this phase.
    • PUT /ai-routing/capability-slots/{slot_key}: backward-compatible alias for draft update; it no longer makes runtime routing immediately consume the change.
    • POST /ai-routing/capability-slots/validate: validate draft slots for missing/disabled/test-failed runtimes, duplicate fallback, high-slot Ollama, protected downgrade, capability requirement misses, missing capability evidence, and stale capability evidence.
    • POST /ai-routing/capability-slots/publish: promote draft slots to active when validation has no critical item, generate a release version, and append operation_logs(entity_type='ai_capability_slot_release', action='publish').
    • POST /ai-routing/capability-slots/rollback: restore a prior published slot snapshot as a new active version and append operation_logs(entity_type='ai_capability_slot_release', action='rollback').

GET /ai-routing/overview

  • Purpose: platform AI routing overview for PMFlow AI operators.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Response data:
    • config_version, config_updated_at, source_of_truth
    • slots[]: low/high slot summaries with Chinese labels, provider/model display summary, connection state, capability coverage, and masked key status.
    • capability_slots[]: configurable low/high/structured/tool/long_context/external_query slots and candidate private/multimodal slots. LLM slots include primary_engine_id, fallback chain, failure policy, protected state, requirements, capability coverage, candidate count, candidate runtime previews, and blocked candidate reasons. external_query includes primary_provider_id, fallback_provider_ids, verifier_required, source_filtering_required, and external_provider_registry status for MCP adapter, bounded live search fallback, verifier, and fail-closed source filtering.
    • metrics: recent 24h/7d calls, failures, failure rate, escalation rate, structured failure rate, average latency, and cost estimate.
    • diagnostics[]: risk cards such as high slot unavailable, same runtime for low/high, protected downgrade, structured failure spike, or local Ollama scope risk.
  • Boundary: no cleartext key, api_env, prompt, raw provider secret, raw error, or raw routing meta.

GET /ai-routing/team-policy

  • Purpose: team-lead-facing business policy view for project launch, requirement structuring, task breakdown, assignee matching, internal QA, external query, Feishu understanding, and Feishu reply.
  • Auth: current workspace OWNER or REVIEWER.
  • Response data:
    • strategy: quality_first | balanced | speed_first
    • scenes[]: Chinese business scene policies, preferred mode, escalation rule, fallback behavior, and editable business note.
    • automation_boundary, budget_guard, quality_targets, updated_at, updated_by
  • Boundary: team policy is saved product governance state only; it does not rewrite llm_service runtime routing in v1.

PUT /ai-routing/team-policy

  • Purpose: save team AI policy display/governance state.
  • Auth: current workspace OWNER only via can_approve_ai_routing_change.
  • Request body:
    • strategy?: "quality_first" | "balanced" | "speed_first"
    • scenes?: [{ key, policy, mode?, human_confirmation?, protected? }]
    • automation_boundary?: string
    • budget_guard?: { enabled?: boolean, monthly_budget_cny?: number | null, alert_threshold_ratio?: number }
    • quality_targets?: string[]
  • Side effects:
    • persist into integrations(type='ai_team_policy')
    • append operation_logs(entity_type='ai_routing_policy')
  • Boundary: never writes backend/.control_plane/pmflow-routing-rules.json, provider secrets, or model-routing overrides; audit payload contains business policy only, not provider/model/runtime fields.

GET /ai-routing/admin-console

  • Purpose: AI admin/operator console aggregating provider connection summaries, capability slots, post-publish slot observability, business-scene routes, recent failure samples, protected scenes, and supplier/runtime diagnostics.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Response data:
    • providers[]: display-only provider health, enable state, fallback marker, connection test state, masked key state, normalized capability tags, capability source, probe status, last verified time, probe error summaries, probe blocking reasons, and state-derived available_actions.
    • capability_slots[]: configurable low/high/structured/tool/long_context/external_query slot binding summaries and candidate private/multimodal placeholders with requirements, coverage, missing capability labels, missing evidence labels, stale evidence labels, candidate runtimes, and external provider registry state for the external-query slot.
    • capability_slot_release: release-control payload from GET /ai-routing/capability-slots; the UI uses draft slots for editing and active slots for current runtime display.
    • slot_observability[]: post-publish read model for active low/high/structured/long_context/tool/external_query slots. Each item includes slot_key, slot_label, active_version, active_runtime, and windows.last_24h / windows.last_7d with status=sampled|empty, total_calls, failed_calls, failure_rate, fallback_hits, fallback_rate, degraded_calls, degraded_rate, active_slot_calls, active_slot_degraded_calls, average_latency_ms, estimated_cost, source labels, and sanitized recent_failure_samples[]. Aggregation is based on ai_call_logs routing metadata when present (slot_key, slot_runtime_source, slot_fallback_index, slot_degraded) and compatible slot columns (planned_tier/executed_tier/routing_decision) for old logs. Empty windows return zero counts and sample_state_label=暂无运行样本; cost and latency are operational estimates from logs, not provider bills or SLA measurements.
    • external_query publish validation fails closed when no external provider is available, neither MCP adapter nor bounded live search fallback is available, verifier is unavailable, source filtering is not fail-closed, or failure policy is not explicit_fail. Runtime only consumes the active external-query slot after route_mode=external; internal query and unpublished drafts do not consume it.
    • scene_routes[]: scene label, mode, backend scene_contract, protection state, lifecycle, and diagnostic function mapping; raw function_name may only be present in admin data and must not be shown in the business-scene route UI.
    • scene_slot_matrix[]: explainability matrix for operators. Each row includes scene_key, scene_label, scene_contract, lifecycle, scene_family, current_slot, required_slot, current_slot_label, required_capabilities[], protected, active_runtime, active_slot_runtime, draft_runtime, draft_slot_runtime, active_version, draft_dirty, capability_gap, recent_failure_rate, recent_failure_count, recent_failed_calls, recent_total_calls, scene_health, release_gate, impact_summary, aggregate risk_level/risk_label, slots[], and advanced functions[]. scene_contract includes business goal, input contract, output contract, success criteria, failure policy, confirmation policy, evidence policy, protected reason, expected slot, scene family, owner, and lifecycle. scene_health includes status=healthy|warning|blocked|unknown, score, blockers, warnings, and evidence summary. release_gate includes whether publish is blocked, blocking reason, draft impact, protected-scene regression, and suggested action. active_runtime / active_slot_runtime and draft_runtime / draft_slot_runtime summarize slot key/label, release version, configured state, runtime label/source, and primary runtime id. capability_gap distinguishes missing capability, missing probe evidence, stale evidence, and human-readable blocking reasons for release review. Each slot row includes slot_key, slot label, whether it is required by the scene, active runtime/source, release version, capability coverage, and risk reasons such as missing active binding, missing capability, missing probe evidence, stale probe evidence, or protected-scene downgrade. functions[] is diagnostic payload only; business-scene route UI must stay at scene/slot level, consume backend scene contracts, and route function-level inspection to hidden Route Lab.
    • recent_failures[]: sanitized failure samples without raw error or prompt; includes scene_key / scene_label when the function belongs to a registered business scene so /platform/ai-routing-failures?scene=... can filter deterministically.
    • protected_scenes[], diagnostics[]
  • Boundary: this is the only user-facing surface that may show provider/model/base URL summaries, and all secrets must remain masked; PMFlow business pages must consume only business policy/mode/trust state.

GET /ai-call-traces

  • Purpose: platform AI call trace ledger for PMFlow AI operators to inspect provider/model call history, sanitized request/response evidence, runtime routing metadata, slot usage, latency, tokens, cost estimates, and recent failure context.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Storage: reads from ai_call_logs; new runtime writes should populate trace_id, user_id when the request has an authenticated operator, raw configured provider code, model, latency_ms, routing_meta, prompt attribution fields prompt_key / prompt_release_id / prompt_source, and true upstream provider payload fields provider_request_payload / provider_response_payload / provider_attempts in addition to existing prompt/response/token/cost/status fields. Operator-facing responses must distinguish raw provider code from product/runtime display labels; DashScope/Qwen calls must persist provider code dashscope, never the removed historical code glm.
  • Query params:
    • page, page_size
    • status
    • provider, model
    • function_name, scene_key, slot_key
    • prompt_key, prompt_source, prompt_release_id
    • trace_id
    • tenant_id
    • keyword
    • since_hours
  • Response data:
    • summary: total calls, failed calls, total tokens, estimated cost, average latency, and top provider codes/display labels for the current filter set.
    • items[]: log id, trace id, tenant/user, created time, raw function_name plus Chinese function_label, scene display metadata, status, raw provider_code, provider_label, runtime_label, optional engine_id/engine_name, model, slot key/label, prompt key/release/source, routing decision/source/rule, token/cost/latency metrics, upstream usage-derived prompt_tokens / completion_tokens / total_tokens, request max_tokens, finish_reason, Function Runtime Profile version/max token metadata, redacted trigger preview, and error summary.
    • page, page_size, total, has_next.
  • Capability probe display: AI call audit follows the real upstream endpoint interaction boundary. New provider capability probes do not write an extra probe_engine_capabilities aggregate log. Rows whose function_name starts with probe_capability_ are visible by default only when they correspond to an upstream provider call; the model self-report probe is shown because it is a short upstream call, while non-upstream declared/contract gates are stored in provider capability evidence but are not written as AI call logs. Historical probe_engine_capabilities aggregate rows are hidden from default list/summary results and remain queryable only through an explicit function_name filter.
  • Boundary: prompt, response, and provider payload content are always redacted before returning to the UI. Provider secrets, cleartext bearer tokens, API keys, phone numbers, emails, and raw transport headers must not be returned. The database stores compatibility prompt/response for legacy search and previews, but operator detail UI should prioritize true upstream provider_request_payload / provider_response_payload / provider_attempts and routing/probe metadata. This view is platform-only and must not appear in customer workspace AI settings, Project Launch, Space, or project-level AI copilot surfaces.

GET /ai-call-traces/{trace_id_or_log_id}

  • Purpose: open one AI call trace detail by trace_id or numeric ai_call_logs.id.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Response data:
    • trace: list-row fields plus routing metadata, probe metadata, redacted upstream payload evidence, and audit policy notes.
    • trace.raw_payload_available=true when ai_call_logs.provider_request_payload, provider_response_payload, or provider_attempts exists; detail response includes request.provider_request_payload_redacted, response.provider_response_payload_redacted, and response.provider_attempts_redacted. Raw encrypted provider payload replay/export is not part of this API.
  • Boundary: 404 returns the standard response envelope with data=null; details follow the same redaction and platform-only visibility rules as the list endpoint.

GET /prompt-assets

  • Purpose: platform Prompt asset center for PMFlow AI operators to inspect all registered and discovered runtime prompts, release state, and migration gaps before editing or optimizing prompt behavior.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Storage/read model: combines backend/app/config/ai_prompt_registry.py, default templates exported by backend/app/config/ai_prompts.py, tenant-scoped prompt_releases, prompt release gate checks in prompt_release_checks, golden cases in prompt_golden_cases, replay runs/results in prompt_replay_runs / prompt_replay_case_results, and prompt-attributed quality metrics from ai_call_logs. It does not expose secrets or raw provider payloads.
  • Query params:
    • family: classification | extraction | planning | response | governance
    • runtime_source: catalog | ai_prompts | inline_discovered
    • editable_policy: managed_release | guarded_release | needs_migration
    • keyword: matches prompt key, business scenario, module, or call site.
  • Response data:
    • summary: total assets, active release count, needs-migration count, and guarded count for the current tenant.
    • items[]: prompt key, module, business scenario, call sites, input/output contract, family, responsibility scope, priority/audience, runtime source, editable policy, risk level, template variables, default template hash/preview, active release summary, latest release summary, release gate summary, latest replay run summary, draft count, release count, and migration status.
  • Boundary: this is a platform-only operational inventory. inline_discovered means the prompt has been found in code but the runtime call site still needs migration to read active releases; the UI must not present such entries as already configurable or active. Customer workspace settings, Space, Project Launch, and project-level AI copilot surfaces must not expose prompt bodies.
  • Runtime migrated governance/query/presentation prompts: PMFLOW_SEMANTIC_CONTEXT_DECISION_PROMPT, PROMPT_CUSTOMER_ANSWER_COMPOSER, PROMPT_CUSTOMER_ANSWER_VERIFIER, PROMPT_RAG_QUERY_SEMANTICS, PROMPT_RAG_FOLLOWUP_ANCHOR_SEMANTICS, and PROMPT_RAG_PENDING_CLARIFICATION_SELECTION_SEMANTICS read the current tenant active release at runtime and record prompt_key / prompt_release_id / prompt_source in AI call logs; missing active releases fall back to the default seed template. PROMPT_PMFLOW_AI_ROUTE_PLANNER is a legacy/deprecated inventory key only and must not be used by Space AI runtime.

GET /prompt-assets/{prompt_key}

  • Purpose: open one prompt asset detail, including the default template body when available, active/draft release state, call sites, contracts, and migration status.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Response data:
    • Same fields as the list item, plus default_template_body, release body_snapshot values for platform-side review and diff, and a 7-day quality_summary based on ai_call_logs.prompt_key.
  • Boundary: 404 returns the standard response envelope with data=null. Guarded prompts are visible for audit, but activation policy still belongs to the prompt release / replay / evaluation workflow and must not bypass release review.

POST /prompt-assets/{prompt_key}/releases

  • Purpose: create a tenant-scoped draft prompt release for a managed or guarded prompt asset.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Request data:
    • body_snapshot: required prompt template body.
    • notes: optional release note / change reason.
  • Validation:
    • prompt_key must exist in ai_prompt_registry.
    • Only editable_policy=managed_release | guarded_release and non-inline assets with a default template can create releases.
    • Template placeholders must not introduce variables outside the default template contract.
  • Boundary: needs_migration and inline_discovered return the standard error envelope and remain read-only until runtime migration is implemented. guarded_release can create candidate releases, but cannot activate until release gate checks pass.

POST /prompt-assets/{prompt_key}/releases/{release_id}/activate

  • Purpose: activate a draft prompt release for the current tenant; any existing active release for the same prompt becomes archived.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Boundary: managed releases can activate directly. Guarded releases require passing gate checks before activation; golden_replay remains blocking when no active golden cases exist, and with active cases it requires a completed release replay run with zero failed cases. Current replay mode is deterministic contract smoke and explicitly records that no real LLM replay was executed.

POST /prompt-assets/{prompt_key}/releases/{release_id}/rollback

  • Purpose: reactivate an archived managed prompt release as a rollback target.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Boundary: only archived releases can be rolled back. Draft releases must use activate, and guarded prompts remain blocked until release gates exist.

GET /prompt-assets/{prompt_key}/quality-summary

  • Purpose: aggregate prompt-attributed AI call quality for one prompt asset.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Query params:
    • window: 24h | 7d | 30d, default 7d.
    • status: optional status filter.
    • release_id: optional prompt release id filter.
  • Response data: total_calls, failed_calls, failure_rate, fallback_calls, active_release_calls, default_fallback_calls, average_latency_ms, estimated_cost, recent_failures, and release_breakdown.
  • Boundary: no attributed call rows returns zero metrics and empty samples; the API must not infer quality from unrelated function names or raw prompt text.

GET /prompt-assets/{prompt_key}/golden-cases

  • Purpose: list deterministic golden cases for a prompt asset.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Query params: status, default can be omitted; UI usually reads active.
  • Response data: items[], total, active_count.

POST /prompt-assets/{prompt_key}/golden-cases

  • Purpose: create a manual golden case for future replay and current guarded release gate.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Request data: case_name, input_payload, optional expected_contract, expected_contains, notes.
  • Boundary: stores JSON contracts only; it does not execute an LLM and does not publish a prompt.

POST /prompt-assets/{prompt_key}/golden-cases/from-call/{ai_call_log_id}

  • Purpose: convert a prompt-attributed AI call log into a golden case seed.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Boundary: the source call must have the same prompt_key. The generated case stores compact prompt/response previews and metadata, not raw provider payloads or secrets.

GET /prompt-assets/{prompt_key}/releases/{release_id}/checks

  • Purpose: list release gate checks for one prompt release and return the derived gate summary.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Response data:
    • items[]: check id, prompt key, release id, check type, status, severity, summary, details, creator, created/completed time.
    • gate: derived status not_run | passed | blocked, blocking reasons, required checks.

POST /prompt-assets/{prompt_key}/releases/{release_id}/checks/run

  • Purpose: run MVP prompt release gate checks for a candidate release.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Current checks:
    • variable_contract: verifies the candidate template does not introduce placeholders outside the default template contract.
    • schema_smoke: checks whether structured/JSON prompt contracts declare JSON/schema constraints.
    • golden_replay: records blocking skipped/no_cases when no active golden cases exist; with active cases it remains blocking until a release replay run exists, and passes only when the latest completed replay run has zero failed cases. Warnings are recorded for human review and do not pretend to be real LLM replay evidence.
  • Boundary: this endpoint does not call an LLM, does not mutate runtime routing, and does not automatically activate a release. Guarded releases stay blocked unless all required checks pass.

POST /prompt-assets/{prompt_key}/releases/{release_id}/replay-runs

  • Purpose: run deterministic replay review for one prompt release against active golden cases.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Request data:
    • mode: default contract_smoke.
    • case_status: default active.
    • max_cases: default 20, max 100.
    • include_llm: must be false in this phase; true returns a standard error.
    • reason: optional audit note.
  • Behavior:
    • Renders candidate release templates with golden case input_payload.
    • Optionally renders the current active release as baseline when present.
    • Evaluates deterministic expected_contract fields such as required_input_keys, required_prompt_contains, expected_contains, and forbidden_terms.
    • Persists one prompt_replay_runs row and per-case prompt_replay_case_results rows.
  • Response data: replay run summary with run_status, counts, risk flags, summary, baseline release id, and case results.
  • Boundary: does not call an LLM, does not write runtime routing, and does not activate a release. Missing active golden cases, unsupported replay mode, or include_llm=true fail closed.

GET /prompt-assets/{prompt_key}/releases/{release_id}/replay-runs

  • Purpose: list replay runs for one prompt release.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Response data: { prompt_key, release_id, items[], total }; item rows include run status, counts, summary and risk flags without per-case results.

GET /prompt-assets/{prompt_key}/replay-runs/{run_id}

  • Purpose: read one replay run with per-case results.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Boundary: 404 returns the standard response envelope with data=null; replay result payloads contain rendered prompt snapshots and must remain platform-only.

POST /ai-routing/diagnostics/run

  • Purpose: run read-only diagnostics for routing/provider health.
  • Auth: PMFlow platform capability platform.ai_routing.manage.
  • Side effects: none; does not modify provider, slot, team policy, or runtime routing.

PMFlow OS Project Memory Read Models

All endpoints return { code, message, data } and require project visibility through membership or manager access. These endpoints are read-only: they must not commit ChangeSets, mutate truth nodes, execute AI actions, or write Project Memory.

GET /pmflow-os/projects/{project_id}/project-memory/overview

  • Purpose: return the Project Knowledge Hub overview for the memory homepage.
  • Response data: { projectId, projectName, generatedAt, metrics[], facts[], requirements[], decisions[], constraints[], evidence[], contextPacks[], writebacks[], aiSuggestions[], warnings[] }.
  • Boundary: overview is a backend read model over confirmed truth, indexed assets, context pack projections, and writeback audit rows; frontend must not reconstruct the authoritative memory overview from raw truth-state except as a degraded fallback.

GET /pmflow-os/projects/{project_id}/project-memory/items

  • Purpose: list confirmed project memory objects across facts, requirements, decisions, risks, constraints, tasks, tests, releases, and metrics.
  • Query params: category, stage, source_type, status, query, limit, offset.
  • Response data: { projectId, total, limit, offset, items[] }; each item includes evidenceRefs, impactRefs, timestamps, status, and metadata.

GET /pmflow-os/projects/{project_id}/project-memory/items/{item_id}

  • Purpose: read one memory item for detail drawers or deep inspection.
  • Response data: { projectId, item }.

GET /pmflow-os/projects/{project_id}/project-memory/assets

  • Purpose: list project assets such as conversation evidence, documents, code/PR evidence, tests, release records, feedback, metrics, and external research assets.
  • Query params: asset_type, source_type, status, query, limit, offset.
  • Boundary: assets may be indexed automatically, but they do not become Project Truth until a Change Review or trusted rule confirms them.

GET /pmflow-os/projects/{project_id}/project-memory/context-packs

  • Purpose: list AI-readable context packs grouped by execution scenario.
  • Response data: { projectId, total, contextPacks[] }; packs expose included item/asset ids, usage, warnings, and freshness.

GET /pmflow-os/projects/{project_id}/project-memory/writebacks

  • Purpose: list ChangeSet writeback/version audit rows.
  • Response data: { projectId, total, limit, offset, writebacks[] }; rows include item counts, committed/skipped/pending status, source ChangeSet id, committer display fields (committedBy / committedById), and item summaries.

PMFlow OS Adaptive Capacity

All endpoints return { code, message, data }. Project members may read. Override simulate/apply requires OWNER or REVIEWER; write endpoints only persist capacity override audit records and must not assign tasks, request review, write ChangeSet, or mutate Project Memory.

GET /pmflow-os/projects/{project_id}/capacity-plan?date=YYYY-MM-DD

  • Purpose: compute the daily adaptive human capacity plan from current truth-state, reviewer routing, execution summary, workspace bindings, user projects, legacy workload reference, and active overrides.
  • Response data:
    • projectId, date, generatedAt
    • teamDemandMix
    • teamEffectiveMinutes, teamPlannedTouchMinutes
    • memberPlans[]: base/effective minutes, dynamic suggestedBaseline, current mix, planned touch minutes, status, remaining minutes, bottleneck, fatigue risk, risk density, canTakeMore, manual override, explanations
    • humanTouches[]: source, target href, work type, estimated minutes, risk, urgency, binding, assigned user, context readiness, AI reduction potential
    • warnings, recommendations
  • Boundary: daily plan is computed at read time. Do not persist fixed baselines or daily snapshots.

POST /pmflow-os/projects/{project_id}/capacity-overrides/simulate

  • Purpose: simulate a manager capacity override before applying it.
  • Request body: PMFlowCapacityOverridePayload
  • Response data: { beforePlan, afterPlan, impactSummary, warnings }
  • Boundary: no database write and no assignment side effect.

POST /pmflow-os/projects/{project_id}/capacity-overrides

  • Purpose: apply a manager override and persist audit in human_capacity_overrides.
  • Request body: PMFlowCapacityOverridePayload
  • Response data: PMFlowCapacityOverrideRecord
  • Side effects: insert one override audit row only.
  • Boundary: reason is required; default expiry is same day 23:59 if omitted. Overtime increases time budget but must not clear fatigue or quality risk.

GET /pmflow-os/projects/{project_id}/capacity-overrides?date=YYYY-MM-DD

  • Purpose: list override audit records for the given day.
  • Response data: PMFlowCapacityOverrideRecord[]

GET /pmflow-os/projects/{project_id}/execution-summary

  • Addition: response data includes qualityContract and acceptance.
  • qualityContract: deterministic execution quality contract with required test levels, release-blocking test cases, test environment, evidence requirements, acceptance gate and computed test-case status.
  • acceptance: human acceptance / technical review projection from progress events; canEnterReleaseGate=false keeps releaseGate in needs_confirmation even when tests pass.

POST /pmflow-os/projects/{project_id}/execution-acceptance-decisions

  • Purpose: record user acceptance or technical review decision for a formal execution task.
  • Request body: { task_id, decision, note?, evidence_event_ids? }, where decision is accept | request_changes | reject | request_technical_review | approve_technical_review.
  • Response data: latest ExecutionSummaryProjection.
  • Errors: 404 task_not_found, 409 acceptance_test_evidence_required, 409 technical_review_required.
  • Boundary: writes an execution_acceptance_decision_v1 ProgressEvent only; does not merge, deploy, release, commit Project Memory, or execute local commands.

POST /pmflow-os/projects/{project_id}/execution-memory-writebacks

  • Purpose: after execution evidence and human acceptance are complete, write the accepted execution result back into PMFlow Project Memory / Work Graph read models.
  • Request body: { task_id, progress_event_ids?, result?, note? }, where result is completed | blocked | changes_requested and defaults to completed.
  • Behavior:
    • Requires the task's acceptance.status="accepted" and userAccepted=true; technical-review-only approval is not enough.
    • Requires at least one execution result evidence event such as branch/commit/PR/test/check/merged/blocked/failed; acceptance events alone are not evidence.
    • Writes ProgressEvent(event_type="execution_memory_writeback", source="pmflow_os", payload.protocol_version="execution_memory_writeback_v1").
    • Updates task stable status: completed -> done, blocked / changes_requested -> blocked; completed also writes completed_at.
    • Adds audit metadata to Task.manual_overrides.latest_execution_memory_writeback.
    • Returns { writeback, executionSummary, projectTruthState }; writeback also appears in GET /project-memory/writebacks.
    • releaseGate remains needs_confirmation / 等待写回项目记忆 after acceptance and becomes ready only after this writeback is present together with test and sync evidence.
  • Errors: 404 task_not_found, 409 execution_acceptance_required, 409 execution_evidence_required, 409 writeback_already_exists, 409 unresolved_blocker_exists, 422 invalid_progress_event_ids.
  • Boundary: does not merge, deploy, publish, execute local commands, create tasks, or commit ChangeSets. It only records PMFlow's accepted execution fact.

GET /pmflow-os/projects/{project_id}/execution-capabilities

  • Addition: response data may include adaptiveCapacitySummary: DailyCapacityPlan.

Task Briefs

GET /task-briefs/center

  • Purpose: list generated brief cards

GET /task-briefs/templates

  • Purpose: list templates

POST /task-briefs/templates

  • Purpose: create template

PUT /task-briefs/templates/{template_id}

  • Purpose: update template

GET /task-briefs/runs

  • Purpose: list generation runs

POST /task-briefs/generate

  • Purpose: generate one task brief run

GET /task-briefs/contract-sync

  • Purpose: expose docs/contract sync status snapshot