docs: plan persistent workspace build environment
This commit is contained in:
@@ -733,3 +733,197 @@ Result payload는 manual 결과와 아직 미관찰인 Stop을 구분하며 Coor
|
||||
검토한다. Active Executor 동안 Root/Coordinator는 non-owned edits/commits를 멈춘다.
|
||||
Main은 prep 전체 gate 뒤 별도 workspace-write invocation만 허용하며 E9의 병렬도1을
|
||||
같이 사용한다. 새로운 동일 실패는 원시 evidence와 기존 retry key로 반환한다.
|
||||
|
||||
## E10. 부모 환경과 독립적인 workspace user preset
|
||||
|
||||
[Root Stop 실패](../../.harness/build/mitc4-eigen-evidence/prep/attempt4/root-stop-after-decision-docs/observation.json)는
|
||||
parent env4 미설정과 public preset의 cache4 빈 값 overwrite/configure1을 보존한다.
|
||||
현재 실패 cache hash는 `125a4dbd163c5a0a6d94bd03d3186790c41e6a0d8e0ed7b9c72f18fdf619d66e`다.
|
||||
이는 MFE-OQ-004 승인 답변이 아니다. Canonical Hook·재신뢰는 계속 미승인이고 새 native/
|
||||
status reset도 미할당이다. 아래는 별도 Root 실행을 위한 문서 계획이며 현재 setup은 미실행이다.
|
||||
|
||||
[Toolchain](../../scripts/msvc_harness/toolchain.py)은 executable 경로만 찾으며
|
||||
[Stop](../../scripts/hooks/stop_validation.py)은 parent env를 복사한다. 따라서 root
|
||||
`CMakeUserPresets.json`의 `mfe-workspace-msvc-ninja-debug`가 public preset을 상속하고
|
||||
dependency4 literal cache와 최소 MSVC INCLUDE/LIB/tool PATH를 제공하도록 한다.
|
||||
Installed CMake4.4 `Help/manual/cmake-presets.7.rst`의 user/common 자동 include,
|
||||
`$penv{PATH}`, build/test `inheritConfigureEnvironment`를 사용한다. Public preset,
|
||||
Harness API/config schema와 source/test/Hook은 바꾸지 않는다.
|
||||
|
||||
Build/test는 configure 환경을 상속한다. 같은 Ninja binaryDir·MSVC Hostx64/x64·Debug,
|
||||
실제 Debug archive 경로와 직렬 병렬도1을 유지한다. Root의 정상 DevShell에서 INCLUDE/LIB,
|
||||
cl/rc/mt/Ninja directory만 capture하고 전체 env·비밀값은 preset에 저장하지 않는다.
|
||||
Parent process는 finally에서 복원한다. 이후 arbitrary Root process에도 CMake child가
|
||||
자체 preset 환경을 적용하므로 parent env4/DevShell 지속성을 전제로 삼지 않는다.
|
||||
|
||||
Preset TEMP/TMP는 setup에서 만든 새80자 이하 ignored 디렉터리를 **설정 수명 동안**
|
||||
사용한다. CMake child에서는 이 값이 E7/E9의 매회 parent TEMP를 대체한다. 기존 model/test의
|
||||
고유 child directory 생성은 유지하고 동시 build/test가 없는지 Root가 setup 전에 실제 확인한다.
|
||||
Python/pytest는 기존 per-invocation 새 짧은 TEMP와 basetemp를 유지한다. 기존 디렉터리/
|
||||
evidence 삭제, 권한·실행 정책 변경이나 Hook 우회는 없다.
|
||||
|
||||
### E10.1. Root의 exact setup과 configure-only 확인
|
||||
|
||||
순서는 Planning3 동결 → Root docs checkpoint → 아래 setup → 실제 observation/최소 문서
|
||||
갱신과 Root exact commit이다. 현재 UserPresets는 미존재·미ignore다. Root가 별도 소유하는
|
||||
tracked 변경은 [.gitignore](../../.gitignore)의 `/CMakeUserPresets.json` 한 줄뿐이다.
|
||||
그 줄을 Root가 검토·commit하며 public preset과 Implementation owned9/phase 범위는 유지한다.
|
||||
UserPresets/local config/TEMP/backup/Ninja configure output은 ignored로 둔다.
|
||||
|
||||
```powershell
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$mfeRoot=(Get-Location).Path
|
||||
$mfePython=Join-Path $mfeRoot '.harness/build/mitc4-eigen-evidence/prep/classifier-correction/pytest-venv/Scripts/python.exe'
|
||||
$mfeCmake=(Get-Command cmake.exe -ErrorAction Stop).Source
|
||||
$mfePreset='mfe-workspace-msvc-ninja-debug'
|
||||
$mfeGitRoot=git rev-parse --show-toplevel
|
||||
if ($LASTEXITCODE -ne 0 -or [IO.Path]::GetFullPath($mfeGitRoot) -ne [IO.Path]::GetFullPath($mfeRoot)) { throw 'Repository mismatch' }
|
||||
$mfeDirty=git status --porcelain
|
||||
if ($LASTEXITCODE -ne 0 -or $mfeDirty) { throw 'Root docs checkpoint and clean required' }
|
||||
if (Test-Path -LiteralPath 'CMakeUserPresets.json') { throw 'Preserve existing UserPresets' }
|
||||
$mfeInputs=@{
|
||||
'.gitignore'='b81d422ee0185f16714e3218369689b808701e5e398a6f687a22784da2290842'
|
||||
'.harness/config.json'='3ebdfa80124f1eb96909b2738d6f2a96fecd55cce61150a9cd7ef27d7c5fd892'
|
||||
'.harness/build-ninja-msvc-debug/CMakeCache.txt'='125a4dbd163c5a0a6d94bd03d3186790c41e6a0d8e0ed7b9c72f18fdf619d66e'
|
||||
}
|
||||
foreach ($mfePath in $mfeInputs.Keys) {
|
||||
if ((Get-FileHash -LiteralPath $mfePath).Hash.ToLower() -ne $mfeInputs[$mfePath]) { throw "Changed input: $mfePath" }
|
||||
}
|
||||
$mfeBackup=Join-Path $mfeRoot ('.harness/build/mfe-preset-'+[guid]::NewGuid().ToString('N').Substring(0,8))
|
||||
$mfeTemp=Join-Path $mfeRoot ('.harness/build/t-'+[guid]::NewGuid().ToString('N').Substring(0,8))
|
||||
if ($mfeTemp.Length -gt 80 -or (Test-Path -LiteralPath $mfeTemp) -or (Test-Path -LiteralPath $mfeBackup)) { throw 'Fresh short paths required' }
|
||||
$null=New-Item -ItemType Directory -Path $mfeBackup
|
||||
$null=New-Item -ItemType Directory -Path $mfeTemp
|
||||
Copy-Item -LiteralPath '.gitignore' -Destination (Join-Path $mfeBackup 'gitignore.before')
|
||||
Copy-Item -LiteralPath '.harness/config.json' -Destination (Join-Path $mfeBackup 'config.before.json')
|
||||
Copy-Item -LiteralPath '.harness/build-ninja-msvc-debug/CMakeCache.txt' -Destination (Join-Path $mfeBackup 'CMakeCache.before.txt')
|
||||
$mfeUtf8=[Text.UTF8Encoding]::new($false)
|
||||
[IO.File]::WriteAllText((Join-Path $mfeBackup 'before.json'),(@{hashes=$mfeInputs; userPresetsExisted=$false; temp=$mfeTemp}|ConvertTo-Json -Depth 6),$mfeUtf8)
|
||||
$mfeProtected=@('CMakePresets.json','.codex/hooks.json','scripts/execute.py','tests/test_execute.py','phases/index.json','phases/mitc4-shell-feast-eigen-execution-prep/index.json','phases/mitc4-shell-feast-eigen-execution-prep/step0-output.json','.harness/build/CMakeCache.txt')
|
||||
$mfeHashes=@{}
|
||||
foreach ($mfePath in $mfeProtected) { $mfeHashes[$mfePath]=(Get-FileHash -LiteralPath $mfePath).Hash }
|
||||
$mfeBeforeEnv=[Environment]::GetEnvironmentVariables('Process')
|
||||
try {
|
||||
$mfeVs='C:/Program Files/Microsoft Visual Studio/18/Community'
|
||||
& (Join-Path $mfeVs 'Common7/Tools/Launch-VsDevShell.ps1') -VsInstallationPath $mfeVs -Arch amd64 -HostArch amd64 -SkipAutomaticLocation -NoLogo
|
||||
$mfeCl=(Get-Command cl.exe -ErrorAction Stop).Source
|
||||
$mfeRc=(Get-Command rc.exe -ErrorAction Stop).Source
|
||||
$mfeMt=(Get-Command mt.exe -ErrorAction Stop).Source
|
||||
$mfeNinja=Join-Path $mfeVs 'Common7/IDE/CommonExtensions/Microsoft/CMake/Ninja/ninja.exe'
|
||||
if ($env:VSCMD_ARG_TGT_ARCH -notin @('x64','amd64') -or $mfeCl -notmatch '[\\/]Hostx64[\\/]x64[\\/]cl\.exe$') { throw 'MSVC x64 required' }
|
||||
if (-not(Test-Path -LiteralPath $mfeNinja) -or [string]::IsNullOrWhiteSpace($env:INCLUDE) -or [string]::IsNullOrWhiteSpace($env:LIB)) { throw 'Toolchain incomplete' }
|
||||
$mfeDirs=@((Split-Path $mfeCl),(Split-Path $mfeNinja),(Split-Path $mfeRc),(Split-Path $mfeMt))|Select-Object -Unique
|
||||
$mfeEnv=@{INCLUDE=$env:INCLUDE; LIB=$env:LIB; PATH=($mfeDirs -join ';')+';$penv{PATH}'; TEMP=$mfeTemp.Replace('\','/'); TMP=$mfeTemp.Replace('\','/'); CMAKE_BUILD_PARALLEL_LEVEL='1'}
|
||||
$mfeCache=@{
|
||||
FESA_GTEST_SOURCE_DIR='C:/git/googletest'
|
||||
MKL_DIR='C:/Program Files (x86)/Intel/oneAPI/mkl/2026.1/lib/cmake/mkl'
|
||||
TBB_DIR='C:/Program Files (x86)/Intel/oneAPI/tbb/2023.1/lib/cmake/tbb'
|
||||
HDF5_DIR='C:/Program Files/HDF_Group/HDF5/2.1.1/cmake'
|
||||
CMAKE_CXX_COMPILER=$mfeCl.Replace('\','/')
|
||||
CMAKE_MAKE_PROGRAM=$mfeNinja.Replace('\','/')
|
||||
CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG=('$'+'{sourceDir}/.harness/build-ninja-msvc-debug/src/fesa/Debug')
|
||||
}
|
||||
$mfeUser=@{
|
||||
version=3
|
||||
configurePresets=@(@{name=$mfePreset; inherits='windows-msvc-ninja-debug'; cacheVariables=$mfeCache; environment=$mfeEnv})
|
||||
buildPresets=@(@{name=$mfePreset; inherits='windows-msvc-ninja-debug'; configurePreset=$mfePreset; inheritConfigureEnvironment=$true})
|
||||
testPresets=@(@{name=$mfePreset; inherits='windows-msvc-ninja-debug'; configurePreset=$mfePreset; inheritConfigureEnvironment=$true})
|
||||
}
|
||||
}
|
||||
finally {
|
||||
foreach ($mfeName in @([Environment]::GetEnvironmentVariables('Process').Keys)) {
|
||||
if (-not $mfeBeforeEnv.Contains($mfeName)) { [Environment]::SetEnvironmentVariable($mfeName,$null,'Process') }
|
||||
}
|
||||
foreach ($mfeName in $mfeBeforeEnv.Keys) { [Environment]::SetEnvironmentVariable($mfeName,$mfeBeforeEnv[$mfeName],'Process') }
|
||||
}
|
||||
$mfeOriginalIgnore=[IO.File]::ReadAllBytes((Join-Path $mfeRoot '.gitignore'))
|
||||
if ($mfeOriginalIgnore[-1] -ne 10) { throw 'Unexpected ignore EOF' }
|
||||
$mfeSuffix=$mfeUtf8.GetBytes('/CMakeUserPresets.json'+[Environment]::NewLine)
|
||||
[IO.File]::WriteAllBytes((Join-Path $mfeRoot '.gitignore'),[byte[]]($mfeOriginalIgnore+$mfeSuffix))
|
||||
git check-ignore --quiet CMakeUserPresets.json
|
||||
if ($LASTEXITCODE -ne 0) { throw 'UserPresets must be ignored' }
|
||||
[IO.File]::WriteAllText((Join-Path $mfeRoot 'CMakeUserPresets.json'),($mfeUser|ConvertTo-Json -Depth 10)+[Environment]::NewLine,$mfeUtf8)
|
||||
$mfeConfig=Get-Content -LiteralPath '.harness/config.json' -Raw|ConvertFrom-Json
|
||||
$mfeConfig.cmake.configurePreset=$mfePreset
|
||||
$mfeConfig.cmake.buildPreset=$mfePreset
|
||||
$mfeConfig.cmake.testPreset=$mfePreset
|
||||
[IO.File]::WriteAllText((Join-Path $mfeRoot '.harness/config.json'),($mfeConfig|ConvertTo-Json -Depth 10)+[Environment]::NewLine,$mfeUtf8)
|
||||
foreach ($mfeName in @('FESA_GTEST_SOURCE_DIR','MKL_DIR','TBB_DIR','HDF5_DIR')) {
|
||||
if (-not [string]::IsNullOrEmpty([Environment]::GetEnvironmentVariable($mfeName,'Process'))) { throw 'Separate env4-unset configure verification required' }
|
||||
}
|
||||
$mfeExit=$null
|
||||
try {
|
||||
& $mfeCmake --list-presets=all
|
||||
$mfeExit=$LASTEXITCODE
|
||||
if ($null -eq $mfeExit) { throw 'Preset validation exit unavailable' }
|
||||
if ($mfeExit -ne 0) { exit $mfeExit }
|
||||
& $mfePython -B -X utf8 -c "from pathlib import Path; from scripts.msvc_harness.config import load_config; c=load_config(Path.cwd()); assert c.cmake.configure_preset==c.cmake.build_preset==c.cmake.test_preset=='mfe-workspace-msvc-ninja-debug'; assert c.cmake.binary_dir==Path.cwd()/'.harness/build-ninja-msvc-debug'; print('Local config valid')"
|
||||
$mfeExit=$LASTEXITCODE
|
||||
if ($null -eq $mfeExit) { throw 'Config validation exit unavailable' }
|
||||
if ($mfeExit -ne 0) { exit $mfeExit }
|
||||
& $mfeCmake --preset mfe-workspace-msvc-ninja-debug
|
||||
$mfeExit=$LASTEXITCODE
|
||||
if ($null -eq $mfeExit) { throw 'Configure exit unavailable' }
|
||||
}
|
||||
finally {
|
||||
$mfeAfter=@{}
|
||||
foreach ($mfePath in @('.gitignore','CMakeUserPresets.json','.harness/config.json','.harness/build-ninja-msvc-debug/CMakeCache.txt')) {
|
||||
$mfeAfter[$mfePath]=(Get-FileHash -LiteralPath $mfePath).Hash.ToLower()
|
||||
}
|
||||
[IO.File]::WriteAllText((Join-Path $mfeBackup 'after.json'),(@{hashes=$mfeAfter; lastNativeExit=$mfeExit}|ConvertTo-Json -Depth 6),$mfeUtf8)
|
||||
foreach ($mfePath in $mfeProtected) {
|
||||
if ((Get-FileHash -LiteralPath $mfePath).Hash -ne $mfeHashes[$mfePath]) { throw "Non-owned change: $mfePath" }
|
||||
}
|
||||
}
|
||||
$mfeFinalDirty=git status --porcelain
|
||||
if ($LASTEXITCODE -ne 0 -or @($mfeFinalDirty).Count -ne 1 -or $mfeFinalDirty -ne ' M .gitignore') { throw 'Unexpected tracked changes' }
|
||||
git diff --check -- .gitignore
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Ignore whitespace check failed' }
|
||||
Write-Output ("Setup evidence: {0}; configure exit {1}" -f $mfeBackup,$mfeExit)
|
||||
exit $mfeExit
|
||||
```
|
||||
|
||||
Original3파일 bytes/hash와 UserPresets 부재를 mutation 전에 backup하고, 실제 CMake
|
||||
`--list-presets=all` schema/inheritance 해석 및 `load_config` 뒤 **env4 unset 상태의
|
||||
configure만** 수행한다. Root는 after cache의 dependency4, Ninja/Debug, compiler 경로·
|
||||
pointer size8, archive 경로와 새 user/config/cache hash를 기록한다. Actual adapter plan의
|
||||
configure/build/discovery/test 네 명령도 같은 local preset으로 대조한다.
|
||||
Library/build/CTest 성공은 configure evidence가 아니다. HEAD/phase history4/source/
|
||||
reference/old VS cache 불변, tracked diff가 ignore1줄뿐인지 감사한 뒤 Root가 exact commit한다.
|
||||
자동 Root outer Stop이 발생하면 실제 결과를 따로 관찰하며 manual Hook으로 대체하지 않는다.
|
||||
|
||||
### E10.2. 기존 명령의 명시 대체와 수명
|
||||
|
||||
Setup 성공을 별도 감사한 뒤 E8/E9 및 모든 prep/main 명령의 preset 인수를 아래로 대체한다.
|
||||
Configure의 archive는 user cache가 고정하므로 예전 추가 `-D`가 필요 없다.
|
||||
|
||||
| 목적 | 정확한 새 명령 |
|
||||
| --- | --- |
|
||||
| Configure | `cmake --preset mfe-workspace-msvc-ninja-debug` |
|
||||
| E9 최초 실제 직렬 재검증 build | `cmake --build --preset mfe-workspace-msvc-ninja-debug --clean-first --verbose` |
|
||||
| 일반 full/registered build | `cmake --build --preset mfe-workspace-msvc-ninja-debug` |
|
||||
| Main focused target build | `cmake --build --preset mfe-workspace-msvc-ninja-debug --target fesa_tests` |
|
||||
| Discovery | `ctest --preset mfe-workspace-msvc-ninja-debug --show-only=json-v1` |
|
||||
| Full CTest | `ctest --preset mfe-workspace-msvc-ninja-debug --output-on-failure` |
|
||||
|
||||
Focused CTest는 원 Step의 `-R` 문자열을 그대로 유지하고 preset 인수만 위 이름으로 바꾼다.
|
||||
E9 세 discovery의 실제 실행/등록 identity·새 binary hash/mtime·fresh manual solve 및
|
||||
registered same-binary full 구분, 전체 Python/CTest, 수치/reference 계약은 유지한다.
|
||||
CMake 검증에 한해 E8/E9의 외부 shell DevShell 재호출·cl/Ninja 사전 검색 조건을 user preset과
|
||||
actual compiler/cache evidence로 대체한다. Python/UV recipe와 finite14400/7500/7200
|
||||
계약, workspace-write 및 모든 Hook/retry/ownership guard는 그대로다.
|
||||
실제 canonical outer1800·재신뢰 문제는 이 local setup으로 해결됐다고 주장하지 않는다.
|
||||
|
||||
[Preset contract test](../../tests/test_harness_preset_contract.py)는 tracked public preset/
|
||||
config.example과 tmp_path에 복사한 example을 검사하며 실제 local config/UserPresets를
|
||||
읽지 않는다. Public/example 불변과 기존 ignore 항목 보존 시 이 선택과 모순되지 않는다.
|
||||
테스트 소스/대상/assertions는 수정하지 않았고 이 Planning에서 테스트를 실행하지 않았다.
|
||||
|
||||
Rollback은 active 실행이 없고 after hash와 현재 파일이 동일한 경우에 Root가 수행한다.
|
||||
`.gitignore`와 local config는 backup bytes로 복원하고, 원래 없었던 정확한
|
||||
`CMakeUserPresets.json`만 `Remove-Item -LiteralPath`로 비재귀 제거한다.
|
||||
필요 시 `CMakeCache.before.txt`를 원래 exact cache 경로에 복사하되 **기존 실패 cache
|
||||
복원**임을 기록한다. Generated outputs/TEMP/evidence는 삭제하지 않고 graph 유효성이나
|
||||
검증 성공을 주장하지 않는다. 이미 ignore1줄을 commit했다면 Root의 exact inverse commit을
|
||||
사용하고 history reset은 하지 않는다. 타 owner 변경이 있으면 덮어쓰지 않고 반환한다.
|
||||
설정은 해당 workspace에 유지하며 feature 종료·설치 경로 변경 때 Root가 수명을 검토한다.
|
||||
|
||||
Reference in New Issue
Block a user