Skip to content

Commit 4acb533

Browse files
authored
Merge pull request #539 from bcorfman/phase2validationharness
Phase2validationharness
2 parents 0ac0c34 + e07690c commit 4acb533

12 files changed

Lines changed: 377 additions & 51 deletions

.github/workflows/ci-build-test.yml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,8 @@ jobs:
2222
unit-tests-node:
2323
runs-on: ubuntu-latest
2424
steps:
25-
- name: Install Git LFS
26-
run: |
27-
sudo apt-get update
28-
sudo apt-get install -y git-lfs
29-
3025
- name: Checkout
3126
uses: actions/checkout@v7
32-
with:
33-
lfs: true
3427

3528
- name: Setup Node
3629
uses: actions/setup-node@v7

.github/workflows/deploy-frontend-pages.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,6 @@ jobs:
4141
github.event.workflow_run.head_repository.full_name == github.repository
4242
)
4343
steps:
44-
- name: Install Git LFS
45-
run: |
46-
sudo apt-get update
47-
sudo apt-get install -y git-lfs
48-
4944
- name: Checkout
5045
uses: actions/checkout@v7
5146
with:

.github/workflows/e2e-main.yml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,8 @@ jobs:
2727
shard: [1, 2, 3, 4]
2828
shards: [4]
2929
steps:
30-
- name: Install Git LFS
31-
run: |
32-
apt-get update
33-
apt-get install -y git-lfs
34-
3530
- name: Checkout
3631
uses: actions/checkout@v7
37-
with:
38-
lfs: true
3932

4033
- name: Setup Node
4134
uses: actions/setup-node@v7

.github/workflows/e2e-nightly-full-matrix.yml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,8 @@ jobs:
2828
shard: [1, 2, 3, 4, 5, 6, 7, 8]
2929
shards: [8]
3030
steps:
31-
- name: Install Git LFS
32-
run: |
33-
apt-get update
34-
apt-get install -y git-lfs
35-
3631
- name: Checkout
3732
uses: actions/checkout@v7
38-
with:
39-
lfs: true
4033

4134
- name: Setup Node
4235
uses: actions/setup-node@v7

.github/workflows/e2e-pr.yml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,8 @@ jobs:
2424
shard: [1, 2]
2525
shards: [2]
2626
steps:
27-
- name: Install Git LFS
28-
run: |
29-
apt-get update
30-
apt-get install -y git-lfs
31-
3227
- name: Checkout
3328
uses: actions/checkout@v7
34-
with:
35-
lfs: true
3629

3730
- name: Setup Node
3831
uses: actions/setup-node@v7

.plans/ci-repair-harness-implementation-plan-2026-07-26.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ Goal: shake out the PhaserForge adapter before any generalization.
307307
change, false success, or token-expensive repeated loop.
308308
- [ ] Tune parsers and catalog entries from measured failures, not anticipated
309309
abstractions.
310-
- [x] Decide whether main-manifest support is justified; defer it until the
310+
- [x] Decide whether main-manifest support is justified; defer it until theHe
311311
required 10--20 failure sample exists because the current evidence does not
312312
justify a second adapter scope.
313313

.plans/hosted-deployment-validation-harness-implementation-plan-2026-07-27.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Hosted Deployment Validation Harness Implementation Plan
22

3-
Status: Phase 1 complete
3+
Status: Phase 2 complete
44

55
Date: 2026-07-27
66

@@ -176,19 +176,19 @@ Timing diagnostics exit criteria:
176176

177177
## Phase 2 — Real-origin browser smoke
178178

179-
- [ ] Add a Playwright adapter using the repository's installed Chromium.
180-
- [ ] Open the configured development Pages frontend, not the local dev
179+
- [x] Add a Playwright adapter using the repository's installed Chromium.
180+
- [x] Open the configured development Pages frontend, not the local dev
181181
server.
182-
- [ ] Assert that API requests target the configured development API origin.
183-
- [ ] Capture request failures, console errors, final URL, and approved
182+
- [x] Assert that API requests target the configured development API origin.
183+
- [x] Capture request failures, console errors, final URL, and approved
184184
response metadata without storing cookie values or auth headers.
185-
- [ ] Add read-only checks for app load, API reachability, and unauthenticated
185+
- [x] Add read-only checks for app load, API reachability, and unauthenticated
186186
state.
187-
- [ ] Add a separate explicit mutation mode for login/signup, project CRUD,
187+
- [x] Add a separate explicit mutation mode for login/signup, project CRUD,
188188
and reload persistence.
189-
- [ ] Use run-specific project names such as
189+
- [x] Use run-specific project names such as
190190
`REPAIR-HARNESS-DEV-<run-id>`.
191-
- [ ] Assert that reload preserves authentication and the updated project.
191+
- [x] Assert that reload preserves authentication and the updated project.
192192

