Files
FESADev/docs/mitc4-shell-feast-eigen/implementation-recovery.md
T

400 lines
26 KiB
Markdown

# 차단된 prep의 보존과 조건부 재개 계획
- Feature ID: `mitc4-shell-feast-eigen`
- Owner: `implementation-planning-agent`
- Input contract revision: `r2`
- 기본 보고서: [implementation-plan](implementation-plan.md)
- 범위: 문서와 정적 검토만 완료한다. 아래 Git mutation/status edit/재실행은 아직 실행하지 않는다.
## R1. 실제 상태와 변경 없는 경계
필수 입력은 Feature 폴더와 [FEATURED_AGENTS](FEATURED_AGENTS.md), [PRD](PRD.md),
[ADR](ADR.md), [현재 Coordinator 감사](coordination.md#execution-prep-attempt-1-실제-결과),
기존 [환경](implementation-environment.md), [interfaces](implementation-interfaces.md),
[verification](implementation-verification.md) 및 그 upstream r2 links다.
[AGENTS](../../AGENTS.md), [agent 계약](../SOLVER_AGENT_DESIGN.md),
[문서 관리](../FEATURE_DOCUMENTATION.md), [harness](../../.agents/skills/harness/SKILL.md),
[fem-implementation-tdd](../../.codex/skills/fem-implementation-tdd/SKILL.md)를 적용한다.
Prep attempt1은 종료되었고 Step0/top은 blocked, history1이다.
[원 보고서](implementation-prep-evidence.md)의 미검증 test 수정/실패 횟수 서술은 후속
Implementation owner가 실제 raw 순서에 맞춰 갱신한다. Planning은 본문을 수정하지 않는다.
[보존된 raw](../../.harness/build/mitc4-eigen-evidence/prep/attempt1/step0-output.json)와
[observation](../../.harness/build/mitc4-eigen-evidence/prep/attempt1/observation.json)을 사용한다.
Raw SHA-256은 `0d5c0fe0aeba5604c5289764e7aad1834902548ca02158f8feac03484b195941`이다.
마지막 focused run은2pass/2fail, 이후 test-only 수정은 미실행이다. Registered CTest의
362pass 기록은 manual full VERIFY/별도 process exit를 대신하지 않는다.
[현재 Executor](../../scripts/execute.py)의 constructor는 경로/schema를 읽고 field를 설정한다.
`_stop_step`은 blocked/history/top을 저장한 뒤 종료하며 커밋하지 않는다.
`_commit_paths`는 자체 `_assert_step_scope`, trusted path 검증, exact staged 경로 검사와
commit 직전 재검사를 수행한다. 내부 index reset은 검사된 dirty 경로의 staging만 정리하며
worktree bytes는 보존한다. 아래 명령은 이 method를 변경 없이 호출한다.
`run/_commit_step/_finalize/_stop_step`, status reset, Hook writes 또는 guard overrides는 없다.
일반 실행용 clean preflight는 dirty WIP 보존 전에 성립하지 않으므로 이 전용 checkpoint는
constructor/identity/scope/commit 경로를 사용하고 마지막 clean 상태에서 정상 preflight를 확인한다.
이는 새로운 recovery CLI가 아니다.
## R2. Root checkpoint 이후의 정확한 WIP 보존 명령
1. 모든 실행이 종료된 상태에서 Coordinator가 이 계획을 감사한다. Root는 management4문서와
이 변경3문서, classifier delta를 반영한 prep step0.md의 정확한8경로만 먼저 checkpoint한다.
Partial runtime/tests/report와 phase index/top의
controls는 stage하거나 커밋하지 않는다. Root checkpoint 후 staging은 비어 있어야 한다.
2. Branch `feat-mitc4-shell-feast-eigen-execution-prep`, linked root, origin
`d533b615410751fe023dc73ac2be994f05d37d30`의 descendant, origin 이후 commit path가
해당8계획/관리 파일 이내임을 아래 명령이 검증한다. 현재 partial implementation8경로와 control2경로가
정확히 남아야 한다. `.codex/hooks.json`은 이 WIP commit의 변경 대상이 아니다.
3. Coordinator가 실행을 할당하면 **실제 Executor method**가 두 개의 local commit을 만든다.
Root/Coordinator는 실행 동안 추가 편집·커밋을 멈춘다. 성공 명칭이나 completed를 쓰지 않는다.
첫 commit 후 두 번째가 실패할 수 있으며 두 commit은 하나의 transaction이 아니다.
실패 시 현재 HEAD/index/worktree/log를 그대로 감사하고 자동 재시도나 rollback을 하지 않는다.
Workspace root의 별도 managed PowerShell process에서 아래 전체 block을 실행하도록 계획한다.
Python native exit를 즉시 저장하여 동일 shell exit로 전파한다. CommandNotFound는 terminating
error이며 나중 명령의 exit0으로 덮이지 않는다. 이 block은 **현재 planning turn에서 미실행**이다.
```powershell
$ErrorActionPreference = 'Stop'
Get-Command python -ErrorAction Stop | Out-Null
@'
import ast, hashlib, json, os
from pathlib import Path
from scripts import execute
phase = "mitc4-shell-feast-eigen-execution-prep"
origin = "d533b615410751fe023dc73ac2be994f05d37d30"
ex = execute.StepExecutor(phase)
root = Path(ex._root)
assert Path.cwd().resolve() == root
assert Path(ex._run_git_checked("rev-parse", "--show-toplevel").stdout.strip()).resolve() == root
assert ex._is_isolated_worktree()
assert ex._codex_sandbox_mode() == "workspace-write"
assert ex._implementation_agent_settings() == ("gpt-5.6-terra", "xhigh")
branch, before_head = ex._git_execution_identity()
assert branch == "refs/heads/feat-" + phase
ex._run_git_checked("merge-base", "--is-ancestor", origin, "HEAD")
doc_names = ("FEATURED_AGENTS.md", "PRD.md", "ADR.md", "coordination.md",
"implementation-plan.md", "implementation-environment.md", "implementation-recovery.md")
doc_paths = {"docs/mitc4-shell-feast-eigen/" + n for n in doc_names}
doc_paths.add("phases/" + phase + "/step0.md")
committed = ex._run_git_checked("diff", "--name-only", "--no-renames", origin, "HEAD").stdout.splitlines()
assert set(committed) <= doc_paths
assert not ex._run_git_checked("diff", "--cached", "--name-only").stdout.strip()
current_source = (root / "scripts/execute.py").read_text(encoding="utf-8")
original_source = ex._run_git_checked("show", origin + ":scripts/execute.py").stdout
assert ast.dump(ast.parse(current_source.replace("CODEX_TIMEOUT_SECONDS = 14400",
"CODEX_TIMEOUT_SECONDS = 1800"))) == ast.dump(ast.parse(original_source))
idx = ex._read_phase_index()
top = ex._read_top_index()
assert len(idx["steps"]) == 1 and idx["steps"][0]["status"] == "blocked"
assert len(idx["steps"][0]["attempt_history"]) == 1
assert next(p for p in top["phases"] if p["dir"] == phase)["status"] == "blocked"
owned = ex._step_owned_paths(idx["steps"][0])
expected_owned = ("scripts/execute.py", ".codex/hooks.json",
"scripts/hooks/stop_validation.py", "scripts/msvc_harness/models.py",
"scripts/msvc_harness/process.py", "tests/test_execute.py",
"tests/test_harness_timeouts.py", "docs/HARNESS_WORKFLOW.md",
"docs/mitc4-shell-feast-eigen/implementation-prep-evidence.md")
assert owned == expected_owned
control = ["phases/index.json", "phases/" + phase + "/index.json"]
code = [p for p in owned if p != ".codex/hooks.json"]
assert set(ex._assert_step_scope(owned)) == set(code + control)
raw_path = "phases/" + phase + "/step0-output.json"
raw = (root / raw_path).read_bytes()
assert hashlib.sha256(raw).hexdigest() == "0d5c0fe0aeba5604c5289764e7aad1834902548ca02158f8feac03484b195941"
frozen_paths = list(owned) + control + ["phases/" + phase + "/step0.md", raw_path]
frozen = {p: (root / p).read_bytes() for p in frozen_paths}
def verify_frozen():
assert all((root / p).read_bytes() == data for p, data in frozen.items())
assert ex._read_phase_index() == idx and ex._read_top_index() == top
assert ex._git_execution_identity()[0] == branch
verify_frozen()
previous = before_head
for paths, message in (
(code, "chore(mitc4-shell-feast-eigen-execution-prep): WIP blocked partial deadline preparation"),
(control, "chore(mitc4-shell-feast-eigen-execution-prep): preserve blocked attempt 1 metadata"),
):
verify_frozen()
assert ex._commit_paths(paths, message, owned_paths=owned)
current = ex._git_execution_identity()[1]
assert current != previous
actual = ex._run_git_checked("diff-tree", "--no-commit-id", "--name-only",
"--no-renames", "-r", current).stdout.splitlines()
assert set(actual) == set(paths), (current, actual)
verify_frozen()
print(json.dumps({"commit": current, "paths": sorted(actual), "status": "blocked"}))
previous = current
assert not ex._worktree_paths()
ex._preflight_repository()
verify_frozen()
print(json.dumps({"clean": True, "branch": branch, "head": previous,
"raw_sha256": hashlib.sha256(raw).hexdigest(),
"phase_status": "blocked", "history_count": 1}))
'@ | python -B -
$mfeCheckpointExit = $LASTEXITCODE
if ($mfeCheckpointExit -ne 0) { exit $mfeCheckpointExit }
exit $mfeCheckpointExit
```
상태/history/timestamps/다른 step/top/step markdown/raw/owned file bytes는 전후 동일해야 한다.
출력 commit SHA와 actual path set, clean/branch/root 및 실제 process exit를 Coordinator가
관리문서에 감사한다. 이 두 commit은 blocked WIP 보존이며 구현/검증 통과가 아니다.
Raw archive는 ignored 상태로 유지하고 Git에 추가하지 않는다.
## R3. 승인 후에만 가능한 status-only checkpoint
현재 exact DFA run의 명시적 사용자 승인은 없다. WIP checkpoint에는 별도 사용자 질문이
필요하지 않지만 DFA는 [harness elevated rule](../../.agents/skills/harness/SKILL.md#elevated-and-remote-execution)에 따라
동일 native 명령 실패 evidence, clean linked worktree, **해당 실행 직전 명시적 사용자 승인**,
approval flag가 모두 필요하다. 과거 일반 구현 승인이나 이 문서 작성은 그 승인이 아니다.
그 승인이 실제로 도착한 경우에만 다음 순서를 같은 bounded 복구 준비로 진행한다.
1. Coordinator가 승인된 exact command와 recovery dispatch를 management에 기록하고 Root가
그 문서만 checkpoint하여 clean을 유지한다. 원시 attempt1 archive는 그대로 보존한다.
2. Coordinator의 별도 명시 할당을 받은 Planning만
`phases/mitc4-shell-feast-eigen-execution-prep/index.json`의 **현재 Step0 status 한 값**
`blocked -> pending`을 바꾼다. `blocked_reason/blocked_at/started_at/created_at/
attempt_history`, owned paths, 다른 Step/top은 그대로 둔다. 현재 dispatch는 이 편집을 허용하지 않는다.
3. Coordinator가 할당한 실제 Executor method는 아래 control-only checkpoint를 수행한다.
Staged HEAD의 blocked JSON과 working pending JSON의 차이가 status 한 값뿐인지 검증한다.
Top은 계속 blocked다. 기존 `_check_blockers`는 phase의 첫 미완료 Step을 판별하므로
pending을 실행할 수 있으며 top을 미리 성공/초기화할 필요가 없다.
4. Clean checkpoint 확인 뒤 별도 변경 없이 R4의 승인된 invocation을 시작한다.
필요한 준비 사이에 실행 범위나 환경이 달라지면 재개하지 않고 Coordinator에 반환한다.
```powershell
$ErrorActionPreference = 'Stop'
Get-Command python -ErrorAction Stop | Out-Null
@'
import json
from pathlib import Path
from scripts import execute
phase = "mitc4-shell-feast-eigen-execution-prep"
ex = execute.StepExecutor(phase)
root = Path(ex._root)
assert Path.cwd().resolve() == root
assert Path(ex._run_git_checked("rev-parse", "--show-toplevel").stdout.strip()).resolve() == root
assert ex._is_isolated_worktree() and ex._codex_sandbox_mode() == "workspace-write"
branch, before_head = ex._git_execution_identity()
assert branch == "refs/heads/feat-" + phase
path = "phases/" + phase + "/index.json"
before = json.loads(ex._run_git_checked("show", "HEAD:" + path).stdout)
after = ex._read_phase_index()
expected = json.loads(json.dumps(before))
assert len(expected["steps"]) == 1 and expected["steps"][0]["status"] == "blocked"
expected["steps"][0]["status"] = "pending"
assert after == expected
assert set(ex._assert_step_scope(())) == {path}
assert not ex._run_git_checked("diff", "--cached", "--name-only").stdout.strip()
top_before = ex._read_control_bytes(ex._top_index_file)
raw_path = root / "phases" / phase / "step0-output.json"
raw_before = raw_path.read_bytes()
phase_before = ex._read_control_bytes(ex._index_file)
assert ex._commit_paths([path],
"chore(mitc4-shell-feast-eigen-execution-prep): queue approved recovery preserving attempt history")
current = ex._git_execution_identity()
assert current[0] == branch and current[1] != before_head
assert ex._run_git_checked("diff-tree", "--no-commit-id", "--name-only", "-r",
current[1]).stdout.splitlines() == [path]
assert ex._read_control_bytes(ex._index_file) == phase_before
assert ex._read_control_bytes(ex._top_index_file) == top_before
assert raw_path.read_bytes() == raw_before
assert ex._read_phase_index() == after and not ex._worktree_paths()
ex._preflight_repository()
print(json.dumps({"commit": current[1], "clean": True,
"step_status": "pending", "history_preserved": True}))
'@ | python -B -
$mfeStatusExit = $LASTEXITCODE
if ($mfeStatusExit -ne 0) { exit $mfeStatusExit }
exit $mfeStatusExit
```
이 단계도 `_commit_step`이나 완료 처리를 부르지 않는다. 이후 실행에서 추가 attempt 기록과
terminal outcome/timestamp 정리는 Executor 소유다. Planning/Root가 과거 failure를 지우지 않는다.
## R4. 조건부 exact DFA invocation과 후속 검증
Prep에 실제 classifier 결함의 TDD delta가 추가되었다. 상세 RED/GREEN/신규 test3개 및 전체
VERIFY는 [prep Step0](../../phases/mitc4-shell-feast-eigen-execution-prep/step0.md)에 있다.
[순수함수 재현](../../.harness/build/mitc4-eigen-evidence/prep/attempt1/classifier-observation.json)은
성공한 source read stdout의 marker7회가 오판 원인이었음을 보여 준다. 실제 protected Hook
쓰기 거부/명시 blocked는 별개의 실제 failure로 보존한다. Root/Coordinator가 확정한 순서는
이번 계획 종료 → 정확 문서 checkpoint → R2의 unchanged Executor WIP 두 commit → 별도
Correction Agent dispatch다. Correction 소유는 scripts/execute.py, tests/test_execute.py와
`docs/mitc4-shell-feast-eigen/corrections.md`이며 Hook/index/status/Git은 변경하지 않는다.
Correction은 Step0에 정의한 최소 RED/GREEN·focused/full acceptance를 수행한다.
Checkpoint/recovery bootstrap이 classifier를 monkeypatch하거나 진단을 지우지 않는다.
이미 시작된 Executor는 source 수정 뒤에도 예전 classifier를 유지하므로 Correction은 다음
실제 prep invocation보다 먼저 완료되어야 한다. 실제 Correction 결과가 반환된 뒤 Coordinator는
Planning을 별도 재개하여 source/report의 정확 checkpoint 계획을 감사한다. 현재 문서는 미래
Correction 성공/hash/commit이나 그 checkpoint를 미리 승인하지 않는다. 해당 검증·checkpoint와
새 process가 수정 classifier를 읽는 activation 확인이 끝나기 전 R3/R4 재개를 실행하지 않는다.
현재 timeout-only AST guard는 최초 WIP 보존에 그대로 유지한다. 수정된 classifier를 현재
Executor에 reload/override하거나 old classifier의 terminal을 성공으로 바꾸지 않는다.
R3과 사용자 승인까지 실제 완료된 경우에만, workspace root의 새 managed PowerShell
process에서 아래 실행을 허용한다. E3의 실제 `main()`과 단일 유한14400 timeout assignment를
유지하며 flag와 process-local sandbox 값만 승인 범위에 맞춘다. 이전 환경 값은 `finally`에서
복원하고 native exit를 즉시 저장한다. transport/ownership/Hook/verification guard는 변경하지 않는다.
```powershell
$ErrorActionPreference = 'Stop'
Get-Command python -ErrorAction Stop | Out-Null
$mfePriorSandbox = [Environment]::GetEnvironmentVariable('FEM_HARNESS_CODEX_SANDBOX', 'Process')
if ($null -ne $mfePriorSandbox -and $mfePriorSandbox -ne 'workspace-write') {
throw 'Unexpected pre-existing sandbox environment'
}
$mfeNativeExit = $null
try {
$env:FEM_HARNESS_CODEX_SANDBOX = 'danger-full-access'
python -B -c "from scripts import execute; execute.StepExecutor.CODEX_TIMEOUT_SECONDS = 14400; execute.main()" mitc4-shell-feast-eigen-execution-prep --approve-danger-full-access
$mfeNativeExit = $LASTEXITCODE
if ($null -eq $mfeNativeExit) { throw 'Native Executor exit was not captured' }
}
finally {
[Environment]::SetEnvironmentVariable('FEM_HARNESS_CODEX_SANDBOX', $mfePriorSandbox, 'Process')
}
exit $mfeNativeExit
```
Implementation은 선행 Correction의 실제 RED/GREEN evidence를 읽고 같은 classifier regression,
남은 Hook 변경, 미검증 test 수정의 focused 재검증, 전체 pytest와
MSVC/x64/Debug CMake/CTest, actual registered Stop을 모두 수행한다. 기존 보고서의 실제
2개 실패와 미검증 수정도 owner가 바로잡는다. 실패 이력을 새 RED 성공이나 correction으로
바꾸지 않는다. Native Exit/Stop 사후 감사까지 prep gate가 완료되기 전 main activation은 금지다.
Push/tag/publish/release 또는 다른 sandbox/guard 변경 권한은 없다.
## R5. 계획 정적 검증
Command AST/PowerShell syntax와 현 상태의 read-only 검사를 수행했다. Python `ast.parse`로
WIP/status checkpoint code2개를 검증했고 PowerShell `Parser::ParseInput`으로 실행 block3개의
syntax errors0을 확인했다(각 exit0). 현재 execute.py는 origin 대비 timeout 상수 외 AST가 같아
checkpoint에 사용되는 guard가 변경되지 않았음을 확인했다. Phase/top/raw는 보존 archive와
동일하며 상태 blocked/history1이다. 문서 EOF/trailing whitespace·local links와
`git diff --check`도 확인했다. Commit/status edit/DFA/CMake/CTest/pytest는 미실행이다.
최종 scope/link count·hash는 handoff에 기록한다.
## R6. 실제 Correction source2의 보존과 남은 실행 조건
R2는 실제 WIP commit `6e00dba1`과 blocked metadata commit
`5dfbea7e543b64fdefcea292de43237adb790a72`을 만든 **과거 명령**이다.
이후 classifier가 바뀌었으므로 그 timeout-only AST guard를 다시 쓰거나 완화하지 않는다.
[Correction 보고서](corrections.md)와 [검증 summary](../../.harness/build/mitc4-eigen-evidence/prep/classifier-correction/20260906025404Z-continuation3-verification-summary.json)는
실제 RED21fail/16pass 뒤 GREEN37pass, 전체 pytest152pass/1fail을 기록한다.
Manual configure0/build1의 FileTracker TEMP 접근 거부 뒤 manual CTest는 미실행이다.
[실제 native 결과](../../.harness/build/mitc4-eigen-evidence/prep/classifier-correction/native-continuation-3-result.json)는
native/wrapper0,1914.797초이며, [등록 process exits](../../.harness/build/mitc4-eigen-evidence/prep/classifier-correction/native-continuation-3-registered-exits.json)의
Stop2개/CTest exit0 및362pass는 별도 자동 검증이다. 이를 manual full 성공으로 합치지 않는다.
Classifier key의 Correction1회는 사용됐고 추가 source correction은 허용하지 않는다.
재개 Implementation은 확보된 RED/GREEN을 읽고 현재 source의 focused/full을 재검증한다.
GREEN source를 다시 망가뜨려 RED를 만들지 않는다. 과거 timeout RED와 마지막 enum fix의
당시 미검증 기록은 보존하며, enum fix가 이번 focused/full에서 통과했다는 새 evidence를 구분한다.
Protected Hook1800!=7500과 manual build 환경 문제는 아직 해소되지 않았다.
Root는 frozen management `FEATURED_AGENTS.md/ADR.md/coordination.md`, Planning의
`implementation-plan.md/implementation-environment.md/implementation-recovery.md`,
독립 Correction의 `corrections.md` **정확7문서만** 먼저 checkpoint한다.
Correction 보고서는 prep owned_paths 밖이므로 이 선행 문서 commit으로 clean하게 만든다.
Root ack 뒤에만 Coordinator가 아래 실제 unchanged Executor method 호출을 할당한다.
Dirty 경로는 source2만 허용하며 phase/top/raw/Hook/status/history와 report는 불변이다.
아래 AST normalization은 검사에만 사용하고 실행 module/method를 교체하지 않는다.
```powershell
$ErrorActionPreference = 'Stop'
$mfeCheckpointPython = Join-Path (Get-Location).Path '.harness/build/mitc4-eigen-evidence/prep/classifier-correction/pytest-venv/Scripts/python.exe'
if (-not (Test-Path -LiteralPath $mfeCheckpointPython -PathType Leaf)) { throw 'Named Python missing' }
@'
import ast, hashlib, json
from pathlib import Path
from scripts import execute
phase = "mitc4-shell-feast-eigen-execution-prep"
origin = "5dfbea7e543b64fdefcea292de43237adb790a72"
ex = execute.StepExecutor(phase)
root = Path(ex._root)
assert Path.cwd().resolve() == root
assert Path(ex._run_git_checked("rev-parse", "--show-toplevel").stdout.strip()).resolve() == root
assert ex._is_isolated_worktree() and ex._codex_sandbox_mode() == "workspace-write"
assert ex._implementation_agent_settings() == ("gpt-5.6-terra", "xhigh")
branch, before_head = ex._git_execution_identity()
assert branch == "refs/heads/feat-" + phase
ex._run_git_checked("merge-base", "--is-ancestor", origin, "HEAD")
docs = {"docs/mitc4-shell-feast-eigen/" + p for p in (
"FEATURED_AGENTS.md", "ADR.md", "coordination.md", "implementation-plan.md",
"implementation-environment.md", "implementation-recovery.md", "corrections.md")}
assert set(ex._run_git_checked("diff", "--name-only", "--no-renames",
origin, "HEAD").stdout.splitlines()) <= docs
assert not ex._run_git_checked("diff", "--cached", "--name-only").stdout.strip()
sources = {"scripts/execute.py": "64f5165fc544b3b17904c633ef3b222de79b52a0960e254c5b5c4eb99e79c2d0",
"tests/test_execute.py": "0eb0c1ca0f25199e00686b7e3ab57672b1390437d09da218a929added0346dd6"}
fixed = {".codex/hooks.json": "0ab23dad4643f45238f4a60402083e32d8801f5c41fd6ba12b68ef6a9fc5fc28",
"phases/index.json": "2e4dfef44cd76b7ae447d0e2186a8a949ec29627df9c573646162b92348f1edb",
"phases/" + phase + "/index.json": "e23269a5518a8dbffbbf2e4706431d7f8af67e43706dcc9086aa6c8991d24262",
"phases/" + phase + "/step0-output.json": "0d5c0fe0aeba5604c5289764e7aad1834902548ca02158f8feac03484b195941",
"docs/mitc4-shell-feast-eigen/corrections.md": "d4ea3fb18accc2b2316eb439f56f5106d8ae6640fe79452cef6cb341b1933ee4"}
def check_hashes():
for path, expected in {**sources, **fixed}.items():
assert hashlib.sha256((root / path).read_bytes()).hexdigest() == expected, path
check_hashes()
old_tree = ast.parse(ex._run_git_checked("show", origin + ":scripts/execute.py").stdout)
new_tree = ast.parse((root / "scripts/execute.py").read_text(encoding="utf-8"))
old_cls = next(n for n in old_tree.body if isinstance(n, ast.ClassDef) and n.name == "StepExecutor")
new_cls = next(n for n in new_tree.body if isinstance(n, ast.ClassDef) and n.name == "StepExecutor")
old_methods = {n.name: n for n in old_cls.body if isinstance(n, ast.FunctionDef)}
new_methods = {n.name: n for n in new_cls.body if isinstance(n, ast.FunctionDef)}
assert set(new_methods) - set(old_methods) == {"_stdout_has_helper_failure"}
assert not set(old_methods) - set(new_methods)
assert {n for n in old_methods if ast.dump(old_methods[n]) != ast.dump(new_methods[n])} == {"_codex_environment_failure"}
new_cls.body = [old_methods["_codex_environment_failure"] if isinstance(n, ast.FunctionDef)
and n.name == "_codex_environment_failure" else n for n in new_cls.body
if not (isinstance(n, ast.FunctionDef) and n.name == "_stdout_has_helper_failure")]
assert ast.dump(new_tree) == ast.dump(old_tree)
idx = ex._read_phase_index()
top = ex._read_top_index()
assert len(idx["steps"]) == 1 and idx["steps"][0]["status"] == "blocked"
assert len(idx["steps"][0]["attempt_history"]) == 1
assert next(p for p in top["phases"] if p["dir"] == phase)["status"] == "blocked"
owned = ex._step_owned_paths(idx["steps"][0])
assert set(sources) <= set(owned)
assert set(ex._assert_step_scope(owned)) == set(sources)
snapshot = {p: (root / p).read_bytes() for p in
list(owned) + list(fixed) + ["phases/" + phase + "/step0.md",
"phases/mitc4-shell-feast-eigen/index.json"]}
assert ex._commit_paths(list(sources),
"chore(mitc4-shell-feast-eigen-execution-prep): WIP classifier correction with full verification blocked",
owned_paths=owned)
after_branch, after_head = ex._git_execution_identity()
assert after_branch == branch and after_head != before_head
actual = ex._run_git_checked("diff-tree", "--no-commit-id", "--name-only",
"--no-renames", "-r", after_head).stdout.splitlines()
assert set(actual) == set(sources)
assert all((root / p).read_bytes() == value for p, value in snapshot.items())
check_hashes()
assert ex._read_phase_index() == idx and ex._read_top_index() == top
assert not ex._worktree_paths()
ex._preflight_repository()
print(json.dumps({"commit": after_head, "paths": sorted(actual), "clean": True,
"status": "blocked", "history_count": 1, "branch": branch}))
'@ | & $mfeCheckpointPython -B -X utf8 -
$mfeCorrectionCommitExit = $LASTEXITCODE
if ($null -eq $mfeCorrectionCommitExit) { throw 'Native exit unavailable' }
exit $mfeCorrectionCommitExit
```
이 명령은 아직 미실행이다. Native exit와 commit path/hash/clean 결과를 실제 관찰한 뒤
Coordinator가 감사한다. 실패하면 현재 bytes/index/HEAD를 보존하고 자동 재시도하지 않는다.
새 source commit은 WIP와 전체 검증의 제한을 명시하며 `_commit_step`/completed를 호출하지 않는다.
성공 뒤에도 R3의 별도 status-only 할당과 해당 실행 직전 exact DFA 사용자 승인이 필요하다.
DFA는 아직 승인되지 않았다. 후속 native process에는 [E6의 실제 환경 recipe](implementation-environment.md#e6-correction-후의-pythonpytest와-process-temp)를 적용하고,
그 환경에서 R4와 동일한 phase/finite14400/approval flag를 사용한다. 새 process는 corrected
classifier를 로드한다. Protected Hook 권한과 TEMP/TMP 운영 설정의 근거를 혼동하지 않는다.
Prep full gate·등록 Stop 실제 exit·Coordinator 사후 감사 전 main activation은 금지다.
정적 검증은 command AST/PowerShell syntax, source2/report hash, 변경 method2와 나머지
Executor AST 불변, local links/EOF/whitespace와 blocked archive 동일성을 대상으로 했다.
정확 결과와 갱신3문서 hash는 handoff에 기록한다. Source/tests/Hook/phase/status/Git과
Correction 본문은 이번 Planning 작업에서 수정하지 않았다.