Skip to content

RFC-0002: publish versioned public API reference - #1

Merged
EstandarMustaq merged 6 commits into
mainfrom
rfc-0002-versioned-openapi
Jul 16, 2026
Merged

RFC-0002: publish versioned public API reference#1
EstandarMustaq merged 6 commits into
mainfrom
rfc-0002-versioned-openapi

Conversation

@EstandarMustaq

@EstandarMustaq EstandarMustaq commented Jul 15, 2026

Copy link
Copy Markdown
Member

Summary

  • Establishes the public developer documentation repository under MAVULA governance
  • Publishes owner-locked OpenAPI contracts for Identity Access, Ledger Core, and Workbench
  • Verifies owner, source path, and SHA-256 provenance for each contract
  • Builds static Redoc references through required CI and GitHub Pages

Validation

  • Guardian and contract provenance checks pass
  • operationId uniqueness test passes
  • Static documentation build succeeds

@EstandarMustaq
EstandarMustaq marked this pull request as ready for review July 16, 2026 20:38
@EstandarMustaq
EstandarMustaq requested a review from a team as a code owner July 16, 2026 20:38
@EstandarMustaq
EstandarMustaq requested a review from MrDimande July 16, 2026 20:38
…enapi

# Conflicts:
#	.github/workflows/pages.yml
#	.github/workflows/required-ci.yml

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 26f6b05613

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread openapi/identity-access.public.v1.yaml
Comment thread src/content/docs/v1/guides/payment-jobs.mdx Outdated
Comment thread src/content/docs/v1/guides/legacy-batches.mdx Outdated
Comment thread src/content/docs/v1/getting-started/roles-permissions.mdx Outdated
Comment thread src/content/docs/v1/getting-started/quickstart.mdx Outdated
Comment thread scripts/check-contracts.mjs
Comment thread src/pages/[legacy].html.astro Outdated
Comment thread .github/workflows/pages.yml
Comment thread scripts/check-contracts.mjs Outdated
@EstandarMustaq

Copy link
Copy Markdown
Member Author

Addressed the Codex review in 8da132c: aligned all examples with the canonical .mavula.dev owner contracts; corrected OAuth, payment, regulatory export, delivery and compliance payloads; added structured provenance and per-operation permission validation; replaced static redirects; and gated Pages publication behind guardian, contract and test checks with deploy-only permissions.

@EstandarMustaq
EstandarMustaq merged commit bb6fcb5 into main Jul 16, 2026
2 checks passed
@EstandarMustaq
EstandarMustaq deleted the rfc-0002-versioned-openapi branch July 16, 2026 21:07

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8da132cf9b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread test/contracts.test.mjs
const operationIds = [];
for (const file of ['identity-access', 'ledger-core', 'workbench']) {
const source = readFileSync(`openapi/${file}.public.v1.yaml`, 'utf8');
operationIds.push(...[...source.matchAll(/^\s+operationId: (\S+)$/gm)].map((match) => match[1]));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Parse inline operationIds in uniqueness test

For the current Ledger contract, the six projection operations define operationId inline on the get: mapping, but this regex only matches IDs that appear on their own indented line. The test therefore counts 57 IDs while the contracts contain 63, so duplicate or missing IDs on those published projection routes would still pass CI and can break generated clients later.

Useful? React with 👍 / 👎.


| Role | Typical responsibility | Core permissions |
| --- | --- | --- |
| `operations_viewer` | Read operational and financial state | `finance.read` |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use role identifiers published by Identity

This table documents operations_viewer as a role to provision, and the same table later lists platform_administrator and service_integration, but the Identity /api/v1/me schema only publishes institution_admin, operations_maker, operations_checker, compliance_officer, and auditor as valid role values. Integrators following the guide can provision role IDs that generated clients reject or that the API never returns, so the table should align with the public enum or the contract should be updated.

Useful? React with 👍 / 👎.

| State | Meaning | Client action |
| --- | --- | --- |
| Accepted or queued | Work is durable and awaiting execution | Poll with bounded backoff |
| Active | Provider interaction or reconciliation is in progress | Continue polling |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Document the WorkerJob status enum exactly

When clients poll GET /api/jobs/{jobId}, the response schema exposes WorkerJob.status as QUEUED, PROCESSING, COMPLETED, or FAILED, but this state table tells them to handle Accepted, Active, Expired, and Compensation required. Polling code written from this guide will branch on states the API does not return and may miss the real PROCESSING value, so the table should use the exact public enum or clearly map these labels to it.

Useful? React with 👍 / 👎.

curl -sS -X POST https://workbench.mavula.dev/api/regulatory-exports/BATCH_ID/delivery \
-H "Authorization: Bearer $COMPLIANCE_TOKEN" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: 076a329b-84f5-4f58-99ef-04ac14f3a343' \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include the required delivery correlation header

The recordRegulatoryExportDelivery operation declares both Idempotency-Key and X-Correlation-ID as required headers, but this copy-paste delivery request only sends the idempotency header. Users following the guide for authority delivery will submit a request that fails request validation, so add the required X-Correlation-ID header here as in the export request above.

Useful? React with 👍 / 👎.

?response_type=code
&client_id=operator-console
&redirect_uri=https%3A%2F%2Fops.example.com%2Fcallback
&scope=openid%20profile%20finance.read%20finance.write

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Request only published operator scopes

The authorization-code flow in the Identity contract publishes only openid, profile, and finance.read scopes, but this operator redirect asks for finance.write. Clients following this guide can receive an invalid_scope response before they ever reach the quickstart account creation flow, so either publish the write scope for this flow or remove it from the authorization request.

Useful? React with 👍 / 👎.

source: 'contracts/openapi/workbench.public.v1.yaml',
}],
]);
if (lock.version !== 1 || !Array.isArray(lock.contracts) || lock.contracts.length !== 3) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require each locked contract exactly once

