init: company-haness 설계
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
"""Phase 0 headless probe — 실제 claude -p 로 stage 를 헤드리스 실행할 수 있는지, process 를
|
||||
넘겨도 원장+artifact 만으로 재개되는지 검증한다. slash 직접 실행이 안 되면 adapter prompt 로 전환.
|
||||
|
||||
실제 실행은 CLI 의 `probe --execute` 가 담당(예산·claude CLI 필요). 여기 함수는 순수 로직."""
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
CLAUDE_CMD = os.environ.get("ORGOS_BENCH_CLAUDE", "claude")
|
||||
|
||||
|
||||
def build_stage_invocation(command_name, command_body, brief_path):
|
||||
"""stage(command)를 headless 로 실행할 사양을 만든다. command_body 가 순수 slash 지시(첫 줄이
|
||||
`# /<name>`)면 direct-slash 로 `/<name>` 프롬프트를, 아니면 command 본문을 펼친 adapter 프롬프트를 쓴다."""
|
||||
first = (command_body.strip().splitlines() or [""])[0].strip()
|
||||
if first.startswith(f"# /{command_name}") or first == f"/{command_name}":
|
||||
mode = "direct-slash"
|
||||
prompt = f"/{command_name}\nbrief: {brief_path}"
|
||||
else:
|
||||
mode = "adapter"
|
||||
prompt = (f"다음 커맨드 절차를 이 brief 로 수행하라.\nbrief: {brief_path}\n\n"
|
||||
f"--- command: {command_name} ---\n{command_body}")
|
||||
argv = [CLAUDE_CMD, "-p", prompt, "--dangerously-skip-permissions"]
|
||||
return {"mode": mode, "prompt": prompt, "argv": argv}
|
||||
|
||||
|
||||
def resume_ok(ledger_before, ledger_after):
|
||||
"""새 process 가 원장만으로 재개 가능한가 — stage 원장이 전진하고 accepted artifact 가 생겼는가."""
|
||||
before = set((ledger_before or {}).get("stages", []))
|
||||
after = set((ledger_after or {}).get("stages", []))
|
||||
return bool(after - before) and bool((ledger_after or {}).get("accepted"))
|
||||
|
||||
|
||||
def run_probe(arm_commit, out_findings_path, execute=False):
|
||||
"""실제 headless probe: worktree(arm_commit) → /ground 1회 headless → 종료 → 새 process 원장 재로드
|
||||
→ resume_ok → PROBE-FINDINGS.md 기록(헤드리스 가능성·adapter 여부·stage별 산출 파일 shape).
|
||||
execute=False 면 미실행(사양만, worktree 도 만들지 않는다) — 무거운 실행은 이 플래그 뒤에 숨긴다.
|
||||
|
||||
실행 절차(execute=True):
|
||||
1. git worktree add → arm 커밋 부스트랩(runner.setup_worktree)
|
||||
2. worktree 에서 runner.run_stage(ground) 로 headless 1회 실행(원장+산출물 기록)
|
||||
3. process 종료(암묵적, exec_fn 이 subprocess 로 격리)
|
||||
4. stage 결과를 원장 anchor 로 재구성(새 process 가 원장만 보고 재개 가능한지 시뮬레이션)
|
||||
5. resume_ok 호출로 전진 검증
|
||||
6. PROBE-FINDINGS.md 에 헤드리스 가능/adapter 여부/stage 산출물 shape 기록
|
||||
"""
|
||||
plan = {"arm-commit": arm_commit, "executed": execute,
|
||||
"worktree": None, "workspace": None, "stage-result": None, "resume-ok": None}
|
||||
if not execute:
|
||||
_write_findings(out_findings_path, plan)
|
||||
return plan
|
||||
|
||||
from . import paths, runner
|
||||
|
||||
rid = paths.run_id(arm_commit)
|
||||
worktree = runner.setup_worktree(rid, "probe", arm_commit, paths.ROOT)
|
||||
workspace = paths.workspace_dir(rid, "probe")
|
||||
os.makedirs(workspace, exist_ok=True)
|
||||
env = runner.evidence_env(os.path.join(workspace, "evidence-pack"))
|
||||
|
||||
def _exec_fn(argv, cwd, exec_env):
|
||||
r = subprocess.run(argv, cwd=cwd, env=exec_env, capture_output=True, text=True)
|
||||
return {"exit-code": r.returncode, "artifacts": [], "transcript": [r.stdout, r.stderr]}
|
||||
|
||||
ledger_before = {"stages": [], "accepted": []}
|
||||
result = runner.run_stage(worktree, workspace, runner.STAGES[0], env, _exec_fn)
|
||||
# process 종료 후 "새 process" 가 보는 원장 상태 — 이 stage 의 반환값만이 그 process 의 유일한
|
||||
# 산출 신호이므로, 성공한 stage 만 원장에 전진 기록된 것으로 재구성한다(원장 재로드 시뮬레이션).
|
||||
advanced = result["exit-code"] == 0
|
||||
ledger_after = {"stages": [result["stage"]] if advanced else [],
|
||||
"accepted": [result["stage"]] if advanced else []}
|
||||
ok = resume_ok(ledger_before, ledger_after)
|
||||
|
||||
plan.update({"worktree": worktree, "workspace": workspace, "stage-result": result, "resume-ok": ok})
|
||||
_write_findings(out_findings_path, plan)
|
||||
return plan
|
||||
|
||||
|
||||
def _write_findings(path, plan):
|
||||
os.makedirs(os.path.dirname(path) or ".", exist_ok=True)
|
||||
lines = ["# PROBE-FINDINGS", "",
|
||||
f"executed: {plan.get('executed')}",
|
||||
f"arm-commit: {plan.get('arm-commit')}",
|
||||
f"resume-ok: {plan.get('resume-ok')}",
|
||||
f"stage-result: {plan.get('stage-result')}"]
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
f.write("\n".join(lines) + "\n")
|
||||
Reference in New Issue
Block a user