Skip to content

release: 0.5.11 — 인계 노트가 세 번째 상태 파일이던 것 (STATUS.md → current-task.json handoff) - #13

Merged
bluecheat merged 2 commits into
mainfrom
feature/handoff-in-current-task-json
Sep 11, 2026
Merged

bluecheat merged 2 commits into
mainfrom
feature/handoff-in-current-task-json

Conversation

@bluecheat

Copy link
Copy Markdown
Owner

왜

.ax/docs/STATUS.md(세션 인계 노트)는 어느 사용자 리포에도 커밋된 적 없는 세션 상태인데, .gitignore.template 에는 없고(state.json·current-task.json·MEMORY.md 는 있어요) 커밋되는 .ax/docs/ 트리 한가운데 놓여 있었어요 — git add -A 한 번이면 새는 자리예요. 리포 계약(CLAUDE.md "Skills update .ax/state.json … and .ax/current-task.json … do not invent new state files")을 하네스 자신이 어긴 세 번째 상태 파일이었어요.

실사용에서 발견: commerce 리포 세션에서 Stop 게이트가 "인계 노트를 적어라" 고 해서 status-note.sh 가 STATUS.md 를 만들었는데, 팀은 그 파일을 쓴 적이 없었고 리뷰에서 "이건 왜 만들었어" 로 잡혔어요.

무엇이 바뀌나

  • 저장소만 옮겨요. 인계 노트의 네 절(지금 상태 · 다음 · 열린 질문 · 이번에 바뀐 이름)과 쓰는 길(status-note.sh)은 그대로, 저장 위치가 .ax/current-task.json 의 handoff 객체로 바뀌어요.
    "handoff": { "now": [], "now_at": null, "next": [], "open": [], "renamed": [] }
  • status-note.sh — CLI 표면 동일(--show|--init|--add|--done|--set|--clear <절>, --json, --dry-run, --cap). --show --json 의 sections/counts/over_cap/exists/path 불변, lines → items(네 절 항목 합), now_at 추가. 줄 끝 (YYYY-MM-DDTHH:MMZ) 스탬프가 now_at 필드로 올라와요 — --set now 만 갱신하고 --add now 는 건드리지 않아요 (게이트 침묵 창 불변). current-task.json 이 없으면 변이 모드는 exit 1 로 거절해요 — 최소 파일을 만들면 MANIFEST -> seed 가 영원히 막혀서요. jq 필수(없으면 exit 2).
  • stop/spec-gate.sh — 이미 열어 둔 current-task.json 의 handoff.now 에 spec 이름 + now_at 24시간으로 판정 (파일 read 하나 줄어요). subagent-start/harness-pointer.sh — handoff 에 항목이 있으면 경로만 한 줄. build-memory.sh 포인터도 같은 조건(HAS_JQ 가드 안).
  • tier-from-state.sh --reset — current-task.json 을 쓰는 유일한 다른 스크립트라 같은 락 문자열(goax_normalize_path(…/.ax/current-task.json).lock)을 잡아요. 필드별 null 대입 그대로라 handoff 는 살아남아요 (next·open·renamed 는 task 를 넘어 살아야 해요). jq 가 죽으면 원본을 두고 tmp 만 치우고 error 로 답해요.
  • doctor-scan.sh — 인계 노트 기한(- [ ] YYYY-MM-DD)을 handoff 네 절에서 읽고, 남은 .ax/docs/STATUS.md 를 마이그레이션 잔재(migration.stale_status_md)로 알려요. 자동 import·삭제 없음 — 이 파일은 per-machine 상태고 내용이 설계상 일시적이라(끝난 항목은 지움, now 는 24h 지나면 무효) 손으로 고친 마크다운을 파싱해 신선도까지 판정하는 코드는 새 실패 모드만 들고 와요. 필요한 줄은 status-note.sh --add 로 옮기고 rm.
  • 버전 0.5.11 + changelog/0.5.11.md. 문서(CLAUDE.md · skill-routing · scripts/hooks README · triage/spec-implement/lane/zero/up/onboarding/doctor SKILL.md · templates/zero) 전부 새 저장소 기준.

.ax/MEMORY.md 는 그대로 두는 이유

