형식과 규칙 문서입니다. 에이전트에게 일을 맡겨 쓰는 데는 읽지 않아도 되고, 기록을 다루는 도구를 만들거나 정확한 동작을 확인할 때 봅니다. 처음이라면 Jaekit 이해하기부터 읽으세요.
이 페이지
- 1. 위치와 소유
- 2. PLAN.md
- 2.1 조건표 (## 조건표)
- 2.1.1 결과 계약 (## 결과 계약)
- 2.1.2 검사 입력과 관측
- 2.1.3 최종 후보 근거
- 2.2 범위 (## 범위)
- 2.3 Task 목록 (## Task)
- 2.4 예산 (## 예산)
- 2.5 시간 제한 (## 시간 제한)
- 2.6 실행 환경 (## 실행 환경)
- 3. tasks/T00n.md
- 4. REVIEW.md
- 보증 등급과 검토 순서
- 검증 근거와 관측 범위
- 보증 정책과 반례
- 5. PROGRESS.md
- 5.1 타임라인
- 5.2 완료 뒤 발견
- 5.3 판단 이력과 함께 쓰는 PROGRESS
- 5.4 검수 요약
- 6. 완료 보고
- 7. 예시 (작은 목표, task를 PLAN에 합친 경우)
- 8. ha lint 오류 코드
계약: 실행 묶음 (execution bundle)
이 문서는 실행 묶음 파일의 구성과 필드에 대한 canonical 정의다. 실행 묶음은 Seal의 산출물이다. 실행 묶음이 읽는 목표 문서(Spec의 산출물)는 goal-docs.md에 있다. 실행 기록(runs.jsonl)의 형식은 run-record.md에 있다.
실행 묶음은 한 목표의 바뀌는 계획과 진행을 담는다. 목적은 하나다. 다른 에이전트가 이전 대화 없이 이 묶음만 읽고 남은 일부터 이어서 끝낼 수 있어야 한다. 문서 수를 늘리는 것이 목적이 아니다.
1. 위치와 소유
docs/specs/<goal>/
SPEC.md 목표 문서 진입점: 조건 ID, (선택) 작업 분해 제안 (Spec이 작성, 사용자 소유)
<보조 문서>.md SPEC.md가 링크한 목표 문서 (Spec, 사용자 소유)
amendments/ 수정안 문서 (Spec이 작성, 사용자가 정하기 전까지 목표 밖, goal-docs.md §6.6)
PLAN.md 조건표, 범위, task 목록, 예산
REVIEW.md 실행 전 검토
tasks/T001.md task별 상세 (작은 목표는 PLAN.md 안에 합쳐도 된다)
PROGRESS.md 현재 상태, task 상태, 타임라인, 계획 변경, 막힘, 완료 보고
runs.jsonl 실행 기록 (`ha`만 덧붙인다)
| 파일 | 쓰는 주체 | 바꿀 수 있는 때 |
|---|---|---|
목표 문서(SPEC.md와 링크된 보조 문서) |
사용자(Spec으로 작성) | 사용자가 결정할 때만. 바뀌면 목표 digest가 바뀌어 모든 기록이 stale이 된다. Seal은 읽기만 한다. |
PLAN.md |
실행자 | 언제든. 단, 조건표는 목표 문서의 조건 ID를 참조하고, 계획 변경은 PROGRESS.md에 기록한다. |
REVIEW.md |
실행자(검토용 subagent를 써도 된다) | 실행 전, 그리고 영향이 큰 계획 변경 뒤 |
tasks/ |
실행자 | 계획 변경과 함께 |
PROGRESS.md |
실행자 | 언제든 |
runs.jsonl |
ha만 |
덧붙이기만 한다. |
goal 디렉토리 안의 다른 파일(검증 스크립트, fixture 등)은 묶음 문서가 아니라 코드로 다룬다. 신선도와 범위 확인에 그대로 들어간다(run-record.md §2). 검증에 영향을 주는 파일을 goal 디렉토리에 두어도, 바뀌면 이전 결과가 stale이 된다. 같은 부모 아래 다른 목표의 실행 묶음 파일이 코드 상태에 들어가는지는 규칙 버전에 따른다(run-record.md §4.6). 예외로 amendments/의 수정안 문서는 목표 문서도 코드도 아니다. SPEC.md가 링크해도 목표 문서 집합에 들지 않고, 이 목표의 것과 같은 부모 아래 다른 목표의 것 모두 규칙 버전에 관계없이 코드 상태에서 빠진다(goal-docs.md §6.6, run-record.md §2).
모든 파일은 일반 Markdown이다. ha lint가 읽어야 하는 부분만 아래의 표 형식을 지킨다. 그 밖의 서술은 자유다.
2. PLAN.md
2.1 조건표 (## 조건표)
| 열 | 의미 |
|---|---|
ID |
목표 문서의 AC-n. 조건 문장은 다시 쓰지 않는다. ha가 목표 문서에서 읽는다. 필수 여부도 목표 문서의 (선택) 표시를 따른다(goal-docs.md §2.1). 실행자가 더하는 확인은 EX-n이고 언제나 선택이다. |
종류 |
change(새 동작), maintain(기존 동작 보존), manual(이 환경에서 기계로 확인할 수 없음) |
검증 명령 |
저장소 루트에서 실행할 명령. 코드 span 하나로 쓴다. ha는 셸 없이 argv로 실행하므로 파이프(|), 리다이렉트, &, ;, $, backquote를 쓰지 않는다. 낱말은 공백으로 나누고, 작은따옴표·큰따옴표로 묶을 수 있다. 복잡하면 저장소 안 스크립트를 가리킨다. manual이면 —와 사유를 쓴다. |
검사 경로 |
이 조건을 판정하는 검사 파일 경로(glob 불가). change 조건은 필수다. Baseline 확인에서 이 파일들만 base 위에 덧씌운다. |
Task |
이 조건을 구현하는 task ID 목록 |
규칙은 다음과 같다(ha lint가 확인한다).
- 목표 문서의 모든
AC-n이 조건표에 정확히 한 번 있다. 빠진 ID와 목표 문서에 없는ACID는 오류다. 목표 문서에 ID가 없는 조건이 있으면 오류이고, 실행자는 목표 문서를 고치지 않고 사용자에게 알린다. - 모든 조건에 task가 하나 이상 있다. 모든 task는 조건이나 다른 task의 선행 산출물에 근거한다. 고아 task는 오류다.
change조건은 검증 명령과 검사 경로가 있다.maintain조건은 검증 명령이 있다.manual조건은 사유가 있다.- 기존 테스트 전체를 보존 조건으로 쓰려면
maintain조건을 하나 둔다. 목표 문서에 그런 조건이 없으면EX-n으로 더한다.EX-n은 실행자의 추가 확인이라 상태를 막지 않는다. 반드시 보존해야 하는 동작은 목표 문서의 필수 조건이어야 한다(goal-docs.md §2.3). 그런 조건이 없는데 깨지면 안 되는 동작이 보이면, 실행 전 검토에서 사용자에게 묻는다(§4의 중요한 미결정).
선택 열 baseline을 마지막에 더할 수 있다. 다섯 열 표도 그대로 유효하다. baseline 열의 요구는 run-rules/7에서 해당 change 조건이 baseline을 요구한다는 뜻이고, 빈 칸·—나 열이 없으면 요구하지 않는다. 모든 change 조건의 검사 경로와 구조화 결과 계약은 표시 여부와 관계없이 필요하다.
| ID | 종류 | 검증 명령 | 검사 경로 | Task | baseline |
| --- | --- | --- | --- | --- | --- |
| AC-1 | change | `python3 checks/greeting.py` | checks/greeting.py | T001 | 요구 |
| AC-2 | change | `python3 checks/format.py` | checks/format.py | T001 | — |
change가 아닌 행의 요구, 또는 요구·—·빈 칸 밖의 값은 baseline_marker lint 문제다. 열과 lint는 규칙 버전에 관계없이 읽지만, run-rules/1~run-rules/6은 표시를 판정에 쓰지 않고 기존 baseline 요구·기본 선택·최소량·출력을 유지한다. /7은 지금 PLAN의 표시로 판정한다. 시작 때의 표시와 지금 표시의 차이는 실행 기록 §4.10의 보고에서 읽는다.
2.1.1 결과 계약 (## 결과 계약)
run-rules/3의 change 검사는 구조화 결과 계약에 연결한다. PLAN에는 ID | 선언 경로 표를 두며 해당 change 조건과 저장소 상대 JSON 선언 경로를 대응시킨다. 선언과 생산자·설정 파일은 조건표의 검사 경로에도 포함한다. 단순 nonzero만으로 기대 실패가 되지 않으며 일반 maintain·manual·task를 이 계약으로 강제 이전하지 않는다. /1·/2의 기존 목표는 종전 결과 의미를 유지한다.
선언 경로는 생산자 선언(check-declaration/v1) 대신 러너 어댑터 선언(check-adapter/v1)을 가리킬 수도 있다. 이때 대상마다 이미 있는 시험 하나를 연결하고, 검증 명령은 go test -json …이나 JUnit XML을 쓰는 러너 명령 그대로다. 생산자 파일은 없으므로 검사 경로에는 선언과 연결한 시험 파일을 넣는다. 형식·출력 위치({HA_JUNIT_XML})·판정은 change 검사 결과 §5다. 실제 실행 파일의 지원 정보에 check-adapter/v1이 있을 때만 쓴다.
2.1.2 검사 입력과 관측
Seal 0.1.14부터 쓰거나 바꾸는 검사에 적용한다. 목표를 어느 Seal 버전으로 시작했는지는 따지지 않는다. 이 규칙만을 이유로 기존 목표의 검사, 기록, PROGRESS·REVIEW를 다시 쓰거나 변환하라고 요구하지 않는다. 사용자 확인·승인·질문 단계를 더하지 않는다. 실행자가 규칙을 적용하고 기존 검사를 고칠지 판단한다.
- 검사가 읽는 것. 조건표의 모든 검사(
change,maintain,EX-n, task 명령)와 그 명령이 실행하거나 읽는 생산자·설정·보조 파일은 검사하는 트리와 조건이 지정한 외부 입력만으로 판정한다. 목표의 시작·base 커밋이나 다른 고정 커밋을 검사에 담지 않는다. 시작 기록이나 Core 출력에서 base를 읽어 쓰는 것도 마찬가지다. 저장소의 다른 커밋, ref, 객체를 읽어 판정하지 않는다. 과거 커밋과의 diff, merge-base, 원격 추적 branch,HEAD~n같은 상대 ref, log 범위, 다른 worktree가 그 예다. 일반 성질은 "같은 트리를 가진 전체 clone과 히스토리 없는 clone에서 판정이 같다"이다. 검사가 스스로 만든 합성 저장소의 히스토리는 대상이 아니다. - 유지 조건.
maintain조건은 목표 문서가 요구하는 성질(내용, 출력, 형식, 동작)을 검사하는 트리에서 관측한다. 검사 코드로 "base 커밋 이후 변경 없음"을 확인하는 것은 그 성질의 관측이 아니다. 경로가 아예 바뀌지 않아야 하면 그 경로를바꿀 수 있는 경로밖에 둔다. 그러면 Core가 base 이후 커밋된 변경을out_of_scope로 알리고, 사용자만 해소한다. 검사는 그 파일이 지킬 성질을 보거나, 추적되는 검사 파일에 적은 기대 내용과 비교할 수 있다. - 변경 조건과 baseline. base 커밋에서의 위반은 Core의 baseline 실행으로만 관측한다. baseline은 base 커밋의 임시 worktree에 HEAD의 검사 경로를 덧씌워 실행한다. 검사 코드는 base 커밋을 checkout하거나 읽거나 비교해 baseline을 흉내 내지 않는다. 같은 검사가 실행되는 트리에서 요구 성질을 관측하므로 base에서는 위반을, 변경 뒤에는 통과를 낸다.
- 히스토리 자체가 조건일 때. 태그 종류나 커밋 메시지 형식처럼 조건이 히스토리나 ref에 관한 것이면 검사는 조건이 지정한 범위와 ref만 읽는다. 그 히스토리가 없거나 읽을 수 없으면 위반도 통과도 아니고 오류나 미관측이다. 구조화된 결과를 내는
change검사는 그 상태를 결과 보고에 적는다.maintain,EX-n, task 명령은 종료 코드로만 기록되고 0이 아닌 종료는 모두 실패로 기록된다. 그래서 실행자는ha check전에 지정한 범위와 ref를 읽을 수 있는지 확인한다. 읽을 수 없으면 결과를 기록하지 않는다. 필수 조건이나 task라면 그 조건과 완료를 보류하고 독립 작업을 계속하며, 남은 일이 그것뿐일 때 원인environment의 막힘을 기록한다.EX-n검사는 미관측으로 남으며 완료를 막지 않는다. 이 구분은 §4의 미관측·환경 오류·skip·실제 위반 구분과 같다. 그런 검사가 필요한 이유와 읽는 범위는 실행 전 검토에 적는다. - 선언된 경계. 목표 문서가 가리키거나 바꾸려는 구성 요소가 범위나 신뢰 경계를 스스로 선언했을 수 있다. 특정 버전·릴리스 고정, 과거 판정 보존, import 격리, 제한된 입력이 그 예다. 그 선언은 지금의 동작이므로 목표 문서가 바꾸라고 명시하지 않는 한 지킨다. 목표 문서를 그 구성 요소를 넓히는 해석과 별도 구성 요소를 두는 해석 모두로 만족할 수 있으면, 선언을 지키는 해석을 고르고 실행 전 검토에 명시적 가정으로 남겨 보고에서 되풀이한다. 사용자에게 새로 묻지 않는다. 목표 문서가 그 구성 요소를 바꾸라고 명시하면 새 코드는 선언된 경계 안에 둔다. 예를 들어 새 import도 같은 import 경계를 거친다. 어느 해석도 선언과 목표 문서를 함께 만족하지 못하면 기존 문서 충돌 규칙을 따른다.
2.1.3 최종 후보 근거
계획 규칙이며 고정 순서가 아니다. 방법과 순서는 실행자가 고른다.
- 탐색 중에는 바꾼 곳에 맞는 좁은 검사를 쓴다. 그 결과는 작업 정보이며 근거가 아니다.
- 완료에 필요한 비싼 전체 검증은 최종 후보에서
ha check로 한 번 얻도록 PLAN에 적는다. 같은 후보에서 개발용으로 전체 검증을 돌린 뒤 기록용으로 다시 돌리는 것은 피할 비용이다. ha check는 조건마다 명령을 따로 실행한다. 여러 필수 조건이 같은 전체 회귀를 필요로 하면 한 조건이 그 회귀를 맡고, 다른 조건은 자기 성질을 관측하도록 권한다. 권장이며 강제 절차가 아니다. 공유 실행을 배정할 뿐 조건을 삭제하거나 약화하는 것이 아니며, 조건마다 자기 기록 결과가 필요하다.
2.2 범위 (## 범위)
바꿀 수 있는 경로: glob 목록. 범위 확인의 기준이다. SPEC의 범위·비목표에서 도출하고, 근거가 되는 SPEC 절을 적는다. Seal 0.1.23 이상은 계획이 새로 만들 시험·검사 파일과 그 도우미 파일을 처음부터 여기에 넣어, 그 파일을 더해도 범위 확인을 묻지 않는다. 목표 문서가 바꾸지 말라고 한 경로는 넣지 않는다.테스트 경로: 테스트 정의로 보는 glob 목록. 기존 테스트 정의 변경 확인의 기준이다. 비우면ha의 기본값(tests/**,**/*_test.*,**/test_*.*,**/*.test.*,**/*.spec.*)을 쓴다.유지할 동작: SPEC의 비목표·현재 동작에서 지켜야 할 것다른 목표 실행 묶음: 선택. 이 목표의 검사가 다른 목표의 실행 묶음 파일(PLAN.md,REVIEW.md,PROGRESS.md,runs.jsonl,tasks/)을 입력으로 읽을 때만 둔다. 값은 code span검사 입력하나다. 예:- 다른 목표 실행 묶음: `검사 입력` (이전 목표의 PROGRESS.md를 검사한다)- 선언하면
run-rules/2와run-rules/3에서도 다른 목표의 실행 묶음 파일이 이 목표의 코드 상태에 들어간다. 그 파일만 바뀌어도 이전 결과가 낡고, 그 파일의 변경은 범위 확인에도 들어간다(run-record.md §4.6). ha는 상태를 계산하고 기록할 때의 PLAN에서 이 선언을 읽는다. 진행 중에 더하면 그때부터 적용된다. 지우면 다른 목표의 실행 묶음이 다시 빠지고, 그 때문에 낡았던 결과가 다시 신선해질 수 있다. 더하거나 지우는 것은 계획 변경으로 남긴다.- 항목은 정확히
다른 목표 실행 묶음:으로 시작해야 한다. 이 이름 뒤에 다른 말이 붙거나 콜론이 없으면, 또는 다른 값이거나 code span이 없으면 lint 오류other_bundles_invalid다. run-rules/1목표에서는 다른 목표의 실행 묶음이 원래 코드라 결과가 달라지지 않는다.
- 선언하면
바꿀 수 있는 경로를 넓히는 것은 계획 변경이다. 단, 넓힌 범위가 SPEC의 비목표나 범위와 충돌하면 사용자 결정이 필요하다.
2.3 Task 목록 (## Task)
| 열 | 의미 |
|---|---|
ID |
T001 형식 |
목표 |
어떤 동작을 완성하는가. "파일 생성", "클래스 추가"처럼 동작이 아닌 목표는 피한다. |
근거 |
구현하는 조건 ID |
제안 |
대응하는 작업 분해 제안 W ID 또는 —. 목표 문서에 제안이 있는데 다르게 계획했으면 REVIEW.md의 요구사항 대응에 이유를 남긴다. |
선행 |
먼저 끝나야 하는 task ID |
필수 |
예 | 아니오 |
문서 |
tasks/T001.md 또는 —(PLAN 안에 합친 경우) |
의존성에 순환이 있으면 오류다.
2.4 예산 (## 예산)
검증 실행: 예산 창 안의ha check실행 횟수 상한(baseline 포함). 값을 정확히자동으로 쓰면(검증 실행: 자동)ha start가max(50, ⌈필수 최소량 × 1.5⌉)로 정하고, 사용자 설정 폴더의ha.json에 적은 사전 승인 상한(없으면 50)을 넘으면 기록 없이 시작을 거부한다. 숫자가 든검증 실행항목이 있으면 그 숫자를 쓴다(run-record.md §1.5)경과 시간: 예산 창 안의 첫 기록부터 마지막 기록까지의 시간 상한.4시간,90분,1시간 30분,2h30m처럼 쓴다. 현재 시각이 아니라 기록 시각으로 잰다. 그래서 기다리는 동안 상태를 조회하기만 해서는 늘지 않지만, 기다린 뒤 같은 창에 기록이 붙으면 기다린 시간도 들어간다. 완료 뒤에 시간이 지나도 완료가 취소되지 않는다(run-record.md §5)비용: 알 수 있으면 상한. 관측 수단이 없으면미관측
예산 창은 ha start나 마지막 reopen(사용자의 재작업 요청)에서 시작한다. 기본값은 Seal Skill이 정한다. 사용자가 요청에서 정하면 그 값을 쓴다. Seal 0.1.20 이상은 사용자가 예산을 정하지 않으면 검증 실행: 자동을 쓰고, 시작이 사용자 승인 필요로 멈추면 산정 값과 사전 승인 상한을 보이며 한 번 묻고, 사용자가 승인한 숫자를 검증 실행에 쓴다. 같은 PLAN에 같은 질문을 다시 하지 않는다. Seal은 사전 승인 상한 설정을 쓰거나 고치지 않는다. 시작 전 예산은 줄일 수 있고 증액에는 사용자 결정이 필요하다. 진행 중 PLAN 수정만으로 한도는 바뀌지 않는다. /3는 ha budget으로 같은 창의 총 실행 횟수 상한을 바꾸며 사용량·시간 상한을 유지한다. 증액은 사용자 원문과 문맥, 감액은 이유를 남긴다. /3의 명시적 재개는 최신 횟수 상한을 계승한다. /1·/2는 최초 상한과 기존 재개 의미를 유지한다(run-record.md §5.2).
/4·/5·/6·/7 목표에서는 실행자가 신고한 사용자 대기가 경과 시간에서 빠지고, 사용자가 인용으로 정한 사전 승인 상한 안에서 실행자가 이유만으로 횟수 상한을 올린다(run-record.md §4.7).
2.5 시간 제한 (## 시간 제한)
선택 절이다. run-rules/4·run-rules/5·run-rules/6·run-rules/7 목표에서만 읽고, 그 밖의 규칙으로 시작한 목표는 이 절이 있어도 모든 명령을 900초로 실행한다. PLAN의 ## 시간 제한 절에 - AC-3: 30분, - T002 명령 1: 20분, - EX-4: 1시간 30분처럼 한 줄에 하나씩 쓴다.
- 대상은 명령이 있는 조건 ID(
AC-n,EX-n)나 task와 명령 순번(T002 명령 1, task 문서## 완료 조건의 명령 순서)이다. - 값은 양의 정수와 단위
시간·분·초, 또는 그 조합이다. 최대 7200초(2시간)다. - 최대를 넘는 값, 형식이 맞지 않는 값, 없는 대상, 같은 대상의 두 번째 선언은
time_limit_invalidlint 문제라ha start·ha check가 실행 전에 거부한다. - 선언하지 않은 명령은 900초다. baseline은 그 조건의 제한으로 실행한다. 적용 제한은 명령 digest에 들어가므로, 제한을 바꾸면 이전 결과는 신선하지 않다(run-record.md §4.7).
2.6 실행 환경 (## 실행 환경)
선택 절이다. 검사가 쓰는 도구를 시작 전에 확인하려고 PLAN에 ## 실행 환경 절을 두고, 한 줄에 도구 하나씩 - <이름>: `<점검 명령>` 형식으로 쓴다. 예: - 브라우저: `node scripts/probe-browser.mjs`.
- 절의 범위는 다른 PLAN 절과 같다: 제목 줄부터 fenced code block 밖의 다음 1·2단계 제목 전까지. 빈 줄은 건너뛰고 나머지 줄은 모두 이 형식의 목록 항목이어야 한다. 절 안의 fenced code block도 항목이 아니므로 형식이 아닌 줄이다:
ha doctor는 블록마다 여는 줄을 알린다(바로 이어진 블록도 따로). - 이름은 첫
:앞의 글자에서 앞뒤 공백을 뗀 것이다. 비어 있거나 백틱을 담을 수 없고, 같은 이름은 한 번만 쓴다. - 점검 명령은 조건표의 검증 명령과 같은 규칙을 따른다: 코드 스팬 하나, 셸 문법 없음, 공백이 있는 낱말은 따옴표.
- Seal 0.1.20 이상은 검사에 필요한 도구(브라우저, DB, 컨테이너, 외부 서비스 등)를 이 절에 적고, baseline을 기록하기 전과 재개 뒤 첫 검사 전에
ha doctor를 돌린다. 사용 불가인 도구는 한 질문으로 모아 묻고, 권한이나 설정을 스스로 넓히지 않으며, 기다리는 동안 독립적인 작업을 계속한다. - Seal 0.1.23 이상은 baseline을 기록하기 전에, 목표 문서·계획·프로젝트 지침·코드에서 미리 알 수 있고 사용자의 말이 필요한 결정을 쓸 수 없는 도구와 승인이 필요한 예산까지 모아 한 메시지로 묻는다. 사용자 확인으로만 충족할 조건이 있으면 그 조건과 끝에 확인해 달라고 할 것을 같은 메시지에서 알린다. 물을 것이 없으면 아무것도 묻지 않는다.
- 이 절은
ha doctor만 읽는다.ha doctor는 점검마다 60초 고정 제한으로 실행하고 도구마다사용 가능또는사용 불가와 이유를 보이며, 기록·실행 횟수·실행 묶음에 아무것도 남기지 않는다(run-record.md §1.4). - 형식이 아닌 줄(
environment_item_invalid), 셸 문법(shell_syntax), 빈 명령(command_empty), 낱말로 나눌 수 없는 명령(command_parse), 겹치는 이름(environment_name_duplicate), 둘째## 실행 환경절(environment_section_duplicate)은ha doctor만 파일과 줄로 알리고 어떤 점검도 실행하지 않는다. lint 오류가 아니다: 절이 있든 없든, 어떤 내용이든ha lint·ha start·ha check·ha status의 결과는 같다.
3. tasks/T00n.md
| 절 | 내용 |
|---|---|
| 목표 | 이 task가 완성하는 동작 |
| 근거 | 조건 ID와, 그 조건이 나온 SPEC 절 |
| 선행 조건 | 필요한 task와 그 산출물 |
| 읽을 자료 | 아래 네 구분으로 쓴다. 이전 대화를 모르는 에이전트가 저장소 문서 전체를 다시 읽지 않고 필요한 근거를 찾게 하는 것이 목적이다. |
| 범위 | 바꿀 대상과 유지해야 할 동작 |
| 완료 조건 | 어떤 조건(AC-n)이 통과해야 하는가. Task 단계에서 따로 확인할 명령이 있으면 ## 완료 조건 절의 목록 항목에 코드 span 하나만 써서 적는다(예: - `go test ./pkg/x`). ha check <goal> T001이 이 명령들을 순서대로 실행해 기록한다. 이 기록은 조건 충족에 쓰이지 않는다. |
읽을 자료의 구분
| 구분 | 남길 것 |
|---|---|
| 필수 맥락 | 목표를 이해하는 데 필요한 문서의 해당 절과 코드 위치 |
| 필요할 때 참고 | 세부 설계, 긴 배경 자료 |
| 판단 근거 | 어떤 기존 동작·문서를 근거로 결정했는가 |
| 충돌·미확인 | 문서와 코드가 다른 부분, 아직 확인하지 못한 사실 |
요약은 원문을 찾아가는 안내로만 쓴다. 문서 경로와 절을 함께 적고, 요약으로 원래 완료 조건을 대체하지 않는다. 작은 목표에서 task를 PLAN 안에 합쳤다면 같은 구분을 PLAN.md의 ## 읽을 자료 절에 둔다.
4. REVIEW.md
실행 전 검토의 결과다. 검토 통과는 "실행할 준비가 됐다"는 뜻이지 구현이 맞다는 뜻이 아니다.
Spec의 정합성 확인(goal-docs.md §3)과는 대상이 다르다.
- Spec의 정합성 확인: 목표 자체가 명확한가
- 실행 전 검토(이 문서): 그 목표를 구현할 계획과 검증 방법이 충분한가
검토 중 목표 문서의 모순이나 모호함을 찾으면 목표 문서를 고치지 않는다. 사용자에게 묻는다.
| 절 | 확인할 것 |
|---|---|
| 요구사항 대응 | ha lint 결과(누락·고아·순환). SPEC의 범위·비목표가 task에 반영됐는지. 목표 문서의 사용 시나리오가 조건표로 덮이는지. 작업 분해 제안과 다르게 계획한 부분과 그 이유 |
| 불필요한 task | 조건에 기여하지 않는 task |
| 문서 충돌 | SPEC, 프로젝트 문서, 코드 현실 사이의 충돌 |
| 중요한 미결정 | 목표 문서의 ## Open Decisions에 남은 결정, 그리고 계획 중 새로 드러난 결과를 바꾸는 결정(공개 동작·데이터·권한·비가역 설계). 각 항목은 사용자 답변(인용) 또는 "가정"으로 닫는다. 가정은 보고서에 다시 나온다. 구성 요소가 선언한 범위나 신뢰 경계를 지키는 해석은 질문이 아니라 이런 가정이다(§2.1.2). ### 사용자의 답, ### 실행자 가정 순서로 나눈다. ### 사용자의 답의 각 항목에는 결정, 사용자의 답 인용, 그 답이 기록된 곳을 적는다. ### 실행자 가정의 각 항목에는 가정과 그 이유를 적고, SPEC 문장을 해석한 가정에는 그렇다는 표시를 붙인다. 선언된 범위나 신뢰 경계를 지키는 해석은 ### 실행자 가정에 적는다. 결정이 하나도 없으면 없음 한 줄만 둔다. 그렇지 않으면 두 소제목을 모두 두고 빈 쪽에 없음을 쓴다. |
| 검증 방법과 환경 | 조건마다 명령이 이 환경에서 실행 가능한지, 필요한 도구·데이터·네트워크·저장소 히스토리(히스토리는 조건이 히스토리에 관한 것일 때만, 읽는 범위와 함께). 여러 구성요소를 잇는 목표면 경계 너머 확인 조건을 어떤 방법으로 검증하는지 |
| 독립 검토 | SPEC의 Assurance: 등급(없으면 없음), 프로젝트 지침이 요구하는 하한과 따른 쪽, 계획한 검토 단계(plan, candidate, fixes, 누적 라운드) 또는 light에서 생략한 이유, plan 검토가 볼 제품의 불변식과 결정 규칙과 그것을 읽거나 지키는 곳(아래 "보증 등급과 검토 순서"), 새 계약이나 검사가 다루는 열린 입력의 지원 입력 형식. 라운드가 돌면 그 라운드·gate 기록을 가리키고 지적 목록을 옮겨 적지 않는다 |
| 결론 | ready 또는 needs_user(사유) |
나뉜 REVIEW 형식은 seal 0.1.29 이상으로 시작한 목표에 쓴다. 그 전 Seal로 시작한 목표의 REVIEW는 시작할 때의 형식을 유지한다. 이미 있는 REVIEW.md는 나뉜 형식으로 고쳐 쓰지 않는다.
보증 등급과 검토 순서
Seal 0.1.20 이상은 SPEC의 Assurance: 줄(goal-docs.md §2.5)을 읽고 등급에 맞는 독립 검토 단계를 적용한다. 검토의 방법(패킷, 리뷰어, 분류 규칙, 단계 상한)은 Spar가 정하고, 이 계약은 시점과 처리만 정한다.
standard: 좁은 검사가 통과한 최종 후보에서 candidate 단계, 검토 수정 commit 뒤 fixes 단계,ha done전에 누적 라운드를 받는다.strict:standard에 더해 baseline을 기록하기 전에 plan 단계를 받는다. 검토 대상은 계획과 검사 선언, 그리고 이 변경이 도입하거나 바꾸는 제품의 불변식과 결정 규칙(대상 식별, 위치 해석, 재시도, 상한 등)이다.light: 독립 검토를 생략할 수 있고, 생략하면 이유를REVIEW.md와 완료 보고에 남긴다. 받으면 아래 완료 순서를 따른다.- 줄이 없는 목표는 선택된 보증 정책을 따른다. 프로젝트 지침(
AGENTS.md등)의 보증 요구는 하한이다. 등급은 그것을 올릴 수만 있고 낮추지 못하며, 둘이 다르면 더 많은 검토를 요구하는 쪽을 따르고 완료 보고에 각각이 요구한 검토와 따른 쪽을 적는다. - 구현 중에 등급이 바뀌고 사용자가 계속을 요청하면 바뀐 등급을 적용한다. 올라간 등급이 요구하는데 받지 않은 단계는 완료 전에 지금 head에 대해 받고, 이미 받은 검토의 기록은 지우지 않는다.
- 누적 라운드는 Spar candidate 단계를 목표의 base commit부터 마지막 head까지로 다시 부른 라운드다. 독립 검토가 필요한 목표는 누적 라운드가 열린
defect·requirement-question없이 끝난 뒤에만ha done을 실행한다. 수정분만 본 fixes 라운드는 이를 대신하지 못하며, candidate 라운드 뒤에 수정이 없었으면 그 라운드가 누적 라운드다. 누적 라운드가 상한에 걸리면 사용자에게 묻고, 사용자의 말 없이 상한을 넘기거나 건너뛰지 않는다. - 라운드마다 그 라운드 전에 기록된, 목표 문서에 없는 사용자의 결정을 모두 넘긴다:
REVIEW.md## 중요한 미결정을 닫은 사용자의 답, 사용자의 말을 인용한 확인(confirm)과 입력(input), 검토의requirement-question에 대한 사용자의 답. 결정마다 정한 대상(REVIEW.md의 항목이나 확인의 대상)을--decision으로, 기록된 인용을 그대로--decision-quote로 준다. 상한 연장, 리뷰어 waiver,reopen은 넘기지 않는다. plan부터 누적 라운드까지 모든 라운드에 넘긴다. 결정 넘기기는 목표를 어느 Seal로 시작했든 이 Seal이 돌리는 라운드에 쓴다. ## 독립 검토는 변경이 도입하거나 바꾸는 제품 불변식과 결정 규칙마다 그것을 읽거나 지키는 곳을 적는다. 곳마다 저장소 경로를 적고, 그곳에서 쓰는 이름이 변경의 이름과 다르면 그 이름도 적는다. 이름으로 찾은 곳뿐 아니라 같은 불변식을 다른 이름으로 지키는 곳도 넣는다. 바꾸는 불변식이 없으면 없다고 적는다. plan부터 누적 라운드까지 라운드마다, 곳마다 그곳이 head에서도 그 불변식을 지키는지 묻는--question하나를 넘긴다. 목록은 리뷰어가 볼 곳을 더할 뿐 읽는 범위를 좁히지 않는다. 곳 목록은 seal 0.1.25 이상으로 시작한 목표에 쓰고, 이미 있는 목표의REVIEW.md는 새 형식으로 고쳐 쓰지 않는다.- 열린 입력(문장, 경로, 이름, 형식 등)에 대한 계약이나 검사를 더하거나 바꾸면 계획은 plan 검토 전에 지원 입력 형식을 적는다. 그 형식은 SPEC 조건·계약·보호 경로가 요구하는 입력보다 좁을 수 없고, 좁히려면 사용자가 정한다. 형식이 적히지 않은 열린 조건은 사용자에게 묻는다.
- 지적의 처리는 Seal이 정한다.
defect는 고치거나 근거로 반박하고,requirement-question은 사용자에게 묻고(목표 문서는 고치지 않는다), 자동 보류된hardening은 사용자의 말 없이 고치지 않는다. 지원 형식 밖의 입력에 대한 지적은hardening이며,defect로 분류되었으면 계약이 지원 형식을 적은 위치를 근거로 반박한다. run-rules/5·run-rules/6·run-rules/7으로 시작한standard·strict목표는 누적 라운드 뒤 그 series의 라운드로spar gate를 HEAD에 대해 만들고ha note <goal> review --gate <file>로 기록한 다음ha done을 실행한다. 라운드에는 목표 문서를 모두--criteria로 준다. 기록된 gate가 없거나 낡았으면 Core가 완료를 기록하지 않는다(run-record.md §4.8). Spar가 없거나 실행할 수 없으면 완료는 보류되고, 검토 없이 끝내려면 사용자가 등급을light로 낮추는 목표 문서 수정을 정한다. 아래 별도 검토의 인정은 이 목표에 적용하지 않는다.- Spar가 없거나 실행할 수 없으면, 검토가 필수가 아닐 때 진행하고 완료 보고에 독립 검토가 없었다고 적는다.
run-rules/4이하로 시작한 목표에서 검토가 필수이면 완료를 보류하고 원인·영향 조건·부족한 근거·해소 조건을 남긴다. 역할·입력·검토한 버전·지적 또는 지적 없음·한계·확인할 수 있는 참조를 남긴 다른 별도 검토는 필수 검토로 인정하며, 완료 보고는 Spar를 쓰지 않았다는 사실과 쓴 방법을 적고, 그 검토도ha done전에 마지막 head 전체를 본다. - 완료 기록 뒤 사용자가 원격 리뷰 반영을 요청하면 그 요청을 인용한
reopen, 수정, 누적 라운드 한 번, 낡은 필수 검사의 재기록,ha done순으로 진행한다. run-rules/4이하로 시작한 목표에서는ha status·ha done의 판정과 출력이 등급 때문에 바뀌지 않고,run-rules/5·run-rules/6·run-rules/7으로 시작한 목표는 위 gate가 완료 조건이 된다. 그 전 Seal로 시작한 목표의REVIEW.md는 시작할 때의 형식을 유지한다.
검증 근거와 관측 범위
Seal 0.1.10 이상으로 시작한 새 목표는 기존 검토와 완료 보고에 아래 구분을 사용한다. 기존 목표는 시작할 때의 형식을 유지하며, 새 항목의 부재는 미기록이지 실패·미실행의 증거가 아니다. 기존 기록을 자동 변환하거나 과거 관측을 채우지 않는다.
- 기대 결과의 근거: 사용자 요구·공개 계약·합의한 불변식과 위치. 실제 동작·참조 구현을 기준으로 삼았다면 그 선택의 계약과 범위도 밝힌다. 실제 실행이나 fake 기대값 자체는 올바름을 정하는 권위가 아니다.
- 관측할 경계: 확인하려는 실제 셸·DB·HTTP·모델 등의 경계와 범위. 결과에 영향을 주는 환경만 적고 예정·미수행·실제 수행을 구분한다.
- 시험 방법과 대체 환경: 합성 입력·fake·실패 주입·참조 구현 비교가 무엇을 통제하거나 대신하는지. 예시를 전체 입력의 정답으로 확대하지 않는다.
- 덮지 않는 실패 종류: 일반 성질·대표 예시·환경 가정의 공백과 위험한 경계. 남은 위험이 없다는 주장에도 범위를 붙이며 검사 개수는 충분성의 근거가 아니다.
모든 조건은 이 세 축과 공백에 연결한다. 같은 내용을 공유하는 조건 그룹은 한 설명을 참조할 수 있으며 AC별 반복이나 여러 문서의 같은 표 복제는 요구하지 않는다. 기대 근거가 미정·충돌이면 그 상태를 드러내고 완성된 정답처럼 쓰지 않는다.
검토의 예정과 보고의 실제 결과를 연결한다. 조건·검사·환경이 바뀌면 근거의 버전과 적용 범위도 구분하며, 이전 결과를 새 관측으로 쓰지 않는다. 기록으로 확인한 사실과 실행자의 해석을 구분한다. 접근·실행이 막힌 범위와 이유는 미관측으로 남긴다.
needs_user인 중요한 미결정이 남아 있으면 실행하지 않고 사용자에게 묻는다. 클래스명, 파일 배치, 구현 순서처럼 구현자가 정할 수 있는 것은 묻지 않는다(Spec의 질문 원칙과 같다).
보증 정책과 반례
Seal 0.1.11 이상으로 시작하는 새 목표와 사용자가 요청한 영향이 큰 검증 설계 변경은 조건 또는 조건 그룹에 보증 정책의 출처, 필수·선택 여부, 위험의 이유를 연결한다. 잘못된 성공의 영향, 관련 경계, 현재 근거의 공백을 설명하고 고위험 후보를 제외한 이유도 남긴다. 위험도만으로 모든 목표에 같은 agent·모델·기준 검사 전 순서를 강제하지 않는다. 실행자가 이미 정한 필수 보증을 낮추지 않으며 미결정인 결과만 사용자 결정으로 남긴다.
기대 근거·관측 경계·방법과 대체 환경을 분리하고 실제 비교는 같은 성질·입력 범위·환경의 결과와 차이를 연결한다. 조건이 주장하는 성질이나 정책에 필요할 때 실제 경계 근거를 확보하며 실제 시스템이 존재한다는 이유만으로 모든 조건에 호출을 요구하지 않는다. 구조화된 원본과 대상 연결이 있으면 불완전한 문자열 추론으로 대체하지 않는다. fake·합성·참조 구현이나 모델 한 번의 성공을 전체 실제 계약 보장으로 승격하지 않는다.
독립 검토는 별도의 검토이며 초기 입력은 목표·공개 계약·검사·기대 근거다. 구현자의 해법 설명으로 시작점을 고정하지 않지만 필요한 구현·통합 코드도 살필 수 있다. 조건·검사·코드 버전, 제공 맥락, 역할, 확인 가능한 근거, 발견·미발견·미수행과 한계를 남긴다. 자기 검토에 다른 역할 이름만 붙인 것은 독립 검토가 아니며 모델 다양성·인증 신원·충분성 보증을 주장하지 않는다.
반례 후보는 입력·예상 위반·검사의 누락 이유와 연결하고 재현·기각·수정·남은 공백을 구분한다. 원래 조건 위반이 확인되면 완료하지 않는다. 기존 검사를 반복 통과시키고 보고의 위험 문구만 추가하는 것으로 닫지 않으며 놓친 일반 성질을 어떤 검사와 수정 근거로 처리했는지 남긴다. 범위를 바꾸는 제안은 사용자 결정 대상으로 남긴다.
근거를 인정하는 검사는 판정 불가를 성공으로 쓰지 않으며 금지 검사는 판정 불가를 실행 없음으로 숨기지 않는다. 미관측·환경 오류·skip·실제 위반을 보존한다. 판정 불가는 의도한 baseline 위반 근거도 아니다. 증거 충분성과 제품 입력의 허용·거부는 별개다.
필수 검토나 실제 근거가 없으면 원인·영향 조건·부족한 근거·해소 조건을 기록하고 해당 필수 작업을 미완료로 두어 완료를 보류한다. 무관한 작업은 기존 권한·예산 안에서 계속하며 선택 비교는 미관측·위험을 후속 평가로 둘 수 있다. 자동 설치·비용 증가·권한 확대나 사실 없는 검토 기록으로 공백을 채우지 않는다.
목표·검사·코드·기대 근거·환경·정책이 바뀌면 검토 대상 버전과 범위를 보존하고 새 적용 범위를 구분한다. 과거 검토를 새 입력으로 재사용하거나 미기록 검토를 소급 생성하지 않는다. Core의 결정성·local 보증·결과 구분·불리한 이력·예산·권한은 유지하고 방법·시점·검토자·모델·mutation은 실행자가 선택한다.
5. PROGRESS.md
아래 형식은 seal 0.1.20 이상으로 시작한 목표에 쓴다. 그 전 Seal로 시작한 목표는 시작할 때의 PROGRESS 형식을 유지한다. 시작 기록의 Skill 버전은 ha status의 skill: 줄에 있다. seal 0.1.6~0.1.19로 시작한 목표의 ## 현재는 확인 시각(시간대 포함)과 그때의 ha status·ha done 판정과 기록 head를 손으로 적는 짧은 요약이며, 고칠 때마다 확인 시각과 기록 head를 그때 값으로 쓰고 확인 시각은 참고다. 그 밖의 절(## 타임라인, 두 표의 시각 규칙)은 아래와 같다.
| 절 | 내용 |
|---|---|
## 현재 |
짧은 최신 요약(대략 5~8줄). 맨 위에 ha report <goal>이 ## 현재 도장으로 보이는 값을 그대로 붙인다: 기록 head(ha status가 보여 주는 그대로 seq와 hash, 예: seq 2 (0123456789ab). 기록이 아직 없으면(ha start 전) ha status처럼 none), 그 기록에 저장된 시각(시간대 포함), 상태, 완료 기록이 있으면 완료 기록 seq. 확인 시각을 손으로 적지 않는다. 그 아래에 진행 중인 일, 남은 문제, 다음 작업, 재개 방법을 담는다. 기록 head가 바뀔 때마다 새 도장으로 고친다. 이어받는 사람은 기록 head를 ha status와 비교해 낡았는지 본다. 같은 seq라도 hash가 다르면 다른 기록이다. 도장의 시각은 참고다. 지난 경위는 쓰지 않고 ## 타임라인을 가리킨다. 완료 기록을 남길 때는 그 완료 기록 기준이라고 밝히고, 묶음의 마지막 commit 뒤에 일어나 묶음에 남지 않는 일(병합, PR 답글, 병합 뒤 확인 등)을 어디서 보는지 가리킨다. 완료 뒤에 할 일을 진행 중인 일처럼 쓰지 않는다. |
## 검수 요약 |
seal 0.1.24 이상으로 시작한 목표에서 완료 기록 뒤에 쓰는 검수 요약. 사용자가 완료한 목표의 검수를 시작하는 곳이다. 아래 5.4절. ha는 이 절을 읽지 않는다. |
## Task 상태 |
표: Task, 상태(todo | doing | done | dropped | blocked), 메모. done은 주장이다. dropped는 계획 변경 기록이 있어야 한다. |
## 타임라인 |
(선택) 판단이나 다음 행동을 바꾼 사건을 덧붙이는 이력. 아래 5.1절. ha는 이 절을 읽지 않는다. |
## 계획 변경 |
표: 시각, 변경, 이유, 영향, 다시 검토한 것. 조건 종류 변경(예: change → maintain)도 여기에 남긴다. 시각은 시간대를 포함한다. 한 행은 사건 하나다. 같은 사건을 타임라인에도 쓰면 상세 설명은 그 타임라인 항목에만 두고, 행은 한 줄 요약과 그 항목의 시각으로 가리킨다. |
## 막힘 |
표: 시각, 원인 종류(auth | permission | quota | environment | spec | other), 내용, 해소 조건. 종료형 실패는 다시 시도하지 않고 여기에 남긴다. 시각은 시간대를 포함한다. 한 행은 사건 하나다. 같은 사건을 타임라인에도 쓰면 상세 설명은 그 타임라인 항목에만 두고, 행은 한 줄 요약과 그 항목의 시각으로 가리킨다. |
## 개선 메모 |
(선택) 실행자가 본 Seal Skill·템플릿·ha의 문제와 제안. 주장이다. 이 목표 안에서 Skill이나 템플릿을 고치지는 않는다. |
## 완료 보고 |
아래 6절 |
5.1 타임라인
## 타임라인은 선택 절이다. 판단이나 다음 행동을 바꾼 사건을 시간 순서로 덧붙여, 다른 세션에서 이어받는 사람이 "왜 이렇게 바꿨는가"를 알 수 있게 한다. 내용은 실행자의 주장이다.
- 항목 제목:
### <시각> · seq <기록 head> — <종류> · <한 줄 요약>- 시각은 시간대를 포함한 ISO 8601이다(예:
2026-01-01T09:00:00+09:00, UTC면Z). 정확한 시각을 모르면 지어내지 않는다. - seq는 항목을 쓸 때의 기록 head다(제목에는 seq만 쓰고, hash는
## 현재에 쓴다). 기록이 아직 없으면seq none으로 쓴다. 검사 실행에 묶인 항목은 그 실행의 seq를 쓴다. seq는runs.jsonl의 해시 연결로 확인되는 순서라서, 주장인 시각보다 확인하기 쉽다. - 종류는
관측,원인,결정,조치,검증,막힘,재개중 하나다.
- 시각은 시간대를 포함한 ISO 8601이다(예:
- 시각 출처와 판단: 사건 시각과 작성 시각을 구분하고 시각 출처를 남긴다. 원래 사건 시각을 모르면 미상으로 두고 제목에는 실제 작성 시각을 사용할 수 있다. 남은 조건, 새 사실, 가설의 근거, 다음에 줄일 불확실성을 해당하는 만큼 적는다. 매 도구 호출을 기록하지 않으며 같은 코드·환경·가설의 같은 결과를 진전으로 꾸미지 않는다. 반복 뒤에는 원인 분리·다른 가설·막힌 조건처럼 달라진 판단이 드러나야 한다.
- 본문 표시: 원인은
가설·확정·기각, 조치는예정·반영, 검증은대기·통과·실패로 표시한다(예:원인 [확정]: …). 근거는 AC, commit, seq로 가리키고 검사 출력 원문은 옮기지 않는다(6절). - 덧붙이기만 한다. 이전 항목은 고치지 않는다. 그 시점에 대기였다는 것도 이력이다. 판단이 바뀌면 새 항목에 무엇을 어떤 근거로 기각했는지 적는다. 원인 확인부터 검증까지 한 번에 끝난 작은 사건은 한 항목이어도 된다.
- 남기는 것: 판단이나 다음 행동을 바꾼 사건. 새 문제, 원인 확정·변경, 접근 방법 변경, 중요한 검증 결과, 막힘과 재개다. 재개는 다시 일을 시작하는 모든 경우다. 새 세션이 이어받을 때, 막힘이 풀렸을 때,
needs_user에 답을 받았을 때가 해당한다.재개항목에는## 현재가 실제 상태와 달랐던 것이 있으면 그것을 적는다. - 남기지 않는 것: 일상적인 편집과 읽기, 같은 실패의 반복 실행, 변화 없는 진행 보고
- 분량: 항목은 대략 3
6줄,8줄이다. 편집 기준이며 상한이 아니다. 복잡한 원인 분석은 더 쓸 수 있다.## 현재는 대략 5
아래는 형식 설명용 가상 예시다. 실제 실행 기록을 나타내지 않는다.
### 2026-01-01T09:00:00+09:00 · seq 2 — 원인 · AC-1 빈 입력 처리
- 관측: 빈 입력을 읽는 검사에서 오류가 났다(seq 2).
- 원인 [확정]: 첫 항목이 항상 있다고 가정했다. 근거: `src/count.go`의 입력 처리
- 조치 [예정]: 빈 입력일 때 0을 반환한다.
5.2 완료 뒤 발견
Seal 0.1.12 이후의 새 보고는 ## 완료 뒤 발견에 상세를 적거나 한곳의 상세를 참조할 수 있다. 기존 목표의 형식·완료 보고·실행 기록은 자동 변환하지 않고 새 절이 없으면 미기록으로 읽는다. 구형 목표에 새 발견을 덧붙일 때도 과거 관측을 만들거나 원래 완료 보고를 덮어쓰지 않는다.
발견 식별자, 대상 코드·목표·당시 완료 참조, 관련 조건 또는 조건 미포함·연결 미정, 내용·출처·재현 근거·관측 범위·현재 확인 주장·후속 작업을 연결한다. 모르는 값은 미정·없음으로 두며 임의 버전·조건·검사 결과를 채우지 않는다. 사건 시각과 기록 시각을 구분하고 시각 출처를 남긴다. 모르는 사건 시각은 미상이며 작성 시각으로 대신하지 않는다.
후보·확인·중복·기각·해결과 새 요구·기존 조건 위반을 구별한다. 판단이 바뀌면 원본을 보존하고 정정 대상·새 판단·이유·근거를 덧붙인다. 중복은 기준 발견을 가리키고 해결은 수정·재확인 근거와 미확인 범위를 남긴다. 보고 수를 고유한 확인 결함 수로 설명하지 않는다. 문서의 상태 이름은 기계적 최신 상태나 동시 수정 충돌 해결을 보장하지 않는다.
현재 요약은 당시 완료·현재 발견·재작업 요청과 진행 여부를 구별한다. 확인된 기존 조건 위반이 있는데 완료 기록만 앞세워 현재 결함이 없는 것처럼 설명하지 않는다. 상세는 한곳에 두고 요약에서 참조하며 후속 수정·검사를 과거 완료의 근거로 소급하지 않는다.
문서 기록·확인·기각·해결은 기존 완료·실행 예산·사용자 권한을 바꾸거나 재작업을 시작하지 않는다. 명시적인 재작업 요청이 있으면 원문 출처·대상 발견·후속 결과를 연결하고 요청·예정·진행·완료·미요청을 구분한다. 원문 로그와 비공개 대화는 기존 보관 경계를 지키고 허용된 위치·식별자로 참조한다. 공개 예시는 합성이라고 밝힌다. 이 문서 형식은 Core의 구조화 조회나 상태 전이 구현이 아니며 별도 기능 계약을 대신하지 않는다.
사용자 요청 없이 받은 리뷰·PR 지적은 완료 목표의 코드를 고칠 권한이 아니다. 이 형식의 완료 뒤 발견으로 남기고 보고한다. 코드를 고치려면 사용자의 요청과 reopen이 필요하다.
5.3 판단 이력과 함께 쓰는 PROGRESS
Seal 0.1.13 이상으로 시작한 목표는 선택 기능인 판단 이력에 상세 판단을 한 번 남기고 PROGRESS에서 사건 ID(D<n>)로 참조할 수 있다. 그 전 Seal로 시작한 목표는 시작할 때의 PROGRESS 형식과 문서 의무를 유지한다. 기능을 지원하는 환경에서 보조 이력을 추가할 수는 있으나 원래 요구된 설명을 소급 생략하거나 과거 타임라인을 변환하지 않는다. ha는 PROGRESS의 서술 절을 읽지 않으며, 사건 ID 참조가 Task 상태나 완료 판정을 바꾸지 않는다.
| 절 | 판단 이력과 함께 쓸 때 |
|---|---|
## 현재 |
현재 상태, 중요한 결정과 짧은 이유, 남은 문제와 재개 방법을 이력 없이도 이해되게 남긴다. 관련 사건 ID는 보조 참조다. |
## 타임라인 |
인계에 필요한 중요 사건의 짧은 색인이다. 위 5.1의 제목 형식(시각·seq·종류·한 줄 요약)에 사건 ID를 덧붙여 상세를 가리키며 모든 사건을 복제하지 않는다. |
## 계획 변경, ## 막힘 |
기존 열과 필요한 요약을 유지하고 상세는 시각·사건 ID로 참조한다. |
- 상세 이유·근거·관계는 이력에 한 번 쓰고
ha history의 Markdown 조회로 읽는다. 조회용 Markdown을 별도 관리 원본으로 저장하거나 PROGRESS 전체를 자동 생성하지 않는다. 문장 수나 고정 작성 순서는 정하지 않는다. - PROGRESS는 저장에 성공한 사건만 ID로 참조한다. 이력을 쓰지 않았거나, 기능을 쓸 수 없거나, 저장이 실패하거나 적용 여부를 확인하지 못한 판단은 5.1의 형식대로 Markdown에 설명을 남긴다. 필수 인계 내용이 사건 ID 하나로만 남아서는 안 된다.
- 판단 이력은 Git 공통 디렉토리의 로컬 자료라서 새 clone이나 다른 기기로 따라가지 않는다. 그곳에서는 상세 이유·근거·관계가 없고, PROGRESS에 남긴 현재 상태·중요한 결정과 짧은 이유·재개 방법만 이 손실을 일부 보완한다. 이 보완은 상세 이력의 복원이 아니다.
- 기록할 사건과 시점, 관계 연결, 작은 사건 묶기는 실행자가 정한다. 남길 사건의 기준은 5.1과 같다. 이 기능만의 사람 승인 절차나 회고 의무는 없다.
5.4 검수 요약
## 검수 요약은 seal 0.1.24 이상으로 시작한 목표에 쓴다. 그 전 Seal로 시작한 목표는 시작할 때의 PROGRESS와 보고 형식을 유지한다. 이미 있는 목표의 PROGRESS.md는 새 형식으로 바꾸지 않는다.
사용자가 완료한 목표의 검수를 시작하는 절이다. 무엇이 바뀌었는지, 왜 바뀌었고 무엇이 근거인지, 사람이 직접 봐야 할 것이 무엇인지를 한 곳에서 보게 한다. ha done이 완료 기록을 남긴 뒤 그 완료 기록 기준으로 쓴다. 목표를 다시 열어 완료를 다시 기록하면 새 완료 기록 기준으로 다시 쓴다. 완료 기록 전과 멈춤(needs_user, blocked, budget_exhausted) 때는 쓰지 않는다. 그 전에는 제목 아래에 그렇다는 한 줄만 두고, 멈춤 때는 지금처럼 ## 현재와 완료 보고(6절)가 상태를 맡는다. ha는 이 절을 읽지 않는다.
완료 기록이 있는 목표를 reopen으로 다시 열면, 다음 완료 기록 전까지 이 절의 이전 내용은 고치지 않는다. 맨 위에 한 줄을 둔다. 그 줄은 이 요약이 어느 완료 기록(seq와 commit) 기준인지, 목표를 다시 열어 그 완료 기록이 지금은 유효하지 않다는 것, 다음 완료 기록 뒤 다시 쓴다는 것을 말한다. 그 사이에 멈춰도(needs_user, blocked, budget_exhausted) 이전 내용과 그 줄은 그대로다. 다음 완료 기록 뒤에는 그 기록 기준으로 이 절을 다시 쓰고 그 줄은 남지 않는다. 다시 연 목표에는 완료 기록 전에 두는 한 줄 대신 이 규칙을 따른다.
절의 구성은 아래 항목이 전부이며 이 순서다. 해당하는 것이 없는 항목에는 없음을 쓴다.
- 제목 없는 첫 줄들: 완료 기록의 seq와 commit, 보증 등급, 필수 조건 충족 수, 독립 검토 gate의 결과. 이 변경이 하는 일 한 줄. 먼저 볼 항목.
### 바뀐 동작과 파일: 열이바뀐 동작 | 조건 | 파일인 표. 목표의 base부터 완료 commit까지 바뀐 파일은 목표 문서를 빼고 모두 어느 행엔가 나온다. 이 목표의 검사 파일도 행으로 둔다.### 범위 밖이나 기존 것을 바꾼 곳: SPEC 범위 밖의 파일 변경, 기존 시험의 변경, 이전 목표가 남긴 검사의 변경을 하나씩 적고, 각각에 그 변경을 허락한 사용자의 말이 있는 곳이나 이유를 함께 쓴다.### 근거: 조건마다 그 조건을 충족한 검사가 무엇을 확인했는지와 어느 commit에서 통과했는지. seq만으로 가리키지 않는다. 그리고 독립 검토 라운드마다 한 행인라운드 | 지적 | 끝표. 지적이 없는 라운드도 행을 둔다. 라운드의 지적은 하나도 빠짐없이 끝 하나로 분류된다:고침,반박,중복,사용자의 답,이슈로 보류,자동 보류,처리 없음.### 누가 정했나: 결정을 세 가지로 나눈다. 사용자가 정한 것(사용자의 말이 있는 곳), 에이전트가 제안하고 사용자가 받아들인 것, 묻지 않고 정한 실행자 가정. SPEC 문장을 해석한 가정에는 그렇다는 표시를 붙인다.### 직접 볼 것: 위험이 큰 순서로, 항목마다 한두 줄로 적는다.ha report의직접 볼 것줄이 보이는 항목 전부와, 그 줄이 무엇을 보이든 다음이 모두 들어간다: 보류한 지적 전부와 그 이슈, 처리 없이 남은 지적 전부, SPEC 문장을 해석해서 정한 실행자 가정, 고정 문구만 확인하는 검사로 충족한 조건(문서의 실제 내용은 사람이 읽어야 한다),manual조건,### 범위 밖이나 기존 것을 바꾼 곳의 변경.### 보지 않은 것: 관측하지 않은 범위와 대체 환경, 보증 수준local, 검사를 실행자가 썼다는 사실, 배포·설치·실제 모델 실행의 증거가 아니라는 사실.### 자세히: 세부 기록이 있는 문서와 절.
완료 보고(6절)의 2에 있던 판단 항목은 다음 자리에 둔다. 바뀐 파일과 각 파일이 기여한 조건은 ### 바뀐 동작과 파일, 가정한 미결정은 ### 누가 정했나, manual 조건은 ### 직접 볼 것, 기대 결과의 근거·실제 관측 경계·시험 방법과 실제로 받은 검토 단계(생략했으면 그 이유, SPEC 등급과 프로젝트 지침이 달랐으면 각각이 요구한 검토와 따른 쪽)는 ### 근거, 미관측 범위와 대체 환경은 ### 보지 않은 것, 독립 검토 결과의 위치는 ### 자세히에 쓴다. 보내거나 병합하려는 head가 완료 기록의 commit인지와, 다르면 그 차이를 완료가 덮지 않는다는 사실(그 head에서 ha status가 같은 완료 기록을 계속 보이면 덮는다)은 첫 줄들에 쓴다.
이 구성에서 ### 근거의 두 부분과 첫 줄들의 항목은 최소 목록이다. 판단 항목 대응 문단이 정한 항목은 그 목록과 함께 그 자리에 들어간다.
완료 보고 2에서 옮긴 판단 항목도 완료 보고 2의 한정을 지킨다. 실행자의 설명은 주장으로 표시한다. 기록으로 확인한 사실과 실행자의 해석을 나눈다. 조건·검사·환경이 계획과 달라졌으면 근거의 버전과 그 근거가 덮는 범위를 밝힌다.
읽기 규칙: 사용자의 언어로 쓴다. 기록은 무엇인지를 먼저 쓰고 seq는 보조로만 붙인다. 항목마다 짧게 쓴다. 검증 출력과 지적 원문을 옮겨 적지 않는다. 지적은 ID, 한 줄 요약, 끝만 적는다. 지적 원문은 검토 기록에 둔다. 완료 때 실행자의 판단 문장은 이 절에만 있고, 완료 보고는 이 절을 가리킨다(6절).
다음 안내는 사용자가 PR을 요청했을 때만 적용한다. 이 PR 설명 안내는 ## 검수 요약이 있는 목표에만 적용한다. PR을 만들거나 고치거나 올리거나 리뷰에 답할 권한을 더하지 않는다.
완료한 목표의 PR 설명을 쓰거나 고칠 때 그 목표의 ## 검수 요약에서 만든다. 완료 기록의 commit, 바뀐 동작과 파일, 근거 요약을 넣는다. ### 직접 볼 것의 모든 항목을 넣고, 보류한 지적과 그 이슈 및 처리 없는 지적도 포함한다. ### 보지 않은 것을 넣는다. 프로젝트 지침이 PR 설명에 요구하는 항목도 넣는다. 보류한 지적의 목록과 검사 경계가 그 예다. ### 직접 볼 것 항목을 빼거나 해결된 것처럼 바꿔 쓰지 않는다.
PR을 읽는 사람이 열 수 없으므로, Git이 추적하지 않는 목표 문서, 실행 묶음, 검토 기록의 경로와 링크는 넣지 않는다. 사용자 대화의 원문은 넣지 않는다. 대신 내용을 짧게 적거나 로컬 기록에 있다고 적는다.
6. 완료 보고
ha done이 완료 기록을 남겼을 때, 또는 더 진행할 수 없어 멈출 때(needs_user, blocked, budget_exhausted) 쓴다.
seal 0.1.20 이상으로 시작한 목표의 완료 보고는 다음 두 부분이다.
- 그때의
ha report <goal>출력. 사용자의 언어가 한국어면--lang ko, 그 밖이면--lang en으로 실행하고 그대로 붙인다. 다섯 줄 요약,## 현재도장, 조건별 근거, 완료 범위(완료 기록의 seq와 commit, HEAD를 덮는지), 미충족 조건의 원문 위치가 들어 있고 검증 출력 원문은 없다.ha status·ha done출력 원문은 붙이지 않는다. - 그 아래에 실행자의 판단 문장만 더한다: 바뀐 파일과 각 파일이 기여한 조건(주장), 가정한 미결정과
manual조건, 기대 결과의 근거·실제 관측 경계·시험 방법과 대체 환경·미관측 범위, 보증 등급과 실제로 받은 검토 단계 또는 생략한 이유, 독립 검토 결과의 위치, SPEC 등급과 프로젝트 지침이 달랐으면 각각이 요구한 검토와 따른 쪽, 보내거나 병합하려는 head가 완료 기록의 commit인지와 다르면 그 차이를 완료가 덮지 않는다는 사실(그 head에서ha status가 같은 완료 기록을 계속 보이면 덮는다), 보증 수준local과 검사 작성자가 실행자라는 사실, 보고가 배포·설치·실제 모델 실행의 증거가 아니라는 사실, 완료가 아니면 이어 가는 방법.
seal 0.1.24 이상으로 시작한 목표에서 완료 기록 뒤의 완료 보고는 1의 출력과 ## 검수 요약을 가리키는 한 줄이다. 2의 판단 문장은 ## 검수 요약에만 쓴다(5.4절). 멈출 때는 위 두 부분 그대로다.
seal 0.1.20 전의 Seal로 시작한 목표는 시작할 때의 보고 형식을 유지하며, 순서는 다음과 같다.
- 완료면
ha done의 출력, 멈출 때는ha status --format md의 출력. 그대로 붙이고 고쳐 쓰지 않는다. 이 출력에는 결과, 이유, digest, 기록 seq만 있고 검증 출력 원문은 없다. - 완료 범위(Seal 0.1.15 이상으로 시작한 목표): 완료 기록의 seq와 commit, 보내거나 병합하려는 head가 그 commit과 같은지, 다르면 그 차이는 완료가 덮지 않는다는 사실. 다만 그 head에서
ha status가 같은 완료 기록을 계속 보이면 완료가 덮는다. 그 전 Seal로 시작한 목표는 시작할 때의 보고 형식을 유지한다. - 조건별 근거: 조건, 결과, 기록 seq. 상태 출력에 있으면 생략한다.
- 바뀐 파일과 각 파일이 기여한 조건. 에이전트의 설명이며 주장으로 표시한다.
- 남은 한계: 가정한 미결정,
manual조건, 보증 수준(local), 검사 작성자가 실행자라는 사실 - 새 보고 형식에서는 검토의 기대 근거·예정 경계·방법을 실제 수행·결과·근거·미관측과 연결한다. 확인한 것·확인하지 못한 것·위험한 경계를 조건 또는 공유 그룹으로 제시한다. 계획과 달라진 검사·환경·버전, 근거의 유효 범위도 밝힌다. 보고는 배포·설치·실제 모델 실행의 증거를 대신하지 않는다.
- 이어 가는 방법: 완료가 아니면 무엇이 남았고 어떤 조건에서 다시 시작하는가
완료 기록 뒤 사용자가 원격 리뷰나 PR 지적의 반영을 요청하면 그것이 재작업 요청이다. 그 요청을 인용해 reopen을 기록하고, 고친 뒤 독립 검토가 필요한 목표는 누적 라운드를 한 번 받고, 최종 head에서 낡은 필수 검사를 다시 기록하며, 보내거나 병합하기 전에 ha done으로 완료를 다시 기록한다. 다시 기록할 검사는 Core의 신선도가 정한다(run-record.md §3).
검증 출력 원문은 실행 묶음 어디에도 붙이지 않는다. 실행 묶음은 커밋되며 사용자가 다른 사람과 공유할 수 있다. 실패 원인을 설명해야 하면 요약하고, 원문은 ha log <goal> <seq>로 로컬에서 보게 한다.
7. 예시 (작은 목표, task를 PLAN에 합친 경우)
아래는 /1·/2의 일반 러너 명령 예시다. 새 /3 change에는 이 pytest 종료 코드만으로 충분하지 않다. 결과 계약의 실제 참조 연동처럼 선언·생산자를 연결한다. 기존 검사 전체를 보존하는 maintain에는 일반 러너를 계속 사용할 수 있다.
# PLAN — empty-input
## 조건표
| ID | 종류 | 검증 명령 | 검사 경로 | Task |
| --- | --- | --- | --- | --- |
| AC-1 | change | `python -m pytest tests/test_empty.py -q` | tests/test_empty.py | T001 |
| AC-2 | maintain | `python -m pytest -q` | — | T001 |
## 범위
- 바꿀 수 있는 경로: `src/textstats/**`, `tests/test_empty.py` (SPEC: Proposed Behavior)
- 테스트 경로: (기본값)
- 유지할 동작: 비어 있지 않은 파일의 출력 형식 (SPEC: Non-goals)
## Task
| ID | 목표 | 근거 | 제안 | 선행 | 필수 | 문서 |
| --- | --- | --- | --- | --- | --- | --- |
| T001 | 빈 입력에서 0 0 0을 출력한다 | AC-1, AC-2 | — | — | 예 | — |
## 예산
- 검증 실행: 20
- 경과 시간: 2시간
- 비용: 미관측
8. ha lint 오류 코드
ha lint는 오류마다 코드, 파일과 줄, 설명을 한 줄로 출력한다. 오류가 없으면 ok: no lint problems 한 줄을 출력하고, 목표 문서에 올바른 Assurance: 줄(goal-docs.md §2.5)이 있으면 그 다음 줄에 assurance tier: <등급>을 더한다. 오류가 하나라도 있으면 ha start와 ha check를 거절하고, ha status는 lint_error를 낸다.
목표 문서(goal-docs.md)
| 코드 | 뜻 |
|---|---|
spec_missing |
goal 디렉토리에 SPEC.md가 없다 |
criteria_missing |
## Acceptance Criteria 절이 없거나 조건이 없다 |
criterion_without_id |
AC-n ID가 없는 조건 |
criterion_duplicate_id |
같은 AC-n이 두 번 나온다 |
criteria_format |
목표 문서의 목록 형식 값이나 선택 표시 위치가 올바르지 않다 |
criteria_format_duplicate |
목표 문서에 목록 형식 선택 표시가 두 번 이상 나온다 |
assurance_format |
Assurance: 줄의 값이 light, standard, strict가 아니거나, 들여썼거나, 첫 2단계 절 뒤에 있다 |
assurance_format_duplicate |
Assurance: 줄이 두 번 이상 나온다 |
criterion_indentation |
새 목록 형식의 들여쓰기가 애매하거나 지원되지 않는다 |
goal_doc_link_missing |
SPEC.md나 보조 문서가 링크한 goal 디렉토리 안 문서가 없다 |
proposal_invalid_id |
작업 분해 제안의 ID가 W1 형식이 아니다 |
proposal_duplicate_id |
같은 W ID가 두 번 나온다 |
proposal_unknown_criterion |
제안이 없는 AC-n을 가리킨다 |
proposal_unknown_dependency |
제안이 없는 W에 의존한다 |
proposal_cycle |
제안의 의존에 순환이 있다 |
table_columns |
계약 표의 열 이름이 다르다(목표 문서와 실행 묶음 공통) |
실행 묶음
| 코드 | 뜻 |
|---|---|
plan_missing |
PLAN.md가 없다 |
bundle_file_missing |
REVIEW.md나 PROGRESS.md가 없다 |
plan_section_missing |
## 조건표, ## 범위, ## Task, ## 예산 중 빠진 절이나 표가 있다 |
criterion_invalid_id |
조건표의 ID가 AC-n·EX-n 형식이 아니다 |
criterion_duplicate_row |
같은 조건이 조건표에 두 번 나온다 |
criterion_unknown |
조건표의 AC-n이 목표 문서에 없다 |
criterion_not_in_plan |
목표 문서의 AC-n이 조건표에 없다 |
invalid_kind |
종류가 change, maintain, manual이 아니다 |
command_missing |
change·maintain 조건에 검증 명령이 없다 |
command_multiple |
한 칸에 검증 명령이 둘 이상이다 |
shell_syntax |
검증 명령에 셸 문법이 있다 |
command_parse |
검증 명령을 낱말로 나눌 수 없다(닫히지 않은 따옴표 등) |
check_paths_missing |
change 조건에 검사 경로가 없다 |
baseline_marker |
baseline 칸이 요구·—·빈 칸 밖의 값이거나, change가 아닌 행에 요구가 있다 |
check_path_glob |
검사 경로가 glob이다 |
manual_reason_missing |
manual 조건에 사유가 없다 |
criterion_without_task |
task가 없는 조건 |
scope_missing |
바꿀 수 있는 경로가 없다 |
task_invalid_id |
task ID가 T001 형식이 아니다 |
task_duplicate_id |
같은 task ID가 두 번 나온다 |
task_required_invalid |
필수가 예·아니오가 아니다 |
task_unknown |
조건표가 없는 task를 가리킨다 |
task_unknown_criterion |
task가 조건표에 없는 조건을 근거로 든다 |
task_unknown_dependency |
task가 없는 task에 의존한다 |
task_orphan |
조건에 근거하지 않고 다른 task의 선행도 아닌 task |
task_cycle |
task 의존에 순환이 있다 |
task_doc_missing |
문서 열이 가리키는 task 문서가 없다 |
proposal_unknown |
task의 제안이 목표 문서에 없는 W다 |
budget_missing |
검증 실행이나 경과 시간이 없거나 읽을 수 없다 |
time_limit_invalid |
run-rules/4·run-rules/5·run-rules/6·run-rules/7 목표의 ## 시간 제한 항목이 형식에 맞지 않거나, 7200초를 넘거나, 대상이 없거나, 같은 대상을 두 번 선언한다 |
evidence_invalid |
결과 계약 표의 조건·선언·생산자 입력이 유효하지 않다 |
evidence_overlay_missing |
선언 또는 생산자 입력이 해당 조건의 검사 경로에 빠져 있다 |
other_bundles_invalid |
## 범위의 다른 목표 실행 묶음 항목이 정확한 키 다른 목표 실행 묶음:으로 시작하지 않거나 값이 code span 검사 입력 하나가 아니다 |
progress_state_invalid |
PROGRESS.md의 task 상태가 허용된 값이 아니다 |
contracts/bundle.md만든 커밋 bcaddb7603e8