v1.91.7.0 feat: add functional QA and pre-publication docs checks (#2983)

* feat: add surface-aware exploratory QA and ship documentation gates

* test: preserve delegated QA setup authority after main integration

* fix(qa): clarify exploration order and preserve report artifacts

* test(qa): follow the shared setup reference directly

* refactor(ship): make verification and recovery routes explicit

* test(ship): align evidence and review guards with explicit routes

* fix(workflows): clarify ship recovery and functional QA evidence

* fix(workflows): clarify approval recovery and full QA coverage

* refactor(workflows): order review transactions and clarify ship state

* fix(ship): clarify final verification and fail closed at publication

* fix(evals): attribute native atomic documentation writes

* fix(ship): clarify recovery and documentation lifecycle guidance

* fix(test): preserve observed native placeholder styling in CI

* fix(codex): report watchdog timeouts without a process-exit race

* Checkpoint functional QA implementation and workflow validation repairs

* Fix documentation and shared-review fixture contracts

* docs: clarify judge reuse and evaluation supervision

* test: align review evidence and selected case contracts

* test: verify append-only documentation checkpoints and recovery

* fix: qualify QA workflows and CI validation repairs

* fix: launch shared-libs fixture scripts on Windows

* fix: qualify QA deadlines, fixture isolation, and shard cleanup

* fix: preserve qualified QA and cancellation repairs

* fix: enforce functional fixture authority and share strict event decoding

* fix: retain free-test evidence and explain recovery

* fix: reject malformed native evidence after decoder consolidation

* test: use reliable capture for telemetry privacy filters

* test: refresh measured quick coverage and document validation costs

* Fix native fixture receipts and preserve VM validation evidence

* Align negative judge controls with upstream clarity policy

* Fix report-only QA preparation and public evidence handling

* Clarify QA-only preparation and current-report preservation

* Stream Ship quality judgments with an explicit 64k response contract

* Validate compact judge reasoning locally with supported wire schema

* Align functional QA fixture instructions with evidence acceptance

* Bind native browser diagnostics to execution evidence and align review verdicts

* Preserve native diagnostic line boundaries

* Serialize functional QA evidence from native captures

* Keep large QA evidence fixture payload out of Windows argv
This commit is contained in:
Garry Tan authored and GitHub committed 2026-09-29 06:07:35 -07:00
1 parent 65bfb0ce49
commit dcaea52800
333 files changed
+41755 -7357

No files matched your search

+79 -24
View File
@@ -389,22 +389,29 @@ export interface RunShardChildOptions {
env: NodeJS.ProcessEnv;
/** External wall-clock deadline; on expiry the child's process GROUP is SIGKILLed. */
timeoutMs: number;
deadlineMs?: number;
/**
* Hook the freshly-spawned child's stdout/stderr. Stream POLICY (classifier
* tees, log spooling, console forwarding, reporters) is entirely the
* caller's. Runs synchronously right after spawn; the returned promises are
* awaited AFTER the child closes, so trailing output is fully drained
* before the caller reads its classifier/reporter state.
* caller's. Runs synchronously right after spawn; child close and every
* returned promise must settle within the same deadline. A wall-expired
* return reports incomplete capture instead of treating the prefix as final.
*/
hookStreams: (child: ChildProcess) => Array<Promise<void>>;
}
export interface ShardChildResult {
exitCode: number | null;
/** True when the wall timer fired and SIGKILLed the group. */
/** True when the shared deadline expired; no further child work is allowed. */
timedOut: boolean;
/** The child's pid — the process-GROUP id on POSIX (detached spawn). */
groupPid: number | null;
incompleteCapture?: {
childClosed: boolean;
pendingStreams: number;
failedStreams: number;
deadlineMs: number;
};
}
/**
@@ -418,7 +425,7 @@ export interface ShardChildResult {
* - arm an EXTERNAL wall-clock timer that SIGKILLs the group — a spinning
* child main thread never fires its own in-process timer,
* - in EVERY exit path: disarm the timer, detach the signal forwarder, and
* reap group survivors with SIGKILL.
* signal group survivors with SIGKILL.
*
* Caller-side cleanup that must run even on a spawn failure (log streams,
* reporters, temp dirs) belongs in the caller's own try/finally around this
@@ -426,6 +433,12 @@ export interface ShardChildResult {
* preserving the runners' existing could-not-run handling.
*/
export async function runShardChild(options: RunShardChildOptions): Promise<ShardChildResult> {
const deadlineMs = Math.min(options.deadlineMs ?? Infinity, Date.now() + options.timeoutMs);
if (!Number.isFinite(deadlineMs)) throw new Error('Shard deadline must be finite');
if (deadlineMs <= Date.now()) {
return { exitCode: null, timedOut: true, groupPid: null,
incompleteCapture: { childClosed: false, pendingStreams: 0, failedStreams: 0, deadlineMs } };
}
const child = spawn(options.command, options.args, {
cwd: options.cwd,
env: options.env,
@@ -443,31 +456,73 @@ export async function runShardChild(options: RunShardChildOptions): Promise<Shar
});
let timedOut = false;
let childClosed = false;
let pendingStreams = 0;
let failedStreams = 0;
let exitCode: number | null = null;
let failed = false;
let firstError: unknown;
const rememberError = (error: unknown) => {
if (failed) return;
failed = true;
firstError = error;
};
const kill = () => {
try { killProcessGroup(child, 'SIGKILL'); }
catch (error) { rememberError(error); }
};
let close!: () => void;
const closed = new Promise<void>(resolve => { close = resolve; });
const onExit = (code: number | null) => { exitCode = code; };
const onClose = (code: number | null) => { exitCode = code; childClosed = true; close(); };
child.once('exit', onExit);
child.once('close', onClose);
child.on('error', rememberError);
let expire!: () => void;
const expired = new Promise<void>(resolve => { expire = resolve; });
const killTimer = setTimeout(() => {
timedOut = true;
killProcessGroup(child, 'SIGKILL');
}, options.timeoutMs);
kill();
expire();
}, Math.max(0, deadlineMs - Date.now()));
let exitCode: number | null = null;
try {
const streams = options.hookStreams(child);
// Observe failures now; a pipe can reject before the child closes. Keep
// that first error until close so final process-group cleanup still runs.
const drainage = Promise.all(streams).then(
() => ({ ok: true as const }),
(error: unknown) => ({ ok: false as const, error }),
);
exitCode = await new Promise<number | null>((resolve, reject) => {
child.once('error', reject);
child.once('close', (code) => resolve(code));
});
const captured = await drainage;
if (!captured.ok) throw captured.error;
let streams: Array<Promise<void>> = [];
try { streams = options.hookStreams(child); }
catch (error) {
rememberError(error);
kill();
child.stdout?.destroy();
child.stderr?.destroy();
}
pendingStreams = streams.length;
const drainage = Promise.all(streams.map(stream => Promise.resolve(stream).then(
() => { pendingStreams -= 1; },
(error: unknown) => { pendingStreams -= 1; failedStreams += 1; rememberError(error); },
)));
await Promise.race([Promise.all([closed, drainage]), expired]);
if (Date.now() >= deadlineMs) timedOut = true;
} finally {
clearTimeout(killTimer);
forwarding.dispose();
// Reap survivors of this shard even on the clean path.
killProcessGroup(child, 'SIGKILL');
kill();
child.off('exit', onExit);
child.off('close', onClose);
if (!childClosed || pendingStreams > 0) {
child.stdout?.destroy();
child.stderr?.destroy();
child.unref();
}
}
return { exitCode, timedOut, groupPid };
const result: ShardChildResult = { exitCode, timedOut, groupPid };
if (!childClosed || pendingStreams > 0 || failedStreams > 0) {
result.incompleteCapture = { childClosed, pendingStreams, failedStreams, deadlineMs };
}
if (failed) {
if (firstError instanceof Error && Object.isExtensible(firstError)) {
Reflect.defineProperty(firstError, 'shardResult', { value: result, configurable: true });
}
throw firstError;
}
return result;
}