193193
Exit criteria:
194194

scripts/e2e-external-webserver.cjs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -251,13 +251,20 @@ async function startManagedExternalWebServer({
251251
};
252252

253253
child.once('exit', (code, signal) => {
254-
const phase = lifecycle.state.readyAt ? 'during the Playwright run' : 'before ready';
255-
const exitError = createManagedServerError(
256-
`Managed E2E web server exited ${phase} (code=${code ?? 'null'}, signal=${signal ?? 'null'})`,
257-
logDir,
258-
);
259-
recordExit(code, signal);
260-
rejectUnexpectedExit(exitError);
254+
void (async () => {
255+
// The child can emit `exit` before pipe consumers have flushed their final
256+
// chunks. Wait for both layers before rejecting so lifecycle diagnostics
257+
// never lose the stderr/stdout that explains an early server failure.
258+
await recordExit(code, signal);
259+
await childOutputStreamsFinished;
260+
await logStreamsFinished;
261+
const phase = lifecycle.state.readyAt ? 'during the Playwright run' : 'before ready';
262+
const exitError = createManagedServerError(
263+
`Managed E2E web server exited ${phase} (code=${code ?? 'null'}, signal=${signal ?? 'null'})`,
264+
logDir,
265+
);
266+
rejectUnexpectedExit(exitError);
267+
})();
261268
});
262269

263270
try {

scripts/repair-harness/cli.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { appendEvent, readState, resolveResumeDirectory, writeState } from './st
1010
import type { EvidenceEnvelope } from './types';
1111
import { aggregateRepairOutcomes, formatRepairMetrics, readRepairOutcomes, writeRepairMetrics } from './metrics';
1212
import { loadHostedConfig } from './hosted/config';
13-
import { runHostedProbe } from './hosted/run';
13+
import { runHostedBrowser, runHostedMutationCommand, runHostedProbe } from './hosted/run';
1414
import { runE2ETiming } from './e2eTimingRun';
1515

1616
const repositoryRoot = path.resolve(new URL('../..', import.meta.url).pathname);
@@ -47,6 +47,38 @@ if (args[0] === 'e2e-timing') {
4747
console.error(error instanceof Error ? error.message : String(error));
4848
process.exitCode = 1;
4949
}
50+
} else if (args[0] === 'hosted-browser') {
51+
try {
52+
const configPath = value('--config');
53+
if (!configPath) throw new Error('Expected --config <path> for hosted-browser.');
54+
const result = await runHostedBrowser({ repo: value('--repo') ?? repositoryRoot, config: loadHostedConfig(path.resolve(configPath)), runId: value('--run-id') });
55+
console.log(`Hosted browser ${result.status} in ${result.runDirectory}`);
56+
if (result.status !== 'passed') process.exitCode = 1;
57+
} catch (error) {
58+
console.error(error instanceof Error ? error.message : String(error));
59+
process.exitCode = 1;
60+
}
61+
} else if (args[0] === 'hosted-mutate') {
62+
try {
63+
const configPath = value('--config');
64+
const email = value('--email');
65+
const password = value('--password');
66+
if (!configPath) throw new Error('Expected --config <path> for hosted-mutate.');
67+
if (!email || !password) throw new Error('Hosted mutation requires --email and --password; credentials are used in memory only.');
68+
const result = await runHostedMutationCommand({
69+
repo: value('--repo') ?? repositoryRoot,
70+
config: loadHostedConfig(path.resolve(configPath)),
71+
runId: value('--run-id'),
72+
account: { email, password, inviteToken: value('--invite-token') },
73+
signup: has('--signup'),
74+
explicitFlag: has('--allow-hosted-mutations'),
75+
});
76+
console.log(`Hosted mutation ${result.result.status} in ${result.runDirectory}`);
77+
if (result.result.status !== 'passed') process.exitCode = 1;
78+
} catch (error) {
79+
console.error(error instanceof Error ? error.message : String(error));
80+
process.exitCode = 1;
81+
}
5082
} else if (args[0] === 'metrics') {
5183
try {
5284
const repo = value('--repo') ?? repositoryRoot;

0 commit comments

Comments
 (0)