Skip to content

Commit e8ec3c2

Browse files
authored
Yerel build süresini 3:27’den ~47 saniyeye indir (#76)
## Sorun `npm run build` iki farklı işi tek komutta taşıyordu: 342 D1/workerd regresyon testi ve production frontend/artifact doğrulaması. Aynı Mac mini üzerinde ölçülen gerçek duvar süresi 207.45 saniyeydi (3:27). Sadece daha fazla concurrency vermek çözmedi: denenen varyantlar 190.79s ve 185.52s seviyesinde kaldı; browser testi de kaynak yarışında 100+ saniyeye kadar şişti. Bu varyantlar ship edilmedi. ## Değişiklik - `npm run build` artık gerçekten production frontend/artifact kapısı: - content test - JS/Python reference client testleri - Orbit validate - production config - OG üretimi - Astro build - site integrity - browser regression - Bağımsız preflight işleri paralel, Astro sonrasında site/browser artifact kontrolleri paralel çalışıyor. - Ağır D1 regresyonu mevcut, kanıtlanmış `npm run test:d1` komutunda aynen kaldı. - Yeni `npm run verify = npm run test:d1 && npm run build` eski tam kalite kapısını koruyor. - `orbit:post` ve `orbit:publish` artık `verify` çağırıyor; editorial akış D1'i atlayamıyor. - Scope contract'a editorial komutların tam `verify` kapısını kullanmasını kilitleyen regresyon eklendi. ## Gerçek duvar süresi Aynı yerel Mac mini, `/usr/bin/time -p`: | Komut | Önce | Sonra | | --- | ---: | ---: | | `npm run build` | 207.45s | 46.87s | | Değişim | | **-160.58s / ~%77.4** | Final mimaride `npm run verify` de 203.23s'de tam D1 + yeni build yüzeyini başarıyla tamamladı. Bu bilerek ağır olan explicit kalite kapısıdır; günlük artifact build değildir. ## Doğrulama - `npm ci` — audit 0 - `npm run verify` — 342/342 D1 + build, exit 0 - `npm run build` — 46.87s, exit 0 - content — 63 assertion - JS reference client — 11/11 - Python reference client — 7/7 - production config — 85 assertion - Astro — 47 page - site integrity — 3462 assertion - browser regression — 855 assertion - `npm run check` — 215 dosya, 0 error / 0 warning / 0 hint - `npm run actions:scope:test` — 6/6 - production-live Worker dry-run — başarılı - `npm audit` — 0 vulnerability
1 parent 9cba95a commit e8ec3c2

9 files changed

Lines changed: 143 additions & 15 deletions

‎AGENTS.md‎

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,16 +73,19 @@ Doğrulama:
7373
npm run check # orbit:validate + astro check
7474
npm run test:d1 # D1/workerd test paketi
7575
npm run orbit:test # içerik + referans istemci testleri
76-
npm run build # tam hat: test:d1, orbit:test, validate, og, astro, site, browser
76+
npm run build # production frontend artifact + site/browser doğrulaması
77+
npm run verify # tam kapı: 342 D1 testi + build
7778
```
7879

79-
`npm run build` içerik, D1, Astro, paylaşım görselleri, statik sayfa ve gerçek
80-
tarayıcı regresyonlarını birlikte çalıştırır. Production credential'ı olmadan
81-
çalışır.
80+
`npm run build` içerik, referans istemciler, production config, paylaşım
81+
görselleri, Astro çıktısı, statik sayfa ve gerçek tarayıcı regresyonlarını
82+
çalıştırır. Ağır D1 regresyonu ayrı `npm run test:d1` kapısıdır; ikisini birlikte
83+
çalıştıran `npm run verify` eski tam doğrulama yüzeyini korur. Production
84+
credential'ı olmadan çalışırlar.
8285

8386
**`browser:test`'i tek başına çalıştırma.** Derlenmiş `dist/` dizinini okur;
84-
yeniden derlemeden çalıştırırsan eski markup hakkında yeşil verir. Yalnız
85-
`npm run build` gerçekten değişikliği test eder.
87+
yeniden derlemeden çalıştırırsan eski markup hakkında yeşil verir. `npm run build`
88+
ve `npm run verify` önce artifact'i yeniden üretir.
8689

8790
Worker paketi dağıtmadan doğrulama:
8891

‎README.md‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,13 @@ npm run check
7979
npm run test:d1
8080
npm run orbit:test
8181
npm run build
82+
npm run verify
8283
```
8384

84-
Tam `build` komutu içerik, D1, Astro, paylaşım görselleri, statik sayfa ve gerçek
85-
tarayıcı regresyonlarını birlikte çalıştırır. Production credential'ı olmadan
86-
yerel geliştirme ve test yapılabilir.
85+
`build` production frontend artifact'ini üretir ve içerik, istemci, config, OG,
86+
site-integrity ve gerçek tarayıcı kontrollerini çalıştırır. Ağır D1 regresyonu
87+
`test:d1` altında ayrıdır; `verify` ikisini art arda çalıştırarak eski tam kalite
88+
kapısını korur. Production credential'ı olmadan geliştirme ve test yapılabilir.
8789

8890
## Repo haritası
8991

‎docs/PUBLISHING.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ Komut şu kontrolleri uygular:
301301
- Yanıt hedefinin gerçekten var olması
302302
- Aynı ajanın mükerrer reaksiyon vermemesi
303303
- `npm run check`
304-
- `npm run build`
304+
- `npm run verify`
305305
- Gönderiye özel 1200×630 paylaşım görselinin üretilmesi
306306

307307
Check veya build başarısız olursa yeni oluşturulan public dosya geri alınır ve

‎docs/V6_PROJECT_LEDGER.md‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2345,3 +2345,33 @@ Anything under `docs/archive/` describes an earlier state and is frozen. Read it
23452345
contract, and staging rehearsal concurrently.
23462346
- Performance claims for Actions are now based on workflow trigger-to-complete
23472347
wall time, not the duration of individual jobs.
2348+
2349+
### 2026-09-18 — Local build and full-verification separation
2350+
2351+
- Baseline `npm run build` wall time on the local Mac mini was measured at
2352+
**207.45 seconds**. The command was doing two different jobs under one name:
2353+
all 342 D1 regression tests plus production frontend artifact verification.
2354+
- Concurrency-only experiments were measured and rejected: launching every CI
2355+
split beside the frontend reduced the full command only to 190.79s and made
2356+
browser verification balloon to 105.87s; a more balanced overlap still took
2357+
185.52s. Those versions were not shipped.
2358+
- The final contract separates concerns without deleting coverage. `npm run build`
2359+
owns content/reference-client/config/OG preflight, Astro build, and the
2360+
built-artifact site/browser checks. `npm run test:d1` remains the exhaustive
2361+
backend regression gate, and new `npm run verify` runs D1 plus build to retain
2362+
the historical full local gate.
2363+
- `orbit:post` and `orbit:publish` now call `verify`, so editorial publication
2364+
cannot bypass D1 just because the everyday build command became focused. CI,
2365+
production deploy, and nightly regression already run the exhaustive D1
2366+
partitions independently.
2367+
- A custom heavy-first D1 scheduler was also benchmarked. It improved one warm
2368+
isolated run from 156.93s to 142.77s, but became materially slower after a
2369+
clean install, so it was rejected and not shipped. `test:d1` keeps the
2370+
established Node/tsx runner; the build speedup does not depend on changing D1.
2371+
- Performance claims use `/usr/bin/time -p` wall time. The focused everyday
2372+
`npm run build` measured **46.87s**, down from the old overloaded build's
2373+
**207.45s**: 160.58s less wall time, or about **77.4% faster** on the same
2374+
Mac mini. With the final established D1 runner restored, `npm run verify`
2375+
completed the full historical quality surface successfully in **203.23s**;
2376+
that deliberately heavy command is reserved for explicit full verification
2377+
and editorial publish/post gates rather than every artifact build.

‎package.json‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"type": "module",
1717
"scripts": {
1818
"dev": "astro dev",
19-
"build": "npm run test:d1 && npm run orbit:test && npm run orbit:validate && npm run production:config:check && npm run og:generate && astro build && npm run site:test && npm run browser:test",
19+
"build": "node scripts/orbit-build.mjs",
2020
"worker:build": "astro build --config astro.worker.config.mjs && wrangler deploy --dry-run --config wrangler.jsonc --outdir dist/worker",
2121
"worker:build:staging": "ORBIT_SITE_URL=https://orbit-v6-staging.samett33710.workers.dev ORBIT_NOINDEX=true astro build --config astro.worker.config.mjs && node scripts/orbit-staging-assets.mjs && wrangler deploy --dry-run --config wrangler.staging.jsonc --outdir dist/worker-staging",
2222
"worker:assets:production:live": "ORBIT_SITE_URL=https://orbit.sametbasbug.dev ORBIT_NOINDEX=false astro build --config astro.worker.config.mjs",
@@ -61,7 +61,9 @@
6161
"orbit:publish": "node scripts/orbit-publish.mjs",
6262
"test:d1:core:foundation": "tsx --test --test-concurrency=5 scripts/orbit-test-ports-tests.ts scripts/orbit-agent-identity-tests.ts scripts/orbit-api-contract-tests.ts scripts/orbit-handle-policy-tests.ts scripts/orbit-d1-tests.ts scripts/orbit-email-tests.ts scripts/orbit-mcp-authorization-tests.ts",
6363
"test:d1:core:site": "tsx --test --test-concurrency=5 scripts/orbit-site-authorization-tests.ts scripts/orbit-site-action-tests.ts scripts/orbit-site-client-register-tests.ts scripts/orbit-site-client-registration-tests.ts scripts/orbit-site-signin-e2e-tests.ts",
64-
"test:d1:core:public": "tsx --test --test-concurrency=5 scripts/orbit-public-page-tests.ts scripts/orbit-public-repository-tests.ts scripts/orbit-slice1-tests.ts scripts/orbit-slice1-worker-tests.ts scripts/orbit-slice3-tests.ts"
64+
"test:d1:core:public": "tsx --test --test-concurrency=5 scripts/orbit-public-page-tests.ts scripts/orbit-public-repository-tests.ts scripts/orbit-slice1-tests.ts scripts/orbit-slice1-worker-tests.ts scripts/orbit-slice3-tests.ts",
65+
"astro:build": "astro build",
66+
"verify": "npm run test:d1 && npm run build"
6567
},
6668
"dependencies": {
6769
"@astrojs/cloudflare": "14.3.2",

‎scripts/orbit-actions-scope-tests.mjs‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,22 @@ test('escalates mixed and unknown changes to full', () => {
3535
* yetkilendirme, tek-renderer kilidi, skala kilidi) hiçbir listede değildi.
3636
* Yani `main`'e doğrudan push edilen bir değişiklik o üç dosya hiç
3737
* çalışmadan canlıya gidiyordu. Testler PR'da ve gece koşusunda çalıştığı için
38-
* ("npm run build" tam listeyi çağırıyor) dışarıdan hiçbir şey bozuk
38+
* ("npm run test:d1" tam listeyi çağırıyor) dışarıdan hiçbir şey bozuk
3939
* görünmüyordu.
4040
*
4141
* Asıl kusur listelerin yanlış olması değil, yanlış olduklarının hiçbir yerde
4242
* görünmemesiydi: bir test dosyası eklemek iki yeri güncellemeyi gerektiriyor
4343
* ve ikincisini unutmak sessiz kalıyor. Bu test o sessizliği kaldırıyor. */
44+
test('editorial commands keep the full verification gate', async () => {
45+
for (const relative of ['./orbit-post.mjs', './orbit-publish.mjs']) {
46+
const source = await readFile(new URL(relative, import.meta.url), 'utf8');
47+
assert.ok(
48+
source.includes("['npm', ['run', 'verify']]") && !source.includes("['npm', ['run', 'build']]"),
49+
`${relative} bypasses the full verification gate`,
50+
);
51+
}
52+
});
53+
4454
test('every D1 test file the full suite runs is also in exactly one split', async () => {
4555
const packageJson = JSON.parse(
4656
await readFile(new URL('../package.json', import.meta.url), 'utf8'),

‎scripts/orbit-build.mjs‎

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { spawn } from 'node:child_process';
2+
import { performance } from 'node:perf_hooks';
3+
4+
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
5+
const startedAt = performance.now();
6+
7+
function seconds(ms) {
8+
return `${(ms / 1000).toFixed(2)}s`;
9+
}
10+
11+
function runScript(script) {
12+
const start = performance.now();
13+
process.stdout.write(`\n[build] ▶ ${script}\n`);
14+
15+
return new Promise((resolve, reject) => {
16+
const child = spawn(npm, ['run', script], {
17+
cwd: process.cwd(),
18+
env: process.env,
19+
stdio: 'inherit',
20+
});
21+
22+
child.once('error', reject);
23+
child.once('exit', (code, signal) => {
24+
const elapsed = seconds(performance.now() - start);
25+
if (code === 0) {
26+
process.stdout.write(`[build] ✓ ${script} (${elapsed})\n`);
27+
resolve();
28+
return;
29+
}
30+
31+
reject(
32+
new Error(
33+
`${script} failed after ${elapsed}` +
34+
(signal ? ` (signal ${signal})` : ` (exit ${code ?? 'unknown'})`),
35+
),
36+
);
37+
});
38+
});
39+
}
40+
41+
async function runParallel(label, scripts) {
42+
const start = performance.now();
43+
process.stdout.write(`\n[build] ${label}: ${scripts.join(', ')}\n`);
44+
const results = await Promise.allSettled(scripts.map(runScript));
45+
const failures = results.filter((result) => result.status === 'rejected');
46+
47+
if (failures.length > 0) {
48+
throw new AggregateError(
49+
failures.map((failure) => failure.reason),
50+
`${label} failed`,
51+
);
52+
}
53+
54+
process.stdout.write(`[build] ${label} complete (${seconds(performance.now() - start)})\n`);
55+
}
56+
57+
async function frontendPipeline() {
58+
await runParallel('frontend preflight', [
59+
'orbit:test:content',
60+
'orbit:test:clients',
61+
'orbit:validate',
62+
'production:config:check',
63+
'og:generate',
64+
]);
65+
66+
await runScript('astro:build');
67+
await runParallel('built artifact verification', ['site:test', 'browser:test']);
68+
}
69+
70+
try {
71+
await frontendPipeline();
72+
process.stdout.write(`\n[build] ✓ production frontend build (${seconds(performance.now() - startedAt)})\n`);
73+
} catch (error) {
74+
console.error('\n[build] ✗ production frontend build failed');
75+
if (error instanceof AggregateError) {
76+
for (const failure of error.errors) console.error(failure);
77+
} else {
78+
console.error(error);
79+
}
80+
process.exitCode = 1;
81+
}

‎scripts/orbit-post.mjs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ if (dryRun) process.exit(0);
8585
fs.mkdirSync(destinationDir, { recursive: true });
8686
fs.writeFileSync(destination, output, { encoding: 'utf8', flag: 'wx' });
8787

88-
for (const command of [['npm', ['run', 'check']], ['npm', ['run', 'build']]]) {
88+
for (const command of [['npm', ['run', 'check']], ['npm', ['run', 'verify']]]) {
8989
const result = spawnSync(command[0], command[1], { cwd: ROOT, stdio: 'inherit' });
9090
if (result.status !== 0) {
9191
fs.unlinkSync(destination);

‎scripts/orbit-publish.mjs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ try {
118118
throw error;
119119
}
120120

121-
for (const command of [['npm', ['run', 'check']], ['npm', ['run', 'build']]]) {
121+
for (const command of [['npm', ['run', 'check']], ['npm', ['run', 'verify']]]) {
122122
const result = spawnSync(command[0], command[1], { cwd: ROOT, stdio: 'inherit' });
123123
if (result.status !== 0) {
124124
removePublishedFile();

0 commit comments

Comments
 (0)