Skip to content

feat(triaging-feedback): 피드백 자동 트리아지 스킬(Plan B) — Codex-SDK 워커·게이트·needs-human 티켓 - #7

Merged
SSFSKIM merged 15 commits into
mainfrom
feat/triaging-feedback-skill
Jul 9, 2026
Merged

feat(triaging-feedback): 피드백 자동 트리아지 스킬(Plan B) — Codex-SDK 워커·게이트·needs-human 티켓#7
SSFSKIM merged 15 commits into
mainfrom
feat/triaging-feedback-skill

Conversation

@SSFSKIM

@SSFSKIM SSFSKIM commented Jul 9, 2026

Copy link
Copy Markdown
Owner

무엇 / 왜

인앱 피드백 자동 트리아지 CI의 Plan B — skills/triaging-feedback/ 스킬입니다. 자체 호스팅 Mac cron이 ida-solution의 Supabase feedback 테이블을 폴링 → 새 행마다 Codex-SDK 스레드 하나로 진단 → 스코프 좁고 안전한 버그는 수정 PR(기존 reviewing-prs --sweep 루프가 리뷰), 그 외(아이디어·질문·진단불가·리스크 표면)는 needs-human 보드 티켓. doperpowers 플러그인의 첫 Node/TypeScript 서브시스템(자체 package.json).

설계 스펙: docs/doperpowers/specs/2026-07-09-feedback-ci-triage-design.md · 구현 계획: docs/doperpowers/plans/2026-07-09-feedback-triage-skill-doperpowers.md

안전 모델 — model-proposes / dispatcher-disposes

Codex 스레드는 일회용 git 워크트리 안의 코드만 읽기/수정한다. 자격증명·gh 토큰은 절대 갖지 않으며, 모든 특권 사이드이펙트(Supabase writeback·gh pr create·board-register.sh)는 디스패처 코드가 실행한다. 픽스 게이트는 모델의 자기보고가 아니라 실제 git diff로 강제한다(리스크 표면·크기·테스트·근본원인 인용).

주요 결정 (스펙 Decision Log)

  • TypeScript 유지(Python 폴백 아님): Task 1 스파이크가 TS SDK엔 per-turn run() sandbox가 없음을 확인했으나, resumeThread(id,{sandboxMode})로 read-only 진단→workspace-write 수정 흐름을 무비용으로 얻음. tsc가 실 @openai/codex-sdk@0.143.0 타입에 통과.
  • 티켓 상태 = needs-human(v8 보드 어휘 확정) · 본문은 --body-file · 모든 gh/보드 호출은 cwd=repoPath로 실행.
  • 사전 adversarial verify 없음 — 여는 PR은 기존 reviewing-prs --sweep가 리뷰(중복 회피).

