파이프라인 3단계(Planning) 산출물 · 2026-09-16 · v1.1(Design 반영 2026-09-16) — 흐름 순열(
docs/flow-permutation-fullstack-code-editor.md) Must-Have 12 · Should-Have 8 과 UX 리뷰가 요구한 시나리오를 추가(D-019). Seed 문면 변경 없음 출처:docs/seed-spec-fullstack-code-editor.mdv1.1.1 LOCKED(hash79991d04) §4 AC-01~AC-24 — 정본. 보조: §2 C-02~C-05 · §3 불변식 ·docs/prd-fullstack-code-editor.mdFR ·docs/planning-inputs-fullstack-code-editor.md§7(패널 지적 이관) 표기 규칙은 상위docs/bdd-cocode.md§0 을 승계한다(태그 사다리 · Gherkin 영문 키워드 + 한국어 본문 ·[AC-NN]출처 표기 ·[C-NN]·[불변식]보충 시나리오).
0. 이 문서를 읽는 규칙
0.1 전제 — Seed 는 잠겼다
Seed v1.1.1 은 Specification Gate 를 통과하고 LOCKED 다. 아래 시나리오는 확정된 인수 계약의 판정 절차다. 단 A-01 은 잠정 결정이고 AC-22 는 상위 D-013 에 종속이라 해당 시나리오는 "작성됨 · 판정 보류"로 표기한다.
0.2 수치 규칙
요구사항 수치는 Seed §4 "수치의 출처"에 근거가 있는 것만 쓴다 — 이 문서가 쓰는 요구사항 수치는 다음이 전부다.
| 수치 | 쓰인 곳 | 근거 |
|---|---|---|
| 파일 둘 이상 · 세션 둘 이상 | Feature 2 · 6 | Seed AC-03 · AC-09 열거 하한 |
| 세 선택(저장 · 폐기 · 취소) | Feature 2 | Seed AC-03 열거 |
| 기본 템플릿 3종 + custom 1 | Feature 5 | Seed AC-08 열거 · PRD §2.5 정본 |
| 프로젝트 디렉터리 판정 입력 3종 | Feature 5 | Seed §0 · D-015 |
| 비-Dart 강조 대상 4종 | Feature 4 | PRD FR-407 |
근거 없는 값은 쓰지 않는다. 시나리오 서술용 임의 식별자(파일명 lib/a.dart · 작업 T · 스냅샷 S1)와 이 문서의 구조 카운트는 이 규칙의 대상이 아니다. 값이 미정인 곳은 # 설정값 — <대상>: 미정 / 확정 주체 / 근거 주석을 달고 §0.4 표에 모았다.
0.3 태그 배정
상위 §0.3 사다리를 그대로 쓴다 — ① @error-handling(오류 · 실패 · 위반 · 충돌 · 상한 초과 · 비정상 종료의 처리) → ② @edge-case(경계값 · 부재 확인(Must-Not) · 기본값 · 상태 유지 · 동시 경합 · [C-NN]/[불변식] 보충) → ③ @happy-path(그 외). 게이트 요건은 @happy-path ≥ 1 + @error-handling ≥ 1 뿐이다.
0.4 미정값 · 판정 보류 (값을 지어내지 않는다)
| # | 대상 | 상태 | 확정 주체 | 영향받는 시나리오 |
|---|---|---|---|---|
| U-1 | 탭 N개(응답성 벤치 조건) | 미정 | Planning — 상위 D-065 절차 | (NFR — 이 문서 밖, ac15 벤치) |
| U-2 | scrollback 상한 기본값 | 미정. 존재는 AC-09 가 강제 | Design(설정 기본값) | Feature 6 — "상한 초과" 시나리오(규칙만 검증) |
| U-3 | 파일 감시 감지 지연 상한 | 미정. 존재는 AC-04 가 강제 | Design | Feature 2 — 외부 변경 시나리오(When 앱의 파일 감시가 변경을 감지하면 — 시간 조건 없음) |
| U-6 | DiagnosticsSink 값 타입 · 언어 서버 SandboxProfile | 미정 | Design | Feature 4 — 진단 시나리오는 "표시된다"만 판정 |
| U-7 | RunConfiguration 영속 파일 | 미정(경로 제안) | Design | Feature 5 — 영속 시나리오 없음(Seed 가 영속을 요구하지 않음) |
| U-8 | PTY 패키지 | 미정 | EPIC-6 S1 스파이크 | Feature 6 — 백엔드 종류는 backend_kind=pty 로만 판정 |
| U-9 | D-013 체인 불연속 | 상위 결정 대기 | 상위 파이프라인 | Feature 7 — [AC-22] 시나리오 작성됨 · 판정 보류 |
| U-10 | D-018 기존 폴더 열기 | 상위 결정 대기 | 상위 파이프라인 | 전 Feature 의 Given 워크스페이스가 열려 있다 전제 — 열리는 경로는 이 문서 밖 |
0.5 AC ↔ Feature 대응 (커버리지)
| Seed AC | Type | Feature | 시나리오 수(제목에 그 AC 가 표기된 건수) |
|---|---|---|---|
| AC-01 | Must | 1 | 10 |
| AC-03 | Must | 2 | 10 |
| AC-04 | Must | 2 | 9 |
| AC-06 | Must | 3 | 12 |
| AC-07 | Must | 4 | 11 |
| AC-08 | Must | 5 | 14 |
| AC-09 | Must | 2 · 6 | 13 |
| AC-10 | Must | 7 | 4 |
| AC-11 | Must-Not | 8 | 2 |
| AC-12 | Must-Not | 8 | 1 |
| AC-13 | Must-Not | 7 | 1 |
| AC-22 | Must-Not | 7 | 2 (판정 보류 U-9) |
| AC-23 | Must-Not | 2 · 3 · 4 · 5 · 6 | 9 (Feature 2 에 1 · 3 에 1 · 4 에 3 · 5 에 2 · 6 에 2) |
| May AC-14~21 · 24 | May | — | 0 (첫 릴리스 밖, 의도) |
Must 8/8 · Must-Not 5/5 커버. 시나리오 총 85건(제목에 AC 가 둘 표기된 시나리오가 있어 위 표의 합 98 은 시나리오 수보다 크다; [불변식] 보충 1건은 AC 표기 없음). 태그 집계: @happy-path 23 · @error-handling 24 · @edge-case 38 — 스크립트 실측(^\s+@tag$ 행 계수). v1.3(Development #339): 흐름 순열 권고 R-4(dirty 버퍼 치환)를 시나리오로 승격 — 규칙(UX-E-14)이 단위 테스트로 판정되지만, 「셸이 디스크를 다시 읽지 않는다」는 배선은 단위 테스트가 볼 수 없다. v1.2(Development #338): 흐름 순열 권고 R-3(결과 행 파일 소실)을 시나리오로 승격 — 규칙이 UX-E-12 로 확정돼 있고 픽스처 step 이 이미 있어, 시나리오 없이 두면 규칙만 남고 판정은 위젯 테스트에만 있게 된다. v1.1(Design 반영): Design 리뷰 · 흐름 순열이 요구한 시나리오 29건 추가(Must-Have 12 · Should-Have 대응 + 흐름 순열 rev.1 재판정 R-0 필수 · R-2 · R-5 · R-9 — 각 시나리오의 # 출처 주석 참조).
1. Feature 모음
Feature 1 — 셸 통합과 디렉터리 트리 (AC-01)
Feature: 셸 통합과 디렉터리 트리
Dart 풀스택 개발자로서
워크스페이스를 열면 실제 에디터 · 트리 · 터미널이 보여야
코드를 바로 다룰 수 있다
# 출처: Seed AC-01 / §0 앱 셸 · 셸 통합 / PRD FR-101~105 · FR-301~303
# 전제 U-10: 워크스페이스가 "열리는" 경로는 상위 소관(D-018). 모든 Given 은 열린 뒤에서 시작한다.
Background:
Given 워크스페이스 "W" 가 열려 있다
@happy-path
Scenario: [AC-01] 앱 셸의 세 슬롯에 실제 뷰가 그려진다
When 앱 셸이 그려지면
Then navigation 슬롯에 "W" 의 디렉터리 트리가 표시된다
And editorStack 슬롯에 에디터 뷰 영역이 표시된다
And terminal 슬롯에 터미널 뷰 영역이 표시된다
And 슬롯 이름만 적힌 플레이스홀더 위젯은 어느 슬롯에도 존재하지 않는다
@edge-case
Scenario: [AC-01] 열린 파일이 없으면 editorStack 은 빈 상태 화면을 그린다
Given 열린 파일이 0개다
When 앱 셸이 그려지면
Then editorStack 슬롯에 CoUI "EmptyState.compact" 가 표시된다
# 상위 ux-spec §2.5 빈 상태 표 ⓐ행 계약 — 워크스페이스는 열렸고 파일만 없는 경우
@edge-case
Scenario: [AC-01] workbench 는 컨테이너이며 자체 내용을 갖지 않는다
When 앱 셸이 그려지면
Then workbench 슬롯의 자식은 editorStack 과 terminal 두 슬롯뿐이다
And workbench 슬롯 자체에 텍스트 위젯이 없다
@happy-path
Scenario: [AC-01] 디렉터리를 펼치면 그 시점에 자식만 읽는다
Given 트리에 디렉터리 "lib" 가 접힌 채 표시되어 있다
And "lib" 의 자식은 아직 읽히지 않았다
When 사용자가 "lib" 를 펼치면
Then "lib" 의 직접 자식만 디스크에서 읽혀 표시된다
And "lib" 의 손자 디렉터리 내용은 읽히지 않는다
@edge-case
Scenario: [AC-01] git 이 무시하는 항목은 트리에 표시되지 않는다
Given "W" 는 git 저장소이고 ".gitignore" 가 "build/" 를 무시한다
And "W" 에 디렉터리 "build" 가 존재한다
When 사용자가 루트를 펼치면
Then "build" 는 트리에 표시되지 않는다
# 판정 정본 = git check-ignore 결과(FR-302, OBJ-1-Analyst-5)
@edge-case
Scenario: [AC-01] git 저장소가 아니고 .gitignore 파일도 없으면 제외 항목이 없다
Given "W" 는 git 저장소가 아니고 ".gitignore" 파일도 없다
And "W" 에 디렉터리 "build" 가 존재한다
When 사용자가 루트를 펼치면
Then "build" 가 트리에 표시된다
@edge-case
Scenario: [AC-01] git 저장소가 아니어도 루트 .gitignore 파일 규칙은 적용된다
Given "W" 는 git 저장소가 아니지만 루트 ".gitignore" 가 "build/" 를 무시한다
And "W" 에 디렉터리 "build" 가 존재한다
When 사용자가 루트를 펼치면
Then "build" 는 트리에 표시되지 않는다
# Seed AC-01 은 파일 규칙 기반 — FR-302 후단(순수 Dart matcher, U-14)
@error-handling
Scenario: [AC-01] 읽기 권한이 없는 디렉터리를 펼치면 사유가 표시되고 트리는 계속 동작한다
Given "W" 에 읽기 권한이 없는 디렉터리 "secret" 이 존재한다
When 사용자가 "secret" 을 펼치면
Then "secret" 노드에 읽기 실패 사유가 표시된다
And 다른 디렉터리의 펼치기는 정상 동작한다
@error-handling
Scenario: [AC-01] git 저장소인데 git 실행 파일이 없으면 파일 규칙으로 후퇴하고 판정 불가가 표시된다
# 출처: flow-permutation E-I1 · architecture ED-06a · PRD FR-302 (Design 반영)
Given 워크스페이스 "W" 는 ".git" 디렉터리를 갖는다
And PATH 에 git 실행 파일이 없다
When 사용자가 루트를 펼치면
Then 루트 ".gitignore" 파일 규칙에 해당하는 항목은 트리에 표시되지 않는다
And 트리 상단에 "git 판정 불가" 표시가 보인다
And 그 밖의 항목은 정상적으로 표시된다
@error-handling
Scenario: [AC-01] 읽기 권한이 없는 파일을 열면 탭은 열리되 본문에 사유가 표시되고 편집할 수 없다
# 출처: flow-permutation E-I2 · UX-E-04 (Design 반영)
Given 파일 "lib/secret.dart" 에 읽기 권한이 없다
When 사용자가 트리에서 "lib/secret.dart" 를 선택하면
Then "lib/secret.dart" 탭이 열린다
And 본문 자리에 읽기 실패 사유가 표시된다
And 본문은 편집할 수 없다
And 탭은 닫을 수 있다
Feature 2 — 문서 버퍼 · 탭 · 저장 · 외부 변경 (AC-03 · AC-04 · AC-23)
Feature: 문서 버퍼와 탭, 저장과 외부 변경
Dart 풀스택 개발자로서
탭을 오가고 저장하고 외부 도구와 파일을 공유해도
편집 내용이 소실되지 않아야 한다
# 출처: Seed AC-03 · AC-04 · AC-23 / §3 DocumentBuffer 불변식 (1)(2)(3) / PRD FR-201~207
Background:
Given 워크스페이스 "W" 가 열려 있다
And 파일 "lib/a.dart" 와 "lib/b.dart" 가 탭으로 열려 있다
@happy-path
Scenario: [AC-03] 탭을 전환해도 dirty 버퍼의 내용과 실행 취소 이력이 보존된다
Given 사용자가 "lib/a.dart" 버퍼를 편집해 dirty 상태다
And 편집 전후의 content 해시를 "H1" 로 기록했다
When 사용자가 "lib/b.dart" 탭으로 전환했다가 "lib/a.dart" 탭으로 돌아오면
Then "lib/a.dart" 버퍼의 content 해시는 "H1" 과 같다
And 실행 취소를 요청하면 편집 전 내용으로 돌아간다
@edge-case
Scenario: [AC-03] dirty 탭을 닫으면 세 선택이 제시되고 선택 전에는 버퍼가 남는다
Given "lib/a.dart" 버퍼가 dirty 다
When 사용자가 "lib/a.dart" 탭 닫기를 요청하면
Then "저장" · "폐기" · "취소" 세 선택이 제시된다
And 선택 전에는 "lib/a.dart" 버퍼가 레지스트리에 남아 있다
And "폐기" 는 Enter 키 기본 활성화 대상이 아니다
# 상위 K4 — 파괴적 동작
@edge-case
Scenario: [AC-03] 앱 종료 시 dirty 버퍼 전체 목록을 한 번에 처분한다
Given "lib/a.dart" 와 "lib/b.dart" 버퍼가 모두 dirty 다
When 사용자가 앱 종료를 요청하면
Then dirty 버퍼 목록에 "lib/a.dart" 와 "lib/b.dart" 가 함께 제시된다
And "일괄 저장" · "일괄 폐기" · "취소" 를 선택할 수 있다
And 선택 전에는 두 버퍼 모두 사라지지 않는다
@edge-case
Scenario: [불변식] 같은 path_key 의 버퍼는 최대 하나다
Given "lib/a.dart" 가 탭으로 열려 있다
When 사용자가 트리에서 "lib/a.dart" 를 다시 열면
Then 새 버퍼가 만들어지지 않고 기존 버퍼의 탭이 활성화된다
@happy-path
Scenario: [AC-04] 저장하면 디스크에 기록되고 disk_hash 가 갱신된다
Given "lib/a.dart" 버퍼가 dirty 이고 content 해시가 "H1" 이다
When 사용자가 저장 명령을 실행하면
Then 디스크의 "lib/a.dart" 내용 해시가 "H1" 이다
And 버퍼의 disk_hash 가 "H1" 로 갱신되어 dirty 가 아니다
@error-handling
Scenario: [AC-04][AC-23] 저장 실패는 사유와 함께 표시되고 버퍼는 dirty 로 남는다
Given "lib/a.dart" 버퍼가 dirty 다
And 디스크의 "lib/a.dart" 가 쓰기 불가(읽기 전용)다
When 사용자가 저장 명령을 실행하면
Then 저장 실패 사유(OS 오류 메시지)가 사용자에게 표시된다
And 버퍼는 dirty 로 남는다
@happy-path
Scenario: [AC-04] 외부 변경이 clean 버퍼에 감지되면 디스크 내용으로 다시 읽는다
Given "lib/a.dart" 버퍼가 dirty 가 아니다
And 외부 도구가 디스크의 "lib/a.dart" 내용을 바꿨다
When 앱의 파일 감시가 그 변경을 감지하면
Then 버퍼의 content 가 디스크 내용으로 교체된다
# 설정값 — 감지 지연 상한: 미정 / Design / Seed AC-04 (U-3). 이 시나리오는 시간 조건을 두지 않는다
@error-handling
Scenario: [AC-04] 외부 변경이 dirty 버퍼에 감지되면 덮어쓰지 않고 선택을 제시한다
Given "lib/a.dart" 버퍼가 dirty 이고 content 해시가 "H1" 이다
And 외부 도구가 디스크의 "lib/a.dart" 내용을 바꿨다
When 앱의 파일 감시가 그 변경을 감지하면
Then "다시 읽기" · "내 편집 유지" 선택이 제시된다
And 선택 전 버퍼의 content 해시는 "H1" 그대로다
@error-handling
Scenario: [AC-04] 열린 파일이 삭제되면 버퍼는 보존되고 다시 읽기 선택은 없다
Given "lib/a.dart" 버퍼가 dirty 가 아니다
And 외부 도구가 디스크의 "lib/a.dart" 를 삭제했다
When 앱의 파일 감시가 삭제를 감지하면
Then 버퍼는 사라지지 않고 external_change_pending 상태가 표시된다
And "다시 읽기" 선택은 제시되지 않는다
And 그 탭을 닫으면 AC-03 의 처분(저장 · 폐기 · 취소)이 적용된다
# OBJ-1-Analyst-1 — clean 버퍼도 같은 규칙
@error-handling
Scenario: [AC-04] 열린 파일의 이름이 바뀌면 버퍼는 dirty 로 남는다
Given "lib/a.dart" 버퍼가 dirty 다
And 외부 도구가 디스크의 "lib/a.dart" 를 "lib/c.dart" 로 이름 바꿨다
When 앱의 파일 감시가 이름변경을 감지하면
Then "lib/a.dart" 버퍼는 dirty 인 채 보존되고 external_change_pending 이 표시된다
And "다시 읽기" 선택은 제시되지 않는다
@edge-case
Scenario Outline: [AC-03] dirty 탭 닫기의 세 선택은 각각 정해진 결과를 낳는다
# 출처: flow-permutation Must-Have 4 · PRD FR-206 (Design 반영)
Given "lib/a.dart" 버퍼가 dirty 다
When 사용자가 "lib/a.dart" 탭을 닫고 "<선택>" 을 고르면
Then 디스크의 "lib/a.dart" 는 "<디스크>"
And "lib/a.dart" 탭은 "<탭>"
Examples:
| 선택 | 디스크 | 탭 |
| 저장 | 버퍼 내용으로 기록된다 | 닫힌다 |
| 폐기 | 변경되지 않는다 | 닫힌다 |
| 취소 | 변경되지 않는다 | dirty 로 남는다 |
@edge-case
Scenario: [AC-03] 활성 탭을 닫으면 직전에 활성이었던 탭이 활성이 된다
# 출처: flow-permutation E-I6 · UX-E-05
Given 사용자가 "lib/b.dart" 를 본 뒤 "lib/a.dart" 를 보고 있다
And 두 버퍼 모두 clean 이다
When 사용자가 "lib/a.dart" 탭을 닫으면
Then 활성 탭은 "lib/b.dart" 다
@error-handling
Scenario: [AC-03][AC-09] 워크스페이스 닫기 시 실행 중 세션이 나열되고 계속을 고른 경우에만 전부 종료된다
# 출처: flow-permutation E-C1 · architecture ED-16 · UX-E-18 · PRD FR-206 (Design 반영)
Given 실행 중인 터미널 세션 "zsh" 와 실행 구성 세션 "Flutter 앱 실행" 이 있다
And dirty 버퍼는 없다
When 사용자가 워크스페이스 닫기를 실행하면
Then 처분 다이얼로그에 실행 중 세션 "zsh" 와 "Flutter 앱 실행" 이 나열된다
And 계속 버튼은 Enter 로 기본 활성화되지 않는다
When 사용자가 "취소" 를 고르면
Then 두 세션은 여전히 실행 중이다
When 사용자가 다시 워크스페이스 닫기를 실행하고 "모두 폐기하고 계속" 을 고르면
Then 두 세션의 프로세스는 종료 확인까지 마친 뒤 워크스페이스가 닫힌다
And 앱이 소유한 자식 프로세스는 남아 있지 않다
@error-handling
Scenario: [AC-03][AC-04] 일괄 저장 중 한 파일이 실패하면 닫기는 진행되지 않고 실패 목록이 남는다
# 출처: flow-permutation E-C2 · UX-E-19 · Seed §3 불변식 (2)
Given "lib/a.dart" 와 "lib/b.dart" 버퍼가 모두 dirty 다
And "lib/b.dart" 는 디스크 쓰기가 실패하도록 되어 있다
When 사용자가 앱 종료를 실행하고 "모두 저장하고 계속" 을 고르면
Then "lib/a.dart" 는 디스크에 기록되어 clean 이 된다
And "lib/b.dart" 는 dirty 로 남는다
And 앱은 종료되지 않는다
And 다이얼로그에 "lib/b.dart" 와 실패 사유가 표시된다
And 다시 시도 · 실패분 폐기하고 계속 · 취소 선택이 제시된다
@error-handling
Scenario: [AC-03][AC-04] 단일 탭 닫기에서 저장을 골랐는데 실패하면 탭과 버퍼는 남는다
# 출처: flow-permutation rev.1 R-0(필수, FP-E203 · E-I8) · Seed §3 불변식 (2) · UX-E-37
Given "lib/a.dart" 버퍼가 dirty 다
And "lib/a.dart" 는 디스크 쓰기가 실패하도록 되어 있다
When 사용자가 "lib/a.dart" 탭을 닫고 "저장" 을 고르면
Then 디스크의 "lib/a.dart" 는 변경되지 않는다
And "lib/a.dart" 탭은 dirty 로 남는다
And 본문 상단에 저장 실패 사유가 표시된다
@happy-path
Scenario: [AC-03][AC-04] 워크스페이스 닫기에서 모두 저장하고 계속을 고르면 전부 기록된 뒤 닫힌다
# 출처: flow-permutation rev.1 R-2 · PRD FR-206 · ED-16
Given "lib/a.dart" 와 "lib/b.dart" 버퍼가 모두 dirty 다
And 실행 중 세션은 없다
When 사용자가 워크스페이스 닫기를 실행하고 "모두 저장하고 계속" 을 고르면
Then 두 파일 모두 버퍼 내용으로 디스크에 기록된다
And 워크스페이스가 닫힌다
@edge-case
Scenario: [AC-03] 닫기 절차는 다이얼로그 이후 되돌릴 수 없고 정해진 순서로 진행된다
# 출처: flow-permutation rev.1 R-9 · E-I29 · UX-E-26 · ED-16
Given 실행 중인 언어 서버와 터미널 세션 "zsh" 가 있고 검색이 실행 중이다
And dirty 버퍼는 없다
When 사용자가 워크스페이스 닫기를 실행하고 "모두 폐기하고 계속" 을 고르면
Then 검색이 취소되고, 언어 서버가 종료되고, 세션 "zsh" 가 종료되고, 파일 감시가 해제되고, 버퍼가 해제되는 순서로 진행된다
And 그 사이 어떤 단계에서도 취소 선택은 제시되지 않는다
Feature 3 — 전역 검색과 치환 (AC-06)
Feature: 전역 검색과 치환
Dart 풀스택 개발자로서
서버 · 클라이언트 코드 전체에서 문자열을 찾고 바꿀 수 있어야
스택을 가로지르는 변경을 한 창에서 끝낸다
# 출처: Seed AC-06 · C-03 / PRD FR-302 · FR-304~306
Background:
Given 워크스페이스 "W" 가 열려 있다
And "lib/a.dart" 와 "backend/server.dart" 가 문자열 "endpointName" 을 포함한다
@happy-path
Scenario: [AC-06] 문자열 검색 결과가 파일 · 행 단위로 표시된다
When 사용자가 문자열 "endpointName" 으로 워크스페이스 전체를 검색하면
Then 결과 목록에 "lib/a.dart" 와 "backend/server.dart" 의 일치 행이 각각 표시된다
@happy-path
Scenario: [AC-06] 정규식 검색이 동작한다
When 사용자가 정규식 "endpoint\w+" 으로 검색하면
Then 결과 목록에 "endpointName" 일치 행이 표시된다
@error-handling
Scenario: [AC-06] 정규식 문법 오류는 검색을 실행하지 않고 오류를 표시한다
When 사용자가 정규식 "endpoint(" 으로 검색하면
Then 검색은 실행되지 않고 정규식 문법 오류가 표시된다
@happy-path
Scenario: [AC-06] 결과를 선택하면 그 위치가 에디터에 열린다
Given "endpointName" 검색 결과가 표시되어 있다
When 사용자가 "backend/server.dart" 의 결과 행을 선택하면
Then "backend/server.dart" 가 버퍼로 열리고 커서가 그 일치 위치에 놓인다
@edge-case
Scenario: [AC-06] git 이 무시하는 파일은 검색되지 않는다
Given "W" 는 git 저장소이고 ".gitignore" 가 "build/" 를 무시한다
And "build/gen.dart" 가 "endpointName" 을 포함한다
When 사용자가 "endpointName" 으로 검색하면
Then 결과 목록에 "build/gen.dart" 는 없다
@edge-case
Scenario: [AC-06] 그 사이 사라진 파일의 결과 행은 «삭제됨» 으로 표시되고 열리지 않는다
# 출처: flow-permutation R-3 · E-I12 · ux-spec §4.3 UX-E-12 (#338 에서 추가 — 판정 근거는 그 Story 의 종료 기록)
Given "lib/gone.dart" 가 "endpointName" 을 포함한다
And "endpointName" 검색 결과가 표시되어 있다
When 외부 도구가 "lib/gone.dart" 를 삭제하고 사용자가 그 결과 행을 열려고 하면
Then 그 결과 행에 "삭제됨" 이 표시된다
And 파괴적 알림이 표시된다
And "lib/gone.dart" 는 탭으로 열리지 않는다
@edge-case
Scenario: [AC-06] dirty 버퍼의 치환은 버퍼 내용 기준이다
# 출처: flow-permutation R-4 · E-I14 · ux-spec §4.3 UX-E-14 (#339 에서 추가 — 판정 근거는 그 Story 의 종료 기록)
Given "lib/dirty.dart" 가 "zzUnsavedProbe" 를 포함하고 그 검색 결과가 표시되어 있다
And 사용자가 그 결과 행으로 파일을 열어 저장하지 않은 편집을 넣어 버퍼가 dirty 다
When 사용자가 "zzUnsavedProbe" 를 "zzReplaced" 로 전체 치환하고 저장하면
Then 디스크의 "lib/dirty.dart" 에 저장하지 않은 편집이 살아 있다
And 디스크의 "lib/dirty.dart" 에 "zzReplaced" 가 있다
@happy-path
Scenario: [AC-06][C-03] 치환은 사람 편집으로 적용되고 EditSnapshot 을 만들지 않는다
Given "endpointName" 검색 결과가 표시되어 있다
And "backend/server.dart" 에 대한 EditSnapshot 개수를 "N" 으로 기록했다
When 사용자가 "endpointName" 을 "endpointId" 로 전체 치환하고 저장하면
Then 디스크의 "backend/server.dart" 에 "endpointId" 가 있고 "endpointName" 이 없다
And "backend/server.dart" 의 EditSnapshot 개수는 여전히 "N" 이다
@edge-case
Scenario: [AC-06] 일치가 없으면 빈 상태와 검색어 지우기 동작이 표시된다
# 출처: ux-spec §8 ⓖ · UX-D-31 (Design 반영)
When 사용자가 어떤 파일에도 없는 문자열로 검색하면
Then 결과 목록 자리에 "일치 없음" 빈 상태가 표시된다
And "검색어 지우기" 동작이 제시된다
@edge-case
Scenario: [AC-06] 빈 검색어는 검색을 실행하지 않는다
# 출처: flow-permutation E-I10 · UX-E-11
Given 검색 입력이 비어 있거나 공백만 포함한다
When 사용자가 Enter 를 누르면
Then 검색은 실행되지 않는다
And 결과 목록은 바뀌지 않는다
@edge-case
Scenario: [AC-06] 검색을 중지하면 그때까지의 부분 결과가 유지된다
# 출처: flow-permutation E-I13 · architecture §4.4 취소 토큰
Given 검색이 실행 중이고 결과가 일부 표시되어 있다
When 사용자가 검색 중지를 실행하면
Then 검색은 더 진행되지 않는다
And 표시된 부분 결과는 남는다
@error-handling
Scenario: [AC-06][AC-23] 치환 저장이 일부 파일에서 실패하면 실패 목록이 표시되고 성공분은 유지된다
# 출처: flow-permutation E-I15 · UX-E-14
Given 검색 결과가 "lib/a.dart" 와 "lib/b.dart" 에 걸쳐 있다
And "lib/b.dart" 는 디스크 쓰기가 실패하도록 되어 있다
When 사용자가 모두 바꾸기를 실행하면
Then "lib/a.dart" 의 치환은 디스크에 기록된다
And "lib/b.dart" 의 치환은 버퍼에 남고 dirty 로 표시된다
And 검색 패널 상단에 "lib/b.dart" 와 실패 사유가 표시된다
Feature 4 — 언어 지원: Dart 진단과 비-Dart 구문 강조 (AC-07 · AC-23)
Feature: 언어 지원
Dart 풀스택 개발자로서
Dart 파일에서는 언어 서버의 색상과 진단을, 그 밖의 파일에서는 구문 강조를 받아야
풀스택 워크스페이스의 모든 파일을 한 에디터에서 다룬다
# 출처: Seed AC-07 · C-02 · §0 진단 / PRD FR-401~407
# 설정값 — DiagnosticsSink 값 타입 · 언어 서버 SandboxProfile: 미정 / Design (U-6)
Background:
Given 워크스페이스 "W" 가 열려 있다
@happy-path
Scenario: [AC-07] Dart 파일을 편집하면 언어 서버의 시맨틱 토큰이 색상에 반영된다
Given Dart 언어 서버가 단일 런처로 기동되어 있다
And "lib/a.dart" 가 열려 있다
When 사용자가 "lib/a.dart" 에 클래스 선언을 입력하면
Then 언어 서버가 보낸 시맨틱 토큰의 역할(class)에 대응하는 색상이 그 식별자에 적용된다
@happy-path
Scenario: [AC-07] 진단이 문제 목록과 거터에 표시된다
Given Dart 언어 서버가 기동되어 있고 "lib/a.dart" 가 열려 있다
When 사용자가 "lib/a.dart" 에 타입 오류가 있는 문장을 입력하면
Then "[문제]" 탭에 "lib/a.dart" · 행 · 심각도 · 메시지가 표시된다
And 그 행의 에디터 거터에 오류 표식이 표시된다
@edge-case
Scenario: [AC-07][상위 C5] 진단은 자가 검증 ④ 의 입력이 아니다
Given 진단이 "[문제]" 탭에 표시되어 있다
When 상위 자가 검증 ④(정적 분석)가 실행되면
Then ④ 의 입력은 "dart analyze" 프로세스 결과이고 DiagnosticsSink 의 내용은 사용되지 않는다
# 상위 이슈 #60 AC3 · architecture C5 — 코드 의존 스캔으로 판정(toolchain 은 DiagnosticsSink 구현을 의존하지 않는다)
@error-handling
Scenario: [AC-07][AC-23] 언어 서버 실행 파일이 없으면 상태가 표시되고 편집은 계속된다
Given "dart" 실행 파일이 PATH 에 없다
When 사용자가 "lib/a.dart" 를 열고 편집하면
Then "[문제]" 탭에 언어 서버 부재 상태가 표시된다
And 편집과 저장은 정상 동작한다
@error-handling
Scenario: [AC-07][AC-23] 언어 서버가 종료되면 종료 코드가 표시되고 편집은 계속된다
Given Dart 언어 서버가 기동되어 있고 "lib/a.dart" 가 열려 있다
When 언어 서버 프로세스가 비정상 종료되면
Then "[문제]" 탭에 서버 종료 상태와 종료 코드가 표시된다
And 편집과 저장은 정상 동작한다
@happy-path
Scenario Outline: [AC-07][C-02] Dart 이외 파일에는 파일 이름 또는 확장자에 대응하는 구문 강조가 적용된다
When 사용자가 "<파일>" 을 열면
Then "<언어>" 구문 강조가 적용된다
And 편집과 저장이 AC-03 · AC-04 와 같은 규칙으로 동작한다
Examples:
| 파일 | 언어 |
| backend/migrations/20260916_init.sql | SQL |
| backend/config/development.yaml | YAML |
| backend/Dockerfile | Dockerfile |
| README.md | Markdown |
@edge-case
Scenario: [AC-07][C-02] Dart 이외 파일에는 언어 서버 연결이 요구되지 않는다
Given 어떤 SQL 언어 서버도 설정되어 있지 않다
When 사용자가 "backend/migrations/20260916_init.sql" 을 열면
Then 구문 강조는 적용되고 "[문제]" 탭에 SQL 서버 관련 상태가 표시되지 않는다
# AC-24(May) — 연결은 선택
@happy-path
Scenario: [AC-07] 언어 서버 다시 시작이 성공하면 상태가 실행 중으로 바뀌고 진단은 새 서버의 것으로 교체된다
# 출처: PRD FR-406(v1.1) · architecture ED-10 · UX-E-22
Given 언어 서버가 종료되어 문제 패널에 종료 코드가 표시되어 있다
And 이전 서버의 진단이 목록에 남아 있다
When 사용자가 "언어 서버 다시 시작" 을 실행하면
Then 문제 패널의 상태는 "실행 중" 으로 바뀐다
And 목록은 새 서버가 보낸 진단으로 교체된다
@error-handling
Scenario: [AC-07][AC-23] 언어 서버 다시 시작이 실패하면 사유가 같은 자리에 표시되고 편집은 계속된다
# 출처: flow-permutation E-I16 · PRD FR-406(v1.1)
Given 언어 서버 실행 파일이 없다
When 사용자가 "언어 서버 다시 시작" 을 실행하면
Then 문제 패널의 상태 줄에 재시작 실패 사유가 표시된다
And 열린 Dart 파일의 편집과 저장은 계속 동작한다
@edge-case
Scenario: [AC-07] 진단이 없으면 문제 패널은 빈 상태를 그리고 동작은 제시하지 않는다
# 출처: ux-spec §8 ⓗ · UX-E-17(의도적 무동작)
Given 언어 서버가 실행 중이고 빈 진단 목록을 보냈다
When 사용자가 문제 패널을 보면
Then "문제 없음" 빈 상태가 표시된다
And 어떤 동작 버튼도 제시되지 않는다
@edge-case
Scenario: [AC-07] 파일을 닫아도 그 파일의 진단은 문제 목록에 남는다
# 출처: flow-permutation rev.1 R-5 · E-I18 · UX-E-22
Given 언어 서버가 "lib/a.dart" 에 오류 진단을 보냈고 "lib/a.dart" 가 열려 있다
When 사용자가 "lib/a.dart" 탭을 닫으면
Then 문제 목록에 "lib/a.dart" 의 진단이 여전히 표시된다
When 언어 서버가 "lib/a.dart" 에 빈 진단 목록을 보내면
Then 문제 목록에서 "lib/a.dart" 의 진단이 제거된다
Feature 5 — 실행 구성 (AC-08 · AC-23)
Feature: 실행 구성
Dart 풀스택 개발자로서
서버 · 앱 · 테스트를 한 번의 조작으로 실행하고 멈출 수 있어야
터미널에 명령을 타이핑하지 않고도 풀스택을 돌린다
# 출처: Seed AC-08 · C-05 · §3 RunConfiguration 불변식 / PRD FR-501~507 · §2.5 템플릿 정본
# 설정값 — 영속 파일 스키마: 미정 / Design (U-7). 이 Feature 는 영속을 판정하지 않는다
Background:
Given 워크스페이스 "W" 가 열려 있다
And "W" 안에 pubspec.yaml 이 있는 디렉터리 "app/mobile"(flutter 의존 + lib/main.dart) 과 "backend/server"(serverpod 의존) 이 있다
@edge-case
Scenario: [AC-08] 설치 직후 기본 템플릿 3종이 비어 있지 않은 채 제공된다
Given 사용자가 실행 구성을 하나도 만들지 않았다
When 사용자가 실행 구성 목록을 열면
Then template_kind 가 flutterRun · serverpodStart · dartTest 인 실행 구성이 각각 하나 이상 있다
And 각 실행 구성의 실행 파일과 인자 목록은 비어 있지 않다
And "Serverpod 3.x 서버 실행" 이름의 custom 실행 구성도 있다
# 정본: PRD §2.5 표 (D-017(5) 확정)
@edge-case
Scenario: [AC-08] 단일 프로젝트 워크스페이스에서도 flutterRun 템플릿이 제공된다
Given "W" 에 프로젝트 디렉터리가 "app/mobile" 하나뿐이다
When 사용자가 실행 구성 목록을 열면
Then template_kind 가 flutterRun 인 실행 구성이 있고 working_dir 은 "app/mobile" 이다
@happy-path
Scenario: [AC-08] 실행 구성을 실행하면 단일 런처가 기동하고 origin 세션에 출력이 표시된다
Given "serverpod" 실행 파일이 PATH 에 있고 버전이 4.x 다
When 사용자가 "Serverpod 풀스택 실행" 실행 구성을 실행하면
Then 프로세스가 단일 런처의 humanTerminal 프로파일로 기동된다
And 세션 목록에 origin 이 "Serverpod 풀스택 실행" 인 TerminalSession 이 나타난다
And 프로세스의 표준 출력이 그 세션에 표시된다
@happy-path
Scenario: [AC-08] 세션의 중지 한 번으로 프로세스가 종료된다
Given origin 이 "Serverpod 풀스택 실행" 인 세션이 running 이다
When 사용자가 그 세션의 "중지" 를 한 번 누르면
Then 프로세스가 종료되고 세션 status 가 exited 로 바뀌며 종료 코드가 표시된다
@error-handling
Scenario: [AC-08] 실행 전제가 미충족이면 세션을 만들지 않고 사유를 표시한다
Given "serverpod" 실행 파일이 PATH 에 없다
When 사용자가 "Serverpod 풀스택 실행" 실행 구성을 실행하면
Then 세션은 만들어지지 않는다
And 실행 파일 부재 사유가 표시된다
# 사유 문구는 «자리표시자» — 상위 UX-D-31 과 같은 취급, 문구 승인 주체 미정
@error-handling
Scenario: [AC-08] serverpod CLI 가 3.x 면 사유와 함께 3.x 대체 템플릿을 안내한다
Given "serverpod" 실행 파일이 있고 버전이 3.x 다
When 사용자가 "Serverpod 풀스택 실행" 실행 구성을 실행하면
Then 세션은 만들어지지 않고 버전 미충족(4.x 전용) 사유가 표시된다
And "Serverpod 3.x 서버 실행" 실행 구성이 대안으로 안내된다
# OBJ-1-PM-4 처분
@error-handling
Scenario: [AC-08][AC-23] 기동 실패는 세션에 오류로 표시된다
Given 실행 구성의 실행 파일이 존재하지만 실행 권한이 없다
When 사용자가 그 실행 구성을 실행하면
Then 세션에 기동 실패 오류 메시지가 표시되고 status 가 exited 다
@error-handling
Scenario: [AC-08][AC-23] 실행 구성 파일이 손상되면 목록은 비고 오류가 표시되며 파일은 재생성되지 않는다
# 출처: flow-permutation E-I25 · architecture ED-17 · UX-E-33 · PRD FR-501(v1.1)
Given ".cocode/editor/run_configurations.json" 이 JSON 으로 파싱되지 않는 내용을 담고 있다
When 사용자가 실행 구성 목록을 열면
Then 목록은 비어 있다
And "실행 구성 파일을 읽을 수 없음" 오류와 "JSON 열기" 동작이 표시된다
And ".cocode/editor/run_configurations.json" 의 내용은 변경되지 않았다
@error-handling
Scenario: [AC-08] working_dir 이 사라진 구성은 실행이 거부되고 사유가 표시된다
# 출처: flow-permutation E-I24 · UX-E-33 · PRD FR-505(v1.1)
Given 실행 구성 "Flutter 앱 실행" 의 working_dir 디렉터리가 삭제되었다
When 사용자가 "Flutter 앱 실행" 을 실행하면
Then 세션은 만들어지지 않는다
And 세션 자리에 working_dir 부재 사유가 표시된다
@happy-path
Scenario: [AC-08] flutterRun 이 디바이스 미지정이면 디바이스 목록에서 선택한 뒤 실행된다
# 출처: flow-permutation E-I23 · UX-E-32 · PRD FR-505(v1.1)
Given 실행 구성 "Flutter 앱 실행" 의 명령 템플릿에 디바이스가 지정되어 있지 않다
And 연결된 디바이스가 둘 이상이다
When 사용자가 "Flutter 앱 실행" 을 실행하면
Then 디바이스 선택 다이얼로그가 연결된 디바이스 목록을 보여준다
When 사용자가 디바이스 하나를 고르면
Then 그 디바이스를 지정한 명령으로 세션이 기동된다
And 선택은 실행 구성 파일에 저장되지 않는다
@edge-case
Scenario: [AC-08] 디바이스 선택을 취소하면 실행되지 않는다
# 출처: flow-permutation E-I23 · UX-E-32
Given 디바이스 선택 다이얼로그가 열려 있다
When 사용자가 취소하면
Then 세션은 만들어지지 않는다
And 오류는 표시되지 않는다
@edge-case
Scenario: [AC-08] 프로젝트 디렉터리가 없으면 빈 상태와 JSON 열기 동작이 표시된다
# 출처: ux-spec §8 ⓘ · UX-D-31
Given 워크스페이스에 pubspec.yaml 을 가진 디렉터리가 없다
When 사용자가 실행 구성 목록을 열면
Then "실행할 프로젝트 없음" 빈 상태가 표시된다
And "실행 구성 JSON 열기" 동작이 제시된다
@edge-case
Scenario: [AC-08] 같은 구성을 두 번 실행하면 두 번째 세션 이름에 순번이 붙는다
# 출처: flow-permutation E-I26 · UX-E-24
Given 실행 구성 "Dart 테스트" 의 세션이 실행 중이다
When 사용자가 "Dart 테스트" 를 다시 실행하면
Then 두 번째 세션이 별도 탭으로 만들어진다
And 두 번째 세션의 이름은 "Dart 테스트 #2" 다
And 첫 세션은 영향을 받지 않는다
@happy-path
Scenario: [AC-08] 종료된 실행 구성 세션의 다시 실행은 같은 탭에서 새 세션을 만든다
# 출처: flow-permutation E-I20 · UX-E-23
Given 실행 구성 "Dart 테스트" 의 세션이 종료 코드와 출력을 남기고 exited 상태다
When 사용자가 그 세션의 "다시 실행" 을 실행하면
Then 이전 세션 탭은 닫히고 같은 자리에 새 세션 탭이 만들어진다
And 새 세션에서 프로세스가 기동된다
And 이전 세션의 출력은 표시되지 않는다
Feature 6 — PTY 터미널 세션 (AC-09 · AC-23 · C-04)
Feature: PTY 터미널 세션
Dart 풀스택 개발자로서
통합 터미널에서 flutter run 의 단축키까지 그대로 쓰고 여러 세션을 나란히 돌릴 수 있어야
다른 터미널 앱으로 나가지 않는다
# 출처: Seed AC-09 · C-04 · C-05 · §3 TerminalSession 불변식 (1) / PRD FR-601~610
# 설정값 — scrollback 상한 기본값: 미정 / Design (U-2) · PTY 패키지: 미정 / 스파이크 (U-8)
Background:
Given 워크스페이스 "W" 가 열려 있다
@happy-path
Scenario: [AC-09][C-05] 새 터미널은 단일 런처를 거쳐 PTY 로 기동된다
When 사용자가 새 터미널을 열면
Then TerminalSession 의 backend_kind 가 pty 다
And 셸 프로세스는 단일 런처의 PTY 경로로 기동되었다
And 셸 프로세스의 환경변수는 상위 DD-23a 화이트리스트를 통과한 키만 갖는다
@edge-case
Scenario: [AC-09] 명령 셸은 로그인 셸로 기동되어 프로필의 PATH 를 갖는다
Given 사용자의 셸 프로필이 PATH 에 Flutter SDK 경로를 추가한다
When 사용자가 새 터미널을 열고 "which flutter" 를 입력하면
Then 출력에 Flutter SDK 경로가 표시된다
# OBJ-1-Architect-6 — flutter_ide §6-e 결함 재현 방지
@happy-path
Scenario: [AC-09] 뷰 크기 변경이 프로세스에 전달된다
Given 터미널 세션이 running 이다
When 사용자가 터미널 뷰의 크기를 바꾸면
Then 셸 프로세스가 보는 창 크기(rows · cols)가 새 크기와 같다
@happy-path
Scenario: [AC-09] 키 입력이 실행 중인 프로세스에 그대로 전달된다
Given 터미널 세션에서 키 입력을 기록하는 프로그램이 실행 중이다
When 사용자가 "r" 키를 누르면
Then 그 프로그램이 "r" 바이트를 표준 입력으로 받는다
# flutter run 의 단일 키 명령과 같은 경로
@happy-path
Scenario: [AC-09] 세션을 둘 이상 열고 각각 개별로 종료한다
Given 터미널 세션 "T1" 이 running 이다
When 사용자가 새 터미널 "T2" 를 열면
Then "T1" 과 "T2" 가 모두 running 으로 하단 탭 그룹에 표시된다
When 사용자가 "T1" 만 종료하면
Then "T1" 은 exited 이고 "T2" 는 running 이다
@edge-case
Scenario: [AC-09] 종료된 세션의 출력은 닫기 전까지 남는다
Given 터미널 세션 "T1" 이 출력 "hello" 를 표시한 뒤 exited 됐다
When 사용자가 "T1" 탭을 닫지 않으면
Then "T1" 의 출력 "hello" 가 여전히 표시된다
@error-handling
Scenario: [AC-09] scrollback 이 상한을 넘으면 오래된 줄부터 버려진다
Given 세션의 scrollback 상한이 설정값 "L" 줄이다
# 설정값 — L 의 기본값: 미정 / Design / Seed AC-09 "양의 유한한 상한" (U-2)
When 프로세스가 "L" 보다 많은 줄을 출력하면
Then 버퍼에 보관된 줄 수는 "L" 이고 가장 오래된 줄이 사라졌다
@edge-case
Scenario: [AC-09][C-04] 한글 IME 판정은 상위 cocode/AC-16 재생 워크플로가 담당한다
Given 터미널 세션이 running 이다
When 상위 "probe.ac16-ime-replay" 워크플로가 터미널 표면에 대해 실행되면
Then 판정 결과는 상위 cocode/AC-16 에 기록되고 이 Feature 의 시나리오 판정에는 합산되지 않는다
# 분리 판정 — Seed AC-09 마지막 문장
@error-handling
Scenario: [AC-09][AC-23] PTY 생성에 실패하면 세션 자리에 사유가 표시된다
Given PTY 장치를 열 수 없는 환경이다
When 사용자가 새 터미널을 열면
Then 세션 자리에 PTY 생성 실패 사유가 표시된다
And 실패가 표시 없이 사라지지 않는다
@edge-case
Scenario: [AC-09] 실행 중 세션의 탭 닫기는 비활성이고 명시적 종료를 거쳐야 닫힌다
# 출처: flow-permutation E-C3 · UX-E-20 · PRD FR-606(v1.1)
Given 터미널 세션 "zsh" 가 실행 중이다
Then 세션 탭의 닫기 버튼은 비활성이다
When 사용자가 툴바의 "터미널 종료" 를 실행하면
Then 세션은 exited 가 된다
And 세션 탭의 닫기 버튼이 활성이 된다
When 사용자가 닫기 버튼을 누르면
Then 세션 탭과 출력이 사라진다
@edge-case
Scenario: [AC-09] 세션이 없으면 빈 상태와 새 터미널 동작이 표시된다
# 출처: ux-spec §8 ⓕ · UX-D-31
Given 열린 터미널 세션이 없다
When 사용자가 하단 터미널 탭을 보면
Then "터미널 없음" 빈 상태가 표시된다
And "새 터미널" 동작이 제시된다
@error-handling
Scenario: [AC-09][AC-23] 셸이 기동 직후 종료되면 세션은 종료 코드와 함께 exited 로 남는다
# 출처: flow-permutation E-I21 · UX-E-21
Given 로그인 셸이 기동 직후 0 이 아닌 코드로 종료되도록 되어 있다
When 사용자가 새 터미널을 열면
Then 세션은 만들어지고 곧 exited 상태가 된다
And 세션 자리에 종료 코드가 사유로 표시된다
And 셸이 남긴 출력이 있다면 그대로 보인다
Feature 7 — 사람 편집과 에이전트 작업의 교차 (AC-10 · AC-13 · AC-22)
Feature: 사람 편집과 에이전트 작업의 교차
Dart 풀스택 개발자로서
에이전트가 작업 중인 파일도 내가 자유롭게 편집할 수 있되
내 편집이 롤백으로 조용히 사라지지 않아야 한다
# 출처: Seed AC-10 · AC-13 · AC-22 · C-03 / PRD FR-701~703
# ⚠️ [AC-22] 시나리오는 상위 D-013(RollbackPrecheck 체인 불연속 조건) 확정 전 판정 보류 (U-9)
Background:
Given 워크스페이스 "W" 가 열려 있다
And 실행 중인 DelegatedTask "T" 가 "lib/a.dart" 에 EditSnapshot "S1" 을 남겼다
@happy-path
Scenario: [AC-10] 작업 대상 파일을 열면 표시되고 저장은 차단되지 않는다
When 사용자가 "lib/a.dart" 를 열고 편집한 뒤 저장하면
Then 에디터에 "작업 T 편집 대상" 표시가 보인다
And 저장은 성공해 디스크에 기록된다
@edge-case
Scenario: [AC-10][AC-13] 사람 저장은 EditSnapshot 을 만들지 않는다
Given "lib/a.dart" 의 EditSnapshot 개수가 "N" 이다
When 사용자가 "lib/a.dart" 를 편집하고 저장하면
Then "lib/a.dart" 의 EditSnapshot 개수는 여전히 "N" 이다
And "lib/a.dart" 에 대한 편집 리스가 사람 편집으로 획득되지 않았다
@error-handling
Scenario: [AC-22] 사람 편집 뒤 작업이 다시 편집하면 체인 불연속이 생기고 롤백은 충돌로 제시된다
# 판정 보류 — 상위 D-013 확정 후 실행 (U-9)
Given 사용자가 "lib/a.dart" 를 편집하고 저장해 내용 해시가 "H" 가 됐다
And 작업 "T" 가 "lib/a.dart" 를 다시 편집해 EditSnapshot "S2" 를 남겼고 S2.base 는 "H" 다
And "S2".base 는 "S1".result 와 다르다
When 사용자가 작업 "T" 를 작업 시작 직전 상태로 롤백하면
Then 롤백은 자동 적용되지 않는다
And 롤백 사전검사가 "lib/a.dart" 의 체인 불연속을 충돌로 제시한다
@edge-case
Scenario: [AC-22] 사람 편집이 없으면 체인은 연속이고 롤백은 기존 규칙대로 동작한다
# 판정 보류 — 상위 D-013 확정 후 실행 (U-9)
Given 작업 "T" 가 "lib/a.dart" 를 다시 편집해 EditSnapshot "S2" 를 남겼고 S2.base 는 S1.result 와 같다
When 사용자가 작업 "T" 를 작업 시작 직전 상태로 롤백하면
Then 체인 불연속 충돌은 제시되지 않는다
@edge-case
Scenario: [AC-10] 작업이 종결되면 배너가 제거된다
# 출처: flow-permutation E-I27 · UX-E-27
Given 사용자가 "lib/a.dart" 를 열어 "작업 T 편집 대상" 표시가 보인다
When 작업 "T" 가 완료 · 실패 · 롤백 · 거부 · 중지 중 하나로 종결되면
Then "작업 T 편집 대상" 표시는 사라진다
And 열린 버퍼의 내용과 dirty 상태는 바뀌지 않는다
@edge-case
Scenario: [AC-10] 두 작업이 같은 파일을 편집하면 표시에 둘 다 나열된다
# 출처: flow-permutation E-I28 · UX-E-25
Given 실행 중인 DelegatedTask "T2" 도 "lib/a.dart" 에 EditSnapshot 을 남겼다
When 사용자가 "lib/a.dart" 를 열면
Then 표시에 작업 "T" 와 "T2" 가 모두 나열된다
And 저장은 여전히 차단되지 않는다
Feature 8 — 범위 가드 (AC-11 · AC-12)
Feature: 범위 가드
cocode ADE 유지보수자로서
Dart 전용 포지셔닝과 단일 런처 원칙이 조용히 무너지지 않도록
부재를 기계적으로 확인한다
# 출처: Seed AC-11 · AC-12 · C-02 · C-05 / PRD FR-704 (상위 D-072 형식)
Background:
Given 앱이 설치 직후 상태로 실행되어 있다
And 앱의 소스 트리가 스캔 도구에 제공되어 있다
@edge-case
Scenario: [AC-11] 새 워크스페이스 선택지에 Dart 이외 1급 타입이 없다
When 워크스페이스 생성 선택지 목록을 열거하면
Then 목록의 모든 항목은 Flutter 앱 · Serverpod 서버 · Jaspr 웹 (또는 그 조합) 이다
@edge-case
Scenario: [AC-11] 기본 실행 구성 템플릿에 Dart 이외 언어 · 프레임워크가 없다
When 설치 직후 제공되는 실행 구성 템플릿을 열거하면
Then 모든 템플릿의 실행 파일은 flutter · serverpod · dart 중 하나다
@edge-case
Scenario: [AC-12][C-05] 앱 명령을 터미널 세션 stdin 에 쓰는 경로가 존재하지 않는다
When 소스에서 TerminalSession 의 표준 입력 쓰기 호출처를 스캔하면
Then 호출처는 사용자 키 입력 전달 경로뿐이다
And 실행 구성 · 언어 서버 · 그 밖의 앱 명령 기동은 전부 단일 런처 파일을 지난다
# check_process_launch_allowlist.py 확장분(FR-602) + stdin 쓰기 호출처 스캔
2. 태그 집계 · 게이트 요건
| 태그 | 건수 |
|---|---|
@happy-path |
23 |
@error-handling |
24 |
@edge-case |
38 |
| 합계 | 85 (Scenario Outline 2건은 각 1로 계수) |
- 게이트 요건(
@happy-path≥ 1 ·@error-handling≥ 1): 충족. - 판정 보류: Feature 7 의
[AC-22]2건(U-9). 나머지 83건은 값 없이 규칙으로 판정 가능. - 모든 시나리오는 Background 를 포함해 Given-When-Then 을 갖춘다(Feature 8 은 v1.1 에서 Background 추가).
Generated by cc-product Planning stage (Analyst persona) · 2026-09-16 · Seed v1.1.1 LOCKED 기준 · v1.1 Design 반영