diff --git a/.github/workflows/r54-cpu.yml b/.github/workflows/r54-cpu.yml new file mode 100644 index 00000000..1b398c4b --- /dev/null +++ b/.github/workflows/r54-cpu.yml @@ -0,0 +1,50 @@ +name: Bounded R54 hosted CPU diagnosis + +on: + push: + branches: ['perf/grapheme-cpu-hosted-r54', 'perf/grapheme-cpu-hosted-r54-setup2', 'perf/grapheme-cpu-hosted-r54-entry3'] + +permissions: + contents: read + +concurrency: + group: r54-cpu-${{ github.ref }} + cancel-in-progress: false + +jobs: + cpu-boundary: + # Evidence or exporter fixes must not silently create replacement observations. + if: github.event.created == true + runs-on: windows-2025 + timeout-minutes: 30 + env: + PYTHONUTF8: '1' + CARGO_HOME: ${{ github.workspace }}/local/r54-cargo-home + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + persist-credentials: false + - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0 + with: + python-version: '3.12' + - name: Install fixed CPU observer + run: python -m pip install -r benchmarks/requirements.txt + - name: Select fixed compiler + run: rustup default 1.92.0 + - name: Verify build, accounting and publication boundaries + run: python -m unittest experiments.measure.test_r54_contract.CostPlanTests experiments.measure.test_r54_batch experiments.measure.test_r54_hosted experiments.measure.test_r54_cpu_diagnostic experiments.measure.test_r54_cpu_hosted -v + - name: Build audited pair and execute one six-observation diagnosis + id: diagnose + run: python -m experiments.measure.r54_cpu_hosted --out local/r54-cpu-raw + - name: Prepare the synthetic artifact whitelist + if: always() && steps.diagnose.outcome != 'skipped' + run: python -m experiments.measure.r54_publish --experiment cpu-boundary --raw local/r54-cpu-raw --out local/r54-cpu-public + - name: Preserve complete or failed synthetic evidence + if: always() && steps.diagnose.outcome != 'skipped' + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: r54-cpu-${{ github.run_id }}-${{ github.run_attempt }} + retention-days: 30 + if-no-files-found: error + path: local/r54-cpu-public/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 61d22796..b44cd3b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -292,7 +292,7 @@ if(BUILD_TESTING) endif() termforge_add_python_test(core -m unittest experiments.core.test_core experiments.core.test_unicode -v) termforge_add_python_test(recovery -m unittest experiments.core.test_recovery -v) - termforge_add_python_test(measure -m unittest experiments.measure.test_measure experiments.measure.test_r54_contract.CostPlanTests experiments.measure.test_r54_batch experiments.measure.test_r54_hosted experiments.measure.test_r54_cpu_diagnostic -v) + termforge_add_python_test(measure -m unittest experiments.measure.test_measure experiments.measure.test_r54_contract.CostPlanTests experiments.measure.test_r54_batch experiments.measure.test_r54_hosted experiments.measure.test_r54_cpu_diagnostic experiments.measure.test_r54_cpu_hosted -v) termforge_add_python_test(binary_paths -m unittest experiments.test_build_paths -v) termforge_add_python_test(conpty_margin_contract -m unittest experiments.conpty.test_margin_contract -v) termforge_add_python_test(benchmark_tools -m unittest discover -s benchmarks/tests -v) diff --git a/docs/EVIDENCE.md b/docs/EVIDENCE.md index 566598b7..4148376e 100644 --- a/docs/EVIDENCE.md +++ b/docs/EVIDENCE.md @@ -165,5 +165,6 @@ python -m unittest experiments.shell.test_workflow_sessions -v | 固定字素成本的批次协议与执行 | [R54 v1 合同和构建/环境记录](../experiments/measure/R54-COST.md)、[执行器](../experiments/measure/r54_batch.py)、[合成进程回归](../experiments/measure/test_r54_batch.py)、[实际预检及限定验证](../experiments/measure/results/2026-10-27-r54-runner/validation.json) | 固定两个种子、各 112 个位置,字节原样保留、首错停止、完整批次后逐组配对统计。共享工作站十区间活动预检未通过,未启动成本样本;测量相关 26 项测试通过,首次 Linux 候选 CI 的采样依赖导入错误及修正分别留证。5% 是环境诊断护栏,并非产品性能容差;实际批次、扰动归因及用户预算确认由 #54 接续。 | | 首次 hosted 字素成本批次 | [来源、停止位置与归档](../experiments/measure/results/2026-10-27-r54-hosted/README.md)、[机器可读记录](../experiments/measure/results/2026-10-27-r54-hosted/validation.json) | 两份固定构建与4次sanity通过,空闲预检通过;第24位置的未归属CPU活动估计5.410%触发原5%护栏,保留23个有效记录和1个失败记录,第二批未启动。全部24次输出正确,但批次不完整,不生成配对成本摘要;临时VM逐进程归因、完整受控批次和预算仍未完成。 | | CPU计量边界诊断(#54) | [固定六位置及归档](../experiments/measure/results/2026-10-27-r54-cpu-boundary/README.md)、[独立复核](../experiments/measure/results/2026-10-27-r54-cpu-boundary/verify.py) | 同一共享Windows宿主、原已审计构建的六次输出和来源核验通过;分别保留完整子进程、内层区间、runner和全机计数。区间外CPU为0.078125–0.109375s,仍有明显未归属活动,不算空闲成本批次,不反推旧hosted原因或修改原5%护栏。 | +| 新hosted VM的CPU分量(#54) | [预声明](../experiments/measure/R54-CPU-HOSTED.md)、[六位置/来源/完整归档与只读复核](../experiments/measure/results/2026-10-27-r54-cpu-hosted/README.md) | 新构建和六个输出均通过;完整扣除自身/runner后余额仍为3.333%–5.263%,不归因旧事件、不作成本验收。准备失败与未创建作业的入口分别保留,未重跑或补样。 | 目前没有足够证据判断 TermForge 距离 WindTerm 快或慢多少。正式结论必须同时提供负载/配置/环境身份、正确性、完成端点、观测开销、重复样本与限制。未知字段保持未知;历史校准未完成不转成要求用户反复手动运行的前置。执行规则见 [ADR-0002](adr/0002-automation-first-investigation.md),核心选型重审见 [ADR-0003](adr/0003-core-reference-and-reuse.md)。 diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 9f3c415e..fae8b271 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -71,7 +71,7 @@ | 自动正确性与构建 | **限定验收**:Windows shell/ConPTY/呈现及 Windows/Linux 核心 CI、差分/恢复/队列/生命周期场景 | 产品打包、干净机器使用、依赖升级、长期回归和更广平台矩阵;#40 的 CI 纯夹具超时、窄窗口选择 #73、四 shell 原事件 #80、hosted 准备 #81 和[复制夹具 OpenClipboard 5 #85](https://github.com/JavaZeroo/termforge/issues/85) 等独立失败仍未闭合;#72 保存判据与 #80 同步条件的限定修正不代替其他配置或未知根因验收 | R2 / R4 | | Windows 产品交付 | **实现中,未验收**:首个 [v0.1.0-alpha.1 预发布](releases/v0.1.0-alpha.1.md)提供 Windows x64、静态 MSVC 运行库、附资源许可和构建身份的免安装 ZIP;未签名,已验环境限 Windows 11 本机与 Server 2025 CI,布局仍写入 LOCALAPPDATA | 这是 R1 体验包,尚非 R2 日常开发版;干净机器与更广平台矩阵、签名/安装、配置升级及持续运行仍待完成。Windows 10 未验收,Server 2022 已知资源门槛未过 | R2 / R3 | | Linux/macOS 与其他架构 | **未实现**客户端;Linux 核心 CI 已有。[官方平台范围台账](../research/windterm-2.7.0-platform-scope.md)已固定 2.7.0 的 Windows x86/x64、macOS x64、Linux x64 资产及声明下限;这不是 TermForge 支持或实测结论 | 最终需真实 Linux/macOS 客户端;平台调查可提前进行,整合及完整验收排在 Windows 11 x64 完整版本之后。其他系统版本、最低版本和架构由用户后续明确;旧系统及 ARM 等保持调查记录,不自动承诺或排除,也不能由核心 CI 推断产品支持 | 持续调查;R5 全平台出口 | -| 吞吐、响应、内存与稳定性 | **实现中,未验收**:已有机制实验、连续 CPU 区间校准与合成回归;候选字素改动的受限诊断中 project/interactive 吞吐中位数约下降 16%/9%,由 [#54](https://github.com/JavaZeroo/termforge/issues/54) 跟踪。[冻结批次执行器](../experiments/measure/R54-COST.md#冻结批次执行器windows)核对构建来源、原始输出、停止规则与逐轮配对统计;[独立 hosted 构建与实测](../experiments/measure/results/2026-10-27-r54-hosted/README.md)已验证来源和失败保留,但首批因环境护栏停止,尚无完整成本批次;[独立CPU边界诊断](../experiments/measure/results/2026-10-27-r54-cpu-boundary/README.md)另记完整子进程/执行器分量,不改原护栏或判成本通过 | 旧诊断的共享宿主、allocator 包装与缺少真实呈现/输入时延端点使其不构成正式预算;新的不完整批次也不作吞吐结论。仍需同负载/同正确性、无插桩对照、观测开销和长期/多会话公平性;可靠原版基线后提出逐项预算及允许波动范围,**由用户明确确认**。与 WindTerm 的实际差距**待取证** | 当前优先;贯穿 R1–R5 | +| 吞吐、响应、内存与稳定性 | **实现中,未验收**:已有机制实验、连续 CPU 区间校准与合成回归;候选字素改动的受限诊断中 project/interactive 吞吐中位数约下降 16%/9%,由 [#54](https://github.com/JavaZeroo/termforge/issues/54) 跟踪。[冻结批次执行器](../experiments/measure/R54-COST.md#冻结批次执行器windows)核对构建来源、原始输出、停止规则与逐轮配对统计;[独立 hosted 构建与实测](../experiments/measure/results/2026-10-27-r54-hosted/README.md)已验证来源和失败保留,但首批因环境护栏停止,尚无完整成本批次;[共享宿主CPU诊断](../experiments/measure/results/2026-10-27-r54-cpu-boundary/README.md)及[新hosted六位置](../experiments/measure/results/2026-10-27-r54-cpu-hosted/README.md)分别记录完整子进程/执行器分量;后者仍有3.333%–5.263%未归属余额,不改原护栏或判成本通过 | 旧诊断的共享宿主、allocator 包装与缺少真实呈现/输入时延端点使其不构成正式预算;新的不完整批次也不作吞吐结论。仍需同负载/同正确性、无插桩对照、观测开销和长期/多会话公平性;可靠原版基线后提出逐项预算及允许波动范围,**由用户明确确认**。与 WindTerm 的实际差距**待取证** | 当前优先;贯穿 R1–R5 | | 大历史与动态内存压缩 | **未实现**产品能力;WindTerm 压缩属于官方性能声明,内部机制尚未证实 | 1/10/100 万行等明确规模下的内存/滚动/搜索/淘汰实验;根据瓶颈决定独立存储/压缩实现 | R4 | | 完整目标验收 | **待取证**:已有固定版本和局部观察,没有完整行为/性能对照矩阵 | 先在 Windows 11 x64 完整验收功能/行为/UI/性能及独立构建,再完成 Linux/macOS 全平台出口;重要差异和性能容差须有用户确认,Windows 通过不代表全平台完成;不依赖 WindTerm 二进制或专有资源 | R5 分平台出口 | diff --git a/experiments/measure/R54-CPU-HOSTED.md b/experiments/measure/R54-CPU-HOSTED.md new file mode 100644 index 00000000..4a63896b --- /dev/null +++ b/experiments/measure/R54-CPU-HOSTED.md @@ -0,0 +1,29 @@ +# R54:独立 hosted CPU 分量诊断 + +本次延续[六位置CPU边界合同](R54-CPU-DIAGNOSTIC.md),回答在一个新GitHub-hosted Windows VM中,自身区间外CPU、runner CPU与全机余额分别多大。共享工作站的[一次实际诊断](results/2026-10-27-r54-cpu-boundary/README.md)已显示这些分量可以分开记录,但其活动水平不支持成本验收;旧hosted第24位置的原因仍未知。 + +## 固定执行 + +以 PR #106 的 `beeb64496b2e2898e8619fa5e9c39f490a3891c4` 为基点。入口为[工作流](../../.github/workflows/r54-cpu.yml),只接受下述三个明确分支的创建push,拒绝attempt2;后续代码/导出器/证据修正不自动触发替代观察。原 `r54-cost.yml`、两批各112位置、原5%护栏及其失败记录不变。 + +首个`perf/grapheme-cpu-hosted-r54`创建作业 [40509157581](https://github.com/JavaZeroo/termforge/actions/runs/40509157581) 来自`eed0ab7bae5fcc5d05a25cea5161dabc4f935878`,attempt1,在31项准备测试中的发布夹具路径边界比较处失败。夹具根路径未规范化,被测发布器则将输入路径resolve后比较;旧job没有记录该临时目录的实际路径形式。构建、诊断和导出均未启动,实际观察为0,旧run不重跑。本地使用真实8.3别名复现了该缺陷:旧比较为false、规范化后为true;这不是旧hosted路径形式的直接证据。修正仅将夹具根目录规范化,不放宽发布器路径边界。 + +修正与审查后,`perf/grapheme-cpu-hosted-r54-setup2`于2026-10-27 13:22:55 UTC在`c14adb9a7fa446476ad5c95c1f8c1b139ceb5ac4`创建。提供者列表只出现无路径过滤的[默认回归40511533857](https://github.com/JavaZeroo/termforge/actions/runs/40511533857),没有该分支的CPU或候选工作流作业,实际诊断观察仍为0;原实验分支同源码更新对应的CPU作业40511437233为skipped。不能将默认回归计作诊断执行。 + +GitHub的[路径过滤规则](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#git-diff-comparisons)依赖push文件差异,空差异不运行工作流。上述缺席与新分支在已发布commit上创建、两个工作流均有路径过滤相符,但事件实际文件列表未留存。为消除入口对此差异计算的依赖,本诊断移除paths过滤,仍保留明确分支白名单、创建push条件和attempt1检查。 + +第三入口预声明为`perf/grapheme-cpu-hosted-r54-entry3`的新创建push,使用修订后新source/run身份,一次完成原构建及六位置诊断。前三个入口的实际状态分别保留,不重建旧分支、不重跑旧run、不增加或替换任何已存在的测量样本;后续修订push仍不会执行诊断。该入口变化不改测量代码、oracle、停止条件或产品容差。[实际run40512310499及归档复核](results/2026-10-27-r54-cpu-hosted/README.md)已完成:六个位置输出正确、计量完整,扣除自身完整工作后仍有3.333%–5.263%的余额;没有成本或性能验收结论。 + +一个新的`windows-2025` VM依次准备Python3.12、psutil7.2.2、Rust1.92.0,执行合同测试,然后[复建并审计](r54_build.py)原固定 `.3/.4` 及四次短正确性。仍是MSVC x64、Release、locked/offline、no-default-features、jobs1、独立target及两个共同harness覆盖;80/84来源文件、原锁文件、真实编译/链接日志和EXE哈希保持可追溯。它是新构建,不借用本地或上次hosted二进制身份。 + +构建/测试结束后只执行一次 `.3,.4,.4,.3,.3,.4`,全部为原interactive 22,000B、chunk1、observe0、内部CPU/墙钟至少2秒。使用未经修改的`r54_cpu_diagnostic`完整子进程/runner/全机计量,原完整输出oracle和来源前后审计继续执行。单子进程90秒、清理5秒;来源、输出、计数或退出不成立时立即停止,不补样。构建期限600秒、job30分钟;构建失败不进入诊断。 + +本次不跑空闲资格预检,不计算A/B成本比或吞吐回归,不接受或调整产品性能容差。`accounting_complete`只表示六份诊断记录完整。全机余额保留正负,可能包含其他guest活动、计数粒度和采样边界;不把它称为某个外部进程的精确CPU,也不能补造旧hosted缺失的全生命周期计数。两台宿主的绝对数值不能直接用于性能比较。 + +## 证据和公开范围 + +保留GitHub事件/run/attempt/commit、实际runner/映像、构建来源、host OS/CPU、原始计数及全部观察;分析时从提供者作业元数据独立核对身份。没有修改电源、优先级、亲和性或后台服务的步骤。物理宿主排他性与频率仍未知。 + +发布器的显式`cpu-boundary`模式只包含本次构建和六位置诊断的固定白名单,与原成本批次分开。它在任何staging之前核对本次raw schema/run/attempt/source,失败和不完整流也保留;测量、sanity及诊断入口identity的stdout/stderr字节不改;bundle内的构建identity日志保留完整内容并执行路径前缀替换。元数据中的实际长/短/转义路径改为别名,子PID及进程清单不公开;清单同时列原始/公开SHA和大小。绝不递归上传checkout、Cargo缓存或任意目录。新分支身份和schema不会被原默认发布模式接受。 + +只有下载并审核实际产物、源码/构建、全部原字节oracle和CPU等式之后,才将观察写入 #54。若此诊断支持改进后续环境计量,须另行冻结新协议与完整样本计划;不倒改原v1,也不以诊断完成代替受控A/B、allocator/projection及组件归因、预算提案和用户确认。 diff --git a/experiments/measure/r54_cpu_hosted.py b/experiments/measure/r54_cpu_hosted.py new file mode 100644 index 00000000..f523fad5 --- /dev/null +++ b/experiments/measure/r54_cpu_hosted.py @@ -0,0 +1,55 @@ +"""One fresh hosted build followed by the separately declared CPU-boundary diagnosis.""" +import argparse +import json +from pathlib import Path + +from experiments.measure.r54_batch import sha, utc, write_json +from experiments.measure.r54_build import prepare_builds +from experiments.measure.r54_contract import ROOT +from experiments.measure.r54_cpu_diagnostic import execute as diagnose +from experiments.measure.r54_hosted import CPU_BOUNDARY_BRANCHES, hosted_identity +from experiments.measure.r54_inputs import git, require + +def execute(output): + output = Path(output).resolve() + require(output.is_relative_to(ROOT / 'local'), 'hosted artifacts must stay under the workspace local directory') + output.mkdir(parents=True, exist_ok=False) + manifest = dict(schema='termforge-r54-cpu-hosted-v1', status='preparing', started_utc=utc(), + source=git(ROOT, 'rev-parse', 'HEAD'), runner_sha256=sha(Path(__file__)), + workflow_sha256=sha(ROOT / '.github/workflows/r54-cpu.yml'), + performance_gate='not_evaluated', diagnostic=None) + try: + manifest['hosted_identity'] = hosted_identity(CPU_BOUNDARY_BRANCHES) + write_json(output / 'hosted.json', manifest) + prepare_builds(output / 'bundle') + declaration = dict(host_kind='hosted_vm', no_known_concurrent_build_or_test=True, + known_concurrent_work=['This job completed setup, tests and both audited builds before diagnosis.', + 'GitHub runner service and operating-system background services remain.', + 'Physical host scheduling and neighboring virtual machines are unobserved.'], + purpose='One six-observation CPU-boundary diagnostic; no idle qualification or cost acceptance.') + write_json(output / 'environment-declaration.json', declaration) + manifest['status'] = 'diagnosing' + write_json(output / 'hosted.json', manifest) + result = diagnose(output / 'bundle/plan-v1.json', output / 'bundle', + output / 'environment-declaration.json', output / 'diagnostic') + manifest['diagnostic'] = result + require(result['status'] == 'accounting_complete', 'diagnosis stopped; no replacement observations') + manifest['status'] = 'accounting_complete' + except BaseException as error: + manifest.update(status='failed', error=f'{type(error).__name__}: {error}') + raise + finally: + manifest['finished_utc'] = utc() + write_json(output / 'hosted.json', manifest) + return manifest + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--out', type=Path, required=True) + args = parser.parse_args() + print(json.dumps(execute(args.out))) + + +if __name__ == '__main__': + main() diff --git a/experiments/measure/r54_hosted.py b/experiments/measure/r54_hosted.py index a59cb725..e30214bd 100644 --- a/experiments/measure/r54_hosted.py +++ b/experiments/measure/r54_hosted.py @@ -9,8 +9,11 @@ from experiments.measure.r54_contract import ROOT, SEEDS from experiments.measure.r54_inputs import git, require +CPU_BOUNDARY_BRANCHES = ('perf/grapheme-cpu-hosted-r54', 'perf/grapheme-cpu-hosted-r54-setup2', + 'perf/grapheme-cpu-hosted-r54-entry3') -def hosted_identity(): + +def hosted_identity(branch='perf/grapheme-hosted-r54'): names = ('GITHUB_ACTIONS', 'RUNNER_ENVIRONMENT', 'RUNNER_OS', 'GITHUB_REPOSITORY', 'GITHUB_SHA', 'GITHUB_REF', 'GITHUB_RUN_ID', 'GITHUB_RUN_NUMBER', 'GITHUB_RUN_ATTEMPT', 'GITHUB_EVENT_NAME', 'ImageOS', 'ImageVersion') @@ -19,7 +22,8 @@ def hosted_identity(): identity['RUNNER_OS'] == 'Windows' and os.name == 'nt', 'requires an actual GitHub-hosted Windows job') require(identity['GITHUB_REPOSITORY'] == 'JavaZeroo/termforge' and identity['GITHUB_EVENT_NAME'] == 'push', 'unexpected repository or event') - require(identity['GITHUB_REF'] == 'refs/heads/perf/grapheme-hosted-r54', 'unexpected experiment branch') + branches = (branch,) if isinstance(branch, str) else branch + require(identity['GITHUB_REF'] in ('refs/heads/' + name for name in branches), 'unexpected experiment branch') require(identity['GITHUB_RUN_ATTEMPT'] == '1', 'a workflow rerun must not replace the first attempt') require(identity['GITHUB_SHA'] == git(ROOT, 'rev-parse', 'HEAD'), 'workflow/source identity mismatch') return identity diff --git a/experiments/measure/r54_publish.py b/experiments/measure/r54_publish.py index 5a9787a0..426fb9e0 100644 --- a/experiments/measure/r54_publish.py +++ b/experiments/measure/r54_publish.py @@ -8,13 +8,20 @@ from experiments.measure.r54_batch import sha, write_json from experiments.measure.r54_contract import ROOT, SEEDS -from experiments.measure.r54_hosted import hosted_identity +from experiments.measure.r54_hosted import CPU_BOUNDARY_BRANCHES, hosted_identity from experiments.measure.r54_inputs import require +EXPERIMENTS = { + 'cost': dict(branch='perf/grapheme-hosted-r54', raw_schema='termforge-r54-hosted-v1', + publication_schema='termforge-r54-hosted-publication-v1'), + 'cpu-boundary': dict(branch=CPU_BOUNDARY_BRANCHES, raw_schema='termforge-r54-cpu-hosted-v1', + publication_schema='termforge-r54-cpu-hosted-publication-v1'), +} + def public_environment(value): """CPU counters remain; process names/PIDs and unrecognized fields do not.""" - fields = ('status', 'host', 'started_utc', 'finished_utc', 'intervals', 'declaration', 'policy', 'power_policy', 'error') + fields = ('status', 'host', 'started_utc', 'finished_utc', 'intervals', 'declaration', 'policy', 'power_policy', 'error', 'scope') result = {name: value[name] for name in fields if name in value} if 'host' in result: host = value['host'] @@ -22,9 +29,9 @@ def public_environment(value): return result -def validate_raw_identity(root, identity): +def validate_raw_identity(root, identity, schema='termforge-r54-hosted-v1'): value = json.loads((root / 'hosted.json').read_text(encoding='utf-8')) - require(value['schema'] == 'termforge-r54-hosted-v1' and value['hosted_identity'] == identity and + require(value['schema'] == schema and value['hosted_identity'] == identity and value['source'] == identity['GITHUB_SHA'], 'raw evidence belongs to another run, attempt or source') @@ -74,8 +81,9 @@ def publish_jsonl(original, replacements): return redact_paths(original, replacements), status -def selected_paths(root): +def selected_paths(root, experiment='cost'): """No recursive directory export: only named builder and runner artifacts.""" + require(experiment in EXPERIMENTS, 'unknown experiment') names = ['hosted.json', 'environment-declaration.json'] names += ['bundle/' + name for name in ('preparation.json', 'plan-v1.json', 'build-plan.json', 'build-audit.json')] for variant in ('baseline', 'candidate'): @@ -84,24 +92,35 @@ def selected_paths(root): names += [f'bundle/{variant}-{step}.{suffix}' for suffix in ('stdout', 'stderr', 'process.json')] for route in ('project', 'interactive'): names += [f'bundle/sanity-{variant}-{route}/{stream}.bin' for stream in ('stdout', 'stderr')] - for seed in SEEDS: - prefix = f'batch-{seed}/' - names += [prefix + name for name in ('manifest.json', 'runner.json', 'environment.json', 'environment-policy.json', - 'environment-declaration.json', 'samples/context.json', 'samples/manifest.json', 'samples/samples.jsonl', 'samples/summary.json')] - for directory in ('baseline-identity', 'candidate-identity', 'power-policy', 'power-policy-after'): + if experiment == 'cost': + for seed in SEEDS: + prefix = f'batch-{seed}/' + names += [prefix + name for name in ('manifest.json', 'runner.json', 'environment.json', 'environment-policy.json', + 'environment-declaration.json', 'samples/context.json', 'samples/manifest.json', 'samples/samples.jsonl', 'samples/summary.json')] + for directory in ('baseline-identity', 'candidate-identity', 'power-policy', 'power-policy-after'): + names += [prefix + directory + '/' + name for name in ('record.json', 'stdout.bin', 'stderr.bin')] + for sequence in range(112): + names += [prefix + f'samples/{sequence:03d}/' + name for name in ('record.json', 'stdout.bin', 'stderr.bin')] + else: + prefix = 'diagnostic/' + names += [prefix + name for name in ('manifest.json', 'runner.json', 'environment.json', 'binding.json', + 'plan-v1.json', 'observations/context.json', 'observations/protocol.json', 'observations/manifest.json')] + for directory in ('baseline-identity', 'candidate-identity'): names += [prefix + directory + '/' + name for name in ('record.json', 'stdout.bin', 'stderr.bin')] - for sequence in range(112): - names += [prefix + f'samples/{sequence:03d}/' + name for name in ('record.json', 'stdout.bin', 'stderr.bin')] + for sequence in range(6): + names += [prefix + f'observations/{sequence:03d}/' + name for name in ('record.json', 'stdout.bin', 'stderr.bin')] return [Path(name) for name in names if (root / name).is_file()] -def publish(root, output): - identity = hosted_identity() +def publish(root, output, experiment='cost'): + require(experiment in EXPERIMENTS, 'unknown experiment') + spec = EXPERIMENTS[experiment] + identity = hosted_identity(spec['branch']) root, output = Path(root).resolve(), Path(output).resolve() require(root.is_relative_to(ROOT / 'local') and output.is_relative_to(ROOT / 'local'), 'publication paths must stay in workspace local') require(root != output and not output.is_relative_to(root), 'public output must be separate from raw records') require(not output.exists(), 'public output already exists') - validate_raw_identity(root, identity) + validate_raw_identity(root, identity, spec['raw_schema']) staging = output.with_name(output.name + '.partial') require(staging.is_relative_to(ROOT / 'local'), 'staging path escaped workspace') staging.mkdir(parents=True, exist_ok=False) @@ -116,13 +135,13 @@ def text(value): def transform(value): if isinstance(value, dict): - return {key: transform(item) for key, item in value.items()} + return {key: transform(item) for key, item in value.items() if key != 'child_pid'} if isinstance(value, list): return [transform(item) for item in value] return text(value) if isinstance(value, str) else value inventory = [] - for relative in selected_paths(root): + for relative in selected_paths(root, experiment): source = root / relative require(source.resolve().is_relative_to(root), 'artifact path escaped raw directory') original = source.read_bytes() @@ -130,7 +149,7 @@ def transform(value): # The measurement EXE consumes only public, fixed synthetic workloads. # Preserve its raw streams even on failure. Other logs can contain host # path prefixes; redact those without discarding their full contents. - raw_sample = bool(re.fullmatch(r'(?:batch-\d+/samples/\d{3}|bundle/sanity-(?:baseline|candidate)-(?:project|interactive))/(?:stdout|stderr)\.bin', relative.as_posix())) + raw_sample = bool(re.fullmatch(r'(?:batch-\d+/samples/\d{3}|bundle/sanity-(?:baseline|candidate)-(?:project|interactive)|diagnostic/(?:observations/\d{3}|(?:baseline|candidate)-identity))/(?:stdout|stderr)\.bin', relative.as_posix())) if raw_sample: data, treatment = original, 'byte_exact_owned_synthetic_stream' elif relative.suffix == '.json': @@ -152,7 +171,7 @@ def transform(value): original_sha256=hashlib.sha256(original).hexdigest(), published_bytes=len(data), published_sha256=sha(target), treatment=treatment, jsonl_status=jsonl_status)) - write_json(staging / 'publication.json', dict(schema='termforge-r54-hosted-publication-v1', + write_json(staging / 'publication.json', dict(schema=spec['publication_schema'], hosted_identity=identity, artifacts=inventory, raw_process_identities_published=False, full_environment_variables_published=False, performance_gate='not_evaluated', limitation='guest CPU evidence cannot establish exclusive physical host or stable frequency')) @@ -164,8 +183,9 @@ def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--raw', type=Path, required=True) parser.add_argument('--out', type=Path, required=True) + parser.add_argument('--experiment', choices=EXPERIMENTS, default='cost') args = parser.parse_args() - print(json.dumps(publish(args.raw, args.out))) + print(json.dumps(publish(args.raw, args.out, args.experiment))) if __name__ == '__main__': diff --git a/experiments/measure/results/2026-10-27-r54-cpu-hosted/README.md b/experiments/measure/results/2026-10-27-r54-cpu-hosted/README.md new file mode 100644 index 00000000..10a4e13a --- /dev/null +++ b/experiments/measure/results/2026-10-27-r54-cpu-hosted/README.md @@ -0,0 +1,54 @@ +# R54:新 hosted VM 的 CPU 分量诊断 + +本次按[预声明合同](../../R54-CPU-HOSTED.md)完成一次六位置诊断,全部输出正确、退出0,完整子进程/runner/全机计量可复核。**它没有执行空闲资格筛选或正式成本批次,不构成性能验收。** + +## 来源与执行身份 + +- 源码 `4772f4f937c4f0f220be1630592f84bed3a591c8`,树 `86e2342d16acd101fe182793d20aef3f1f017633`;与审查树一致。 +- [run 40512310499](https://github.com/JavaZeroo/termforge/actions/runs/40512310499),job `122217071656`,attempt1,创建push分支 `perf/grapheme-cpu-hosted-r54-entry3`。提供者元数据、作业日志及归档身份相符。 +- 实际映像 `windows-2025-vs2026` / `20261021.278.1`;Windows Server 2025 build26100、UBR33650、24H2,AMD EPYC 7763,guest4逻辑/2物理CPU,Python3.12.10、psutil7.2.2。 +- Rust1.92.0、MSVC14.51.36231 x64;Release、locked/offline、no-default-features、jobs1,独立target。构建前31项准备测试通过(14.042s),两次构建和四次短正确性通过后才进入诊断。 + +| 核心 | 固定来源 | 本次新EXE SHA-256 | 字节数 | +|---|---|---|---:| +| `.3` | `65988f5f20f62294ff52fcac5b5b81e563f93f3b` | `5f31a54e5543eca286e98a10b31aae060b0a52f2ccbcfb4bfc1d7983d6428c03` | 523264 | +| `.4` | `3d6d44d3b3e9a9a3e41da98e8711e9f19a211fd8` | `45a15862e2bd8c8ce93073923b68f23bc6f3f848aa147ed1ce6340135e214207` | 580096 | + +80/84个跟踪来源文件、原锁文件与两处共同harness覆盖均核对。Git blob和实际Windows检出换行不同的文件,逐个用完整SHA验证准确的LF→CRLF转换;没有修改证据来匹配仓库字节。4份共同harness/校验入口及164份原文件共168次来源核对,其中115份对应CRLF检出、53份直接匹配blob。它是独立构建,不沿用此前EXE身份。 + +## 实际六位置 + +固定interactive 22,000B、chunk1、observe0,内部CPU/墙钟至少2秒,顺序 `.3,.4,.4,.3,.3,.4`;单进程90秒、清理5秒。未重跑或补样,原完整oracle不变。 + +| sequence | 核心 | 自身区间外CPU/s | runner CPU/s | 全机未归属余额/s | 余额占全机总CPU区间 | +|---:|---|---:|---:|---:|---:| +| 0 | `.3` | 0.093750 | 0 | 0.500000 | 5.263158% | +| 1 | `.4` | 0.062500 | 0.015625 | 0.281250 | 3.333333% | +| 2 | `.4` | 0.078125 | 0 | 0.328125 | 3.888889% | +| 3 | `.3` | 0.078125 | 0 | 0.328125 | 3.860294% | +| 4 | `.3` | 0.062500 | 0 | 0.296875 | 3.492647% | +| 5 | `.4` | 0.078125 | 0 | 0.312500 | 3.703704% | + +余额为全机busy减完整子进程CPU及runner同区间CPU,允许正负;可能包括其他guest活动、计数粒度和非原子端点。sequence0即使扣除自身完整工作,余额仍超过原5%环境护栏的数值;本诊断不应用该护栏判通过。结果仅支持“补齐自身计量不能消除这个新环境的全部余额”,不将余额归因某一进程,不解释旧hosted第24位置失败,也不证明物理宿主排他或频率稳定。 + +没有计算吞吐比、没有改原v1两批各112位置及5%护栏,也没有接受产品性能容差。`accounting_complete`仅表示诊断记录完整;`performance_gate=not_evaluated`,正式成本验收样本为0。 + +## 保留的入口缺口 + +首次source `eed0ab7` 的 [40509157581](https://github.com/JavaZeroo/termforge/actions/runs/40509157581)在31项准备测试中的路径边界比较失败,实际构建/测量0。夹具根路径未规范化;本地8.3别名复现该缺陷,但旧job实际临时路径形式未记录。只规范化测试ROOT,生产路径边界未放宽。首次四条普通CI也在Windows的同一测试失败,Linux成功;元数据与错误摘录留在 [validation.json](validation.json)。 + +修订 `c14adb9a` 的四条普通CI及setup2默认CI均通过;在已发布source创建setup2时,仅出现无路径过滤的默认回归40511533857,没有CPU或候选workflow run。CPU入口随后去掉paths过滤,并单独预声明entry3;创建事件与attempt1限制保持。没有删除重建旧分支、重跑旧run或用新观察覆盖失败。触发解释及其未知范围见合同。 + +## 归档和复核 + +审核后的[evidence.zip](evidence.zip)与提供者产物字节相同:123388B,SHA-256 `263a3bf8e229b89f1e443b12e522daf69d30de403affa0dc49fe674c0dd8f241`,artifact `12738430576`。75文件中74份有原始/公开哈希清单,24份sanity/诊断identity/观察流保持原字节;元数据移除子PID、长短路径改别名,不含checkout、缓存、进程清单或WindTerm私有产物。 + +完整构建日志、来源清单、原始计数与输出均在归档;[validation.json](validation.json)整理实际身份和结论。运行以下只读复核,不启动编译或测量,需包含固定来源提交的Git历史: + +```powershell +python experiments/measure/results/2026-10-27-r54-cpu-hosted/verify.py +``` + +复核包含所有公开文件哈希、24份原字节流、来源及构建绑定、四次sanity、六次完整输出oracle和全部CPU等式。本地measurement40/40(19.436s),入口增量4/4(0.297s);实际hosted测试与上述本地测试身份分别保留。 + +后续仍需受控完整A/B、allocator/projection扰动与组件归因、可靠WindTerm基线及用户确认的逐项预算。#54、#34和R2保持未完成,产品核心与后端继续作为候选。 diff --git a/experiments/measure/results/2026-10-27-r54-cpu-hosted/evidence.zip b/experiments/measure/results/2026-10-27-r54-cpu-hosted/evidence.zip new file mode 100644 index 00000000..f1bdd091 Binary files /dev/null and b/experiments/measure/results/2026-10-27-r54-cpu-hosted/evidence.zip differ diff --git a/experiments/measure/results/2026-10-27-r54-cpu-hosted/validation.json b/experiments/measure/results/2026-10-27-r54-cpu-hosted/validation.json new file mode 100644 index 00000000..b3554a61 --- /dev/null +++ b/experiments/measure/results/2026-10-27-r54-cpu-hosted/validation.json @@ -0,0 +1,2538 @@ +{ + "schema": "termforge-r54-cpu-hosted-validation-v1", + "source": "4772f4f937c4f0f220be1630592f84bed3a591c8", + "hosted_identity": { + "GITHUB_ACTIONS": "true", + "RUNNER_ENVIRONMENT": "github-hosted", + "RUNNER_OS": "Windows", + "GITHUB_REPOSITORY": "JavaZeroo/termforge", + "GITHUB_SHA": "4772f4f937c4f0f220be1630592f84bed3a591c8", + "GITHUB_REF": "refs/heads/perf/grapheme-cpu-hosted-r54-entry3", + "GITHUB_RUN_ID": "40512310499", + "GITHUB_RUN_NUMBER": "3", + "GITHUB_RUN_ATTEMPT": "1", + "GITHUB_EVENT_NAME": "push", + "ImageOS": "win25-vs2026", + "ImageVersion": "20261021.278.1" + }, + "host": { + "host": { + "platform": "Windows-2025Server-10.0.26100-SP0", + "python": "3.12.10", + "psutil": "7.2.2", + "cpu_logical": 4, + "cpu_physical": 2, + "cpu": { + "ProcessorNameString": "AMD EPYC 7763 64-Core Processor ", + "Identifier": "AMD64 Family 25 Model 1 Stepping 1" + }, + "windows": { + "CurrentBuildNumber": "26100", + "UBR": 33650, + "DisplayVersion": "24H2" + } + }, + "declaration": { + "host_kind": "hosted_vm", + "no_known_concurrent_build_or_test": true, + "known_concurrent_work": [ + "This job completed setup, tests and both audited builds before diagnosis.", + "GitHub runner service and operating-system background services remain.", + "Physical host scheduling and neighboring virtual machines are unobserved." + ], + "purpose": "One six-observation CPU-boundary diagnostic; no idle qualification or cost acceptance." + }, + "scope": "accounting diagnosis on declared host; no idle qualification or cost acceptance" + }, + "builds": { + "baseline": { + "source": "65988f5f20f62294ff52fcac5b5b81e563f93f3b", + "version": "0.26.1-dev+termforge.3", + "candidate_tree": "38f901ce2407d73ab7d4ae70987c294849bafa92", + "tracked_candidate_files": 80, + "changed_paths": [ + "experiments/candidates/alacritty/Cargo.toml", + "experiments/candidates/alacritty/src/measure.rs" + ], + "binary": { + "bytes": 523264, + "sha256": "5f31a54e5543eca286e98a10b31aae060b0a52f2ccbcfb4bfc1d7983d6428c03" + }, + "identity": { + "allocator_wrapper_compiled": false, + "projection_selectable": true, + "schema": "termforge-core-cost-build-v1", + "timing_gates_compiled": true + }, + "linker": { + "path": "C:\\Program Files\\Microsoft Visual Studio\\18\\Enterprise\\VC\\Tools\\MSVC\\14.51.36231\\bin\\HostX64\\x64\\link.exe", + "sha256": "a8c42e25c91ca2453e1110540ac08f0fc12d7539454a11b9af8baeecb469837d" + }, + "receipt_sha256": "886d9a3f024d46a221dc4833a485e0c9c2c4b6e6193dd42190fe10fc6bc70a8a" + }, + "candidate": { + "source": "3d6d44d3b3e9a9a3e41da98e8711e9f19a211fd8", + "version": "0.26.1-dev+termforge.4", + "candidate_tree": "2cce55fcf2d379440110bbbf8612117cce3edf64", + "tracked_candidate_files": 84, + "changed_paths": [ + "experiments/candidates/alacritty/Cargo.toml", + "experiments/candidates/alacritty/src/measure.rs" + ], + "binary": { + "bytes": 580096, + "sha256": "45a15862e2bd8c8ce93073923b68f23bc6f3f848aa147ed1ce6340135e214207" + }, + "identity": { + "allocator_wrapper_compiled": false, + "projection_selectable": true, + "schema": "termforge-core-cost-build-v1", + "timing_gates_compiled": true + }, + "linker": { + "path": "C:\\Program Files\\Microsoft Visual Studio\\18\\Enterprise\\VC\\Tools\\MSVC\\14.51.36231\\bin\\HostX64\\x64\\link.exe", + "sha256": "a8c42e25c91ca2453e1110540ac08f0fc12d7539454a11b9af8baeecb469837d" + }, + "receipt_sha256": "5d8e407aa31a9d2fc3921a15fcc15e295e9fa8a748acf2f40e81744d1cdaa914" + } + }, + "observations": [ + { + "item": { + "sequence": 0, + "variant": "baseline", + "route": "interactive", + "chunk": 1 + }, + "inner_cpu_seconds": 2.234375, + "child_cpu": { + "creation_filetime": 134375815087328400, + "exit_filetime": 134375815111035208, + "kernel_seconds": 0.609375, + "user_seconds": 1.71875, + "total_seconds": 2.328125 + }, + "runner_cpu_seconds": 0.0, + "environment": { + "total_seconds": 9.5, + "busy_seconds": 2.828125, + "busy_percent": 29.769736842105264, + "before": { + "user": 224.96875, + "kernel_including_idle": 1054.8125, + "idle": 938.25, + "system": 116.5625, + "perf_counter_seconds": 320.6986669, + "utc": "2026-10-27T13:31:48.731677+00:00" + }, + "after": { + "user": 226.921875, + "kernel_including_idle": 1062.359375, + "idle": 944.921875, + "system": 117.4375, + "perf_counter_seconds": 323.0708238, + "utc": "2026-10-27T13:31:51.102693+00:00" + } + }, + "accounting": { + "inner_only_balance_seconds": 0.59375, + "inner_only_balance_percent": 6.25, + "child_outside_inner_seconds": 0.09375, + "runner_cpu_seconds": 0.0, + "unassigned_balance_seconds": 0.5, + "unassigned_balance_percent": 5.2631578947368425 + }, + "state_fnv1a64": "8035857386658397897" + }, + { + "item": { + "sequence": 1, + "variant": "candidate", + "route": "interactive", + "chunk": 1 + }, + "inner_cpu_seconds": 2.015625, + "child_cpu": { + "creation_filetime": 134375815111116270, + "exit_filetime": 134375815132177544, + "kernel_seconds": 0.578125, + "user_seconds": 1.5, + "total_seconds": 2.078125 + }, + "runner_cpu_seconds": 0.015625, + "environment": { + "total_seconds": 8.4375, + "busy_seconds": 2.375, + "busy_percent": 28.14814814814815, + "before": { + "user": 226.921875, + "kernel_including_idle": 1062.359375, + "idle": 944.921875, + "system": 117.4375, + "perf_counter_seconds": 323.0773715, + "utc": "2026-10-27T13:31:51.111019+00:00" + }, + "after": { + "user": 228.546875, + "kernel_including_idle": 1069.171875, + "idle": 950.984375, + "system": 118.1875, + "perf_counter_seconds": 325.1850088, + "utc": "2026-10-27T13:31:53.217016+00:00" + } + }, + "accounting": { + "inner_only_balance_seconds": 0.359375, + "inner_only_balance_percent": 4.2592592592592595, + "child_outside_inner_seconds": 0.0625, + "runner_cpu_seconds": 0.015625, + "unassigned_balance_seconds": 0.28125, + "unassigned_balance_percent": 3.3333333333333335 + }, + "state_fnv1a64": "6154007251599136798" + }, + { + "item": { + "sequence": 2, + "variant": "candidate", + "route": "interactive", + "chunk": 1 + }, + "inner_cpu_seconds": 2.03125, + "child_cpu": { + "creation_filetime": 134375815132252696, + "exit_filetime": 134375815153338773, + "kernel_seconds": 0.5625, + "user_seconds": 1.546875, + "total_seconds": 2.109375 + }, + "runner_cpu_seconds": 0.0, + "environment": { + "total_seconds": 8.4375, + "busy_seconds": 2.4375, + "busy_percent": 28.88888888888889, + "before": { + "user": 228.546875, + "kernel_including_idle": 1069.234375, + "idle": 951.046875, + "system": 118.1875, + "perf_counter_seconds": 325.1909982, + "utc": "2026-10-27T13:31:53.223062+00:00" + }, + "after": { + "user": 230.296875, + "kernel_including_idle": 1075.921875, + "idle": 957.046875, + "system": 118.875, + "perf_counter_seconds": 327.3011683, + "utc": "2026-10-27T13:31:55.334541+00:00" + } + }, + "accounting": { + "inner_only_balance_seconds": 0.40625, + "inner_only_balance_percent": 4.814814814814815, + "child_outside_inner_seconds": 0.078125, + "runner_cpu_seconds": 0.0, + "unassigned_balance_seconds": 0.328125, + "unassigned_balance_percent": 3.888888888888889 + }, + "state_fnv1a64": "6154007251599136798" + }, + { + "item": { + "sequence": 3, + "variant": "baseline", + "route": "interactive", + "chunk": 1 + }, + "inner_cpu_seconds": 2.03125, + "child_cpu": { + "creation_filetime": 134375815153414663, + "exit_filetime": 134375815174567926, + "kernel_seconds": 0.484375, + "user_seconds": 1.625, + "total_seconds": 2.109375 + }, + "runner_cpu_seconds": 0.0, + "environment": { + "total_seconds": 8.5, + "busy_seconds": 2.4375, + "busy_percent": 28.676470588235293, + "before": { + "user": 230.296875, + "kernel_including_idle": 1075.921875, + "idle": 957.046875, + "system": 118.875, + "perf_counter_seconds": 327.3071463, + "utc": "2026-10-27T13:31:55.340090+00:00" + }, + "after": { + "user": 232.109375, + "kernel_including_idle": 1082.609375, + "idle": 963.109375, + "system": 119.5, + "perf_counter_seconds": 329.4241257, + "utc": "2026-10-27T13:31:57.457105+00:00" + } + }, + "accounting": { + "inner_only_balance_seconds": 0.40625, + "inner_only_balance_percent": 4.779411764705882, + "child_outside_inner_seconds": 0.078125, + "runner_cpu_seconds": 0.0, + "unassigned_balance_seconds": 0.328125, + "unassigned_balance_percent": 3.860294117647059 + }, + "state_fnv1a64": "8035857386658397897" + }, + { + "item": { + "sequence": 4, + "variant": "baseline", + "route": "interactive", + "chunk": 1 + }, + "inner_cpu_seconds": 2.046875, + "child_cpu": { + "creation_filetime": 134375815174640115, + "exit_filetime": 134375815195919780, + "kernel_seconds": 0.5625, + "user_seconds": 1.546875, + "total_seconds": 2.109375 + }, + "runner_cpu_seconds": 0.0, + "environment": { + "total_seconds": 8.5, + "busy_seconds": 2.40625, + "busy_percent": 28.308823529411764, + "before": { + "user": 232.109375, + "kernel_including_idle": 1082.609375, + "idle": 963.109375, + "system": 119.5, + "perf_counter_seconds": 329.4296819, + "utc": "2026-10-27T13:31:57.463164+00:00" + }, + "after": { + "user": 233.84375, + "kernel_including_idle": 1089.375, + "idle": 969.203125, + "system": 120.171875, + "perf_counter_seconds": 331.5593194, + "utc": "2026-10-27T13:31:59.593006+00:00" + } + }, + "accounting": { + "inner_only_balance_seconds": 0.359375, + "inner_only_balance_percent": 4.227941176470588, + "child_outside_inner_seconds": 0.0625, + "runner_cpu_seconds": 0.0, + "unassigned_balance_seconds": 0.296875, + "unassigned_balance_percent": 3.4926470588235294 + }, + "state_fnv1a64": "8035857386658397897" + }, + { + "item": { + "sequence": 5, + "variant": "candidate", + "route": "interactive", + "chunk": 1 + }, + "inner_cpu_seconds": 2.03125, + "child_cpu": { + "creation_filetime": 134375815195995616, + "exit_filetime": 134375815217130487, + "kernel_seconds": 0.453125, + "user_seconds": 1.65625, + "total_seconds": 2.109375 + }, + "runner_cpu_seconds": 0.0, + "environment": { + "total_seconds": 8.4375, + "busy_seconds": 2.421875, + "busy_percent": 28.703703703703702, + "before": { + "user": 233.84375, + "kernel_including_idle": 1089.4375, + "idle": 969.25, + "system": 120.1875, + "perf_counter_seconds": 331.5651614, + "utc": "2026-10-27T13:31:59.597040+00:00" + }, + "after": { + "user": 235.671875, + "kernel_including_idle": 1096.046875, + "idle": 975.265625, + "system": 120.78125, + "perf_counter_seconds": 333.6804548, + "utc": "2026-10-27T13:32:01.713906+00:00" + } + }, + "accounting": { + "inner_only_balance_seconds": 0.390625, + "inner_only_balance_percent": 4.62962962962963, + "child_outside_inner_seconds": 0.078125, + "runner_cpu_seconds": 0.0, + "unassigned_balance_seconds": 0.3125, + "unassigned_balance_percent": 3.7037037037037037 + }, + "state_fnv1a64": "6154007251599136798" + } + ], + "archive": { + "bytes": 123388, + "sha256": "263a3bf8e229b89f1e443b12e522daf69d30de403affa0dc49fe674c0dd8f241", + "files": 75, + "inventory_files": 74, + "byte_exact_streams": 24 + }, + "source_checkout_forms": { + "experiments/candidates/alacritty/Cargo.toml": "git_blob_lf_to_crlf", + "experiments/candidates/alacritty/src/measure.rs": "git_blob_lf_to_crlf", + "experiments/measure/run.py": "git_blob_bytes", + "experiments/measure/r54_contract.py": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/Cargo.lock": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/Cargo.toml": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/PROVENANCE.md": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/README.md": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/include/termforge_candidate.h": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-24-windows/summary.json": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-24-windows/validation.json": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/alternate-query/candidate.jsonl": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/alternate-query/candidate.stderr.txt": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/alternate-query/chunks.txt": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/alternate-query/input.bin": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/alternate-query/report.json": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/bounded-history/candidate.jsonl": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/bounded-history/candidate.stderr.txt": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/bounded-history/chunks.txt": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/bounded-history/input.bin": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/bounded-history/report.json": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-byte/candidate.jsonl": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-byte/candidate.stderr.txt": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-byte/chunks.txt": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-byte/input.bin": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-byte/report.json": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-whole/candidate.jsonl": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-whole/candidate.stderr.txt": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-whole/chunks.txt": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-whole/input.bin": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-whole/report.json": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-1/summary.json": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/alternate-query/candidate.jsonl": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/alternate-query/candidate.stderr.txt": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/alternate-query/chunks.txt": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/alternate-query/input.bin": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/alternate-query/report.json": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/bounded-history/candidate.jsonl": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/bounded-history/candidate.stderr.txt": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/bounded-history/chunks.txt": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/bounded-history/input.bin": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/bounded-history/report.json": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-byte/candidate.jsonl": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-byte/candidate.stderr.txt": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-byte/chunks.txt": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-byte/input.bin": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-byte/report.json": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-whole/candidate.jsonl": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-whole/candidate.stderr.txt": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-whole/chunks.txt": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-whole/input.bin": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-whole/report.json": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/results/2026-10-25-termforge-2/summary.json": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/run.py": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/src/ffi.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/src/main.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/src/measure.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/test_candidate.py": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/CHANGELOG.md": "git_blob_bytes", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/Cargo.toml": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/LICENSE-APACHE": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/event.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/event_loop.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/grid/mod.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/grid/resize.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/grid/row.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/grid/storage.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/grid/tests.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/index.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/lib.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/selection.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/sync.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/term/cell.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/term/color.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/term/mod.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/term/search.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/thread.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/tty/mod.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/tty/unix.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/tty/windows/blocking.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/tty/windows/child.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/tty/windows/conpty.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/tty/windows/mod.rs": "git_blob_lf_to_crlf", + "baseline/experiments/candidates/alacritty/vendor/alacritty_terminal/src/vi_mode.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/Cargo.lock": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/Cargo.toml": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/PROVENANCE.md": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/README.md": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/grapheme_checks.py": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/include/termforge_candidate.h": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-24-windows/summary.json": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-24-windows/validation.json": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/alternate-query/candidate.jsonl": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/alternate-query/candidate.stderr.txt": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/alternate-query/chunks.txt": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/alternate-query/input.bin": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/alternate-query/report.json": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/bounded-history/candidate.jsonl": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/bounded-history/candidate.stderr.txt": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/bounded-history/chunks.txt": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/bounded-history/input.bin": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/bounded-history/report.json": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-byte/candidate.jsonl": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-byte/candidate.stderr.txt": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-byte/chunks.txt": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-byte/input.bin": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-byte/report.json": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-whole/candidate.jsonl": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-whole/candidate.stderr.txt": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-whole/chunks.txt": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-whole/input.bin": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/fragmentation-whole/report.json": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-1/summary.json": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/alternate-query/candidate.jsonl": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/alternate-query/candidate.stderr.txt": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/alternate-query/chunks.txt": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/alternate-query/input.bin": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/alternate-query/report.json": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/bounded-history/candidate.jsonl": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/bounded-history/candidate.stderr.txt": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/bounded-history/chunks.txt": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/bounded-history/input.bin": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/bounded-history/report.json": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-byte/candidate.jsonl": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-byte/candidate.stderr.txt": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-byte/chunks.txt": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-byte/input.bin": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-byte/report.json": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-whole/candidate.jsonl": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-whole/candidate.stderr.txt": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-whole/chunks.txt": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-whole/input.bin": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/fragmentation-whole/report.json": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/results/2026-10-25-termforge-2/summary.json": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/run.py": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/src/ffi.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/src/main.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/src/measure.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/test_candidate.py": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/CHANGELOG.md": "git_blob_bytes", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/Cargo.toml": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/LICENSE-APACHE": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/event.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/event_loop.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/grid/mod.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/grid/resize.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/grid/row.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/grid/storage.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/grid/tests.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/index.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/lib.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/selection.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/sync.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/term/cell.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/term/color.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/term/grapheme.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/term/mod.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/term/search.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/thread.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/tty/mod.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/tty/unix.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/tty/windows/blocking.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/tty/windows/child.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/tty/windows/conpty.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/tty/windows/mod.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/src/vi_mode.rs": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/tests/data/GraphemeBreakTest-17.0.0.txt": "git_blob_lf_to_crlf", + "candidate/experiments/candidates/alacritty/vendor/alacritty_terminal/tests/data/UNICODE-LICENSE.txt": "git_blob_lf_to_crlf" + }, + "sanity_oracles": 4, + "observation_oracles": 6, + "formal_cost_samples": 0, + "performance_gate": "not_evaluated", + "old_hosted_event_cause": "unknown", + "source_tree": "86e2342d16acd101fe182793d20aef3f1f017633", + "provider": { + "run": 40512310499, + "attempt": 1, + "job": 122217071656, + "event": "push", + "branch": "perf/grapheme-cpu-hosted-r54-entry3", + "source": "4772f4f937c4f0f220be1630592f84bed3a591c8", + "status": "completed", + "conclusion": "success", + "labels": [ + "windows-2025" + ], + "started_at": "2026-10-27T13:28:22Z", + "completed_at": "2026-10-27T13:32:07Z", + "steps": [ + { + "number": 1, + "name": "Set up job", + "status": "completed", + "conclusion": "success", + "started_at": "2026-10-27T13:28:23Z", + "completed_at": "2026-10-27T13:28:24Z" + }, + { + "number": 2, + "name": "Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "started_at": "2026-10-27T13:28:24Z", + "completed_at": "2026-10-27T13:28:33Z" + }, + { + "number": 3, + "name": "Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "success", + "started_at": "2026-10-27T13:28:33Z", + "completed_at": "2026-10-27T13:28:33Z" + }, + { + "number": 4, + "name": "Install fixed CPU observer", + "status": "completed", + "conclusion": "success", + "started_at": "2026-10-27T13:28:33Z", + "completed_at": "2026-10-27T13:28:40Z" + }, + { + "number": 5, + "name": "Select fixed compiler", + "status": "completed", + "conclusion": "success", + "started_at": "2026-10-27T13:28:40Z", + "completed_at": "2026-10-27T13:28:49Z" + }, + { + "number": 6, + "name": "Verify build, accounting and publication boundaries", + "status": "completed", + "conclusion": "success", + "started_at": "2026-10-27T13:28:49Z", + "completed_at": "2026-10-27T13:29:04Z" + }, + { + "number": 7, + "name": "Build audited pair and execute one six-observation diagnosis", + "status": "completed", + "conclusion": "success", + "started_at": "2026-10-27T13:29:04Z", + "completed_at": "2026-10-27T13:32:02Z" + }, + { + "number": 8, + "name": "Prepare the synthetic artifact whitelist", + "status": "completed", + "conclusion": "success", + "started_at": "2026-10-27T13:32:02Z", + "completed_at": "2026-10-27T13:32:03Z" + }, + { + "number": 9, + "name": "Preserve complete or failed synthetic evidence", + "status": "completed", + "conclusion": "success", + "started_at": "2026-10-27T13:32:03Z", + "completed_at": "2026-10-27T13:32:04Z" + }, + { + "number": 17, + "name": "Post Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "success", + "started_at": "2026-10-27T13:32:04Z", + "completed_at": "2026-10-27T13:32:04Z" + }, + { + "number": 18, + "name": "Post Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "started_at": "2026-10-27T13:32:04Z", + "completed_at": "2026-10-27T13:32:06Z" + }, + { + "number": 19, + "name": "Complete job", + "status": "completed", + "conclusion": "success", + "started_at": "2026-10-27T13:32:06Z", + "completed_at": "2026-10-27T13:32:06Z" + } + ], + "artifact_id": 12738430576, + "artifact_digest": "sha256:263a3bf8e229b89f1e443b12e522daf69d30de403affa0dc49fe674c0dd8f241", + "image": "windows-2025-vs2026", + "image_version": "20261021.278.1" + }, + "previous_entries": [ + { + "source": "eed0ab7bae5fcc5d05a25cea5161dabc4f935878", + "run": 40509157581, + "job": 122206160085, + "attempt": 1, + "result": "preparation_test_path_boundary_failure", + "preparation_tests": 31, + "errors": 1, + "builds": 0, + "observations": 0, + "actual_temp_path_form": "not_recorded" + }, + { + "source": "c14adb9a7fa446476ad5c95c1f8c1b139ceb5ac4", + "branch": "perf/grapheme-cpu-hosted-r54-setup2", + "default_run": 40511533857, + "result": "no_cpu_workflow_run_listed", + "observations": 0, + "actual_push_file_list": "not_recorded" + } + ], + "local_tests": { + "measurement": { + "tests": 40, + "seconds": 19.436 + }, + "entry3_boundary": { + "tests": 4, + "seconds": 0.297 + }, + "hosted_preparation": { + "tests": 31, + "seconds": 14.042 + } + }, + "initial_ci": { + "40509376603": { + "jobs": [ + { + "id": 122206943124, + "name": "alacritty-headless (windows-2025, experiments/candidates/alacritty/target/release/termforge-alacr...", + "conclusion": "failure", + "steps": [ + { + "name": "Set up job", + "status": "completed", + "conclusion": "success", + "number": 1, + "started_at": "2026-10-27T13:08:09Z", + "completed_at": "2026-10-27T13:08:10Z" + }, + { + "name": "Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "number": 2, + "started_at": "2026-10-27T13:08:10Z", + "completed_at": "2026-10-27T13:08:16Z" + }, + { + "name": "Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "success", + "number": 3, + "started_at": "2026-10-27T13:08:16Z", + "completed_at": "2026-10-27T13:08:16Z" + }, + { + "name": "Install fixed semantic references", + "status": "completed", + "conclusion": "success", + "number": 4, + "started_at": "2026-10-27T13:08:16Z", + "completed_at": "2026-10-27T13:08:22Z" + }, + { + "name": "Install fixed CPU observer", + "status": "completed", + "conclusion": "success", + "number": 5, + "started_at": "2026-10-27T13:08:22Z", + "completed_at": "2026-10-27T13:08:25Z" + }, + { + "name": "Select fixed Rust toolchain", + "status": "completed", + "conclusion": "success", + "number": 6, + "started_at": "2026-10-27T13:08:25Z", + "completed_at": "2026-10-27T13:08:34Z" + }, + { + "name": "Build locked candidate", + "status": "completed", + "conclusion": "success", + "number": 7, + "started_at": "2026-10-27T13:08:34Z", + "completed_at": "2026-10-27T13:09:17Z" + }, + { + "name": "Test Rust projection", + "status": "completed", + "conclusion": "success", + "number": 8, + "started_at": "2026-10-27T13:09:17Z", + "completed_at": "2026-10-27T13:09:33Z" + }, + { + "name": "Test fixed upstream and compatibility patches", + "status": "completed", + "conclusion": "success", + "number": 9, + "started_at": "2026-10-27T13:09:33Z", + "completed_at": "2026-10-27T13:09:50Z" + }, + { + "name": "Build candidate measurement", + "status": "completed", + "conclusion": "success", + "number": 10, + "started_at": "2026-10-27T13:09:50Z", + "completed_at": "2026-10-27T13:09:51Z" + }, + { + "name": "Build candidate measurement without allocator wrapper", + "status": "completed", + "conclusion": "success", + "number": 11, + "started_at": "2026-10-27T13:09:51Z", + "completed_at": "2026-10-27T13:10:22Z" + }, + { + "name": "Configure native trace on Windows", + "status": "completed", + "conclusion": "success", + "number": 12, + "started_at": "2026-10-27T13:10:22Z", + "completed_at": "2026-10-27T13:10:33Z" + }, + { + "name": "Configure native trace on Unix", + "status": "completed", + "conclusion": "skipped", + "number": 13, + "started_at": "2026-10-27T13:10:33Z", + "completed_at": "2026-10-27T13:10:33Z" + }, + { + "name": "Build native trace", + "status": "completed", + "conclusion": "success", + "number": 14, + "started_at": "2026-10-27T13:10:33Z", + "completed_at": "2026-10-27T13:10:37Z" + }, + { + "name": "Build native measurement", + "status": "completed", + "conclusion": "success", + "number": 15, + "started_at": "2026-10-27T13:10:37Z", + "completed_at": "2026-10-27T13:10:41Z" + }, + { + "name": "Build and test candidate C++ adapter", + "status": "completed", + "conclusion": "success", + "number": 16, + "started_at": "2026-10-27T13:10:41Z", + "completed_at": "2026-10-27T13:10:49Z" + }, + { + "name": "Build and test candidate shell on Windows", + "status": "completed", + "conclusion": "success", + "number": 17, + "started_at": "2026-10-27T13:10:49Z", + "completed_at": "2026-10-27T13:11:35Z" + }, + { + "name": "Verify empty-title GUI and UTF-8 conversion on Windows", + "status": "completed", + "conclusion": "success", + "number": 18, + "started_at": "2026-10-27T13:11:35Z", + "completed_at": "2026-10-27T13:12:03Z" + }, + { + "name": "Build real application capture on Windows", + "status": "completed", + "conclusion": "success", + "number": 19, + "started_at": "2026-10-27T13:12:03Z", + "completed_at": "2026-10-27T13:12:07Z" + }, + { + "name": "Run headless integration checks", + "status": "completed", + "conclusion": "success", + "number": 20, + "started_at": "2026-10-27T13:12:07Z", + "completed_at": "2026-10-27T13:12:08Z" + }, + { + "name": "Test runner and failure gates", + "status": "completed", + "conclusion": "success", + "number": 21, + "started_at": "2026-10-27T13:12:08Z", + "completed_at": "2026-10-27T13:12:08Z" + }, + { + "name": "Compare common native traces", + "status": "completed", + "conclusion": "success", + "number": 22, + "started_at": "2026-10-27T13:12:08Z", + "completed_at": "2026-10-27T13:12:11Z" + }, + { + "name": "Test common comparison and failure gates", + "status": "completed", + "conclusion": "success", + "number": 23, + "started_at": "2026-10-27T13:12:11Z", + "completed_at": "2026-10-27T13:12:14Z" + }, + { + "name": "Compare extended capability traces", + "status": "completed", + "conclusion": "success", + "number": 24, + "started_at": "2026-10-27T13:12:14Z", + "completed_at": "2026-10-27T13:12:15Z" + }, + { + "name": "Test extended capabilities and unsupported gates", + "status": "completed", + "conclusion": "success", + "number": 25, + "started_at": "2026-10-27T13:12:15Z", + "completed_at": "2026-10-27T13:12:16Z" + }, + { + "name": "Compare real application traces on Windows", + "status": "completed", + "conclusion": "success", + "number": 26, + "started_at": "2026-10-27T13:12:16Z", + "completed_at": "2026-10-27T13:12:17Z" + }, + { + "name": "Test real application traces on Windows", + "status": "completed", + "conclusion": "success", + "number": 27, + "started_at": "2026-10-27T13:12:17Z", + "completed_at": "2026-10-27T13:12:29Z" + }, + { + "name": "Run bounded recovery fuzz", + "status": "completed", + "conclusion": "success", + "number": 28, + "started_at": "2026-10-27T13:12:29Z", + "completed_at": "2026-10-27T13:12:29Z" + }, + { + "name": "Test fuzz minimization and fixed regressions", + "status": "completed", + "conclusion": "success", + "number": 29, + "started_at": "2026-10-27T13:12:29Z", + "completed_at": "2026-10-27T13:12:31Z" + }, + { + "name": "Compare interleaved project costs", + "status": "completed", + "conclusion": "success", + "number": 30, + "started_at": "2026-10-27T13:12:31Z", + "completed_at": "2026-10-27T13:13:02Z" + }, + { + "name": "Compare interleaved interactive costs", + "status": "completed", + "conclusion": "success", + "number": 31, + "started_at": "2026-10-27T13:13:02Z", + "completed_at": "2026-10-27T13:13:42Z" + }, + { + "name": "Test measurement contracts", + "status": "completed", + "conclusion": "failure", + "number": 32, + "started_at": "2026-10-27T13:13:42Z", + "completed_at": "2026-10-27T13:14:15Z" + }, + { + "name": "Preserve synthetic candidate evidence", + "status": "completed", + "conclusion": "success", + "number": 33, + "started_at": "2026-10-27T13:14:15Z", + "completed_at": "2026-10-27T13:14:19Z" + }, + { + "name": "Post Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "skipped", + "number": 65, + "started_at": "2026-10-27T13:14:19Z", + "completed_at": "2026-10-27T13:14:19Z" + }, + { + "name": "Post Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "number": 66, + "started_at": "2026-10-27T13:14:19Z", + "completed_at": "2026-10-27T13:14:22Z" + }, + { + "name": "Complete job", + "status": "completed", + "conclusion": "success", + "number": 67, + "started_at": "2026-10-27T13:14:22Z", + "completed_at": "2026-10-27T13:14:22Z" + } + ], + "log_evidence": [ + "2026-10-27T13:12:08.8322257Z Ran 6 tests in 0.149s", + "2026-10-27T13:12:14.1163493Z Ran 4 tests in 2.122s", + "2026-10-27T13:12:16.1916158Z Ran 4 tests in 0.522s", + "2026-10-27T13:12:28.9034935Z Ran 8 tests in 10.796s", + "2026-10-27T13:12:30.9126353Z Ran 4 tests in 0.716s", + "2026-10-27T13:14:15.3632402Z ERROR: test_publication_keeps_failed_streams_and_separates_the_six_observation_scope (test_r54_cpu_hosted.CpuHostedBoundaryTests.test_publication_keeps_failed_streams_and_separates_the_six_observation_scope)", + "2026-10-27T13:14:15.3646222Z ValueError: publication paths must stay in workspace local", + "2026-10-27T13:14:15.3646942Z Ran 49 tests in 31.869s", + "2026-10-27T13:14:15.3647151Z FAILED (errors=1)" + ] + }, + { + "id": 122206943421, + "name": "alacritty-headless (ubuntu-24.04, experiments/candidates/alacritty/target/release/termforge-alacr...", + "conclusion": "success", + "steps": [ + { + "name": "Set up job", + "status": "completed", + "conclusion": "success", + "number": 1, + "started_at": "2026-10-27T13:08:10Z", + "completed_at": "2026-10-27T13:08:11Z" + }, + { + "name": "Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "number": 2, + "started_at": "2026-10-27T13:08:11Z", + "completed_at": "2026-10-27T13:08:13Z" + }, + { + "name": "Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "success", + "number": 3, + "started_at": "2026-10-27T13:08:13Z", + "completed_at": "2026-10-27T13:08:13Z" + }, + { + "name": "Install fixed semantic references", + "status": "completed", + "conclusion": "success", + "number": 4, + "started_at": "2026-10-27T13:08:13Z", + "completed_at": "2026-10-27T13:08:14Z" + }, + { + "name": "Install fixed CPU observer", + "status": "completed", + "conclusion": "success", + "number": 5, + "started_at": "2026-10-27T13:08:14Z", + "completed_at": "2026-10-27T13:08:15Z" + }, + { + "name": "Select fixed Rust toolchain", + "status": "completed", + "conclusion": "success", + "number": 6, + "started_at": "2026-10-27T13:08:15Z", + "completed_at": "2026-10-27T13:08:22Z" + }, + { + "name": "Build locked candidate", + "status": "completed", + "conclusion": "success", + "number": 7, + "started_at": "2026-10-27T13:08:22Z", + "completed_at": "2026-10-27T13:08:43Z" + }, + { + "name": "Test Rust projection", + "status": "completed", + "conclusion": "success", + "number": 8, + "started_at": "2026-10-27T13:08:43Z", + "completed_at": "2026-10-27T13:08:52Z" + }, + { + "name": "Test fixed upstream and compatibility patches", + "status": "completed", + "conclusion": "success", + "number": 9, + "started_at": "2026-10-27T13:08:52Z", + "completed_at": "2026-10-27T13:09:03Z" + }, + { + "name": "Build candidate measurement", + "status": "completed", + "conclusion": "success", + "number": 10, + "started_at": "2026-10-27T13:09:03Z", + "completed_at": "2026-10-27T13:09:03Z" + }, + { + "name": "Build candidate measurement without allocator wrapper", + "status": "completed", + "conclusion": "success", + "number": 11, + "started_at": "2026-10-27T13:09:03Z", + "completed_at": "2026-10-27T13:09:21Z" + }, + { + "name": "Configure native trace on Windows", + "status": "completed", + "conclusion": "skipped", + "number": 12, + "started_at": "2026-10-27T13:09:21Z", + "completed_at": "2026-10-27T13:09:21Z" + }, + { + "name": "Configure native trace on Unix", + "status": "completed", + "conclusion": "success", + "number": 13, + "started_at": "2026-10-27T13:09:21Z", + "completed_at": "2026-10-27T13:09:23Z" + }, + { + "name": "Build native trace", + "status": "completed", + "conclusion": "success", + "number": 14, + "started_at": "2026-10-27T13:09:23Z", + "completed_at": "2026-10-27T13:09:24Z" + }, + { + "name": "Build native measurement", + "status": "completed", + "conclusion": "success", + "number": 15, + "started_at": "2026-10-27T13:09:24Z", + "completed_at": "2026-10-27T13:09:27Z" + }, + { + "name": "Build and test candidate C++ adapter", + "status": "completed", + "conclusion": "success", + "number": 16, + "started_at": "2026-10-27T13:09:27Z", + "completed_at": "2026-10-27T13:09:34Z" + }, + { + "name": "Build and test candidate shell on Windows", + "status": "completed", + "conclusion": "skipped", + "number": 17, + "started_at": "2026-10-27T13:09:34Z", + "completed_at": "2026-10-27T13:09:34Z" + }, + { + "name": "Verify empty-title GUI and UTF-8 conversion on Windows", + "status": "completed", + "conclusion": "skipped", + "number": 18, + "started_at": "2026-10-27T13:09:34Z", + "completed_at": "2026-10-27T13:09:34Z" + }, + { + "name": "Build real application capture on Windows", + "status": "completed", + "conclusion": "skipped", + "number": 19, + "started_at": "2026-10-27T13:09:34Z", + "completed_at": "2026-10-27T13:09:34Z" + }, + { + "name": "Run headless integration checks", + "status": "completed", + "conclusion": "success", + "number": 20, + "started_at": "2026-10-27T13:09:34Z", + "completed_at": "2026-10-27T13:09:34Z" + }, + { + "name": "Test runner and failure gates", + "status": "completed", + "conclusion": "success", + "number": 21, + "started_at": "2026-10-27T13:09:34Z", + "completed_at": "2026-10-27T13:09:34Z" + }, + { + "name": "Compare common native traces", + "status": "completed", + "conclusion": "success", + "number": 22, + "started_at": "2026-10-27T13:09:34Z", + "completed_at": "2026-10-27T13:09:35Z" + }, + { + "name": "Test common comparison and failure gates", + "status": "completed", + "conclusion": "success", + "number": 23, + "started_at": "2026-10-27T13:09:35Z", + "completed_at": "2026-10-27T13:09:36Z" + }, + { + "name": "Compare extended capability traces", + "status": "completed", + "conclusion": "success", + "number": 24, + "started_at": "2026-10-27T13:09:36Z", + "completed_at": "2026-10-27T13:09:36Z" + }, + { + "name": "Test extended capabilities and unsupported gates", + "status": "completed", + "conclusion": "success", + "number": 25, + "started_at": "2026-10-27T13:09:36Z", + "completed_at": "2026-10-27T13:09:37Z" + }, + { + "name": "Compare real application traces on Windows", + "status": "completed", + "conclusion": "skipped", + "number": 26, + "started_at": "2026-10-27T13:09:37Z", + "completed_at": "2026-10-27T13:09:37Z" + }, + { + "name": "Test real application traces on Windows", + "status": "completed", + "conclusion": "skipped", + "number": 27, + "started_at": "2026-10-27T13:09:37Z", + "completed_at": "2026-10-27T13:09:37Z" + }, + { + "name": "Run bounded recovery fuzz", + "status": "completed", + "conclusion": "success", + "number": 28, + "started_at": "2026-10-27T13:09:37Z", + "completed_at": "2026-10-27T13:09:37Z" + }, + { + "name": "Test fuzz minimization and fixed regressions", + "status": "completed", + "conclusion": "success", + "number": 29, + "started_at": "2026-10-27T13:09:37Z", + "completed_at": "2026-10-27T13:09:37Z" + }, + { + "name": "Compare interleaved project costs", + "status": "completed", + "conclusion": "success", + "number": 30, + "started_at": "2026-10-27T13:09:37Z", + "completed_at": "2026-10-27T13:10:06Z" + }, + { + "name": "Compare interleaved interactive costs", + "status": "completed", + "conclusion": "success", + "number": 31, + "started_at": "2026-10-27T13:10:06Z", + "completed_at": "2026-10-27T13:10:45Z" + }, + { + "name": "Test measurement contracts", + "status": "completed", + "conclusion": "success", + "number": 32, + "started_at": "2026-10-27T13:10:45Z", + "completed_at": "2026-10-27T13:11:11Z" + }, + { + "name": "Preserve synthetic candidate evidence", + "status": "completed", + "conclusion": "success", + "number": 33, + "started_at": "2026-10-27T13:11:11Z", + "completed_at": "2026-10-27T13:11:14Z" + }, + { + "name": "Post Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "success", + "number": 65, + "started_at": "2026-10-27T13:11:14Z", + "completed_at": "2026-10-27T13:11:14Z" + }, + { + "name": "Post Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "number": 66, + "started_at": "2026-10-27T13:11:14Z", + "completed_at": "2026-10-27T13:11:15Z" + }, + { + "name": "Complete job", + "status": "completed", + "conclusion": "success", + "number": 67, + "started_at": "2026-10-27T13:11:15Z", + "completed_at": "2026-10-27T13:11:15Z" + } + ], + "log_evidence": [] + } + ] + }, + "40509377108": { + "jobs": [ + { + "id": 122206924548, + "name": "regression (windows-2025, build/bin/Release)", + "conclusion": "failure", + "steps": [ + { + "name": "Set up job", + "status": "completed", + "conclusion": "success", + "number": 1, + "started_at": "2026-10-27T13:08:07Z", + "completed_at": "2026-10-27T13:08:08Z" + }, + { + "name": "Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "number": 2, + "started_at": "2026-10-27T13:08:08Z", + "completed_at": "2026-10-27T13:08:13Z" + }, + { + "name": "Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "success", + "number": 3, + "started_at": "2026-10-27T13:08:13Z", + "completed_at": "2026-10-27T13:08:13Z" + }, + { + "name": "Install test dependencies", + "status": "completed", + "conclusion": "success", + "number": 4, + "started_at": "2026-10-27T13:08:13Z", + "completed_at": "2026-10-27T13:08:20Z" + }, + { + "name": "Configure", + "status": "completed", + "conclusion": "success", + "number": 5, + "started_at": "2026-10-27T13:08:20Z", + "completed_at": "2026-10-27T13:08:35Z" + }, + { + "name": "Build", + "status": "completed", + "conclusion": "success", + "number": 6, + "started_at": "2026-10-27T13:08:35Z", + "completed_at": "2026-10-27T13:09:33Z" + }, + { + "name": "Verify shell preparation guards and oracles", + "status": "completed", + "conclusion": "success", + "number": 7, + "started_at": "2026-10-27T13:09:33Z", + "completed_at": "2026-10-27T13:09:34Z" + }, + { + "name": "Prepare hosted Windows shell prerequisites", + "status": "completed", + "conclusion": "success", + "number": 8, + "started_at": "2026-10-27T13:09:34Z", + "completed_at": "2026-10-27T13:10:14Z" + }, + { + "name": "Preserve sanitized shell preparation result", + "status": "completed", + "conclusion": "success", + "number": 9, + "started_at": "2026-10-27T13:10:14Z", + "completed_at": "2026-10-27T13:10:16Z" + }, + { + "name": "Test", + "status": "completed", + "conclusion": "failure", + "number": 10, + "started_at": "2026-10-27T13:10:16Z", + "completed_at": "2026-10-27T13:14:29Z" + }, + { + "name": "Preserve clipboard and window integration evidence", + "status": "completed", + "conclusion": "success", + "number": 11, + "started_at": "2026-10-27T13:14:29Z", + "completed_at": "2026-10-27T13:14:34Z" + }, + { + "name": "Full ASCII state replay", + "status": "completed", + "conclusion": "skipped", + "number": 12, + "started_at": "2026-10-27T13:14:34Z", + "completed_at": "2026-10-27T13:14:34Z" + }, + { + "name": "Full Unicode state replay", + "status": "completed", + "conclusion": "skipped", + "number": 13, + "started_at": "2026-10-27T13:14:34Z", + "completed_at": "2026-10-27T13:14:34Z" + }, + { + "name": "Preserve synthetic failure evidence", + "status": "completed", + "conclusion": "success", + "number": 14, + "started_at": "2026-10-27T13:14:34Z", + "completed_at": "2026-10-27T13:14:39Z" + }, + { + "name": "Post Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "skipped", + "number": 27, + "started_at": "2026-10-27T13:14:39Z", + "completed_at": "2026-10-27T13:14:39Z" + }, + { + "name": "Post Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "number": 28, + "started_at": "2026-10-27T13:14:39Z", + "completed_at": "2026-10-27T13:14:41Z" + }, + { + "name": "Complete job", + "status": "completed", + "conclusion": "success", + "number": 29, + "started_at": "2026-10-27T13:14:41Z", + "completed_at": "2026-10-27T13:14:41Z" + } + ], + "log_evidence": [ + "2026-10-27T13:09:34.6075054Z Ran 23 tests in 0.141s", + "2026-10-27T13:10:42.1081064Z ERROR: test_publication_keeps_failed_streams_and_separates_the_six_observation_scope (experiments.measure.test_r54_cpu_hosted.CpuHostedBoundaryTests.test_publication_keeps_failed_streams_and_separates_the_six_observation_scope)", + "2026-10-27T13:10:42.1091660Z ValueError: publication paths must stay in workspace local", + "2026-10-27T13:10:42.1092267Z Ran 40 tests in 14.741s", + "2026-10-27T13:10:42.1092447Z FAILED (errors=1)", + "2026-10-27T13:14:29.5651977Z 98% tests passed, 1 tests failed out of 46" + ] + }, + { + "id": 122206924940, + "name": "regression (ubuntu-24.04, build/bin)", + "conclusion": "success", + "steps": [ + { + "name": "Set up job", + "status": "completed", + "conclusion": "success", + "number": 1, + "started_at": "2026-10-27T13:08:07Z", + "completed_at": "2026-10-27T13:08:09Z" + }, + { + "name": "Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "number": 2, + "started_at": "2026-10-27T13:08:09Z", + "completed_at": "2026-10-27T13:08:11Z" + }, + { + "name": "Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "success", + "number": 3, + "started_at": "2026-10-27T13:08:11Z", + "completed_at": "2026-10-27T13:08:11Z" + }, + { + "name": "Install test dependencies", + "status": "completed", + "conclusion": "success", + "number": 4, + "started_at": "2026-10-27T13:08:11Z", + "completed_at": "2026-10-27T13:08:13Z" + }, + { + "name": "Configure", + "status": "completed", + "conclusion": "success", + "number": 5, + "started_at": "2026-10-27T13:08:13Z", + "completed_at": "2026-10-27T13:08:14Z" + }, + { + "name": "Build", + "status": "completed", + "conclusion": "success", + "number": 6, + "started_at": "2026-10-27T13:08:14Z", + "completed_at": "2026-10-27T13:08:27Z" + }, + { + "name": "Verify shell preparation guards and oracles", + "status": "completed", + "conclusion": "success", + "number": 7, + "started_at": "2026-10-27T13:08:27Z", + "completed_at": "2026-10-27T13:08:28Z" + }, + { + "name": "Prepare hosted Windows shell prerequisites", + "status": "completed", + "conclusion": "skipped", + "number": 8, + "started_at": "2026-10-27T13:08:28Z", + "completed_at": "2026-10-27T13:08:28Z" + }, + { + "name": "Preserve sanitized shell preparation result", + "status": "completed", + "conclusion": "skipped", + "number": 9, + "started_at": "2026-10-27T13:08:28Z", + "completed_at": "2026-10-27T13:08:28Z" + }, + { + "name": "Test", + "status": "completed", + "conclusion": "success", + "number": 10, + "started_at": "2026-10-27T13:08:28Z", + "completed_at": "2026-10-27T13:08:50Z" + }, + { + "name": "Preserve clipboard and window integration evidence", + "status": "completed", + "conclusion": "skipped", + "number": 11, + "started_at": "2026-10-27T13:08:50Z", + "completed_at": "2026-10-27T13:08:50Z" + }, + { + "name": "Full ASCII state replay", + "status": "completed", + "conclusion": "success", + "number": 12, + "started_at": "2026-10-27T13:08:50Z", + "completed_at": "2026-10-27T13:08:50Z" + }, + { + "name": "Full Unicode state replay", + "status": "completed", + "conclusion": "success", + "number": 13, + "started_at": "2026-10-27T13:08:50Z", + "completed_at": "2026-10-27T13:08:50Z" + }, + { + "name": "Preserve synthetic failure evidence", + "status": "completed", + "conclusion": "skipped", + "number": 14, + "started_at": "2026-10-27T13:08:50Z", + "completed_at": "2026-10-27T13:08:50Z" + }, + { + "name": "Post Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "success", + "number": 27, + "started_at": "2026-10-27T13:08:50Z", + "completed_at": "2026-10-27T13:08:51Z" + }, + { + "name": "Post Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "number": 28, + "started_at": "2026-10-27T13:08:51Z", + "completed_at": "2026-10-27T13:08:51Z" + }, + { + "name": "Complete job", + "status": "completed", + "conclusion": "success", + "number": 29, + "started_at": "2026-10-27T13:08:51Z", + "completed_at": "2026-10-27T13:08:51Z" + } + ], + "log_evidence": [] + } + ] + }, + "40509157544": { + "jobs": [ + { + "id": 122206159254, + "name": "alacritty-headless (windows-2025, experiments/candidates/alacritty/target/release/termforge-alacr...", + "conclusion": "failure", + "steps": [ + { + "name": "Set up job", + "status": "completed", + "conclusion": "success", + "number": 1, + "started_at": "2026-10-27T13:06:32Z", + "completed_at": "2026-10-27T13:06:33Z" + }, + { + "name": "Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "number": 2, + "started_at": "2026-10-27T13:06:33Z", + "completed_at": "2026-10-27T13:06:39Z" + }, + { + "name": "Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "success", + "number": 3, + "started_at": "2026-10-27T13:06:39Z", + "completed_at": "2026-10-27T13:06:39Z" + }, + { + "name": "Install fixed semantic references", + "status": "completed", + "conclusion": "success", + "number": 4, + "started_at": "2026-10-27T13:06:39Z", + "completed_at": "2026-10-27T13:06:45Z" + }, + { + "name": "Install fixed CPU observer", + "status": "completed", + "conclusion": "success", + "number": 5, + "started_at": "2026-10-27T13:06:45Z", + "completed_at": "2026-10-27T13:06:47Z" + }, + { + "name": "Select fixed Rust toolchain", + "status": "completed", + "conclusion": "success", + "number": 6, + "started_at": "2026-10-27T13:06:47Z", + "completed_at": "2026-10-27T13:06:57Z" + }, + { + "name": "Build locked candidate", + "status": "completed", + "conclusion": "success", + "number": 7, + "started_at": "2026-10-27T13:06:57Z", + "completed_at": "2026-10-27T13:07:28Z" + }, + { + "name": "Test Rust projection", + "status": "completed", + "conclusion": "success", + "number": 8, + "started_at": "2026-10-27T13:07:28Z", + "completed_at": "2026-10-27T13:07:41Z" + }, + { + "name": "Test fixed upstream and compatibility patches", + "status": "completed", + "conclusion": "success", + "number": 9, + "started_at": "2026-10-27T13:07:41Z", + "completed_at": "2026-10-27T13:07:53Z" + }, + { + "name": "Build candidate measurement", + "status": "completed", + "conclusion": "success", + "number": 10, + "started_at": "2026-10-27T13:07:53Z", + "completed_at": "2026-10-27T13:07:54Z" + }, + { + "name": "Build candidate measurement without allocator wrapper", + "status": "completed", + "conclusion": "success", + "number": 11, + "started_at": "2026-10-27T13:07:54Z", + "completed_at": "2026-10-27T13:08:15Z" + }, + { + "name": "Configure native trace on Windows", + "status": "completed", + "conclusion": "success", + "number": 12, + "started_at": "2026-10-27T13:08:15Z", + "completed_at": "2026-10-27T13:08:25Z" + }, + { + "name": "Configure native trace on Unix", + "status": "completed", + "conclusion": "skipped", + "number": 13, + "started_at": "2026-10-27T13:08:25Z", + "completed_at": "2026-10-27T13:08:25Z" + }, + { + "name": "Build native trace", + "status": "completed", + "conclusion": "success", + "number": 14, + "started_at": "2026-10-27T13:08:25Z", + "completed_at": "2026-10-27T13:08:29Z" + }, + { + "name": "Build native measurement", + "status": "completed", + "conclusion": "success", + "number": 15, + "started_at": "2026-10-27T13:08:29Z", + "completed_at": "2026-10-27T13:08:32Z" + }, + { + "name": "Build and test candidate C++ adapter", + "status": "completed", + "conclusion": "success", + "number": 16, + "started_at": "2026-10-27T13:08:32Z", + "completed_at": "2026-10-27T13:08:39Z" + }, + { + "name": "Build and test candidate shell on Windows", + "status": "completed", + "conclusion": "success", + "number": 17, + "started_at": "2026-10-27T13:08:39Z", + "completed_at": "2026-10-27T13:09:22Z" + }, + { + "name": "Verify empty-title GUI and UTF-8 conversion on Windows", + "status": "completed", + "conclusion": "success", + "number": 18, + "started_at": "2026-10-27T13:09:22Z", + "completed_at": "2026-10-27T13:09:43Z" + }, + { + "name": "Build real application capture on Windows", + "status": "completed", + "conclusion": "success", + "number": 19, + "started_at": "2026-10-27T13:09:43Z", + "completed_at": "2026-10-27T13:09:46Z" + }, + { + "name": "Run headless integration checks", + "status": "completed", + "conclusion": "success", + "number": 20, + "started_at": "2026-10-27T13:09:46Z", + "completed_at": "2026-10-27T13:09:46Z" + }, + { + "name": "Test runner and failure gates", + "status": "completed", + "conclusion": "success", + "number": 21, + "started_at": "2026-10-27T13:09:46Z", + "completed_at": "2026-10-27T13:09:47Z" + }, + { + "name": "Compare common native traces", + "status": "completed", + "conclusion": "success", + "number": 22, + "started_at": "2026-10-27T13:09:47Z", + "completed_at": "2026-10-27T13:09:49Z" + }, + { + "name": "Test common comparison and failure gates", + "status": "completed", + "conclusion": "success", + "number": 23, + "started_at": "2026-10-27T13:09:49Z", + "completed_at": "2026-10-27T13:09:51Z" + }, + { + "name": "Compare extended capability traces", + "status": "completed", + "conclusion": "success", + "number": 24, + "started_at": "2026-10-27T13:09:51Z", + "completed_at": "2026-10-27T13:09:52Z" + }, + { + "name": "Test extended capabilities and unsupported gates", + "status": "completed", + "conclusion": "success", + "number": 25, + "started_at": "2026-10-27T13:09:52Z", + "completed_at": "2026-10-27T13:09:52Z" + }, + { + "name": "Compare real application traces on Windows", + "status": "completed", + "conclusion": "success", + "number": 26, + "started_at": "2026-10-27T13:09:52Z", + "completed_at": "2026-10-27T13:09:53Z" + }, + { + "name": "Test real application traces on Windows", + "status": "completed", + "conclusion": "success", + "number": 27, + "started_at": "2026-10-27T13:09:53Z", + "completed_at": "2026-10-27T13:10:05Z" + }, + { + "name": "Run bounded recovery fuzz", + "status": "completed", + "conclusion": "success", + "number": 28, + "started_at": "2026-10-27T13:10:05Z", + "completed_at": "2026-10-27T13:10:05Z" + }, + { + "name": "Test fuzz minimization and fixed regressions", + "status": "completed", + "conclusion": "success", + "number": 29, + "started_at": "2026-10-27T13:10:05Z", + "completed_at": "2026-10-27T13:10:06Z" + }, + { + "name": "Compare interleaved project costs", + "status": "completed", + "conclusion": "success", + "number": 30, + "started_at": "2026-10-27T13:10:06Z", + "completed_at": "2026-10-27T13:10:36Z" + }, + { + "name": "Compare interleaved interactive costs", + "status": "completed", + "conclusion": "success", + "number": 31, + "started_at": "2026-10-27T13:10:36Z", + "completed_at": "2026-10-27T13:11:16Z" + }, + { + "name": "Test measurement contracts", + "status": "completed", + "conclusion": "failure", + "number": 32, + "started_at": "2026-10-27T13:11:16Z", + "completed_at": "2026-10-27T13:11:44Z" + }, + { + "name": "Preserve synthetic candidate evidence", + "status": "completed", + "conclusion": "success", + "number": 33, + "started_at": "2026-10-27T13:11:44Z", + "completed_at": "2026-10-27T13:11:49Z" + }, + { + "name": "Post Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "skipped", + "number": 65, + "started_at": "2026-10-27T13:11:49Z", + "completed_at": "2026-10-27T13:11:49Z" + }, + { + "name": "Post Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "number": 66, + "started_at": "2026-10-27T13:11:49Z", + "completed_at": "2026-10-27T13:11:50Z" + }, + { + "name": "Complete job", + "status": "completed", + "conclusion": "success", + "number": 67, + "started_at": "2026-10-27T13:11:50Z", + "completed_at": "2026-10-27T13:11:50Z" + } + ], + "log_evidence": [ + "2026-10-27T13:09:47.1510883Z Ran 6 tests in 0.112s", + "2026-10-27T13:09:51.1475615Z Ran 4 tests in 1.624s", + "2026-10-27T13:09:52.7038066Z Ran 4 tests in 0.401s", + "2026-10-27T13:10:04.9281496Z Ran 8 tests in 10.681s", + "2026-10-27T13:10:06.4638361Z Ran 4 tests in 0.571s", + "2026-10-27T13:11:44.7874775Z ERROR: test_publication_keeps_failed_streams_and_separates_the_six_observation_scope (test_r54_cpu_hosted.CpuHostedBoundaryTests.test_publication_keeps_failed_streams_and_separates_the_six_observation_scope)", + "2026-10-27T13:11:44.7884371Z ValueError: publication paths must stay in workspace local", + "2026-10-27T13:11:44.7884990Z Ran 49 tests in 28.223s", + "2026-10-27T13:11:44.7885202Z FAILED (errors=1)" + ] + }, + { + "id": 122206159638, + "name": "alacritty-headless (ubuntu-24.04, experiments/candidates/alacritty/target/release/termforge-alacr...", + "conclusion": "success", + "steps": [ + { + "name": "Set up job", + "status": "completed", + "conclusion": "success", + "number": 1, + "started_at": "2026-10-27T13:06:33Z", + "completed_at": "2026-10-27T13:06:34Z" + }, + { + "name": "Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "number": 2, + "started_at": "2026-10-27T13:06:34Z", + "completed_at": "2026-10-27T13:06:36Z" + }, + { + "name": "Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "success", + "number": 3, + "started_at": "2026-10-27T13:06:36Z", + "completed_at": "2026-10-27T13:06:36Z" + }, + { + "name": "Install fixed semantic references", + "status": "completed", + "conclusion": "success", + "number": 4, + "started_at": "2026-10-27T13:06:36Z", + "completed_at": "2026-10-27T13:06:37Z" + }, + { + "name": "Install fixed CPU observer", + "status": "completed", + "conclusion": "success", + "number": 5, + "started_at": "2026-10-27T13:06:37Z", + "completed_at": "2026-10-27T13:06:38Z" + }, + { + "name": "Select fixed Rust toolchain", + "status": "completed", + "conclusion": "success", + "number": 6, + "started_at": "2026-10-27T13:06:38Z", + "completed_at": "2026-10-27T13:06:46Z" + }, + { + "name": "Build locked candidate", + "status": "completed", + "conclusion": "success", + "number": 7, + "started_at": "2026-10-27T13:06:46Z", + "completed_at": "2026-10-27T13:07:08Z" + }, + { + "name": "Test Rust projection", + "status": "completed", + "conclusion": "success", + "number": 8, + "started_at": "2026-10-27T13:07:08Z", + "completed_at": "2026-10-27T13:07:18Z" + }, + { + "name": "Test fixed upstream and compatibility patches", + "status": "completed", + "conclusion": "success", + "number": 9, + "started_at": "2026-10-27T13:07:18Z", + "completed_at": "2026-10-27T13:07:30Z" + }, + { + "name": "Build candidate measurement", + "status": "completed", + "conclusion": "success", + "number": 10, + "started_at": "2026-10-27T13:07:30Z", + "completed_at": "2026-10-27T13:07:30Z" + }, + { + "name": "Build candidate measurement without allocator wrapper", + "status": "completed", + "conclusion": "success", + "number": 11, + "started_at": "2026-10-27T13:07:30Z", + "completed_at": "2026-10-27T13:07:48Z" + }, + { + "name": "Configure native trace on Windows", + "status": "completed", + "conclusion": "skipped", + "number": 12, + "started_at": "2026-10-27T13:07:48Z", + "completed_at": "2026-10-27T13:07:48Z" + }, + { + "name": "Configure native trace on Unix", + "status": "completed", + "conclusion": "success", + "number": 13, + "started_at": "2026-10-27T13:07:48Z", + "completed_at": "2026-10-27T13:07:51Z" + }, + { + "name": "Build native trace", + "status": "completed", + "conclusion": "success", + "number": 14, + "started_at": "2026-10-27T13:07:51Z", + "completed_at": "2026-10-27T13:07:54Z" + }, + { + "name": "Build native measurement", + "status": "completed", + "conclusion": "success", + "number": 15, + "started_at": "2026-10-27T13:07:54Z", + "completed_at": "2026-10-27T13:07:56Z" + }, + { + "name": "Build and test candidate C++ adapter", + "status": "completed", + "conclusion": "success", + "number": 16, + "started_at": "2026-10-27T13:07:56Z", + "completed_at": "2026-10-27T13:08:03Z" + }, + { + "name": "Build and test candidate shell on Windows", + "status": "completed", + "conclusion": "skipped", + "number": 17, + "started_at": "2026-10-27T13:08:03Z", + "completed_at": "2026-10-27T13:08:03Z" + }, + { + "name": "Verify empty-title GUI and UTF-8 conversion on Windows", + "status": "completed", + "conclusion": "skipped", + "number": 18, + "started_at": "2026-10-27T13:08:03Z", + "completed_at": "2026-10-27T13:08:03Z" + }, + { + "name": "Build real application capture on Windows", + "status": "completed", + "conclusion": "skipped", + "number": 19, + "started_at": "2026-10-27T13:08:03Z", + "completed_at": "2026-10-27T13:08:03Z" + }, + { + "name": "Run headless integration checks", + "status": "completed", + "conclusion": "success", + "number": 20, + "started_at": "2026-10-27T13:08:03Z", + "completed_at": "2026-10-27T13:08:03Z" + }, + { + "name": "Test runner and failure gates", + "status": "completed", + "conclusion": "success", + "number": 21, + "started_at": "2026-10-27T13:08:03Z", + "completed_at": "2026-10-27T13:08:04Z" + }, + { + "name": "Compare common native traces", + "status": "completed", + "conclusion": "success", + "number": 22, + "started_at": "2026-10-27T13:08:04Z", + "completed_at": "2026-10-27T13:08:04Z" + }, + { + "name": "Test common comparison and failure gates", + "status": "completed", + "conclusion": "success", + "number": 23, + "started_at": "2026-10-27T13:08:04Z", + "completed_at": "2026-10-27T13:08:05Z" + }, + { + "name": "Compare extended capability traces", + "status": "completed", + "conclusion": "success", + "number": 24, + "started_at": "2026-10-27T13:08:05Z", + "completed_at": "2026-10-27T13:08:06Z" + }, + { + "name": "Test extended capabilities and unsupported gates", + "status": "completed", + "conclusion": "success", + "number": 25, + "started_at": "2026-10-27T13:08:06Z", + "completed_at": "2026-10-27T13:08:06Z" + }, + { + "name": "Compare real application traces on Windows", + "status": "completed", + "conclusion": "skipped", + "number": 26, + "started_at": "2026-10-27T13:08:06Z", + "completed_at": "2026-10-27T13:08:06Z" + }, + { + "name": "Test real application traces on Windows", + "status": "completed", + "conclusion": "skipped", + "number": 27, + "started_at": "2026-10-27T13:08:06Z", + "completed_at": "2026-10-27T13:08:06Z" + }, + { + "name": "Run bounded recovery fuzz", + "status": "completed", + "conclusion": "success", + "number": 28, + "started_at": "2026-10-27T13:08:06Z", + "completed_at": "2026-10-27T13:08:06Z" + }, + { + "name": "Test fuzz minimization and fixed regressions", + "status": "completed", + "conclusion": "success", + "number": 29, + "started_at": "2026-10-27T13:08:06Z", + "completed_at": "2026-10-27T13:08:06Z" + }, + { + "name": "Compare interleaved project costs", + "status": "completed", + "conclusion": "success", + "number": 30, + "started_at": "2026-10-27T13:08:06Z", + "completed_at": "2026-10-27T13:08:36Z" + }, + { + "name": "Compare interleaved interactive costs", + "status": "completed", + "conclusion": "success", + "number": 31, + "started_at": "2026-10-27T13:08:36Z", + "completed_at": "2026-10-27T13:09:16Z" + }, + { + "name": "Test measurement contracts", + "status": "completed", + "conclusion": "success", + "number": 32, + "started_at": "2026-10-27T13:09:16Z", + "completed_at": "2026-10-27T13:09:42Z" + }, + { + "name": "Preserve synthetic candidate evidence", + "status": "completed", + "conclusion": "success", + "number": 33, + "started_at": "2026-10-27T13:09:42Z", + "completed_at": "2026-10-27T13:09:45Z" + }, + { + "name": "Post Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "success", + "number": 65, + "started_at": "2026-10-27T13:09:45Z", + "completed_at": "2026-10-27T13:09:45Z" + }, + { + "name": "Post Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "number": 66, + "started_at": "2026-10-27T13:09:45Z", + "completed_at": "2026-10-27T13:09:45Z" + }, + { + "name": "Complete job", + "status": "completed", + "conclusion": "success", + "number": 67, + "started_at": "2026-10-27T13:09:45Z", + "completed_at": "2026-10-27T13:09:45Z" + } + ], + "log_evidence": [] + } + ] + }, + "40509157365": { + "jobs": [ + { + "id": 122206159312, + "name": "regression (ubuntu-24.04, build/bin)", + "conclusion": "success", + "steps": [ + { + "name": "Set up job", + "status": "completed", + "conclusion": "success", + "number": 1, + "started_at": "2026-10-27T13:06:32Z", + "completed_at": "2026-10-27T13:06:33Z" + }, + { + "name": "Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "number": 2, + "started_at": "2026-10-27T13:06:33Z", + "completed_at": "2026-10-27T13:06:34Z" + }, + { + "name": "Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "success", + "number": 3, + "started_at": "2026-10-27T13:06:34Z", + "completed_at": "2026-10-27T13:06:35Z" + }, + { + "name": "Install test dependencies", + "status": "completed", + "conclusion": "success", + "number": 4, + "started_at": "2026-10-27T13:06:35Z", + "completed_at": "2026-10-27T13:06:37Z" + }, + { + "name": "Configure", + "status": "completed", + "conclusion": "success", + "number": 5, + "started_at": "2026-10-27T13:06:37Z", + "completed_at": "2026-10-27T13:06:44Z" + }, + { + "name": "Build", + "status": "completed", + "conclusion": "success", + "number": 6, + "started_at": "2026-10-27T13:06:44Z", + "completed_at": "2026-10-27T13:06:53Z" + }, + { + "name": "Verify shell preparation guards and oracles", + "status": "completed", + "conclusion": "success", + "number": 7, + "started_at": "2026-10-27T13:06:53Z", + "completed_at": "2026-10-27T13:06:54Z" + }, + { + "name": "Prepare hosted Windows shell prerequisites", + "status": "completed", + "conclusion": "skipped", + "number": 8, + "started_at": "2026-10-27T13:06:54Z", + "completed_at": "2026-10-27T13:06:54Z" + }, + { + "name": "Preserve sanitized shell preparation result", + "status": "completed", + "conclusion": "skipped", + "number": 9, + "started_at": "2026-10-27T13:06:54Z", + "completed_at": "2026-10-27T13:06:54Z" + }, + { + "name": "Test", + "status": "completed", + "conclusion": "success", + "number": 10, + "started_at": "2026-10-27T13:06:54Z", + "completed_at": "2026-10-27T13:07:10Z" + }, + { + "name": "Preserve clipboard and window integration evidence", + "status": "completed", + "conclusion": "skipped", + "number": 11, + "started_at": "2026-10-27T13:07:10Z", + "completed_at": "2026-10-27T13:07:10Z" + }, + { + "name": "Full ASCII state replay", + "status": "completed", + "conclusion": "success", + "number": 12, + "started_at": "2026-10-27T13:07:10Z", + "completed_at": "2026-10-27T13:07:10Z" + }, + { + "name": "Full Unicode state replay", + "status": "completed", + "conclusion": "success", + "number": 13, + "started_at": "2026-10-27T13:07:10Z", + "completed_at": "2026-10-27T13:07:10Z" + }, + { + "name": "Preserve synthetic failure evidence", + "status": "completed", + "conclusion": "skipped", + "number": 14, + "started_at": "2026-10-27T13:07:10Z", + "completed_at": "2026-10-27T13:07:10Z" + }, + { + "name": "Post Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "success", + "number": 27, + "started_at": "2026-10-27T13:07:10Z", + "completed_at": "2026-10-27T13:07:11Z" + }, + { + "name": "Post Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "number": 28, + "started_at": "2026-10-27T13:07:11Z", + "completed_at": "2026-10-27T13:07:11Z" + }, + { + "name": "Complete job", + "status": "completed", + "conclusion": "success", + "number": 29, + "started_at": "2026-10-27T13:07:11Z", + "completed_at": "2026-10-27T13:07:11Z" + } + ], + "log_evidence": [] + }, + { + "id": 122206159781, + "name": "regression (windows-2025, build/bin/Release)", + "conclusion": "failure", + "steps": [ + { + "name": "Set up job", + "status": "completed", + "conclusion": "success", + "number": 1, + "started_at": "2026-10-27T13:06:33Z", + "completed_at": "2026-10-27T13:06:35Z" + }, + { + "name": "Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "number": 2, + "started_at": "2026-10-27T13:06:35Z", + "completed_at": "2026-10-27T13:06:42Z" + }, + { + "name": "Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "success", + "number": 3, + "started_at": "2026-10-27T13:06:42Z", + "completed_at": "2026-10-27T13:06:42Z" + }, + { + "name": "Install test dependencies", + "status": "completed", + "conclusion": "success", + "number": 4, + "started_at": "2026-10-27T13:06:42Z", + "completed_at": "2026-10-27T13:06:53Z" + }, + { + "name": "Configure", + "status": "completed", + "conclusion": "success", + "number": 5, + "started_at": "2026-10-27T13:06:53Z", + "completed_at": "2026-10-27T13:07:10Z" + }, + { + "name": "Build", + "status": "completed", + "conclusion": "success", + "number": 6, + "started_at": "2026-10-27T13:07:10Z", + "completed_at": "2026-10-27T13:08:45Z" + }, + { + "name": "Verify shell preparation guards and oracles", + "status": "completed", + "conclusion": "success", + "number": 7, + "started_at": "2026-10-27T13:08:45Z", + "completed_at": "2026-10-27T13:08:47Z" + }, + { + "name": "Prepare hosted Windows shell prerequisites", + "status": "completed", + "conclusion": "success", + "number": 8, + "started_at": "2026-10-27T13:08:47Z", + "completed_at": "2026-10-27T13:09:33Z" + }, + { + "name": "Preserve sanitized shell preparation result", + "status": "completed", + "conclusion": "success", + "number": 9, + "started_at": "2026-10-27T13:09:33Z", + "completed_at": "2026-10-27T13:09:34Z" + }, + { + "name": "Test", + "status": "completed", + "conclusion": "failure", + "number": 10, + "started_at": "2026-10-27T13:09:34Z", + "completed_at": "2026-10-27T13:14:21Z" + }, + { + "name": "Preserve clipboard and window integration evidence", + "status": "completed", + "conclusion": "success", + "number": 11, + "started_at": "2026-10-27T13:14:21Z", + "completed_at": "2026-10-27T13:14:30Z" + }, + { + "name": "Full ASCII state replay", + "status": "completed", + "conclusion": "skipped", + "number": 12, + "started_at": "2026-10-27T13:14:30Z", + "completed_at": "2026-10-27T13:14:30Z" + }, + { + "name": "Full Unicode state replay", + "status": "completed", + "conclusion": "skipped", + "number": 13, + "started_at": "2026-10-27T13:14:30Z", + "completed_at": "2026-10-27T13:14:30Z" + }, + { + "name": "Preserve synthetic failure evidence", + "status": "completed", + "conclusion": "success", + "number": 14, + "started_at": "2026-10-27T13:14:30Z", + "completed_at": "2026-10-27T13:14:38Z" + }, + { + "name": "Post Run actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0", + "status": "completed", + "conclusion": "skipped", + "number": 27, + "started_at": "2026-10-27T13:14:38Z", + "completed_at": "2026-10-27T13:14:38Z" + }, + { + "name": "Post Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1", + "status": "completed", + "conclusion": "success", + "number": 28, + "started_at": "2026-10-27T13:14:38Z", + "completed_at": "2026-10-27T13:14:41Z" + }, + { + "name": "Complete job", + "status": "completed", + "conclusion": "success", + "number": 29, + "started_at": "2026-10-27T13:14:41Z", + "completed_at": "2026-10-27T13:14:41Z" + } + ], + "log_evidence": [ + "2026-10-27T13:08:46.9370598Z Ran 23 tests in 0.204s", + "2026-10-27T13:10:07.8942946Z ERROR: test_publication_keeps_failed_streams_and_separates_the_six_observation_scope (experiments.measure.test_r54_cpu_hosted.CpuHostedBoundaryTests.test_publication_keeps_failed_streams_and_separates_the_six_observation_scope)", + "2026-10-27T13:10:07.8959865Z ValueError: publication paths must stay in workspace local", + "2026-10-27T13:10:07.8961082Z Ran 40 tests in 16.284s", + "2026-10-27T13:10:07.8961443Z FAILED (errors=1)", + "2026-10-27T13:14:21.2079969Z 98% tests passed, 1 tests failed out of 46" + ] + } + ] + } + }, + "limits": [ + "No idle qualification, A/B cost ratio or performance acceptance.", + "Signed CPU residual includes possible guest activity, counter quantization and non-atomic endpoints; no process attribution.", + "Own outside-inner CPU does not explain all residual activity in this new run; old hosted cause remains unknown.", + "New binaries and host identity are independent of earlier local and hosted builds.", + "Full controlled batches, wrapper/projection/component attribution and user-confirmed budgets remain incomplete." + ] +} diff --git a/experiments/measure/results/2026-10-27-r54-cpu-hosted/verify.py b/experiments/measure/results/2026-10-27-r54-cpu-hosted/verify.py new file mode 100644 index 00000000..eff75a07 --- /dev/null +++ b/experiments/measure/results/2026-10-27-r54-cpu-hosted/verify.py @@ -0,0 +1,177 @@ +"""Read retained evidence only; never build or launch a measurement.""" +import hashlib +import json +from pathlib import Path +import re +import subprocess +import sys +import zipfile + +ROOT = Path(__file__).resolve().parents[4] +sys.path.insert(0, str(ROOT)) +from experiments.measure.r54_contract import SOURCES, canonical, expected_sample, protocol, validate_sample +from experiments.measure.r54_inputs import IDENTITY, OVERLAYS +from experiments.measure.run import validate_result + +SOURCE = '4772f4f937c4f0f220be1630592f84bed3a591c8' +RUN = '40512310499' +ORDER = ('baseline', 'candidate', 'candidate', 'baseline', 'baseline', 'candidate') + +def digest(data): + return hashlib.sha256(data).hexdigest() + +def source_file_matches(commit, name, sha): + data = subprocess.check_output(['git','show',commit+':'+name],cwd=ROOT) + if digest(data) == sha: + return 'git_blob_bytes' + # Windows checkout can convert text without explicit eol attributes to CRLF. + # Require the complete captured SHA to match that exact conversion. + assert b'\0' not in data and b'\r\n' not in data, name + assert digest(data.replace(b'\n', b'\r\n')) == sha, name + return 'git_blob_lf_to_crlf' + +def main(path): + assert path.stat().st_size == 123388 + assert digest(path.read_bytes()) == '263a3bf8e229b89f1e443b12e522daf69d30de403affa0dc49fe674c0dd8f241' + with zipfile.ZipFile(path) as archive: + read = lambda name: json.loads(archive.read(name)) + publication = read('publication.json') + assert publication['schema'] == 'termforge-r54-cpu-hosted-publication-v1' + inventory = {v['path']: v for v in publication['artifacts']} + assert len(inventory) == len(publication['artifacts']) == 74 + assert len(archive.namelist()) == 75 + assert set(archive.namelist()) == set(inventory) | {'publication.json'} + exact = [] + for name, row in inventory.items(): + assert not Path(name).is_absolute() and '..' not in Path(name).parts + data = archive.read(name) + assert len(data) == row['published_bytes'] and digest(data) == row['published_sha256'], name + assert not re.search(rb'[A-Za-z]:[\\/]+(?:Users|a)[\\/]', data, re.I), name + assert b'child_pid' not in data and b'process_inventory' not in data, name + if row['treatment'] == 'byte_exact_owned_synthetic_stream': + assert row['original_bytes'] == len(data) and row['original_sha256'] == digest(data), name + exact.append(name) + assert len(exact) == 24 + original = lambda name: inventory[name]['original_sha256'] + identity = publication['hosted_identity'] + assert identity['GITHUB_SHA'] == SOURCE and identity['GITHUB_RUN_ID'] == RUN + assert identity['GITHUB_RUN_ATTEMPT'] == '1' and identity['GITHUB_EVENT_NAME'] == 'push' + assert identity['GITHUB_REF'] == 'refs/heads/perf/grapheme-cpu-hosted-r54-entry3' + assert identity['GITHUB_REPOSITORY'] == 'JavaZeroo/termforge' + assert identity['RUNNER_ENVIRONMENT'] == 'github-hosted' and identity['RUNNER_OS'] == 'Windows' + hosted = read('hosted.json') + assert hosted['source'] == SOURCE and hosted['hosted_identity'] == identity + assert hosted['status'] == 'accounting_complete' and hosted['performance_gate'] == 'not_evaluated' + for key, name in (('runner_sha256','experiments/measure/r54_cpu_hosted.py'), + ('workflow_sha256','.github/workflows/r54-cpu.yml')): + assert digest(subprocess.check_output(['git','show',SOURCE+':'+name],cwd=ROOT)) == hosted[key] + runner = read('diagnostic/runner.json') + assert runner['commit'] == SOURCE and runner['worktree_status'] == '' + for name, sha in runner['sources'].items(): + assert digest(subprocess.check_output(['git','show',SOURCE+':'+name],cwd=ROOT)) == sha, name + preparation = read('bundle/preparation.json') + assert preparation['status'] == 'built_and_audited' and preparation['source'] == SOURCE + plan, builds = read('bundle/plan-v1.json'), read('bundle/build-plan.json') + assert plan['protocol'] == protocol() + assert plan['protocol_sha256'] == digest(canonical(protocol())) + assert builds['harness_source'] == SOURCE and builds['frozen_plan']['sha256'] == original('bundle/plan-v1.json') + assert builds['protocol_sha256'] == plan['protocol_sha256'] + checkout_forms = {name: source_file_matches(SOURCE, name, sha) for name, sha in plan['harness_sha256'].items()} + binding, audit = read('diagnostic/binding.json'), read('bundle/build-audit.json') + assert audit['passed'] is True and audit['formal_samples'] == 0 + assert binding['plan_sha256'] == original('bundle/plan-v1.json') + assert binding['harness_source'] == SOURCE and binding['protocol_sha256'] == plan['protocol_sha256'] + for name, sha in binding['evidence'].items(): + assert original('bundle/'+name) == sha, name + for variant, source in SOURCES.items(): + spec, observed = builds['builds'][variant], audit['builds'][variant] + receipt = read('bundle/'+variant+'-build.json') + assert spec['commit'] == observed['source'] == source['commit'] + assert spec['version'] == observed['version'] == source['version'] + assert len(spec['before_files']) == len(spec['after_files']) == (80 if variant == 'baseline' else 84) + assert set(spec['before_files']) == set(spec['after_files']) + assert set(spec['changed_paths']) == set(spec['overlay_files']) == set(OVERLAYS) + for name, before in spec['before_files'].items(): + checkout_forms[variant+'/'+name] = source_file_matches(source['commit'], name, before) + expected = plan['harness_sha256'][name] if name in OVERLAYS else before + assert spec['after_files'][name] == expected, name + assert spec['overlay_patch_sha256'] == original('bundle/'+variant+'-harness.patch') + assert receipt['status'] == 'built_identity_only' and receipt['exit_code'] == 0 and not receipt['timed_out'] + assert receipt['build_plan_sha256'] == original('bundle/build-plan.json') + assert observed['receipt_sha256'] == original('bundle/'+variant+'-build.json') + assert receipt['binary'] == observed['binary'] == binding['builds'][variant]['binary'] + assert receipt['identity'] == observed['identity'] == read('bundle/'+variant+'-identity.stdout') == IDENTITY + assert read('diagnostic/'+variant+'-identity/stdout.bin') == IDENTITY + assert read('diagnostic/'+variant+'-identity/record.json')['exit_code'] == 0 + assert receipt['command'] == spec['command'] + for flag in ('--release','--locked','--offline','--no-default-features','--jobs','1','x86_64-pc-windows-msvc'): + assert flag in spec['command'] + for name, log in receipt['logs'].items(): + assert log['sha256'] == original('bundle/'+name) + assert log['bytes'] == inventory['bundle/'+name]['original_bytes'] + assert audit['builds']['baseline']['linker'] == audit['builds']['candidate']['linker'] + assert len(audit['short_sanity_calls']) == 4 + for call in audit['short_sanity_calls']: + assert call['passed'] and call['exit_code'] == 0 and not call['timed_out'] + prefix = 'bundle/sanity-'+call['variant']+'-'+call['route']+'/' + for name, stream in call['streams'].items(): + data = archive.read(prefix+name) + assert digest(data) == stream['sha256'] and len(data) == stream['bytes'] + validate_result(read(prefix+'stdout.bin'), .1, expected_sample(dict(variant=call['variant'], route=call['route'], chunk=4096))) + manifest = read('diagnostic/manifest.json') + observations = read('diagnostic/observations/manifest.json') + assert hosted['diagnostic'] == manifest + assert manifest['status'] == observations['status'] == 'accounting_complete' + assert manifest['observations'] == observations + assert observations['attempted'] == observations['accounted_observations'] == 6 + assert observations['performance_gate'] == 'not_evaluated' + for key, name in (('context_sha256','context.json'), ('protocol_sha256','protocol.json')): + assert observations[key] == original('diagnostic/observations/'+name) + rows = [] + for index, variant in enumerate(ORDER): + prefix = f'diagnostic/observations/{index:03d}/' + row = read(prefix+'record.json') + assert row['item'] == dict(sequence=index, variant=variant, route='interactive', chunk=1) + assert row['status'] == 'accounted' and row['exit_code'] == 0 and not row['timed_out'] + for name, stream in row['streams'].items(): + data = archive.read(prefix+name) + assert digest(data) == stream['sha256'] and len(data) == stream['bytes'] + raw = read(prefix+'stdout.bin') + assert raw == row['result'] + validate_sample(raw,row['item']) + env, child, accounting = row['environment'], row['child_cpu'], row['accounting'] + before, after = env['before'], env['after'] + busy = after['user']+after['system']-before['user']-before['system'] + total = busy+after['idle']-before['idle'] + assert abs(busy-env['busy_seconds']) < 1e-8 and abs(total-env['total_seconds']) < 1e-8 + assert child['total_seconds'] == child['kernel_seconds']+child['user_seconds'] + assert child['exit_filetime'] > child['creation_filetime'] + inner, runner_cpu = raw['interval_cpu_seconds'], row['runner_cpu_after_seconds']-row['runner_cpu_before_seconds'] + assert runner_cpu == row['runner_cpu_seconds'] == accounting['runner_cpu_seconds'] + assert child['total_seconds'] >= inner + assert accounting['child_outside_inner_seconds'] == child['total_seconds']-inner + assert accounting['inner_only_balance_seconds'] == busy-inner + assert abs(accounting['inner_only_balance_percent']-(busy-inner)*100/total) < 1e-8 + assert accounting['unassigned_balance_seconds'] == busy-child['total_seconds']-runner_cpu + assert abs(accounting['unassigned_balance_percent']-accounting['unassigned_balance_seconds']*100/total) < 1e-8 + rows.append(dict(item=row['item'],inner_cpu_seconds=inner,child_cpu=child,runner_cpu_seconds=runner_cpu, + environment=env,accounting=accounting,state_fnv1a64=raw['state_fnv1a64'])) + result = dict(schema='termforge-r54-cpu-hosted-validation-v1',source=SOURCE,hosted_identity=identity, + host=read('diagnostic/environment.json'),builds=audit['builds'],observations=rows, + archive=dict(bytes=path.stat().st_size,sha256=digest(path.read_bytes()),files=75,inventory_files=74,byte_exact_streams=24), + source_checkout_forms=checkout_forms,sanity_oracles=4,observation_oracles=6,formal_cost_samples=0, + performance_gate='not_evaluated',old_hosted_event_cause='unknown') + retained = json.loads(path.with_name('validation.json').read_text(encoding='utf-8')) + for name, value in result.items(): + assert retained[name] == value, name + provider = retained['provider'] + assert provider['run'] == int(RUN) and provider['attempt'] == 1 and provider['source'] == SOURCE + assert provider['job'] == 122217071656 and provider['conclusion'] == 'success' + assert provider['artifact_digest'] == 'sha256:'+digest(path.read_bytes()) + assert sum(value == 'git_blob_lf_to_crlf' for value in checkout_forms.values()) == 115 + assert len(checkout_forms) == 168 + print(json.dumps(dict(files=75,hashed_evidence=74,byte_exact_streams=24,sanity_oracles=4,observation_oracles=6, + formal_cost_samples=0,performance_gate='not_evaluated'))) + +if __name__ == '__main__': + main(Path(__file__).with_name('evidence.zip')) diff --git a/experiments/measure/test_r54_cpu_hosted.py b/experiments/measure/test_r54_cpu_hosted.py new file mode 100644 index 00000000..62738e2b --- /dev/null +++ b/experiments/measure/test_r54_cpu_hosted.py @@ -0,0 +1,106 @@ +"""Synthetic publication and hosted-identity boundaries, never actual hosted runs.""" +import json +import os +from pathlib import Path +import subprocess +import sys +import tempfile +import unittest +from unittest.mock import patch + + +class CpuHostedBoundaryTests(unittest.TestCase): + def test_wrong_experiment_or_stale_run_is_rejected_before_publication_staging(self): + from experiments.measure import r54_publish as publisher + identity = dict(GITHUB_RUN_ID='123', GITHUB_RUN_ATTEMPT='1', GITHUB_SHA='a' * 40) + with tempfile.TemporaryDirectory() as folder: + root = Path(folder).resolve() + raw = root / 'local/raw' + raw.mkdir(parents=True) + output = root / 'local/public' + for schema, recorded in (('termforge-r54-hosted-v1', identity), + ('termforge-r54-cpu-hosted-v1', dict(identity, GITHUB_RUN_ID='122'))): + (raw / 'hosted.json').write_text(json.dumps(dict(schema=schema, source='a' * 40, + hosted_identity=recorded)), encoding='utf-8') + with patch.object(publisher, 'ROOT', root), \ + patch.object(publisher, 'hosted_identity', return_value=identity), self.assertRaises(ValueError): + publisher.publish(raw, output, experiment='cpu-boundary') + self.assertFalse(output.exists()) + self.assertFalse(output.with_name('public.partial').exists()) + + def test_non_hosted_entry_preserves_failure_without_building(self): + root = Path(__file__).resolve().parents[2] + (root / 'local').mkdir(exist_ok=True) + with tempfile.TemporaryDirectory(dir=root / 'local') as folder: + output = Path(folder) / 'raw' + result = subprocess.run([sys.executable, '-m', 'experiments.measure.r54_cpu_hosted', '--out', str(output)], + cwd=root, env=dict(os.environ, GITHUB_ACTIONS='false'), + capture_output=True, timeout=15) + self.assertNotEqual(result.returncode, 0) + manifest = json.loads((output / 'hosted.json').read_text(encoding='utf-8')) + self.assertEqual(manifest['status'], 'failed') + self.assertIn('actual GitHub-hosted Windows job', manifest['error']) + self.assertFalse((output / 'bundle').exists()) + self.assertFalse((output / 'diagnostic').exists()) + + def test_branch_attempt_and_source_cannot_be_mixed(self): + from experiments.measure import r54_hosted as hosted + identity = dict(GITHUB_ACTIONS='true', RUNNER_ENVIRONMENT='github-hosted', RUNNER_OS='Windows', + GITHUB_REPOSITORY='JavaZeroo/termforge', GITHUB_EVENT_NAME='push', + GITHUB_REF='refs/heads/perf/grapheme-cpu-hosted-r54', GITHUB_RUN_ATTEMPT='1', + GITHUB_SHA='a' * 40) + with patch.dict(os.environ, identity, clear=True), patch.object(os, 'name', 'nt'), \ + patch.object(hosted, 'git', return_value='a' * 40): + self.assertEqual(hosted.hosted_identity('perf/grapheme-cpu-hosted-r54')['GITHUB_SHA'], 'a' * 40) + for branch in ('perf/grapheme-cpu-hosted-r54-setup2', 'perf/grapheme-cpu-hosted-r54-entry3'): + with patch.dict(os.environ, GITHUB_REF='refs/heads/' + branch): + self.assertEqual(hosted.hosted_identity(hosted.CPU_BOUNDARY_BRANCHES)['GITHUB_SHA'], 'a' * 40) + with self.assertRaises(ValueError): + hosted.hosted_identity() + with self.assertRaises(ValueError): + hosted.hosted_identity() + for key, value in (('GITHUB_RUN_ATTEMPT', '2'), ('GITHUB_SHA', 'b' * 40)): + with patch.dict(os.environ, {key: value}), self.assertRaises(ValueError): + hosted.hosted_identity('perf/grapheme-cpu-hosted-r54') + + def test_publication_keeps_failed_streams_and_separates_the_six_observation_scope(self): + from experiments.measure import r54_publish as publisher + identity = dict(GITHUB_RUN_ID='123', GITHUB_RUN_ATTEMPT='1', GITHUB_SHA='a' * 40) + with tempfile.TemporaryDirectory() as folder: + root = Path(folder).resolve() + raw = root / 'local/raw' + raw.mkdir(parents=True) + (raw / 'hosted.json').write_text(json.dumps(dict(schema='termforge-r54-cpu-hosted-v1', + source='a' * 40, hosted_identity=identity, status='failed')), encoding='utf-8') + record = raw / 'diagnostic/observations/000/record.json' + record.parent.mkdir(parents=True) + record.write_text(json.dumps(dict(child_pid=12345, status='failed', + child_cpu=dict(total_seconds=2.25), command=[str(root / 'tool.exe')])), encoding='utf-8') + payload = b'partial\xff\x00\n' + (record.parent / 'stdout.bin').write_bytes(payload) + for extra in ('diagnostic/observations/006/stdout.bin', 'batch-20261026/samples/000/stdout.bin', + 'diagnostic/observations/000/private.json', 'credentials.json'): + path = raw / extra + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(b'do-not-publish') + output = root / 'local/public' + # Host and short-path queries are OS boundaries. No fixture claims + # a real hosted identity or CPU measurement. + with patch.object(publisher, 'ROOT', root), \ + patch.object(publisher, 'hosted_identity', return_value=identity), \ + patch.object(publisher, 'windows_short_path', side_effect=lambda path: path): + publisher.publish(raw, output, experiment='cpu-boundary') + publication = json.loads((output / 'publication.json').read_text(encoding='utf-8')) + self.assertEqual(publication['schema'], 'termforge-r54-cpu-hosted-publication-v1') + self.assertEqual({item['path'] for item in publication['artifacts']}, + {'hosted.json', 'diagnostic/observations/000/record.json', 'diagnostic/observations/000/stdout.bin'}) + published = json.loads((output / 'diagnostic/observations/000/record.json').read_text(encoding='utf-8')) + self.assertNotIn('child_pid', published) + self.assertEqual(published['child_cpu']['total_seconds'], 2.25) + self.assertEqual(published['status'], 'failed') + self.assertTrue(published['command'][0].startswith('${WORKSPACE}')) + self.assertEqual((output / 'diagnostic/observations/000/stdout.bin').read_bytes(), payload) + + +if __name__ == '__main__': + unittest.main()