STATUS.md 의 문제는 "고유 정보가 상태 파일이 아닌 곳에, gitignore 도 없이" 있었던 거예요. MEMORY.md 는 셋 다 해당하지 않아요 — 고유 정보가 없고(build-memory.sh 가 마크다운·상태에서 결정론 재생성), 이미 gitignore 돼 있고, 소비자는 triage §1.0 하나예요. state.json.hud 가 update-state.sh 의 렌더 캐시인 것과 같은 지위예요. state.json 에 접으면 수 KB 마크다운이 HUD JSON 에 들어가 3-way 동기화 규칙에 걸리고, 파일 없이 stdout 을 읽으면 재열람이 안 돼요. 이번 결정에 필요한 변경은 인계 노트 포인터 한 줄뿐이라 그것만 했어요.

왜 current-task.json 이고 state.json 이 아닌가 · 그 비용

  • state.json 은 "사용자가 편집하지 않는 렌더 캐시 SSOT"(docs/state-ownership.md)라 고유 정보를 넣으면 캐시가 아니게 되고, template + statusline.sh + ownership 표 3-way 동기화에 걸리고, writer 트래픽(update-state.sh 매 skill 종료 · tasks-gate 봉인 · 인라인 jq 9곳)이 훨씬 많아요. current-task.json 은 "triage→spec→audit 컨텍스트 인계" 파일이라 세션 간 인계와 같은 축이고, 읽는 훅 4곳이 이미 여는 파일이에요.
  • 정직한 비용 (steelman: .ax/handoff.json 별도 파일이면 셋 다 없지만 "새 상태 파일 금지" 정면 위반이라 기각): (1) 같은 파일 동시 쓰기 노출 — 스크립트 writer 둘은 같은 락으로 직렬화되지만 SKILL.md 인라인 jq 5곳은 무락이에요 (두 세션이 같은 리포를 동시에 쓸 때만, 인라인 jq 끼리는 오늘도 같은 노출 — 후속: update-task.sh 로 흡수). (2) writer 가 객체를 통째로 재조립하면 handoff 가 조용히 사라져요 — smoke 에 "current-task.json 으로 곧장 리다이렉트 금지(in-place jq 만)" 구조 가드를 계약으로 넣었어요. (3) current-task.json 이 task 를 넘어 사는 하위 객체를 하나 갖게 돼요 — reset-task.sh 가 handoff 를 남기는 걸 문서와 smoke 로 고정했어요.

행동 변화 (업그레이드하는 쪽)

  • status-note.sh 변이 모드는 current-task.json 없으면 exit 1 (/up 먼저). jq 없으면 exit 2 — zero-ablation.sh --on 의 기한 체크박스 기록(|| true)도 조용히 같이 건너뛰어요 (예전 텍스트 모드는 awk 라 jq 없이도 됐어요).
  • 상한 40 은 "항목 40개" (헤더·빈 줄이 빠져 실효 예산이 ~31 → 40).
  • 기존 STATUS.md 는 자동으로 옮기지 않아요. doctor 가 잔재로 알려요.

검증

  • bash tests/smoke.sh — 571 통과 / 0 실패 / exit 0 (main 기준선 559, +12). 재작성: §34 status-note 픽스처, §35 stop 게이트·doctor-scan·zero-ablation·SubagentStart, §41 now_at 신선도, §43 락 동시성(--init ×5 · --add ‖ --add ×10 유실 0 · --add ‖ tier-from-state --reset ×5 둘 다 생존 · dry-run 은 락도 handoff 도 안 만듦 · 선점 current-task.json.lock 앞 exit 1 — 7종). 추가: writer in-place 가드, reset 이 handoff 를 안 지움, doctor stale_status_md findings +1, harness-pointer 경로만·600자 미만.
  • 수동 픽스처: --set now 직후 spec-gate 통과(출력 없음) → now_at 을 2020 으로 바꾸면 decision:block → --set now "" 뒤 now==[]·now_at==null. now_at 이 깨진 값 7종·now 가 문자열·handoff 부재 → 전부 block 으로 fall through(크래시 없음). 깨진 JSON 에서 --reset → exit 1, 원본·락 그대로.
  • 계약 점검: MANIFEST·docs/state-ownership.md 변경 없음, 락 문자열 두 스크립트 바이트 동일, [a-z] 범위 0, 버전 마커 0, 남은 STATUS.md 참조는 doctor 잔재 통지(doctor-scan.sh · doctor/SKILL.md · scripts README 행 · smoke 픽스처)만.
  • 계획·리뷰: Planner → Architect → Critic 합의(2회차) 뒤 구현, 구현 뒤 architect(AC1–AC10 실행) · code-reviewer · security-reviewer 셋 APPROVE. 리뷰에서 나온 것 반영: writer 가드 정규식 강화(산문 오탐 제거, <<EOF·"$ROOT/…" 리다이렉트 포착), --reset jq 실패 처리, 선점 락 7종.