After the new per-entry owner/source validation, the lock still only checks that there are three entries; a lock with identity-access.public.v1.yaml duplicated and workbench.public.v1.yaml omitted still passes every loop check, so the omitted contract’s digest is never verified. Track seen files or delete from expectedContracts and assert the expected set is exhausted so required CI cannot publish drift for an omitted owner contract.

Useful? React with 👍 / 👎.

Comment on lines +298 to +302
payload:
oneOf:
- $ref: '#/components/schemas/PaymentStartPayload'
- $ref: '#/components/schemas/PaymentSettlementPayload'
- $ref: '#/components/schemas/PaymentReconciliationPayload'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Tie job payload schemas to their job type

Because payload is validated independently from type, the public schema accepts mismatched jobs such as PAYMENT_CAPTURE with a settlement or reconciliation payload, even though those payloads cannot be executed as capture jobs. Generated clients and contract tests will treat those combinations as valid and then get runtime rejections, so model CreateJob as whole-object variants or conditional schemas keyed by the selected type.

Useful? React with 👍 / 👎.

description: Submit tenant-scoped payment work. The tenant is always derived from the access token.
tags: [Jobs]
x-mavula-permissions: [workbench.jobs.write]
requestBody:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add idempotency headers to job contract

This payment-job mutation is the only non-Identity POST without Idempotency-Key/X-Correlation-ID parameters, even though the docs tell integrators to use idempotency for mutating requests and the guide sends those headers. Generated clients built from the contract will omit the replay key for payment jobs, so a timeout retry can enqueue duplicate payment work instead of returning the original job receipt.

Useful? React with 👍 / 👎.

Comment on lines +9 to +13
link: /v1/getting-started/quickstart/
icon: right-arrow
variant: primary
- text: Explore API reference
link: /v1/api/ledger-core/

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Prefix splash links with the Pages base path

With base: '/developer-docs', Astro does not automatically rewrite root-relative URLs in Markdown/frontmatter content, and the workflow links below already hardcode /developer-docs. These hero CTAs therefore point to https://mavulahq.github.io/v1/... on GitHub Pages instead of the deployed /developer-docs/v1/... routes, so clicking either primary action from the landing page lands on a 404.

Useful? React with 👍 / 👎.

Comment on lines +763 to +766
allOf:
- $ref: '#/components/schemas/CreateFinancialAdjustment'
- type: object
required: [id, status, requested_by, correlation_id, created_at]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Don't compose closed create schemas into responses

In OpenAPI 3.1/JSON Schema, the additionalProperties: false on CreateFinancialAdjustment still applies inside this allOf, so response fields added by the second schema such as id, status, and requested_by are treated as forbidden additional properties. The same closed-create-schema pattern appears on Rule, EntitySchema, and Workflow, making normal API responses fail validation in generated clients; move the shared properties into an open base schema or use unevaluatedProperties at the composed level.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant