From c76bab0281843fca298af8b0d9ba521247ac745a Mon Sep 17 00:00:00 2001 From: JavaZero <71128095+JavaZeroo@users.noreply.github.com> Date: Tue, 27 Oct 2026 20:30:30 +0800 Subject: [PATCH 1/2] perf: retain whole-child CPU boundary diagnosis for #54 Independent six-observation diagnostic; preserve the original v1 cost failure. Reviewed local tree: 10542c04a569605b416c074a3780f409da84f887. Measured local source: ff0d7caca138b91683f16ce8d748eea6fbb289b7. Published tree is byte-identical to the final Standards/Spec reviewed tree. --- CMakeLists.txt | 2 +- docs/EVIDENCE.md | 1 + docs/FEATURES.md | 2 +- experiments/measure/R54-CPU-DIAGNOSTIC.md | 37 ++ experiments/measure/r54_cpu_diagnostic.py | 236 ++++++++++ .../2026-10-27-r54-cpu-boundary/README.md | 34 ++ .../2026-10-27-r54-cpu-boundary/evidence.zip | Bin 0 -> 100053 bytes .../validation.json | 422 ++++++++++++++++++ .../2026-10-27-r54-cpu-boundary/verify.py | 73 +++ .../measure/test_r54_cpu_diagnostic.py | 98 ++++ 10 files changed, 903 insertions(+), 2 deletions(-) create mode 100644 experiments/measure/R54-CPU-DIAGNOSTIC.md create mode 100644 experiments/measure/r54_cpu_diagnostic.py create mode 100644 experiments/measure/results/2026-10-27-r54-cpu-boundary/README.md create mode 100644 experiments/measure/results/2026-10-27-r54-cpu-boundary/evidence.zip create mode 100644 experiments/measure/results/2026-10-27-r54-cpu-boundary/validation.json create mode 100644 experiments/measure/results/2026-10-27-r54-cpu-boundary/verify.py create mode 100644 experiments/measure/test_r54_cpu_diagnostic.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 5825ca6b..61d22796 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 -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(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 e7402838..566598b7 100644 --- a/docs/EVIDENCE.md +++ b/docs/EVIDENCE.md @@ -164,5 +164,6 @@ python -m unittest experiments.shell.test_workflow_sessions -v | 候选 `.3`→`.4` 字素改动 | [固定字素验证](../experiments/shell/results/2026-10-26-streaming-graphemes/validation.json)、[性能限制与原始样本身份](research/streaming-graphemes.md)、[#54](https://github.com/JavaZeroo/termforge/issues/54) | 同宿主交错诊断中 project/interactive 吞吐中位数约下降 16%/9%;共享宿主、allocator 包装、无真实呈现/输入时延,使其不能作为正式预算或性能通过。#54 受控定位仍阻塞 #34 的性能裁决。 | | 固定字素成本的批次协议与执行 | [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%护栏。 | 目前没有足够证据判断 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 6619b2a3..9f3c415e 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)已验证来源和失败保留,但首批因环境护栏停止,尚无完整成本批次 | 旧诊断的共享宿主、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)另记完整子进程/执行器分量,不改原护栏或判成本通过 | 旧诊断的共享宿主、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-DIAGNOSTIC.md b/experiments/measure/R54-CPU-DIAGNOSTIC.md new file mode 100644 index 00000000..49f54d10 --- /dev/null +++ b/experiments/measure/R54-CPU-DIAGNOSTIC.md @@ -0,0 +1,37 @@ +# R54:CPU 计量边界的独立诊断 + +本项接续 [#54](https://github.com/JavaZeroo/termforge/issues/54) 的首次 hosted 停止事件:原批次第24个位置按 v1 口径得到 5.410% 未归属活动估计,超过原5%环境护栏。原记录没有整个子进程及执行器CPU,无法事后区分自身区间外工作和其他guest活动。该事件、失败状态、[v1合同](R54-COST.md)及两批各112位置均保持;此诊断不补样、不重试旧批次、不判性能通过。 + +## 预声明问题与执行范围 + +按以下预测分别记录,而不是先假定护栏误报: + +1. 若自身区间外工作有贡献,完整子进程CPU会高于其内部连续测量区间CPU;差值包括启动、准备、oracle、输出和退出,不能仅凭差值细分各阶段。 +2. 若执行器有贡献,其同一外部区间的进程CPU会大于零。 +3. 扣除前两项后的余额仍可能包含其他guest活动、系统归账粒度和非原子采样边界;余额保留正负,不称为精确后台进程CPU。物理宿主争用和频率仍未知。 + +固定一次六位置序列为 `.3, .4, .4, .3, .3, .4`,全部使用原 `interactive` 22,000B 语料、chunk=1、observe=0、内部CPU/墙钟至少2秒及原正确性校验。沿用已审计的共同harness与两份无allocator包装EXE,不重新构建。只比较计量范围,**不计算A/B成本比或吞吐变化,也不运行空闲合格筛选**。允许在如实声明的共享宿主研究这些计数;这不把共享宿主升级为成本验收环境。 + +每个进程90秒期限,超时终止直接子进程并最多等待5秒;退出未确认、计数缺失、输出错误或来源变化立即停止,不补跑。固定核心EXE不派生进程,本工具只支持这个直接子进程边界,不宣称通用进程树计量或回收。诊断状态 `accounting_complete` 只说明六次记录/正确性/来源完整,始终 `performance_gate=not_evaluated`。 + +## 计数与证据 + +`GetSystemTimes` 先取全机计数,再取runner的 `process_time`,然后启动并等待直接子进程;退出后通过保留的进程句柄读取 `GetProcessTimes`,再取runner和全机末计数。全机计数只支持1–64逻辑CPU。两个采样端点不是原子操作,读取进程计数本身也有成本;诊断不声称无扰动。 + +每个观察保留全机原始前后计数、runner前后CPU、子进程创建/退出FILETIME及user/kernel/总CPU、原始stdout/stderr、内层区间和以下余额: + +- `inner_only_balance = guest_busy - inner_cpu`:本次插桩区间的内层单项扣除,不冒充旧批次的原值。 +- `child_outside_inner = child_lifetime_cpu - inner_cpu`。 +- `unassigned_balance = guest_busy - child_lifetime_cpu - runner_cpu`:保留负值,不据此修正成本或设新护栏。 + +Windows进程对象在外部仍持有句柄时可于退出后查询,依据 [GetProcessTimes](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocesstimes) 和[进程终止语义](https://learn.microsoft.com/en-us/windows/win32/procthread/terminating-a-process)。诊断限定Windows CPython3.12,通过Popen持有的句柄避免退出后按PID查询;该私有接口依赖及句柄生命周期按[CPython3.12.10源码](https://github.com/python/cpython/blob/v3.12.10/Lib/subprocess.py)核对,不能静默扩展到其他runtime。 + +入口要求已提交且干净的工具源码、显式环境声明、原计划及完整构建包,运行前后复核全部来源、编译产物及实际`--identity`。输出目录必须不存在;过程、失败和中断记录保留。原始本地路径和PID留local,公开时单独审核白名单、路径脱敏和原字节流哈希,不递归上传工作目录。 + +```powershell +python -m experiments.measure.r54_cpu_diagnostic ` + --plan <原plan-v1.json> --build-bundle <原构建包> ` + --environment <含host_kind与known_concurrent_work的JSON> --out <全新目录> +``` + +本次结果只回答声明宿主上的计量问题,不能补造旧hosted事件的原因。是否改变后续环境测量方法须先依据诊断另定协议,不能倒改原v1或用新口径将旧失败改绿。完整成本批次、allocator/projection及组件归因、数值预算提案与用户确认仍由 #54 接续。 diff --git a/experiments/measure/r54_cpu_diagnostic.py b/experiments/measure/r54_cpu_diagnostic.py new file mode 100644 index 00000000..6b04b424 --- /dev/null +++ b/experiments/measure/r54_cpu_diagnostic.py @@ -0,0 +1,236 @@ +"""Separate whole-child CPU accounting from R54's unchanged v1 cost batches.""" +from __future__ import annotations + +import argparse +import ctypes +from ctypes import wintypes +import json +import math +import os +from pathlib import Path +import subprocess +import sys +import time + +from experiments.measure.r54_batch import capture, sha, utc, write_json +from experiments.measure.r54_contract import CPU_SECONDS, ROOT, SOURCES, validate_sample +from experiments.measure.r54_environment import cpu_delta, cpu_snapshot, host_identity +from experiments.measure.r54_inputs import IDENTITY, git, load_builds, read, require + +PROTOCOL = dict(schema='termforge-r54-cpu-boundary-v1', + order=['baseline', 'candidate', 'candidate', 'baseline', 'baseline', 'candidate'], + route='interactive', chunk=1, observe=0, inner_cpu_seconds=CPU_SECONDS, + process_timeout_seconds=90, cleanup_timeout_seconds=5, + activity_acceptance_gate=False, performance_gate='not_evaluated', + purpose='separate whole-child, inner interval and runner CPU; no cost ratios', + residual_scope='other guest activity plus counter quantization and bracket mismatch; not exact attribution') + + +def partition_cpu(record, inner_cpu): + """Expose balances without labelling the signed residual external activity. + + Counter updates and non-atomic bracket endpoints can leave a negative + residual. Keep it visible; do not clamp, normalize or subtract it from cost. + """ + total = record['environment']['total_seconds'] + busy = record['environment']['busy_seconds'] + child = record['child_cpu']['total_seconds'] + runner = record['runner_cpu_seconds'] + if (any(not math.isfinite(value) or value < 0 for value in (total, busy, child, runner, inner_cpu)) + or total <= 0 or child < inner_cpu): + raise ValueError('inconsistent whole-child or CPU accounting') + residual = busy - child - runner + return dict(inner_only_balance_seconds=busy - inner_cpu, + inner_only_balance_percent=(busy - inner_cpu) * 100 / total, + child_outside_inner_seconds=child - inner_cpu, + runner_cpu_seconds=runner, unassigned_balance_seconds=residual, + unassigned_balance_percent=residual * 100 / total) + + +def exited_child_cpu(process): + """Borrow CPython's retained Windows process handle after wait, before close. + + The handle belongs to Popen. Querying by PID after exit would lose the + lifetime or risk a reused identity; retaining this handle avoids that race. + This private CPython dependency is limited to the pinned diagnostic runtime. + """ + if process.returncode is None: + raise ValueError('child must have exited before lifetime accounting') + creation, end, kernel, user = (wintypes.FILETIME() for _ in range(4)) + function = ctypes.WinDLL('kernel32', use_last_error=True).GetProcessTimes + function.argtypes = [wintypes.HANDLE] + [ctypes.POINTER(wintypes.FILETIME)] * 4 + function.restype = wintypes.BOOL + if not function(int(process._handle), ctypes.byref(creation), ctypes.byref(end), + ctypes.byref(kernel), ctypes.byref(user)): + raise ctypes.WinError(ctypes.get_last_error()) + ticks = lambda value: (value.dwHighDateTime << 32) | value.dwLowDateTime + return dict(creation_filetime=ticks(creation), exit_filetime=ticks(end), + kernel_seconds=ticks(kernel) / 10_000_000, + user_seconds=ticks(user) / 10_000_000, + total_seconds=(ticks(kernel) + ticks(user)) / 10_000_000) + + +def capture_cpu(command, output, timeout=90): + """Capture a direct child and its complete CPU lifetime, including exit. + + The fixed measurement executables do not spawn children. This helper does + not claim descendant accounting or cleanup. Stream bytes are never decoded + or rewritten here, including failed and timed-out executions. + """ + if os.name != 'nt' or sys.implementation.name != 'cpython' or sys.version_info[:2] != (3, 12): + raise ValueError('CPU diagnostic requires Windows CPython 3.12') + output = Path(output) + result = dict(command=command, started_utc=utc(), exit_code=None, timed_out=False, + child_cpu=None, clock='GetProcessTimes kernel plus user', + runtime=sys.version, accounting_scope='direct child only') + with (output / 'stdout.bin').open('xb') as stdout, (output / 'stderr.bin').open('xb') as stderr: + before = cpu_snapshot() + runner_before = time.process_time() + try: + # Popen.__exit__ waits without a bound. Keep the object alive for + # accounting, but use explicit bounded waits on failure instead. + child = subprocess.Popen(command, stdin=subprocess.DEVNULL, stdout=stdout, stderr=stderr) + result['child_pid'] = child.pid + try: + child.wait(timeout=timeout) + except subprocess.TimeoutExpired: + result.update(timed_out=True, error=f'direct child timed out after {timeout}s') + child.kill() + child.wait(timeout=PROTOCOL['cleanup_timeout_seconds']) + except BaseException: + child.kill() + child.wait(timeout=PROTOCOL['cleanup_timeout_seconds']) + raise + result['exit_code'] = child.returncode + result['child_cpu'] = exited_child_cpu(child) + except (OSError, subprocess.SubprocessError) as error: + result['error'] = f'{type(error).__name__}: {error}' + finally: + runner_after = time.process_time() + after = cpu_snapshot() + result['runner_cpu_seconds'] = runner_after - runner_before + result['runner_cpu_before_seconds'] = runner_before + result['runner_cpu_after_seconds'] = runner_after + result['environment'] = dict(cpu_delta(before, after), before=before, after=after) + result['finished_utc'] = utc() + result['streams'] = {name: dict(bytes=(output / name).stat().st_size, sha256=sha(output / name)) + for name in ('stdout.bin', 'stderr.bin')} + return result + + +def run_observations(commands, output, context): + """Process/artifact seam for the fixed six-observation diagnostic only.""" + require(set(commands) == set(SOURCES), 'fixed source pair required') + output = Path(output) + output.mkdir(parents=True, exist_ok=False) + write_json(output / 'context.json', context) + write_json(output / 'protocol.json', PROTOCOL) + manifest = dict(schema='termforge-r54-cpu-observations-v1', status='running', + started_utc=utc(), attempted=0, accounted_observations=0, + context_sha256=sha(output / 'context.json'), protocol_sha256=sha(output / 'protocol.json'), + performance_gate='not_evaluated') + try: + for sequence, variant in enumerate(PROTOCOL['order']): + item = dict(sequence=sequence, variant=variant, route=PROTOCOL['route'], chunk=PROTOCOL['chunk']) + directory = output / f'{sequence:03d}' + directory.mkdir() + record = dict(item=item, status='started') + manifest.update(attempted=sequence + 1, active_sequence=sequence) + write_json(output / 'manifest.json', manifest) + write_json(directory / 'record.json', record) + try: + command = list(commands[variant]) + [item['route'], str(item['chunk']), '0', str(CPU_SECONDS)] + before_sha = sha(command[0]) + if 'binding' in context: + require(before_sha == context['binding']['builds'][variant]['binary']['sha256'], + 'binary changed before observation') + record.update(capture_cpu(command, directory, PROTOCOL['process_timeout_seconds'])) + require(not record['timed_out'] and record['exit_code'] == 0 and 'error' not in record, + record.get('error', 'nonzero child exit')) + result = json.loads((directory / 'stdout.bin').read_bytes().decode('utf-8')) + validate_sample(result, item) + require(result['cpu_clock'] == 'GetProcessTimes kernel plus user', 'wrong child CPU clock') + require(sha(command[0]) == before_sha, 'binary changed during observation') + record['result'] = result + record['accounting'] = partition_cpu(record, result['interval_cpu_seconds']) + record['status'] = 'accounted' + except Exception as error: + record.update(status='failed', error=f'{type(error).__name__}: {error}') + finally: + write_json(directory / 'record.json', record) + require(record['status'] == 'accounted', record.get('error', 'observation incomplete')) + manifest['accounted_observations'] += 1 + manifest.update(status='accounting_complete', active_sequence=None) + except Exception as error: + manifest.update(status='failed', error=f'{type(error).__name__}: {error}') + except BaseException: + manifest['status'] = 'interrupted' + raise + finally: + manifest['finished_utc'] = utc() + write_json(output / 'manifest.json', manifest) + return manifest + + +def execute(plan, bundle, declaration, output): + """Audit retained builds; do not rebuild or repeat an old preflight/batch.""" + require(os.name == 'nt', 'Windows accounting required') + output = Path(output) + output.mkdir(parents=True, exist_ok=False) + manifest = dict(schema='termforge-r54-cpu-diagnostic-v1', status='preparing', started_utc=utc(), + performance_gate='not_evaluated') + try: + runner = dict(commit=git(ROOT, 'rev-parse', 'HEAD'), worktree_status=git(ROOT, 'status', '--porcelain'), + sources={name: sha(ROOT / name) for name in ( + 'experiments/measure/r54_cpu_diagnostic.py', 'experiments/measure/r54_environment.py', + 'experiments/measure/r54_batch.py', 'experiments/measure/r54_contract.py', + 'experiments/measure/r54_inputs.py', 'experiments/measure/run.py')}) + write_json(output / 'runner.json', runner) + require(not runner['worktree_status'], 'runner source must be committed and clean') + environment = read(declaration) + require(environment.get('host_kind') in ('shared_workstation', 'hosted_vm', 'dedicated_host') and + isinstance(environment.get('known_concurrent_work'), list), 'explicit environment declaration required') + write_json(output / 'environment.json', dict(host=host_identity(), declaration=environment, + scope='accounting diagnosis on declared host; no idle qualification or cost acceptance')) + binding = load_builds(plan, bundle) + write_json(output / 'binding.json', binding) + (output / 'plan-v1.json').write_bytes(Path(plan).read_bytes()) + for variant, command in binding['commands'].items(): + directory = output / (variant + '-identity') + directory.mkdir() + value = capture(command + ['--identity'], directory, timeout=10) + write_json(directory / 'record.json', value) + require(value['exit_code'] == 0 and read(directory / 'stdout.bin') == IDENTITY, 'actual build identity mismatch') + result = run_observations(binding['commands'], output / 'observations', + dict(evidence_kind='cpu_boundary_diagnostic', binding=binding, runner=runner)) + manifest['observations'] = result + require(result['status'] == 'accounting_complete', 'diagnostic stopped; no replacement observations') + require(load_builds(plan, bundle) == binding, 'build binding changed during diagnosis') + for name, digest in runner['sources'].items(): + require(sha(ROOT / name) == digest, 'runner changed during diagnosis') + manifest['status'] = 'accounting_complete' + except Exception as error: + manifest.update(status='failed', error=f'{type(error).__name__}: {error}') + except BaseException: + manifest['status'] = 'interrupted' + raise + finally: + manifest['finished_utc'] = utc() + write_json(output / 'manifest.json', manifest) + return manifest + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--plan', type=Path, required=True) + parser.add_argument('--build-bundle', type=Path, required=True) + parser.add_argument('--environment', type=Path, required=True) + parser.add_argument('--out', type=Path, required=True) + args = parser.parse_args() + result = execute(args.plan, args.build_bundle, args.environment, args.out) + print(json.dumps(result)) + raise SystemExit(0 if result['status'] == 'accounting_complete' else 1) + + +if __name__ == '__main__': + main() diff --git a/experiments/measure/results/2026-10-27-r54-cpu-boundary/README.md b/experiments/measure/results/2026-10-27-r54-cpu-boundary/README.md new file mode 100644 index 00000000..34a93f29 --- /dev/null +++ b/experiments/measure/results/2026-10-27-r54-cpu-boundary/README.md @@ -0,0 +1,34 @@ +# CPU 计量边界:一次共享宿主诊断 + +按[预声明合同](../../R54-CPU-DIAGNOSTIC.md),在共享Windows11宿主完成一次固定六位置诊断,所有进程退出0、输出和完整来源前后核验通过。**这不是原112位置成本批次,也没有性能通过结论。** 原hosted第24位置失败保留,当前结果不能反推其具体原因。 + +实际执行源码为本地提交 `ff0d7caca138b91683f16ce8d748eea6fbb289b7`,树 `796005cdcd0e330ae86d676ec5386125459d733d`;开始时工作树干净。运行时间为2026-10-27 12:17:43–12:18:00 UTC。完整工具源哈希在归档`runner.json`,发布版本中的执行代码与它逐文件一致;后续仅调整测试的runtime跳过边界及增加本记录。 + +环境为Windows11 build26200/UBR9711/25H2、Intel i7-9700、8逻辑/8物理CPU、CPython3.12.10、psutil7.2.2。明确共享宿主,未调整个人设置,未执行空闲资格筛选。复用[原构建记录](../2026-10-27-r54-runner/validation.json)中已审计的 `.3/.4` EXE;两份来源、harness、build命令/日志/覆盖、80/84文件身份、linker与实际`--identity`在运行前后重新校验。没有重建,二进制与旧hosted的两份构建不同。 + +下表均为CPU秒;余额比例的分母是全机总CPU区间,所有位置固定interactive/chunk1/observe0。它不报告吞吐或A/B成本比。 + +| 位置 | 核心 | 内部区间 | 完整子进程 | 区间外差值 | runner | 未归属余额 | 余额占比 | +|---|---|---:|---:|---:|---:|---:|---:| +| 0 | .3 | 2.125000 | 2.203125 | 0.078125 | 0 | 9.796875 | 49.920% | +| 1 | .4 | 2.140625 | 2.234375 | 0.093750 | 0.015625 | 8.859375 | 44.575% | +| 2 | .4 | 2.203125 | 2.296875 | 0.093750 | 0 | 6.656250 | 34.578% | +| 3 | .3 | 2.156250 | 2.265625 | 0.109375 | 0.015625 | 9.343750 | 47.611% | +| 4 | .3 | 2.125000 | 2.203125 | 0.078125 | 0 | 7.359375 | 38.231% | +| 5 | .4 | 2.031250 | 2.109375 | 0.078125 | 0.015625 | 9.812500 | 50.974% | + +此宿主确有可见的自身区间外CPU和runnerCPU,单扣内层区间不能准确区分这些部分。但完整扣除后的余额仍很大;原始计数和非原子采样可能有粒度差异,不把余额归因到某个后台进程,也不声称空闲、无扰动或物理宿主独占。下一步应在另行声明的独立hosted诊断中采用相同分量记录;不重复本地批次取绿,不调整原5%护栏,不将本诊断混入原正式样本。 + +相关measurement本地回归36/36(18.660s),新增真实进程/原字节产物边界及固定算例覆盖自身区间外CPU、超时、首错停止、不可覆盖与负余额。首次合成夹具使用venv重定向启动器,暴露了直接子进程与实际解释器的边界;改用实际解释器并核对子PID后验证通过,没有把派生进程CPU算进直接子进程。测试随后限定Windows CPython3.12、1–64逻辑CPU的native诊断;其他支持的环境仍可运行项目普通测试,并跳过这三个专属用例,跳过不表示计量通过。 + +runtime/CPU适用条件修正后的同组回归仍为36/36(17.069s)。实际执行代码与原测量源码哈希保持一致,没有重跑六位置诊断。 + +[归档](evidence.zip)为100053B,SHA256 `9bec0731e08d7f2ef99d140a9e56acbc01468814cc68fb01fbdcfe30eaa8e10c`。内含46份清单证据及`publication.json`,其中16份stdout/stderr按原字节保留(12份观察、4份身份)。路径改为别名,子PID移除;清单分别保留原始/公开大小和SHA,原元数据里的来源哈希不回填成脱敏后哈希。未上传EXE、进程清单、任意环境变量或私有文件;完整本地原件保留。 + +离线复核命令,不执行任何测量: + +```powershell +python experiments/measure/results/2026-10-27-r54-cpu-boundary/verify.py +``` + +完整受控批次、allocator/projection及组件归因、预算提案与用户确认仍未完成;#54、#34与R2保持开放。 diff --git a/experiments/measure/results/2026-10-27-r54-cpu-boundary/evidence.zip b/experiments/measure/results/2026-10-27-r54-cpu-boundary/evidence.zip new file mode 100644 index 0000000000000000000000000000000000000000..0414e68ae633192a4f31cc401099e20274245058 GIT binary patch literal 100053 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 SV+Q>df*y?Gd4eu`!2TbVp(JGh literal 0 HcmV?d00001 diff --git a/experiments/measure/results/2026-10-27-r54-cpu-boundary/validation.json b/experiments/measure/results/2026-10-27-r54-cpu-boundary/validation.json new file mode 100644 index 00000000..8ad4b4e7 --- /dev/null +++ b/experiments/measure/results/2026-10-27-r54-cpu-boundary/validation.json @@ -0,0 +1,422 @@ +{ + "schema": "termforge-r54-cpu-boundary-validation-v1", + "performance_gate": "not_evaluated", + "measured_source": { + "commit": "ff0d7caca138b91683f16ce8d748eea6fbb289b7", + "worktree_status": "", + "sources": { + "experiments/measure/r54_cpu_diagnostic.py": "3071ae52fbddc0e080b586a78837498bdc2105072471ac12c6a48d15f5eb032e", + "experiments/measure/r54_environment.py": "60375a50e83637d27210d5ac0ff958cb0191cb65782fe91e69a741655c1d51f2", + "experiments/measure/r54_batch.py": "b7e19a85797b6d31c22d32eb9878e1975bfe733fdb09aa289da70fe0680e5b68", + "experiments/measure/r54_contract.py": "08c744f3d78e23439fecd8cc01348fdc1673c5397e16738266774fb49fbc76fa", + "experiments/measure/r54_inputs.py": "6e5430681254df364c8abc6b662969ca00991027878708ecdd3ba6f4e96f4eed", + "experiments/measure/run.py": "5643194c95c710790bee3a10e825cd338626222e88a9e2af194ad905b0718852" + } + }, + "measured_tree": "796005cdcd0e330ae86d676ec5386125459d733d", + "baseline": "ed0c12597d3b80a8806b2c6c24032cffaacf0945", + "manifest": { + "schema": "termforge-r54-cpu-diagnostic-v1", + "status": "accounting_complete", + "started_utc": "2026-10-27T12:17:43.046171+00:00", + "performance_gate": "not_evaluated", + "observations": { + "schema": "termforge-r54-cpu-observations-v1", + "status": "accounting_complete", + "started_utc": "2026-10-27T12:17:44.816067+00:00", + "attempted": 6, + "accounted_observations": 6, + "context_sha256": "ad54a604709f4a2f28d2af4349de08ebccf1f30d0f2d2238e5381c3005fd2707", + "protocol_sha256": "c92098b46db730cfd7939163831682e5650ca7c4995da40d13980cf7b355410e", + "performance_gate": "not_evaluated", + "active_sequence": null, + "finished_utc": "2026-10-27T12:17:59.527911+00:00" + }, + "finished_utc": "2026-10-27T12:18:00.346147+00:00" + }, + "environment": { + "host": { + "platform": "Windows-11-10.0.26200-SP0", + "python": "3.12.10", + "psutil": "7.2.2", + "cpu_logical": 8, + "cpu_physical": 8, + "cpu": { + "ProcessorNameString": "Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz", + "Identifier": "Intel64 Family 6 Model 158 Stepping 13" + }, + "windows": { + "CurrentBuildNumber": "26200", + "UBR": 9711, + "DisplayVersion": "25H2" + } + }, + "declaration": { + "host_kind": "shared_workstation", + "known_concurrent_work": [ + "This agent completed the measurement contract tests before this diagnostic and starts no concurrent owned build or test.", + "The user workstation, operating-system services and other applications are not isolated or changed.", + "Guest-visible system CPU is recorded; physical-host contention and clock stability remain unobserved." + ], + "purpose": "One predeclared six-observation CPU-boundary diagnostic, not an idle-qualified cost batch." + }, + "scope": "accounting diagnosis on declared host; no idle qualification or cost acceptance" + }, + "builds": { + "baseline": { + "source": { + "commit": "65988f5f20f62294ff52fcac5b5b81e563f93f3b", + "version": "0.26.1-dev+termforge.3", + "states": { + "project": "11966868740884721388", + "interactive": "8035857386658397897" + } + }, + "binary": { + "bytes": 523264, + "sha256": "33cb90beebffc57f07aa993b8ea635eaf461b49d86c143939a41f6242c087b6d" + }, + "candidate_tree": "38f901ce2407d73ab7d4ae70987c294849bafa92", + "tracked_files": 80 + }, + "candidate": { + "source": { + "commit": "3d6d44d3b3e9a9a3e41da98e8711e9f19a211fd8", + "version": "0.26.1-dev+termforge.4", + "states": { + "project": "16178973312633948535", + "interactive": "6154007251599136798" + } + }, + "binary": { + "bytes": 579584, + "sha256": "d4d068be44a0a9ec733ad17f0323765ee38ffbf775e6efacb4632c1dce6b3f01" + }, + "candidate_tree": "2cce55fcf2d379440110bbbf8612117cce3edf64", + "tracked_files": 84 + } + }, + "observations": [ + { + "item": { + "sequence": 0, + "variant": "baseline", + "route": "interactive", + "chunk": 1 + }, + "exit_code": 0, + "timed_out": false, + "inner_cpu_seconds": 2.125, + "child_cpu": { + "creation_filetime": 134375770648262487, + "exit_filetime": 134375770672853118, + "kernel_seconds": 0.921875, + "user_seconds": 1.28125, + "total_seconds": 2.203125 + }, + "runner_cpu_seconds": 0.0, + "environment": { + "total_seconds": 19.625, + "busy_seconds": 12.0, + "busy_percent": 61.146496815286625, + "before": { + "user": 4467.78125, + "kernel_including_idle": 24590.65625, + "idle": 19905.25, + "system": 4685.40625, + "perf_counter_seconds": 3632.723437, + "utc": "2026-10-27T12:17:44.825276+00:00" + }, + "after": { + "user": 4474.515625, + "kernel_including_idle": 24603.546875, + "idle": 19912.875, + "system": 4690.671875, + "perf_counter_seconds": 3635.1845603, + "utc": "2026-10-27T12:17:47.286686+00:00" + } + }, + "accounting": { + "inner_only_balance_seconds": 9.875, + "inner_only_balance_percent": 50.318471337579616, + "child_outside_inner_seconds": 0.078125, + "runner_cpu_seconds": 0.0, + "unassigned_balance_seconds": 9.796875, + "unassigned_balance_percent": 49.9203821656051 + }, + "state_fnv1a64": "8035857386658397897" + }, + { + "item": { + "sequence": 1, + "variant": "candidate", + "route": "interactive", + "chunk": 1 + }, + "exit_code": 0, + "timed_out": false, + "inner_cpu_seconds": 2.140625, + "child_cpu": { + "creation_filetime": 134375770673032344, + "exit_filetime": 134375770697758213, + "kernel_seconds": 0.625, + "user_seconds": 1.609375, + "total_seconds": 2.234375 + }, + "runner_cpu_seconds": 0.015625, + "environment": { + "total_seconds": 19.875, + "busy_seconds": 11.109375, + "busy_percent": 55.89622641509434, + "before": { + "user": 4474.515625, + "kernel_including_idle": 24603.671875, + "idle": 19912.96875, + "system": 4690.703125, + "perf_counter_seconds": 3635.2004591, + "utc": "2026-10-27T12:17:47.302400+00:00" + }, + "after": { + "user": 4480.765625, + "kernel_including_idle": 24617.296875, + "idle": 19921.734375, + "system": 4695.5625, + "perf_counter_seconds": 3637.6748693, + "utc": "2026-10-27T12:17:49.776942+00:00" + } + }, + "accounting": { + "inner_only_balance_seconds": 8.96875, + "inner_only_balance_percent": 45.125786163522015, + "child_outside_inner_seconds": 0.09375, + "runner_cpu_seconds": 0.015625, + "unassigned_balance_seconds": 8.859375, + "unassigned_balance_percent": 44.575471698113205 + }, + "state_fnv1a64": "6154007251599136798" + }, + { + "item": { + "sequence": 2, + "variant": "candidate", + "route": "interactive", + "chunk": 1 + }, + "exit_code": 0, + "timed_out": false, + "inner_cpu_seconds": 2.203125, + "child_cpu": { + "creation_filetime": 134375770697951230, + "exit_filetime": 134375770722075739, + "kernel_seconds": 0.828125, + "user_seconds": 1.46875, + "total_seconds": 2.296875 + }, + "runner_cpu_seconds": 0.0, + "environment": { + "total_seconds": 19.25, + "busy_seconds": 8.953125, + "busy_percent": 46.50974025974026, + "before": { + "user": 4480.796875, + "kernel_including_idle": 24617.390625, + "idle": 19921.8125, + "system": 4695.578125, + "perf_counter_seconds": 3637.6917606, + "utc": "2026-10-27T12:17:49.793919+00:00" + }, + "after": { + "user": 4485.46875, + "kernel_including_idle": 24631.96875, + "idle": 19932.109375, + "system": 4699.859375, + "perf_counter_seconds": 3640.1066225, + "utc": "2026-10-27T12:17:52.208557+00:00" + } + }, + "accounting": { + "inner_only_balance_seconds": 6.75, + "inner_only_balance_percent": 35.064935064935064, + "child_outside_inner_seconds": 0.09375, + "runner_cpu_seconds": 0.0, + "unassigned_balance_seconds": 6.65625, + "unassigned_balance_percent": 34.577922077922075 + }, + "state_fnv1a64": "6154007251599136798" + }, + { + "item": { + "sequence": 3, + "variant": "baseline", + "route": "interactive", + "chunk": 1 + }, + "exit_code": 0, + "timed_out": false, + "inner_cpu_seconds": 2.15625, + "child_cpu": { + "creation_filetime": 134375770722276046, + "exit_filetime": 134375770746664698, + "kernel_seconds": 0.75, + "user_seconds": 1.515625, + "total_seconds": 2.265625 + }, + "runner_cpu_seconds": 0.015625, + "environment": { + "total_seconds": 19.625, + "busy_seconds": 11.625, + "busy_percent": 59.23566878980892, + "before": { + "user": 4485.5, + "kernel_including_idle": 24632.0625, + "idle": 19932.171875, + "system": 4699.890625, + "perf_counter_seconds": 3640.1245048, + "utc": "2026-10-27T12:17:52.226226+00:00" + }, + "after": { + "user": 4491.75, + "kernel_including_idle": 24645.4375, + "idle": 19940.171875, + "system": 4705.265625, + "perf_counter_seconds": 3642.5663847, + "utc": "2026-10-27T12:17:54.668146+00:00" + } + }, + "accounting": { + "inner_only_balance_seconds": 9.46875, + "inner_only_balance_percent": 48.2484076433121, + "child_outside_inner_seconds": 0.109375, + "runner_cpu_seconds": 0.015625, + "unassigned_balance_seconds": 9.34375, + "unassigned_balance_percent": 47.611464968152866 + }, + "state_fnv1a64": "8035857386658397897" + }, + { + "item": { + "sequence": 4, + "variant": "baseline", + "route": "interactive", + "chunk": 1 + }, + "exit_code": 0, + "timed_out": false, + "inner_cpu_seconds": 2.125, + "child_cpu": { + "creation_filetime": 134375770746872014, + "exit_filetime": 134375770770988460, + "kernel_seconds": 0.578125, + "user_seconds": 1.625, + "total_seconds": 2.203125 + }, + "runner_cpu_seconds": 0.0, + "environment": { + "total_seconds": 19.25, + "busy_seconds": 9.5625, + "busy_percent": 49.675324675324674, + "before": { + "user": 4491.78125, + "kernel_including_idle": 24645.53125, + "idle": 19940.25, + "system": 4705.28125, + "perf_counter_seconds": 3642.5841586, + "utc": "2026-10-27T12:17:54.685918+00:00" + }, + "after": { + "user": 4497.65625, + "kernel_including_idle": 24658.90625, + "idle": 19949.9375, + "system": 4708.96875, + "perf_counter_seconds": 3644.9979968, + "utc": "2026-10-27T12:17:57.098922+00:00" + } + }, + "accounting": { + "inner_only_balance_seconds": 7.4375, + "inner_only_balance_percent": 38.63636363636363, + "child_outside_inner_seconds": 0.078125, + "runner_cpu_seconds": 0.0, + "unassigned_balance_seconds": 7.359375, + "unassigned_balance_percent": 38.23051948051948 + }, + "state_fnv1a64": "8035857386658397897" + }, + { + "item": { + "sequence": 5, + "variant": "candidate", + "route": "interactive", + "chunk": 1 + }, + "exit_code": 0, + "timed_out": false, + "inner_cpu_seconds": 2.03125, + "child_cpu": { + "creation_filetime": 134375770771152026, + "exit_filetime": 134375770795208267, + "kernel_seconds": 0.953125, + "user_seconds": 1.15625, + "total_seconds": 2.109375 + }, + "runner_cpu_seconds": 0.015625, + "environment": { + "total_seconds": 19.25, + "busy_seconds": 11.9375, + "busy_percent": 62.01298701298701, + "before": { + "user": 4497.65625, + "kernel_including_idle": 24659.03125, + "idle": 19950.03125, + "system": 4709.0, + "perf_counter_seconds": 3645.0124583, + "utc": "2026-10-27T12:17:57.114619+00:00" + }, + "after": { + "user": 4503.953125, + "kernel_including_idle": 24671.984375, + "idle": 19957.34375, + "system": 4714.640625, + "perf_counter_seconds": 3647.4196989, + "utc": "2026-10-27T12:17:59.521405+00:00" + } + }, + "accounting": { + "inner_only_balance_seconds": 9.90625, + "inner_only_balance_percent": 51.46103896103896, + "child_outside_inner_seconds": 0.078125, + "runner_cpu_seconds": 0.015625, + "unassigned_balance_seconds": 9.8125, + "unassigned_balance_percent": 50.97402597402598 + }, + "state_fnv1a64": "6154007251599136798" + } + ], + "formal_cost_samples": 0, + "old_hosted_event_cause": "unknown", + "archive": { + "bytes": 100053, + "sha256": "9bec0731e08d7f2ef99d140a9e56acbc01468814cc68fb01fbdcfe30eaa8e10c", + "inventory_files": 46, + "byte_exact_streams": 16, + "path_prefixes_aliased": true, + "child_pid_omitted": true + }, + "local_tests": { + "before_measurement": { + "count": 36, + "seconds": 18.66 + }, + "after_test_runtime_boundary_fix": { + "count": 36, + "seconds": 17.069, + "log_sha256": "e3ab51e002dd2446be8ee34943895825e433197f5d7bff6338b4cf5c3763edf7" + } + }, + "limits": [ + "Shared host, no idle qualification and no performance ratios.", + "Residual includes possible other guest activity, counter quantization and non-atomic endpoints.", + "New instrumentation does not recreate missing whole-child counters for the old hosted failure.", + "Full controlled batches, wrapper/projection and component attribution, budget proposal and user confirmation remain incomplete." + ] +} diff --git a/experiments/measure/results/2026-10-27-r54-cpu-boundary/verify.py b/experiments/measure/results/2026-10-27-r54-cpu-boundary/verify.py new file mode 100644 index 00000000..f60f9e5a --- /dev/null +++ b/experiments/measure/results/2026-10-27-r54-cpu-boundary/verify.py @@ -0,0 +1,73 @@ +"""Recheck retained synthetic evidence without extracting files or launching a cost run.""" +import hashlib +import json +from pathlib import Path +import sys +import zipfile + +ROOT = Path(__file__).resolve().parents[4] +sys.path.insert(0, str(ROOT)) +from experiments.measure.r54_contract import validate_sample + + +def verify(): + path = Path(__file__).with_name('evidence.zip') + assert hashlib.sha256(path.read_bytes()).hexdigest() == '9bec0731e08d7f2ef99d140a9e56acbc01468814cc68fb01fbdcfe30eaa8e10c' + with zipfile.ZipFile(path) as archive: + read = lambda name: json.loads(archive.read(name)) + inventory = read('publication.json')['files'] + assert len(archive.namelist()) == 47 + assert len({row['path'] for row in inventory}) == 46 + assert set(archive.namelist()) == {row['path'] for row in inventory} | {'publication.json'} + for row in inventory: + data = archive.read(row['path']) + assert len(data) == row['published_bytes'] + assert hashlib.sha256(data).hexdigest() == row['published_sha256'] + if row['treatment'] == 'byte_exact_owned_synthetic_stream': + assert row['published_sha256'] == row['original_sha256'] + assert read('manifest.json')['status'] == 'accounting_complete' + manifest = read('observations/manifest.json') + assert manifest['attempted'] == manifest['accounted_observations'] == 6 + assert manifest['performance_gate'] == 'not_evaluated' + builds = read('binding.json')['builds'] + prior = json.loads((path.parent.parent / '2026-10-27-r54-runner/validation.json').read_text(encoding='utf-8')) + for variant in ('baseline', 'candidate'): + assert builds[variant]['binary'] == prior['builds'][variant]['binary'] + assert builds[variant]['source']['commit'] == prior['builds'][variant]['source'] + for index, variant in enumerate(('baseline', 'candidate', 'candidate', 'baseline', 'baseline', 'candidate')): + prefix = f'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'] + assert 'child_pid' not in row + for name in ('stdout.bin', 'stderr.bin'): + data = archive.read(prefix + name) + assert len(data) == row['streams'][name]['bytes'] + assert hashlib.sha256(data).hexdigest() == row['streams'][name]['sha256'] + raw = read(prefix + 'stdout.bin') + assert raw == row['result'] + validate_sample(raw, row['item']) + env, child = row['environment'], row['child_cpu'] + 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 + assert abs(total - env['total_seconds']) < 1e-8 + assert child['total_seconds'] == child['kernel_seconds'] + child['user_seconds'] + assert child['exit_filetime'] > child['creation_filetime'] + runner = row['runner_cpu_after_seconds'] - row['runner_cpu_before_seconds'] + assert runner == row['runner_cpu_seconds'] + accounted = row['accounting'] + inner = raw['interval_cpu_seconds'] + assert child['total_seconds'] >= inner + assert accounted['child_outside_inner_seconds'] == child['total_seconds'] - inner + assert accounted['inner_only_balance_seconds'] == busy - inner + assert accounted['runner_cpu_seconds'] == runner + assert accounted['unassigned_balance_seconds'] == busy - child['total_seconds'] - runner + assert abs(accounted['unassigned_balance_percent'] - accounted['unassigned_balance_seconds'] * 100 / total) < 1e-8 + return dict(files=47, hashed_evidence=46, byte_exact_streams=16, observations=6, + oracles_passed=6, accepted_cost_samples=0, performance_gate='not_evaluated') + + +if __name__ == '__main__': + print(json.dumps(verify())) diff --git a/experiments/measure/test_r54_cpu_diagnostic.py b/experiments/measure/test_r54_cpu_diagnostic.py new file mode 100644 index 00000000..d97220ac --- /dev/null +++ b/experiments/measure/test_r54_cpu_diagnostic.py @@ -0,0 +1,98 @@ +"""Process/artifact boundary tests; synthetic CPU work is not a core benchmark.""" +import json +import os +from pathlib import Path +import sys +import tempfile +import unittest + + +class AccountingTests(unittest.TestCase): + def test_own_interval_excluded_cpu_is_separated_and_negative_balance_is_retained(self): + from experiments.measure.r54_cpu_diagnostic import partition_cpu + record = dict(environment=dict(total_seconds=10, busy_seconds=3), + child_cpu=dict(total_seconds=2.25), runner_cpu_seconds=.125) + value = partition_cpu(record, 2) + self.assertEqual(value['inner_only_balance_seconds'], 1) + self.assertEqual(value['child_outside_inner_seconds'], .25) + self.assertEqual(value['unassigned_balance_seconds'], .625) + self.assertEqual(value['unassigned_balance_percent'], 6.25) + record['environment']['busy_seconds'] = 2.25 + self.assertEqual(partition_cpu(record, 2)['unassigned_balance_seconds'], -.125) + with self.assertRaises(ValueError): + partition_cpu(record, 3) + for invalid in (float('nan'), float('inf'), -1): + record['runner_cpu_seconds'] = invalid + with self.assertRaises(ValueError): + partition_cpu(record, 2) + + +def native_environment_supported(): + if os.name != 'nt' or sys.implementation.name != 'cpython' or sys.version_info[:2] != (3, 12): + return False + import psutil + return 0 < (psutil.cpu_count() or 0) <= 64 + + +@unittest.skipUnless(native_environment_supported(), 'native diagnostic requires Windows CPython 3.12, 1..64 CPUs') +class ProcessAccountingTests(unittest.TestCase): + def test_lifetime_cpu_includes_work_outside_child_reported_interval(self): + from experiments.measure.r54_cpu_diagnostic import capture_cpu + code = '''import json,os,time +def burn(seconds): + start=time.process_time() + while time.process_time()-start < seconds: + pass +burn(.15) +start=time.process_time() +burn(.05) +inner=time.process_time()-start +burn(.15) +print(json.dumps({'inner_cpu':inner,'pid':os.getpid()})) +''' + with tempfile.TemporaryDirectory() as folder: + # A Windows venv executable is a redirector which starts another + # process. Use the actual interpreter to test the direct-child seam. + result = capture_cpu([sys._base_executable, '-c', code], Path(folder), timeout=5) + self.assertEqual(result['exit_code'], 0, result) + self.assertNotIn('error', result) + child = json.loads((Path(folder) / 'stdout.bin').read_bytes()) + self.assertEqual(result['child_pid'], child['pid']) + self.assertGreaterEqual(result['child_cpu']['total_seconds'] - child['inner_cpu'], .29) + self.assertGreater(result['child_cpu']['exit_filetime'], result['child_cpu']['creation_filetime']) + self.assertGreater(result['environment']['total_seconds'], 0) + self.assertGreaterEqual(result['runner_cpu_seconds'], 0) + + def test_timeout_retains_partial_streams_and_exited_child_accounting(self): + from experiments.measure.r54_cpu_diagnostic import capture_cpu + code = "import os,time; os.write(1,b'partial\\xff'); os.write(2,b'error\\xfe'); time.sleep(10)" + with tempfile.TemporaryDirectory() as folder: + result = capture_cpu([sys._base_executable, '-c', code], Path(folder), timeout=1) + self.assertTrue(result['timed_out']) + self.assertIsNotNone(result['exit_code']) + self.assertGreater(result['child_cpu']['exit_filetime'], 0) + self.assertEqual((Path(folder) / 'stdout.bin').read_bytes(), b'partial\xff') + self.assertEqual((Path(folder) / 'stderr.bin').read_bytes(), b'error\xfe') + + def test_bad_output_stops_diagnostic_without_overwrite_or_cost_summary(self): + from experiments.measure.r54_cpu_diagnostic import run_observations + command = [sys._base_executable, '-c', "import os; os.write(1,b'bad\\xff')"] + with tempfile.TemporaryDirectory() as folder: + output = Path(folder) / 'observations' + context = {'evidence_kind': 'synthetic_process_fixture'} + result = run_observations({name: command for name in ('baseline', 'candidate')}, output, context) + self.assertEqual(result['status'], 'failed') + self.assertEqual(result['attempted'], 1) + self.assertEqual(result['accounted_observations'], 0) + self.assertEqual((output / '000/stdout.bin').read_bytes(), b'bad\xff') + self.assertFalse((output / '001').exists()) + self.assertFalse((output / 'summary.json').exists()) + self.assertEqual(result['performance_gate'], 'not_evaluated') + original = (output / 'manifest.json').read_bytes() + with self.assertRaises(FileExistsError): + run_observations({name: command for name in ('baseline', 'candidate')}, output, context) + self.assertEqual((output / 'manifest.json').read_bytes(), original) + + +if __name__ == '__main__': + unittest.main() From beeb64496b2e2898e8619fa5e9c39f490a3891c4 Mon Sep 17 00:00:00 2001 From: JavaZero <71128095+JavaZeroo@users.noreply.github.com> Date: Tue, 27 Oct 2026 20:42:50 +0800 Subject: [PATCH 2/2] ci: install pinned CPU observer for candidate contracts (#54) Preserve the first missing-psutil CI failures. Clean Python reproduces the error; fixed requirements give 4/4 native/accounting and 36/36 measurement tests. Reviewed local commit: 769c84eba37a4ab49ac0abf7d6402596123c4db1. Measurement code and retained six observations are unchanged. --- .github/workflows/core-candidate.yml | 2 ++ .../2026-10-27-r54-cpu-boundary/README.md | 2 ++ .../validation.json | 33 ++++++++++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/.github/workflows/core-candidate.yml b/.github/workflows/core-candidate.yml index 0b8d962c..5f1ba36b 100644 --- a/.github/workflows/core-candidate.yml +++ b/.github/workflows/core-candidate.yml @@ -56,6 +56,8 @@ jobs: python-version: '3.12' - name: Install fixed semantic references run: python -m pip install --require-hashes -r experiments/differential/requirements.txt + - name: Install fixed CPU observer + run: python -m pip install -r benchmarks/requirements.txt - name: Select fixed Rust toolchain run: rustup default 1.92.0 - name: Build locked candidate diff --git a/experiments/measure/results/2026-10-27-r54-cpu-boundary/README.md b/experiments/measure/results/2026-10-27-r54-cpu-boundary/README.md index 34a93f29..338d62ab 100644 --- a/experiments/measure/results/2026-10-27-r54-cpu-boundary/README.md +++ b/experiments/measure/results/2026-10-27-r54-cpu-boundary/README.md @@ -23,6 +23,8 @@ runtime/CPU适用条件修正后的同组回归仍为36/36(17.069s)。实际执行代码与原测量源码哈希保持一致,没有重跑六位置诊断。 +首次发布 `c76bab0` 的默认[PR](https://github.com/JavaZeroo/termforge/actions/runs/40504397868)/[push](https://github.com/JavaZeroo/termforge/actions/runs/40504336483)均通过(Windows46/46、Linux29/29);候选[PR](https://github.com/JavaZeroo/termforge/actions/runs/40504397941)/[push](https://github.com/JavaZeroo/termforge/actions/runs/40504336888)的Linux measurement为41通过/4跳过,Windows因未安装`psutil`在导入新测试时失败。原失败保留;修正候选工作流安装仓库已有固定`benchmarks/requirements.txt`,不跳过缺少依赖的测试。干净Python环境复现同一缺包错误,安装后4个新测试通过(1.583s)。修订CI单独跟踪,不将原两条候选失败写成通过。 + [归档](evidence.zip)为100053B,SHA256 `9bec0731e08d7f2ef99d140a9e56acbc01468814cc68fb01fbdcfe30eaa8e10c`。内含46份清单证据及`publication.json`,其中16份stdout/stderr按原字节保留(12份观察、4份身份)。路径改为别名,子PID移除;清单分别保留原始/公开大小和SHA,原元数据里的来源哈希不回填成脱敏后哈希。未上传EXE、进程清单、任意环境变量或私有文件;完整本地原件保留。 离线复核命令,不执行任何测量: diff --git a/experiments/measure/results/2026-10-27-r54-cpu-boundary/validation.json b/experiments/measure/results/2026-10-27-r54-cpu-boundary/validation.json index 8ad4b4e7..20b89e3e 100644 --- a/experiments/measure/results/2026-10-27-r54-cpu-boundary/validation.json +++ b/experiments/measure/results/2026-10-27-r54-cpu-boundary/validation.json @@ -418,5 +418,36 @@ "Residual includes possible other guest activity, counter quantization and non-atomic endpoints.", "New instrumentation does not recreate missing whole-child counters for the old hosted failure.", "Full controlled batches, wrapper/projection and component attribution, budget proposal and user confirmation remain incomplete." - ] + ], + "initial_ci": { + "source": "c76bab0281843fca298af8b0d9ba521247ac745a", + "all_attempts": 1, + "default_pr": { + "run": 40504397868, + "status": "success", + "windows": 46, + "linux": 29 + }, + "default_push": { + "run": 40504336483, + "status": "success", + "windows": 46, + "linux": 29 + }, + "candidate_pr": { + "run": 40504397941, + "status": "failure", + "windows_failure": "ModuleNotFoundError: No module named psutil", + "linux_passed": 41, + "linux_skipped": 4 + }, + "candidate_push": { + "run": 40504336888, + "status": "failure", + "windows_failure": "ModuleNotFoundError: No module named psutil", + "linux_passed": 41, + "linux_skipped": 4 + }, + "fix": "Install the existing pinned benchmarks/requirements.txt in candidate CI; no measurement source or observation change." + } }