Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
3e4bd1c
test(track-b): validate graph registry contract at host boundary
try-works Aug 29, 2026
8ceb314
feat(track-b): verify staged graph registry bindings
try-works Aug 29, 2026
4427564
test(track-b): bind v2 registry fixtures to staged contract
try-works Aug 29, 2026
00f2a31
test(track-b): cover graph registry boundary cases
try-works Aug 29, 2026
fa8b711
feat(trace): bind message graph occurrence provenance
try-works Aug 30, 2026
d6bf719
feat(sqlite): validate deduplicated storage inventories
try-works Aug 30, 2026
1c98c2a
feat(sqlite): validate occurrence migration cutover
try-works Aug 30, 2026
9ba2df6
feat(runtime): propagate occurrence provenance to extensions
try-works Aug 30, 2026
5d4307e
feat(runtime): distinguish storage observation state
try-works Aug 30, 2026
8377e26
test(runtime): serialize worker-backed host integration
try-works Aug 30, 2026
312e7b7
fix(runtime): resolve built profile aggregator exports
try-works Aug 30, 2026
cb843ed
fix(storage): recognize verified graph pointers during migration
try-works Aug 30, 2026
13919c6
fix(storage): recover verified pointer quarantine
try-works Aug 30, 2026
2832896
fix(storage): refresh migration proof receipt
try-works Aug 30, 2026
0a92f46
fix(runtime): retry queued cloud aggregates on startup
try-works Aug 30, 2026
2f56b06
fix(runtime): make recommendation downloads idempotent
try-works Aug 30, 2026
a2f971a
fix(runtime): persist recommendation head cursor
try-works Aug 30, 2026
83c6b72
fix(runtime): coalesce sibling model health probes
try-works Aug 30, 2026
82674dc
fix(runtime): preserve public startup retry typing
try-works Aug 30, 2026
daa2846
style: format Run 95 migration sources
try-works Aug 30, 2026
9e95cd2
fix(ci): build runtime test dependency
try-works Aug 30, 2026
0b8cb3e
fix(ci): keep restart validation hermetic
try-works Aug 30, 2026
0b7003b
fix(ci): build smoke dependency closure
try-works Aug 30, 2026
6ae7a47
test(track-b): align storage header contract
try-works Aug 30, 2026
6f591e2
test(track-b): assert physical storage projection
try-works Aug 30, 2026
36324b8
Merge pull request #196 from try-works/codex/95-graph-occurrence-stor…
try-works Aug 30, 2026
4c2b376
Merge branch 'stage' into dev
try-works Aug 30, 2026
d0feb98
Merge pull request #197 from try-works/dev
try-works Aug 30, 2026
85c5b25
fix(release): build Track B adapter dependencies
try-works Aug 30, 2026
e661880
Merge pull request #198 from try-works/codex/95-track-b-runtime-depen…
try-works Aug 30, 2026
62af0c1
Merge branch 'stage' into dev
try-works Aug 30, 2026
5d5bf8a
Merge pull request #199 from try-works/dev
try-works Aug 30, 2026
7d01aa0
fix(stage): keep secrets out of release packages
try-works Aug 30, 2026
4f245d2
Merge pull request #200 from try-works/codex/95-stage-runtime-readine…
try-works Aug 30, 2026
19f3058
Merge pull request #201 from try-works/dev
try-works Aug 30, 2026
47f786a
fix(stage): disable aggregate without external trust
try-works Aug 31, 2026
3f27450
Merge pull request #202 from try-works/codex/95-stage-runtime-readine…
try-works Aug 31, 2026
8bbe6b2
Merge pull request #203 from try-works/dev
try-works Aug 31, 2026
287cb4d
docs(release): clarify stage candidate publication
try-works Aug 31, 2026
ad8a874
Merge pull request #204 from try-works/codex/95-stage-pairing-receipt
try-works Aug 31, 2026
5a8b15a
Merge stage into codex/95-stage-pairing-receipt
try-works Aug 31, 2026
fcb4b2a
Merge current dev into stage reconciliation
try-works Aug 31, 2026
39e92da
Merge pull request #207 from try-works/codex/95-stage-pairing-receipt
try-works Aug 31, 2026
2721eba
Merge pull request #208 from try-works/dev
try-works Aug 31, 2026
a4f49ee
fix(storage): expose asynchronous audit state
try-works Aug 31, 2026
3feaa14
Merge pull request #209 from try-works/codex/95-stage-pairing-receipt
try-works Aug 31, 2026
fc97237
Merge pull request #210 from try-works/dev
try-works Aug 31, 2026
3fb0142
fix(runtime): preserve graph key recovery boundary
try-works Aug 31, 2026
e33c890
Merge pull request #211 from try-works/codex/95-stage-pairing-receipt
try-works Aug 31, 2026
274bea6
chore(release): reconcile accepted stage RC into dev
try-works Aug 31, 2026
37ea84e
Merge pull request #214 from try-works/codex/reconcile-stage-into-dev-95
try-works Aug 31, 2026
a4e3fc6
Merge pull request #212 from try-works/dev
try-works Aug 31, 2026
b339439
fix(runtime): extend bounded remote readiness probes
try-works Aug 31, 2026
f6a5c8d
Merge pull request #215 from try-works/codex/reconcile-stage-into-dev-95
try-works Aug 31, 2026
2f2714a
Merge pull request #216 from try-works/dev
try-works Aug 31, 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
35 changes: 22 additions & 13 deletions .github/workflows/build-binaries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,16 @@ jobs:
- name: Build UI
run: pnpm --filter @role-model-router/runtime-ui run build

