chore(core,admin-template): 리베이스 후 산출물 재빌드 + 코어 테스트 정합

develop 리베이스 중 빌드 산출물을 매 커밋 develop 베이스라인으로 넘겼으므로,
병합된 소스 기준으로 core:build + template:build 를 1회 재실행해 정합화했다.
iife 에 자산 URL 감지 핸들러가, main.css safelist 에 drift_alert amber 클래스가
develop 상위집합과 함께 담겼다.

코어 스위트에서 드러난 실패 4종을 처리했다(직전 세션이 admin 스위트만 돌려 누락):

- assetUrlRecovery(L6): 프로브 판정이 probeAssetUrlMode 로 추출됐는데 테스트가
 옛 detectAssetUrlMode 앵커를 봤다. 앵커 재조준(코드 정상, 테스트 stale).
- TranslationEngine: suffixed 헬퍼 일원화로 쿼리 파라미터 순서가 바뀌었다(서버엔
 무관). 순서 무관 단언으로 정정.
- sitemap sampleData 미커버: editor-spec 의 byDataSourceId 에 sitemap_status/
 sitemap_progress_ws 샘플 추가.
- SectionHeader/ThemeToggle 캡: audit 룰 SSoT 엔 이미 비대상 등록됐으나 테스트
 병행 allowlist 만 어긋나 있었다. allowlist 동기화.

앞 두 건은 훼손→red 로 가드 유효성을 확인했다. 순서상 테스트가 읽는 소스만
바뀌었고 런타임 동작 변화는 없다.
This commit is contained in:
HeuJung
2026-07-23 13:52:09 +09:00
parent d6e1f98a4f
commit 95008ee2af
9 changed files with 75 additions and 40 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,3 +1,4 @@
// e2e:allow 테스트 전용 수정 — 프로브 판정 함수 추출 리팩토링 후 stale 앵커(detect→probe) 정정. 런타임 동작 무변경이며 대상 기능 E2E 는 tests/Playwright/specs/asset-url-mode.spec.ts 로 이미 커버됨.
/**
* 자산 URL 자가 복구 불변식 가드 — 이슈 #486 단위 D (§12 L1~L9).
*
@@ -176,8 +177,8 @@ describe('자산 URL 자가 복구 불변식 (§12)', () => {
);
const source = readFileSync(installerPath, 'utf-8');
const start = source.indexOf('async function detectAssetUrlMode(');
expect(start, 'installer.js 에서 detectAssetUrlMode 를 찾지 못했다').toBeGreaterThan(-1);
const start = source.indexOf('async function probeAssetUrlMode(');
expect(start, 'installer.js 에서 probeAssetUrlMode 를 찾지 못했다').toBeGreaterThan(-1);
// 주석은 제거하고 실행 코드만 본다 — 주석에 남은 "Content-Type" 문구가
// 검사 삭제를 가려주면 가드가 무력해진다(실제로 겪은 오탐).
@@ -1,3 +1,4 @@
// e2e:allow 테스트 전용 수정 — suffixed 헬퍼 일원화(#486)로 바뀐 쿼리 파라미터 순서를 순서 무관 단언으로 정정. 런타임 동작 무변경이며 대상 기능 E2E 는 tests/Playwright/specs/asset-url-mode.spec.ts 로 이미 커버됨.
import { describe, it, expect, beforeEach, vi } from 'vitest';
import {
TranslationEngine,
@@ -1211,9 +1212,13 @@ describe('TranslationEngine', () => {
await engine.loadTranslations('template-1', 'ko', '/api', true);
// bustCache가 true이면 타임스탬프 쿼리 파라미터도 추가됨
// bustCache가 true이면 타임스탬프 쿼리 파라미터도 추가됨.
// 두 파라미터의 순서는 기능상 무의미하다 — #486 에서 URL 조립이 suffixed 헬퍼로
// 일원화되며 v=/_= 순서가 바뀌었다. 순서에 의존하지 말고 둘 다 존재하는지만 검증한다.
expect(global.fetch).toHaveBeenCalledWith(
expect.stringMatching(/\/api\/templates\/template-1\/lang\/ko\.json\?v=1735000000&_=\d+/)
expect.stringMatching(
/\/api\/templates\/template-1\/lang\/ko\.json\?(?=.*\bv=1735000000\b)(?=.*\b_=\d+\b)/
)
);
});
@@ -150,7 +150,7 @@ const NON_TARGET: Record<string, Set<string>> = {
'Card', 'Badge', 'StatusBadge', 'Alert', 'EmptyState', 'LoadingSpinner', 'FormField',
'Label', 'FileInput', 'FileUploader', 'HtmlContent', 'HtmlEditor', 'Accordion', 'IconButton',
'StatCard', 'ProductCard', 'TemplateCard', 'ExtensionBadge', 'Toggle', 'Checkbox',
'ChipCheckbox', 'MultilingualTagInput',
'ChipCheckbox', 'MultilingualTagInput', 'SectionHeader', 'ThemeToggle',
]),
basic: new Set([
'Div', 'Span', 'P', 'H1', 'H2', 'H3', 'H4', 'A', 'Button', 'Img', 'Icon', 'Hr',
File diff suppressed because one or more lines are too long
@@ -1,6 +1,30 @@
{
"comment": "admin 자체 + 코어 SSoT 도메인. locales/admin_menus/me/installed_modules/active_plugins/users 등. 실제 데이터소스 ID 는 착수 시점 admin 레이아웃 data_sources 로 재검증 — 본 블록은 코어 SSoT/공통 폴백.",
"byDataSourceId": {
"sitemap_status": {
"data": {
"last_updated_at": "2026-06-21T15:40:00+09:00",
"realtime_enabled": true,
"progress": {
"status": "completed",
"total": 128,
"written": 128,
"percent": 100
}
}
},
"sitemap_progress_ws": {
"data": {
"last_updated_at": "2026-06-21T15:40:00+09:00",
"realtime_enabled": true,
"progress": {
"status": "running",
"total": 128,
"written": 64,
"percent": 50
}
}
},
"locales": {
"data": [
{
File diff suppressed because one or more lines are too long