Skip to content

Commit 3798a05

Browse files
committed
Landing: 문서 본문 청크의 검색 원문 중복을 제거
상황: 원격 Linux landing-build에서 docs/skills/ops/foundation/testing-and-gates.md에 대응하는 문서 청크가 103,527바이트로 102,400바이트 예산을 1,127바이트 초과했다. 로컬의 이전 build는 문서 갱신 전 산출물이어서 100,676바이트로 보였고, 새 빌드로 재현하자 pageContent가 화면용 html과 검색용 text를 함께 담는 중복 소유가 원인이었다. 변경: landing/scripts/generateContent.js의 writeDocsPageModules가 pageContent에 html만 기록하도록 바꾸고, 검색 원문 text는 기존 searchIndex.js 생성 경로가 계속 단독 소유하게 했다. verifyLandingDocsBundleSplit.py는 53개 생성 module을 전부 JSON으로 해석해 export 형식과 정확한 html 단일 key를 검사하고 최대 원본 크기도 evidence로 남긴다. testing-and-gates.md에는 화면·prerender와 검색 index의 소유 경계를 기록했다. 영향: 문서 route의 동적 로딩, SSR/prerender, llms-full mirror는 기존처럼 html을 사용하므로 화면과 검색 결과는 유지된다. 최대 생성 module은 65,394바이트, 최대 build chunk는 64,905바이트로 줄어 원격 예산 대비 37,495바이트 여유가 생겼다. 문서가 더 커져도 검색 원문이 페이지 chunk에 다시 중복되면 landing-build가 즉시 실패한다. 검증: uv run python -X utf8 tests/run.py gate landing-build 통과, verifyLandingDocsBundleSplit.py 8개 결과 통과(53 modules, largest built 64,905 bytes), CODARO_FRONTEND_BUILD_REUSE=1 환경의 landing-public 통과(SEO·claims·hydration·Playwright 포함), docs 통과, preflight 3/3 통과(root-clean 1.8초, docs 38.0초, backend 402.1초), git diff --cached --check 통과.
1 parent c78c6f6 commit 3798a05

3 files changed

Lines changed: 21 additions & 5 deletions

File tree

