docs: pin CHAT-00 protocol research and synthetic checks (#1507)
This commit is contained in:
@@ -0,0 +1,246 @@
|
||||
# CHAT-00 protocol and boundary investigation
|
||||
|
||||
Issue #1507. Charter comment 26094. Darkwing authors; Filbert independently
|
||||
reviews the exact candidate. Rocko supplies a separate architecture review under
|
||||
comment 26098. Confirmed plan `../2026-09-13_webui-session-chat.md`, SHA-256
|
||||
`481428295199c55e0dc2f7f752b64e1dac165f02e44ceb1975004bf327513809`, published
|
||||
at `4c436f4ce493028c5f602035a29ce27d8a266d92` after investigation began.
|
||||
Owner confirmation 26093 and plan-review closure 26095 are separate from approval
|
||||
of this research. Status: research candidate, independent review pending.
|
||||
|
||||
## Finding
|
||||
|
||||
A mediated conversation controller is a reasonable package boundary, but raw Pi
|
||||
RPC or Claude stream-json is not that controller. Both expose engine operations
|
||||
without Mosaic's actor, scope, generation or durable request admission rules.
|
||||
Neither native response success nor process idle establishes stopped tool cohorts.
|
||||
No running seat can be adopted by starting another engine against its UUID.
|
||||
|
||||
Protocol documentation supports a bounded adapter proposal, not a live readiness
|
||||
claim. Claude has a concrete compatibility concern: the brief observed 2.1.269,
|
||||
whereas the installed binary now reports 2.1.270. Its own help says print mode
|
||||
skips workspace trust and silently ignores invalid settings. Native approval
|
||||
callbacks do not repair that difference. Keep fail-closed preflight and effective
|
||||
configuration verification as implementation prerequisites.
|
||||
|
||||
## Evidence and pins
|
||||
|
||||
`sources.json` records byte hashes, versions, locations and inspected sections.
|
||||
Pi declared and installed package both read 0.85.1. README, RPC and session-format
|
||||
docs were read completely; RPC declarations and framing helper were also read.
|
||||
RPC implementation excerpts confirm prompt preflight, queue and branch commands.
|
||||
This is not a complete extension/SDK/launcher audit. The implementer must still
|
||||
read the relevant SDK/extensions/TUI documents and examples in full before choosing
|
||||
and implementing that integration. No Pi engine, loader or model was started.
|
||||
|
||||
Claude 2.1.270 was queried only with `--version` and `--help`, using an empty
|
||||
environment and temporary HOME/config directory, without prompt/session flags.
|
||||
No actual auth file was read. The installed binary digest and help digest are
|
||||
recorded. This does not prove which binary any existing seat is running.
|
||||
|
||||
Official Python SDK source is pinned at commit
|
||||
`37a52c9fb3f0271de017911914b0d42efea6267e`, project version 0.2.152. Its wire
|
||||
request/response implementation and relevant types were inspected, not installed
|
||||
or executed. The transport declares minimum Claude 2.0.0; that minimum is not a
|
||||
compatibility certificate for 2.1.270. Official headless and TypeScript-reference
|
||||
pages are retrieval-hash pins, not release-frozen documentation. Sections name
|
||||
minimum CLI capabilities; actual capability negotiation remains untested.
|
||||
An initial platform documentation URL returned HTML, not a usable protocol source;
|
||||
it is excluded from supporting evidence.
|
||||
|
||||
No private history, fleet configuration, account data or live registrations were
|
||||
inventoried. Named classes below are requirements, not access grants or a count
|
||||
of verified seats. No source package, launcher or historical contract was edited.
|
||||
|
||||
## Capability matrix
|
||||
|
||||
Source IDs refer to `sources.json`. DOCUMENTED means a cited protocol shape or
|
||||
behavior; OBSERVED is restricted to version/help commands and pure offline checks.
|
||||
UNVERIFIED is not an optional capability.
|
||||
|
||||
| Requirement | Pi 0.85.1 evidence | Claude evidence | Remaining proof |
|
||||
|---|---|---|---|
|
||||
| Prompt and acknowledgement | P-RPC prompt, P-TYPES, P-MODE. `id` correlates acceptance; success may mean queued or extension-handled | C-TYPES/C-QUERY control envelopes; C-REF SDKUserMessage UUID and replay; C-HELP replay-user-messages | Durable Mosaic admission and duplicate/conflicting identity rejection. Neither `id` nor UUID alone supplies exactly-once effects |
|
||||
| Incremental user/assistant/tool conversation | P-RPC message_start/update/end; contentIndex deltas; authoritative message_end; toolCallId | C-REF stream_event and complete assistant/user messages; parent_tool_use_id separates nested work | Bound per-execution stream ordering, temporary-to-persisted reconciliation and actual reported-return regression for both adapters |
|
||||
| Settled versus finished | P-RPC agent_end can precede retry/compaction/queued continuation; agent_settled means no automatic continuation | C-HEADLESS result and background-task behavior; C-REF result correlation | Settled is still not cohort termination; do not use either to release a writer claim |
|
||||
| Complete branch history | P-SESSION v3 tree, compaction/retainedTail, custom visibility; P-RPC get_entries with since and leafId, get_tree | C-REF user UUID, session_id, compaction events; C-HELP resume identity | Claude persisted branch format and exact leaf selection are not verified. Pi get_entries is append order across branches, not a safe selected-branch transcript or bounded page |
|
||||
| Read-only catalogue | Pi header/cwd/tree documented; SessionManager.open can auto-migrate old files | C-HEADLESS resume searches by ID across projects, can accept a transcript path | Separate no-write parser and explicit adoption/access mapping required. Never use a migrating loader or global recent-session search |
|
||||
| Native approval and denial | P-RPC extension_ui_request/response uses exact id; select/confirm/input/editor, timeouts and cancellation; not a universal builtin approval system | C-QUERY can_use_tool supplies tool/input/tool_use_id and allow/deny response; C-REF says callback only runs when native flow reaches a prompt | Inventory approved Pi extensions and Claude request choices. Native denies remain authoritative; no general chat yes, permission-mode switch or updatedPermissions forwarding |
|
||||
| Approval reconnect | Pi pending UI map is in one process; no documented durable pending-dialog replay command | C-REF initialize wrapper pending_permission_requests, required from CLI 2.1.268; repeats must be idempotent | Pin/verify actual reconnect behavior, persist broker pending intent, fence stale controller replies; missing list is not an empty list |
|
||||
| Ordinary Interrupt Q20 | P-RPC explicitly clear_queue BEFORE abort; abort alone continues queued work. Returned queues contain text only | C-REF direct interrupt request can use cancel_queued:true, gated by interrupt_cancel_queued_v1; SDK interrupt() does not send it. Python pinned interrupt also sends only subtype | Broker owns durable drafts and attachment identity; serialize dispatch fencing before cancellation, classify races. Cancel receipt covers UUID-bearing main-thread pending messages only, not every possible input |
|
||||
| Queue edit/cancel and takeover | Native steering/followUp queues expand commands and do not offer durable per-request edit/cancel | Interrupt receipts expose still_queued/cancelled but do not establish Mosaic edit/cancel semantics | Keep queued work in broker until dispatch; retain native queues as reconciliation evidence. Never relabel already-dispatched work unsent |
|
||||
| Images/files | P-RPC prompt images use base64 data/mimeType; no general private-file upload API | C-REF SDKUserMessage MessageParam; C-HELP --file is startup download, not browser staging; stream-json input advertised | Verify exact image/file limits and supported content schemas for installed Claude; privately stage other files through an approved bridge. Q17 caps cannot be assumed harness limits |
|
||||
| Force stop and Resume | abort waits idle; no attributable-cohort proof in RPC response | C-HEADLESS describes SIGTERM and resume of unfinished turns; no Mosaic stop proof | Supervisor cohort identity, external-effect uncertainty, durable stop/recovery transaction and per-seat approved sacrificial test. Resume can have effects; not a read operation |
|
||||
| Controller/terminal | Raw stdin is the only RPC input channel; TUI does not expose an attach-RPC command | Native attach/background/remote-control help is not a reviewed Mosaic controller interface | One broker-owned engine and mediated terminal; no second UUID writer. All old input channels must be fenced |
|
||||
| Ambient config/tool isolation | P-README disables discovery/builtin tools with flags; extensions run with full process access | C-HELP tools empty, safe-mode/restricted/bare documented; print skips trust/invalid settings; C-REF allowedTools auto-approves, not allowlists | Approved tool bridge plus execution separation; verified configuration discovery/refusal behavior. Do not substitute auth-changing bare mode or permission callbacks for this gate |
|
||||
| Fleet | No remote channel in Pi RPC itself | No reviewed private fleet mapping from local Claude help | Identity, transport, transfer and remote-cohort contracts; held behind Q22 prerequisites |
|
||||
|
||||
## Protocol details that change the design
|
||||
|
||||
1. Frame Pi JSON on LF only, retain split UTF-8 bytes and optional CRLF. A string
|
||||
containing U+2028/U+2029 is one payload, not several records. Place explicit
|
||||
size bounds above the engine. Do not expose unbounded get_tree/get_entries
|
||||
or raw paths to a browser. A missing cursor is a reconciliation error.
|
||||
2. Pi `prompt` may invoke an extension command immediately, including while busy.
|
||||
Skills/templates expand before queueing. A broker cannot classify all strings
|
||||
as harmless chat merely because the RPC command is named prompt. Reviewed
|
||||
explicit resources and command policy must cover this route too.
|
||||
3. Pi message_update contains deltas, not the former cumulative partial message.
|
||||
Tool execution updates instead contain accumulated partialResult. Applying the
|
||||
same append operation to both duplicates output. Reconcile with authoritative
|
||||
message_end and later selected-branch persisted entries.
|
||||
4. Claude wire control is `{type:control_request, request_id, request:{subtype,...}}`;
|
||||
success response correlates inside `response.request_id`. Permission allow uses
|
||||
`updatedInput`; deny uses behavior/message and optional interrupt. Refuse
|
||||
permission mutations beyond the exact reviewed decision, even if SDK types
|
||||
expose updatedPermissions. Raw engine account/config fields never go to UI.
|
||||
5. Official Claude documentation exposes an important Q20 distinction. A direct
|
||||
control request may set `cancel_queued:true` only after verifying advertised
|
||||
`interrupt_cancel_queued_v1` and receipt support. SDK `interrupt()` alone does
|
||||
not do this. Receipts may contain unknown external UUIDs and omit unnumbered
|
||||
or subagent input. An empty still_queued list is not universal quiescence.
|
||||
Missing capabilities block dependent behavior; do not rely on version comparison.
|
||||
6. Broker-owned draft records must retain text and attachment IDs. Pi clear_queue
|
||||
returns text, not all upload metadata; Claude cancel receipts return IDs. Neither
|
||||
is sufficient to recreate a durable draft without the original admission record.
|
||||
7. Native engine state and Mosaic policy are distinct. An engine can acknowledge a
|
||||
prompt before the new answer appears. The required regression must show user,
|
||||
tools and NEW assistant output in the same selected conversation, not just a
|
||||
successful POST or a reused last-message preview.
|
||||
|
||||
## Retained foundation requirements and proposed extensions
|
||||
|
||||
Foundation RUNTIME sections 3-5 remain the accepted design baseline, not installed
|
||||
runtime enforcement. No change to their files is part of CHAT-00.
|
||||
|
||||
| Requirement | Disposition | CHAT-01/03 prerequisite |
|
||||
|---|---|---|
|
||||
| Scope/access/legacy adoption, R22/R30 | RETAIN | Approved mappings and grants for each legacy conversation; UUID/cwd/basename is not a project assignment |
|
||||
| One writer and current controller generation, R24 | RETAIN | Durable claim, process incarnation, explicit transfer and controller generation check on admission AND dispatch |
|
||||
| Snapshot and selected branch at Resume, R7/R25 | RETAIN | Exact private snapshot/leaf/config pins; no autoload-migration, fallback Fresh or start-before-binding |
|
||||
| Mediated terminal, R34 | RETAIN | Terminal is another authorized client, not an independently writable native engine TUI |
|
||||
| No builtin-tool escape, reviewed bridge, no tools in credential-bearing engine | RETAIN, ENFORCEMENT UNPROVED | Separate tool executor with least privilege; every builtin/direct shell/plugin/MCP path must be disabled, mediated or explicitly refused. Native approval callbacks are insufficient |
|
||||
| No ambient extensions/context | RETAIN, COMPATIBILITY CONFLICT TO RESOLVE | Explicit manifest and discovery controls; native Claude print trust/settings behavior requires preflight/effective-state proof without dropping denies |
|
||||
| Exact decision correlation and no permission widening | RETAIN | Dialog id plus actor, intent digest, scope, tool, execution and controller binding; native deny and expired/canceled requests fence replies |
|
||||
| Invocation/effect evidence and no blind replay | RETAIN | Write-ahead intent, causal actor, dedup and uncertainty recovery. Signal/EOF/idle do not close effects |
|
||||
| Pi-only bounded text | PROPOSED EXTENSION | Claude mappings, safe images/files, content/byte limits, approvals and transcript branches; explicit schema review in CHAT-01 |
|
||||
| Browser/server durable drafts and uploads | PROPOSED EXTENSION | Private storage ownership/capacity, state transitions and crash recovery, not workspace files or immutable run-record rewrites |
|
||||
| Private remote control | PROPOSED EXTENSION, Q22 HELD | Authenticated host/seat identity and permissions plus remote stop/transfer proof. No fleet path or service authority yet |
|
||||
|
||||
Do not solve a conflict by installing the parked registry or weakening role/policy
|
||||
contracts. Escalate an exact bounded contract disposition only when evidence shows
|
||||
the retained requirement cannot be met within a proposed implementation.
|
||||
|
||||
## Proposed identity and access map
|
||||
|
||||
These are design fields, not a new accepted schema. Authoritative binding should
|
||||
include opaque conversation id, approved project/workspace/seat identity, host id,
|
||||
harness/version, private source-root reference, native session id and selected
|
||||
branch, execution incarnation, supervisor cohort reference, controller generation,
|
||||
authenticated actor/connection, config/permission revision and current access grant.
|
||||
|
||||
Required classes: repository Pi on the workstation, repository Claude on the
|
||||
workstation, local fleet Pi, remote fleet Pi, and any additional Claude/host class
|
||||
identified by the separately authorized all-seat inventory. Do not assert that an
|
||||
uninspected class is deployed or accessible. Existing Rocko launch identity is
|
||||
not proof of its current execution, model or all fleet identities.
|
||||
|
||||
Local proposal: private Unix socket with verified OS peer identity between mediated
|
||||
terminal and broker; loopback WebUI server using authenticated, per-browser-session
|
||||
credentials and per-conversation observer/controller grants. Bind browser requests
|
||||
to exact allowed Origin and Host, reject cross-origin/CSRF mutations, avoid query
|
||||
string secrets, and use secure session lifecycle, rotation, revocation and bounded
|
||||
idle expiry. Cookie security must match the chosen local HTTPS/origin arrangement;
|
||||
loopback HTTP cannot simply be labeled secure. No credentials are created here.
|
||||
|
||||
Remote proposal: private authenticated host channel with verified peer identity,
|
||||
explicit per-host/seat grants and revocation, plus a host supervisor that attests
|
||||
execution/cohort incarnation. SSH or mutual TLS remains a reviewed mechanism choice,
|
||||
not an installed service. Separate transport credentials from provider accounts.
|
||||
Transport connectivity alone grants neither transcript visibility nor control.
|
||||
|
||||
Store drafts/uploads privately, keyed by actor and approved conversation identity.
|
||||
Use opaque attachment references with digest, verified bytes/type and declared
|
||||
recipient. Transfer to a remote host needs exact-seat acknowledgement and replay
|
||||
protection. Sent content follows conversation visibility. Enforce 10 files,
|
||||
20 MiB/file and 100 MiB/message plus any stricter verified engine limit; no silent
|
||||
expiry, extraction, execution or overwrite. No public staging URL or arbitrary
|
||||
browser-supplied path.
|
||||
|
||||
## Every-ingress disposition
|
||||
|
||||
| Ingress | Required disposition before cutover |
|
||||
|---|---|
|
||||
| Old board Reply and agent-send/tmux | Refuse delivery to migrated engine paths or route through authenticated broker admission. Existing preamble is untrusted text. Merely hiding the old button is not fencing |
|
||||
| Native TUI keyboard and external editor | Replace engine input with mediated terminal connection; observer cannot submit and takeover invalidates old connection generation |
|
||||
| Raw RPC, Claude stream-json and direct shell commands | Private supervisor-owned descriptors; allowlist translated operations, never raw client forwarding |
|
||||
| Engine follow-ups/steering, hooks and scheduled/internal input | Inventory/disable or mediate; reconcile inherited queues at handoff. No input can evade actor and scope admission |
|
||||
| Approval replies and reinitialization | Exact outstanding request and current generation; late/duplicate-conflicting replies refused, lost replies reconciled, no auto-approval |
|
||||
| Alternate launcher, crash restart, same UUID Resume | Exclusive durable writer reservation and prior-cohort proof before start; uncertainty retains claim. Record and test rollback without prompt/approval replay |
|
||||
|
||||
## Synthetic checks and their limits
|
||||
|
||||
Run `node docs/plans/chat-00/check.mjs`. `fixtures.json` contains synthetic cases
|
||||
only. Checks cover pinned-source identities where available, LF/UTF-8 framing,
|
||||
documented envelope shapes, Q20/takeover state examples, stale binding rejection,
|
||||
unknown delivery and stop-proof distinctions, and upload-cap arithmetic.
|
||||
They do not launch engines, read sessions/auth, make network calls or test native
|
||||
permissions, live races, private remote transport, actual image support or cutover.
|
||||
A passing miniature model is not runtime enforcement or Claude compatibility.
|
||||
|
||||
## Blocking gates and next bounded work
|
||||
|
||||
- B1: prove the exact Claude CLI/protocol combination, capability negotiation,
|
||||
transcript branch selection and image/file input shapes. Public SDK/source
|
||||
examples narrow uncertainty but do not certify the installed binary.
|
||||
- B2: prove tool-execution separation, resource manifest isolation and native
|
||||
trust/settings refusal parity. This is a security gate, not UI polish.
|
||||
- B3: complete all-ingress writer/controller fencing and supervisor crash/stop
|
||||
proof. No native attach or second UUID process substitutes for it.
|
||||
- B4: source/access mapping and authentication design need independent contract
|
||||
review and any required owner grants. No private inventory has been performed.
|
||||
- B5: Q22 retains piece 5, required #1508 and fleet-launch dependencies. CHAT-04R
|
||||
cannot proceed ahead of them; all-seat acceptance remains blocked meanwhile.
|
||||
- B6: exact per-seat live envelope and rollback approval remains separate from
|
||||
source publication. First-seat approval never authorizes later seats.
|
||||
|
||||
Finish independent CHAT-00 review, then propose only the bounded CHAT-01 contract
|
||||
charter with these proof gates intact. Do not silently start runtime adapters or
|
||||
other queue rows. Rocko findings and Filbert verdict will be recorded as issue
|
||||
comments, with exact research hashes, before claiming this task approved.
|
||||
|
||||
|
||||
## Rocko architecture review and reconciled qualifications
|
||||
|
||||
Rocko independently reviewed the plan and foundation boundaries and returned
|
||||
findings through agent-send. He recommends distinguishing strict foundation
|
||||
workers from existing host seats, with a possible host-seat ceiling of WebUI
|
||||
powers no greater than native terminal powers. This is an owner/security-review
|
||||
proposal, NOT an accepted exception to tool isolation. Until an exact ruling,
|
||||
retain the foundation requirements and mark native parity/enforcement unproved.
|
||||
No policy change or loss of required host-seat functionality is approved here.
|
||||
|
||||
Keep Pi and Claude proof matrices separate and propose distinct adapter fixtures
|
||||
and a mediated-terminal/old-ingress work boundary at CHAT-01. No such subtask has
|
||||
started. Any required change to excluded tmux/comms paths needs explicit bounded
|
||||
scope approval; disabling communication without a replacement does not meet the
|
||||
all-seat outcome. Observer-mode pasted messages may be retained as untrusted
|
||||
recoverable input, not silently dispatched as an authenticated controller.
|
||||
|
||||
Four qualifications were sent back and Rocko explicitly accepted them:
|
||||
|
||||
- Claude help's copy-when-already-running wording belongs to `--bg` with
|
||||
`--resume`, not proof of ordinary `--resume` behavior. Exact same-identity
|
||||
resume of a stopped seat remains a measured handoff gate. Native attach is
|
||||
unverified, not proved impossible or accepted as an alternative controller.
|
||||
- The official TypeScript reference documents `cancel_queued:true`; the claim
|
||||
that Claude has no queue clear was withdrawn. Exact CLI behavior is still
|
||||
unverified, and the SDK convenience method omits that field.
|
||||
- Pi clear_queue text cannot reconstruct attachment identifiers or durable
|
||||
metadata. The broker must retain the original queue records.
|
||||
- Disconnect is neither auto-allow nor blanket auto-deny. Keep outstanding
|
||||
approval state under the exact native timeout/cancellation semantics and
|
||||
reconcile it before a current-controller reply.
|
||||
|
||||
The phase-2 Pi document pin predates 0.85.1. All citations here use the current
|
||||
sources.json hash and current sections, never inherited phase-2 line numbers.
|
||||
@@ -0,0 +1,114 @@
|
||||
// CHAT-00 research checker only. No engine, filesystem mutation or network.
|
||||
// These small models check proposed examples, not production authorization.
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { PassThrough } from 'node:stream';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import path from 'node:path';
|
||||
|
||||
const here = path.dirname(fileURLToPath(import.meta.url));
|
||||
const root = path.resolve(here, '../../..');
|
||||
const sources = JSON.parse(readFileSync(path.join(here, 'sources.json'), 'utf8'));
|
||||
const fixture = JSON.parse(readFileSync(path.join(here, 'fixtures.json'), 'utf8'));
|
||||
let checks = 0;
|
||||
const check = (name, fn) => { fn(); checks++; console.log(`PASS ${name}`); };
|
||||
check('source IDs unique; provenance and inspected sections explicit', () => {
|
||||
assert.equal(new Set(sources.sources.map(s => s.id)).size, sources.sources.length);
|
||||
for (const s of sources.sources) {
|
||||
assert.match(s.sha256, /^[a-f0-9]{64}$/);
|
||||
assert.ok(s.locator && s.coverage && s.evidence);
|
||||
}
|
||||
});
|
||||
for (const s of sources.sources.filter(s => s.repoPath)) {
|
||||
check(`${s.id} installed/repository source hash`, () => {
|
||||
const file = path.resolve(root, s.repoPath);
|
||||
assert.ok(file.startsWith(root + path.sep));
|
||||
const hash = createHash('sha256').update(readFileSync(file)).digest('hex');
|
||||
assert.equal(hash, s.sha256, 'Source changed: re-investigate, do not refresh pin blindly');
|
||||
});
|
||||
}
|
||||
// Public reference caches are deliberately not a required dependency. No fetch.
|
||||
check('fixture provenance is synthetic, no runtime claim', () => {
|
||||
assert.equal(fixture.evidence, 'synthetic-research-only');
|
||||
assert.equal(fixture.runtimeEnforcementProven, false);
|
||||
});
|
||||
|
||||
const context = fixture.binding;
|
||||
const fields = ['actor', 'host', 'seat', 'project', 'workspace', 'conversation', 'branch', 'execution', 'controllerGeneration'];
|
||||
const allowed = new Set(['prompt', 'approval', 'interrupt', 'force-stop', 'takeover']);
|
||||
function admissible(request) {
|
||||
return request.authenticated === true && request.accessGranted === true &&
|
||||
fields.every(f => request[f] === context[f]) && allowed.has(request.operation) &&
|
||||
request.source === 'broker' && request.role === 'controller' && request.claim === 'held' &&
|
||||
(request.operation !== 'prompt' || (typeof request.message === 'string' && !request.message.startsWith('/')));
|
||||
}
|
||||
for (const c of fixture.admission) {
|
||||
check(c.id, () => assert.equal(admissible({ ...fixture.request, ...c.patch }), c.expected));
|
||||
}
|
||||
|
||||
function recoverQueue(queue) {
|
||||
return queue.map(item => ({ ...item, state: item.state === 'queued' ? 'draft' : item.state }));
|
||||
}
|
||||
for (const operation of ['interrupt', 'force-stop', 'takeover']) {
|
||||
check(`${operation}: only undispatched queue becomes draft, identity retained`, () => {
|
||||
const result = recoverQueue(fixture.queue);
|
||||
assert.deepEqual(result, fixture.recoveredQueue);
|
||||
assert.equal(result[0].attachments[0], 'upload-1');
|
||||
assert.equal(result[1].actor, 'old-controller');
|
||||
});
|
||||
}
|
||||
for (const c of fixture.stopProof) {
|
||||
check(c.id, () => {
|
||||
const stopped = c.cohortVerified && c.liveMembers === 0 && c.effectsReconciled;
|
||||
assert.equal(stopped, c.expectedStopped);
|
||||
});
|
||||
}
|
||||
for (const c of fixture.uploads) {
|
||||
check(c.id, () => {
|
||||
const valid = c.sizes.length <= 10 && c.sizes.every(s => Number.isSafeInteger(s) && s > 0 && s <= 20 * 1024 * 1024) &&
|
||||
c.sizes.reduce((a, b) => a + b, 0) <= 100 * 1024 * 1024;
|
||||
assert.equal(valid, c.expected);
|
||||
});
|
||||
}
|
||||
check('Claude documented interrupt cancellation is capability gated', () => {
|
||||
const required = ['interrupt_receipt_v1', 'interrupt_cancel_queued_v1'];
|
||||
assert.equal(required.every(x => fixture.claude.capabilities.includes(x)), true);
|
||||
assert.equal(required.every(x => fixture.claude.oldCapabilities.includes(x)), false);
|
||||
assert.deepEqual(fixture.claude.interrupt.request, { subtype: 'interrupt', cancel_queued: true });
|
||||
assert.equal(fixture.claude.interrupt.type, 'control_request');
|
||||
assert.equal(fixture.claude.response.response.request_id, fixture.claude.interrupt.request_id);
|
||||
assert.deepEqual(fixture.claude.response.response.response.cancelled, ['message-1']);
|
||||
// Empty lists are never treated as universal quiescence.
|
||||
assert.equal(fixture.claude.emptyReceiptProvesCohortStopped, false);
|
||||
});
|
||||
check('Pi ordinary interrupt sequence fences first, clears before abort', () => {
|
||||
assert.deepEqual(fixture.pi.interruptSequence, ['fence-dispatch', 'persist-draft-intent', 'clear_queue', 'abort', 'reconcile']);
|
||||
assert.deepEqual(fixture.pi.clearResponse.data.followUp, ['next']);
|
||||
assert.equal(fixture.pi.clearResponsePreservesAttachmentIds, false);
|
||||
});
|
||||
check('approval must match outstanding intent and cannot widen permissions', () => {
|
||||
const pending = fixture.approval.pending;
|
||||
const accept = response => response.id === pending.id && response.intent === pending.intent &&
|
||||
response.execution === pending.execution && response.generation === pending.generation &&
|
||||
pending.choices.includes(response.choice) && response.updatedPermissions === undefined;
|
||||
for (const sample of fixture.approval.responses) assert.equal(accept(sample.value), sample.expected);
|
||||
});
|
||||
check('uncertain send is not safe replay, native success is not task completion', () => {
|
||||
assert.equal(fixture.uncertain.allowBlindReplay, false);
|
||||
assert.equal(fixture.uncertain.releaseWriterClaim, false);
|
||||
assert.equal(fixture.uncertain.promptSuccessProvesAnswer, false);
|
||||
});
|
||||
|
||||
// Import only the fully inspected pure framing helper, not the harness/SDK.
|
||||
const { attachJsonlLineReader } = await import('../../../node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/jsonl.js');
|
||||
check('installed Pi LF framing preserves UTF-8 chunk splits and Unicode separators', () => {
|
||||
const stream = new PassThrough(); const lines = [];
|
||||
const detach = attachJsonlLineReader(stream, line => lines.push(JSON.parse(line)));
|
||||
const payload = { type: 'prompt', message: 'one\u2028two\u2029three 🦆' };
|
||||
const bytes = Buffer.from(JSON.stringify(payload) + '\r\n');
|
||||
for (const byte of bytes) stream.write(Buffer.from([byte]));
|
||||
assert.deepEqual(lines, [payload]);
|
||||
detach(); stream.destroy();
|
||||
});
|
||||
console.log(`CHAT-00 ${checks} checks passed. Synthetic/source checks only; engines, auth, live access and cutover NOT TESTED.`);
|
||||
@@ -0,0 +1,450 @@
|
||||
{
|
||||
"evidence": "synthetic-research-only",
|
||||
"runtimeEnforcementProven": false,
|
||||
"binding": {
|
||||
"actor": "actor-1",
|
||||
"host": "host-1",
|
||||
"seat": "seat-1",
|
||||
"project": "project-1",
|
||||
"workspace": "workspace-1",
|
||||
"conversation": "conversation-1",
|
||||
"branch": "leaf-1",
|
||||
"execution": "incarnation-1",
|
||||
"controllerGeneration": 2
|
||||
},
|
||||
"request": {
|
||||
"actor": "actor-1",
|
||||
"host": "host-1",
|
||||
"seat": "seat-1",
|
||||
"project": "project-1",
|
||||
"workspace": "workspace-1",
|
||||
"conversation": "conversation-1",
|
||||
"branch": "leaf-1",
|
||||
"execution": "incarnation-1",
|
||||
"controllerGeneration": 2,
|
||||
"authenticated": true,
|
||||
"accessGranted": true,
|
||||
"operation": "prompt",
|
||||
"message": "hello",
|
||||
"source": "broker",
|
||||
"role": "controller",
|
||||
"claim": "held"
|
||||
},
|
||||
"admission": [
|
||||
{"id":"refuse extension command during streaming", "patch":{"message":"/dangerous-command", "streaming":true}, "expected":false},
|
||||
{"id":"refuse second launcher while claim held", "patch":{"operation":"launch"}, "expected":false},
|
||||
{
|
||||
"id": "admit exact synthetic binding",
|
||||
"patch": {},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"id": "refuse stale or foreign actor",
|
||||
"patch": {
|
||||
"actor": "foreign"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse stale or foreign host",
|
||||
"patch": {
|
||||
"host": "foreign"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse stale or foreign seat",
|
||||
"patch": {
|
||||
"seat": "foreign"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse stale or foreign project",
|
||||
"patch": {
|
||||
"project": "foreign"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse stale or foreign workspace",
|
||||
"patch": {
|
||||
"workspace": "foreign"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse stale or foreign conversation",
|
||||
"patch": {
|
||||
"conversation": "foreign"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse stale or foreign branch",
|
||||
"patch": {
|
||||
"branch": "foreign"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse stale or foreign execution",
|
||||
"patch": {
|
||||
"execution": "foreign"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse stale or foreign controllerGeneration",
|
||||
"patch": {
|
||||
"controllerGeneration": 0
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse authenticated=False",
|
||||
"patch": {
|
||||
"authenticated": false
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse accessGranted=False",
|
||||
"patch": {
|
||||
"accessGranted": false
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse role=observer",
|
||||
"patch": {
|
||||
"role": "observer"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse claim=uncertain",
|
||||
"patch": {
|
||||
"claim": "uncertain"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse source=old-board",
|
||||
"patch": {
|
||||
"source": "old-board"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse source=tmux-paste",
|
||||
"patch": {
|
||||
"source": "tmux-paste"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse source=native-terminal",
|
||||
"patch": {
|
||||
"source": "native-terminal"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse operation=bash",
|
||||
"patch": {
|
||||
"operation": "bash"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse operation=switch_session",
|
||||
"patch": {
|
||||
"operation": "switch_session"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "refuse operation=set_permission_mode",
|
||||
"patch": {
|
||||
"operation": "set_permission_mode"
|
||||
},
|
||||
"expected": false
|
||||
}
|
||||
],
|
||||
"queue": [
|
||||
{
|
||||
"id": "q1",
|
||||
"state": "queued",
|
||||
"actor": "old-controller",
|
||||
"attachments": [
|
||||
"upload-1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "q2",
|
||||
"state": "dispatched",
|
||||
"actor": "old-controller",
|
||||
"attachments": []
|
||||
},
|
||||
{
|
||||
"id": "q3",
|
||||
"state": "delivery-unknown",
|
||||
"actor": "old-controller",
|
||||
"attachments": []
|
||||
}
|
||||
],
|
||||
"recoveredQueue": [
|
||||
{
|
||||
"id": "q1",
|
||||
"state": "draft",
|
||||
"actor": "old-controller",
|
||||
"attachments": [
|
||||
"upload-1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "q2",
|
||||
"state": "dispatched",
|
||||
"actor": "old-controller",
|
||||
"attachments": []
|
||||
},
|
||||
{
|
||||
"id": "q3",
|
||||
"state": "delivery-unknown",
|
||||
"actor": "old-controller",
|
||||
"attachments": []
|
||||
}
|
||||
],
|
||||
"stopProof": [
|
||||
{
|
||||
"id": "idle without cohort proof is not stopped",
|
||||
"cohortVerified": false,
|
||||
"liveMembers": 0,
|
||||
"effectsReconciled": true,
|
||||
"expectedStopped": false
|
||||
},
|
||||
{
|
||||
"id": "live tool child is not stopped",
|
||||
"cohortVerified": true,
|
||||
"liveMembers": 1,
|
||||
"effectsReconciled": true,
|
||||
"expectedStopped": false
|
||||
},
|
||||
{
|
||||
"id": "unreconciled effects retain uncertainty",
|
||||
"cohortVerified": true,
|
||||
"liveMembers": 0,
|
||||
"effectsReconciled": false,
|
||||
"expectedStopped": false
|
||||
},
|
||||
{
|
||||
"id": "synthetic confirmed stop proof",
|
||||
"cohortVerified": true,
|
||||
"liveMembers": 0,
|
||||
"effectsReconciled": true,
|
||||
"expectedStopped": true
|
||||
}
|
||||
],
|
||||
"uploads": [
|
||||
{
|
||||
"id": "attachment caps exact boundary",
|
||||
"sizes": [
|
||||
20971520,
|
||||
20971520,
|
||||
20971520,
|
||||
20971520,
|
||||
20971520
|
||||
],
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"id": "too many attachments",
|
||||
"sizes": [
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "file over cap",
|
||||
"sizes": [
|
||||
20971521
|
||||
],
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"id": "message over cap",
|
||||
"sizes": [
|
||||
20971520,
|
||||
20971520,
|
||||
20971520,
|
||||
20971520,
|
||||
20971520,
|
||||
1
|
||||
],
|
||||
"expected": false
|
||||
}
|
||||
],
|
||||
"approval": {
|
||||
"pending": {
|
||||
"id": "approval-1",
|
||||
"intent": "intent-1",
|
||||
"execution": "incarnation-1",
|
||||
"generation": 2,
|
||||
"choices": [
|
||||
"allow",
|
||||
"deny"
|
||||
]
|
||||
},
|
||||
"responses": [
|
||||
{
|
||||
"value": {
|
||||
"id": "approval-1",
|
||||
"intent": "intent-1",
|
||||
"execution": "incarnation-1",
|
||||
"generation": 2,
|
||||
"choice": "deny"
|
||||
},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"value": {
|
||||
"id": "approval-1",
|
||||
"intent": "intent-1",
|
||||
"execution": "incarnation-1",
|
||||
"generation": 2,
|
||||
"choice": "allow"
|
||||
},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"value": {
|
||||
"id": "other",
|
||||
"intent": "intent-1",
|
||||
"execution": "incarnation-1",
|
||||
"generation": 2,
|
||||
"choice": "deny"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"value": {
|
||||
"id": "approval-1",
|
||||
"intent": "other",
|
||||
"execution": "incarnation-1",
|
||||
"generation": 2,
|
||||
"choice": "deny"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"value": {
|
||||
"id": "approval-1",
|
||||
"intent": "intent-1",
|
||||
"execution": "old",
|
||||
"generation": 2,
|
||||
"choice": "deny"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"value": {
|
||||
"id": "approval-1",
|
||||
"intent": "intent-1",
|
||||
"execution": "incarnation-1",
|
||||
"generation": 1,
|
||||
"choice": "deny"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"value": {
|
||||
"id": "approval-1",
|
||||
"intent": "intent-1",
|
||||
"execution": "incarnation-1",
|
||||
"generation": 2,
|
||||
"choice": "always-allow"
|
||||
},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"value": {
|
||||
"id": "approval-1",
|
||||
"intent": "intent-1",
|
||||
"execution": "incarnation-1",
|
||||
"generation": 2,
|
||||
"choice": "deny",
|
||||
"updatedPermissions": []
|
||||
},
|
||||
"expected": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"uncertain": {
|
||||
"allowBlindReplay": false,
|
||||
"releaseWriterClaim": false,
|
||||
"promptSuccessProvesAnswer": false
|
||||
},
|
||||
"pi": {
|
||||
"interruptSequence": [
|
||||
"fence-dispatch",
|
||||
"persist-draft-intent",
|
||||
"clear_queue",
|
||||
"abort",
|
||||
"reconcile"
|
||||
],
|
||||
"clearResponse": {
|
||||
"type": "response",
|
||||
"command": "clear_queue",
|
||||
"success": true,
|
||||
"data": {
|
||||
"steering": [],
|
||||
"followUp": [
|
||||
"next"
|
||||
]
|
||||
}
|
||||
},
|
||||
"clearResponsePreservesAttachmentIds": false
|
||||
},
|
||||
"claude": {
|
||||
"capabilities": [
|
||||
"interrupt_receipt_v1",
|
||||
"interrupt_cancel_queued_v1"
|
||||
],
|
||||
"oldCapabilities": [
|
||||
"interrupt_receipt_v1"
|
||||
],
|
||||
"interrupt": {
|
||||
"type": "control_request",
|
||||
"request_id": "interrupt-1",
|
||||
"request": {
|
||||
"subtype": "interrupt",
|
||||
"cancel_queued": true
|
||||
}
|
||||
},
|
||||
"response": {
|
||||
"type": "control_response",
|
||||
"response": {
|
||||
"subtype": "success",
|
||||
"request_id": "interrupt-1",
|
||||
"response": {
|
||||
"still_queued": [],
|
||||
"cancelled": [
|
||||
"message-1"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"emptyReceiptProvesCohortStopped": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
{
|
||||
"recordedAt": "2026-09-13T01:37:49.527399+00:00",
|
||||
"piVersion": "0.85.1",
|
||||
"claudeObservedVersion": "2.1.270",
|
||||
"claudeBinarySha256": "3a624a5a7cd79bbad4d32bd7db36f1197ecf458bc5bf1e2aed81834a01ad3ef0",
|
||||
"claudeSdkCommit": "37a52c9fb3f0271de017911914b0d42efea6267e",
|
||||
"claudeSdkVersion": "0.2.152",
|
||||
"sources": [
|
||||
{
|
||||
"id": "P-README",
|
||||
"repoPath": "node_modules/@earendil-works/pi-coding-agent/README.md",
|
||||
"locator": "node_modules/@earendil-works/pi-coding-agent/README.md",
|
||||
"sha256": "a63ba45d9c16ad63631c9bbeb13699a39c1d097174324e03c784fa8fb3a7b5d8",
|
||||
"coverage": "entire file, 718 lines",
|
||||
"evidence": "installed source/documentation"
|
||||
},
|
||||
{
|
||||
"id": "P-RPC",
|
||||
"repoPath": "node_modules/@earendil-works/pi-coding-agent/docs/rpc.md",
|
||||
"locator": "node_modules/@earendil-works/pi-coding-agent/docs/rpc.md",
|
||||
"sha256": "15fcd26bee72777b373fd5f2edd77091a01cadd4de95e48b08422ced0552a28d",
|
||||
"coverage": "entire file, 1618 lines; fresh pin, not phase-2 offsets",
|
||||
"evidence": "installed source/documentation"
|
||||
},
|
||||
{
|
||||
"id": "P-SESSION",
|
||||
"repoPath": "node_modules/@earendil-works/pi-coding-agent/docs/session-format.md",
|
||||
"locator": "node_modules/@earendil-works/pi-coding-agent/docs/session-format.md",
|
||||
"sha256": "c0f25475ab08fb96e244e6bf433aeaa41b69bfb5a52de5c7b01b81c900a84a54",
|
||||
"coverage": "entire file, 438 lines",
|
||||
"evidence": "installed source/documentation"
|
||||
},
|
||||
{
|
||||
"id": "P-TYPES",
|
||||
"repoPath": "node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts",
|
||||
"locator": "node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts",
|
||||
"sha256": "e968e5be01dc7ad9615f938ae867ef136fa495f13dcf169942e9f781a299d9eb",
|
||||
"coverage": "entire file",
|
||||
"evidence": "installed source/documentation"
|
||||
},
|
||||
{
|
||||
"id": "P-FRAME",
|
||||
"repoPath": "node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/jsonl.js",
|
||||
"locator": "node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/jsonl.js",
|
||||
"sha256": "049a9f8ca4242c79f1911ed977949e8d8906b4561f424c2729687f426fabaacf",
|
||||
"coverage": "entire file",
|
||||
"evidence": "installed source/documentation"
|
||||
},
|
||||
{
|
||||
"id": "P-MODE",
|
||||
"repoPath": "node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js",
|
||||
"locator": "node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js",
|
||||
"sha256": "e7e4724aa55c5aac73cf36793653b26736200e5c59d58373990fc31028f86477",
|
||||
"coverage": "292-346 read; targeted lookups get_entries/get_tree and UI request handling",
|
||||
"evidence": "installed source/documentation"
|
||||
},
|
||||
{
|
||||
"id": "FOUNDATION",
|
||||
"repoPath": "docs/plans/foundation-v1-candidate/RUNTIME.md",
|
||||
"locator": "docs/plans/foundation-v1-candidate/RUNTIME.md",
|
||||
"sha256": "b1a2b4d0df88ba6f7b197252807f3a3925ffff9375f4e70d4ff28593337c3438",
|
||||
"coverage": "sections 3-5 read; accepted design not runtime proof",
|
||||
"evidence": "repository design contract"
|
||||
},
|
||||
{
|
||||
"id": "PLAN",
|
||||
"repoPath": "docs/plans/2026-09-13_webui-session-chat.md",
|
||||
"locator": "docs/plans/2026-09-13_webui-session-chat.md",
|
||||
"sha256": "481428295199c55e0dc2f7f752b64e1dac165f02e44ceb1975004bf327513809",
|
||||
"coverage": "entire confirmed plan",
|
||||
"evidence": "repository owner-confirmed brief"
|
||||
},
|
||||
{
|
||||
"id": "C-QUERY",
|
||||
"locator": "https://raw.githubusercontent.com/anthropics/claude-agent-sdk-python/37a52c9fb3f0271de017911914b0d42efea6267e/src/claude_agent_sdk/_internal/query.py",
|
||||
"cache": "/tmp/chat-00-claude-query.py",
|
||||
"sha256": "c24f24ac2cb45a7debd3ba8fb945c65ffca7f1414ee0fb37a49fc500e1afcb8c",
|
||||
"coverage": "469-713 read; initialization/response/cancel routing targeted lookups",
|
||||
"evidence": "official SDK source at exact commit; CLI compatibility unverified"
|
||||
},
|
||||
{
|
||||
"id": "C-TYPES",
|
||||
"locator": "https://raw.githubusercontent.com/anthropics/claude-agent-sdk-python/37a52c9fb3f0271de017911914b0d42efea6267e/src/claude_agent_sdk/types.py",
|
||||
"cache": "/tmp/chat-00-claude-types.py",
|
||||
"sha256": "49e6a4ca6155ad9b245133d138516d9269bbb3aad2eb21311d02d77d75bca86a",
|
||||
"coverage": "1090-1154 and 2360-end read; type name searches",
|
||||
"evidence": "official SDK source at exact commit; CLI compatibility unverified"
|
||||
},
|
||||
{
|
||||
"id": "C-TRANSPORT",
|
||||
"locator": "https://raw.githubusercontent.com/anthropics/claude-agent-sdk-python/37a52c9fb3f0271de017911914b0d42efea6267e/src/claude_agent_sdk/_internal/transport/subprocess_cli.py",
|
||||
"cache": "/tmp/chat-00-claude-transport.py",
|
||||
"sha256": "748227e42cb9802d7316fabc836428d69bd219b63ef1b2f9f8f7a86a72a03e45",
|
||||
"coverage": "targeted flag/version searches only; not a complete transport audit",
|
||||
"evidence": "official SDK source at exact commit; CLI compatibility unverified"
|
||||
},
|
||||
{
|
||||
"id": "C-PROJECT",
|
||||
"locator": "https://raw.githubusercontent.com/anthropics/claude-agent-sdk-python/37a52c9fb3f0271de017911914b0d42efea6267e/pyproject.toml",
|
||||
"cache": "/tmp/chat-00-claude-pyproject.toml",
|
||||
"sha256": "00bcff397a21f835b90a8ca9c1765250b47b46e85346ebcecdbd344e3bb4693a",
|
||||
"coverage": "1-60 read; version 0.2.152",
|
||||
"evidence": "official SDK source at exact commit; CLI compatibility unverified"
|
||||
},
|
||||
{
|
||||
"id": "C-HEADLESS",
|
||||
"locator": "https://code.claude.com/docs/en/headless.md",
|
||||
"cache": "/tmp/chat-00-claude-headless.md",
|
||||
"sha256": "72521df6ef71d978d8c8298e518db15a4362b4fbf97f32a36626e31d088675a1",
|
||||
"coverage": "entire file",
|
||||
"evidence": "official floating documentation, retrieval bytes pinned; not CLI observation"
|
||||
},
|
||||
{
|
||||
"id": "C-REF",
|
||||
"locator": "https://code.claude.com/docs/en/agent-sdk/typescript.md",
|
||||
"cache": "/tmp/chat-00-claude-sdk-reference.md",
|
||||
"sha256": "f9800fcad978115589b40b6cb73a63ab9eae3289628094a9b515793204a78cbb",
|
||||
"coverage": "640-702,1223-1280,1448-1491 read; targeted capability/permission searches, not whole reference",
|
||||
"evidence": "official floating documentation, retrieval bytes pinned; not CLI observation"
|
||||
},
|
||||
{
|
||||
"id": "C-HELP",
|
||||
"locator": "Claude Code 2.1.270 --help in empty env and temp HOME/config",
|
||||
"cache": "/tmp/chat-00-claude-help.txt",
|
||||
"sha256": "ae85d661e9c086f05637ebcd868f5702b477ff6e55e2e65b8ada7807cd51a4b6",
|
||||
"coverage": "entire help; --version reported 2.1.270",
|
||||
"evidence": "help/version observation only; no engine session started"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user