Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
8b0f05e
Archive v0.24: add provider expansion policy and capability ledger
WangEn Oct 6, 2026
32c0655
Archive v0.24: require explicit adapter capability manifests
WangEn Oct 6, 2026
39f980b
Declare provider adapter metadata capabilities
WangEn Oct 6, 2026
a6b4a18
Declare provider adapter metadata capabilities
WangEn Oct 6, 2026
d5189ef
Declare provider adapter metadata capabilities
WangEn Oct 6, 2026
78a4c85
Archive v0.24: derive provider expansion readiness from evidence
WangEn Oct 6, 2026
8bddc9c
Add provider adapter manifests to catalog bootstrap dependencies
WangEn Oct 6, 2026
7b2a2d0
Export provider expansion playbook repository
WangEn Oct 6, 2026
761dd7a
Archive v0.24: seed capability declarations from adapter manifests
WangEn Oct 6, 2026
f16fa32
Archive v0.24: add provider expansion control API
WangEn Oct 6, 2026
4b1ee52
Wire provider expansion repository into API
WangEn Oct 6, 2026
7d0818e
Archive v0.24: add Provider Expansion web contracts
WangEn Oct 6, 2026
c6e7a8b
Archive v0.24: add Provider Expansion operator view
WangEn Oct 6, 2026
32c258d
Link Provider Expansion from operator menu
WangEn Oct 6, 2026
09edec1
Test provider bootstrap capability manifests
WangEn Oct 6, 2026
4f59c2c
Test Provider Expansion playbook readiness end to end
WangEn Oct 6, 2026
04c1c57
Fix Provider Expansion fixture causality and append-only assertion
WangEn Oct 6, 2026
421b7cd
Run Provider Expansion integration coverage in CI
WangEn Oct 6, 2026
5047686
Test Provider Expansion control API
WangEn Oct 6, 2026
cb80fa0
Test explicit provider capability manifest
WangEn Oct 6, 2026
32402c5
Test explicit provider capability manifest
WangEn Oct 6, 2026
f4d8f03
Test explicit provider capability manifest
WangEn Oct 6, 2026
af69fb5
Document Archive v0.24 Provider Expansion Playbook
WangEn Oct 6, 2026
3be6b91
ADR 0020: gate Provider onboarding on evidence
WangEn Oct 6, 2026
d373539
Mark Archive v0.24 Provider Expansion Playbook implemented
WangEn Oct 6, 2026
e9f7200
Update provider adapter policy fixture for capability contract
WangEn Oct 6, 2026
ee3ae56
Type provider adapter capability fixture explicitly
WangEn Oct 6, 2026
aca941d
Update evidence transport adapter fixture for capability contract
WangEn Oct 6, 2026
83306d9
Update test adapter fixtures for capability contract
WangEn Oct 6, 2026
66aaafd
Update test adapter fixtures for capability contract
WangEn Oct 6, 2026
413eb54
Type provider adapter capability descriptors explicitly
WangEn Oct 6, 2026
c514b37
Type provider adapter capability descriptors explicitly
WangEn Oct 6, 2026
81a8a13
Type provider adapter capability descriptors explicitly
WangEn Oct 6, 2026
41a8441
Include Provider Adapter runtimes in API image
WangEn Oct 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 221 additions & 0 deletions apps/api/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ import type {
PgCatalogPresence,
PgCatalogPresenceReview,
PgCatalogRemoteIdCase,
PgProviderExpansion,
PgProviderTestability,
RecordProviderExpansionPolicyInput,
RecordProviderCapabilityInput,
RecordProviderTestabilityObservationInput,
} from "@modelapse/catalog-admin";

