Skip to content

Commit c4bb3f2

Browse files
Merge: two-pass paid trial preparation (fail-closed config, sourced tariffs, preflight; no paid calls)
Co-authored-by: Alfonso <alfonso-magic-context@users.noreply.github.com>
2 parents ed22d41 + 3e0bee2 commit c4bb3f2

10 files changed

Lines changed: 555 additions & 40 deletions

File tree

‎packages/plugin/scripts/two-pass-activation-runs/README.md‎

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,44 @@ bun packages/plugin/scripts/two-pass-activation-runs/container-launcher.ts \
189189
.cortexkit/internal-docs/investigations/two-pass-credential-bridge/evidence
190190
```
191191

192-
`paid-credential-run.json` names `apikey:anthropic:ufukaltinokgmail` and
193-
`apikey:cline-pass`, not code defaults. Its jobs are deliberately empty until
194-
approved route/catalog, tariff, prompts, container image and model inputs are
195-
provided. A filled config uses the same command with its path plus an explicit
196-
enrollment-file path as the third argument. Paid configs **must** specify
197-
`network: "bridge"` and a nonempty exact grant list; missing network or grants
192+
`paid-credential-run.json` is now a **preparation plan, not an executable
193+
campaign**. It inventories every matrix row plus the cache check, names the two
194+
exact grants, records current sources and proposed grader/budget inputs, and
195+
explicitly excludes only the two dropped Sonnet fallback rows. Other unresolved
196+
jobs stay visible and prevent dispatch with `credential_unresolved_jobs`.
197+
`preparationOnly: true` also refuses with `credential_campaign_driver_required`,
198+
even if all unresolved rows are excluded: the credential probe cannot load a
199+
corpus, run the replay schedule/graders, or share a ledger across containers.
200+
Its `@corpus:` / `@persisted-measurement:` prompt references must never be sent
201+
as literal model prompts. Selected-candidate images, real read-tool/origin
202+
evidence, billing gaps and prior-spend reconciliation are still outstanding.
203+
204+
Run the static, provider-free preparation check from the repository root:
205+
206+
```sh
207+
bun packages/plugin/scripts/two-pass-activation-runs/paid-preflight.ts \
208+
--mock-preflight packages/plugin/scripts/two-pass-activation-runs/paid-credential-run.json \
209+
<private-preflight-result.json>
210+
```
211+
212+
Run it on Linux or in a capped offline container with the private corpus mounted
213+
read-only. It uses the native corpus/profile preflight and existing token
214+
counter, emits only case ids/sizes/counts, and exits **1 while anything is
215+
unresolved**. Static profile acceptance is not an effective host-profile report
216+
or live authorization. Grading estimates use recorded-output proxies and full
217+
output allowances; the proposed retry ceiling is conditional on caps a future
218+
campaign driver must enforce. Actual unknown charges remain null, not zero.
219+
The temporary `corpus-readonly` path must be restaged from the authorized bundle
220+
before reproducing the check; the private data is never committed.
221+
222+
For separately prepared credential probes, the launcher accepts config, evidence
223+
directory and explicit enrollment-file path. Network mode must be
224+
`network: "bridge"` for non-mock jobs. Paid jobs require an exact listed grant;
225+
grant-free jobs require provider `opencode` on an OpenCode lane, an explicit zero
226+
tariff with a nonempty `source`, and `checkedAt` equal to today's UTC date.
227+
They receive no secret stdin payload or credential environment and never open
228+
the vault. OpenCode uses its literal `public` API marker for free access; that
229+
marker is not a user credential or a grant. Missing network or paid grants
198230
refuse with `paid_network_bridge_required` or `real_grant_list_required`.
199231
Mock configs can never select bridge networking. The launcher
200232
logs the selected network once per job. The proxy records each upstream host

‎packages/plugin/scripts/two-pass-activation-runs/container-child.ts‎

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { cpSync, existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, re
22
import { join } from "node:path";
33
import { networkInterfaces } from "node:os";
44
import { createHash } from "node:crypto";
5-
import { readHandoff, assertNoMaterial, secretForms, type Handoff } from "./credential-protocol";
5+
import { readJobHandoff, assertNoMaterial, secretForms, type Handoff } from "./credential-protocol";
66
import type { ContainerJob } from "./container-config";
77
import { callMeter, redact } from "./activation-driver";
88
import { hostAdapter } from "./host-adapters";
@@ -69,23 +69,24 @@ export async function runContainerChild(job: ContainerJob, mock: boolean) {
6969
} finally { environ.fill(0); }
7070
};
7171
const profile: Profile = { id: "credential-transport", family: "credential-transport", modelRoute: `${job.providerId ?? "mock"}/${job.modelId}`,
72-
priceClass: "paid", tariff: job.tariff ?? { inputUSDPerMillion: 1, outputUSDPerMillion: 1, source: "Synthetic mock tariff, not provider pricing" },
72+
priceClass: job.priceClass ?? "paid", tariff: job.tariff ?? { inputUSDPerMillion: 1, outputUSDPerMillion: 1, source: "Synthetic mock tariff, not provider pricing" },
7373
configurationSource: "explicit container job", variantSource: "explicit container job",
7474
entry: buildTurnOneAuthorizationRequest({ lane: job.lane === "anthropic-cache" ? "omp" : job.lane,
7575
carrier: job.lane === "omp" ? "pi-historian-rpc" : "hidden-completion", provider: job.providerId ?? "mock", modelId: job.modelId,
7676
variant: null, temperature: null, thinkingLevel: null }, { system: "credential-transport", formatInstruction: "credential-transport", toolSurface: [], checkToolSurface: [] }).requestedIdentity };
7777
try {
78-
handoff = await readHandoff(process.stdin, job.grant);
79-
process.stdin.destroy();
80-
key = handoff.material; handoff.material = "";
78+
try { handoff = await readJobHandoff(process.stdin, job.grant); }
79+
finally { process.stdin.destroy(); }
80+
if (handoff) { key = handoff.material; handoff.material = ""; }
8181
assertNoMaterial("reader_environ", readFileSync(`/proc/${process.pid}/environ`), key);
8282
for (const [name, path] of Object.entries(env)) mkdirSync(name === "OPENCODE_DB" ? join(path, "..") : path, { recursive: true, mode: 0o700 });
8383
if (existsSync(join(install, "host-sdk"))) cpSync(join(install, "host-sdk"), env.XDG_CONFIG_HOME, { recursive: true });
8484
let endpoint = job.providerURL;
8585
if (mock) {
8686
provider = mockProvider(() => "Mock credential transport acknowledged.", undefined, (observed) => {
8787
const expectedHeader = job.lane === "anthropic-cache" ? "x-api-key" : "authorization";
88-
headers.push({ expectedHeader, matched: observed.get(expectedHeader) === (expectedHeader === "authorization" ? `Bearer ${key}` : key),
88+
headers.push({ expectedHeader, matched: job.grant ? observed.get(expectedHeader) === (expectedHeader === "authorization" ? `Bearer ${key}` : key)
89+
: observed.get("authorization") === "Bearer public" && !observed.has("x-api-key"),
8990
authorizationMatched: observed.get("authorization") === `Bearer ${key}`, apiKeyMatched: observed.get("x-api-key") === key,
9091
presentHeaders: ["authorization", "x-api-key"].filter((name) => observed.has(name)) });
9192
});
@@ -133,17 +134,18 @@ export async function runContainerChild(job: ContainerJob, mock: boolean) {
133134
} else {
134135
const adapter = hostAdapter(job.lane, { sourceRoot: install, mockProviderURL: endpoint,
135136
modelId: job.modelId, providerId: job.providerId ?? "mock", providerPackage: job.providerPackage,
136-
piApi: job.piApi, piAuth: job.grant.kind === "api_key" ? "apiKey" : "oauth",
137-
outputCeiling: job.outputCeiling, providerKeyEnv: "TWO_PASS_PROVIDER_API_KEY",
137+
piApi: job.piApi, piAuth: job.grant?.kind === "api_key" ? "apiKey" : "oauth",
138+
outputCeiling: job.outputCeiling, providerKeyEnv: job.grant ? "TWO_PASS_PROVIDER_API_KEY" : undefined,
139+
grantFree: !job.grant,
138140
paidProvider: !mock, foregroundOnly: mock, timeoutMs: 120_000,
139141
onProviderAttempt(providerHost) { console.log(JSON.stringify({ providerAttempt: { providerHost } })); },
140142
onProcessObserved: (pid) => observeProcess(pid),
141143
magicContext: mock ? { enabled: false } : job.magicContext ?? {} });
142144
const entry = join(install, job.lane === "omp" ? "packages/pi-plugin/dist/index.js" : job.lane === "opencode-2" ? "packages/plugin/dist/v2/server.js" : "packages/plugin/dist/index.js");
143-
const childEnv = { ...env, TWO_PASS_PROVIDER_API_KEY: key };
145+
const childEnv = { ...env, ...(job.grant ? { TWO_PASS_PROVIDER_API_KEY: key } : {}) };
144146
host = await adapter.start({ installRoot: install, pluginEntrypoint: entry, env: childEnv, meter: callMeter(ledger, profile) });
145-
observeProcess(host.pid, "TWO_PASS_PROVIDER_API_KEY", true);
146-
childEnvironment = { pid: host.pid, allowedVariable: "TWO_PASS_PROVIDER_API_KEY", environContainsKey: true, argvClean: true };
147+
observeProcess(host.pid, "TWO_PASS_PROVIDER_API_KEY", !!job.grant);
148+
childEnvironment = { pid: host.pid, allowedVariable: job.grant ? "TWO_PASS_PROVIDER_API_KEY" : null, environContainsKey: !!job.grant, argvClean: true };
147149
result = await host.runSession(job.prompt);
148150
}
149151
if (mock && (!headers.length || headers.some((entry) => !entry.matched))) throw new Error("credential_provider_header_mismatch");

‎packages/plugin/scripts/two-pass-activation-runs/container-config.ts‎

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ import type { HostLane } from "./host-adapters";
33
import type { Profile } from "../two-pass-live-replay/artifact-schema";
44

55
export interface ContainerJob {
6+
id?: string;
7+
status?: "ready" | "unresolved";
8+
unresolvedReason?: string;
9+
priceClass?: "free" | "paid";
610
lane: HostLane | "anthropic-cache";
711
image: string;
8-
grant: GrantRequest;
12+
grant?: GrantRequest;
913
providerURL?: string;
1014
providerId?: string;
1115
providerPackage?: string;
@@ -16,7 +20,7 @@ export interface ContainerJob {
1620
magicContext?: Record<string, unknown>;
1721
cacheSystem?: string;
1822
cacheTurnTwo?: string;
19-
tariff?: Profile["tariff"];
23+
tariff?: Profile["tariff"] & { checkedAt?: string };
2024
}
2125
export interface ContainerRunConfig {
2226
version: 1;
@@ -25,29 +29,57 @@ export interface ContainerRunConfig {
2529
runMs: number;
2630
grants: GrantRequest[];
2731
jobs: ContainerJob[];
32+
excludedJobIds?: string[];
33+
preparationOnly?: boolean;
34+
}
35+
36+
export function selectedJobs(config: ContainerRunConfig): ContainerJob[] {
37+
const excluded = config.excludedJobIds ?? [];
38+
if (new Set(excluded).size !== excluded.length || excluded.some((id) => !config.jobs.some((job) => job.id === id)))
39+
throw new Error("credential_excluded_job_unknown");
40+
const ids = config.jobs.map((job) => job.id).filter((id) => id !== undefined);
41+
if (new Set(ids).size !== ids.length) throw new Error("credential_duplicate_job_id");
42+
return config.jobs.filter((job) => !job.id || !excluded.includes(job.id));
2843
}
2944

3045
export function validateRunConfig(config: ContainerRunConfig) {
3146
if (config.version !== 1 || typeof config.mock !== "boolean" || !Number.isSafeInteger(config.runMs) ||
3247
config.runMs < 1000 || config.runMs > 1_800_000) throw new Error("credential_run_config");
3348
if (config.mock && config.network !== "none") throw new Error("mock_network_must_be_none");
3449
if (!config.mock && config.network !== "bridge") throw new Error("paid_network_bridge_required");
35-
if (!Array.isArray(config.grants) || !config.grants.length) throw new Error("real_grant_list_required");
50+
if (!Array.isArray(config.grants)) throw new Error("real_grant_list_required");
3651
for (const grant of config.grants) validateGrant(grant);
3752
if (new Set(config.grants.map((grant) => grant.name)).size !== config.grants.length) throw new Error("duplicate_credential_grant");
3853
if (!config.jobs?.length) throw new Error("credential_jobs_required");
39-
for (const job of config.jobs) {
40-
validateGrant(job.grant);
41-
if (!config.grants.some((grant) => grant.name === job.grant.name && grant.kind === job.grant.kind))
54+
for (const job of config.jobs) if (job.status === "unresolved" && (!job.id || !job.unresolvedReason?.trim()))
55+
throw new Error("credential_unresolved_job_reason_required");
56+
const jobs = selectedJobs(config);
57+
if (!jobs.length) throw new Error("credential_jobs_required");
58+
if (!config.grants.length && jobs.some((job) => job.priceClass !== "free")) throw new Error("real_grant_list_required");
59+
for (const job of jobs) {
60+
if (job.status === "unresolved") throw new Error("credential_unresolved_jobs");
61+
if (job.status && !["ready", "unresolved"].includes(job.status)) throw new Error("credential_job_status");
62+
const free = job.priceClass === "free";
63+
if (free && (job.grant || job.providerId !== "opencode" || !["opencode-1", "opencode-2"].includes(job.lane)))
64+
throw new Error("credential_free_route_required");
65+
if (!free) validateGrant(job.grant!);
66+
if (job.grant && !config.grants.some((grant) => grant.name === job.grant!.name && grant.kind === job.grant!.kind))
4267
throw new Error("unlisted_credential_grant");
4368
if (!["opencode-1", "opencode-2", "omp", "anthropic-cache"].includes(job.lane) ||
4469
!/^[\w./:@-]+$/.test(job.image) || !job.modelId || !job.prompt ||
4570
!Number.isSafeInteger(job.outputCeiling) || job.outputCeiling < 1 || job.outputCeiling > 8192)
4671
throw new Error("credential_job_config");
47-
if (!config.mock) {
72+
if (!config.mock || free) {
4873
if (!job.tariff || !Number.isFinite(job.tariff.inputUSDPerMillion) || !Number.isFinite(job.tariff.outputUSDPerMillion) ||
49-
job.tariff.inputUSDPerMillion <= 0 || job.tariff.outputUSDPerMillion <= 0 || !job.tariff.source)
74+
job.tariff.inputUSDPerMillion < 0 || job.tariff.outputUSDPerMillion < 0 || !job.tariff.source?.trim())
5075
throw new Error("paid_tariff_required");
76+
if (free ? job.tariff.inputUSDPerMillion !== 0 || job.tariff.outputUSDPerMillion !== 0
77+
: job.tariff.inputUSDPerMillion === 0 || job.tariff.outputUSDPerMillion === 0)
78+
throw new Error("paid_tariff_required");
79+
if (free && job.tariff.checkedAt !== new Date().toISOString().slice(0, 10))
80+
throw new Error("credential_zero_tariff_fresh_source_required");
81+
}
82+
if (!config.mock) {
5183
if (!job.providerURL) throw new Error("paid_provider_route_required");
5284
const url = new URL(job.providerURL);
5385
if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash)
@@ -56,8 +88,10 @@ export function validateRunConfig(config: ContainerRunConfig) {
5688
if (job.lane === "anthropic-cache" && (job.modelId !== "claude-sonnet-5-5" || !job.cacheSystem || !job.cacheTurnTwo))
5789
throw new Error("cache_measurement_inputs_required");
5890
}
59-
for (const grant of config.grants) if (!config.jobs.some((job) => job.grant.name === grant.name))
91+
for (const grant of config.grants) if (!config.jobs.some((job) => job.grant?.name === grant.name))
6092
throw new Error("unused_credential_grant");
93+
// The credential probe cannot execute corpus schedules or share a ledger across containers.
94+
if (config.preparationOnly) throw new Error("credential_campaign_driver_required");
6195
}
6296

6397
export function containerArgs(config: ContainerRunConfig, job: ContainerJob, name: string) {
@@ -73,6 +107,7 @@ export function containerArgs(config: ContainerRunConfig, job: ContainerJob, nam
73107
export function containerInvocation(config: ContainerRunConfig, job: ContainerJob, name: string, material: string) {
74108
const argv = containerArgs(config, job, name);
75109
const env = { PATH: process.env.PATH, HOME: process.env.HOME };
76-
assertSpawnBoundary(argv, env, material);
110+
if (job.grant) assertSpawnBoundary(argv, env, material);
111+
else if (material) throw new Error("credential_free_material_refused");
77112
return { argv, env };
78113
}

0 commit comments

Comments
 (0)