mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
perf(entropy): separate physical reads from report resolution (#6950)
* perf(entropy): separate physical reads from report blocks * test(entropy): type the injected positional short-read boundary * test(entropy): retain full catalog transport capacity in task probe * docs(perf): record real entropy task costs and limits * docs(perf): record latest-main entropy qualification
This commit is contained in:
1 parent
b869fa762a
commit
b5c42dfc2a
7 files changed
+1973
-7
No files matched your search
@@ -0,0 +1,94 @@
|
||||
"""Verify 18 completed entropy tasks and report whole-task resource/token costs."""
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
import hashlib, json, statistics
|
||||
import tiktoken
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--receipts', type=Path, required=True)
|
||||
parser.add_argument('--output', type=Path, required=True)
|
||||
options = parser.parse_args()
|
||||
b = options.receipts
|
||||
cohort = b / 'cohort'
|
||||
index = json.loads((cohort / 'index.json').read_text())
|
||||
assert len(index) == 18 and all((r['exit'] == 0 for r in index))
|
||||
assert len({item['name'] for item in index}) == 18
|
||||
enc = tiktoken.get_encoding('cl100k_base')
|
||||
compact = lambda d: json.dumps(d, ensure_ascii=False, separators=(',', ':'), allow_nan=False)
|
||||
count = lambda s: len(enc.encode(s, disallowed_special=()))
|
||||
digest = lambda p: hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
rows = []
|
||||
for item in index:
|
||||
p = cohort / item['name']
|
||||
r = json.loads((p / 'report.json').read_text())
|
||||
catalog = json.loads((p / 'catalog.json').read_text())
|
||||
tx = json.loads((p / 'transcript.json').read_text())
|
||||
scope = next((json.loads(l) for l in reversed((cohort / (item['name'] + '.log')).read_text().splitlines()) if l.startswith('{"resource_scope":')))
|
||||
obs = scope['payload_resource_observation']
|
||||
events = obs['resource_events']
|
||||
assert r['oracle_sha256'] == digest(b / f"{item['case']}-oracle.json")
|
||||
assert item['exit'] == 0 and r['status'] == 'passed' and r['complete_source_export_verified'] and (not r['cleanup_failures']) and (not r['receipt_failures'])
|
||||
assert scope['abort'] is None and scope['payload_resource_observation_verified'] and (obs['payload_exit_code'] == 0) and obs['payload_cleanup_verified']
|
||||
assert all((events['memory.events'][k] == 0 for k in ['high', 'max', 'oom', 'oom_kill'])) and events['pids.events']['max'] == 0
|
||||
assert [e['name'] for e in tx] == ['inspect_byte_entropy', 'export_evidence_bundle']
|
||||
assert all((not e['reply'].get('isError', False) for e in tx))
|
||||
inp = count(compact([{k: t[k] for k in ['name', 'description', 'inputSchema']} for t in catalog['tools']]))
|
||||
args = sum((count(compact({'name': e['name'], 'arguments': e['input']})) for e in tx))
|
||||
replies = sum((count(c['text']) for e in tx for c in e['reply']['content'] if c['type'] == 'text'))
|
||||
prompt = count(r['question'])
|
||||
instructions = count(r['server_instructions'])
|
||||
rows.append({
|
||||
**item,
|
||||
'catalog_tools': len(catalog['tools']),
|
||||
'catalog_sha256': digest(p / 'catalog.json'),
|
||||
'parent_evidence_id': r['parent_evidence_id'],
|
||||
'source_report_sha256': r['source_report_sha256'],
|
||||
'runtime_identity_sha256': r['runtime_identity_sha256'],
|
||||
'wall_seconds': scope['elapsed_seconds'],
|
||||
'cpu_seconds': obs['cpu_stat']['usage_usec'] / 1000000.0,
|
||||
'kernel_family_peak_bytes': obs['memory_peak_bytes'],
|
||||
'inspection_ms': r['calls'][0]['elapsed_ms'],
|
||||
'discovery_ms': r['phases']['discovery_ms'],
|
||||
'token_estimate': {
|
||||
'question': prompt,
|
||||
'instructions': instructions,
|
||||
'directory_once': inp,
|
||||
'arguments': args,
|
||||
'text_replies': replies,
|
||||
'whole_task': prompt + instructions + inp + args + replies,
|
||||
'raw_catalog': count(compact(catalog)),
|
||||
},
|
||||
'receipt_sha256': {n: digest(p / n) for n in ['report.json', 'transcript.json', 'catalog.json', 'source.evidence.json']},
|
||||
'payload_exit_events': events,
|
||||
'payload_cleanup_verified': True,
|
||||
'whole_scope_events_final': scope['resource_events_final'],
|
||||
})
|
||||
summary = {}
|
||||
for case in ['llvm-small-block', 'llvm-large-block', 'ls']:
|
||||
rs = [r for r in rows if r['case'] == case]
|
||||
for k in ['catalog_sha256', 'source_report_sha256', 'parent_evidence_id']:
|
||||
assert len({r[k] for r in rs}) == 1, (case, k)
|
||||
summary[case] = {}
|
||||
for lane in ['before', 'after']:
|
||||
ls = [r for r in rs if r['lane'] == lane]
|
||||
assert len(ls) == 3
|
||||
assert {r['repeat'] for r in ls} == {1, 2, 3}
|
||||
metrics = {k: [r[k] for r in ls] for k in ['wall_seconds', 'cpu_seconds', 'kernel_family_peak_bytes', 'inspection_ms', 'discovery_ms']}
|
||||
metrics['whole_task_tokens'] = [r['token_estimate']['whole_task'] for r in ls]
|
||||
summary[case][lane] = {k: {'median': statistics.median(v), 'min': min(v), 'max': max(v)} for k, v in metrics.items()}
|
||||
identities = {lane: json.loads((b / f'{lane}-runtime-identity.json').read_text()) for lane in ['before', 'after']}
|
||||
assert all(identity['source_clean'] for identity in identities.values())
|
||||
for row in rows:
|
||||
assert row['runtime_identity_sha256'] == digest(b / f"{row['lane']}-runtime-identity.json")
|
||||
result = {
|
||||
'tiktoken': tiktoken.__version__,
|
||||
'encoding': enc.name,
|
||||
'actual_model_usage': None,
|
||||
'revisions': {l: i['source_revision'] for l, i in identities.items()},
|
||||
'identity_receipts': {l: digest(b / f'{l}-runtime-identity.json') for l in identities},
|
||||
'oracles': {c: {'sha256': digest(b / f'{c}-oracle.json'), 'artifact': json.loads((b / f'{c}-oracle.json').read_text())['expected']['artifact']} for c in summary},
|
||||
'summary': summary,
|
||||
'recordings': rows,
|
||||
'measurement': 'Three alternating fresh production stdio SDK sessions per lane/case; exact discovered toolDefinition/default validator, fresh HOME, Node compile cache disabled, OS caches unflushed. Each task discovers complete catalog, inspects bytes and exports/compares full source Evidence; all oracle facts checked. Whole process-family CPU and kernel peak include client/server, runtime fingerprint verification, serialization, export and cleanup. Oracle generation and tokenization outside measured tasks. One-CPU quota, 3GiB early stop/4GiB hard/no swap; payload exit/cleanup/events verified, final whole-scope counters unavailable. Token serialization estimate includes question/instructions/all input name+description+schema once/all arguments/all text replies, raw catalog separately. Host framing, replay, model inference quality and billing unmeasured.',
|
||||
}
|
||||
options.output.write_text(json.dumps(result, indent=2) + '\n')
|
||||
print(json.dumps(summary, indent=2))
|
||||
@@ -0,0 +1,56 @@
|
||||
"""Independent Python histogram oracle; reads artifact bytes without execution."""
|
||||
import argparse
|
||||
from collections import Counter
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
from pathlib import Path
|
||||
|
||||
def entropy(counts, size):
|
||||
if not size:
|
||||
return 0
|
||||
value = -sum((counts[k] / size) * math.log2(counts[k] / size) for k in sorted(counts) if counts[k])
|
||||
return math.floor(value * 10000 + 0.5) / 10000
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--path', required=True)
|
||||
parser.add_argument('--output', required=True)
|
||||
parser.add_argument('--block-size', type=int, required=True)
|
||||
parser.add_argument('--offset', type=int, default=0)
|
||||
parser.add_argument('--length', type=int)
|
||||
args = parser.parse_args()
|
||||
path = Path(args.path)
|
||||
before = path.stat()
|
||||
counts = Counter()
|
||||
digest = hashlib.sha256()
|
||||
with path.open('rb') as source:
|
||||
while chunk := source.read(1024 * 1024):
|
||||
digest.update(chunk)
|
||||
counts.update(chunk)
|
||||
length = args.length if args.length is not None else before.st_size - args.offset
|
||||
assert 0 <= args.offset <= before.st_size and 0 <= length <= before.st_size - args.offset
|
||||
blocks, runs = [], []
|
||||
source.seek(args.offset)
|
||||
for offset in range(args.offset, args.offset + length, args.block_size):
|
||||
chunk = source.read(min(args.block_size, args.offset + length - offset))
|
||||
value = entropy(Counter(chunk), len(chunk))
|
||||
block = {'offset': offset, 'length': len(chunk), 'entropy': value}
|
||||
blocks.append(block)
|
||||
classification = 'high' if value >= 7.2 else 'low' if value <= 1 else None
|
||||
if classification is not None:
|
||||
if runs and runs[-1]['classification'] == classification and runs[-1]['offset'] + runs[-1]['length'] == offset:
|
||||
runs[-1]['length'] += len(chunk)
|
||||
else:
|
||||
runs.append({'offset': offset, 'length': len(chunk), 'classification': classification})
|
||||
after = path.stat()
|
||||
assert (before.st_dev, before.st_ino, before.st_size, before.st_mtime_ns, before.st_ctime_ns) == (after.st_dev, after.st_ino, after.st_size, after.st_mtime_ns, after.st_ctime_ns)
|
||||
expected = {'artifact': {'path': args.path, 'bytes': before.st_size, 'sha256': digest.hexdigest()}, 'block_size':args.block_size,'window':{'offset':args.offset,'length':length},'file_entropy':entropy(counts,before.st_size),'thresholds':{'high':7.2,'low':1},'blocks':blocks,'runs':runs}
|
||||
request = {'path':args.path,'block_size':args.block_size,'offset':args.offset}
|
||||
if args.length is not None:
|
||||
request['length'] = args.length
|
||||
Path(args.output).write_text(json.dumps({'input':request,'expected':expected},indent=2)+'\n')
|
||||
print(json.dumps({'path':args.path,'sha256':digest.hexdigest(),'blocks':len(blocks),'runs':len(runs)}))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,158 @@
|
||||
# Byte entropy: separate physical reads from report resolution
|
||||
|
||||
Issue: [#6947](https://github.com/morluto/rea/issues/6947).
|
||||
|
||||
The question is to return the full-file SHA-256 and entropy, every block in a
|
||||
selected byte window, and adjacent high/low runs, preserving complete source
|
||||
Evidence. `ByteEntropyService` previously used `block_size` for both reporting
|
||||
and physical reads, including outside the selected window. Small report blocks
|
||||
therefore caused hundreds of thousands of asynchronous reads of a large file.
|
||||
|
||||
The shared service now fills a bounded 64 KiB buffer before calculating the
|
||||
caller-selected blocks. Supported power-of-two block sizes divide that buffer;
|
||||
the window starts its own block sequence, and only its final block can be short.
|
||||
Short physical reads are joined before interpretation. The same stable-file,
|
||||
whole-file hash, cancellation, capacity and descriptor-cleanup owners remain.
|
||||
No new cache, parser, contract or output selection is introduced.
|
||||
|
||||
## Fixed comparison
|
||||
|
||||
Baseline: `1d896e03b776453282beca7fd89338be778bfca2`.
|
||||
Measured implementation: `3ed3276d0ee79c291e1006901ace5b06626c1d4e`.
|
||||
Both were clean and built with Node 24.22.1, npm 11.16.0 and SDK 2.3.1.
|
||||
The runtime receipt fingerprints 2,582 compiled/catalog/entrypoint/dependency
|
||||
and driver files in each lane, checked before and after every task.
|
||||
|
||||
Real artifacts are installed Linux x64 binaries, inspected without execution:
|
||||
|
||||
| Artifact | Bytes | SHA-256 |
|
||||
| ----------------------------------------------------- | ----------: | ------------------------------------------------------------------ |
|
||||
| LLVM 16 (`/usr/lib/x86_64-linux-gnu/libLLVM-16.so.1`) | 123,379,936 | `f62d254b7f2bf42df8c8b07d46ee3bb4c2cafeca436b2e6bc6ccbe4581f58f40` |
|
||||
| GNU ls (`/usr/bin/ls`) | 151,344 | `cb30d69b24245bf2ecdc9e7f53bbad19159999970b6d82c0c00c7d32d9e37aa4` |
|
||||
|
||||
`byte-entropy-oracle.py` independently computes Python byte histograms,
|
||||
Shannon entropy, selected blocks, rounded-value run classifications and digests.
|
||||
It checks file state around its reads. Every returned fact agrees with this
|
||||
oracle, and both lanes have identical complete report hashes and Evidence IDs.
|
||||
|
||||
There are three alternating fresh production stdio MCP sessions per lane/case,
|
||||
18 tasks total. Each discovers all 222 tools, uses exact discovered
|
||||
`toolDefinition` validation, inspects the bytes, exports the complete Evidence
|
||||
bundle and verifies its parent record. Fresh HOME/client/server, Node compile
|
||||
cache disabled, OS caches unflushed. These are fresh sessions; no warm-runtime
|
||||
speedup is claimed. Cached-catalog SDK bulk validation was not measured here.
|
||||
|
||||
| Task (3 samples per lane) | Whole elapsed median, s | Family CPU median, s | Kernel family peak median, MiB | Whole-task estimated tokens |
|
||||
| ----------------------------------------------------------- | ----------------------: | -------------------: | -----------------------------: | --------------------------: |
|
||||
| LLVM: 256-byte blocks, offset 3, length 65,539 (257 blocks) | 29.842 → 8.584 | 25.286 → 6.358 | 629.5 → 672.4 | 62,000 → 62,000 |
|
||||
| LLVM: whole file, 65,536-byte blocks (1,883 blocks) | 12.314 → 12.115 | 7.581 → 7.325 | 667.9 → 674.3 | 91,900 → 91,900 |
|
||||
| ls: whole file, 256-byte blocks (592 blocks) | 7.075 → 8.286 | 5.804 → 5.528 | 659.1 → 659.3 | 67,215 → 67,215 |
|
||||
|
||||
The large fine-resolution task improves elapsed median by 71.2% and CPU by
|
||||
74.9%. Elapsed ranges are 28.541–33.290 → 7.981–10.396 seconds; CPU ranges
|
||||
23.600–25.429 → 6.049–6.633 seconds. Its kernel peak increases by about
|
||||
43 MiB (ranges 620.4–637.5 → 665.7–673.2 MiB). This is a speed/CPU improvement
|
||||
with higher measured peak memory, not a memory optimization.
|
||||
|
||||
The other controls do not establish a stable whole-task speedup. The small
|
||||
file's elapsed median is worse; ranges overlap at 6.469–9.892 → 6.169–9.188
|
||||
seconds. No general latency or memory benefit is claimed. Full-file reading
|
||||
and hashing remain necessary even when the selected window is short or empty.
|
||||
|
||||
A separate single real-file service probe delegated to actual `open/stat/read`
|
||||
while counting reads: 481,955 → 1,885 physical reads of all 123,379,936 bytes,
|
||||
maximum request 256 → 65,536 bytes, service elapsed 17.09 → 1.34 seconds.
|
||||
The complete Evidence objects were equal and independently checked. This probe
|
||||
locates the work removed; it is not the repeated public-task performance table.
|
||||
|
||||
The [machine-readable report](./byte-entropy-reads.json) preserves ranges,
|
||||
per-sample phase timings, calls, receipt hashes, artifact identities and commands.
|
||||
`cl100k_base` via tiktoken 0.14.0 counts the fixed question, server instructions,
|
||||
all tool names/descriptions/input schemas once, every argument and every text
|
||||
reply including export. Input-directory cost is 56,685 tokens; raw catalog with
|
||||
output schemas is separately 838,375. Actual model billing, host framing/replay,
|
||||
model reasoning quality and inference latency were not measured. No token saving
|
||||
is claimed: replies and catalog remain unchanged.
|
||||
|
||||
## Resource and correctness verification
|
||||
|
||||
All tasks ran serially under a one-CPU quota, 3 GiB early memory stop, 4 GiB hard
|
||||
limit, zero swap and 192-task ceiling. Whole process-family CPU and kernel memory
|
||||
peak include client/server, runtime fingerprint reads, serialization, source
|
||||
export and cleanup; kernel peak includes charged file cache. Independent oracle
|
||||
generation and tokenization are outside timed tasks. Payload exits, remaining
|
||||
owned processes and memory/PID-limit events were checked: all task payloads
|
||||
exited 0, cleanup verified, no guard stop/OOM. Final whole-scope counters were
|
||||
unavailable after transient-scope removal and are not represented as verified.
|
||||
|
||||
Executed additional checks:
|
||||
|
||||
- Six real CLI calls (three cases in both lanes): every oracle fact, complete
|
||||
CLI Evidence equality and matching MCP parent identity passed.
|
||||
- 36 tests in four exact source/public-boundary files passed, including short
|
||||
reads, unaligned windows across buffers, partial tails at minimum/intermediate/
|
||||
maximum block sizes, empty windows, cancellation through finalization,
|
||||
identity changes, capacity refusal, retained summaries and cleanup retry.
|
||||
- Six serial static tasks (typecheck, lint including module boundaries, format,
|
||||
knip, metadata and required compilation), plus architecture guards passed.
|
||||
Static family peak was 1.96 GiB; focused-test/preparation peak was 2.15 GiB.
|
||||
- An initial typecheck failure in the new short-read test's injected callback
|
||||
was fixed with an explicitly typed positional boundary. Its failed receipt is
|
||||
retained, not counted as a successful run. Initial local formatter path and
|
||||
early profile verification attempts also failed before their intended checks;
|
||||
corrected checks are recorded separately.
|
||||
|
||||
The public experiments qualify static byte inspection on these Linux files.
|
||||
They do not establish behavior on every filesystem or operating system and do
|
||||
not execute LLVM or ls. CLI/MCP contracts, Evidence fields, input limits and
|
||||
provider authority remain unchanged; generated catalogs and builds are ignored.
|
||||
|
||||
After integrating main `21a20306b`, the six serial static tasks, architecture
|
||||
guards and all 36 focused cases passed again. Three fresh real MCP/source-export
|
||||
tasks and three CLI calls matched every oracle fact and the frozen cohort's
|
||||
report/parent identity. The integrated test/preparation family peaked at
|
||||
2.23 GiB with verified payload exit/cleanup and no guard stop/OOM. These are
|
||||
integration qualification runs; they do not replace the fixed performance pins.
|
||||
The committed cost verifier also reproduced the complete measurement JSON.
|
||||
|
||||
## Reproduction
|
||||
|
||||
Build both pinned checkouts using their locked toolchain, serially. Supply an
|
||||
independent installed dependency tree matching the lock, without upgrading host
|
||||
software. Use the exact artifact digests above. The oracle accepts explicit
|
||||
`--path`, `--block-size`, `--offset`, `--length` and `--output`; omit length for
|
||||
the two whole-file controls. For example:
|
||||
|
||||
```sh
|
||||
python3 experiments/analysis-efficiency/byte-entropy-oracle.py \
|
||||
--path /usr/lib/x86_64-linux-gnu/libLLVM-16.so.1 \
|
||||
--block-size 256 --offset 3 --length 65539 --output /absolute/oracle.json
|
||||
python3 experiments/analysis-efficiency/resource-run.py --observe-payload-exit -- \
|
||||
node experiments/analysis-efficiency/byte-entropy-reads.mjs \
|
||||
--runtime /absolute/pinned-checkout --oracle /absolute/oracle.json \
|
||||
--identity /absolute/runtime-identity.json --output /absolute/new-task-directory
|
||||
```
|
||||
|
||||
Runtime identity JSON contains `source_revision`, `source_clean`,
|
||||
`node_sha256` and `files: [{path, sha256}]` with absolute paths. Fingerprint the
|
||||
entire compiled runtime and catalogs, scripts, lock/toolchain files, actual SDK
|
||||
JavaScript dependencies and the driver/helpers. Both sessions must use the same
|
||||
Node and dependency contents. Use the same one-CPU/memory policy for the harness;
|
||||
the historical runs additionally pinned the payload to CPUs 0–1 and the initial
|
||||
observer to CPU 15. Do not compare an unguarded default-concurrency run as an
|
||||
equivalent resource measurement.
|
||||
|
||||
Retained raw receipts are on the investigation host at
|
||||
`/tmp/rea-perf-byte-entropy-20261024/`. This includes `cohort/index.json`,
|
||||
per-task catalog/transcript/report/source export/guard logs, runtime identities,
|
||||
three oracle JSONs, CLI stdout/stderr, boundary profiles and verification logs.
|
||||
The cost verifier takes that receipt directory and a separate output:
|
||||
|
||||
```sh
|
||||
python3 experiments/analysis-efficiency/byte-entropy-costs.py \
|
||||
--receipts /absolute/receipt-directory --output /absolute/costs.json
|
||||
```
|
||||
|
||||
It requires all 18 successful verified samples, matching parent/report/catalog
|
||||
identity across lanes, successful source exports and oracle/runtime receipts.
|
||||
Failed or stopped attempts cannot enter the published cohort.
|
||||
@@ -0,0 +1,154 @@
|
||||
/** Complete entropy question through production stdio, with full source export. */
|
||||
import assert from "node:assert/strict";
|
||||
import { createHash } from "node:crypto";
|
||||
import { createWriteStream } from "node:fs";
|
||||
import { mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join, resolve } from "node:path";
|
||||
import { finished } from "node:stream/promises";
|
||||
import { parseArgs } from "node:util";
|
||||
import { Client } from "@modelcontextprotocol/client";
|
||||
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
|
||||
import { createRetainedQueryCaller } from "./retained-query-calls.mjs";
|
||||
import { finalizeRetainedQueryReceipt } from "./retained-query-finalization.mjs";
|
||||
|
||||
const { values } = parseArgs({
|
||||
options: Object.fromEntries(
|
||||
["runtime", "oracle", "identity", "output"].map((name) => [
|
||||
name,
|
||||
{ type: "string" },
|
||||
]),
|
||||
),
|
||||
});
|
||||
for (const value of Object.values(values)) assert.equal(value, resolve(value));
|
||||
const sha256 = (value) => createHash("sha256").update(value).digest("hex");
|
||||
const oracleBytes = await readFile(values.oracle);
|
||||
const oracle = JSON.parse(oracleBytes);
|
||||
const identityBytes = await readFile(values.identity);
|
||||
const identity = JSON.parse(identityBytes);
|
||||
await mkdir(values.output, { mode: 0o700 });
|
||||
const account = await mkdtemp(join(tmpdir(), "rea-entropy-task-"));
|
||||
const client = new Client({ name: "entropy-complete-task", version: "1" });
|
||||
const transport = new StdioClientTransport({
|
||||
command: process.execPath,
|
||||
args: [join(values.runtime, "scripts/rea.mjs"), "mcp"],
|
||||
maxBufferSize: 10485760,
|
||||
env: {
|
||||
HOME: account,
|
||||
TMPDIR: account,
|
||||
PATH: process.env.PATH,
|
||||
REA_LOG_LEVEL: "silent",
|
||||
NODE_OPTIONS: "--max-old-space-size=2048",
|
||||
NODE_DISABLE_COMPILE_CACHE: "1",
|
||||
UV_THREADPOOL_SIZE: "2",
|
||||
},
|
||||
stderr: "pipe",
|
||||
});
|
||||
const serverLog = createWriteStream(join(values.output, "server.log"));
|
||||
const serverLogFinished = finished(serverLog);
|
||||
serverLogFinished.catch(() => {});
|
||||
transport.stderr?.pipe(serverLog);
|
||||
const report = {
|
||||
status: "running",
|
||||
question:
|
||||
"Return the file SHA-256, file-wide entropy, every entropy block and adjacent high/low run in the requested byte window; preserve the complete source Evidence.",
|
||||
request: oracle.input,
|
||||
calls: [],
|
||||
phases: {},
|
||||
client:
|
||||
"Production stdio SDK, exact discovered toolDefinition and default validator",
|
||||
runtime_identity_sha256: sha256(identityBytes),
|
||||
oracle_sha256: sha256(oracleBytes),
|
||||
driver_sha256: sha256(await readFile(new URL(import.meta.url))),
|
||||
};
|
||||
const transcript = [];
|
||||
let definitions;
|
||||
const call = createRetainedQueryCaller(
|
||||
{
|
||||
callTool(params, options) {
|
||||
return client.callTool(params, {
|
||||
...options,
|
||||
toolDefinition: definitions.get(params.name),
|
||||
});
|
||||
},
|
||||
},
|
||||
(receipt, event) => {
|
||||
report.calls.push(receipt);
|
||||
transcript.push(event);
|
||||
},
|
||||
);
|
||||
const observe = async (name, args, phase) => {
|
||||
const result = await call(name, args, phase);
|
||||
assert.notEqual(result.isError, true, JSON.stringify(result));
|
||||
assert.ok(result.structuredContent);
|
||||
return result.structuredContent;
|
||||
};
|
||||
const verifyRuntime = async () => {
|
||||
assert.equal(sha256(await readFile(values.oracle)), sha256(oracleBytes));
|
||||
assert.equal(sha256(await readFile(values.identity)), sha256(identityBytes));
|
||||
assert.equal(sha256(await readFile(process.execPath)), identity.node_sha256);
|
||||
assert.equal(
|
||||
sha256(await readFile(new URL(import.meta.url))),
|
||||
report.driver_sha256,
|
||||
);
|
||||
for (const item of identity.files)
|
||||
assert.equal(sha256(await readFile(item.path)), item.sha256, item.path);
|
||||
};
|
||||
try {
|
||||
await verifyRuntime();
|
||||
const start = performance.now();
|
||||
await client.connect(transport);
|
||||
report.server_instructions = client.getInstructions() ?? "";
|
||||
const catalog = await client.listTools();
|
||||
definitions = new Map(catalog.tools.map((tool) => [tool.name, tool]));
|
||||
await writeFile(join(values.output, "catalog.json"), JSON.stringify(catalog));
|
||||
report.phases.discovery_ms = performance.now() - start;
|
||||
const parent = await observe("inspect_byte_entropy", oracle.input, "inspect");
|
||||
for (const [key, value] of Object.entries(oracle.expected))
|
||||
assert.deepEqual(parent.normalized_result[key], value, key);
|
||||
report.parent_evidence_id = parent.evidence_id;
|
||||
report.source_report_sha256 = sha256(
|
||||
JSON.stringify(parent.normalized_result),
|
||||
);
|
||||
report.artifact = parent.normalized_result.artifact;
|
||||
await observe(
|
||||
"export_evidence_bundle",
|
||||
{ path: join(values.output, "source.evidence.json") },
|
||||
"export",
|
||||
);
|
||||
const bundle = JSON.parse(
|
||||
await readFile(join(values.output, "source.evidence.json")),
|
||||
);
|
||||
assert.deepEqual(
|
||||
bundle.records.find((item) => item.evidence_id === parent.evidence_id),
|
||||
parent,
|
||||
);
|
||||
report.complete_source_export_verified = true;
|
||||
report.status = "passed";
|
||||
} catch (cause) {
|
||||
report.status = "failed";
|
||||
report.error = String(cause);
|
||||
} finally {
|
||||
try {
|
||||
await verifyRuntime();
|
||||
} catch (cause) {
|
||||
report.status = "failed";
|
||||
report.identity_failure = String(cause);
|
||||
}
|
||||
await finalizeRetainedQueryReceipt({
|
||||
client,
|
||||
transport,
|
||||
account,
|
||||
serverLog,
|
||||
serverLogFinished,
|
||||
report,
|
||||
transcript,
|
||||
output: values.output,
|
||||
});
|
||||
if (
|
||||
report.status !== "passed" ||
|
||||
report.cleanup_failures.length ||
|
||||
report.receipt_failures.length
|
||||
)
|
||||
process.exitCode = 1;
|
||||
}
|
||||
@@ -38,6 +38,70 @@ it("keeps whole-file identity and entropy while selecting unaligned blocks and a
|
||||
expect(result.value.confidence).toBe("observed");
|
||||
});
|
||||
|
||||
it.each([256, 4096, 65536])(
|
||||
"keeps %i-byte blocks relative to an unaligned window across short physical reads",
|
||||
async (blockSize) => {
|
||||
const root = await createTestTempDirectory("rea-entropy-short-reads-");
|
||||
const path = join(root, "bytes");
|
||||
const bytes = Buffer.from(
|
||||
Array.from({ length: 3 * 65536 + 256 }, (_, i) => i % 256),
|
||||
);
|
||||
await writeFile(path, bytes);
|
||||
let reads = 0;
|
||||
const service = new ByteEntropyService({
|
||||
stat,
|
||||
open: async (...args) => {
|
||||
const file = await open(...args);
|
||||
const read = file.read.bind(file);
|
||||
Object.defineProperty(file, "read", {
|
||||
value: async (
|
||||
buffer: Buffer,
|
||||
offset: number,
|
||||
length: number,
|
||||
position: number,
|
||||
) => {
|
||||
reads += 1;
|
||||
return read(buffer, offset, Math.min(length, 3571), position);
|
||||
},
|
||||
});
|
||||
return file;
|
||||
},
|
||||
});
|
||||
try {
|
||||
const result = await service.inspect({
|
||||
path,
|
||||
offset: 3,
|
||||
length: 2 * 65536 + 1,
|
||||
block_size: blockSize,
|
||||
});
|
||||
if (!result.ok) throw result.error;
|
||||
const report = byteEntropySchema.parse(result.value.normalized_result);
|
||||
const fullBlocks = (2 * 65536) / blockSize;
|
||||
expect(report.blocks).toEqual([
|
||||
...Array.from({ length: fullBlocks }, (_, i) => ({
|
||||
offset: 3 + i * blockSize,
|
||||
length: blockSize,
|
||||
entropy: 8,
|
||||
})),
|
||||
{ offset: 3 + 2 * 65536, length: 1, entropy: 0 },
|
||||
]);
|
||||
expect(report.runs).toEqual([
|
||||
{ offset: 3, length: 2 * 65536, classification: "high" },
|
||||
{ offset: 3 + 2 * 65536, length: 1, classification: "low" },
|
||||
]);
|
||||
expect(report.file_entropy).toBe(8);
|
||||
expect(report.artifact.sha256).toBe(
|
||||
createHash("sha256").update(bytes).digest("hex"),
|
||||
);
|
||||
// Even with 3,571-byte short reads, finer report resolution does not
|
||||
// require hundreds of asynchronous reads of this 193 KiB file.
|
||||
expect(reads).toBeLessThan(100);
|
||||
} finally {
|
||||
await service.close();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it("rejects missing files, non-files and windows beyond EOF, but accepts empty windows", async () => {
|
||||
const root = await createTestTempDirectory("rea-entropy-input-");
|
||||
const path = join(root, "empty");
|
||||
|
||||
@@ -241,7 +241,10 @@ export class ByteEntropyService {
|
||||
);
|
||||
const end = input.offset + length;
|
||||
const blocks: ByteEntropy["blocks"] = [];
|
||||
const buffer = Buffer.alloc(input.block_size);
|
||||
// Physical reads must not shrink with report resolution, including
|
||||
// outside the selected window. Every admitted power-of-two block
|
||||
// size divides this buffer, so only the window's final block is short.
|
||||
const buffer = Buffer.alloc(65_536);
|
||||
const counts = new Float64Array(256);
|
||||
const hash = createHash("sha256");
|
||||
let position = 0;
|
||||
@@ -250,7 +253,7 @@ export class ByteEntropyService {
|
||||
const selected = position >= input.offset && position < end;
|
||||
const boundary =
|
||||
position < input.offset ? input.offset : selected ? end : size;
|
||||
const wanted = Math.min(input.block_size, boundary - position);
|
||||
const wanted = Math.min(buffer.length, boundary - position);
|
||||
let filled = 0;
|
||||
while (filled < wanted) {
|
||||
assertArtifactReadActive(options?.signal);
|
||||
@@ -267,11 +270,18 @@ export class ByteEntropyService {
|
||||
hash.update(bytes);
|
||||
for (const byte of bytes) counts[byte] = (counts[byte] ?? 0) + 1;
|
||||
if (selected)
|
||||
blocks.push({
|
||||
offset: position,
|
||||
length: filled,
|
||||
entropy: computeBlockEntropy(bytes),
|
||||
});
|
||||
for (
|
||||
let offset = 0;
|
||||
offset < filled;
|
||||
offset += input.block_size
|
||||
) {
|
||||
const block = bytes.subarray(offset, offset + input.block_size);
|
||||
blocks.push({
|
||||
offset: position + offset,
|
||||
length: block.length,
|
||||
entropy: computeBlockEntropy(block),
|
||||
});
|
||||
}
|
||||
position += filled;
|
||||
}
|
||||
if (
|
||||
|
||||
Reference in new issue
Block a user