Expand Down Expand Up @@ -81,6 +84,15 @@ type ProviderTestabilityRepository = Pick<
PgProviderTestability,
"listProviders" | "getProvider" | "recordObservation"
>;
type ProviderExpansionRepository = Pick<
PgProviderExpansion,
| "ping"
| "listProviders"
| "getProvider"
| "listPolicies"
| "recordPolicy"
| "recordCapability"
>;
type CostLedgerRepository = Pick<
PgCostLedger,
"ping" | "listDailyCosts" | "listBudgetStatus" | "recordBudgetPolicy"
Expand Down Expand Up @@ -123,6 +135,7 @@ export interface AppDependencies {
readonly catalogPresenceReview?: CatalogPresenceReviewRepository;
readonly catalogRemoteIdCase?: CatalogRemoteIdCaseRepository;
readonly providerTestability?: ProviderTestabilityRepository;
readonly providerExpansion?: ProviderExpansionRepository;
readonly costLedger?: CostLedgerRepository;
readonly calibration?: CalibrationRepository;
readonly comparability?: ComparabilityRepository;
Expand Down Expand Up @@ -225,6 +238,7 @@ export function createApp(deps: AppDependencies) {
if (deps.costLedger) await deps.costLedger.ping();
if (deps.calibration) await deps.calibration.ping();
if (deps.comparability) await deps.comparability.ping();
if (deps.providerExpansion) await deps.providerExpansion.ping();
return c.json({
ready: true,
service: "modelapse-api",
Expand Down Expand Up @@ -627,6 +641,213 @@ export function createApp(deps: AppDependencies) {
}
});

app.get("/v1/control/provider-expansion", async (c) => {
if (!deps.providerExpansion || !controlToken) {
return c.json({ error: "control_plane_disabled" }, 503);
}
const authIssue = controlAuthIssue(c.req.header("authorization"), controlToken);
if (authIssue) return c.json(controlAuthError(authIssue), 401);
const policyVersion = c.req.query("policyVersion");
if (
policyVersion &&
!/^[a-z0-9][a-z0-9._-]*$/.test(policyVersion)
) {
return c.json({ error: "invalid_policy_version" }, 400);
}
return c.json({
providers: await deps.providerExpansion.listProviders(policyVersion),
});
});

app.get("/v1/control/provider-expansion/policies", async (c) => {
if (!deps.providerExpansion || !controlToken) {
return c.json({ error: "control_plane_disabled" }, 503);
}
const authIssue = controlAuthIssue(c.req.header("authorization"), controlToken);
if (authIssue) return c.json(controlAuthError(authIssue), 401);
return c.json({ policies: await deps.providerExpansion.listPolicies() });
});

app.get("/v1/control/provider-expansion/:providerId", async (c) => {
if (!deps.providerExpansion || !controlToken) {
return c.json({ error: "control_plane_disabled" }, 503);
}
const authIssue = controlAuthIssue(c.req.header("authorization"), controlToken);
if (authIssue) return c.json(controlAuthError(authIssue), 401);

const providerId = c.req.param("providerId");
const policyVersion = c.req.query("policyVersion");
if (!UUID_RE.test(providerId)) {
return c.json({ error: "invalid_provider_id" }, 400);
}
if (
policyVersion &&
!/^[a-z0-9][a-z0-9._-]*$/.test(policyVersion)
) {
return c.json({ error: "invalid_policy_version" }, 400);
}

const provider = await deps.providerExpansion.getProvider(
providerId,
policyVersion,
);
if (!provider) {
return c.json({ error: "provider_expansion_provider_not_found" }, 404);
}
return c.json({ provider });
});

app.post("/v1/control/provider-expansion/capabilities", async (c) => {
if (!deps.providerExpansion || !controlToken) {
return c.json({ error: "control_plane_disabled" }, 503);
}
const authIssue = controlAuthIssue(c.req.header("authorization"), controlToken);
if (authIssue) return c.json(controlAuthError(authIssue), 401);

let raw: unknown;
try {
raw = await c.req.json();
} catch {
return c.json({ error: "invalid_json" }, 400);
}
const body = apiRecord(raw);
const providerId = body?.providerId;
const capability = body?.capability;
const supportState = body?.supportState;
const sourceId = body?.sourceId;
const declaredAt = body?.declaredAt;
const actor = body?.actor;
const note = body?.note;
const capabilityKeys = [
"returned_model_metadata",
"model_version_metadata",
"provider_request_id",
"provider_response_id",
"service_tier_metadata",
"token_usage",
"catalog_model_list",
];

if (
typeof providerId !== "string" ||
!UUID_RE.test(providerId) ||
typeof capability !== "string" ||
!capabilityKeys.includes(capability) ||
(supportState !== "supported" && supportState !== "unsupported") ||
(sourceId !== undefined &&
(typeof sourceId !== "string" || !UUID_RE.test(sourceId))) ||
(declaredAt !== undefined &&
(typeof declaredAt !== "string" ||
!Number.isFinite(Date.parse(declaredAt)))) ||
typeof actor !== "string" ||
!actor.trim() ||
(note !== undefined && typeof note !== "string")
) {
return c.json({ error: "invalid_provider_capability" }, 400);
}

try {
const input = {
providerId,
capability: capability as RecordProviderCapabilityInput["capability"],
supportState,
...(typeof sourceId === "string" ? { sourceId } : {}),
...(typeof declaredAt === "string" ? { declaredAt } : {}),
actor,
...(typeof note === "string" ? { note } : {}),
} satisfies RecordProviderCapabilityInput;
return c.json(
{ capability: await deps.providerExpansion.recordCapability(input) },
201,
);
} catch (error) {
return c.json(
{
error: "provider_capability_rejected",
message:
error instanceof Error
? error.message
: "Provider capability declaration rejected",
},
409,
);
}
});

app.post("/v1/control/provider-expansion/policies", async (c) => {
if (!deps.providerExpansion || !controlToken) {
return c.json({ error: "control_plane_disabled" }, 503);
}
const authIssue = controlAuthIssue(c.req.header("authorization"), controlToken);
if (authIssue) return c.json(controlAuthError(authIssue), 401);

let raw: unknown;
try {
raw = await c.req.json();
} catch {
return c.json({ error: "invalid_json" }, 400);
}
const body = apiRecord(raw);
const requiredCapabilities = apiStringArray(body?.requiredCapabilities);
const version = body?.version;
const actor = body?.actor;
const note = body?.note;
const booleanKeys = [
"requireIdentityProvenance",
"requireCatalogCollection",
"requireProviderPolicy",
"requirePricingEvidence",
"requireRunnerContext",
"requireDirectRun",
"requireCalibration",
] as const;

if (
typeof version !== "string" ||
!/^[a-z0-9][a-z0-9._-]*$/.test(version) ||
!requiredCapabilities ||
requiredCapabilities.length === 0 ||
booleanKeys.some((key) => typeof body?.[key] !== "boolean") ||
typeof actor !== "string" ||
!actor.trim() ||
(note !== undefined && typeof note !== "string")
) {
return c.json({ error: "invalid_provider_expansion_policy" }, 400);
}

try {
const input = {
version,
requiredCapabilities:
requiredCapabilities as RecordProviderExpansionPolicyInput["requiredCapabilities"],
requireIdentityProvenance: body!.requireIdentityProvenance as boolean,
requireCatalogCollection: body!.requireCatalogCollection as boolean,
requireProviderPolicy: body!.requireProviderPolicy as boolean,
requirePricingEvidence: body!.requirePricingEvidence as boolean,
requireRunnerContext: body!.requireRunnerContext as boolean,
requireDirectRun: body!.requireDirectRun as boolean,
requireCalibration: body!.requireCalibration as boolean,
actor,
...(typeof note === "string" ? { note } : {}),
} satisfies RecordProviderExpansionPolicyInput;
return c.json(
{ policy: await deps.providerExpansion.recordPolicy(input) },
201,
);
} catch (error) {
return c.json(
{
error: "provider_expansion_policy_rejected",
message:
error instanceof Error
? error.message
: "Provider expansion policy rejected",
},
400,
);
}
});

app.get("/v1/control/provider-testability", async (c) => {
if (!deps.providerTestability || !controlToken) {
return c.json({ error: "control_plane_disabled" }, 503);
Expand Down
4 changes: 4 additions & 0 deletions apps/api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
PgCatalogPresence,
PgCatalogPresenceReview,
PgCatalogRemoteIdCase,
PgProviderExpansion,
PgProviderTestability,
} from "@modelapse/catalog-admin";
import {
Expand Down Expand Up @@ -46,6 +47,7 @@ const catalogPresence = PgCatalogPresence.connect(databaseUrl);
const catalogPresenceReview = PgCatalogPresenceReview.connect(databaseUrl);
const catalogRemoteIdCase = PgCatalogRemoteIdCase.connect(databaseUrl);
const providerTestability = PgProviderTestability.connect(databaseUrl);
const providerExpansion = PgProviderExpansion.connect(databaseUrl);
const controlToken = process.env.MODELAPSE_CONTROL_TOKEN;
const port = Number(process.env.PORT ?? "3000");
const app = createApp({
Expand All @@ -66,6 +68,7 @@ const app = createApp({
catalogPresenceReview,
catalogRemoteIdCase,
providerTestability,
providerExpansion,
...(controlToken ? { controlToken } : {}),
});

Expand Down Expand Up @@ -100,6 +103,7 @@ function shutdown(signal: string): void {
catalogPresenceReview.close(),
catalogRemoteIdCase.close(),
providerTestability.close(),
providerExpansion.close(),
]).finally(() => {
if (error) {
console.error(error);
Expand Down
Loading
Loading