# The Track B adapter bundles sqlite-memory directly from TypeScript.
# That package resolves profile-aggregator through its runtime export,
# which intentionally targets dist/. A fresh CI checkout therefore
# needs this focused public build before the paired private distribution
# can be assembled.
- name: Build public runtime adapter dependencies
if: env.ROLE_MODEL_BUILD_CHANNEL == 'stage' || env.ROLE_MODEL_BUILD_CHANNEL == 'production'
working-directory: ${{ env.ROLE_MODEL_BUILD_CHANNEL == 'production' && '.cache/paired-public' || '.' }}
run: corepack pnpm --filter @role-model-router/profile-aggregator... build

- name: Validate exact private release revision
if: env.ROLE_MODEL_BUILD_CHANNEL == 'stage' || env.ROLE_MODEL_BUILD_CHANNEL == 'production'
shell: bash
Expand Down Expand Up @@ -440,21 +450,20 @@ jobs:
}
}

- name: Include managed stage secrets in the stage package
if: env.ROLE_MODEL_BUILD_CHANNEL == 'stage'
- name: Assert release package has no bundled secret material
shell: pwsh
env:
STAGE_ARTIFACT_DIGEST_KEY: ${{ secrets.STAGE_ARTIFACT_DIGEST_KEY }}
STAGE_ARTIFACT_ENCRYPTION_KEY: ${{ secrets.STAGE_ARTIFACT_ENCRYPTION_KEY }}
STAGE_DESTINATION_MATERIAL: ${{ secrets.STAGE_DESTINATION_MATERIAL }}
STAGE_RECOMMENDATION_MATERIAL: ${{ secrets.STAGE_RECOMMENDATION_MATERIAL }}
run: |
$secretsDir = "role-model-router/dist/release/${{ matrix.target }}/secrets"
New-Item -ItemType Directory -Force -Path $secretsDir | Out-Null
[IO.File]::WriteAllText("$secretsDir/artifact-digest.key", $env:STAGE_ARTIFACT_DIGEST_KEY)
[IO.File]::WriteAllText("$secretsDir/artifact-encryption.key", $env:STAGE_ARTIFACT_ENCRYPTION_KEY)
[IO.File]::WriteAllText("$secretsDir/destination-material.json", $env:STAGE_DESTINATION_MATERIAL)
[IO.File]::WriteAllText("$secretsDir/recommendation-material.json", $env:STAGE_RECOMMENDATION_MATERIAL)
$packageDir = "role-model-router/dist/release/${{ matrix.target }}"
$forbiddenPaths = @(
"$packageDir/secrets",
"$packageDir/.env",
"$packageDir/.env.local"
)
foreach ($path in $forbiddenPaths) {
if (Test-Path $path) {
throw "Bundled secret material is forbidden in release packages: $path"
}
}

- name: Archive standalone package (Unix)
if: matrix.target != 'win32-x64'
Expand Down
4 changes: 4 additions & 0 deletions docs/operations/02-ci-and-release-flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ Reviewed `hotfix/* -> main` is the explicit emergency exception.
packages are available by explicit manual dispatch. Every successful `stage` push publishes a GitHub prerelease with
all four stage-channel archives and `SHA256SUMS.txt`; prereleases are never selected by the stable installers.

An explicit `workflow_dispatch` build is useful for package diagnostics, but it does not publish or replace a Stage
prerelease. To create a candidate for acceptance, promote a reviewed public change through `dev -> stage` so that a
`stage` push produces a new immutable `stage-rc-<stage-sha>` identity.