후속 (이 PR 밖)

  • SKILL.md 의 current-task.json 인라인 jq 5곳(triage·spec·spec-validate·spec-tasks·spec-implement)을 락 있는 update-task.sh --phase <p> [--set k=v] 로 흡수 — 결정론 경계 룰과 위 비용 (1) 을 같이 닫아요.
  • tier-from-state.sh 의 .ax/current-task.json.template 복사 fallback 정리 (설치본엔 그 파일이 없어요).

🤖 Generated with Claude Code

https://claude.ai/code/session_01XgYfK9moXVF9YCRPvfg8tH

bluecheat and others added 2 commits September 11, 2026 22:58
`.ax/docs/STATUS.md` 는 어느 리포에도 커밋된 적 없는 세션 상태인데 `.gitignore.template` 에
없었고, 커밋되는 `.ax/docs/` 트리 한가운데 있었어요. 리포 계약(CLAUDE.md)은 "상태 파일은
state.json · current-task.json 둘, 새로 만들지 않아요" 인데 STATUS.md 가 그걸 어겼어요.

- 인계 노트를 `.ax/current-task.json` 의 `handoff` 객체로 옮겨요 — now · now_at · next · open · renamed.
  writer 는 그대로 `status-note.sh` 하나 (CLI 불변, `--show --json` 의 sections/counts/over_cap 불변,
  `lines` → `items`, `now_at` 추가). 줄 끝 `(YYYY-MM-DDTHH:MMZ)` 스탬프는 `now_at` 필드로 올라와요.
- Stop 게이트(`spec-gate.sh`)는 이미 열어 둔 current-task.json 의 `handoff.now` + `now_at` 으로 24시간을 봐요.
  `harness-pointer.sh` 는 handoff 에 항목이 있으면 경로만 한 줄, `build-memory.sh` 포인터도 같은 조건.
- `tier-from-state.sh --reset` 이 `current-task.json.lock` 을 잡아요 — 같은 파일을 쓰는 두 스크립트가
  같은 락 문자열을 갖게. reset 은 `handoff` 를 지우지 않아요 (next·open·renamed 는 task 를 넘어 살아요).
  jq 가 죽으면 원본을 두고 tmp 만 치우고 error 로 답해요.
- doctor 가 남은 `.ax/docs/STATUS.md` 를 마이그레이션 잔재(`stale_status_md`)로 알려요 — 자동 삭제·import 없음.
- `.ax/MEMORY.md` 는 그대로 — 고유 정보가 없는 재생성 캐시고 이미 gitignore 돼 있어요. 포인터 한 줄만 바뀌어요.
- smoke: §34·§35·§41·§43 을 JSON 저장소 기준으로 재작성 + writer in-place 가드 · reset 보존 · 선점 락 7종.
  571 통과 / 0 실패 (기준선 559).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XgYfK9moXVF9YCRPvfg8tH
- changelog/0.5.11.md: "A 의 정직한 비용" 의 "A" 는 플래닝 세션의 옵션 라벨이라 독자에게 정의가 없었어요 —
  "current-task.json 에 두는 것의 정직한 비용" 으로.
- tests/smoke.sh: current-task.json writer in-place 가드가 skills/ 만 훑었어요 — agents/ ·
  templates/default/.ax/scripts/bash/ 까지. 후속 update-task.sh 같은 writer 스크립트가 자동으로 계약 아래 들어와요.
- tier-from-state.sh --help: 헤더 주석이 27행까지인데 2,23p 로 잘라 Output 4줄이 안 나왔어요 (기존 결함).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LDjdeZ7Tjc5fhXGDpopXC6
@bluecheat
bluecheat force-pushed the feature/handoff-in-current-task-json branch from 272de55 to 3d33e4a Compare September 11, 2026 13:58
@bluecheat
bluecheat merged commit 5b1691d into main Sep 11, 2026
2 checks passed
@bluecheat
bluecheat deleted the feature/handoff-in-current-task-json branch September 11, 2026 13:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant