Skip to content

Commit ee6194a

Browse files
authored
Merge pull request #82 from decipherhub/fix/deployment-studio-localization-state
fix: gate Deployment Studio progress on verified evidence
2 parents 12da185 + 2b02527 commit ee6194a

6 files changed

Lines changed: 378 additions & 64 deletions

File tree

FEATURES.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,26 @@
99

1010
동시에 하나의 feature만 `active` 상태로 둔다.
1111

12+
## STUDIO-002 — Localized Evidence-Gated Workflow
13+
14+
### Behavior
15+
16+
- Deployment Studio는 한국어를 기본으로 제공하고 사용자가 English로 전환한
17+
선택을 브라우저에 유지한다.
18+
- 설정 저장, Doctor, 배포 계획, 배포, Artifact 검증, DEX 실행 단계는 이전
19+
단계의 실제 evidence가 존재할 때만 완료로 표시한다.
20+
- 후속 단계 데이터가 남아 있더라도 선행 설정이 저장되지 않았다면 완료 표시와
21+
실행 버튼을 fail-closed한다.
22+
23+
### Verification
24+
25+
- `npm test --prefix services/deployment-studio`
26+
- `git diff --check`
27+
28+
### State
29+
30+
passing
31+
1232
## DOC-004 — Product Architecture and Technical Whitepaper
1333

1434
### Behavior

PROGRESS.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ source of truth로 사용한다.
1515

1616
## Completed
1717

18+
- `STUDIO-002 — Localized Evidence-Gated Workflow`: Deployment Studio의 기본
19+
언어를 한국어로 제공하고 English 전환 선택을 유지한다. 설정 저장부터 Doctor,
20+
계획, 배포, Artifact 검증, DEX 실행까지 실제 evidence와 선행 단계가 모두
21+
충족된 경우에만 완료로 표시하도록 workflow 상태를 fail-closed했다.
22+
Deployment Studio smoke test와 `git diff --check`를 통과했다.
1823
- `DOC-004 — Product Architecture and Technical Whitepaper`: current
1924
source-of-truth와 구현을 기준으로 외부 공유용 기술 백서를 작성했다. 문제 정의,
2025
제품 경계, Element/Recipe/Manifest/Operator, Router fill-time enforcement,

services/deployment-studio/test/smoke.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,36 @@ async function main(): Promise<void> {
386386
const app = readFileSync(resolve(webRoot, "app.js"), "utf8");
387387
const css = readFileSync(resolve(webRoot, "styles.css"), "utf8");
388388
new Function(app);
389+
const {workflowCompletion} = require(resolve(webRoot, "app.js")) as {
390+
workflowCompletion(value: Record<string, unknown>): Record<string, boolean>;
391+
};
392+
const prematureWorkflow = workflowCompletion({
393+
project: "treasury-dex",
394+
configReady: false,
395+
doctorReady: true,
396+
planReady: true,
397+
deploymentReady: true,
398+
verified: true,
399+
activationReady: true
400+
});
401+
if (
402+
prematureWorkflow.project !== true ||
403+
Object.entries(prematureWorkflow).some(([stage, complete]) => stage !== "project" && complete)
404+
) {
405+
throw new Error("workflow displayed downstream completion before configuration was explicitly saved");
406+
}
407+
const completedWorkflow = workflowCompletion({
408+
project: "treasury-dex",
409+
configReady: true,
410+
doctorReady: true,
411+
planReady: true,
412+
deploymentReady: true,
413+
verified: true,
414+
activationReady: true
415+
});
416+
if (Object.values(completedWorkflow).some((complete) => !complete)) {
417+
throw new Error("workflow did not display completion after every stage supplied evidence");
418+
}
389419
for (const marker of [
390420
'id="projectMode"', 'id="network"', 'id="assetProfile"', 'id="venueRfq"',
391421
'id="runDoctor"', 'id="reviewPlan"', 'id="deployDemo"', 'id="verifyArtifact"',
@@ -401,6 +431,7 @@ async function main(): Promise<void> {
401431
'id="productionDeploymentId"', 'id="productionDeployer"', 'id="productionOperator"',
402432
'id="productionVenueRfq"', 'id="productionVenueAmm"',
403433
'id="runProductionPreflight"', 'id="generateProductionPlan"', 'id="exportProductionPlan"',
434+
'id="languageToggle"',
404435
"Runtime constraints", "Demo fixtures", "Manual evidence checklist",
405436
"Arbitrum One · production plan only", "GIWA / organization EVM · plan only",
406437
"Production core", "preflight → plan"
@@ -413,15 +444,16 @@ async function main(): Promise<void> {
413444
"startDexDemo", "stopDexDemo", "/runtime/start", "/runtime/stop",
414445
"HELP_CONTENT", "DEMO_BROADCAST_NETWORKS", "selectedNetwork", "selectedModule",
415446
"openContextHelp", "buildProductionConfig", "runProductionPreflight",
416-
"generateProductionPlan", "exportProductionPlan"
447+
"generateProductionPlan", "exportProductionPlan", "initializeLanguage",
448+
"corner-store-studio-language", "프로젝트 방식", "Artifact 검증"
417449
]) {
418450
if (!app.includes(marker)) throw new Error(`studio UI wiring missing: ${marker}`);
419451
}
420452
for (const marker of [
421453
"--ink:", "--signal:", ".studio-shell", ".rail", ".workflow-map", ".status-led",
422454
".artifact-grid", ".boundary-banner", ".help-trigger", ".context-dialog",
423455
".target-switch", ".production-ledger", ".production-actions",
424-
".handoff-actions",
456+
".handoff-actions", ".language-toggle",
425457
"@media (max-width: 820px)"
426458
]) {
427459
if (!css.includes(marker)) throw new Error(`studio visual token missing: ${marker}`);

0 commit comments

Comments
 (0)