353 lines
16 KiB
Markdown
353 lines
16 KiB
Markdown
# Compaction-Refresh WI-0 Gate0 Evidence Pack
|
||
|
||
- **Issue:** Gitea #827
|
||
- **Milestone:** 188 — Compaction-Refresh Mechanism
|
||
- **Branch:** `feat/827-gate0-probe`
|
||
- **Starting HEAD:** `d801d6c4c8a984d6a95033c49714210018d3d9a8`
|
||
- **Host/runtime:** Linux 6.1.0-48-amd64; Mosaic 0.0.48; Pi 0.80.7; Claude Code 2.1.205
|
||
- **Scope:** Probe fixtures and evidence only. No WI-1..WI-7 feature implementation.
|
||
|
||
## Verdict — 5/6 PASS; BUILD ADMISSION: **NO**
|
||
|
||
| Probe | Verdict | Short result |
|
||
| --- | --- | --- |
|
||
| P1 launcher topology + ancestry | **PASS** | Real Mosaic→Pi and Mosaic→Claude chains reached the registered anchor; real Claude `SessionStart` hook ancestry accepted; same-UID sibling with the minted victim ID rejected. |
|
||
| P2 Pi last-position + nonce map | **PASS** | Real Pi proved last-or-closed; `message_end` mapped exact `toolCallId → requestNonce` before `tool_call`; provider-response hook occurred before stream consumption/content completion. |
|
||
| P3 same-PID generation revocation | **PASS** | Same Pi PID/starttime persisted through reload/fork/new/resume while broker generations increased; reload revoked a prior `VERIFIED` generation. |
|
||
| P4 `SO_PEERCRED` + socket posture | **PASS** | Real Unix socket peer PID/UID/starttime matched `/proc`; 0700 directory + 0600 socket demonstrated. Same-UID counterfeit replacement remains explicitly T-C without a distinct principal/authenticated response. |
|
||
| P5 source invalidation | **PASS** | Missing, oversize, and hash-mismatched fragments each refused injection/promotion, revoked broker state, and blocked the exact emitted tool call. |
|
||
| P6 atomic injection | **T-C GAP** | Both runtimes empirically delivered a complete single block/message, but neither installed runtime contract states an **atomic/prefix-preserving** transport guarantee. Observation is not a guarantee; A-v5-1/T27 cannot be admitted. |
|
||
|
||
**Planner return item:** P6. The evidence establishes successful complete delivery in these runs, not the required invariant that the harness cannot middle-drop/replace bytes while preserving the terminal token. Per R1, such a middle-drop is not receipt-detectable. It is therefore classed **T-C**, not assumed away.
|
||
|
||
## STEP 0 — Authority re-verification
|
||
|
||
Command:
|
||
|
||
```bash
|
||
sha256sum \
|
||
~/agent-work/reviews/compaction-refresh-BUILD-BRIEF.md \
|
||
~/agent-work/reviews/compaction-refresh-SPEC-v5.md \
|
||
~/agent-work/reviews/compaction-refresh-SPEC-RATIFICATION.md
|
||
```
|
||
|
||
Captured result:
|
||
|
||
```text
|
||
89fdbc27ed0e5050dc7b52f3ef2ddaea691edf17fd89d51b15e26fb5ed47171b .../compaction-refresh-BUILD-BRIEF.md
|
||
a6d07ade835758e8488ca10d3b0631caf0beb93ea3a6733631f151b0c2f01433 .../compaction-refresh-SPEC-v5.md
|
||
bac58319c9c4028b5b40e1129e0033cdb5a6b7b02033c25f06f4cb77d7779c67 .../compaction-refresh-SPEC-RATIFICATION.md
|
||
```
|
||
|
||
All three **MATCH**. They were read in full before probe construction. Raw artifact: [`evidence/raw/STEP0-authority-hashes.txt`](./evidence/raw/STEP0-authority-hashes.txt).
|
||
|
||
## Evidence method
|
||
|
||
The scripts under [`probes/`](./probes/) are isolated Gate0 instrumentation, not product implementation. They run the installed `mosaic yolo` launcher and real installed runtime binaries. Broker prototypes use Linux `SO_PEERCRED` and `/proc`; runtime adapters are temporary Claude hooks/Pi extensions. No product source under `packages/mosaic` was changed.
|
||
|
||
Raw-output artifact integrity is indexed at [`evidence/RAW-SHA256SUMS.txt`](./evidence/RAW-SHA256SUMS.txt).
|
||
|
||
---
|
||
|
||
## P1 — Launcher exec/parent topology + supported-hook ancestry (D1)
|
||
|
||
**Verdict: PASS**
|
||
|
||
### Commands
|
||
|
||
```bash
|
||
python3 docs/compaction-refresh/probes/p1_run.py --runtime both
|
||
rg -n "spawnSync|execRuntime" \
|
||
~/.npm-global/lib/node_modules/@mosaicstack/mosaic/dist/commands/launch.js | tail -8
|
||
```
|
||
|
||
Full outputs:
|
||
|
||
- [`evidence/raw/P1-launch-ancestry.txt`](./evidence/raw/P1-launch-ancestry.txt)
|
||
- [`evidence/raw/P1-claude-hook-events.txt`](./evidence/raw/P1-claude-hook-events.txt)
|
||
|
||
### Real topology observed
|
||
|
||
The installed Mosaic launcher does **not** replace itself with the runtime despite its `execRuntime` name; installed `launch.js:668` uses `spawnSync`. The Gate0 anchor first registered, then `execvpe` replaced the anchor with the real `mosaic yolo` process (PID/starttime retained). Mosaic remained the stable parent while it spawned the runtime.
|
||
|
||
Pi run:
|
||
|
||
```text
|
||
anchor before exec: pid=4010843 starttime=365919858 exe=/usr/bin/python3.11
|
||
anchor after exec: pid=4010843 starttime=365919858 exe=/usr/bin/node
|
||
Pi runtime: pid=4011046 ppid=4010843 starttime=365920219 exe=/usr/bin/node
|
||
|
||
ps:
|
||
4010843 4010840 Fri Jul 17 19:35:18 2026 1001 1001 node
|
||
4011046 4010843 Fri Jul 17 19:35:22 2026 1001 1001 pi
|
||
```
|
||
|
||
Claude supported-hook run (latest capture):
|
||
|
||
```text
|
||
hook python pid=4011380 starttime=365920845
|
||
-> /bin/sh pid=4011379 starttime=365920845
|
||
-> claude pid=4011285 starttime=365920748
|
||
-> node/mosaic anchor pid=4011129 starttime=365920380
|
||
```
|
||
|
||
The stream independently recorded the real hook firing:
|
||
|
||
```json
|
||
{"type":"system","subtype":"hook_started","hook_name":"SessionStart:startup","hook_event":"SessionStart"}
|
||
{"type":"system","subtype":"hook_response","hook_name":"SessionStart:startup","exit_code":0,"outcome":"success","stdout":"...GATE0_P1_SUPPORTED_HOOK_ANCESTRY_ACCEPTED..."}
|
||
```
|
||
|
||
### Authentication and sibling substitution
|
||
|
||
The broker minted the logical ID on first peercred contact and keyed the anchor by `(pid,starttime)`. It took the hook/extension PID from `SO_PEERCRED`, walked `/proc/<pid>/stat`, and re-read every starttime before accepting.
|
||
|
||
Real Pi acceptance excerpt:
|
||
|
||
```json
|
||
{"peercred":{"pid":4011046,"uid":1001,"gid":1001},"decision":"ACCEPT","reason":"ancestry-reaches-registered-anchor","starttimes_rechecked":true}
|
||
```
|
||
|
||
A separately spawned same-UID sibling was given the real minted victim ID. Its ancestry did not reach the anchor:
|
||
|
||
```json
|
||
{"attacker_uid":1001,"victim_session_id_known":true,"broker_decision":"REJECT","broker_reason":"victim-id-known-but-ancestry-mismatch"}
|
||
```
|
||
|
||
The same rejection occurred in both Pi and Claude runs. This is positive runtime evidence for D1/T15a under the supported non-daemonizing topology.
|
||
|
||
---
|
||
|
||
## P2 — Pi last-position invariant + nonce map (D5)
|
||
|
||
**Verdict: PASS**
|
||
|
||
### Commands
|
||
|
||
```bash
|
||
python3 docs/compaction-refresh/probes/pi_gate0_run.py
|
||
python3 docs/compaction-refresh/probes/p2_provider_timing_run.py
|
||
```
|
||
|
||
Full outputs:
|
||
|
||
- [`evidence/raw/P2-P3-P5-P6-pi.txt`](./evidence/raw/P2-P3-P5-P6-pi.txt)
|
||
- [`evidence/raw/P2-provider-timing.txt`](./evidence/raw/P2-provider-timing.txt)
|
||
|
||
### Last-or-closed evidence
|
||
|
||
Real Pi argv/load order with the probe last:
|
||
|
||
```json
|
||
{"extensions":[".../mosaic-extension.ts",".../pi_gate0_extension.ts"],"lastPosition":true,"gateState":"UNVERIFIED_READY","pid":4004545}
|
||
```
|
||
|
||
A second real Pi launch deliberately appended a later handler:
|
||
|
||
```json
|
||
{"extensions":[".../mosaic-extension.ts",".../pi_gate0_extension.ts",".../pi_later_extension.ts"],"lastPosition":false,"gateState":"CLOSED_NOT_LAST","pid":4005692}
|
||
```
|
||
|
||
Thus the invariant observed is exactly **last or closed**, not an asserted registration order.
|
||
|
||
### Exact nonce → tool-call-ID map
|
||
|
||
In one real GPT-5.6 Sol Pi response, sequence 5 completed the assistant tool-call message and bound its exact ID:
|
||
|
||
```json
|
||
{"seq":5,"event":"message_end","requestNonce":"e5a82358-a6c9-490b-a0de-2e1f1d9b8d79","toolCallIds":["call_bgGE...57c"],"nonceMappings":[{"toolCallId":"call_bgGE...57c","requestNonce":"e5a82358-a6c9-490b-a0de-2e1f1d9b8d79"}]}
|
||
```
|
||
|
||
The following `tool_call` was sequence 6 and carried the same ID/nonce:
|
||
|
||
```json
|
||
{"seq":6,"event":"tool_call","toolCallId":"call_bgGE...57c","mapping":{"nonce":"e5a82358-a6c9-490b-a0de-2e1f1d9b8d79","verified":true},"allowed":true}
|
||
```
|
||
|
||
The harmless tool executed at sequence 7 with that same tool-call ID. No session-global “current epoch” was borrowed.
|
||
|
||
### `after_provider_response` is not assistant-content observation
|
||
|
||
A deterministic localhost HTTP provider was used only to force headers/status exposure through the real Pi transport. Actual order:
|
||
|
||
```json
|
||
{"seq":4,"event":"before_provider_request"}
|
||
{"seq":5,"event":"after_provider_response","status":200,"assistantContentAvailableAtThisHook":false,"timing":"headers/status before stream consumption"}
|
||
{"seq":6,"event":"message_end","role":"assistant","assistantContentObserved":true}
|
||
```
|
||
|
||
```text
|
||
headers_hook_precedes_completed_message=True
|
||
```
|
||
|
||
This positively confirms SPEC-v5’s precision correction: receipt content is observed at `message_end`; `after_provider_response` is status/headers before stream consumption.
|
||
|
||
---
|
||
|
||
## P3 — Same-PID `runtime_generation` bump revokes prior lease (D4)
|
||
|
||
**Verdict: PASS**
|
||
|
||
### Command
|
||
|
||
```bash
|
||
python3 docs/compaction-refresh/probes/pi_gate0_run.py
|
||
```
|
||
|
||
Full output: [`evidence/raw/P2-P3-P5-P6-pi.txt`](./evidence/raw/P2-P3-P5-P6-pi.txt).
|
||
|
||
The real Pi process identity remained:
|
||
|
||
```text
|
||
pid=4004545 starttime_ticks=365907677 uid=1001
|
||
```
|
||
|
||
Broker state around reload:
|
||
|
||
```json
|
||
{"event":"runtime_generation_bump","reason":"startup","old_generation":0,"new_generation":1,"new_lease_state":"UNVERIFIED"}
|
||
{"event":"probe_lease_promoted","generation":1,"new_lease_state":"VERIFIED"}
|
||
{"event":"runtime_generation_bump","phase":"shutdown","reason":"reload","old_generation":1,"new_generation":2,"prior_lease":"VERIFIED","prior_lease_revoked":true,"new_lease_state":"REVOKED"}
|
||
{"event":"runtime_generation_bump","phase":"start","reason":"reload","old_generation":2,"new_generation":3,"new_lease_state":"UNVERIFIED"}
|
||
```
|
||
|
||
The same `(pid,starttime)` then emitted monotonic bumps for real `fork`, `new`, and `resume` replacement flows, reaching generation 12. Pi 0.80.7 emitted an additional conservative `session_start` callback in each of those replacement flows; the broker bumped again rather than reusing authority. This is an availability/idempotence consideration for implementation, not a fail-open result.
|
||
|
||
---
|
||
|
||
## P4 — `SO_PEERCRED` + socket authenticity posture
|
||
|
||
**Verdict: PASS, with the spec’s named same-UID T-C residual**
|
||
|
||
### Command
|
||
|
||
```bash
|
||
python3 docs/compaction-refresh/probes/p4_peercred_probe.py
|
||
```
|
||
|
||
Full output: [`evidence/raw/P4-so-peercred.txt`](./evidence/raw/P4-so-peercred.txt).
|
||
|
||
Captured real socket result:
|
||
|
||
```text
|
||
server_pid=4013762 server_uid=1001 server_gid=1001
|
||
directory_mode=0700 socket_mode=0600
|
||
SO_PEERCRED pid=4013768 uid=1001 gid=1001
|
||
client_claim={"pid":4013768,"starttime_ticks":365927069,"uid":1001,...}
|
||
proc_observed={"pid":4013768,"starttime_ticks":365927069,"uid":1001,...}
|
||
pid_match=True
|
||
uid_match=True
|
||
starttime_match=True
|
||
client_exit_status=0
|
||
```
|
||
|
||
Achievable unprivileged posture on this host is a user-owned 0700 parent plus 0600 socket. That excludes other UIDs and positively authenticates the connecting kernel PID/UID/GID. It does **not** stop another process running as `hermes` from unlinking/rebinding the socket. A claim stronger than T-C against counterfeit replacement therefore requires the ratified distinct-principal system service or authenticated broker responses. No stronger claim is made.
|
||
|
||
---
|
||
|
||
## P5 — Source invalidation fail-closed
|
||
|
||
**Verdict: PASS**
|
||
|
||
### Command
|
||
|
||
```bash
|
||
python3 docs/compaction-refresh/probes/pi_gate0_run.py
|
||
```
|
||
|
||
Full output: [`evidence/raw/P2-P3-P5-P6-pi.txt`](./evidence/raw/P2-P3-P5-P6-pi.txt).
|
||
|
||
Each fault was injected into the manifest/source read by the real Pi `context` hook. Each run reached an actual model-produced `toolCallId`, then the runtime gate refused it:
|
||
|
||
| Fault | Runtime validation | Injection/promotion | Broker | Tool result |
|
||
| --- | --- | --- | --- | --- |
|
||
| Missing path | `reason=missing` | `injectionDecision=REFUSED`, `promotion=false` | `source_invalidation_revoke` | `allowed=false`, `unverified-source:missing` |
|
||
| 65 bytes with 64-byte max | `reason=oversize` | `REFUSED`, `promotion=false` | revoked | `allowed=false`, `unverified-source:oversize` |
|
||
| Bytes differ from pinned SHA-256 | `reason=hash-mismatch` | `REFUSED`, `promotion=false` | revoked | `allowed=false`, `unverified-source:hash-mismatch` |
|
||
|
||
Missing example:
|
||
|
||
```json
|
||
{"event":"context_return","sourceValidation":{"ok":false,"reason":"missing"},"injectionDecision":"REFUSED","promotion":false,"sourceBroker":{"event":"source_invalidation_revoke","new_lease_state":"REVOKED"}}
|
||
{"event":"tool_call","mapping":{"verified":false,"sourceReason":"missing"},"allowed":false,"reason":"unverified-source:missing"}
|
||
```
|
||
|
||
No fault case reached tool execution or promotion.
|
||
|
||
---
|
||
|
||
## P6 — Atomic Claude `additionalContext` + Pi `context` injection (A-v5-1 / T27)
|
||
|
||
**Verdict: T-C GAP — returns to planner**
|
||
|
||
### Commands
|
||
|
||
```bash
|
||
python3 docs/compaction-refresh/probes/pi_gate0_run.py
|
||
python3 docs/compaction-refresh/probes/p6_claude_run.py
|
||
rg -n -i "atomic|prefix-preserv" <installed Pi and Claude hook docs>
|
||
```
|
||
|
||
Full outputs:
|
||
|
||
- [`evidence/raw/P2-P3-P5-P6-pi.txt`](./evidence/raw/P2-P3-P5-P6-pi.txt)
|
||
- [`evidence/raw/P6-claude-additional-context.txt`](./evidence/raw/P6-claude-additional-context.txt)
|
||
- [`evidence/raw/P6-contract-gap.txt`](./evidence/raw/P6-contract-gap.txt)
|
||
|
||
### Positive empirical observations
|
||
|
||
**Pi:** The real `context` hook returned exactly one additional `AgentMessage`; the prior message prefix hash was unchanged. The real final provider payload contained exactly one occurrence in one content item, and the real model copied all bytes exactly:
|
||
|
||
```json
|
||
{"event":"context_return","inputCount":1,"outputCount":2,"injectionDecision":"ONE_ATOMIC_AGENT_MESSAGE","prefixPreservedByReturn":true,"blockLength":108,"blockSha256":"99c3...a0dd"}
|
||
{"event":"before_provider_request","markerOccurrences":1,"markerPaths":["$.input[1].content[0].text"],"finalPayloadValid":true}
|
||
{"event":"message_end","exactContextBlockCopied":true,"assistantTextSha256":"99c3...a0dd"}
|
||
```
|
||
|
||
**Claude:** The real `SessionStart` hook emitted one `hookSpecificOutput.additionalContext` string. Claude’s stream recorded successful hook execution, and the real model’s exact copied block matched byte length and SHA-256:
|
||
|
||
```text
|
||
block_length=116
|
||
block_sha256=ef6377d63552af075f4f4adec00165988418c5f46a992f4dce8e678b56fd34ac
|
||
assistant_copy_length=116
|
||
assistant_copy_sha256=ef6377d63552af075f4f4adec00165988418c5f46a992f4dce8e678b56fd34ac
|
||
assistant_copy_exact=True
|
||
```
|
||
|
||
### Why this is not a PASS
|
||
|
||
The installed Pi documentation says only that `context` receives a deep copy and may return `{ messages }`. The installed Claude documentation says only that `additionalContext` enters/adds to context/system prompt. The exact search result was:
|
||
|
||
```text
|
||
NO MATCH: neither installed runtime document states an atomic/prefix-preserving transport guarantee.
|
||
```
|
||
|
||
One or several successful complete deliveries cannot prove the transport invariant needed by A-v5-1. In particular, a harness-side middle deletion/replacement that preserves the terminal receipt is not detectable by the receipt. That is precisely R1’s assurance boundary. Therefore:
|
||
|
||
- absent or prefix-truncated terminal token: receipt-detectable;
|
||
- middle-drop preserving the tail token: **not receipt-detectable**;
|
||
- no documented runtime contract excludes that transform;
|
||
- classification: **T-C contract gap**.
|
||
|
||
No atomicity claim is inferred from empirical success.
|
||
|
||
---
|
||
|
||
## Independent probe review
|
||
|
||
After an initial review identified a session-global P2 correlation flaw, the probe was changed to queue request-scoped cycles from `before_provider_request` through assistant `message_end`; all runtime probes were re-run and raw checksums regenerated. The final independent review command was:
|
||
|
||
```bash
|
||
~/.config/mosaic/tools/codex/codex-code-review.sh \
|
||
-b d801d6c4c8a984d6a95033c49714210018d3d9a8 \
|
||
-o /tmp/827-gate0-rereview.json
|
||
```
|
||
|
||
Final review: **APPROVE**, confidence 0.91, 18 files reviewed, 0 blockers, 0 should-fix findings, 0 suggestions.
|
||
|
||
## Final admission decision
|
||
|
||
Gate0 requires every item to produce positive runtime evidence. P6 does not. **Do not admit WI-1..WI-7. Return A-v5-1/T27 to planner review.**
|
||
|
||
No feature work, push, PR, merge, or issue closure was performed.
|