‎docs/skills/ops/foundation/testing-and-gates.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ uv run python -X utf8 tests/run.py gate attempts
251251
- `playwright-curriculum-runtime`는 Playwright 전용 학습 트랙을 실제 브라우저에서 검증한다. `curricula/python/automation/browser/playwright/*.yaml`의 structured contract, `meta.packages`, `meta.tags`, `yamlToDocument` 변환을 확인한 뒤 모든 `snippet`과 `exercise.solution`을 `output/test-runner/playwright-curriculum-runtime/scratch` 아래 Python 파일로 추출해 Chromium에서 실행한다. 결과는 `output/test-runner/playwright-curriculum-runtime/playwright-curriculum-runtime-report.json`에 lesson/sample/failure 단위로 남긴다.
252252
- `onboarding-browser`는 첫 화면에서 provider 연결 전 fallback이 명확하고, 첫 화면의 `Provider 연결` CTA가 provider 설정으로 실제 연결되며, provider 연결 후 실제 응답 사용 상태가 분명한지 본다. 이 gate는 `output/test-runner/onboarding-browser/onboarding-report.json`에 case별 결과와 `providerFallbackBeforeReady`, `providerReadyAfterValidate`, `diagnosticExportCopied` signal을 남기고, `quality-cycle` summary는 이 report를 `payloadGitHead` evidence로 대조한다. product surface 기준이며 landing page 상태를 대체하지 않는다.
253253
- `frontend-performance-budget`는 `editor/vite.config.ts`의 Vite 8 `rolldownOptions.output.codeSplitting` 그룹과 build output을 함께 본다. `yaml`, `curriculumSurface`, CodeMirror, Radix, icon, xterm, vendor 경계가 실제 named chunk로 남아야 한다. 현재 검산값은 curriculum surface 306,128 bytes, entry 180,279 bytes, YAML 206,163 bytes, 최대 CodeMirror 389,437 bytes다. app-shell은 1,877,388 bytes, 473개 lazy curriculum은 12,996,050 bytes로 분리해 추적하며 400,000-byte 단일 JS 예산을 낮추거나 우회하지 않았다. 가장 큰 JS chunk와 전체 JS/CSS 크기는 `output/test-runner/frontend-performance-budget/performance-report.json`에 남긴다. 이 report의 `gitHead`, `startedAt`, `completedAt`, `durationMs`, `payloadGitHead` evidence는 `quality-cycle` artifact freshness 검증에 들어간다.
254-
- `landing-build`는 공개 문서 surface가 generated docs 본문 HTML을 nav chunk에 싣지 않는지도 확인한다. `docsNav.js`는 metadata와 `contentModule`만 담고, 각 문서 본문은 `landing/src/lib/generated/docsPages/page*.js`로 분리되어 slug route에서 동적 로딩되어야 한다. `docs/skills` 핵심 SSOT 문구가 generated docs에 반영되지 않은 stale 상태도 실패로 본다.
254+
- `landing-build`는 공개 문서 surface가 generated docs 본문 HTML을 nav chunk에 싣지 않는지도 확인한다. `docsNav.js`는 metadata와 `contentModule`만 담고, 각 문서 본문 module은 화면과 prerender가 소비하는 `html`만 가진 채 `landing/src/lib/generated/docsPages/page*.js`로 분리되어 slug route에서 동적 로딩되어야 한다. 검색 원문 `text`는 `searchIndex.js`가 소유하므로 페이지 module에 중복하지 않는다. `docs/skills` 핵심 SSOT 문구가 generated docs에 반영되지 않은 stale 상태도 실패로 본다.
255255
- 기존 부채를 새 테스트로 한 번에 해결하지 못하면 별도 baseline 또는 명시적 TODO 문서로 분리한다.
256256
- CI YAML은 세부 명령을 소유하지 않고 `tests/run.py gate <name>`만 호출한다.
257257
- `completion-bootstrap`은 완료 protocol을 소비할 다른 packet보다 먼저 green·CI required로 고정한다. 독립 R10 보고서 완전성은 downstream `plan-quality`가 계속 차단하며 bootstrap packet의 선행 조건으로 되돌리지 않는다.

‎landing/scripts/generateContent.js‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,6 @@ function writeDocsPageModules(pages) {
306306
for (const page of pages) {
307307
const content = {
308308
html: page.html,
309-
text: page.text,
310309
};
311310
writeFileSync(
312311
resolve(generatedDocsPageRoot, `${docsContentModuleName(page.path)}.js`),

‎tests/surface/verifyLandingDocsBundleSplit.py‎

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,26 @@ def verifyDocsPageContentModules() -> dict[str, Any]:
6262
files = sorted(path.glob("page*.js")) if path.exists() else []
6363
if len(files) < MIN_DOC_PAGE_MODULES:
6464
missing.append(f"expected at least {MIN_DOC_PAGE_MODULES} docs page modules, found {len(files)}")
65-
if files and "export const pageContent" not in files[0].read_text(encoding="utf-8"):
66-
missing.append("docs page modules do not export pageContent")
67-
return result("docs-page-content-modules", missing, {"moduleCount": len(files)})
65+
largest = 0
66+
for file in files:
67+
largest = max(largest, file.stat().st_size)
68+
prefix = "export const pageContent = "
69+
text = file.read_text(encoding="utf-8")
70+
if not text.startswith(prefix) or not text.endswith(";\n"):
71+
missing.append(f"{file.name} does not export the canonical pageContent object")
72+
continue
73+
try:
74+
content = json.loads(text[len(prefix):-2])
75+
except json.JSONDecodeError as exc:
76+
missing.append(f"{file.name} contains invalid pageContent JSON: {exc.msg}")
77+
continue
78+
if set(content) != {"html"}:
79+
missing.append(f"{file.name} must contain html only, found {sorted(content)}")
80+
return result(
81+
"docs-page-content-modules",
82+
missing,
83+
{"moduleCount": len(files), "largestBytes": largest, "contentKeys": ["html"]},
84+
)
6885

6986

7087
def verifyGeneratedDocsFreshness() -> dict[str, Any]:

0 commit comments

Comments
 (0)