After testing, a maintainer runs `.github/workflows/accept-release-candidate.yml` with the exact prerelease tag and
checks the explicit acceptance input. That workflow re-downloads the candidate, validates all checksums and stage
manifests, and creates the immutable `rc-approved/<full-stage-sha>` receipt. Do not approve a candidate based only on
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"storage:compact": "node scripts/track-b/run-command-test.mjs TB06-CMD-04",
"test:track-b-authorization": "node scripts/track-b/run-command-test.mjs TB07-CMD-03",
"test:rust": "cargo test --manifest-path role-model-router/rust/Cargo.toml --workspace",
"smoke": "corepack pnpm --filter @role-model-router/gateway-smoke exec tsx src/index.ts",
"smoke": "corepack pnpm --filter @role-model-router/gateway-smoke... run build && corepack pnpm --filter @role-model-router/gateway-smoke exec tsx src/index.ts",
"ci:check": "corepack pnpm run lint && corepack pnpm run schemas:validate && corepack pnpm run build && corepack pnpm run test && corepack pnpm run runtime:test-critical && corepack pnpm run test:rust && corepack pnpm run smoke"
},
"devDependencies": {
Expand Down
27 changes: 27 additions & 0 deletions packages/extension-host/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,33 @@ import {
verifySignedBundle,
} from "../extension-sdk/index.mjs";

/**
* Reject malformed graph-contract metadata at the host boundary. Extension
* packages must not be able to treat an incomplete registry as a usable
* contract, even when they are loaded independently from the Track-B bundle.
*/
export function validateGraphRegistry(registry) {
if (!registry || registry.version !== 1 || !Array.isArray(registry.kinds)) {
throw new Error("invalid graph registry");
}
const seen = new Set();
const kinds = registry.kinds.map((kind) => {
if (
!kind?.id ||
!Number.isInteger(kind.version) ||
!kind.category ||
!Array.isArray(kind.fields)
) {
throw new Error("incomplete graph registry entry");
}
const key = `${kind.id}@${kind.version}`;
if (seen.has(key)) throw new Error(`duplicate graph registry entry: ${key}`);
seen.add(key);
return Object.freeze({ ...kind, fields: Object.freeze([...kind.fields]) });
});
return Object.freeze({ version: registry.version, kinds: Object.freeze(kinds) });
}

const runtimePath = fileURLToPath(new URL("./worker-runtime.mjs", import.meta.url));
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const normalizeModuleUrl = (value) =>
Expand Down
4 changes: 2 additions & 2 deletions role-model-router/apps/runtime-host-bridge/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
"scripts": {
"build": "tsc -p tsconfig.json",
"test": "vitest run",
"test:critical": "vitest run test/account-repair.test.ts test/unified-runtime-config.test.ts test/provider-overlap-metadata.test.ts test/benchmark-summary.test.ts test/validate-observability.test.ts test/validate-ui.test.ts",
"test:router": "vitest run test/controller-routing-contract.test.ts test/runtime-routing-model.test.ts test/request-capability-inference.test.ts test/alias-capability-routing.test.ts test/restart-rehydration.test.ts test/endpoint-rehydration.test.ts test/model-capability-resolver.test.ts test/session-readiness-api.test.ts test/downstream-openai-discovery.test.ts test/validate-restart-rehydration.test.ts test/validate-observability.test.ts",
"test:critical": "corepack pnpm --filter @role-model-router/profile-aggregator build && vitest run test/account-repair.test.ts test/unified-runtime-config.test.ts test/provider-overlap-metadata.test.ts test/benchmark-summary.test.ts test/validate-observability.test.ts test/validate-ui.test.ts",
"test:router": "corepack pnpm --filter @role-model-router/profile-aggregator build && vitest run test/controller-routing-contract.test.ts test/runtime-routing-model.test.ts test/request-capability-inference.test.ts test/alias-capability-routing.test.ts test/restart-rehydration.test.ts test/endpoint-rehydration.test.ts test/model-capability-resolver.test.ts test/session-readiness-api.test.ts test/downstream-openai-discovery.test.ts test/validate-restart-rehydration.test.ts test/validate-observability.test.ts",
"package-sea": "tsx src/package-sea.ts",
"validate-packaging": "corepack pnpm build && tsx src/validate-packaging.ts"
}
Expand Down
32 changes: 20 additions & 12 deletions role-model-router/apps/runtime-host-bridge/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -703,9 +703,7 @@ export function applyRecommendationServiceLauncherConfig(values: LauncherConfigV
(channel === "stage" ? "https://recommendations-stage.role-model.dev" : undefined);
const verificationKey = readLauncherString(values, "recommendation-verification-key");
const serviceToken = readLauncherString(values, "recommendation-service-token");
const materialFile =
readLauncherString(values, "recommendation-material-file") ??
(channel === "stage" ? path.resolve("secrets", "recommendation-material.json") : undefined);
const materialFile = readLauncherString(values, "recommendation-material-file");
const aggregateScope = readLauncherString(values, "aggregate-scope");
const recommendationScope = readLauncherString(values, "recommendation-scope");

Expand Down Expand Up @@ -1007,6 +1005,13 @@ export async function main(): Promise<void> {
),
});
let postObservationOperations: ReturnType<typeof createTrackBOperations> | null = null;
// `createBackend` initializes this after the packaged runtime is selected.
// Keep that initialization boundary opaque to TypeScript's local control-flow
// analysis: the public-only build does not inline the private operations
// adapter, but startup still needs to retry a durable outbox when it is
// available at runtime.
const currentPostObservationOperations = (): ReturnType<typeof createTrackBOperations> | null =>
postObservationOperations;
const drainPostObservationOutbox = async (
runtime: Awaited<ReturnType<typeof createProductionExtensionRuntime>>,
) =>
Expand Down Expand Up @@ -1212,6 +1217,10 @@ export async function main(): Promise<void> {
}
const trackBStateRoot = path.join(options.runtimeStateRoot, options.scopeId, "track-b");
const runtimeChannel = packagedProfile?.channel ?? "development";
const destinationTrustMaterialFile =
args.values["destination-material-file"] ??
args.values["destination-trust-material-file"] ??
process.env.ROLE_MODEL_DESTINATION_AUTH_SECRET_FILE;
const artifactKeyFiles = await resolveManagedArtifactKeyFiles({
channel: runtimeChannel,
stateRoot: trackBStateRoot,
Expand Down Expand Up @@ -1244,23 +1253,19 @@ export async function main(): Promise<void> {
channel: runtimeChannel,
artifactDigestKeyFile: artifactKeyFiles.artifactDigestKeyFile,
artifactEncryptionKeyFile: artifactKeyFiles.artifactEncryptionKeyFile,
trustMaterialFile:
args.values["destination-material-file"] ??
args.values["destination-trust-material-file"] ??
process.env.ROLE_MODEL_DESTINATION_AUTH_SECRET_FILE ??
(runtimeChannel === "stage"
? path.resolve("secrets", "destination-material.json")
: undefined),
trustMaterialFile: destinationTrustMaterialFile,
aggregateEndpoint:
args.values["aggregate-ingestion-url"] ??
process.env.ROLE_MODEL_AGGREGATE_INGESTION_URL ??
(runtimeChannel === "stage"
(runtimeChannel === "stage" && destinationTrustMaterialFile
? "https://ingest-stage.role-model.dev/contribution/aggregate"
: undefined),
aggregateScope:
args.values["aggregate-scope"] ??
process.env.ROLE_MODEL_AGGREGATE_SCOPE ??
(runtimeChannel === "stage" ? "standalone-runtime-stage" : undefined),
(runtimeChannel === "stage" && destinationTrustMaterialFile
? "standalone-runtime-stage"
: undefined),
...(aggregateCorrelationReleaseId && aggregateCorrelationCohortId
? {
aggregateCorrelationReleaseId,
Expand Down Expand Up @@ -1320,6 +1325,9 @@ export async function main(): Promise<void> {
qaStartupReceipts.set(extension.descriptor.id, { ...receipt, requestId });
}
await drainPostObservationOutbox(extensionRuntime);
// A prior cloud outage must not require an unrelated new provider request
// before its already-authorized, durable aggregate is retried.
await currentPostObservationOperations()?.retryContributionAggregates();
} catch (error) {
console.error("[role-model] extension host failed after core runtime was ready:", error);
}
Expand Down
40 changes: 38 additions & 2 deletions role-model-router/apps/runtime-host-bridge/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25748,6 +25748,15 @@ export async function createRuntimeBridgeBackend(
const contribution = (await operations.readContributionState()) as {
readonly recommendationTier?: string;
};
const recommendationTier = contribution.recommendationTier ?? "advanced";
const persistedCursor = await operations.readRecommendationCursor();
const activeCursor =
persistedCursor?.channel === channel &&
persistedCursor.scopeId === recommendationScopeId &&
persistedCursor.recommendationTier === recommendationTier
? persistedCursor
: null;
const legacyRecommendationRevision = await operations.readRecommendationRevision();
let run88CorrelationHeader: Record<string, string> = {};
if (runtimeChannel === "stage") {
const identity = options.run88StageIdentity;
Expand Down Expand Up @@ -25783,9 +25792,15 @@ export async function createRuntimeBridgeBackend(
channel,
runtimeChannel: channel,
releaseTrack: "stable",
recommendationTier: contribution.recommendationTier ?? "advanced",
recommendationTier,
clientSchemaVersions: ["1.0.0"],
activeChannelSequence: 0,
activeChannelSequence: activeCursor?.channelSequence ?? 0,
...(activeCursor
? {
activeSnapshotId: activeCursor.snapshotId,
activeManifestHash: activeCursor.manifestHash,
}
: {}),
identityKind: "anonymous_public",
scopeId: recommendationScopeId,
boundaryProtocolVersion: "1.1",
Expand All @@ -25797,10 +25812,30 @@ export async function createRuntimeBridgeBackend(
return operations.listRecommendations();
if (
resolved.status !== "available" ||
!Number.isSafeInteger(Number(resolved.channelSequence)) ||
typeof resolved.snapshotId !== "string" ||
typeof resolved.bundleUri !== "string" ||
typeof resolved.manifestHash !== "string"
)
throw new Error("recommendation resolve response did not include an available bundle");
const recommendationCursor = {
channel,
scopeId: recommendationScopeId,
recommendationTier,
channelSequence: Number(resolved.channelSequence),
snapshotId: resolved.snapshotId,
manifestHash: resolved.manifestHash,
};
if (!activeCursor && recommendationCursor.channelSequence === legacyRecommendationRevision) {
const existing = await operations.listRecommendations();
if (
existing.length > 0 &&
existing.every((row) => row.provenance === `cloud:${recommendationCursor.manifestHash}`)
) {
await operations.rememberRecommendationCursor(recommendationCursor);
return existing;
}
}
const manifestUrl = new URL(resolved.bundleUri);
const manifestResponse = await fetch(manifestUrl);
if (!manifestResponse.ok)
Expand Down Expand Up @@ -25840,6 +25875,7 @@ export async function createRuntimeBridgeBackend(
signature,
},
verificationKey,
recommendationCursor,
);
},
async applyRecommendation(body: Record<string, unknown>): Promise<unknown> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,64 @@ describe("remote-health-probe", () => {
});
});

it("coalesces one model-list request across effort siblings on the same provider account", async () => {
let requestCount = 0;
const result = await probeRemoteEndpoints({
litellmHealthy: true,
targets: [
{
endpointId: "deepseek.personal.primary.global.deepseek-v4-flash",
providerAccountId: "deepseek.personal.primary",
modelId: "deepseek/deepseek-v4-flash",
apiBase: "https://api.deepseek.com/v1",
servingSource: "remote-service",
},
{
endpointId: "deepseek.personal.primary.global.deepseek-v4-flash-max",
providerAccountId: "deepseek.personal.primary",
modelId: "deepseek/deepseek-v4-flash",
apiBase: "https://api.deepseek.com/v1",
servingSource: "remote-service",
},
{
endpointId: "deepseek.personal.primary.global.deepseek-v4-pro-max",
providerAccountId: "deepseek.personal.primary",
modelId: "deepseek/deepseek-v4-pro",
apiBase: "https://api.deepseek.com/v1",
servingSource: "remote-service",
},
],
resolveAuthorization: async () => "deepseek-live-key",
networkFetcher: async () => {
requestCount += 1;
return new Response(
JSON.stringify({ data: [{ id: "deepseek-v4-flash" }, { id: "deepseek-v4-pro" }] }),
{ status: 200, headers: { "content-type": "application/json" } },
);
},
});

expect(requestCount).toBe(1);
expect(result).toMatchObject({ probed: 3, healthy: 3, degraded: 0 });
expect(result.results).toMatchObject([
{
endpointId: "deepseek.personal.primary.global.deepseek-v4-flash",
modelId: "deepseek/deepseek-v4-flash",
reason: "healthy",
},
{
endpointId: "deepseek.personal.primary.global.deepseek-v4-flash-max",
modelId: "deepseek/deepseek-v4-flash",
reason: "healthy",
},
{
endpointId: "deepseek.personal.primary.global.deepseek-v4-pro-max",
modelId: "deepseek/deepseek-v4-pro",
reason: "healthy",
},
]);
});

it("maps auth failures to degraded health with auth reason", async () => {
const result = await probeRemoteEndpoints({
litellmHealthy: true,
Expand Down
Loading
Loading