OpenAPI member-surface gaps — annotation checklist
What this is: a checklist comparing the utoipa paths(...) list in
icn/crates/icn-gateway/src/openapi.rs against the member-facing routes
actually registered by the governance app
(icn/apps/governance/src/http/configure.rs, handlers in
icn/apps/governance/src/http/handlers.rs, mounted by the gateway under
/v1/gov). Checklist only — no annotations are added here.
Why it matters: the gateway serves Swagger UI at /swagger-ui/ backed
by /api-docs/openapi.json (icn/crates/icn-gateway/src/server.rs,
SwaggerUi::new(...).url("/api-docs/openapi.json", ...)). Once a handler
carries a #[utoipa::path(...)] annotation and is listed in
openapi.rs paths(...), it lands in that served document automatically.
The static web/api-docs/openapi.yaml is stale (last touched 2026-03-03;
zero member endpoints) — handler source is truth.
Current paths(...) contents (verified 2026-06-12): exactly one entry,
crate::api::federation::propose_clearing_adoption. Every member-facing
route below is therefore missing from the served OpenAPI document.
Mechanism note: these handlers live in the icn-governance-actor app
crate, not in icn-gateway. Annotating them means adding
#[utoipa::path] to the app-crate handlers (the response models in
icn/apps/governance/src/http/models.rs already derive ToSchema) and
referencing them from the gateway's paths(...) / components(schemas(...))
lists, or merging a second OpenApi doc from the app crate. Generic
handlers (<E: GovernanceEventEmitter>) may need concrete-fn shims for
utoipa registration — that design choice belongs to the implementation PR,
not this checklist.
Missing member-facing endpoints (12)
Standing and caller-scoped views
-
GET /v1/gov/me/standing— handlerget_my_standing— scopegovernance:read— responseStandingResponse(models.rs). Annotation needed: document the?domain_idfilter and the empty-standing-is-200 contract. -
GET /v1/gov/me/action-cards— handlerget_my_action_cards— scopegovernance:read— responseActionCardsResponsewrapper{did, cards, generated_at}, not a bare array. Annotation needed: schema forActionCard+ the four closed enums. -
GET /v1/gov/me/scopes— handlerget_my_scopes— scopegovernance:read— responseVec<RoleAssignmentResponse>. Annotation needed: flat-list shape across all structures. -
GET /v1/gov/me/work— handlerget_my_work— scopegovernance:read— responseVec<ActionItemResponse>. Annotation needed: document the filter query params (build_my_work_filter).
Action items + completion receipts
-
GET /v1/gov/domains/{domain_id}/action-items— handlerlist_action_items— scopegovernance:read— responseVec<ActionItemResponse>. Annotation needed: filter params. -
GET /v1/gov/domains/{domain_id}/action-items/{item_id}— handlerget_action_item— scopegovernance:read— responseActionItemResponse. Annotation needed: 404 contract. -
PUT /v1/gov/domains/{domain_id}/action-items/{item_id}/status— handlerupdate_action_item_status— scopesgovernance:meeting:write|governance:write(narrowest-first viarequire_any_scope_matched; creator/assignee + domain membership also enforced) — requestStatusUpdateRequest({"status": "pending" | "in_progress" | "completed" | "deferred" | "cancelled"}) — responseActionItemResponse. Annotation needed: note that first transition tocompletedemits anActionItemCompletionReceipt. -
GET /v1/gov/domains/{domain_id}/action-items/{item_id}/completion-receipt— handlerget_action_item_completion_receipt— scopegovernance:read— responseicn_governance::ActionItemCompletionReceipt(icn/crates/icn-governance/src/proof.rs; would need aToSchemaderive or a gateway-side mirror type). Annotation needed: 404-when- absent/cross-domain contract.
Meetings / attendance receipts
-
PUT /v1/gov/meetings/{meeting_id}/attendance— handlermark_attendance— scopesgovernance:meeting:write|governance:write(+ domain membership) — responseMeetingResponse. Annotation needed: note that a transition intoPresent/Remoteemits aMeetingAttendanceReceipt(ADR-0026 Layer 2). Adjacent observation (not an annotation gap): there is no GET retrieval endpoint for attendance receipts today — the receipt is emitted and stored (receipt_backend.rs) but a member shell has no route to fetch it. That is an endpoint gap, tracked by themeeting/attendfollow-up noted in ADR-0020 §7.
Proposals / votes / decision receipts
-
POST /v1/gov/proposals/{proposal_id}/vote— handlercast_vote— scopesgovernance:proposal:write|governance:write— requestCastVoteRequest— response: the updated proposal object (re-fetched after the vote). Annotation needed: choice stringsfor/against/abstain. -
GET /v1/gov/proposals/{proposal_id}/tally— handlerget_vote_tally— scopegovernance:read— response: handler-localVoteTallyResponsestruct (for_votes,against_votes,abstain_votes,total_votes). Annotation needed: the struct is private to the handler body and would need promotion tomodels.rsforToSchema. -
GET /v1/gov/proposals/{proposal_id}/proof— handlerget_proof— scopegovernance:read— response:GovernanceProof(decision receipt + attestations; served only after signature/hash verification). Annotation needed: schema exposure for the proof envelope. -
GET /v1/gov/proposals/{proposal_id}/chain— handlerget_chain— scopegovernance:read— response:ProvenanceChain(apps/governance/src/manager.rs::get_chain; governance decision receipt + linked allocation receipts + effect records). Annotation needed: schema exposure for the chain object.
Count
12 member-facing endpoints missing from paths(...), plus 1 adjacent
observation (no attendance-receipt retrieval endpoint exists to annotate).
Out of scope for this checklist
- Adding the annotations themselves.
- Non-member-facing governance routes (domain admin, charters, programs, delegations, discussion, federation/SDIS proposals) — also unannotated, but not part of the member-shell surface this checklist tracks.
- Regenerating
web/api-docs/openapi.yamlor the TypeScript SDK types (that follows the annotation PR per the drift chain inCLAUDE.md).