ELNOR REPO READER TEXT MIRROR Original path: Memory Rebuild Docs/Flattening/Reviews/Stage 6 Reviews/Stage 6 E0 Red Teaming/DOC80 S6 E0 RT Adj Card R3.md Source repo: /Users/OpenClaw1/Elnor/Elnor Specs Git branch: main Git commit: dbaa25962edc11ab30e8d4ca1715f9ae5bf77331 Generated: 2026-06-09T01:23:58.539Z --- # E0 / DOC80-Core — Red-Team Adjudication Card R3 (egress lock fold) **Status:** Adjudication delta card. Supersedes R2's §22 (full replacement) and adds the non-egress lock patch. R2's §0–§21 and non-egress body otherwise stand as adjudicated. **R2 (base) + R3 (this delta) are the adjudicated patch package to be APPLIED to `Charter_Draft.md` to ratify E0 (Stage 6) — they are NOT yet applied. The ratified draft then becomes input to Stage-7 schema-body work.** **Base:** `DOC80 S6 E0 RT Adj Card R2.md` **Verdict:** **§22 ADJUDICATED WITH FIXES (Critical — must-fold-first; does NOT stall; NO architecture reopen).** Non-egress lock patch **specified** as the patch list in §(b). R3 confirmation passes complete (Claude `R3_LOCK_READY`; ChatGPT `R3_FOLD_FIX_NEEDED` → scope-residue sweep applied); capture audit `E0_CAPTURE_CONFIRMED` (confirms the **card** faithfully captures the adjudication — NOT that the spec was changed). **NOT YET APPLIED / NOT RATIFIED:** E0 ratifies only after R2's ~80 edits + R3's §22 + the non-egress patch are applied to `Charter_Draft.md`, the §15.5 regression runs, `Ratification.md` is written, and the discharge sweep completes. **Review lineage:** R2 §22 → two §22 red-team passes (ChatGPT + Claude, every citation verified) → adjudication → two adjudication red-team passes (ChatGPT + Claude) → this R3 fold. Citations verified against PropA R6.3, DOC24 R3.1.1, KDA R3, EC Core Add A V3.3. ## R3 change summary - §22 re-tiered to **Critical ratification blocker** (was "Substantive high"); the rhetorical "ARCHITECT_STOP — re-tier" phrasing is dropped (ARCHITECT_STOP is reserved for architectural-stop conditions). - **INV-E0-EGRESS-1**: gate-level **default-deny** (CR2, pre-attestation) on any non-`same_machine_local_runtime` destination that is unrecognized / unresolved / unmatched / permissive-by-omission. - **`E0EgressAttestation`**: trimmed **discriminated union** (same-machine no-lookup vs policy-bound); diagnostic field set (debugging-justified); over-keyed/redundant fields cut. - **`E0EgressDecisionOutcome`** aligned to PropA `SharingActionSchema` (`allow|warn|block|strip|redact`); **`scope` dropped** (no silent sixth value). - **payload_hash** = post-transform egressed bytes + TOCTOU verify; **multi-destination** = per-destination N attestations (not most-restrictive-as-default). - **KDA category error fixed**: render egress → `enforceKdaRenderPolicy`; **all** egress → the EC/DOC24 §21.1 gate. - **N8 unification**: `DisclosureScopeAttestationRef` resolves to `E0EgressAttestation`; the MFC carries the destination. - **Convergence ledger**: ONE record, two facets, **EC-signed / DOC24-appended** (`anchored_attestation`; NOT EC `serialized_durable` write — per the §12.1 "delivery attestations MUST NOT take a write-queue lock" invariant). - **`local_file_export` = egress** + PropA L1116 patch obligation (principle #2 omits it; principle #3 says only same-machine is non-egress → self-inconsistent). - **Non-egress lock patch:** destruction ledger EC-written; `RestoreMFC.initiating_member_ref` (promoted to `BaseMFC`); `PromptShellExposure` → `final_prompt_truth_ref` (no boolean proof); `RegistryEntryLifecycleState += candidate`; `SourceRevocationCascade.affected_set_manifest_ref`; `E0DurableRecord` illustrative; EC §4 in the Import-Graph sweep; `ErasureMFC` legal-hold for redaction; `RestoreMFC` re-evaluation invariant; "No manual tracking required" reworded. - Cross-doc obligations recorded in **OPA §6.Z3** (discharge like §8, NOT from this card). **Two genuinely-new items:** the PropA L1116 patch and the EC-owned destruction ledger. --- # (a) §22 — Egress enforcement binding (REVISED — replaces R2 §22) *Value-tier: **Critical ratification blocker**. "Critical" = must-fold-first: E0 does not ratify until §22-with-fixes is folded; folding the NAMED binding is the unblock — enforcement bodies are downstream cross-doc obligations (UR-53), so this does not stall the build and does not reopen DOC80 architecture.* **Audit result, one line:** the egress *model* exists and is strong (PropA P1 classifier L1623; §2 outbound taxonomy L1083-1092; fail-closed L785) but **no lint binds every send-site to a destination-correct policy decision**, and DOC24 §21.1 `SharedActionHandlerLayer` (validate → idempotency → receipt → emit) has **no policy-decision gate step**. UR-49 makes the PropA L95 "every outbound boundary runs through the policy engine" rule mechanically provable. **Grounding (verified — do NOT re-spec):** PropA P1 (L1623); PropA §2 destination enum (L1083-1092); PropA `SharingActionSchema` = `allow|warn|block|strip|redact` (L1073-1079); fail-closed (L785); matrix principles #2/#3 (L1116-1117 — see UR-53 PropA patch); KDA §3.2C `enforceKdaRenderPolicy` (render-only); EC §8.1; DOC24 §21.1 (char 176913). **> INV-E0-EGRESS-1 (DOC80-owned).** No outbound action may cross an egress boundary without an attached, destination-correct `E0EgressAttestation`. The egress gate (EC/DOC24 `SharedActionHandlerLayer`) resolves the **actual terminal destination** before dispatch; any destination that is (a) not `same_machine_local_runtime` and (b) **either** not a recognized PropA §2 destination **or** lacks a resolved `policy_decision` whose destination class equals the actual terminal destination and whose outcome permits or constrains the payload → **fail closed**. Unrecognized destination, unresolved terminal destination, stale policy generation, destination mismatch, permissive-by-omission, or dispatched bytes ≠ attested payload hash → fail closed. `same_machine_local_runtime` is no-lookup only for execution that stays on the machine and invokes no outbound tool; any terminal outbound tool call creates a new egress action and must be attested. Generalizes N8 to all outbound destinations. *(CR2 default-deny is a **gate rule, pre-attestation**: a destination that does not resolve to one of PropA's eight cannot be typed into the attestation and is blocked before any attestation is issued.)* **UR-50 — `E0EgressAttestation` (schema_owner DOC80; enforcement bodies cross-doc).** Trimmed discriminated union; vocabularies reference PropA, not redeclared. ```ts export type E0OutboundDestinationClass = | "same_machine_local_runtime" | "local_file_export" | "local_network_peer" | "firm_server" | "remote_peer" | "cloud_api" | "email_outbound" | "agent_messaging"; // == PropA §2 (L1083-1092) export type E0EgressDecisionOutcome = "allow" | "warn" | "block" | "strip" | "redact"; // == PropA SharingActionSchema (L1073-1079); "scope" intentionally NOT a value export type E0EgressActionKind = | "render_to_model" | "raw_artifact_export" | "connector_send" | "agent_message" | "channel_projection" | "cloud_api_call" | "network_transfer"; export type E0InteractionMode = "interactive" | "background_non_interactive" | "scheduled" | "agent_initiated"; type E0EgressAttestationBase = { schema_version: 1; attestation_id: string; created_at: string; // RFC3339 UTC action_envelope_ref: string; action_kind: E0EgressActionKind; outbound_destination_class: E0OutboundDestinationClass; declared_destination_ref: string; actual_terminal_destination_ref: string; // resolved after connector/adapter/channel; MUST be dereferenceable to provider/connector/channel terminal identity sufficient for policy replay decision_outcome: E0EgressDecisionOutcome; interaction_mode: E0InteractionMode; payload_hash: string; // hash of the ACTUAL egressed bytes, AFTER any strip/redact transform payload_privilege_classes: PrivilegeClassPropA[]; // PropA P1 (L1623) — referenced, not redeclared receipt_ref: string; // required for ALL non-same-machine egress, including "allow" memory_coordination_trace_ref: string; memory_flow_certificate_id?: string; // link to Render/Export/DelegationMFC chain disclosure_reevaluated_at_boundary: true; // the N8 attestation, generalized — verifiable via policy_generation_id redaction_map_ref?: string; // required iff decision_outcome === "redact"; reconciles the post-transform payload_hash }; type SameMachineEgressAttestation = E0EgressAttestationBase & { outbound_destination_class: "same_machine_local_runtime"; policy_lookup_required: false; policy_decision_id?: never; }; type PolicyBoundEgressAttestation = E0EgressAttestationBase & { outbound_destination_class: Exclude; policy_lookup_required: true; policy_decision_id: string; policy_decision_destination: E0OutboundDestinationClass; // MUST === outbound_destination_class policy_generation_id: string; // required — boundary-freshness proof policy_evaluator_hash?: string; // optional pending EC §8 confirmation; compiled_policy_ref deferred to EC }; export type E0EgressAttestation = SameMachineEgressAttestation | PolicyBoundEgressAttestation; ``` **Convergence ledger — one record, two facets (EC-signed, DOC24-appended).** Same primitive egress + learning need, but two facets, not one column; a delivery/audit (`anchored_attestation`) object, NOT a mutation — EC-signed against a read-consistent generation and **DOC24-appended off the write-queue**. Do not route through EC's `serialized_durable` path. ```ts // schema_owner: DOC80. EC-signed (issued_by:'EC', read-consistent generation), DOC24-appended OFF the write-queue // (anchored_attestation; NOT serialized_durable). Consumed by DOC84/DOC85. One record, two facets — not one column. export type SourceDeliveryDisposition = "delivered" | "truncated" | "dropped" | "suppressed" | "redacted" | "stripped" | "blocked"; export type E0PerSourceTurnLedgerRow = { schema_version: 1; row_id: string; trace_ref: string; // -> MemoryCoordinationTrace (a composite correlating serialized_durable + anchored_attestation records) turn_id: string; source_ref: string; context_product_instance_ref?: string; prompt_span_ref?: string; final_prompt_disposition?: SourceDeliveryDisposition; // facet 1 -> learning attribution feeds LearningAttributionMFC (serialized_durable, downstream/off hot path) final_prompt_truth_ref?: string; egress_disposition?: SourceDeliveryDisposition; // facet 2 -> egress boundary egress_attestation_ref?: string; outbound_destination_class?: E0OutboundDestinationClass; actual_terminal_destination_ref?: string; reason_codes: string[]; issued_by: "EC"; // EC-signed created_at: string; }; ``` **UR-51 — lints** (canonical = inherited from Flatten §17.4; rest `[proposed]`, Stage-9 confirm): ```text [canonical] policy.bare_render_action [canonical] policy.export_stamp_without_destination [proposed] egress.outbound_action_without_egress_attestation # umbrella [proposed] egress.outbound_action_without_destination_policy_decision [proposed] egress.destination_mismatch_between_action_and_policy [proposed] egress.unrecognized_destination_not_failed_closed # CR2 [proposed] egress.terminal_destination_unresolved_before_dispatch [proposed] egress.policy_generation_missing [proposed] egress.redaction_without_redaction_map [proposed] egress.enforced_outcome_without_receipt # subsumes strip/redact/allow-to-external receipt checks [proposed] egress.warn_background_not_coerced_to_block [proposed] egress.dispatched_payload_differs_from_attested_hash # TOCTOU [proposed] egress.fanout_attestation_count_mismatch # multi-destination [proposed] egress.destination_class_enum_drift_from_propa # don't redeclare PropA §2 [proposed] egress.same_machine_runtime_invoked_outbound_tool_without_attestation ``` **UR-52 — golden fixtures** (`gate_level: final_switchover`; negative/invariant cases first): ```text egress.destination_mismatch_fails_closed # the core INV check egress.unrecognized_destination_fails_closed # CR2 egress.unclassified_source_fails_closed_except_same_machine # PropA L785 egress.same_machine_allows_without_lookup egress.same_machine_runtime_invoked_outbound_tool_requires_new_attestation egress.allow_to_external_emits_receipt egress.dispatched_payload_differs_from_attested_hash_fails_closed # TOCTOU egress.fanout_per_destination_decisions # privileged email: internal=allow, external=block egress.privileged_to_email_outbound_blocks egress.privileged_to_agent_messaging_blocks egress.sensitive_to_cloud_api_redacts egress.raw_artifact_export_to_non_local_blocks_or_redacts egress.local_file_export_privileged_requires_policy_decision egress.local_network_peer_privileged_blocks egress.firm_server_client_confidential_warns egress.remote_peer_privileged_blocks egress.channel_projection_applies_policy egress.warn_background_non_interactive_coerces_to_block ``` **UR-53 — cross-doc / OPA implications (discharge like §8 — NOT edited from this card; recorded in OPA §6.Z3):** ```md - EC / DOC24 §21.1: ADD the policy-decision gate step — validate -> resolve terminal destination -> destination policy decision -> egress attestation -> execute. - DOC24: emit the per-turn per-source ledger (final_prompt + egress facets), EC-signed / DOC24-appended off the write-queue (anchored_attestation; NOT EC durable-write). Owner split: appender DOC24 / signer EC / consumers DOC84-DOC85. - KDA / DOC84: rendered-content egress ONLY routes through enforceKdaRenderPolicy; KDA is NOT the universal gate for raw artifact export, connector send, or DOC12 channel projection — those use the EC/DOC24 gate. - PropA: bind §2 outbound matrix mechanically; PATCH §2.6 principle #2 (L1116) to include local_file_export, or reword as "all destinations except same_machine_local_runtime are outbound." [NEW cross-doc item] - DOC11 / OpenClaw: EXTEND OBL-D11/OPENCLAW-NEW-FINAL-PROMPT-SPAN-01 for as-sent capture; ADD separate egress-gate obligations for native/connector dispatch outside final-prompt render. - DOC12: channel projection applies egress policy before dispatch. - DOC16 / connectors / DOC4: provider/native outbound adapters expose terminal destination before dispatch; MUST NOT bypass the gate. - DOC23: outbound task modules call the EC/DOC24 egress gate before provider execution. - DOC20 / DOC21 / DOC22: egress policy-decision receipts (allow/warn/block/strip/redact) visible on send/export/share surfaces; register new UI. - DOC84 / DOC85: consume the source ledger for learning attribution (LearningAttributionMFC = serialized_durable, downstream/off hot path). - PHASE-2 FLIP (named gate row, ADQ-222): remote_peer / firm_server / local_network_peer flip fail-closed -> gated-allow when networking ships; anchor for the local<->networked memory boundary. ``` **Tracking.** UR-49/50/51/52 = active DOC80 §22 additions (Critical tier). UR-53 = OPA obligations (OPA §6.Z3). **Two genuinely-new cross-doc items: the PropA L1116 patch and the EC-owned destruction ledger.** The empirical piece (do connector/DOC11/DOC12 dispatch actually call the gate at runtime) is a Claude Code probe, enrollable in §7 + §15.4. --- # (b) Non-egress lock-patch list (R3) — targeted edits to the R2 body 1. **[ChatGPT #1 · HIGH] `MemoryDestructionLedger` EC-owned.** §3.7 currently reads "bodies/storage = DOC84 + DOC85 + DOC11" — conflicts with EC-sole-writer. EC owns the durable append/write path; DOC84/85/11 are consumers/surfaces/effects. Change the §15.4/deferral row `DOC84 + DOC85 + DOC11` → `EC durable storage/write path; DOC84/DOC85/DOC11 consumers/surfaces/effects`. (Records erasure/restamp/restore — all `serialized_durable`, so EC-written is correct; contrast the convergence ledger, which is NOT.) 2. **[ChatGPT #2 / Claude D] `RestoreMFC.executor` → `initiating_member_ref`, promoted to `BaseMFC`.** Add `initiating_member_ref: ProducerDocRef` to `BaseMFC`; EC remains `issued_by` / durable executor. Replace lint `restore.executor_equals_ec` → `mfc.uses_executor_field_instead_of_initiating_member` + keep the EC-issuer invariant. 3. **[ChatGPT #3] `PromptShellExposure` boolean → proof-shaped.** Replace `exposed_in_final_prompt: boolean` with required handoff: `final_prompt_truth_ref` + rendered/trimmed/suppressed span refs (+ `context_product_instance_ids` where applicable). NAMED-only, body Stage 7. Lint `prompt_shell.exposure_boolean_without_final_prompt_truth_ref`. 4. **[ChatGPT #4] `RegistryEntryLifecycleState += candidate`.** `'candidate' | 'active' | 'deprecated' | 'retired'`; rule "candidate entries are not runtime-emittable unless a registry-specific rule allows test fixtures"; lint `registry.candidate_entry_emitted_at_runtime`. 5. **[ChatGPT #5] `SourceRevocationCascade += affected_set_manifest_ref`.** Add `affected_set_manifest_ref: SourceRevocationAffectedSetManifestRef`; lint `revocation.cascade_missing_affected_set_manifest`. Names the requirement; per-plane scan bodies stay downstream. 6. **[ChatGPT #6] `E0DurableRecord` illustrative.** "The list is illustrative, not exhaustive; every durable registry/retained-proof/audit artifact carries `schema_version` + `created_at`." 7. **[ChatGPT #7] EC §4 in Import-Graph sweep.** Sweep line → "confirm EC §1/§3/§4/§7/§8 ECSeamContract pins; no local redefinition." 8. **[Claude A · litigation] Legal-hold clearance for redaction.** `ErasureMFC.legal_hold_clearance_ref` required iff `erasure_kind ∈ {hard_destruction, redaction}` (currently gates only `hard_destruction`); `soft_tombstone` ungated; lint `erasure.redaction_under_legal_hold_without_clearance`. 9. **[Claude B · litigation] Restore re-evaluation invariant.** §12.1: "a restore re-evaluates current policy + source-revocation + legal-hold at restore time; a `hard_destruction` cannot be restored." Lints `restore.reintroduces_revoked_or_held_material`, `restore.of_hard_destruction`. `prior_erasure_certificate_ref` required iff `restored_from === 'recycle_bin'`. 10. **[Claude C] N8 unification** — in §22 (`DisclosureScopeAttestationRef` resolves to `E0EgressAttestation`; add `outbound_destination_class`/attestation ref to Export/DelegationMFC). 11. **[ChatGPT #8 · low] Reword "No manual tracking required"** → "No out-of-band memory is required once the §7 deferral register, §15.4 gate table, §17.4 preservation matrix, OP-A rows, ADQ ledger, and cross-artifact sweep entries are updated." --- *End of R3.*