검증

  • 유닛 46/46 통과, tsc --noEmit clean. 스파이크 + 9개 TDD/글루 태스크, 각 태스크 독립 리뷰 + Opus 전체-브랜치 리뷰.
  • 전체-브랜치 리뷰가 태스크 단위 리뷰가 못 본 통합 버그 2건을 잡아 수정:
    • 게이트 우회(Critical): git diff --numstat가 tracked 수정 파일만 봐서 새로 추가된 파일(새 sql/pNN.sql·app/api/cron/* = 리스크 표면)이 빈 diff로 게이트 통과 → add -A로 커밋될 뻔. git add -A + git diff --cached --numstat로 커밋될 형태 그대로 측정하게 수정.
    • 죽은 리클레임(Important): 원자적 claimpending만 가드해서 findActionable이 회수 대상으로 고른 stale-claimed 행을 영영 재클레임 못 함 → reclaimMs 무력. findActionable과 동일 predicate로 수정.

병합 전 필요 (⚠️ 무단 머지 금지 — 사람 리뷰 후)

  • Task 11(라이브 섀도우 런)은 핸드오프: Plan A의 p86 마이그레이션이 라이브 + Mac에 OPENAI_API_KEY/service-role 키가 있어야 함. 미검증 3개 seam(codexAdapter 2턴 흐름·git.ts 워크트리/빌드·poll.ts end-to-end)을 실인프라로 검증.
  • Plan A(ida PR docs: add AdaL installation instructions obra/superpowers#400) 선행: triage_state/host 컬럼이 존재해야 폴러가 claim/writeback 가능.
  • 하드닝 대기: findExistinggh pr list가 fail-open(에러 시 중복 PR 여지) — 현재는 본문 마커 + 사람 리뷰가 백스톱.

SSFSKIM added 15 commits July 10, 2026 00:11
…웃·게이트/프롬프트 안전

- codexAdapter: process.env 통째 상속 제거, PATH/HOME만 통과하는
  buildCodexOptions 순수함수 + makeCodexRunner 팩토리(F1). 매 턴 fresh
  thread로 전환해 resumeThread/CodexThread 제거(F2). AbortController로
  timeoutMs 실배선(F3, 죽은 설정이던 것을 활성화).
- dispatch: verdict.feedback_id가 요청 행과 다르면 실패 처리(행 id
  참칭/혼동 방어, F2). fix 프롬프트는 검증된 verdict 필드만 전달하고
  row.body는 배제.
- config: TRIAGE_FIX_ENABLED 기본값을 안전한 false로(리터럴 'true'만
  활성, F5), TRIAGE_RECLAIM_MS 기본값을 30분→90분으로(F3).
- git.ts diffStat에 --no-renames 추가 — rename이 게이트 G4의 리스크
  표면 정규식을 우회하던 문제 수정(F6).
- prompt.ts의 모든 replaceAll을 함수 치환으로 전환 — 본문에 $&/$' 등이
  있을 때 프롬프트가 왜곡되던 문제 수정(F7).
- 테스트: codexAdapter 신규 3건, dispatch 1건 추가, config 기대값 갱신.
- SKILL.md/setup.md: "failed는 재시도된다"는 잘못된 문구를 코드 실제
  동작(findActionable/claim이 pending·stale-claimed만 고르고 failed는
  절대 재클레임하지 않음)에 맞게 교정 — 재시도하려면 운영자가
  triage_state를 pending으로 리셋해야 함을 명시(F4).
- setup.md: TRIAGE_RECLAIM_MS 기본값 스니펫을 90분(5400000)으로 갱신하고
  reclaim > 최대 실행시간 조건 + launchd 단일 label 가정을 명문화(F3).
- SKILL.md/setup.md: TRIAGE_FIX_ENABLED 기본값이 false(리터럴 'true'만
  활성)임을 반영(F5).
- 스펙 Decision Log에 write 턴 fresh-thread 전환(F2) 항목 추가 —
  resumeThread 폐기 이유와 "변경파일 ⊆ 인용파일" 검증 v1 보류 사유 기록.
@SSFSKIM

SSFSKIM commented Jul 9, 2026

Copy link
Copy Markdown
Owner Author

프리머지 외부 리뷰(3자, Codex/gpt-5.5 high) + 수정 웨이브 2

머지 전 독립 리뷰를 돌렸고, Critical 2건 포함 7건을 수정했다(82b1b73 코드, 3f468d8 문서). vitest 51/51 · tsc clean 재확인.

# 심각도 발견 수정
F1 Critical new Codex()process.env 전체(서비스롤 키 포함)를 CLI 자식에 상속 → 샌드박스 안 모델이 printenv로 읽어 티켓/PR 본문으로 유출 가능 buildCodexOptions: env 명시(PATH·HOME만) + apiKey 전달 — SDK가 process.env 상속 중단. approvalPolicy:'never'·networkAccessEnabled:false도 고정
F2 Critical 신뢰불가 피드백 원문이 resumeThread를 타고 workspace-write 턴 컨텍스트에 잔존 → 주입 지시가 write 턴에 작용 가능 write 턴 = fresh thread(resumeThread 설계 폐기). 프롬프트엔 검증된 verdict 필드만(원문 배제) + 데이터 경계 문구. verdict.feedback_id !== row.id면 실패 처리
F3 Important timeoutMs 죽은 설정(행업 시 폴러 영구 정지) + reclaim 30분 < 최악 실행시간 턴별 AbortController 배선, reclaim 기본 90분, setup.md에 단일 폴러 가정 명문화
F4 Important 문서가 "failed 재시도" 약속, 코드는 터미널 문서를 코드 실동작에 맞게 정정(수동 pending 리셋 안내)
F5 Important TRIAGE_FIX_ENABLED 기본 ON — 섀도 모드 우선 원칙 위반 기본 false, 리터럴 'true'만 활성
F6 Important(자체 발견) rename 감지로 lib/{a => auth.ts} 결합 경로가 나와 리스크표면 게이트(G4) 우회 diffStat--no-renames
F7 Minor(자체 발견) replaceAll 문자열 치환의 $& 특수 패턴으로 프롬프트 왜곡 함수 replacer로 리터럴 치환 강제

보류(하드닝, Task 11 후보): "변경파일 ⊆ 인용파일" 검증, findExisting gh-list fail-open. 근거: G1–G6 게이트 + 사람 PR 리뷰 백스톱.

@SSFSKIM
SSFSKIM merged commit 81a8c19 into main Jul 9, 2026
@SSFSKIM
SSFSKIM deleted the feat/triaging-feedback-skill branch July 9, 2026 22:30
@SSFSKIM
SSFSKIM restored the feat/triaging-feedback-skill branch July 9, 2026 22:38
@SSFSKIM

SSFSKIM commented Jul 9, 2026

Copy link
Copy Markdown
Owner Author

⏪ 머지 리버트됨 (185ad75)

main에 동시 진행된 워커 거버넌스 변경(예: 79e063a — task reviewer Standards axis)과 이 스킬의 정책 정합(worker agents governance reconcile)을 사람이 확인할 때까지 머지를 리버트했다. 코드 결함으로 인한 리버트가 아니다 — 브랜치 내용·리뷰 결과는 유효.

  • 작업 브랜치는 feat/triaging-feedback-skill(head 3f468d8)로 origin에 복원해 둠.
  • 재랜딩 절차(거버넌스 정합 확인 후): 커밋들이 이미 main 조상이므로 같은 브랜치 재-PR은 빈 diff가 된다. 새 브랜치에서 git revert 185ad75(리버트의 리버트)로 PR을 열거나, 정합 과정에서 스킬이 수정되면 그 수정과 함께 새 브랜치로 PR.

@SSFSKIM

SSFSKIM commented Jul 9, 2026

Copy link
Copy Markdown
Owner Author

후속: 리버트 5분 뒤 main에 Reapply 커밋(aad1bf3, 리버트의 리버트)이 직접 랜딩되어 스킬이 main에 복원됨(+거버넌스 리컨사일 커밋 058a475). 별도 리랜딩 PR은 불필요해져 열지 않음 — diff가 비기 때문. 이 PR의 리뷰 기록(외부 리뷰 F1-F7 수정 포함)이 현재 main 내용의 리뷰 근거다.

@SSFSKIM

SSFSKIM commented Jul 9, 2026

Copy link
Copy Markdown
Owner Author

정정: Reapply(aad1bf3)는 실수로 확인되어 재리버트(d7ceb6a)했고, 리랜딩은 PR #8로 진행한다(내용은 이 PR 리뷰본과 비트 동일, 거버넌스 정합 확인 후 사람 머지). 이 스레드의 후속 추적은 PR #8에서.

SSFSKIM added a commit that referenced this pull request Jul 10, 2026
Two-tier trust (review #1, human design call): developer feedback — the
server-resolved role snapshot in TRIAGE_TRUSTED_ROLES (default admin), or
a stripped .env #TRIAGE_DEV_CODE body prefix — is read as instruction
(R1/R4 waived: dev ideas can be born ready-for-agent, labeled
source:dev-feedback); user feedback keeps the conservative gate, residual
risk explicitly accepted in the Decision Log. The dev code is stripped
before the body reaches the prompt or ticket so it never leaks into a
public issue.

The rest of the review, all fixed:
- #2 R2 requires a REAL file citation (path-shaped after :line strip;
  unknown:12 no longer counts)
- #3 R3 scans risk SYMBOLS (assertStudentAccess, supabaseAdmin, RLS,
  generate-plan layout fns, past_exam_problems, SUPABASE_SERVICE_ROLE_KEY)
  in addition to paths
- #4 claim issues a lease token; writeback is lease-conditional (late
  writeback after reclaim throws instead of clobbering); reclaim window
  validated at config load; second idempotency check right before
  registerTicket
- #5 findExisting fails closed on gh search errors
- #6 ticket body temp files: mkdtemp dir, mode 0600, removed in finally
- #7 TRIAGE_ENABLED checked before config parsing
- #8 spec drift fixed (feedback-dispatch.ts references, two-kill-switches)

p86 DDL note gains triage_lease UUID. New src/trust.ts. 91 tests green,
tsc clean.
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