ELNOR REPO READER TEXT MIRROR Original path: Current Specs/DOC73/DOC73_Artifact4_R0.4.md Source repo: /Users/OpenClaw1/Elnor/Elnor Specs Git branch: main Git commit: dbaa25962edc11ab30e8d4ca1715f9ae5bf77331 Generated: 2026-06-09T01:23:58.539Z --- # DOC73 V1.6 — Artifact 4: DOC24 + EC Session & Search Runtime Addendum (R0.4) **Status:** R0.4 — CSA extraction applied; pending red-team Round 1. The prior "R1.0 freeze candidate" claim from R0.3 is RESCINDED. §18 CSAInjectionTierPolicy DELETED in entirety; SessionProfile.csa_injection_tier_policy_ref field removed; worked examples consuming CSAInjectionTierPolicy removed; consumer-side session-orientation orchestration deferred to DOC72. **R0.4 changes from R0.3:** Per architect-issued CSA extraction prompt 2026-05-04 (see `DOC73_V1_6_CSA_EXTRACTION_PRE_REPORT.md` and `DOC73_V1_6_CSA_EXTRACTION_REPORT.md`): | Change | Action | Section | |---|---|---| | §18 CSAInjectionTierPolicy entire section | DELETED wholesale; replaced with deferral note | §18 | | SessionProfile schema | Removed `csa_injection_tier_policy_ref?: string` field and comment | §2.1 SessionProfile | | Q-3-A4-7 R0.3 status entry | Replaced with moot-post-extraction note; architect preference (tier_3_minimal_orientation) preserved in BUILD_QUESTIONS §11 historical record for future DOC72 session-orientation design | R0.3 changes table | | Worked examples consuming CSAInjectionTierPolicy | DELETED; other worked examples (session/search runtime mechanics) preserved | §21 | | Landing Matrix entries citing CSAInjectionTierPolicy | REMOVED rows; corresponding entries shifted | Landing Matrix | | `DOC24_CSA_INJECTION_DEFAULT_TIER` env var | REMOVED (cleaned up with §18 deletion) | §18 | | Scope statement "+ CSAInjectionTierPolicy" | REMOVED | Scope | | `tier_strategy` enum (4 values: tier_1_full_orientation / tier_2_targeted_orientation / tier_3_minimal_orientation / tier_4_disabled) | REMOVED (lives in §18 schema; cleaned up with §18 deletion) | §18 | | G-ACT-3 acceptance test | DELETED entirely | Acceptance tests | | §15.7 INTENT_DISCLOSURE_CONFIDENCE_THRESHOLD 0.85 default | PRESERVED (Q-3-A4-6 architect decision survives extraction); no CSA dependency | §15.7 | | Status header | Updated to R0.4; removed "R1.0 freeze candidate" language | (header) | **No V3.7-or-earlier obligation rows added or removed in DOC73 itself.** R0.4 is a surgical extraction of CSAInjectionTierPolicy + all CSA-implied scaffolding from Artifact 4. OPA V3.10 → next-revision flags tracked in `DOC73_V1_6_CSA_EXTRACTION_REPORT.md`. --- **R0.3 changes from R0.2 (PRESERVED FOR HISTORICAL RECORD; partially superseded by R0.4 extraction above):** | Question | R0.3 action | R0.3 section | |---|---|---| | **Q-3-A4-6** — INTENT_DISCLOSURE_CONFIDENCE_THRESHOLD default value | Lowered from 0.95 → 0.85; rationale: most full-sentence litigator queries classify clearly above 0.85; BDSM EMA per V4-§4.X-BDSM EMA tunes per-user from telemetry | §15.7 (PRESERVED in R0.4 — no CSA dependency) | | **Q-3-A4-7** — CSAInjectionTierPolicy default tier | [R0.4 PATCH per CSA extraction 2026-05-04: MOOT post-extraction; CSAInjectionTierPolicy removed from V1.6 per CSA extraction. Architect's preference (tier_3_minimal_orientation) preserved in BUILD_QUESTIONS §11 historical record for future DOC72 session-orientation design.] | §18.2 (REMOVED in R0.4) | **R0.3 was a defaults-tuning pass per architect Tier B triage. R0.4 supersedes §18.2 disposition entirely via CSA extraction.** --- **R0.2 changes from R0.1:** Per `AUDIT_DOC73_Artifact4_R0.1.md` findings + architect Path B-minus decision: | Audit finding | R0.2 action | R0.2 section | |---|---|---| | **CRIT-A4-1** — Phantom UIComplexityTier | Inlined enum declaration (4-tier scale) | §2.0 (NEW pre-schema) | | **CRIT-A4-2** — Phantom DocumentRef + StructuralSelectorList | DocumentRef aliased to SourceArtifactRef; StructuralSelectorList annotated `[forecast Artifact 2 §K]` | §4.1 | | **CRIT-A4-3** — share_link_grant envelope construction missing | Added §5.0 "Share-link grant envelope construction" with `grant_share_link()` flow + kernel envelope per Artifact 3 §4.3.9 | §5.0 (NEW) | | **HIGH-A4-1** — Phantom helper functions (~32) | DEFERRED to Step 9 per Path B-minus (cross-artifact consolidation needed); inline note added | (deferred) | | **HIGH-A4-2** — INV-15.7.8/9 sole-writer + read-only specialist NOT enforced for memory_agent / document_intelligence_agent | Added cross-references to Artifact 3 §20 in §11 ExecutorClass + §11.4 dispatch | §11 + §11.4 | | **HIGH-A4-3** — ShareTokenRevocation runtime split between Artifact 4 §5.2 + Artifact 3 §4.3.10 | Added explicit reconciliation note in §5.2 | §5.2 | | **HIGH-A4-4** — Worked Example §21.1 result counts illustrative not canonical | Annotated as ILLUSTRATIVE | §21.1 | | **HIGH-A4-5** — `compute_session_access_set` forward-reference §15.4 → §16.1 | Added forward-reference note in §15.4 | §15.4 | | **MED-A4-1** — WatermarkPolicy "custom" kind underspec | Removed "custom" from V1.6 enum; deferred V1.7+ | §6.1 | | **MED-A4-2** — ShareTokenRateLimits defaults not in schema | Inlined V1.6 default values per Q-3-A4-8 | §5.1 | | **MED-A4-3** — SearchExecutionResult schema missing | Declared inline | §10.1 | | **MED-A4-4** — SearchResult schema missing | Declared inline | §10.1 | | **MED-A4-5** — OutputPolicy / DocumentDeliveryPolicy / TranscriptRetentionPolicy / LearningCapturePolicy schemas missing | Cross-referenced V1.5.1 §11.X carry-forward | §2.1 | | **MED-A4-6** — RRF_K constant cross-reference inlined | RRF_K = 60 inlined | §10.3 | | **MED-A4-7** — INTENT_DISCLOSURE_CONFIDENCE_THRESHOLD configuration | DOC24_-prefixed config name added | §15.7 | | **MED-A4-8** — DOC24_/EC_ prefix consistency | Renamed configs to DOC24_-prefix | §10.3 + §13.5 | | **MED-A4-10** — AccessOverlay cache invalidation | Added §16.5 cache invalidation rules | §16.5 (NEW) | | LOW + DRAFTING NOTES | Tracked in `DOC73_V1_6_BUILD_QUESTIONS.md` for Step 9 architect review | (deferred) | **No V3.7-or-earlier obligation rows added or removed.** R0.2 is a tightening pass. --- **Status:** R0.2 (Step 5 output → Step 6 audit revision). **Scope:** DOC24 capability registry runtime + Group I session profile + share-link Mode 1 + reason code registry consumption + Group M search posture + Unified Search Router + multi-executor search plan + retrieval posture + SearchCoverageReceipt internal/visible split + QueryExpansion access filtering + Group B2 read-time access overlay enforcement + Group K read path (binding outcome consumption). [R0.4 PATCH per CSA extraction 2026-05-04: "+ CSAInjectionTierPolicy" removed from scope; §18 deleted; consumer-side session-orientation orchestration deferred to DOC72.] **Owners:** DOC24 (runtime routing, capability registry, manifests, registries) + EC (session enforcement, capability execution gating, capacity leases). Per V4-§0.4-1 (R-CG #1 + R-G55X §3): capability registry is owned by DOC24, NOT EC. EC owns capacity leases and capability execution gating. DOC25 owns document-intelligence tool registration payloads. **Position in V1.6 release wave:** Artifact 4 of 5 (per V4 §0.4: Artifact 1 Core / Artifact 2 Legal & Corpus Surfaces / Artifact 3 EC + DOC73 Transaction Kernel / **Artifact 4 DOC24 + EC Session & Search Runtime** / Artifact 5 DOC25 Legal Artifact & Materialization). **Consumes from Artifact 1:** canonical schemas (PBEOperationEnvelope, KernelEffect, RecordedModelOutput, ContentHashRef, activity entry types per Artifact 1 §A.5 — WorkPhaseEntry/CorpusActivityEntry/CaseActivityEntry/ArtifactEntry/UnresolvedThreadEntry); V16 cross-cutting INVs; RecentActivityRollup canonical schema; PBEOperationKindV16Candidate enum + simulation_support_level lookup table (per Artifact 1 R0.3 §2.1.A). [R0.4 PATCH per CSA extraction 2026-05-04: OrientationContextEntry removed from consumes list — type was deleted in Artifact 1 R0.5 §A.4.] **Consumes from Artifact 3:** kernel runtime entry points, AccessOverlay write-time enforcement (read-time mirror specified here); INV-A-TAINT-INFECTIOUS-1 lattice; visibility class typing. **Consumes from Artifact 5:** SourceArtifact / ArtifactSegment schemas + ECF header parser output (read-time consumers). **This artifact does NOT redefine those schemas.** --- ## §0. About this artifact ### §0.1 Position in the V1.6 Release Wave Artifact 4 specifies **the runtime mechanics of the read path**: session profile lifecycle, share-link Mode 1, capability registry runtime, search router (multi-executor), retrieval posture resolution, search coverage and expansion receipts, read-time access overlay enforcement, and binding-outcome consumption. [R0.4 PATCH per CSA extraction 2026-05-04: "and CSA injection tier policy" removed from scope; §18 session-orientation injection deferred to DOC72.] Artifact 3 specified the **write path** (kernel envelope construction, write-time access overlay enforcement). Artifact 4 mirrors that boundary on the read side. Where Artifact 3 specifies how visibility taint propagates AT WRITE TIME (the create envelope picks up max_visibility_class), Artifact 4 specifies how visibility filtering applies AT READ TIME (search retrieval enforces access set BEFORE ranking). The two artifacts share the AccessOverlay schema (declared in Artifact 1; read-time + write-time enforcement live in Artifact 4 + Artifact 3 respectively). ### §0.2 What Artifact 4 covers ```text Artifact 4 normative scope: §1 Runtime overview (DOC24 + EC split; consumed schemas; entry points) §2 Group I — SessionProfile schema + state machine §3 Group I — SessionKind enum + identity_mode + capability_policy §4 Group I — SharedCorpusView (V4-I-2 + V4-I-4 expansion + INV-I-SHARE-VIEW-1 + INV-I-SHARE-VIEW-2 deny-wins per V4-I-1) §5 Group I — ShareTokenPolicy + ShareTokenRevocation per V4-I-5 (active_session_disposition / downloaded_copies_disposition / cached_response_disposition) §6 Group I — NativeSessionScopeBinding (V4-I-3 expanded with context_inheritance_policy / auth_inheritance_policy / transcript_visibility_policy / watermark_policy / child_spawn_constraint) §7 Group I — UtilitySignalPolicy share-link defaults per V4-I-6 + DOC1GovernanceSplit + INV-DOC1-GOV-1 + SessionDenialMessage per V4-I-DENIAL-1 + ExternalUploadFileSafetyControls + INV-I-UPLOAD-1 §8 DOC24 capability registry runtime + namespace registry + registration semantics + INV-I-CAP-1 refined per V4-I-2 §9 Reason code registry consumption (registry canonical at §0.7.2; this artifact specifies session runtime consumption) §10 Group M — Unified Search Router runtime §11 Group M — UnifiedSearchPlan (V4-M-5 multi-executor + result_fusion_strategy) + ExecutorAssignment + ExecutorClass §12 Group M — RetrievalPosture (V4-M-1 renamed) + SearchScope (V4-M-SCOPE temporal_scope) + filing_content_scope §13 Group M — SearchExecutionManifest emission + SearchCoverageReceipt internal vs visible split (V4-M-2) + INV-M-COVERAGE-VISIBILITY-1 + scope_digest (V4-M-8) + ranked_top_k_not_exhaustive (V4-M-6) §14 Group M — QueryExpansion access-filtered (V4-M-3) + INV-M-EXPANSION-ACCESS-1 §15 Group M — SearchPlanFailure narrowed (V4-M-4) + INV-M-VERSION-AWARE-1 (V4-M-7) + INV-M-SESSION-1 (V4-M-INV-SESSION) + QueryIntentResolution + INV-M-INTENT-1 + INV-M-NEGATIVE-1 + INV-M-COVERAGE-INDEX-1 + INV-M-ACCESS-RANK-1 §16 Group B2 — Read-time access overlay enforcement (mirror of Artifact 3 §12 write-time) §17 Group K read path — binding outcome consumption + CorpusBindingContribution ledger reads + extraction_run_id linkage §18 Session-orientation injection — DEFERRED TO DOC72 [R0.4 PATCH per CSA extraction 2026-05-04: §18 previously specified CSAInjectionTierPolicy (V4-§0.4-2 reclassified from Artifact 1); now a deferral note. Consumer-side session- orientation orchestration is DOC72's architectural concern.] §19 INV-MVC-1 + INV-MVC-2 (read-time mirror; canonical home Artifact 1 §15.X) §20 SearchReceiptRetentionPolicy (V3-M-13 + INV-M-RETENTION-1 ephemeral vs durable per V4-§0.7-2) §21 Worked Examples Appendix (multi-executor search plan dispatch, SharedCorpusView deny-wins resolution, sub-agent context isolation, share-token revocation downloaded-copies disposition) §22 Landing Matrix entries authored by Artifact 4 Drafting Summary ``` ### §0.3 What Artifact 4 does NOT cover ```text Out of scope: - Kernel write primitives (Artifact 3) - Write-time access overlay enforcement (Artifact 3 §12) - Legal domain semantics — FilingUnit, MotionChain, RulingDisposition, CourtDispositionObservation (Artifact 2 §O) - DOC25 ingestion mechanics, materialization, ECF parser internals (Artifact 5) - StructuredExtractionStrategy / pattern library / extraction pipeline (Artifact 5 §6 + Artifact 2 §J) - Brief-bank profile semantics, topic governance (Artifact 2 §J) - Source bindings entity, contribution ledger, lifecycle UI (Artifact 2 §K — schemas; Artifact 3 §13-§14 — kernel runtime; Artifact 4 §17 — read path consumption only) - Mechanism 4 RecentActivityRollup canonical schema (Artifact 1 §16; Artifact 4 §18 originally specified CSAInjectionTierPolicy runtime consumer surface — REMOVED in R0.4 per CSA extraction; consumer-side orchestration deferred to DOC72) - User-facing UI rendering of search results / cards / snippets (DOC20/DOC7 per V4 §2.1.4 owner split; Artifact 4 specifies the data contract Q Dashboard renders) - Q Dashboard "Jump to Source" affordance for CU.source_spans (Q Dashboard layer) - Cluster emergence (Artifact 1 §11) - VersionedClaim trait (Artifact 1 §10) - Authority computation algorithm (Artifact 1 §9) ``` ### §0.4 [V1.6 DRAFTING NOTE] markers in this artifact Per the standing build process: ambiguities not resolvable from V4 / V1.5.1 / OPA V3.8 sources are documented inline as `[V1.6 DRAFTING NOTE]` and tracked in `DOC73_V1_6_BUILD_QUESTIONS.md`. Tracked items (Q-3-A4-*) appear in §6 of that file after this artifact's self-audit. ### §0.5 Per-Artifact Gating Contract for Artifact 4 (per V4 §0.2.1) Artifact 4 ships only when the following gates pass: ```text G4.1 Group I session profile spec complete: - SessionProfile schema (V2 base + V3-I-* + V4-I-* patches) - profile_state state machine (draft / active / expired / revoked / suspended) - identity_mode enum (anonymous_share_token / email_bound / passcode_required / host_approved_named_external / host_user / system_agent) - capability_policy with deny-wins resolution - SharedCorpusView (V4-I-2 document_scope + V4-I-4 view_temporal_mode + visibility_class_ceiling) - INV-I-SHARE-VIEW-1 default-source-only enforcement - INV-I-SHARE-VIEW-2 deny-wins precedence per V4-I-1 - ShareTokenPolicy + ShareTokenRevocation per V4-I-5 - NativeSessionScopeBinding per V4-I-3 - SessionDenialMessage per V4-I-DENIAL-1 - UtilitySignalPolicy share-link defaults per V4-I-6 - ExternalUploadFileSafetyControls + INV-I-UPLOAD-1 G4.2 DOC24 capability registry: - Namespace registry schema + registration semantics - INV-I-CAP-1 (V3 + V4-I-2 refined) - CapabilityPattern (kind: exact / prefix_wildcard / namespace_all) - Capability execution gating split: DOC24 owns registry; EC owns execution capacity gating - Reason code registry consumer surface G4.3 Group M search router: - Unified Search Router runtime - UnifiedSearchPlan with executor_assignments[] + result_fusion_strategy per V4-M-5 - ExecutorClass enum + ExecutorAssignment schema - RetrievalPosture (V4-M-1 renamed: document_text_primary / derived_memory_primary / metadata_primary / mixed_surface_disclosed / cross_source_synthesis) - SearchScope with temporal_scope per V4-M-SCOPE - SearchExecutionManifest emission + retention classification - SearchCoverageReceipt internal vs visible split per V4-M-2 - INV-M-COVERAGE-VISIBILITY-1 - QueryExpansion access-filtered per V4-M-3 - INV-M-EXPANSION-ACCESS-1 - SearchPlanFailure narrowed per V4-M-4 - INV-M-VERSION-AWARE-1 per V4-M-7 - scope_digest field per V4-M-8 - ranked_top_k_not_exhaustive per V4-M-6 - INV-M-SESSION-1 per V4-M-INV-SESSION - QueryIntentResolution + INV-M-INTENT-1 - INV-M-NEGATIVE-1 (no phantom emptiness) - INV-M-COVERAGE-INDEX-1 - INV-M-ACCESS-RANK-1 (access before ranking) - INV-MVC-1, INV-MVC-2 read-time mirrors G4.4 Group B2 read-time enforcement: - AccessOverlay consumption at search retrieval - INV-B2-OVERLAY-RESOLUTION-1 read-side mirror per V4-B2-1 - access_restriction enum runtime check (preview_only / redacted_only / not_shareable affordances in result rendering) - Per-recipient state resolution per Artifact 5 §5.3 + Artifact 4 §16 G4.5 Group K read path: - Binding outcome consumption (BindingOutcomeRecord reads) - CorpusBindingContribution ledger reads - extraction_run_id linkage + INV-EXT-7 field-level resolution consumer surface G4.6 [R0.4 PATCH per CSA extraction 2026-05-04: gate G4.6 originally tracked CSAInjectionTierPolicy schema declaration / tier control / consumer contract. CSAInjectionTierPolicy has been DELETED from V1.6; consumer-side session-orientation orchestration deferred to DOC72. Gate G4.6 is RESCINDED.] G4.7 Cross-artifact dependencies declared in Landing Matrix: - Consumed schemas listed - V4 patches covered enumerated - OP-A rows authored All gates required before Artifact 4 ships to coding agents. ``` ### §0.6 Drafting discipline reminders Per Artifact 1 §1 standing rules: - **Anti-summarization mandate**: every normative rule stated explicitly. - **No-invention rule**: ambiguities not resolvable from sources flagged with `[V1.6 DRAFTING NOTE]`. - **State machine fidelity**: profile_state transitions enumerated; SearchPlanFailure failure_kind enum complete. - **INVs are executable**: runtime check pseudocode for each Group M / Group I / Group B2 INV. - **Cross-spec contracts consumed, not redefined** (INV-V16-NO-LOCAL-SCHEMA-1). --- ## §1. Runtime overview ### §1.1 Two-owner split (DOC24 + EC) Per V4-§0.4-1 (R-CG #1 + R-G55X §3) — Artifact 4 owner correction: ```text DOC24 owns (runtime routing + registries): - Capability registry (namespace registry + per-capability registration; canonical home §8 below) - Unified Search Router (deterministic planner; canonical home §10) - SearchExecutionManifest + SearchCoverageReceipt schemas - SourceSurfaceDisclosure schema - SearchIndexSnapshot + QueryExpansionRecord schemas - QueryIntentResolution - Reason code registry consumer surface (registry canonical at §0.7.2 storage registry gate; Artifact 4 §9 specifies session runtime consumption) - Manifests / retention policy enforcement at runtime - SessionProfile lifecycle (state machine + transitions) EC owns (session enforcement + capacity): - Session profile persistence (durable per INV-V16-RETENTION-DURABLE-1) - Capability execution gating (whether the registered capability can execute given current capacity) - Capacity leases for search routing (per V3.7 OBL-EC-NEW-CAPACITY-LEASE-01) - Native session scope binding enforcement (per §6 below) DOC73 cross-doc owns: - Posture policy (which posture maps to which retrieval contract; §12 below) - Memory/document semantics (INV-MVC-1, INV-MVC-2 read-time mirror §19 below; canonical home Artifact 1 §15.X) - Query intent enumeration (QueryIntent values; §A enum in Artifact 1) DOC15/KDA: source-surface render templates (out of scope here) DOC20/DOC7: per-result UI cards (out of scope here) DOC25: DocumentArtifactVersionChanged event emission (Artifact 5 §13) DOC18: legal citation/token normalization (FTS5 tokenizer; consumed at §11 ExecutorClass) PropA: exposure policy contract for stateless API authorization (consumed at §16 read-time) ``` OP-A row coverage cited per-section. ### §1.2 Position in the 5-artifact split ```text Artifact 1 (Core) declares schemas + cross-cutting INVs Artifact 2 (Legal & Corpus Surfaces) declares legal entity schemas Artifact 3 (Kernel Runtime) write path + INV enforcement at write Artifact 4 (Session & Search Runtime) ← this artifact read path + session + capability registry + access overlay read-time Artifact 5 (DOC25 Legal Artifact & ingestion + materialization + Materialization) ECF parser + ExtractionStateMachine ``` Artifact 4 is the **read path** mirror to Artifact 3's **write path**. The two share AccessOverlay (Artifact 1-declared; Artifact 3 §12 write-time + Artifact 4 §16 read-time enforcement). ### §1.3 Consumed schemas (verbatim from Artifact 1, Artifact 3, Artifact 5) ```text From Artifact 1 (Core): PBEOperationEnvelope Artifact 1 §17.1 RecordedModelOutput (R0.3) Artifact 1 §A.11 ContentHashRef Artifact 1 §A.9 PBEOperationKindV16Candidate Artifact 1 §2.1 SimulationSupportLevel Artifact 1 R0.3 §2.1.A (simulate eligibility lookup) RecentActivityRollup Artifact 1 §16.2 (Mechanism 4 canonical; consumer-side orchestration deferred to DOC72 per R0.4 CSA extraction) [R0.4 PATCH per CSA extraction 2026-05-04: OrientationContextEntry Artifact 1 §A.4 removed from cross-reference — type was deleted in Artifact 1 R0.5 §A.4 (reserved-note in place).] ExcludedCorpus / ExcludedFilingUnit / Artifact 1 §A.1-§A.3 ExcludedFilingPart QueryIntent Artifact 1 §A.6 CapabilityRef / EdgeTypeRef Artifact 1 §A.7 TopicDirective Artifact 1 §A.7 V16 cross-cutting INVs: INV-V16-TIMEZONE-1 Artifact 1 §19.1 (consumed for SearchScope.temporal_scope) INV-V16-NO-LOCAL-SCHEMA-1 Artifact 1 §19.2 INV-V16-RETENTION-EPHEMERAL-1 Artifact 1 §19.3 INV-V16-RETENTION-DURABLE-1 Artifact 1 §19.4 INV-V16-STORAGE-GRANULARITY-1 Artifact 1 §19.6 From Artifact 3 (Kernel Runtime): AccessOverlay schema cross-artifact (declared in Artifact 1 §A; read-time enforcement here) AccessOverlayTarget enum Artifact 3 §12.1 + Artifact 1 INV-A-TAINT-INFECTIOUS-1 lattice Artifact 3 §7.2 (read-time consumer) INV-B2-OVERLAY-RESOLUTION-1 Artifact 3 §12.3 (canonical home; read-time mirror §16) PBEOperationEnvelope read API Artifact 3 §1.4 (kernel.read_envelope) AuditReplayReceipt schema Artifact 3 §6 + Artifact 1 §17.4 From Artifact 5 (DOC25): SourceArtifact schema Artifact 5 §2.2 ArtifactSegment schema Artifact 5 §3 ECFHeaderParserOutput Artifact 5 §4.2 MaterializationState (V4-O-7) Artifact 5 §5 (consumed for share-link delivery resolution) RecipientMaterializationResolution Artifact 5 §5.3 (R0.2 NEW) From Artifact 2 (forecast — Step 7): FilingUnit / FilingUnitVersion / Artifact 2 §O (forecast; FilingUnitTextVersion cross-artifact) StructuredExtractionStrategy Artifact 2 §J (forecast) TopicVisibilityPolicy Artifact 2 §J (forecast) CorpusProfile Artifact 2 §J (forecast) ``` Group M / Group I / Group B2 invariants whose canonical home is **this** artifact (Artifact 4): ```text INV-M-ACCESS-RANK-1 Artifact 4 §15 INV-M-NEGATIVE-1 Artifact 4 §15 INV-M-COVERAGE-INDEX-1 Artifact 4 §15 INV-M-COVERAGE-VISIBILITY-1 Artifact 4 §13 (V4-M-2) INV-M-EXPANSION-ACCESS-1 Artifact 4 §14 (V4-M-3) INV-M-VERSION-AWARE-1 Artifact 4 §15 (V4-M-7) INV-M-INTENT-1 Artifact 4 §15 INV-M-RETENTION-1 Artifact 4 §20 INV-M-SESSION-1 Artifact 4 §15 (V4-M-INV-SESSION) INV-I-CAP-1 Artifact 4 §8 (V4-I-2 refined) INV-I-SHARE-VIEW-1 Artifact 4 §4 INV-I-SHARE-VIEW-2 Artifact 4 §4 (V4-I-1 deny-wins) INV-I-NATIVE-SESSION-1 Artifact 4 §6 INV-I-UPLOAD-1 Artifact 4 §7 INV-DOC1-GOV-1 Artifact 4 §7 (V4-§4.5-DOC1) INV-MVC-1, INV-MVC-2 Artifact 4 §19 (read-time mirror; canonical Artifact 1 §15.X) INV-B2-OVERLAY-RESOLUTION-1 Artifact 4 §16 (read-time mirror; canonical Artifact 3 §12.3) ``` ### §1.4 Runtime entry points ```text DOC24 Search Router entry points: router.plan_search(query: string, session_profile_ref: string, query_intent_hint?: QueryIntent) → UnifiedSearchPlan Resolves query intent → constructs UnifiedSearchPlan with executor_assignments + RetrievalPosture + SearchScope. router.execute_search(plan: UnifiedSearchPlan) → SearchExecutionResult Dispatches to executor_assignments[]; applies result_fusion_strategy; emits SearchExecutionManifest + SearchCoverageReceipt. router.access_filtered_query_expansion(query: string, session_profile_ref: string) → QueryExpansionRecord[] Per INV-M-EXPANSION-ACCESS-1: returns only access-permitted expansions. DOC24 Capability Registry entry points: capability_registry.register_capability( capability_id: string, namespace: string, metadata: CapabilityMetadata) → RegistrationReceipt Adds capability to registry; namespace must exist or be co-registered. capability_registry.lookup_capability(capability_id: string) → CapabilityEntry | undefined Retrieves registered capability. capability_registry.list_namespace(namespace: string) → CapabilityEntry[] Lists all capabilities in a namespace. capability_registry.check_pattern_match( pattern: CapabilityPattern, capability_id: string) → boolean Tests if a capability matches a pattern (per INV-I-CAP-1 rules). EC Session entry points: session.create(profile: SessionProfile) → SessionRef Persists profile (durable per INV-V16-RETENTION-DURABLE-1); returns ref. session.read(ref: SessionRef) → SessionProfile session.transition_state( ref: SessionRef, new_state: SessionProfileState, reason_code: string) → StateTransitionReceipt State machine transition (per §2.X). session.revoke(ref: SessionRef, reason_code: string) → SessionRef Profile_state → revoked. Active recipient sessions terminate per active_session_disposition. session.bind_native( ec_session_ref: SessionRef, openclaw_session_id: string, binding_kind: NativeSessionScopeBinding["binding_kind"]) → NativeSessionScopeBinding Binds EC session to OpenClaw native session per §6. EC Capability execution gating: ec.gate_capability_execution( capability_id: string, session_profile_ref: string) → CapabilityExecutionGate Checks (a) capability registered (consults DOC24 registry); (b) session profile permits per capability_policy; (c) EC capacity available; returns gate decision. ``` --- ## §2. Group I — SessionProfile schema + state machine ### §2.0 Supporting type declarations (R0.2 NEW per AUDIT_DOC73_Artifact4_R0.1.md CRIT-A4-1) The following types are declared inline in Artifact 4 for SessionProfile schema use. UIComplexityTier was a phantom type in R0.1; this section provides the canonical inline declaration. Per V4 §3.7 Group L (cross-doc design note): UI complexity discipline lives at the cross-doc level; UIComplexityTier as enum is a runtime convenience consumed by SessionProfile + Q Dashboard rendering layer. ```typescript type UIComplexityTier = // R0.2 NEW per CRIT-A4-1 // per Group L cross-doc // design note | "tier_1_minimal" // beginner UI; minimal // controls visible | "tier_2_standard" // V1.6 default | "tier_3_advanced" // power-user controls visible | "tier_4_expert"; // expert_mode all controls // visible // Per V4 §3.7.1 V3-L-1 UIControlTierDeclaration: per-control tier // declarations live at the cross-doc level; UIComplexityTier (this // enum) is the SESSION-level effective tier. Step 9 cross-artifact // audit reconciles with Artifact 2 §J (forecast — Group J UI // complexity tier rendering rules). // R0.2 NEW per CRIT-A4-2 — DocumentRef alias declaration: type DocumentRef = SourceArtifactRef; // R0.2 NEW per CRIT-A4-2 // V1.6 model: document = // SourceArtifact-derived // entity (per Artifact 5 // §2.2 SourceArtifact; // alias for clarity in // user-facing surfaces // that say "document" but // reference SourceArtifact) // Policy refs forward-referenced in SessionProfile (R0.2 PATCH per // MED-A4-5): the following policy types are carry-forward from V1.5.1 // §11.X (referenced by name; not redefined per INV-V16-NO-LOCAL-SCHEMA-1): // OutputPolicy — V1.5.1 §11.X.OutputPolicy // DocumentDeliveryPolicy — V1.5.1 §11.X.DocumentDeliveryPolicy // TranscriptRetentionPolicy — V1.5.1 §11.X.TranscriptRetentionPolicy // LearningCapturePolicy — V1.5.1 §11.X.LearningCapturePolicy // V1.6 ships the same schemas; consumed via session_profile.{output, // document_delivery, transcript_retention, learning_capture}_policy_ref. // Step 9 cross-artifact audit verifies V1.5.1 carry-forward correctness. ``` ### §2.1 SessionProfile canonical schema Per V4 §3.4.7 Stage 4 [INSERT] (V2 base + V3 patches + V4 patches consolidated). The schema is owned by Artifact 4 §2 (this section). DOC24 + EC jointly persist; DOC24 specifies the read-side; EC enforces the persistence + state machine. ```typescript type SessionProfile = { // V1.6 contract // Identity session_profile_hash: string; // canonical hash policy_generation_id: string; // per V4-§0.4-1 race-safety profile_version: number; // monotonic per profile created_by_actor_ref: string; // origin actor origin_user_ref?: string; // host user (when share-link) share_token_id?: string; // when this profile is for // share-link session originating_share_ref?: string; // which ShareTokenPolicy // provisioned // State profile_state: SessionProfileState; // per §2.2 enum identity_mode: SessionIdentityMode; // per §3.1 enum session_kind: SessionKind; // per §3.0 enum // Capability policy (per V3-I-7 named) capability_policy_ref: string; // CapabilityPolicy ref; // schema per §8 // Access policy document_access_policy_ref?: string; source_visibility_floor?: VisibilityClass; // session may not exceed // below this floor why_blocked_surface: boolean; // host-tier only // Session denial messages session_denial_message_policy_ref: string; // per V4-I-DENIAL-1; §7 // Share-link specifics (V3-I-2 + V4-I-1/2/4) shared_corpus_view_refs?: string[]; // SharedCorpusView refs; // schema §4 derived_memory_share_policy?: SharedCorpusView["derived_memory_share_policy"]; host_annotation_policy?: SharedCorpusView["host_annotation_policy"]; // Output / delivery output_policy_ref?: string; document_delivery_policy_ref?: string; transcript_retention_policy_ref?: string; // Learning / utility learning_capture_policy_ref?: string; utility_signal_policy_ref?: string; // per V4-I-6; §7 // Rate limits max_queries_per_hour?: number; max_document_views_per_hour?: number; max_uploads_per_day?: number; max_result_count?: number; max_context_tokens?: number; max_document_bytes?: number; // UI max_ui_complexity_tier?: UIComplexityTier; effective_ui_complexity_tier?: UIComplexityTier; expert_mode?: boolean; // Sub-agent (V3-I-4 + V4-I-3) native_session_scope_binding_ref?: string; // NativeSessionScopeBinding; // schema §6 // External upload (V3-I-6 + V4-I-3.4.6) external_upload_file_safety_controls_ref?: string; // per §7 // [R0.4 PATCH per CSA extraction 2026-05-04: csa_injection_tier_policy_ref? // field removed from SessionProfile. CSAInjectionTierPolicy was deleted // wholesale from §18; consumer-side session-orientation orchestration // deferred to DOC72.] // Policy snapshots source_policy_snapshot_ref?: string; audit_scope: "host_only" | "session_local" | "both"; // Lifecycle created_at: ISO8601; activated_at?: ISO8601; expires_at?: ISO8601; revoked_at?: ISO8601; revoked_reason_code?: string; // V3-I-1 STRIPPED in V4: user_identity_required + per_user_partitioning // (DOC75 design space; deferred V1.7+; see DOC75 parking lot per // OBL-D75-PARKING-LOT-01). schema_version: 1; }; ``` ### §2.2 SessionProfileState state machine ```typescript type SessionProfileState = | "draft" // profile being constructed; not yet active | "active" // profile in use; queries route through it | "expired" // expires_at passed; queries blocked | "revoked" // explicitly revoked; queries blocked | "suspended"; // temporary block; can return to active ``` Allowed transitions: ```text draft → active (activation; capability_policy + access_policy finalized) active → expired (expires_at passed; auto-transition by EC scheduler) active → revoked (explicit user/system revocation) active → suspended (temporary block; admin or rate-limit-driven) suspended → active (resume; admin action) suspended → revoked (escalation) expired → (terminal; cannot revive; create new session profile) revoked → (terminal; cannot revive; create new session profile) Disallowed transitions: draft → expired (must activate first) draft → revoked (cannot revoke unactivated profile; just discard draft) active → draft (cannot regress to draft; create new) expired → active / suspended (terminal state) revoked → active / suspended (terminal state) ``` State transition pseudocode: ```typescript function validate_state_transition( from: SessionProfileState, to: SessionProfileState ): boolean { const allowed: Record = { draft: ["active"], active: ["expired", "revoked", "suspended"], expired: [], revoked: [], suspended: ["active", "revoked"], }; return allowed[from].includes(to); } function transition_session_state( ref: SessionRef, new_state: SessionProfileState, reason_code: string ): StateTransitionReceipt { const current = session.read(ref); if (!validate_state_transition(current.profile_state, new_state)) { throw new Error(`session_state_transition_invalid: ${current.profile_state} → ${new_state}`); } // Per INV-M-SESSION-1 (§15): if transitioning to revoked / expired / // suspended, in-flight searches against this profile must complete // current operation OR halt; ongoing operations are NOT silently // re-routed. const updated = { ...current, profile_state: new_state, ...(new_state === "revoked" ? { revoked_at: NOW(), revoked_reason_code: reason_code } : {}), }; return persist_state_transition(ref, updated, reason_code); } ``` ### §2.3 Identity_mode and origin actor Per V3-I-3 + V4-I-1: ```typescript type SessionIdentityMode = | "anonymous_share_token" // share-link with no recipient identity | "email_bound" // share-link bound to recipient email | "passcode_required" // share-link gated by passcode | "host_approved_named_external" // host approved external party | "host_user" // host user themselves | "system_agent"; // system-spawned session ``` Per V3-I-1 strip (V4 confirmed): `user_identity_required` and `per_user_partitioning` REMOVED. DOC75 design space; tracked V1.7+ per OBL-D75-PARKING-LOT-01. ### §2.4 SessionKind enum ```typescript type SessionKind = | "host_session" // host user's main session | "share_link_session" // share-link recipient session | "subagent_session" // sub-agent spawned within session | "system_agent_session"; // system-initiated agent ``` This enum is duplicated on NativeSessionScopeBinding.binding_kind (§6) by design — SessionKind reflects the SessionProfile's intent; binding_kind reflects the OpenClaw native runtime relationship. They MUST agree per INV-I-NATIVE-SESSION-1 (§6). ### §2.5 Profile activation gate Per §2.2 draft → active transition: activation requires: ```text G-ACT-1: capability_policy_ref non-null and resolvable. G-ACT-2: source_policy_snapshot_ref non-null when session_kind ∈ {host_session, share_link_session}. [G-ACT-3 DELETED per R0.4 CSA extraction 2026-05-04: previously required csa_injection_tier_policy_ref non-null when session_kind == host_session; CSAInjectionTierPolicy removed from V1.6; consumer-side session-orientation orchestration deferred to DOC72.] G-ACT-4: For share_link_session: shared_corpus_view_refs non-empty AND share_token_id non-null AND originating_share_ref non-null. G-ACT-5: For subagent_session: native_session_scope_binding_ref non-null AND parent host_session referenced via binding. G-ACT-6: All referenced schema rows resolvable; missing refs cause activation rejection with reason_code = session.activation_blocked_unresolved_ref. Activation pseudocode: function activate_profile(ref: SessionRef): ActivationResult { const profile = session.read(ref); if (profile.profile_state !== "draft") { return reject("session_already_activated"); } const gates = run_activation_gates(profile); if (!gates.all_pass) { return reject("session_activation_failed", gates.failed); } return transition_session_state(ref, "active", "session.activation_succeeded"); } ``` ### §2.6 OP-A row coverage ```text Artifact 4 §2 SessionProfile entries: OBL-D24-SESSION-PROFILE-V16-01 (NEW per Artifact 4) — DOC24 owns SessionProfile schema; EC owns persistence + state machine. OBL-EC-SESSION-LIFECYCLE-V16-01 (NEW per Artifact 4) — EC enforces state transitions per §2.2. ``` [V1.6 DRAFTING NOTE: dedicated SessionProfile OP-A rows may need explicit registration in OPA V3.8.1; tracked Tier B Q-3-A4-SESSION-PROFILE-OP-A.] --- ## §3. Group I — SessionKind + identity_mode + capability_policy ### §3.1 capability_policy schema Per V3-I-7 + V4-I-2 + V4 §3.4.3 INV-I-CAP-1: ```typescript type CapabilityPolicy = { policy_id: string; mode: "deny_all_except" | "allow_all_except" | "inherit_default"; allowed_capabilities: CapabilityPattern[]; // V3 NAMED denied_capabilities: CapabilityPattern[]; // V3 NAMED schema_version: 1; }; type CapabilityPattern = | { kind: "exact"; capability: string } | { kind: "prefix_wildcard"; prefix: string } // "calendar.*" | { kind: "namespace_all"; namespace: string }; // "calendar" ``` ### §3.2 INV-I-CAP-1 (V3 + V4-I-2 refined) **[V4 PATCH:V4-I-2 per R-CG #16 — INV-I-CAP-1 namespace registry refinement]** Canonical home Artifact 4 §3.2: ```text INV-I-CAP-1 (V3 NEW + V4 REFINED): CapabilityPolicy resolution rules: 1. DENY WINS. If a capability matches any pattern in denied_capabilities, it is denied regardless of allowed_capabilities. 2. PATTERNS ARE REGISTRY-BOUND (V4 REFINED per V4-I-2 / R-CG #16): - "namespace_all" and "prefix_wildcard" patterns MUST reference a NAMESPACE registered in DOC24's capability namespace registry (per §8 below). Future capabilities WITHIN that namespace are deny-effective without explicit re-registration. - "exact_match" patterns MUST reference a registered capability at capability granularity. - Unregistered namespace or capability patterns are rejected at policy construction time with `unregistered_pattern` reason code. 3. WILDCARD PRECEDENCE: "calendar.*" denies all capabilities in the calendar namespace including not-yet-registered future ones — PROVIDED "calendar" is a registered namespace. 4. mode = "deny_all_except" treats allowed_capabilities as the allowlist; everything else denied. mode = "allow_all_except" treats denied_capabilities as the denylist; everything else allowed. 5. mode = "inherit_default" inherits from the session profile's parent policy; resolution is recursive but capped at three levels. V3 had a registry contradiction: rule 2 said "registry-bound" but rule 3 said wildcards cover not-yet-registered future capabilities. R3 reviewers correctly flagged this. V4 resolution: registry binding is at NAMESPACE granularity for wildcards (the namespace must exist; future capabilities within get covered); at CAPABILITY granularity for exact-match patterns. Runtime check pseudocode: function check_capability_permitted( capability_id: string, policy: CapabilityPolicy ): { permitted: boolean; reason: string } { const ns = extract_namespace(capability_id); // Step 1: deny-wins. for (const pattern of policy.denied_capabilities) { if (matches_pattern(pattern, capability_id, ns)) { return { permitted: false, reason: "denied_by_pattern" }; } } // Step 2: mode-specific handling. switch (policy.mode) { case "deny_all_except": for (const pattern of policy.allowed_capabilities) { if (matches_pattern(pattern, capability_id, ns)) { return { permitted: true, reason: "allowed_by_pattern" }; } } return { permitted: false, reason: "deny_all_default" }; case "allow_all_except": return { permitted: true, reason: "allow_all_default" }; case "inherit_default": const parent = lookup_parent_policy(policy); if (!parent || policy.inheritance_depth > 3) { return { permitted: false, reason: "inheritance_depth_exceeded" }; } return check_capability_permitted(capability_id, parent); } } function matches_pattern( pattern: CapabilityPattern, capability_id: string, namespace: string ): boolean { // Per V4-I-2: registry validation occurs at policy construction; // here we just do the match. switch (pattern.kind) { case "exact": return pattern.capability === capability_id; case "prefix_wildcard": return capability_id.startsWith(pattern.prefix); case "namespace_all": return namespace === pattern.namespace; } } ``` OP-A row: `OBL-D24-CAPABILITY-POLICY-V16-01` (consumes capability registry per §8). Acceptance test: V4-AT-30 (CapabilityPattern namespace registry compliance). ### §3.3 inherit_default depth cap The `inherit_default` mode chain is capped at 3 levels per V3-I-3 (V4 confirmed): `session profile → parent profile → grandparent profile`. Beyond depth 3: rejection with `inheritance_depth_exceeded` reason code; coding agents must restructure the policy hierarchy. --- ## §4. Group I — SharedCorpusView ### §4.1 SharedCorpusView canonical schema Per V3-I-2 + V4-I-2 + V4-I-4 + V4-I-1 (V4 §3.4.2): ```typescript type SharedCorpusView = { // V3 + V4 expansion shared_view_id: string; corpus_ref: CorpusRef; exposed_surfaces: Array< | "source_documents" // raw filed documents | "filing_metadata" // case_number, court, parties | "filing_relationships" // motion chains, court orders | "court_rulings" // V4 SPLIT (was rulings_and_outcomes) | "court_disposition_observations" | "host_outcome_analysis" // host's analytical synthesis | "rulings_and_outcomes" // V3 alias kept for back-compat | "neutral_topics" // shareable topic labels | "host_annotations" // host comments on documents | "host_strategy_notes" // host strategy analysis | "host_topics" // host-authored topic labels | "derived_memories" // CUs / VersionedClaims | "derived_outcomes_synthesis" // host's outcome analysis >; derived_memory_share_policy: | "exclude_all" // V1.6 default for share-link | "include_with_provenance" // CUs with source-span citations | "include_only_user_marked_shareable"; host_annotation_policy: | "exclude_all" // V1.6 default for share-link | "include_marked_shareable" | "include_all"; // V4 NEW per V4-I-4 (R-G55S §1) — view temporal mode: view_temporal_mode: | "snapshot_at_share" // recipient sees corpus as of share | "snapshot_at_share_with_drift_disclosure" | "live_view" // recipient sees current state | "live_view_with_change_log"; snapshot_at_timestamp?: ISO8601; snapshot_index_state?: SearchIndexSnapshotRef; // V4 NEW per V4-I-2 (R-G55 #19) — document scope: // [R0.2 PATCH per AUDIT_DOC73_Artifact4_R0.1.md CRIT-A4-2 — phantom type fix:] // - DocumentRef aliased to SourceArtifactRef (Artifact 5 §2.2); // V1.6 model: document = SourceArtifact-derived entity. // - StructuralSelectorList canonical home: Artifact 2 §K // (forecast schema per V4 §3.6.1 V3-K-1; cross-artifact drift // verification at Step 9). document_scope?: | { kind: "all_documents" } | { kind: "explicit_document_list"; document_refs: DocumentRef[] } // = SourceArtifactRef[] | { kind: "filing_unit_version_list"; version_refs: FilingUnitVersionRef[] } | { kind: "structural_selector"; selector: StructuralSelectorList }; // [forecast Artifact 2 §K] // V4 NEW per V4-I-1 (R-CG #15) — visibility ceiling: visibility_class_ceiling?: VisibilityClass; // recipient cannot see // above this schema_version: 1; }; ``` V1.6 share-link default `SharedCorpusView`: ```typescript { exposed_surfaces: [ "source_documents", "filing_metadata", "filing_relationships", "court_rulings", // V4 NEW (split) "court_disposition_observations" // V4 NEW // host_outcome_analysis NOT in default; host opts in. ], derived_memory_share_policy: "exclude_all", host_annotation_policy: "exclude_all", view_temporal_mode: "snapshot_at_share", // V4 default for legal share-link document_scope: { kind: "all_documents" }, visibility_class_ceiling: "public_open" } ``` Default `view_temporal_mode` for legal share-link is `snapshot_at_share` (work-product stability). Default for collaborative share is `live_view`. Choice is per-shared-view. ### §4.2 INV-I-SHARE-VIEW-1 — share-link defaults to source-only Per V3-I-2: ```text INV-I-SHARE-VIEW-1 (V3 NEW; canonical home Artifact 4 §4.2): Share-link sessions expose ONLY surfaces declared in the session's SharedCorpusView. Host work product (annotations, strategy notes, derived memories without explicit shareable marking, host-authored topics, derived outcomes synthesis) defaults to excluded. Co-counsel reviewing a brief bank sees source documents + neutral metadata; they do NOT see the host's internal analysis unless the host has explicitly added it to the SharedCorpusView. Default rendering for a share-link with default SharedCorpusView shows: - Source documents + filing metadata + relationships + court_rulings - "Host annotations and analysis are not included in this share" framing visible to recipient - No silent exclusion (recipient knows the share is curated) Runtime check (search router): function filter_results_per_shared_corpus_view( results: SearchResult[], session_profile: SessionProfile ): SearchResult[] { if (session_profile.session_kind !== "share_link_session") { return results; // host session sees everything } const shared_views = lookup_shared_corpus_views( session_profile.shared_corpus_view_refs ?? [] ); return results.filter(result => { // Check exposed_surfaces const result_surface = classify_result_surface(result); const view_for_corpus = shared_views.find(v => v.corpus_ref === result.corpus_ref); if (!view_for_corpus) return false; // corpus not in any shared view if (!view_for_corpus.exposed_surfaces.includes(result_surface)) { return false; } // ... derived_memory_share_policy + host_annotation_policy checks return true; }); } ``` OP-A row: `OBL-D24-SHARED-CORPUS-VIEW-V16-01`. ### §4.3 INV-I-SHARE-VIEW-2 — deny-wins precedence **[V4 PATCH:V4-I-1 per R-CG #15 + R-G55X §23 — INV-I-SHARE-VIEW-2 deny-wins]** ```text INV-I-SHARE-VIEW-2 (V4 NEW; canonical home Artifact 4 §4.3): SharedCorpusView conflict resolution: when a session has multiple SharedCorpusView refs (host has multiple corpora shared via different views), conflicting policy settings resolve via deny-wins (most restrictive policy wins per corpus per surface). Multiple views referencing same corpus: - exposed_surfaces: INTERSECTION (only surfaces present in ALL views) - derived_memory_share_policy: most-restrictive per enum precedence (exclude_all > include_only_user_marked_shareable > include_with_provenance) - host_annotation_policy: most-restrictive (exclude_all > include_marked_shareable > include_all) - visibility_class_ceiling: most-restrictive (lowest in lattice) - view_temporal_mode: most-restrictive (snapshot_at_share > snapshot_at_share_with_drift_disclosure > live_view > live_view_with_change_log) Implementation: when share-link session profile resolves SharedCorpusView list, compute the intersection/most-restrictive across all referenced views per corpus. Conflicts surface as `effective_view` in session manifest; not stored as new view (avoids unbounded view proliferation). Same deny-wins rule as INV-I-CAP-1 but applied to share views. Runtime resolution pseudocode: function resolve_effective_shared_corpus_view( views: SharedCorpusView[], target_corpus: CorpusRef ): EffectiveSharedCorpusView { const relevant = views.filter(v => v.corpus_ref === target_corpus); if (relevant.length === 0) return null; if (relevant.length === 1) return relevant[0]; // Intersection of exposed_surfaces. const all_surfaces = new Set(SHARED_CORPUS_VIEW_SURFACES); let intersected = all_surfaces; for (const v of relevant) { intersected = intersect(intersected, new Set(v.exposed_surfaces)); } // Most-restrictive per other fields. const derived_memory_policy = most_restrictive_derived_memory( relevant.map(v => v.derived_memory_share_policy)); const host_annotation_policy = most_restrictive_host_annotation( relevant.map(v => v.host_annotation_policy)); const visibility_ceiling = lowest_in_lattice( relevant.map(v => v.visibility_class_ceiling).filter(Boolean)); const temporal_mode = most_restrictive_temporal( relevant.map(v => v.view_temporal_mode)); return { effective: true, corpus_ref: target_corpus, exposed_surfaces: Array.from(intersected), derived_memory_share_policy: derived_memory_policy, host_annotation_policy: host_annotation_policy, visibility_class_ceiling: visibility_ceiling, view_temporal_mode: temporal_mode, // Document scope: intersection (only documents in ALL views' scopes) document_scope: intersect_document_scopes( relevant.map(v => v.document_scope)), }; } ``` OP-A row: `OBL-D24-SHARE-VIEW-DENY-WINS-V16-01` (V4 NEW per V4-I-1). Acceptance test: V3-AT-13 + V4-AT-29 (deny-wins precedence). --- ## §5. Group I — ShareTokenPolicy + ShareTokenRevocation ### §5.0 Share-link grant envelope construction (R0.2 NEW per AUDIT_DOC73_Artifact4_R0.1.md CRIT-A4-3) Per Artifact 3 §4.3.9 share_link_grant effect_kind: when ShareTokenPolicy is created, an envelope MUST fire with effect_kind = "share_link_grant" + reversibility = "irreversible_external_effect". R0.1 specified the revocation flow (§5.2) but omitted the initial grant flow. R0.2 adds: ```typescript function grant_share_link( host_session_ref: string, share_view_ids: string[], // SharedCorpusView refs // per §4 recipient_identity_mode: SessionIdentityMode, // per §3.0 expires_at?: ISO8601, rate_limits?: ShareTokenRateLimits, // per §5.1 watermark_downloads: boolean = true, audit_visibility: ShareTokenPolicy["audit_visibility"] = "both", allowed_actions: CapabilityPattern[] = [ { kind: "namespace_all", namespace: "search" }, { kind: "namespace_all", namespace: "document_view" }, { kind: "namespace_all", namespace: "document_download" } ] // V1.6 default // share-link actions ): { token: ShareTokenPolicy; envelope: PBEOperationEnvelope } { // Step 1: validate host session is active per §15.6 INV-M-SESSION-1. const host = session.read(host_session_ref); if (host.profile_state !== "active") { throw new Error("share_link_grant_blocked_host_session_not_active"); } // Step 2: validate share_view_ids reference existing SharedCorpusViews // owned by host. for (const view_id of share_view_ids) { const view = lookup_shared_corpus_view(view_id); if (!view || view.owner_session_ref !== host_session_ref) { throw new Error("share_link_grant_blocked_invalid_view_ref"); } } // Step 3: construct ShareTokenPolicy schema row. const token: ShareTokenPolicy = { share_token_id: new_id(), token_hash: hash_random_token(), // never store raw shared_view_ids: share_view_ids, document_access_policy_ref: derive_document_access_policy( host_session_ref, share_view_ids ), allowed_actions, recipient_identity_mode, expires_at, rate_limits, watermark_downloads, audit_visibility, schema_version: 1, }; // Step 4: construct kernel envelope (per Artifact 3 §4.3.9). const envelope: PBEOperationEnvelope = { operation_id: new_operation_id(), envelope_version: "1.6", operation_kind: "create", // share-link // issuance is a // create operation semantic_intent: "create", primitive_effects: [ { effect_id: new_effect_id(), effect_kind: "share_link_grant", // V4-A-1 effect_kind reversibility: "irreversible_external_effect", // per Artifact 3 §4.3.9 external_effect_descriptor: `share-link token issued at ${NOW()}; ` + `recipient_identity_mode=${recipient_identity_mode}; ` + `expires_at=${expires_at ?? "never"}`, // No inverse_operation_kind: revocation is a NEW operation per // Artifact 3 §4.3.10; not a Tier 1 inverse. schema_version: 1, } ], causal_parent_operation_ids: [host.session_creation_op_id], // links audit chain // to host session // creation idempotency_key: hash(host_session_ref, share_view_ids, recipient_identity_mode, NOW()), actor: "user", source_refs: share_view_ids, // share views consumed target_refs: [token.share_token_id], policy_generation_id: host.policy_generation_id, affected_subgraph_descriptor: { scope_kind: "single_node", affected_node_refs: [token.share_token_id], affected_edge_refs: [], visibility_class_envelope: ["work_product_internal"], // share-link is // work-product-level estimated_cascade_depth: 0, schema_version: 1, }, read_set_refs: share_view_ids, write_set_refs: [token.share_token_id], effect_set_refs: [/* primitive_effects copied */], recorded_at: NOW(), duration_ms: 0, schema_version: 1, }; // Step 5: submit to kernel (per Artifact 3 §1.4 kernel.submit_operation). const submission = kernel.submit_operation(envelope); // Step 6: persist ShareTokenPolicy. persist_share_token_policy(token); // Step 7: emit user-visible token (the raw token; never persist). return { token, envelope }; } ``` **Behavior contract:** - **Reversibility:** `share_link_grant` effect is `irreversible_external_effect` per Artifact 3 §4.3.9. Token cannot be unissued; recipient may have downloaded artifacts. Revocation is a NEW operation per §5.2. - **Idempotency:** idempotency_key includes timestamp; concurrent grant attempts with same parameters get distinct token_ids. - **Audit:** kernel envelope is durable per INV-V16-RETENTION-DURABLE-1. ShareTokenPolicy entity is durable. - **Side effects:** none beyond kernel write + policy persistence; the actual token delivery to recipient is via separate notification path (DOC10 / Artifact 4 UI layer). OP-A row: `OBL-D24-SHARE-LINK-GRANT-V16-01` (R0.2 NEW per CRIT-A4-3; pairs with OBL-I-EXTERNAL-UPLOAD-QUARANTINE-01 + OBL-D24-SHARED-CORPUS-VIEW-V16-01). [V1.6 DRAFTING NOTE: `lookup_shared_corpus_view` and `derive_document_access_policy` and `hash_random_token` are phantom helpers per HIGH-A4-1; resolution at Step 9 helper-home consolidation.] ### §5.1 ShareTokenPolicy schema Per V3-I-2 + V4 §3.4.7 Stage 4 [INSERT]: ```typescript type ShareTokenPolicy = { share_token_id: string; token_hash: string; // hashed token // (never store raw) shared_view_ids: string[]; // V3 NEW per V3-I-2 document_access_policy_ref: string; allowed_actions: CapabilityPattern[]; // V3 NAMED per V3-I-7 recipient_identity_mode: SessionIdentityMode; // anonymous / email_bound // / passcode_required expires_at?: ISO8601; rate_limits?: ShareTokenRateLimits; watermark_downloads: boolean; // applies watermark to // downloaded artifacts audit_visibility: "host_only" | "session_local" | "both"; // Revocation revoked_at?: ISO8601; revoke_reason?: string; // Default for legal/work-product: email_bound or passcode_required schema_version: 1; }; type ShareTokenRateLimits = { // R0.2 PATCH per // MED-A4-2: defaults // inlined per Q-3-A4-8 max_queries_per_hour?: number; // V1.6 default: 50 max_document_views_per_hour?: number; // V1.6 default: 200 max_uploads_per_day?: number; // V1.6 default: 10 max_recipient_sessions_concurrent?: number; // V1.6 default: 5 // (R0.3 PATCH per // architect triage // 2026-05-03 Q-3-A4-8: // raised from 1 to 5 // to support small-to- // mid legal team // share-link use cases // — brief-bank co- // counsel scenarios // typically lead + // associate + paralegal // + 2; configurable // per share-link) }; ``` ### §5.2 ShareTokenRevocation per V4-I-5 **[V4 PATCH:V4-I-5 per R-G55 #24 + R-G55X §26 + R-G55S §23 — Share-token revocation semantics]** Per V4 §3.4.2 (lines 5060-5083). Canonical home Artifact 4 §5.2. **[R0.2 RECONCILIATION NOTE per AUDIT_DOC73_Artifact4_R0.1.md HIGH-A4-3]** — ShareTokenRevocation runtime split between Artifact 4 §5.2 and Artifact 3 §4.3.10: ```text ShareTokenRevocation runtime split: Artifact 4 §5.2 (this section): ShareTokenRevocation entity schema — carries 3 disposition fields (active_session_disposition, downloaded_copies_disposition, cached_response_disposition) that drive post-emission orchestration (handle active sessions, recall request, cache invalidation). Artifact 3 §4.3.10: share_link_revoke effect_kind on KernelEffect — reversibility = "compensating_operation_only". Single effect_kind; granular dispositions are not represented at the kernel-effect level. Reconciliation: - revoke_share_token() per §5.2 below performs: (a) Persist ShareTokenRevocation entity (Artifact 4-canonical schema). (b) Construct kernel envelope with primitive_effects = [{effect_kind: "share_link_revoke", reversibility: "compensating_operation_only", ...}] (Artifact 3-canonical effect classification). (c) Submit envelope to kernel via Artifact 3 §1.4 kernel.submit_operation. (d) On submission success, drive post-emission orchestration per disposition fields (§5.3 active session handling, recall request emission, cache invalidation). - The kernel envelope records the revocation event (audit trail); ShareTokenRevocation entity carries the orchestration metadata (which dispositions applied). - Per Artifact 3 §4.3.10: revocation reversibility = compensating_operation_only. No Tier 1 inverse (un-revoking is a NEW share_link_grant, not a rollback). ShareTokenRevocation entity is durable per INV-V16-RETENTION-DURABLE-1. Both artifacts converge: Artifact 4 owns the "what dispositions apply" schema; Artifact 3 owns the "what kernel effect classifies the change" schema. They compose via revoke_share_token() flow below. ``` V3 had revocation as a flag (`revoked_at`). R3 reviewers correctly noted: revoking a share-token doesn't address (a) what about already-downloaded documents, (b) what about active recipient sessions, (c) what about cached responses. ```typescript type ShareTokenRevocation = { // V4 NEW per V4-I-5 revocation_id: string; share_token_id: string; revoked_at: ISO8601; revoke_reason: string; active_session_disposition: | "terminate_immediately" | "allow_session_complete" // grace period | "terminate_after_grace"; active_session_grace_period_seconds?: number; downloaded_copies_disposition: | "no_recall_attempt" // accept that recipient has copies | "best_effort_recall_request"; // notify recipient + revoke watermark validity cached_response_disposition: | "session_local_invalidate" | "no_action"; // can't reach external caches anyway schema_version: 1; }; ``` User-facing language for revocation flow: "Revoking share-link prevents new access. Documents already downloaded by recipient cannot be recalled. Active recipient sessions terminate per grace policy." Runtime pseudocode (revoke entry point): ```typescript function revoke_share_token( share_token_id: string, revocation_params: ShareTokenRevocation ): ShareTokenRevocationResult { const token = lookup_share_token_policy(share_token_id); if (token.revoked_at) { return reject("share_token_already_revoked"); } // Step 1: mark token as revoked. persist_share_token_revocation(share_token_id, revocation_params); // Step 2: handle active recipient sessions per active_session_disposition. const active_sessions = lookup_active_sessions_by_share_token( share_token_id); for (const session of active_sessions) { handle_active_session_disposition( session, revocation_params.active_session_disposition, revocation_params.active_session_grace_period_seconds ); } // Step 3: handle cached responses per cached_response_disposition. if (revocation_params.cached_response_disposition === "session_local_invalidate") { invalidate_session_local_cache_for_share_token(share_token_id); } // Step 4: handle downloaded copies per downloaded_copies_disposition. if (revocation_params.downloaded_copies_disposition === "best_effort_recall_request") { emit_recall_request_to_recipient(share_token_id); invalidate_watermark_validity(share_token_id); } // No action for "no_recall_attempt". // Step 5: emit kernel envelope per Artifact 3 §4.3.10 share_link_revoke. // (Cross-artifact: kernel records the revocation as an operation.) return emit_share_link_revoke_envelope(share_token_id, revocation_params); } ``` Per Artifact 3 §4.3.10: `share_link_revoke` effect_kind reversibility = `compensating_operation_only`. The revocation is itself a NEW operation; not a Tier 1 inverse of `share_link_grant`. OP-A row: covered via OBL-I-EXTERNAL-UPLOAD-QUARANTINE-01 + new `OBL-I-SHARE-TOKEN-REVOCATION-V16-01` (per V4-I-5; V3.8.1 candidate). Acceptance test: V4-AT-34. ### §5.3 Active session disposition handling ```typescript function handle_active_session_disposition( session: SessionProfile, disposition: ShareTokenRevocation["active_session_disposition"], grace_period_seconds?: number ): void { switch (disposition) { case "terminate_immediately": session.transition_state(session.ref, "revoked", "share_token_revoked"); break; case "allow_session_complete": // Mark as "expiring"; let session run to natural completion. mark_session_expiring(session.ref, "share_token_revoked_grace"); break; case "terminate_after_grace": schedule_session_termination( session.ref, NOW() + (grace_period_seconds ?? 300) * 1000, "share_token_revoked_grace_expired" ); break; } } ``` --- ## §6. Group I — NativeSessionScopeBinding ### §6.1 NativeSessionScopeBinding canonical schema (V4-I-3 expanded) **[V4 PATCH:V4-I-3 per R-CG #17 + R-G55 #23 + R-G55X §25 — NativeSessionScopeBinding expanded]** Per V4 §3.4.4 (lines 5158-5217): ```typescript type NativeSessionScopeBinding = { // V3 base + V4 expansion binding_id: string; ec_session_id: string; // EC session profile ID openclaw_native_session_id: string; // OpenClaw runtime ID binding_kind: | "host_session" // host user's main session | "share_link_session" // share-link recipient | "subagent_session" // sub-agent spawned | "system_agent_session"; // system-initiated agent // Constraints inherited from EC session profile inherited_capability_policy_ref: string; inherited_share_token_policy_ref?: string; inherited_visibility_constraints: VisibilityClass[]; // Constraints specific to OpenClaw runtime (V3 base) fork_forbidden: boolean; // share_link: true; // host: false max_spawn_depth: number; max_children_per_agent: number; // V4 NEW per V4-I-3: context_inheritance_policy: | "full_inherit" // sub-agent inherits all // host context | "scoped_inherit" // sub-agent inherits only // scoped context | "no_inherit"; // sub-agent has fresh context auth_inheritance_policy: | "inherit_with_session_token" // sub-agent uses session token | "session_only" // sub-agent uses isolated auth | "no_auth"; // sub-agent has no external // auth transcript_visibility_policy: | "shared" // host sees sub-agent // transcript | "isolated" // sub-agent transcript private | "host_only"; // sub-agent cannot see host // transcript watermark_policy?: WatermarkPolicy; // for sub-agent outputs // visible to share-link child_spawn_constraint: | "deny_all" // sub-agent cannot spawn | "deny_external" // sub-agent can only spawn // internal agents | "inherit_parent_constraint" // recursive | "explicit_allow_list"; // pre-declared list child_spawn_allow_list?: string[]; // when constraint = // "explicit_allow_list" schema_version: 1; }; type WatermarkPolicy = { // R0.2 PATCH per // MED-A4-1: "custom" // removed (V1.7+ // candidate; needs // custom_watermark_template // field spec) applies_to: "downloaded_artifacts" | "displayed_content" | "both"; watermark_kind: "user_email" | "session_id" | "timestamp"; // V1.7+: add "custom" // with custom_watermark_template // field per Tier B // Q-3-A4-WATERMARK-CUSTOM watermark_visibility: "visible" | "invisible_metadata" | "both"; schema_version: 1; }; ``` ### §6.2 INV-I-NATIVE-SESSION-1 Per V3-I-4 + V4 §3.4.4: ```text INV-I-NATIVE-SESSION-1 (V3 NEW + V4 EXPANDED; canonical home Artifact 4 §6.2): NativeSessionScopeBinding constrains OpenClaw runtime session behavior per EC session profile: - fork_forbidden: when true, OpenClaw cannot spawn child sub-agents from this session (e.g., share-link sessions cannot fork agents that operate on host's authority). - max_spawn_depth: limits transitive sub-agent depth (sub-agent of sub-agent of host = depth 2). - max_children_per_agent: limits fan-out per agent. - context_inheritance_policy: controls what context sub-agents see. "full_inherit" → sub-agent has full host context (including privileged material). "scoped_inherit" → sub-agent gets scoped subset (per SharedCorpusView equivalent for sub-agent boundaries). "no_inherit" → sub-agent starts fresh. - auth_inheritance_policy: controls sub-agent authentication. "inherit_with_session_token" → sub-agent uses session credentials (acts on host's behalf). "session_only" → isolated auth scope; sub-agent cannot use host credentials externally. "no_auth" → sub-agent has no external authentication. - transcript_visibility_policy: controls audit trail visibility. "shared" → host sees sub-agent transcript. "isolated" → sub-agent transcript private (rare; usually for system-confidential operations). "host_only" → sub-agent does not see host's transcript. - child_spawn_constraint: controls recursive spawning. "deny_all" → no recursive spawn. "deny_external" → can spawn internal but not external agents. "inherit_parent_constraint" → child inherits parent's constraint. "explicit_allow_list" → pre-declared allow list. V1.6 defaults: host_session: fork_forbidden: false; max_spawn_depth: 3; max_children: 5; context_inheritance_policy: "full_inherit"; auth_inheritance_policy: "inherit_with_session_token"; transcript_visibility_policy: "shared"; child_spawn_constraint: "inherit_parent_constraint". share_link_session: fork_forbidden: TRUE; max_spawn_depth: 0; max_children: 0; context_inheritance_policy: "no_inherit"; auth_inheritance_policy: "session_only"; transcript_visibility_policy: "isolated"; child_spawn_constraint: "deny_all"; watermark_policy: enabled (per ShareTokenPolicy.watermark_downloads). subagent_session: fork_forbidden: per parent; max_spawn_depth: parent - 1; context_inheritance_policy: parent-inherited; auth_inheritance_policy: parent-inherited; transcript_visibility_policy: "shared"; child_spawn_constraint: parent-inherited. Runtime check pseudocode: function validate_subagent_spawn( parent_binding: NativeSessionScopeBinding, candidate_child_kind: SessionKind ): ValidationResult { if (parent_binding.fork_forbidden) { return reject("native_session_fork_forbidden"); } if (parent_binding.max_spawn_depth <= 0) { return reject("native_session_max_spawn_depth_exceeded"); } if (parent_binding.children_count >= parent_binding.max_children_per_agent) { return reject("native_session_max_children_per_agent_exceeded"); } switch (parent_binding.child_spawn_constraint) { case "deny_all": return reject("native_session_child_spawn_denied"); case "deny_external": if (is_external_agent(candidate_child_kind)) { return reject("native_session_child_spawn_external_denied"); } break; case "inherit_parent_constraint": // Recursive check. return validate_subagent_spawn(parent_of(parent_binding), candidate_child_kind); case "explicit_allow_list": if (!parent_binding.child_spawn_allow_list?.includes( candidate_child_kind)) { return reject("native_session_child_spawn_not_in_allow_list"); } break; } return accept(); } ``` OP-A row: `OBL-D24-SUBAGENT-SESSION-V16-01` (V4-I-3 native session expansion). Acceptance test: V4-AT-30 (sub-agent spawn constraints). ### §6.3 Session-kind binding agreement check Per §2.4: SessionKind on SessionProfile MUST agree with binding_kind on NativeSessionScopeBinding: ```typescript function validate_session_binding_agreement( session: SessionProfile, binding: NativeSessionScopeBinding ): ValidationResult { if (session.session_kind !== binding.binding_kind) { return reject("session_binding_kind_mismatch", `SessionProfile.session_kind = ${session.session_kind} ` + `but NativeSessionScopeBinding.binding_kind = ${binding.binding_kind}`); } return accept(); } ``` --- ## §7. Group I — UtilitySignalPolicy + DOC1GovernanceSplit + SessionDenialMessage + ExternalUploadFileSafetyControls ### §7.1 UtilitySignalPolicy share-link defaults (V4-I-6) **[V4 PATCH:V4-I-6 per R-G55S §22 — UtilitySignalPolicy share-link defaults]** Per V4 §3.4.6 (lines 5392-5402): ```typescript type UtilitySignalPolicy = { policy_id: string; utility_signal_capture: | "host_global" // signals update host's global models | "session_local_only" // signals stay within session | "corpus_aggregate_review_required"; // signals aggregate per corpus; // host reviews before global capture_kinds: Array< | "click_dwell" // user dwell time on results | "explicit_helpful" // user marked helpful | "explicit_not_helpful" // user marked not helpful | "query_refinement" // user refined query | "result_share" // user shared a result >; schema_version: 1; }; ``` V1.6 default UtilitySignalPolicy per session_kind: ```text V1.6 default UtilitySignalPolicy per session_kind: host_session: utility_signal_capture: "host_global" capture_kinds: all 5 share_link_session (anonymous): utility_signal_capture: "session_local_only" capture_kinds: ["click_dwell"] // minimal; do not feed host models share_link_session (named external): utility_signal_capture: "corpus_aggregate_review_required" capture_kinds: ["click_dwell", "explicit_helpful", "explicit_not_helpful"] (host reviews aggregated signals before they update models) subagent_session: utility_signal_capture: parent-inherited capture_kinds: parent-inherited system_agent_session: utility_signal_capture: "host_global" capture_kinds: all 5 Host opt-in required for external signals to feed global learning. Runtime check (after every interaction event): function should_capture_utility_signal( session: SessionProfile, signal_kind: UtilitySignalKind ): boolean { const policy = lookup_utility_signal_policy( session.utility_signal_policy_ref ); if (!policy.capture_kinds.includes(signal_kind)) { return false; } return true; } function dispatch_captured_signal( session: SessionProfile, signal: UtilitySignal ): SignalDispatch { const policy = lookup_utility_signal_policy( session.utility_signal_policy_ref ); switch (policy.utility_signal_capture) { case "host_global": return route_to_host_global_model(signal); case "session_local_only": return route_to_session_local(signal, session.ref); case "corpus_aggregate_review_required": return route_to_corpus_aggregate_pending_review(signal); } } ``` OP-A row: `OBL-D24-UTILITY-SIGNAL-V16-01` (V4-I-6). ### §7.2 DOC1GovernanceSplit + INV-DOC1-GOV-1 **[V4 PATCH:V4-§4.5-DOC1 per R-CG / R-G55X — DOC1GovernanceSplit]** Per V4 §4.5 (cross-cutting): ```typescript type DOC1GovernanceSplit = { // V4 NEW per V4-§4.5-DOC1 split_id: string; doc1_governance_kind: | "session_governance_only" // DOC1 governs only the // session-level rules | "corpus_governance_only" // DOC1 governs only the // corpus-level rules | "session_and_corpus"; // both doc1_share_link_governance_role: | "share_link_session_owns_governance" // share-link's session // has its own DOC1 rules | "host_session_governance_inherited" // share-link inherits host's | "share_link_governance_disabled"; // no DOC1 for share-link schema_version: 1; }; ``` ```text INV-DOC1-GOV-1 (V4 NEW per V4-§4.5-DOC1; canonical home Artifact 4 §7.2): DOC1 governance scope is explicitly declared per session via DOC1GovernanceSplit. Share-link sessions default to "share_link_governance_disabled" — DOC1 governance applies only at host session level. Host opt-in to "host_session_governance_inherited" enables DOC1 to govern share-link recipient interactions. Implementation: DOC1's governance rules consult SessionProfile.doc1_governance_split_ref before applying. Share-link sessions without explicit DOC1 inheritance route through generic governance only (rate limits, access overlay, capability policy); DOC1-specific rules (memory resilience policies, citation enforcement, authority validation hooks) do not apply. ``` OP-A row: `OBL-D1-GOV-SPLIT-V16-01` (V4 NEW; per Artifact 1 §13.5 cross-doc note). ### §7.3 SessionDenialMessage + V4-I-DENIAL-1 per-reason-code visibility **[V4 PATCH:V4-I-DENIAL-1 per R-CL4 #6 — per-reason-code exposure]** Per V4 §3.4.5 (lines 5276-5308): ```typescript type SessionDenialMessage = { // V4 SIMPLIFIED per V4-I-DENIAL-1 visible_text: string; reason_code: string; // resolves visibility from // registry // V3 expose_reason_code_to_recipient: bool REMOVED in V4 // (replaced by per-reason-code registry visibility field). schema_version: 1; }; // Reason code registry consumer per V4-I-DENIAL-1: // (registry canonical at §0.7.2; consumed here for denial message // visibility resolution.) type ReasonCodeRegistryEntry = { // V4 EXPANDED reason_code: string; // namespaced, e.g., // "session.capability_not_available" description: string; default_recipient_visibility: // V4 NEW per V4-I-DENIAL-1 | "expose" // safe to show recipient | "generic_only" // generic message only | "audit_log_only"; // host audit only owner_doc: string; schema_version: 1; }; ``` ```text V4-I-DENIAL-1 visibility examples: - rate_limit_exceeded: default_recipient_visibility: "expose" → "You've hit your rate limit. Please wait." - calendar.not_available_in_session: default_recipient_visibility: "generic_only" → "Not available in this session." - session.policy_internal_violation: default_recipient_visibility: "audit_log_only" → "Not available in this session." + host audit log records actual policy violation detail. Runtime resolution: function resolve_denial_message_text( reason_code: string, session: SessionProfile ): string { const entry = reason_code_registry.lookup(reason_code); if (!entry) { return "Not available."; // generic fallback } const visibility = entry.default_recipient_visibility; if (session.session_kind === "host_session") { return entry.description; // host sees full reason } switch (visibility) { case "expose": return entry.description; // safe to show case "generic_only": return "Not available in this session."; case "audit_log_only": emit_audit_log_entry(reason_code, session.ref); return "Not available in this session."; // generic; details // NOT shown to user } } ``` OP-A row: `OBL-D24-REASON-CODE-VISIBILITY-V16-01` (V4 NEW per V4-I-DENIAL-1). ### §7.4 ExternalUploadFileSafetyControls (V4-I-3.4.6 stripped phantom) Per V4 §3.4.6 (lines 5310-5390): ```typescript type ExternalUploadFileSafetyControls = { // V4 STRIPPED // hash_reputation_check // Pre-acceptance checks mime_type_sniffing: boolean; // verify declared mime max_file_size_bytes: number; // default: 100MB archive_decompression_bomb_guard: boolean; // detect zip bombs archive_max_decompression_ratio: number; // default: 100x archive_max_decompressed_size: number; // default: 1GB // Active content active_content_macro_warning: boolean; // warn on Office macros // PDF JavaScript active_content_block_or_warn: | "block" // refuse upload | "warn_user" // proceed with warning | "strip_active_content"; // attempt to remove macros // Local duplicate check (kept; uses local hash store, not external // reputation) local_duplicate_check: boolean; // check against existing // host artifacts // V4 STRIPPED: hash_reputation_check (was V3; phantom feature) // V1.7+ candidate per OBL-I-V17-HASH-REPUTATION-01 // On failure on_safety_failure: | "reject_with_reason" | "quarantine_and_alert_host" | "warn_recipient_proceed_anyway"; schema_version: 1; }; ``` V1.6 share-link default: ```typescript { mime_type_sniffing: true, max_file_size_bytes: 100_000_000, // 100MB archive_decompression_bomb_guard: true, archive_max_decompression_ratio: 100, archive_max_decompressed_size: 1_000_000_000, // 1GB active_content_macro_warning: true, active_content_block_or_warn: "warn_user", // V4: hash_reputation_check REMOVED (phantom feature) local_duplicate_check: true, on_safety_failure: "reject_with_reason" } ``` ### §7.5 INV-I-UPLOAD-1 ```text INV-I-UPLOAD-1 (V3 + V4; canonical home Artifact 4 §7.5): External uploads through share-link sessions MUST pass file-safety controls (mime sniffing, size cap, decompression bomb guard, active content warning, local duplicate check) BEFORE reaching DOC25 conversion (per Artifact 5 §6.1 hybrid_deterministic_schema_llm strategy). V4 NOTE: V3 included "hash reputation" in this list. V4 strips because the hash_reputation_check field was a phantom feature (no provider, no API spec). Hash reputation is V1.7+ feature; not blocked on V1.6 ship. Failure routes to upload_safety_failed with namespaced reason code. Bypassing file-safety controls is non-conformant. Runtime pseudocode: function validate_external_upload( upload_event: ExternalUploadEvent, session: SessionProfile ): ValidationResult { if (session.session_kind !== "share_link_session") return accept(); const controls = lookup_external_upload_file_safety_controls( session.external_upload_file_safety_controls_ref ); // Mime sniffing if (controls.mime_type_sniffing) { const sniffed = sniff_mime(upload_event.bytes); if (sniffed !== upload_event.declared_mime) { return reject("upload_safety_failed", "mime_type_mismatch"); } } // Size cap if (upload_event.size_bytes > controls.max_file_size_bytes) { return reject("upload_safety_failed", "file_size_exceeds_cap"); } // Decompression bomb guard if (is_archive(upload_event)) { const ratio = compute_decompression_ratio(upload_event); if (ratio > controls.archive_max_decompression_ratio) { return reject("upload_safety_failed", "decompression_bomb_detected"); } const decompressed_size = compute_decompressed_size(upload_event); if (decompressed_size > controls.archive_max_decompressed_size) { return reject("upload_safety_failed", "decompressed_size_exceeds_cap"); } } // Active content if (has_active_content(upload_event)) { switch (controls.active_content_block_or_warn) { case "block": return reject("upload_safety_failed", "active_content_blocked"); case "warn_user": emit_user_warning("active_content_detected"); break; case "strip_active_content": attempt_strip_active_content(upload_event); break; } } // Local duplicate check if (controls.local_duplicate_check) { const dup = lookup_existing_artifact_by_hash(upload_event.hash); if (dup) { emit_user_notification("upload_duplicate_detected", dup.ref); } } return accept(); } ``` OP-A rows: `OBL-I-EXTERNAL-UPLOAD-QUARANTINE-01` (existing) + `OBL-I-V17-HASH-REPUTATION-01` (V1.7 deferred). Acceptance test: V3-AT-15. --- ## §8. DOC24 capability registry runtime ### §8.1 Owner clarification (V4-§0.4-1) **[V4 PATCH:V4-§0.4-1 per R-CG #1 + R-G55X §3 — DOC24 owns capability registry]** Per V4 §0.4.1 ownership correction: ```text DOC24 OWNS the capability registry. NOT EC. NOT DOC25. V3 had implicit confusion (V3 §0.4 listed EC as capability registry owner; V3 §4.1 said DOC24). V4 corrects: capability registry is a DOC24 runtime concern. DOC25 V2.0 §25.6 amended (per Artifact 5 R0.2 §1.2 A1) to reference DOC24 R3.1+ §14 capability registry as authoritative source. EC owns: - Capacity leases for capability execution (per V3.7 OBL-EC-NEW-CAPACITY-LEASE-01) - Capability execution gating runtime (whether the registered capability can execute given current capacity) DOC25 owns: - Document-intelligence tool registration payloads (consumed by DOC24 registry as registration metadata). ``` OP-A row: `OBL-EC-NEW-01` (V3.7 base) — RegisterRuntimeToolWithKnowledgeCommandSchema atomic command (creates registry row + graph node + cache entry transactionally; rollback on partial failure). Per V4-§0.4-1: DOC24 owns the registry; EC implements the atomic command bus that DOC24 invokes. ### §8.2 Capability registry schema ```typescript type CapabilityRegistryEntry = { // DOC24-owned capability_id: string; // canonical id; namespaced // e.g., "calendar.create_event" namespace: string; // "calendar" / "email" / etc. name: string; // human-readable name description: string; registered_at: ISO8601; registered_by_actor_ref: string; // origin actor (typically // DOC24 or system) registration_basis: | "v1_5_1_native_capability" // V1.5.1 carry-forward | "v1_6_native_capability" // V1.6-introduced | "doc25_tool_intelligence_registration" // per DOC25 V2.0 §25 | "user_registered_external" // user opt-in external tool | "system_synthesized"; // system-derived metadata: CapabilityMetadata; lifecycle_state: | "active" | "deprecated" | "retired" | "experimental"; schema_version: 1; }; type CapabilityNamespaceEntry = { // DOC24-owned namespace: string; // canonical namespace name description: string; registered_at: ISO8601; parent_namespace?: string; // hierarchical (e.g., // "email.outbox" parent = // "email") registration_basis: | "v1_5_1_carry_forward" | "v1_6_introduced" | "doc25_tool_intelligence" | "user_registered"; schema_version: 1; }; type CapabilityMetadata = { schema_kind: // input schema typing | "json_schema" | "structured_grammar" | "free_form_query" | "no_schema"; schema_ref?: string; // pointer to schema // declaration output_kind: | "structured_data" | "side_effect_only" | "search_results" | "synthesis"; side_effects: Array< // non-exhaustive list // of side effects | "external_api_call" | "graph_write" | "file_emit" | "notification" >; capacity_lease_class?: string; // EC capacity bucket // (per OBL-EC-NEW- // CAPACITY-LEASE-01) schema_version: 1; }; ``` ### §8.3 INV-I-CAP-1 V4-I-2 namespace registry refinement (canonical home) Per §3.2 above (full INV-I-CAP-1 statement); §8.3 specifies the registry-side enforcement. ```text Registry-side rules per V4-I-2: 1. Namespace registration: - "namespace_all" CapabilityPattern requires the namespace exist in CapabilityNamespaceEntry registry. - "prefix_wildcard" pattern with prefix "calendar.event_" requires "calendar" be a registered namespace (the wildcard depends on the namespace existing; future capabilities within that namespace are deny-effective). 2. Capability registration: - "exact" CapabilityPattern requires the specific capability_id exist in CapabilityRegistryEntry registry. 3. Pattern construction validation: - At CapabilityPolicy persistence time: kernel validates each pattern against the registry. Unregistered patterns reject with reason_code = "unregistered_pattern". 4. Capability registration ordering: - To register a CapabilityPattern, the namespace OR capability MUST already be registered (or co-registered atomically). Atomic registration command (per V3.7 OBL-EC-NEW-01): function register_capability_atomically( capability_id: string, namespace: string, metadata: CapabilityMetadata ): RegistrationReceipt { return ec.atomic_command({ kind: "register_capability", operations: [ // 1. Ensure namespace exists. { op: "ensure_namespace", namespace }, // 2. Insert capability row. { op: "insert_capability", capability_id, namespace, metadata }, // 3. Create graph node (per DOC72 capability node-kind). { op: "create_graph_node", node_kind: "capability", ref: capability_id }, // 4. Cache entry. { op: "cache_entry", ref: capability_id } ], rollback_on_partial_failure: true, }); } ``` OP-A rows: `OBL-EC-NEW-01` (atomic command) + `OBL-D24-CAPABILITY-POLICY-V16-01` + `OBL-D24-CAPABILITY-NAMESPACE-V16-01` (NEW per Artifact 4). [V1.6 DRAFTING NOTE: capability namespace hierarchy depth (parent_namespace) max depth deferred; V1.6 default is no enforcement; V1.7+ may add depth cap. Tracked Tier B Q-3-A4-CAPABILITY-NAMESPACE-DEPTH.] ### §8.4 EC capability execution gating (per V4-§0.4-1) ```typescript function ec_gate_capability_execution( capability_id: string, session_profile_ref: string ): CapabilityExecutionGate { // Step 1: capability registered (DOC24 registry consult). const entry = capability_registry.lookup_capability(capability_id); if (!entry) { return { permitted: false, reason: "capability_not_registered", reason_code: "session.capability_not_available" }; } if (entry.lifecycle_state !== "active") { return { permitted: false, reason: `capability_lifecycle_${entry.lifecycle_state}`, reason_code: "session.capability_not_active" }; } // Step 2: session capability_policy permits. const session = session.read(session_profile_ref); const policy = lookup_capability_policy(session.capability_policy_ref); const policy_check = check_capability_permitted(capability_id, policy); if (!policy_check.permitted) { return { permitted: false, reason: policy_check.reason, reason_code: "session.capability_blocked_by_policy" }; } // Step 3: EC capacity available. if (entry.metadata.capacity_lease_class) { const lease = ec.capacity_lease_request( entry.metadata.capacity_lease_class, "user_initiated" ); if (!lease.granted) { return { permitted: false, reason: "capacity_unavailable", reason_code: "session.capability_capacity_blocked", lease_state: lease.state }; } } return { permitted: true, lease: lease ?? null }; } ``` This split honors V4-§0.4-1 ownership: DOC24 owns the registry decision; EC owns the capacity decision; both gate execution. --- ## §9. Reason code registry consumption ### §9.1 Registry consumer surface The reason code registry canonical home is V4 §0.7.2 + Artifact 1 §19 (cross-referenced; not yet R0.1 schema). This section specifies how Artifact 4 session runtime consumes the registry. Per V4 §0.7.2: every reason code emitted by V1.6 release wave artifacts MUST be registered in the registry with `default_recipient_visibility` field per V4-I-DENIAL-1. ```typescript type ReasonCodeRegistry = { // canonical home V4 §0.7.2 entries: Record; // keyed by reason_code schema_version: 1; }; type ReasonCodeRegistryEntry = { // per §7.3 reason_code: string; // namespaced description: string; default_recipient_visibility: | "expose" | "generic_only" | "audit_log_only"; owner_doc: string; // origin doc // (DOC73 / DOC24 / // DOC25 / EC / etc.) schema_version: 1; }; ``` ### §9.2 Consumer entry points ```typescript function lookup_reason_code(reason_code: string): ReasonCodeRegistryEntry | undefined { return reason_code_registry.entries[reason_code]; } function resolve_recipient_visibility( reason_code: string, session: SessionProfile ): "expose" | "generic_only" | "audit_log_only" { const entry = lookup_reason_code(reason_code); if (!entry) return "generic_only"; // unregistered → safe default if (session.session_kind === "host_session") return "expose"; // host sees all return entry.default_recipient_visibility; } ``` ### §9.3 Common reason code namespaces (V1.6 enumeration) Per V4 §0.7.2 + Artifact 1 §19 + cross-doc obligations: ```text V1.6 reason code namespaces (consumed by Artifact 4 runtime): session.* — session lifecycle, capability gating (this artifact) cap.* — capability registry runtime (this artifact) search.* — search router failures (this artifact) retrieval.* — retrieval-time failures (this artifact) access.* — access overlay enforcement (Artifact 3 §12 + this artifact §16) envelope.* — kernel envelope validation (Artifact 3) binding.* — binding evaluation (Artifact 3) extraction.* — extraction pipeline (Artifact 5) filing.* — filing-unit lifecycle (Artifact 2) cu.* — CU lifecycle + INV-MVC-CU-1 (Artifact 1 + Artifact 3) policy.* — policy generation, advance, snapshot (Artifact 1 + Artifact 3) share.* — share-link grant / revocation (this artifact) upload.* — external upload safety (this artifact §7) doc1.* — DOC1 governance hooks (DOC1 cross-doc) doc25.* — DOC25 ingestion (cross-doc) capacity.* — EC capacity gating (EC; consumed here) Each namespace registered in CapabilityNamespaceEntry-style root (per V4 §0.7.2 reason code registry). Namespace ownership tracked via owner_doc field. ``` [V1.6 DRAFTING NOTE: full per-reason-code visibility table not inlined here; V1.6 release wave handoff includes the registry as a separate deliverable. Step 9 cross-artifact audit verifies each reason code referenced in any artifact has a registry entry.] OP-A rows: `OBL-D24-REASONCODES-V16-01` (V3.7 base; consumed here) + `OBL-D24-REASON-CODE-VISIBILITY-V16-01` (V4-I-DENIAL-1; per §7.3). --- ## §10. Group M — Unified Search Router runtime ### §10.1 Router runtime entry point Per V4 §2.1 + R-EX §6 executor classes: ```typescript // Router top-level entry point: router.plan_search( query: string, session_profile_ref: string, query_intent_hint?: QueryIntent ) → UnifiedSearchPlan // R0.2 NEW per AUDIT_DOC73_Artifact4_R0.1.md MED-A4-3 + MED-A4-4 — // SearchExecutionResult + SearchResult schemas declared inline: type SearchExecutionResult = { // R0.2 NEW per MED-A4-3 search_run_id: string; results: SearchResult[]; // empty array on no // results (NOT null) result_count: number; // 0 on empty; // semantically // distinct from null manifest_ref: string; // pointer to // SearchExecutionManifest // (§13.1) coverage_visible_ref: string; // pointer to // SearchCoverageReceiptVisible // (§13.2) coverage_internal_ref: string; // pointer to // SearchCoverageReceiptInternal failure?: SearchPlanFailure; // populated when // plan validation // or execution // failed (per §15.1) schema_version: 1; }; type SearchResult = { // R0.2 NEW per MED-A4-4 result_id: string; result_kind: | "filing_unit" | "artifact_segment" | "derived_memory" // CU | "topic_assignment" | "court_disposition_observation" | "binding_outcome"; source_artifact_id?: SourceArtifactRef; // when source-bound // (per Artifact 5 §2.2) filing_unit_id?: FilingUnitRef; // when filing-bound filing_unit_version_id?: FilingUnitVersionRef; cu_id?: string; // when CU-bound // (per Artifact 1 §8.2) rank_score: number; // post-fusion ranking // score source_spans?: SourceSpan[]; // per // source_span_required // on RetrievalPosture // (§12.1); per // INV-MVC-CU-1 visibility_class: VisibilityClass; // per Artifact 1 §13.1 match_surface: string; // which surface matched // (per // required_surface_disclosure) version_selection_disclosure?: { // per // INV-M-VERSION-AWARE-1 // §15.5 selected_version: string; excluded_versions: string[]; selection_basis: string; // e.g., // "legal_version_kind_precedence" }; affordances?: Array< // per Artifact 5 // §5.3 RecipientMaterializationResolution // when share-link | "download" | "download_redacted" | "view" | "view_redacted" | "quote" | "quote_from_redacted" | "cite" | "fetch_to_view" | "fetch_to_quote" >; schema_version: 1; }; ``` Runtime flow: ```text Phase 1: Resolve query intent (per §15 QueryIntentResolution) - Deterministic-pattern resolver attempts first. - Session profile may force intent (e.g., review session forces "review_audit"). - User explicit tag overrides. - Model-assisted disclosed (low-confidence fallback). - Output: QueryIntentResolution. Phase 2: Resolve retrieval posture (per §12 RetrievalPosture) - Maps QueryIntent + query characteristics to RetrievalPosture per §12.5 default rules. - Posture determines source_span_required + filing_content_scope. Phase 3: Resolve scope (per §12 SearchScope) - Combines RetrievalPosture + temporal_scope (per V4-M-SCOPE) + case_scope + corpus_scope + filing_unit_scope + visibility_class_scope. Phase 4: Resolve executor assignments (per §11 ExecutorAssignment) - Maps RetrievalPosture + query characteristics to executor list. - Multi-executor for queries spanning surfaces. - Default rules: content_primary single-corpus → primary_direct legal citation lookup → doc18_legal_search_direct memory-primary → memory_agent cross_source_synthesis → multi-executor (memory_agent + document_intelligence_agent) - Per-executor budget allocation via EC capacity leases. Phase 5: Plan assembly - Construct UnifiedSearchPlan with executor_assignments[] + result_fusion_strategy + search_index_snapshots + query_expansions_planned. - Validate plan (per §11.X plan validation). - Return plan. Phase 6: Execute (router.execute_search) - Dispatch to each executor per ExecutorAssignment. - Apply result_fusion_strategy. - Emit SearchExecutionManifest + SearchCoverageReceipt. - Return SearchExecutionResult. ``` ### §10.2 Router determinism Per V3-M-9 + Reference R1 §2: graph queries never spawn sub-agents. Search Router selects executor classes deterministically; agents do NOT pick their own class. ```text Determinism rules: - For a given (query + session_profile_ref + query_intent_hint), router.plan_search returns the same UnifiedSearchPlan modulo timestamp / non-deterministic identifiers (plan_id is fresh per call but executor_assignments etc. are deterministic). - Result fusion strategy is deterministic given the same executor outputs. - Index snapshot selection is deterministic (latest available per index_id at plan_at). Non-determinism sources allowed: - Model-assisted intent resolution (per QueryIntentResolution. resolver_kind = "model_assisted_disclosed"); user-corrected classification. - LLM-driven query expansion (per QueryExpansionRecord. expansion_kind = "embedding_neighbor"); declared in plan. Non-determinism sources disallowed: - Random sampling of corpora. - Hidden model-assisted classification (per INV-M-INTENT-1; §15). - Agent-class picks not driven by router (per V3-M-9; §10). ``` ### §10.3 Multi-executor result fusion Per V4-M-5: plans with executor_assignments[] of length > 1 use result_fusion_strategy: ```typescript type ResultFusionStrategy = | "rrf" // reciprocal rank fusion | "weighted_sum" // weighted by ExecutorAssignment.weight | "executor_priority"; // first-executor wins; others backfill ``` Fusion runtime: ```typescript function fuse_results( plan: UnifiedSearchPlan, executor_results: ExecutorResult[] ): SearchExecutionResult { switch (plan.result_fusion_strategy) { case "rrf": return reciprocal_rank_fusion(executor_results, RRF_K); case "weighted_sum": const weights = plan.executor_assignments.map(a => a.weight ?? 1); return weighted_sum_fusion(executor_results, weights); case "executor_priority": // First executor's result drives; others backfill if first // returns < min_results threshold. for (const result of executor_results) { if (result.items.length >= MIN_RESULTS_THRESHOLD) { return result; } } return concat_unique(executor_results); } } ``` `RRF_K = 60` per Artifact 1 §20 + V1.5.1 §28A.2 RRF formula constant. V1.6 default; configurable per `DOC24_SEARCH_RRF_K_CONSTANT` (R0.2 PATCH per MED-A4-6 inlines + MED-A4-8 prefix consistency). `MIN_RESULTS_THRESHOLD` default: 5 (configurable per `DOC24_SEARCH_MIN_RESULTS_FOR_PRIMARY_EXECUTOR_PRIORITY`; R0.2 renamed from EC_-prefix per MED-A4-8 — DOC24 owns search router runtime per V4-§0.4-1). OP-A row: `OBL-D24-SEARCH-FUSION-V16-01` (V4-M-5; multi-executor result fusion). --- ## §11. Group M — UnifiedSearchPlan + ExecutorAssignment ### §11.1 UnifiedSearchPlan canonical schema (V4-M-5 + V4-M-SCOPE) Per V4 §2.1.8 + V4 §2.1.9: ```typescript type UnifiedSearchPlan = { // V4 expanded per V4-M-5 // + V4-M-SCOPE plan_id: string; query_intent_resolution: QueryIntentResolution; // per §15.X search_scope: SearchScope; // V4 NEW per V4-M-SCOPE // (replaces standalone // retrieval_posture) executor_assignments: ExecutorAssignment[]; // V4 NEW: 1+ executors // per plan result_fusion_strategy: ResultFusionStrategy; // V4 NEW search_index_snapshots: SearchIndexSnapshotRef[]; query_expansions_planned: QueryExpansionRecord[]; amendable_by_executor: boolean; // false for read-only // graph queries plan_at: ISO8601; // when plan was constructed schema_version: 1; }; ``` ### §11.2 ExecutorClass enum Per V3-M-9 + V4-M-5: ```typescript type ExecutorClass = | "primary_direct" // graph query directly against EC; no agent | "doc18_legal_search_direct" // FTS5 legal citation tokenizer; no agent // (per OP-A V3.7 OBL-D18-LEGAL-SEARCH-01) | "memory_agent" // agent for memory-primary retrieval // (per Artifact 1 §15.X.7.7-9 // MemoryAgent specialist; READ-ONLY // per INV-15.7.9) | "document_intelligence_agent"; // agent for content-primary deep retrieval // (OCR, table extraction, span grounding; // per Artifact 1 §15.X.7.7-9 // DocumentIntelligenceAgent specialist; // READ-ONLY per INV-15.7.9) ``` **[R0.2 PATCH per AUDIT_DOC73_Artifact4_R0.1.md HIGH-A4-2]** — INV-15.7.8 (sole-writer) + INV-15.7.9 (read-only specialists) constraints flow into agent-class executor dispatch: ```text INV-15.7.8 + INV-15.7.9 enforcement for memory_agent / document_intelligence_agent (R0.2 NEW per HIGH-A4-2): Per Artifact 3 §20.1 INV-15.7.8 (sole-writer): PrimaryPBEOrchestrator is the ONLY authorized envelope writer. The search router dispatches to memory_agent and document_intelligence_agent for retrieval; results return as SpecialistPartialOutput; the orchestrator decides whether to construct a downstream envelope (e.g., authority_recompute trigger after ranking). Per Artifact 3 §20.2 INV-15.7.9 (read-only specialists): memory_agent and document_intelligence_agent are READ-ONLY against durable storage. They: - READ from kernel_event_log, durable receipts, blob_store (per Artifact 1 §A.11), corpus_membership_records, ExtractionRunRecord, BindingEvaluationManifest, etc. - WRITE to session_context store (ephemeral; per V3.7 OBL-EC-NEW-SESSION-CONTEXT-01). - EMIT OperationIntent (upstream concept) for orchestrator materialization. - DO NOT submit PBEOperationEnvelopes directly. Search router enforcement: function dispatch_to_executor( assignment: ExecutorAssignment, plan: UnifiedSearchPlan, access_set: AccessSet, session: SessionProfile ): ExecutorResult { switch (assignment.executor_class) { case "primary_direct": case "doc18_legal_search_direct": // Direct query against indexes; no agent boundary; no INV // 15.7.8/9 concern. return execute_direct_query(...); case "memory_agent": case "document_intelligence_agent": // Specialist sub-agent dispatch. Spawn boundary checked per // §6.2 INV-I-NATIVE-SESSION-1 + Artifact 3 §20. const binding = spawn_specialist_sub_agent( session, assignment.executor_class, plan ); // Specialist runs READ-ONLY against durable storage; // intermediate results in session_context store. const partial_output = run_specialist_query( binding, assignment, access_set ); // Orchestrator (NOT specialist) materializes any envelope // emissions. Specialist returns SpecialistPartialOutput. return convert_partial_output_to_executor_result(partial_output); } } function spawn_specialist_sub_agent( parent_session: SessionProfile, executor_class: "memory_agent" | "document_intelligence_agent", plan: UnifiedSearchPlan ): NativeSessionScopeBinding { // Per §6.2 validate_subagent_spawn: const parent_binding = lookup_native_session_scope_binding( parent_session.native_session_scope_binding_ref ); const validation = validate_subagent_spawn( parent_binding, "subagent_session" ); if (!validation.accepted) { throw new Error(`specialist_sub_agent_spawn_blocked_${validation.reason}`); } return create_native_session_scope_binding({ ec_session_id: new_id(), openclaw_native_session_id: spawn_openclaw_native_session(), binding_kind: "subagent_session", inherited_capability_policy_ref: parent_binding.inherited_capability_policy_ref, // ... per §6.1 schema max_spawn_depth: parent_binding.max_spawn_depth - 1, context_inheritance_policy: "scoped_inherit", // search // scope only transcript_visibility_policy: "shared", // host sees // sub-agent log child_spawn_constraint: "deny_all", // search-time // specialists // don't spawn further schema_version: 1, }); } ``` ### §11.3 ExecutorAssignment schema Per V4-M-5: ```typescript type ExecutorAssignment = { // V4 NEW per V4-M-5 executor_class: ExecutorClass; scope_ref: string; // sub-scope this executor // handles (e.g., specific // corpus or filter) weight?: number; // for weighted_sum fusion budget_tokens?: number; // EC capacity allocation reason_code: string; // why this executor // was assigned (per // §9 reason codes) schema_version: 1; }; ``` ### §11.4 Executor assignment defaults ```text Default ExecutorAssignment dispatch per RetrievalPosture: document_text_primary (single corpus, simple keyword query): executor_assignments: [primary_direct] result_fusion_strategy: executor_priority document_text_primary (citation lookup): executor_assignments: [doc18_legal_search_direct] result_fusion_strategy: executor_priority derived_memory_primary: executor_assignments: [memory_agent] result_fusion_strategy: executor_priority metadata_primary: executor_assignments: [primary_direct] result_fusion_strategy: executor_priority mixed_surface_disclosed (cross-corpus + cross-source): executor_assignments: [primary_direct, memory_agent] result_fusion_strategy: rrf weight: undefined (RRF doesn't use weight) cross_source_synthesis: executor_assignments: [memory_agent, document_intelligence_agent] result_fusion_strategy: rrf Per V3-M-3: synthesis REQUIRES source span grounding; document_intelligence_agent provides spans. Multi-executor for queries spanning surfaces: Example: "find oppositions to MTDs that argue PSLRA falls short" → [doc18_legal_search_direct (FTS5 for "PSLRA"), memory_agent (extracted argument-CUs), document_intelligence_agent (span-grounded confirmation)] fusion: rrf ``` OP-A rows: `OBL-EC-V16-K-ROUTING-OUTBOX-01` (existing) + `OBL-D24-SEARCH-FUSION-V16-01` (V4-M-5). ### §11.5 Plan validation ```text Plan validation gates (called from router.plan_search after Phase 5 assembly): V-PLAN-1: query_intent_resolution.resolved_intent ∈ QueryIntent enum. V-PLAN-2: search_scope.retrieval_posture.posture ∈ RetrievalPosture enum. V-PLAN-3: executor_assignments[] non-empty. V-PLAN-4: At least one executor_assignment has scope_ref covering the full query scope (or executors collectively cover scope). V-PLAN-5: search_index_snapshots correspond to executors needing them (e.g., FTS5 needs index snapshot ref). V-PLAN-6: query_expansions_planned filtered through access overlay (per INV-M-EXPANSION-ACCESS-1; §14). V-PLAN-7: Session profile valid (per INV-M-SESSION-1). Plan validation failure → SearchPlanFailure with appropriate failure_kind. ``` --- ## §12. Group M — RetrievalPosture + SearchScope ### §12.1 RetrievalPosture canonical schema (V4-M-1 renamed) **[V4 PATCH:V4-M-1 per R-CG #4 + R-G55 #5 + R-G55X §7 — RetrievalPosture rename]** Per V4 §2.1.1 (lines 1728-1755): ```typescript type RetrievalPosture = { posture: // V4 RENAMED: | "document_text_primary" // V3: content_primary // user wants source text | "derived_memory_primary" // V3: memory_primary // user wants extracted memories | "metadata_primary" // unchanged // metadata answers (when/who) | "mixed_surface_disclosed" // V3: hybrid_disclosed // search both, disclose // match surface | "cross_source_synthesis"; // V3: synthesis_disclosed // synthesis with required // source spans // Where in the source surface to look (replaces V2's // SearchSurfaceScope) filing_content_scope?: | "lead_argument_only" | "all_argument_parts" | "exhibits_only" | "proposed_orders_only" | "all_filing_parts" | "package_metadata_only"; // Source-span requirement bound to posture source_span_required: boolean; source_span_count_minimum?: number; // for cross_source_synthesis // Surface disclosure mandatory required_surface_disclosure: boolean; schema_version: 1; }; ``` V3 → V4 rename migration: V3 references update to V4 names. Coding agents constructing posture with V3 names should reject with `posture_name_v3_legacy` reason code. ### §12.2 SearchScope canonical schema (V4-M-SCOPE) **[V4 PATCH:V4-M-SCOPE per R-CL4 #15 — SearchScope schema]** Per V4 §2.1.8 (lines 2206-2245): ```typescript type SearchScope = { // V4 NEW per V4-M-SCOPE retrieval_posture: RetrievalPosture; // posture stays separate // V4 NEW: temporal scope for date-range queries temporal_scope?: { date_field: "filing_date" | "effective_date" | "ruling_date" | "ingested_at" | "docket_entry_date"; start: ISO8601 | null; // null = no lower bound end: ISO8601 | null; // null = no upper bound inclusive_endpoints: boolean; timezone_basis: "originating" | "utc" | "host_user_local"; // (per INV-V16-TIMEZONE-1) }; // V4 NEW: scope axes already implied in V3, now explicit case_scope?: CaseRef[]; corpus_scope?: CorpusRef[]; filing_unit_scope?: FilingUnitRef[]; visibility_class_scope?: VisibilityClass[]; schema_version: 1; }; ``` Search router operates over SearchScope; index snapshots verify temporal coverage of the requested date range. OP-A row: `OBL-D24-SEARCH-SCOPE-V16-01` (V4 NEW per V4-M-SCOPE). ### §12.3 INV-V16-TIMEZONE-1 in temporal_scope (Artifact 1 §19.1 cross-reference) Per Artifact 1 §19.1: time-bearing fields persist UTC + IANA tz + originating calendar date when carrying legal significance. SearchScope.temporal_scope honors: ```text - timezone_basis = "originating": use originating_tz of the date_field (per FilingUnit.filing_date_originating_tz / etc.). - timezone_basis = "utc": use UTC instant. - timezone_basis = "host_user_local": resolve relative to host's configured timezone. Implementation: query construction translates start/end to the underlying field's tz basis before search. ``` ### §12.4 RetrievalPosture default rules (V3-M-3) Per V4 §2.1.2: ```text "What does brief argue about X?" → document_text_primary + filing_content_scope: lead_argument_only + source_span_required: true "Find risk disclosure defendants cite" → document_text_primary + filing_content_scope: all_filing_parts + source_span_required: true "Show me the proposed order" → document_text_primary + filing_content_scope: proposed_orders_only + source_span_required: true "What documents were filed with motion?" → metadata_primary + filing_content_scope: package_metadata_only + source_span_required: false "Quote what they said" → document_text_primary + filing_content_scope: lead_argument_only + source_span_required: true "Themes across briefs" [V3 CHANGED from memory_primary per V3-M-3] → cross_source_synthesis + filing_content_scope: all_argument_parts + source_span_required: true + source_span_count_minimum: 3 "Across these briefs, where did X come up" → cross_source_synthesis + filing_content_scope: all_filing_parts + source_span_required: true + source_span_count_minimum: 2 "Show me my notes on this brief" → derived_memory_primary + source_span_required: false ``` `cross_source_synthesis` REQUIRES source span grounding. The system cannot answer thematic synthesis queries by aggregating memories without producing source spans. ### §12.5 INV-MVC-1 + INV-MVC-2 read-time consumer Per V4 §2.1.3 INV-MVC-2 + Artifact 1 §15.X.7.A. Read-time mirror: ```text INV-MVC-2 read-time enforcement (canonical home Artifact 1 §15.X; read-side mirror Artifact 4 §12.5): When DOC25 emits DocumentArtifactVersionChangedEvent (per Artifact 5 §13), DOC73 §15.X stale-memory gate marks affected derived memories / topic assignments / CUs / VersionedClaims / relationship candidates as `stale_pending_source_changed`. Read-time: search retrieval results from `stale_pending_source_changed` entities are filtered or surfaced with framing per FieldResolution.source (per Artifact 5 §9.2). For derived_memory_primary or cross_source_synthesis posture: stale memories are NOT cited as authoritative; framing surfaces "stale; re-extraction in progress" per INV-EXT-7. ``` OP-A rows: `OBL-D25-D73-V16-STALE-01` (DOC73 consumer side; V3.7 base). ### §12.6 INV-MVC-3 read-time consumer Per Artifact 1 §15.X.7.A + Artifact 3 §10: ```text INV-MVC-3 read-time consumer: Read-time consumers (search retrieval, snippet generation) MUST treat all source content (text + metadata fields per V4-A-3) as data, NEVER as instructions. The wrapper applied at ingestion (Artifact 5 §6.4 INV-D25-PROMPTINJ-1) ensures content is escaped/marked; read-time consumers honor the marker scheme (per DOC25 V2.0 §18 marker scheme). Implementation: snippet generators inject content under marker boundaries; LLM-driven post-retrieval critique (per "llm_invocation_permitted_for_simulation"-eligible operation kinds) honors the marker scheme. ``` --- ## §13. Group M — SearchExecutionManifest + SearchCoverageReceipt ### §13.1 SearchExecutionManifest schema Per V4 §2.1.5: ```typescript type SearchExecutionManifest = { // DOC24-owned manifest_id: string; search_run_id: string; // stable per-run id plan_id: string; // ref to UnifiedSearchPlan executed_at: ISO8601; // Per-executor execution records executor_executions: Array<{ executor_class: ExecutorClass; started_at: ISO8601; completed_at: ISO8601; result_count: number; capacity_lease_id?: string; failures?: ExecutorFailure[]; }>; // Result fusion record fusion_strategy: ResultFusionStrategy; fusion_completed_at: ISO8601; // Linked receipts coverage_receipt_internal_ref: string; // SearchCoverageReceiptInternal coverage_receipt_visible_ref: string; // SearchCoverageReceiptVisible // Session session_profile_ref: string; policy_generation_id: string; schema_version: 1; }; ``` ### §13.2 SearchCoverageReceipt internal vs visible split (V4-M-2) **[V4 PATCH:V4-M-2 per R-CG #5 + R-G55 #7 + R-G55X §9 + R-G55S §5 — internal vs visible split]** Per V4 §2.1.5: ```typescript // V4 NEW per V4-M-2: type SearchCoverageReceiptInternal = { // host_user + advanced+ // tiers only receipt_id: string; search_run_id: string; // Coverage scope (full) searched_corpora: CorpusRef[]; searched_corpus_segments: CorpusSegmentRef[]; searched_filing_units: FilingUnitRef[]; excluded_corpora: ExcludedCorpus[]; excluded_filing_units: ExcludedFilingUnit[]; excluded_filing_parts: ExcludedFilingPart[]; // Counts (full breakdown) searched_count: number; excluded_count: number; policy_filtered_count: number; visibility_filtered_count: number; staleness_filtered_count: number; // Index health (V3 NEW per R-V22 §3) index_snapshots_used: SearchIndexSnapshotRef[]; any_index_stale: boolean; staleness_summary?: { index_id: string; stale_seconds: number }[]; // Query expansion (V3 NEW per R-V22 §3) query_expansions_used: QueryExpansionRef[]; expansion_disclosure_provided: boolean; // Completeness (V4 expanded per V4-M-6) result_set_completeness: | "exhaustive_for_scope" | "exhaustive_for_scope_stale" | "ranked_top_k_not_exhaustive" // V4 NEW per V4-M-6 | "partial_due_to_policy" | "partial_due_to_visibility" | "partial_due_to_staleness" | "partial_due_to_index_health" | "partial_due_to_resource_limit"; // V4 NEW per V4-M-8 — scope digest: scope_digest: string; // SHA-256 of // (corpus_ids | selectors | // snapshots | session_profile_hash) schema_version: 1; }; type SearchCoverageReceiptVisible = { // share-link sessions receipt_id: string; search_run_id: string; searched_count: number; excluded_count_total: number; // aggregate; per-reason // counts SUPPRESSED result_set_completeness: SearchCoverageReceiptInternal["result_set_completeness"]; expansion_disclosure_provided: boolean; scope_digest: string; // OK to share schema_version: 1; }; ``` ### §13.3 INV-M-COVERAGE-VISIBILITY-1 Per V4-M-COVERAGE-VISIBILITY: ```text INV-M-COVERAGE-VISIBILITY-1 (V4 NEW; canonical home Artifact 4 §13.3): Per-reason exclusion counts are NOT exposed to share-link sessions. Aggregate exclusion count + generic "some results excluded" framing only. Host sessions see full reason breakdown via SearchCoverageReceiptInternal; share-link sessions see SearchCoverageReceiptVisible. Runtime dispatch: function emit_search_coverage_receipts( search_run: SearchRun, session: SessionProfile ): { internal: SearchCoverageReceiptInternal; visible: SearchCoverageReceiptVisible } { const internal = construct_full_coverage_receipt(search_run); persist_coverage_receipt_internal(internal); // Always construct visible receipt (regardless of session_kind); // policy controls who sees which. const visible = { receipt_id: new_id(), search_run_id: search_run.id, searched_count: internal.searched_count, excluded_count_total: internal.excluded_count, result_set_completeness: internal.result_set_completeness, expansion_disclosure_provided: internal.expansion_disclosure_provided, scope_digest: internal.scope_digest, schema_version: 1, }; persist_coverage_receipt_visible(visible); return { internal, visible }; } function expose_to_session( receipts: { internal: ...; visible: ... }, session: SessionProfile ): SearchCoverageReceiptInternal | SearchCoverageReceiptVisible { return session.session_kind === "host_session" ? receipts.internal : receipts.visible; } ``` OP-A row: `OBL-D24-COVERAGE-RECEIPT-V16-01` (V4-M-2). ### §13.4 scope_digest (V4-M-8) Per V4 §2.1.5: ```text scope_digest is SHA-256 of: (corpus_ids sorted | selectors serialized | snapshot_ids sorted | session_profile_hash) Purpose: stable identity of "what was searched"; enables: - Identical-scope cache hits (same scope_digest → same expected coverage profile). - Audit comparison ("did the scope of this search change between runs?"). - Share-link safe (does not leak content; just identifies scope fingerprint). scope_digest is included in BOTH internal and visible receipts (safe for share-link). OP-A row: covered via OBL-D24-COVERAGE-RECEIPT-V16-01. ``` ### §13.5 ranked_top_k_not_exhaustive (V4-M-6) Per V4-M-6: ```text result_set_completeness = "ranked_top_k_not_exhaustive" (V4 NEW): Used when search has applied an intentional top-k truncation (e.g., k=20 top results returned; the underlying corpus had more matches but ranking determined top-k was sufficient for query intent). NOT a failure (per V4-M-4 SearchPlanFailure narrowed). Results are valid; the receipt explicitly flags that more matches exist. Distinct from "exhaustive_for_scope": exhaustive_for_scope means all in-scope items were examined and the result set is complete. Top-k truncation explicitly indicates that ranking selected k results from a larger candidate pool. Per INV-M-NEGATIVE-1: "no results" requires exhaustive_for_scope; top-k truncation is NOT a "no results" state. V1.6 default top-k: 50 (configurable per DOC24_SEARCH_DEFAULT_TOP_K_LIMIT — R0.2 renamed per MED-A4-8 prefix consistency). Per RetrievalPosture.posture: document_text_primary: top-k = 50 derived_memory_primary: top-k = 50 metadata_primary: top-k = 100 (metadata smaller per result) mixed_surface_disclosed: top-k = 50 cross_source_synthesis: top-k = 100 (more candidates needed for synthesis) ``` OP-A row: `OBL-D24-RETENTION-V16-01` (existing) + scope_digest covered via OBL-D24-COVERAGE-RECEIPT-V16-01. --- ## §14. Group M — QueryExpansion (V4-M-3 access-filtered) ### §14.1 QueryExpansionRecord schema Per V4 §2.1.5: ```typescript type QueryExpansionRecord = { // V4 expanded per V4-M-3 // + R-G55S §7 expansion_id: string; query_run_id: string; expansion_kind: | "synonym" | "stemming" | "citation_normalization" | "legal_term_expansion" | "embedding_neighbor"; applied_terms: string[]; expansion_source_corpus_ref?: CorpusRef; // V4 NEW: which corpus // contributed expansion_visible_to_session: boolean; // V4 NEW: passes access // overlay check schema_version: 1; }; ``` ### §14.2 INV-M-EXPANSION-ACCESS-1 **[V4 PATCH:V4-M-3 per R-CG #6 + R-G55 #8 + R-G55X §10 + R-G55S §7 + R-CL4 #36 — INV-M-EXPANSION-ACCESS-1]** Per V4 §2.1.5: ```text INV-M-EXPANSION-ACCESS-1 (V4 NEW; canonical home Artifact 4 §14.2): Query expansion neighborhoods derive ONLY from access-permitted content. "Did you mean PSLRA?" expansion suggestions visible to user are filtered through access overlay before rendering. Implementation: QueryExpansionRecord.applied_terms include only terms derived from corpora the session profile permits. Cross-corpus expansion that would reveal terms from inaccessible corpora is non-conformant. Specifically: a public-corpus session typing "PSLR" does NOT get "did you mean PSLRA?" expansion if PSLRA appears only in a sealed corpus inaccessible to the session. This may feel restrictive in mixed-access contexts; correct privacy behavior, not a bug. User-facing rendering: when expansion is suppressed for access reasons, the system does NOT signal "expansion suppressed" (which itself would leak access-state). System silently provides only access-permitted expansions or no expansion. Runtime pseudocode: function compute_query_expansions( query: string, session: SessionProfile ): QueryExpansionRecord[] { const candidates = compute_raw_expansion_candidates(query); return candidates.filter(candidate => { // Per INV-M-EXPANSION-ACCESS-1: filter by source corpus access. const source_corpus = candidate.expansion_source_corpus_ref; if (!source_corpus) return true; // no corpus → safe const permitted = check_corpus_access(source_corpus, session); candidate.expansion_visible_to_session = permitted; return permitted; }); } ``` OP-A row: `OBL-D24-QUERY-EXPANSION-V16-01` (V4-M-3). Acceptance test: V4-AT-33 (cross-firewall expansion blocked). ### §14.3 SearchIndexSnapshot schema Per V4 §2.1.5: ```typescript type SearchIndexSnapshot = { // DOC24-owned snapshot_id: string; index_id: string; // FTS5 / vector / metadata snapshot_timestamp: ISO8601; documents_covered_count: number; schema_version: 1; }; ``` V4-M-3 INV-M-EXPANSION-ACCESS-1 strict reading: even temporal scope expansions (e.g., "this case had filings in March-April 2024") that would derive from index snapshots covering inaccessible corpora must be filtered. --- ## §15. Group M — SearchPlanFailure + INVs (NEGATIVE / COVERAGE-INDEX / VERSION-AWARE / SESSION / INTENT / ACCESS-RANK) ### §15.1 SearchPlanFailure narrowed (V4-M-4) **[V4 PATCH:V4-M-4 per R-CG #7 + R-G55 #6 + R-G55X §8 + R-G55S §3 — narrowed]** Per V4 §2.1.1: ```typescript type SearchPlanFailure = { // V4 narrowed failure_kind: | "document_required_unavailable" // posture demanded; // none available | "memory_only_source_unavailable" // memory exists but no // source span | "scope_exceeds_session_capability" // session profile blocks // required scope | "index_stale_blocks_completeness" // index too stale | "policy_blocked" // PropA blocked | "session_profile_invalid" // V4 NEW per V4-M-INV-SESSION | "extraction_in_flight_required_for_query"; // V4 NEW failure_reason_code: string; // namespaced per §9 remediation_hint?: string; // user-facing schema_version: 1; }; ``` V4 narrowed: `no_results_within_scope` REMOVED. Empty result with valid scope is NOT a failure: it's a successful SearchExecutionManifest with empty result set + coverage receipt has `result_set_completeness: exhaustive_for_scope`. ### §15.2 INV-M-NEGATIVE-1 (no phantom emptiness) Per V4 §2.1.5: ```text INV-M-NEGATIVE-1 (V3 NEW; canonical home Artifact 4 §15.2): A "no results found" answer requires SearchCoverageReceipt.result_set_completeness == "exhaustive_for_scope" with no index health degradation. Otherwise the answer must be a scoped negative ("no briefs found in active corpora; N corpora excluded due to ") with the SearchCoverageReceipt visible or available. Phantom emptiness (a confident "no" produced when scope was not exhaustive) is a high-severity correctness violation. V4 NOTE: ranked_top_k_not_exhaustive is NOT a "no results" state — it's a successful search with k results returned and more results truncated. "No results" requires exhaustive_for_scope completeness specifically. Runtime check: function format_no_results_answer( coverage: SearchCoverageReceiptInternal, session: SessionProfile ): string { if (coverage.result_set_completeness === "exhaustive_for_scope" && !coverage.any_index_stale) { return "No results found."; } // Scoped negative return `No results in active corpora. ${coverage.excluded_count} ` + `items excluded due to ` + summarize_exclusion_reasons_for_session(coverage, session); } ``` OP-A row: covered via OBL-D24-COVERAGE-RECEIPT-V16-01. ### §15.3 INV-M-COVERAGE-INDEX-1 Per V4 §2.1.5: ```text INV-M-COVERAGE-INDEX-1 (V3 NEW; canonical home Artifact 4 §15.3): A SearchCoverageReceipt may claim result_set_completeness == "exhaustive_for_scope" ONLY IF: (a) all index_snapshots_used were current at search time (any_index_stale == false), AND (b) any query_expansions_used were disclosed in the rendered result. If either condition fails, completeness must be one of the partial_* classes with reason_code identifying the limitation. Runtime check: function classify_completeness( snapshots: SearchIndexSnapshot[], expansions_used: QueryExpansionRecord[], expansions_disclosed: boolean, actual_returned_results: number, candidates_count: number ): SearchCoverageReceiptInternal["result_set_completeness"] { if (!expansions_disclosed && expansions_used.length > 0) { return "partial_due_to_index_health"; // disclosure violation } const any_stale = snapshots.some(s => is_stale(s)); if (any_stale) { return "exhaustive_for_scope_stale"; } if (actual_returned_results >= TOP_K_DEFAULT && candidates_count > actual_returned_results) { return "ranked_top_k_not_exhaustive"; // V4-M-6 } return "exhaustive_for_scope"; } ``` ### §15.4 INV-M-ACCESS-RANK-1 (canonical home) **[V3 PATCH:V3-M-10 per R-V22 §2 — INV-M-ACCESS-RANK-1]** Per V4 §2.1.6: ```text INV-M-ACCESS-RANK-1 (V3 NEW; canonical home Artifact 4 §15.4): Search retrieval enforces access control BEFORE ranking, snippet generation, counts, facets, query expansion neighborhoods, and result- list composition. For every search: 1. Compute access set: documents / filing units / filing parts / segments / chunks the session profile + visibility class lattice + AccessOverlay permits. 2. Restrict ranking corpus to the access set. Inaccessible items contribute ZERO ranking signal. 3. Restrict snippet generation to accessible spans only. 4. Counts, facets, "did you mean," and query expansion neighborhoods derive ONLY from accessible content. 5. Result list composition operates on the access-restricted ranked set. Rendering MAY add an excluded_count surface (per SearchCoverageReceiptVisible) so the user knows N items were excluded — but not their identity, content, metadata, or any signal that would enable identification. Filtering at rendering only is non-conformant. Runtime pseudocode: // [R0.2 NOTE per AUDIT_DOC73_Artifact4_R0.1.md HIGH-A4-5] // `compute_session_access_set` body declared at §16.1 // (Group B2 read-time access overlay enforcement). Per // INV-M-ACCESS-RANK-1 (this section): the function is invoked // BEFORE ranking begins. Forward reference for read order; // implementation order is bottom-up. function execute_search_with_access_first( plan: UnifiedSearchPlan, session: SessionProfile ): SearchExecutionResult { // Phase 1: compute access set BEFORE candidate selection. const access_set = compute_session_access_set(session, plan.search_scope); // → defined §16.1 // Phase 2: dispatch to executors with access set as filter. const candidates_filtered = []; for (const assignment of plan.executor_assignments) { const executor_results = dispatch_executor( assignment, plan, access_set // <-- access_set as input ); candidates_filtered.push(executor_results); } // Phase 3: rank ONLY filtered candidates. const ranked = rank_within_access_set(candidates_filtered, plan); // Phase 4: compose result list from access-restricted ranked set. const result_list = compose_result_list(ranked); // Phase 5: emit coverage receipts (excluded_count records what was // filtered, not what was found inaccessible). emit_coverage_receipts(plan, result_list, access_set); return { results: result_list }; } ``` Acceptance tests: V3-AT-3, V3-AT-14, V3-AT-17. OP-A rows: `OBL-D24-ACCESS-FIRST-V16-01` (V4 NEW per Artifact 4) + `OBL-D73-B2-SOURCEINSTANCE-01`. ### §15.5 INV-M-VERSION-AWARE-1 **[V4 PATCH:V4-M-7 per R-G55X §37 — INV-M-VERSION-AWARE-1]** Per V4 §2.1.8: ```text INV-M-VERSION-AWARE-1 (V4 NEW; canonical home Artifact 4 §15.5): Search result merging across FilingUnitVersions: When multiple versions of same FilingUnit match query, the merge path: 1. Filters versions by session profile visibility class permission 2. Selects most authoritative version per legal_version_kind precedence (amended > corrected > reissued > public_redacted > original_as_filed) 3. Returns single result per FilingUnit (the selected version) 4. Surfaces "version_selection_disclosure" indicating which version was selected and which were excluded Implementation: result merge happens AFTER access filtering (per INV-M-ACCESS-RANK-1) but BEFORE ranking. A query matching content in both sealed_unredacted and public_redacted versions of same FilingUnit returns ONLY the version permitted by session profile. Runtime pseudocode: function merge_filing_unit_versions( candidates: SearchResult[], session: SessionProfile ): SearchResult[] { const grouped = group_by_filing_unit(candidates); const merged: SearchResult[] = []; for (const [filing_unit_id, versions] of grouped) { const accessible = versions.filter(v => check_access_overlay_permits(v, session) ); if (accessible.length === 0) continue; const selected = select_most_authoritative_version(accessible); const excluded = accessible.filter(v => v !== selected); const result_with_disclosure = { ...selected, version_selection_disclosure: { selected_version: selected.filing_unit_version_id, excluded_versions: excluded.map(v => v.filing_unit_version_id), selection_basis: "legal_version_kind_precedence", } }; merged.push(result_with_disclosure); } return merged; } function select_most_authoritative_version( versions: SearchResult[] ): SearchResult { // Per V4 §2.2.6: amended > corrected > reissued > public_redacted > // original_as_filed const order = ["amended", "corrected", "reissued", "public_redacted", "original_as_filed"]; return versions.sort((a, b) => order.indexOf(a.legal_version_kind) - order.indexOf(b.legal_version_kind) )[0]; } ``` OP-A row: `OBL-D24-VERSION-AWARE-V16-01` (V4-M-7). ### §15.6 INV-M-SESSION-1 (invalid session profile handling) **[V4 PATCH:V4-M-INV-SESSION per R-CL4 #32 — INV-M-SESSION-1]** Per V4 §2.1.1 (lines 1788-1798): ```text INV-M-SESSION-1 (V4 NEW; canonical home Artifact 4 §15.6): Search router receiving a query with session profile in revoked / expired / suspended state returns SearchPlanFailure with failure_kind = "session_profile_invalid" + appropriate failure_reason_code. The router does NOT execute the query under the inactive profile, even partially. Default reason codes: - session.profile_revoked - session.profile_expired - session.profile_suspended Runtime check (V-PLAN-7): function validate_session_profile_for_search( session_profile_ref: string ): ValidationResult { const profile = session.read(session_profile_ref); switch (profile.profile_state) { case "active": return accept(); case "draft": return reject({ failure_kind: "session_profile_invalid", failure_reason_code: "session.profile_not_yet_activated", }); case "expired": return reject({ failure_kind: "session_profile_invalid", failure_reason_code: "session.profile_expired", }); case "revoked": return reject({ failure_kind: "session_profile_invalid", failure_reason_code: "session.profile_revoked", }); case "suspended": return reject({ failure_kind: "session_profile_invalid", failure_reason_code: "session.profile_suspended", }); } } ``` OP-A row: `OBL-D24-SESSION-PROFILE-V16-01` (per §2 + INV-M-SESSION-1). ### §15.7 QueryIntentResolution + INV-M-INTENT-1 Per V3-M-8 + V4 §2.1.7: ```typescript type QueryIntentResolution = { resolved_intent: QueryIntent; // canonical V1.6 enum // (Artifact 1 §A.6) resolver_kind: | "deterministic_pattern" // regex / keyword / // structural | "deterministic_session_profile" // forced by session_profile | "deterministic_user_specified" // user explicitly tagged | "model_assisted_disclosed" // LLM classified; // disclosed to user | "user_corrected"; // user corrected prior // model classification pattern_id?: string; // if deterministic_pattern classifier_model_ref?: string; // if model_assisted_disclosed classifier_confidence?: number; user_can_override: boolean; schema_version: 1; }; ``` ```text INV-M-INTENT-1 (V3 NEW; canonical home Artifact 4 §15.7): When resolver_kind == "model_assisted_disclosed", the classification surface MUST be visible to the user with override available. Hidden model-assisted intent classification is non-conformant. Implementation: Q Dashboard surfaces a small disclosure ("Intent classified as: synthesis. Click to change to: evidence_search / doctrine_lookup / etc.") when resolver_kind = "model_assisted_disclosed" AND classifier_confidence < INTENT_DISCLOSURE_CONFIDENCE_THRESHOLD (default 0.85; configurable per DOC24_INTENT_DISCLOSURE_CONFIDENCE_THRESHOLD per MED-A4-7; **[R0.3 PATCH per architect triage 2026-05-03 — Q-3-A4-6: lowered from 0.95 to 0.85 because most full-sentence litigator queries classify clearly above 0.85; threshold mainly fires for short fragments which are user error per architect. BDSM EMA per V4-§4.X-BDSM EMA tunes per-user from telemetry over time]**). User override creates a new resolver_kind = "user_corrected" QueryIntentResolution record; the original model-assisted record is preserved in audit trail. ``` OP-A row: `OBL-D24-QUERY-INTENT-V16-01` (Artifact 4-internal). --- ## §16. Group B2 — Read-time access overlay enforcement ### §16.1 Read-time enforcement (mirror of Artifact 3 §12 write-time) Per V4 §3.2.5 Group B2 split: read-time enforcement lives in Artifact 4. AccessOverlay schema canonical home is Artifact 1 §A; write-time enforcement Artifact 3 §12; read-time enforcement here. ```typescript // AccessOverlay consumed at search retrieval (per // INV-M-ACCESS-RANK-1 §15.4: enforce BEFORE ranking). function compute_session_access_set( session: SessionProfile, scope: SearchScope ): AccessSet { // Step 1: Compute baseline corpus / filing-unit / segment / chunk // candidates from scope (per §12.2 SearchScope). const candidates = enumerate_in_scope_entities(scope); // Step 2: For each candidate, resolve overlays per // INV-B2-OVERLAY-RESOLUTION-1 (Artifact 3 §12.3 canonical; // read-time mirror here). const access_set: AccessSet = { permitted: [], excluded: [] }; for (const entity of candidates) { const overlays = resolve_overlays_for_entity(entity); if (overlays.length === 0) { access_set.permitted.push(entity); continue; } const winning = resolve_overlays_per_inv_b2(overlays, entity); if (winning.access_restriction === "blocked") { access_set.excluded.push({ entity, reason: "blocked", overlay_ref: winning.overlay_id }); continue; } if (winning.access_restriction === "preview_only") { access_set.permitted_preview_only.push(entity); // per §16.2 continue; } if (winning.access_restriction === "redacted_only") { // Substitute redacted artifact ref per RedactedAccessPolicy // (Artifact 3 §12.6). const redacted = substitute_redacted_artifact(entity, winning); access_set.permitted_redacted.push(redacted); continue; } if (winning.access_restriction === "not_shareable") { // Per §3.2: not_shareable means self-write/read OK; share-link // session blocks. if (session.session_kind === "share_link_session") { access_set.excluded.push({ entity, reason: "not_shareable_for_share_link_session", overlay_ref: winning.overlay_id }); continue; } // Host session: permitted. access_set.permitted.push(entity); continue; } if (winning.access_restriction === "explicit_access_required") { const has_grant = check_explicit_access_grant(session, entity); if (!has_grant) { access_set.excluded.push({ entity, reason: "explicit_access_required", overlay_ref: winning.overlay_id }); continue; } access_set.permitted.push(entity); continue; } // access_restriction === "none" (no restriction) access_set.permitted.push(entity); } // Step 3: Per V4-B2-2 (Artifact 3 §12.4): access_ceremony_required // overlays already rejected at construction time; should not appear here. // Defensive check: if (any_overlay_with_ceremony_required(candidates)) { log_warning("access_ceremony_required overlay encountered at " + "read time; should have been rejected at construction"); } return access_set; } type AccessSet = { permitted: Entity[]; // full access permitted_preview_only: Entity[]; // preview affordances only permitted_redacted: Entity[]; // redacted artifact only excluded: Array<{ entity: Entity; reason: string; overlay_ref: string; }>; }; ``` ### §16.2 access_restriction read-time affordance dispatch ```text Read-time affordance dispatch per AccessRestriction value: "none" → full read affordances "explicit_access_required" → blocked unless grant exists "preview_only" → preview-affordance-only (snippet-level metadata; no full content access) "redacted_only" → redacted artifact substituted per RedactedAccessPolicy (Artifact 3 §12.6) "not_shareable" → blocked for share-link sessions only "blocked" → completely blocked V4-B2-2 (Artifact 3 §12.4): access_ceremony_required REMOVED from V1.6 active enum; rejected at AccessOverlay construction time per b1_not_yet_supported. Read-time should not encounter this value. Per INV-M-ACCESS-RANK-1 (§15.4): all this filtering happens BEFORE ranking. Inaccessible items contribute ZERO ranking signal. ``` ### §16.3 Per-recipient state resolution (Artifact 5 §5.3 cross-reference) For share-link sessions, materialization state resolves via Artifact 5 §5.3 RecipientMaterializationResolution. Artifact 4 §16 handles AccessOverlay; Artifact 5 §5.3 handles MaterializationState; the two compose: ```typescript function resolve_share_link_search_result( result: SearchResult, session: SessionProfile, shared_view: SharedCorpusView ): ShareLinkSearchResult { // Step 1: AccessOverlay check (this section). const overlay_check = compute_session_access_set( session, { ...current_scope, filing_unit_scope: [result.filing_unit_id] } ); if (overlay_check.excluded.length > 0) { return null; // result excluded } // Step 2: MaterializationState check (Artifact 5 §5.3). const artifact = lookup_source_artifact(result.source_artifact_id); const recipient_resolution = resolve_materialization_for_recipient( artifact, session, shared_view ); if (recipient_resolution.recipient_state === "unavailable_blocked") { return null; } return { ...result, affordances: recipient_resolution.affordances, materialization_state: recipient_resolution.recipient_state, }; } ``` ### §16.4 INV-B2-CACHING-1 read-time cross-reference Per Artifact 3 §12.5 (canonical home): sealed/firewalled visibility class strictly bypasses Tier 2 prompt caching. Read-time consumer: when search retrieval pipeline routes through prompt-caching-bearing executors (e.g., LLM-driven query expansion fallback), the kernel ensures sealed/firewalled sources never hit Tier 2 cache (per Artifact 3 §12.5 enforcement at envelope V validation). OP-A rows: `OBL-D73-B2-SOURCEINSTANCE-01` (existing; covers). ### §16.5 Overlay cache invalidation (R0.2 NEW per AUDIT_DOC73_Artifact4_R0.1.md MED-A4-10) Per AUDIT_DOC73_Artifact4_R0.1.md MED-A4-10: read-time access overlay enforcement requires explicit cache invalidation rules to avoid stale overlay results in search. ```text Overlay cache invalidation rules (R0.2 NEW per MED-A4-10): Cache invalidation triggers: T-OV-1: policy_generation_advance (Artifact 3 §4.3.17): All session overlay caches invalidated at the moment the policy_generation_id increments. Next access_set computation refreshes from canonical AccessOverlay tables. T-OV-2: AccessOverlay creation/update/delete (Artifact 3 §12 envelope fires): Kernel emits overlay_changed event after envelope commits. Session-cache consumers subscribe and invalidate affected entries. Affected = any session whose access_set includes a target_kind granularity covered by the changed overlay. T-OV-3: Session profile state transition (this artifact §2.2): On any session_profile.profile_state transition (active → expired, active → revoked, active → suspended): overlay cache for that session purged immediately. T-OV-4: SharedCorpusView creation/update (this artifact §4): On SharedCorpusView changes affecting session: recipient session's overlay cache invalidated; next access_set computation refreshes. T-OV-5: Session profile policy_generation_id refresh: When a session profile's policy_generation_id is updated (during re-activation or policy refresh): overlay cache for that session invalidated. Cache implementation hints: - In-memory overlay cache per session, keyed by (session_profile_ref, scope_target_kind, scope_target_ref). - Invalidation via subscribe-publish to overlay_changed + policy_generation_advance + session_state_transition events. - Cache TTL fallback: 60s default per DOC24_OVERLAY_CACHE_TTL_SECONDS (configurable). - On cache miss OR after invalidation: recompute via compute_session_access_set per §16.1. OP-A row: implicit (covered by OBL-D73-B2-SOURCEINSTANCE-01 + DOC24-side runtime per V4-§0.4-1). ``` --- ## §17. Group K — Read path (binding outcome consumption) ### §17.1 Read-path scope clarification Group K canonical schemas (binding entity, BindingResourcePolicy, BindingEvaluationManifest, BindingGenerationSnapshot, BindingOutcomeRecord) are owned by Artifact 2 §K (semantics) + Artifact 3 §13-§15 (kernel runtime). Artifact 4 §17 specifies the **read path consumer surface** only: - BindingOutcomeRecord lookup at search time. - CorpusBindingContribution ledger reads for binding health UI. - extraction_run_id linkage between BindingOutcomeRecord and ExtractionAttempt for INV-EXT-7 field-level resolution. ### §17.2 BindingOutcomeRecord read API ```typescript function lookup_binding_outcome( binding_id: string, source_event_id: string ): BindingOutcomeRecord | undefined { // Read from binding_outcome_records table. // Schema canonical home: Artifact 2 §K + Artifact 3 §13.5. return db.read_binding_outcome(binding_id, source_event_id); } function lookup_binding_outcomes_by_target( target_kind: BindingTargetKind, target_ref: string ): BindingOutcomeRecord[] { // Reverse lookup: which binding fires produced this target? return db.list_binding_outcomes_by_target(target_kind, target_ref); } function lookup_binding_evaluation_manifest( source_event_id: string ): BindingEvaluationManifest | undefined { // Per INV-K-MANIFEST-DURABLE-1 (Artifact 3 §15.2): manifests are // durable; always available via lookup. return db.read_binding_evaluation_manifest(source_event_id); } ``` ### §17.3 CorpusBindingContribution ledger reads Per Artifact 2 §K K.15 + V3-K-10: ```text CorpusBindingContribution ledger records per-binding contribution to corpus membership: - Which membership records were created by which binding fires. - Which were soft-deleted (per V3-K-10 corpus eviction). - Which were rejected by user. - Which had extraction failures. Read-path consumer (binding health UI per V2 patch L5 INV-K-HEALTH-1): - "How many documents has this binding produced?" - "What's the user-engagement rate of binding-produced documents?" - "What's the soft-delete rate of binding-produced documents?" (signal that binding may need refinement) Implementation: function read_corpus_binding_contribution( binding_id: string, time_window?: { start: ISO8601; end: ISO8601 } ): CorpusBindingContribution[] { return db.list_contributions(binding_id, time_window); } function compute_binding_health_metrics( binding_id: string, window_days: number = 30 ): BindingHealthMetrics { const contributions = read_corpus_binding_contribution( binding_id, { start: NOW() - window_days * 86400 * 1000, end: NOW() } ); return { total_fires: contributions.length, confirmed_count: count_state(contributions, "confirmed"), rejected_count: count_state(contributions, "rejected"), soft_deleted_count: count_state(contributions, "soft_deleted"), extraction_failed_count: count_state(contributions, "extraction_failed"), user_engagement_rate: compute_engagement_rate(contributions), // Per V2 L5 INV-K-HEALTH-1: contribution_count alone is // insufficient; user_engagement_rate is the primary signal. }; } ``` OP-A rows: `OBL-EC-V16-BINDING-CONTRIBUTION-LEDGER-01` (kernel runtime per Artifact 3) + Artifact 4-side read entry points. ### §17.4 extraction_run_id linkage and INV-EXT-7 field-level resolution Per Artifact 5 §9.2 INV-EXT-7 + Artifact 3 §16: ```text Read-path consumer for INV-EXT-7 field-level resolution: A search query touching a FilingUnit that has stale memories AND a re-extraction in degraded state needs field-level resolution per Artifact 5 §9.2 FieldResolution. Read-path runtime (Artifact 4 §17.4): function resolve_field_at_read_time( field: string, document_id: string, session: SessionProfile ): FieldResolution { // Delegates to Artifact 5 §9.2 algorithm return artifact5.resolve_field_value(field, document_id); // Q Dashboard rendering rules (Artifact 5 §9.3 + Artifact 4 UI // layer) consume FieldResolution.framing for "stale" / "partial" / // etc. badges. } Stale + degraded interaction: Per Artifact 5 §9: search retrieval surfaces field-level resolution with explicit framing. Implicit fallback to stale data without disclosure is non-conformant. ``` OP-A row: implicit (covered by OBL-EXT-FSM-01 in Artifact 3 §16; Artifact 4 read-side consumer). --- ## §18. Session-orientation injection — DEFERRED TO DOC72 **[R0.4 PATCH per CSA extraction 2026-05-04: This section previously specified `CSAInjectionTierPolicy` (§18.1 reclassification framing; §18.2 schema with tier_strategy enum: tier_1_full_orientation / tier_2_targeted_orientation / tier_3_minimal_orientation / tier_4_disabled; §18.3 inject_csa_orientation() consumer contract; §18.4 INV-N-ORIENTATION-1 + INV-N-NO-CIRCULAR-EVIDENCE-1 read-time enforcement). The entire §18 has been DELETED per CSA extraction.]** V1.6 release wave does NOT include `CSAInjectionTierPolicy` or equivalent runtime session-orientation policy. DOC73 V1.6 specifies the `RecentActivityRollup` producer/consumer contract in Artifact 1 §16 (canonical home for Mechanism 4 schema + writer agent + INV-N invariants); consumer-side orchestration (when to inject `RecentActivityRollup` data into agent context at session start, tiering, session-runtime behavior) is DOC72's architectural concern and is deferred from V1.6 release wave. Until DOC72 ships session-orientation orchestration, DOC24's context assembly MAY include the most recent `RecentActivityRollup` of each cadence in agent context per its own logic. No tier policy, no `CSAInjectionTierPolicy`, no session-profile field for injection orchestration in V1.6. Tracked at `OBL-D73-RECENT-ACTIVITY-ROLLUP-CONSUMER-CONTRACT-01` (R0.4 NEW per CSA extraction 2026-05-04; canonical home Artifact 1 §16.6). **Architect preference preserved for future DOC72 design:** Per Q-3-A4-7 architect triage 2026-05-03 (BUILD_QUESTIONS §11.1 historical record), the architect indicated a preference for `tier_3_minimal_orientation` semantics — inject `RecentActivityRollup` data ONCE at session start, not per-query — as the right default for legal-litigation tools. This preference is recorded for whenever DOC72 designs session-orientation injection orchestration. INV-N-NOT-EVIDENCE-1 (renamed from INV-N-ORIENTATION-1 in Artifact 1 R0.5 per CSA extraction) + INV-N-NO-CIRCULAR-EVIDENCE-1 + INV-0B.1 receipt-wrapping discipline survive as canonical invariants on `RecentActivityRollup` (canonical home Artifact 1 §16.4); read-time consumer enforcement of these invariants is preserved at Artifact 4 read paths that touch `RecentActivityRollup` data (search router does NOT include rollup activity entries in SearchExecutionResult.results[]; ranking does NOT use rollup-cited refs as signal). Acceptance test V3-AT-22 (RecentActivityRollup cannot satisfy legal evidence queries per INV-N-NOT-EVIDENCE-1) survives as a search-router acceptance test independent of CSAInjectionTierPolicy deletion. --- ## §19. INV-MVC-1 + INV-MVC-2 read-time mirror This section explicitly mirrors the canonical INV-MVC-1 and INV-MVC-2 declarations from Artifact 1 §15.X. ### §19.1 INV-MVC-1 read-time mirror Per Artifact 1 §15.X (canonical home): "memories are pointers, not bare claims" — V1.6 INV-MVC-CU-1 (Artifact 3 §9 kernel runtime) requires source_spans on CU creation. Read-time mirror: search retrieval honors source_spans. CUs surface "Jump to Source" affordances per source_span (Q Dashboard renders; data contract here): ```typescript type CURenderingDataContract = { cu_id: string; cu_authority: number; // per Artifact 1 §9 + // INV-A-AUTHORITY-EAGER-1 source_spans: SourceSpan[]; // per Artifact 1 §8.2; // non-empty per // INV-MVC-CU-1 display_kind: // per Artifact 1 §8.2 | "synthesis_with_spans" | "synthesis_summary_no_spans"; visibility_class: VisibilityClass; // per Artifact 1 §11 // + INV-A-TAINT-INFECTIOUS-1 affordances: // per session-level | "jump_to_source_per_span" // resolution | "synthesis_summary_framing_only"; // for no-spans CUs schema_version: 1; }; ``` OP-A row: implicit (Q Dashboard render layer per DOC20/DOC7). ### §19.2 INV-MVC-2 read-time mirror Per Artifact 1 §15.X + V3-M-4: stale-memory gate consumes DocumentArtifactVersionChanged events. Read-time enforcement: search retrieval respects `stale_pending_source_changed` flag on CUs and other derived memories. ```typescript function filter_stale_memories_at_read( candidates: SearchResult[] ): SearchResult[] { return candidates.filter(result => { if (result.kind !== "derived_memory") return true; const memory = lookup_derived_memory(result.id); if (memory.stale_pending_source_changed) { // Per INV-MVC-2 + INV-EXT-7 (Artifact 5 §9): // - For derived_memory_primary or cross_source_synthesis posture: // stale memory NOT returned as current evidence. // - For metadata_primary or document_text_primary posture: // memory does not surface at all (it's derived; not source). return false; } return true; }); } ``` Per INV-EXT-7 (Artifact 5 §9): when stale memory exists AND re-extraction is in degraded state, field-level resolution surfaces partial data with explicit framing. OP-A row: `OBL-D25-D73-V16-STALE-01` (V3.7 base + V4-O-2 enrichment). --- ## §20. SearchReceiptRetentionPolicy + INV-M-RETENTION-1 ### §20.1 SearchReceiptRetentionPolicy schema (V3-M-13) Per V4 §2.1.9: ```typescript type SearchReceiptRetentionPolicy = { // V1.6 contract policy_id: string; default_retention_class: // per // INV-V16-RETENTION-EPHEMERAL-1 // / INV-V16-RETENTION-DURABLE-1 | "ephemeral_session_lifetime" // session_lifetime + N hours // grace | "durable_audit_1y" // audit retention 1y | "durable_audit_7y"; // legal work-product 7y // Per-kind retention overrides search_execution_manifest_class: ...; search_coverage_receipt_internal_class: ...; search_coverage_receipt_visible_class: ...; search_index_snapshot_class: ...; query_expansion_record_class: ...; unified_search_plan_class: ...; audit_replay_receipt_class: ...; // Upgrade rules (per V3-M-13 + V3-M-14) upgrade_to_durable_when: | "persisted_in_answer" // answer references it | "delivered_to_downstream_consumer" | "used_for_feedback" | "referenced_by_saved_search_or_standing_order" | "user_marked_audit_essential"; schema_version: 1; }; ``` ### §20.2 INV-M-RETENTION-1 Per V4 §2.1.9: ```text INV-M-RETENTION-1 (V3 NEW; canonical home Artifact 4 §20.2): SearchExecutionManifest, SearchCoverageReceipt, SearchIndexSnapshot, QueryExpansionRecord, and UnifiedSearchPlan records become durable kernel receipts only when persisted, cited in an answer, delivered to a downstream consumer, used for feedback, or referenced by a saved search/standing order. Otherwise they follow SearchReceiptRetentionPolicy. Default exploratory share-link search receipts are session-only. Upgrade pseudocode: function classify_search_receipt_retention( receipt: SearchReceipt, upgrade_signal: UpgradeSignal | null ): RetentionClass { if (upgrade_signal) { return "durable_audit_1y"; // upgraded to durable } return "ephemeral_session_lifetime"; // default } ``` V1.6 default `SearchReceiptRetentionPolicy`: ```typescript { default_retention_class: "ephemeral_session_lifetime", search_execution_manifest_class: "ephemeral_session_lifetime", search_coverage_receipt_internal_class: "ephemeral_session_lifetime", search_coverage_receipt_visible_class: "ephemeral_session_lifetime", search_index_snapshot_class: "durable_audit_1y", // index health is audit-essential query_expansion_record_class: "ephemeral_session_lifetime", unified_search_plan_class: "ephemeral_session_lifetime", audit_replay_receipt_class: "ephemeral_session_lifetime", // per // Artifact 3 §17.6 conditional // upgrade upgrade_to_durable_when: "persisted_in_answer" } ``` OP-A rows: `OBL-D24-RETENTION-V16-01` (V3.7 base + INV-M-RETENTION-1 enforcement). ### §20.3 Per V4-§0.7-2 ephemeral vs durable split Per Artifact 1 §19.3 + §19.4: V1.6 splits retention class into: - ephemeral (read-only search receipts; session_lifetime + N hours grace) — INV-V16-RETENTION-EPHEMERAL-1. - durable (state-changing receipts + audit-replay records; never downgraded) — INV-V16-RETENTION-DURABLE-1. SearchReceiptRetentionPolicy default for read-only search receipts is ephemeral; upgrade-to-durable rules apply per §20.2. OP-A row: `OBL-EC-STORAGE-REG-V16-01` (per V4 §0.7). --- ## §21. Worked Examples Appendix Per prompt: 4 worked examples required: 1. Multi-executor search plan dispatch (§21.1) 2. SharedCorpusView deny-wins resolution (§21.2) 3. Sub-agent context isolation (§21.3) 4. Share-token revocation downloaded-copies disposition (§21.4) ### §21.1 Worked Example 1 — Multi-executor search plan dispatch **[R0.2 NOTE per AUDIT_DOC73_Artifact4_R0.1.md HIGH-A4-4]** — Result counts (23 FTS5 hits, 8 argument-CUs, 14 span-grounded confirmations, fused = 18 unique filings) and scope_ref values (e.g., "PSLRA-FTS5-search") are ILLUSTRATIVE for the worked example; they are not canonical test data. Acceptance tests verify shape + behavior, not specific numerical values. ```text Setup: User session: host_session; brief bank corpus = "MTD Securities Litigation 9th Circuit"; identity = host_user. User query: "Find oppositions to MTDs that argue PSLRA falls short on scienter." Step 1: Router receives query (router.plan_search). Step 2: Phase 1 — Resolve query intent. Pattern resolver matches "find ... that argue ..." → query_intent = evidence_search. resolver_kind = "deterministic_pattern"; pattern_id = legal_argument_search; user_can_override = true. Step 3: Phase 2 — Resolve retrieval posture. Per §12.5 default rule "Find risk disclosure defendants cite": → document_text_primary + filing_content_scope: all_filing_parts + source_span_required: true. Step 4: Phase 3 — Resolve scope. SearchScope = { retrieval_posture: { posture: document_text_primary, filing_content_scope: all_filing_parts, source_span_required: true, required_surface_disclosure: true }, case_scope: undefined (broad search across cases), corpus_scope: ["MTD Securities Litigation 9th Circuit"], visibility_class_scope: ["public_open", "work_product_internal"] (host's permitted classes), temporal_scope: undefined } Step 5: Phase 4 — Resolve executor assignments. Query has citation ("PSLRA") + thematic component ("argue ... falls short on scienter") + needs span grounding. → multi-executor: [ { executor_class: doc18_legal_search_direct, scope_ref: "PSLRA-FTS5-search", weight: undefined, budget_tokens: 200, reason_code: "search.legal_citation_lookup" }, { executor_class: memory_agent, scope_ref: "argument-CU-search-scienter", weight: undefined, budget_tokens: 5000, reason_code: "search.derived_memory_argument_synthesis" }, { executor_class: document_intelligence_agent, scope_ref: "span-grounded-confirmation", weight: undefined, budget_tokens: 10000, reason_code: "search.span_grounded_confirmation_for_synthesis" } ] result_fusion_strategy: "rrf" Step 6: Phase 5 — Plan assembly. UnifiedSearchPlan { plan_id: PLAN-001, query_intent_resolution: { resolved_intent: "evidence_search", resolver_kind: "deterministic_pattern", pattern_id: legal_argument_search, user_can_override: true }, search_scope: { ... per Step 4 }, executor_assignments: [...3 entries per Step 5], result_fusion_strategy: "rrf", search_index_snapshots: [SS-FTS5-001, SS-VECTOR-001, SS-DOC-INDEX-001], query_expansions_planned: [ { expansion_kind: "citation_normalization", applied_terms: ["PSLRA", "Private Securities Litigation Reform Act"], expansion_visible_to_session: true } ], amendable_by_executor: false, plan_at: 2026-05-03T14:30:00Z, schema_version: 1 } Step 7: Plan validation (V-PLAN-1 through V-PLAN-7). All gates pass. V-PLAN-7: session profile valid (active state). Step 8: Execute (router.execute_search). - Dispatch executor 1 (doc18_legal_search_direct) with PSLRA query. Returns 23 FTS5 hits across 12 filings. - Dispatch executor 2 (memory_agent) with scienter argument query. Returns 8 argument-CUs across 6 filings. - Dispatch executor 3 (document_intelligence_agent) with span confirmation request. Returns 14 span-grounded confirmations across 9 filings. Step 9: Apply RRF fusion (per Artifact 1 §28A.2 RRF formula, k=60). Fused result list: 18 unique filings (some appear in multiple executor result sets), ranked by RRF score. Step 10: Apply INV-M-ACCESS-RANK-1 — ALREADY APPLIED in Steps 8 (each executor consumed access_set as input filter). Step 11: Apply INV-M-VERSION-AWARE-1 — for each FilingUnit appearing in multiple versions, select most authoritative version (amended > corrected > reissued > public_redacted > original_as_filed). Result: 18 → 16 unique FilingUnits (2 had version dedup). Step 12: Construct SearchExecutionManifest + SearchCoverageReceipts. SearchCoverageReceiptInternal: searched_corpora: ["MTD Securities Litigation 9th Circuit"] searched_count: 1247 (all corpus filings examined) excluded_count: 0 (no exclusions for host session) result_set_completeness: "exhaustive_for_scope" scope_digest: SHA-256 of scope inputs expansion_disclosure_provided: true SearchCoverageReceiptVisible: Same fields but no per-reason exclusion breakdown (regardless of session_kind; both receipts produced; host sees internal). Step 13: Q Dashboard rendering (out of scope here; data contract delivered). Each result accompanied by: - Source span citations (per source_span_required=true) - Version_selection_disclosure (where applicable per INV-M-VERSION-AWARE-1) - Surface disclosure ("matched in: brief / opposition / etc.") Audit trail: - UnifiedSearchPlan PLAN-001: persisted as kernel receipt. - SearchExecutionManifest: emitted; ephemeral by default per INV-V16-RETENTION-EPHEMERAL-1. - SearchCoverageReceiptInternal + Visible: emitted; ephemeral. - QueryExpansionRecords: emitted; ephemeral. - When user cites a result in an answer or saved search: upgrade to durable per INV-M-RETENTION-1 §20.2. ``` ### §21.2 Worked Example 2 — SharedCorpusView deny-wins resolution ```text Setup: Host has 3 SharedCorpusViews active for share-link recipient (recipient is co-counsel reviewing brief bank): View V1: corpus_ref: "MTD Securities Litigation 9th Circuit" exposed_surfaces: [source_documents, filing_metadata, court_rulings] derived_memory_share_policy: "include_with_provenance" host_annotation_policy: "include_marked_shareable" visibility_class_ceiling: "public_open" view_temporal_mode: "snapshot_at_share" View V2: corpus_ref: "MTD Securities Litigation 9th Circuit" exposed_surfaces: [source_documents, filing_metadata] derived_memory_share_policy: "exclude_all" host_annotation_policy: "exclude_all" visibility_class_ceiling: "public_open" view_temporal_mode: "snapshot_at_share_with_drift_disclosure" View V3: corpus_ref: "MTD Securities Litigation 9th Circuit" exposed_surfaces: [source_documents, filing_metadata, filing_relationships, court_rulings, court_disposition_observations] derived_memory_share_policy: "include_only_user_marked_shareable" host_annotation_policy: "include_marked_shareable" visibility_class_ceiling: "work_product_internal" view_temporal_mode: "live_view" Step 1: Recipient session activates; resolves EffectiveSharedCorpusView per INV-I-SHARE-VIEW-2. Step 2: Apply intersection of exposed_surfaces: V1: [source_documents, filing_metadata, court_rulings] V2: [source_documents, filing_metadata] V3: [source_documents, filing_metadata, filing_relationships, court_rulings, court_disposition_observations] Intersection: [source_documents, filing_metadata] Step 3: Apply most-restrictive derived_memory_share_policy: V1: include_with_provenance V2: exclude_all ← most restrictive V3: include_only_user_marked_shareable Effective: exclude_all Step 4: Apply most-restrictive host_annotation_policy: V1: include_marked_shareable V2: exclude_all ← most restrictive V3: include_marked_shareable Effective: exclude_all Step 5: Apply most-restrictive visibility_class_ceiling: V1: public_open V2: public_open V3: work_product_internal Lattice ordering: public_open < work_product_internal. Most restrictive (lowest in lattice): public_open Effective: public_open Step 6: Apply most-restrictive view_temporal_mode: V1: snapshot_at_share ← most restrictive V2: snapshot_at_share_with_drift_disclosure V3: live_view Effective: snapshot_at_share Step 7: EffectiveSharedCorpusView for recipient session: effective: true corpus_ref: "MTD Securities Litigation 9th Circuit" exposed_surfaces: [source_documents, filing_metadata] derived_memory_share_policy: exclude_all host_annotation_policy: exclude_all visibility_class_ceiling: public_open view_temporal_mode: snapshot_at_share Step 8: Recipient queries are filtered through EffectiveSharedCorpusView. - Source documents: visible. - Filing metadata: visible. - Court rulings: NOT in exposed_surfaces → not visible. - Filing relationships: NOT in exposed_surfaces → not visible. - Derived memories (CUs): excluded. - Host annotations: excluded. Step 9: Q Dashboard (recipient view) renders: - Source documents (visible). - Filing metadata (visible). - Banner: "Host annotations and analysis are not included in this share." - View_temporal_mode banner: "You're viewing a snapshot of this corpus as of ." Audit trail: - EffectiveSharedCorpusView resolution emitted as session manifest receipt; ephemeral. - Per INV-I-SHARE-VIEW-1: framing visible to recipient that share is curated; no silent exclusion. ``` ### §21.3 Worked Example 3 — Sub-agent context isolation ```text Setup: Host session: host_session; user is securities litigator. Host invokes "search for MTD oppositions" capability — this triggers document_intelligence_agent sub-agent for span-grounded retrieval. Host's NativeSessionScopeBinding NSB-host: binding_kind: host_session fork_forbidden: false max_spawn_depth: 3 max_children_per_agent: 5 context_inheritance_policy: "full_inherit" auth_inheritance_policy: "inherit_with_session_token" transcript_visibility_policy: "shared" child_spawn_constraint: "inherit_parent_constraint" Host's session profile: visibility_class_ceiling: undefined (host has all classes) capability_policy: deny_all_except [search.*, retrieval.*, document_view.*, ...] Step 1: Host invokes "search for MTD oppositions" via search router. Step 2: Search router (per §10.X) determines RetrievalPosture = cross_source_synthesis with executor_assignments including document_intelligence_agent. Step 3: EC dispatches document_intelligence_agent. EC creates new NativeSessionScopeBinding NSB-subagent: Per §6.2 INV-I-NATIVE-SESSION-1 + V4-I-3 expanded: Validate spawn (validate_subagent_spawn(NSB-host, subagent_session)): NSB-host.fork_forbidden = false → OK. NSB-host.max_spawn_depth (3) > 0 → OK. NSB-host.children_count (0) < 5 → OK. NSB-host.child_spawn_constraint = "inherit_parent_constraint" → recursive check up parent chain (host has no parent) → no further constraint. NSB-subagent constructed: binding_kind: subagent_session inherited_capability_policy_ref: inherited_visibility_constraints: [host's classes] fork_forbidden: false (inherited from host) max_spawn_depth: 2 (host's 3 - 1) max_children_per_agent: 5 context_inheritance_policy: "full_inherit" (per host) auth_inheritance_policy: "inherit_with_session_token" (per host) transcript_visibility_policy: "shared" (host sees sub-agent log) child_spawn_constraint: "inherit_parent_constraint" Step 4: Sub-agent operates within constraints: - Has full host context (full_inherit). - Uses session token for tool auth. - Transcript visible to host. Step 5: Sub-agent attempts to spawn sub-sub-agent (e.g., needs OCR-specialist sub-agent for scanned PDF). Validate (validate_subagent_spawn(NSB-subagent, subagent_session)): NSB-subagent.max_spawn_depth (2) > 0 → OK. NSB-subagent.child_spawn_constraint = "inherit_parent_constraint" → check up to NSB-host: also "inherit_parent_constraint"; root (host) has no further constraint. Approved. NSB-subsubagent constructed: max_spawn_depth: 1 (subagent's 2 - 1) other fields inherited. Step 6: Sub-sub-agent operates within its constraints. If it tries to spawn another level (sub-sub-sub-agent): validate_subagent_spawn(NSB-subsubagent, ...): max_spawn_depth (1) > 0 → OK; spawn allowed. But that fourth-level sub-agent would have max_spawn_depth = 0; beyond which spawns rejected per "native_session_max_spawn_depth_exceeded". Step 7: Compare to share-link session (different scenario): Share-link session profile + NSB-share: binding_kind: share_link_session fork_forbidden: TRUE (V1.6 default for share-link per §6.2) max_spawn_depth: 0 max_children_per_agent: 0 context_inheritance_policy: "no_inherit" auth_inheritance_policy: "session_only" transcript_visibility_policy: "isolated" child_spawn_constraint: "deny_all" Share-link session attempts to spawn sub-agent: validate_subagent_spawn(NSB-share, ...): NSB-share.fork_forbidden = TRUE → reject "native_session_fork_forbidden" reason code. Share-link recipient cannot fork sub-agents; cannot escalate capability via sub-agent boundary; transcript stays isolated. Audit trail: - NSB-host, NSB-subagent, NSB-subsubagent: durable per INV-V16-RETENTION-DURABLE-1 (state-changing native session bindings). - validate_subagent_spawn outcomes (especially rejections): durable audit trail. - Share-link recipient denied sub-agent spawn: emit `session_denial_message` with reason_code per §7.3 + `default_recipient_visibility = "generic_only"` per V4-I-DENIAL-1. ``` ### §21.4 Worked Example 4 — Share-token revocation downloaded-copies disposition ```text Setup: Host shared brief bank with co-counsel via share-link STK-001: ShareTokenPolicy STK-001: shared_view_ids: [V1] (per §21.2 example) allowed_actions: [search.*, document_view.*, document_download.*] recipient_identity_mode: email_bound (recipient: cocounsel@firm.com) watermark_downloads: true audit_visibility: both Recipient has been using the share-link for 2 weeks; has downloaded 47 PDF artifacts. Currently has 1 active session via STK-001. Host discovers PDF #34 contained inadvertently sealed material that should not have been shared. Host invokes share_link_revoke per Artifact 3 §4.3.10 + §5.2 ShareTokenRevocation. Step 1: Host constructs ShareTokenRevocation request: share_token_id: STK-001 revoke_reason: "inadvertently_shared_sealed_material" active_session_disposition: "terminate_immediately" active_session_grace_period_seconds: undefined (immediate) downloaded_copies_disposition: "best_effort_recall_request" cached_response_disposition: "session_local_invalidate" Step 2: revoke_share_token(STK-001, params): Step 2a: lookup ShareTokenPolicy STK-001: Verify not already revoked → proceed. Step 2b: persist revocation: Create ShareTokenRevocation entity (per Artifact 4 §5.2). Update STK-001.revoked_at = NOW(). Update STK-001.revoke_reason = "inadvertently_shared_sealed_material". Step 3: Handle active sessions per active_session_disposition. Lookup active sessions by share_token: 1 session found (recipient cocounsel's current session). Per "terminate_immediately": session.transition_state(session.ref, "revoked", "share_token_revoked"). Recipient's active session terminated immediately. Step 4: Handle cached responses per cached_response_disposition. Per "session_local_invalidate": invalidate_session_local_cache_for_share_token(STK-001). Any cached search results / context packets associated with STK-001 invalidated. Step 5: Handle downloaded copies per downloaded_copies_disposition. Per "best_effort_recall_request": Step 5a: emit_recall_request_to_recipient(STK-001). Email sent to cocounsel@firm.com: Subject: "Share-link revoked: please delete downloaded files" Body: "Per host instruction, please delete the 47 PDF artifacts you downloaded from share-link STK-001. Reason: . Note: we cannot retrieve files from your local storage; this is a request, not a recall." Step 5b: invalidate_watermark_validity(STK-001). Watermarks on the 47 downloaded PDFs are marked invalid in host's watermark validity registry. Future audit tools using watermark verification will flag these PDFs as "from a revoked share-link." Step 6: Emit kernel envelope per Artifact 3 §4.3.10: semantic_intent: "share_link_revoke" primitive_effects: [share_link_revoke] Reversibility: compensating_operation_only. target_refs: [STK-001] Submit to kernel via Artifact 3 §2.X. Step 7: User-facing surfaces: Host sees: "Share-link STK-001 revoked. 1 active session terminated. Recall request sent to cocounsel@firm.com for 47 downloaded files. Cached responses invalidated. Note: we cannot retrieve files from recipient's local storage; downloaded copies persist until recipient deletes them." Cocounsel (recipient) sees: Active session abruptly terminated. Receives recall email per Step 5a. Audit trail: - ShareTokenRevocation entity: durable per INV-V16-RETENTION-DURABLE-1 (audit-essential; revocation events are forensic). - Kernel envelope (share_link_revoke): durable per INV-V16-RETENTION-DURABLE-1. - Watermark validity registry update: durable. - Recall email send: durable (notification audit log). Per Artifact 3 §4.3.10: share_link_revoke reversibility = compensating_operation_only. Inverse: share_link_grant is a NEW operation (re-grant a NEW token; not reversal of revocation). Per V4-I-5: revocation is itself terminal. Acceptance test: V4-AT-34. ``` --- ## §22. Landing Matrix entries authored by Artifact 4 ```text Group I (Session profile + share-link): Row A4.1 SessionProfile schema + lifecycle (§2) Row A4.2 SessionKind / identity_mode / capability_policy (§3) Row A4.3 SharedCorpusView (V4-I-2 + V4-I-4) (§4) Row A4.4 INV-I-SHARE-VIEW-1 (§4.2) Row A4.5 INV-I-SHARE-VIEW-2 deny-wins (V4-I-1) (§4.3) Row A4.6 ShareTokenPolicy + ShareTokenRevocation (V4-I-5) (§5) Row A4.7 NativeSessionScopeBinding (V4-I-3) (§6) Row A4.8 INV-I-NATIVE-SESSION-1 (§6.2) Row A4.9 UtilitySignalPolicy (V4-I-6) (§7.1) Row A4.10 DOC1GovernanceSplit + INV-DOC1-GOV-1 (V4-§4.5-DOC1) (§7.2) Row A4.11 SessionDenialMessage (V4-I-DENIAL-1) (§7.3) Row A4.12 ExternalUploadFileSafetyControls + INV-I-UPLOAD-1 (V4-I-3.4.6) (§7.5) DOC24 capability registry: Row A4.13 Capability registry runtime (V4-§0.4-1) (§8) Row A4.14 CapabilityNamespaceEntry registry (§8.2) Row A4.15 INV-I-CAP-1 (V4-I-2 namespace registry refined) (§3.2 + §8.3) Row A4.16 EC capability execution gating split (§8.4) Reason code registry: Row A4.17 Reason code registry consumer surface (§9) Row A4.18 Per-reason-code visibility (V4-I-DENIAL-1) (§9 + §7.3) Group M search router: Row A4.19 Unified Search Router runtime (§10) Row A4.20 UnifiedSearchPlan + ExecutorAssignment (V4-M-5) (§11) Row A4.21 ExecutorClass enum + executor dispatch defaults (§11.4) Row A4.22 Result fusion (rrf / weighted_sum / executor_priority) (§10.3) Row A4.23 RetrievalPosture rename (V4-M-1) (§12.1) Row A4.24 SearchScope + temporal_scope (V4-M-SCOPE) (§12.2) Row A4.25 SearchExecutionManifest (§13.1) Row A4.26 SearchCoverageReceipt internal/visible (V4-M-2) (§13.2) Row A4.27 INV-M-COVERAGE-VISIBILITY-1 (§13.3) Row A4.28 scope_digest (V4-M-8) (§13.4) Row A4.29 ranked_top_k_not_exhaustive (V4-M-6) (§13.5) Row A4.30 QueryExpansion access-filtered (V4-M-3) + INV-M-EXPANSION-ACCESS-1 (§14) Row A4.31 SearchPlanFailure narrowed (V4-M-4) (§15.1) Row A4.32 INV-M-NEGATIVE-1 (§15.2) Row A4.33 INV-M-COVERAGE-INDEX-1 (§15.3) Row A4.34 INV-M-ACCESS-RANK-1 (§15.4) Row A4.35 INV-M-VERSION-AWARE-1 (V4-M-7) (§15.5) Row A4.36 INV-M-SESSION-1 (V4-M-INV-SESSION) (§15.6) Row A4.37 QueryIntentResolution + INV-M-INTENT-1 (§15.7) Group B2 read-time: Row A4.38 Read-time AccessOverlay enforcement (§16) Row A4.39 Per-recipient state resolution (cross-Artifact 5) (§16.3) Group K read path: Row A4.40 BindingOutcomeRecord read API (§17.2) Row A4.41 CorpusBindingContribution ledger reads + binding health metrics (§17.3) Row A4.42 extraction_run_id / INV-EXT-7 read-time (§17.4) [R0.4 PATCH per CSA extraction 2026-05-04: Rows A4.43, A4.44, A4.45 REMOVED. Previously tracked CSAInjectionTierPolicy schema + INV-N-ORIENTATION-1 read-time mirror + INV-N-NO-CIRCULAR-EVIDENCE-1 read-time mirror at §18. CSAInjectionTierPolicy DELETED in R0.4 §18; INV-N-ORIENTATION-1 renamed to INV-N-NOT-EVIDENCE-1 in Artifact 1 R0.5 (canonical home Artifact 1 §16.4 — read-time consumer enforcement at search router preserves the invariants without a dedicated §18.4 mirror). Consumer-side session-orientation orchestration deferred to DOC72.] Cross-cutting: Row A4.46 INV-MVC-1 + INV-MVC-2 read-time mirrors (§19) Row A4.47 SearchReceiptRetentionPolicy + INV-M-RETENTION-1 (§20) Row A4.48 SearchIndexSnapshot (§14.3) Total Artifact 4 Landing Matrix entries: 45 (R0.4: 3 entries removed per CSA extraction; was 48 in R0.3). ``` --- ## Drafting Summary This section is required by the standing build process. ### Sections produced in R0.1 ```text §0 About this artifact (framing, scope, gating contract) §1 Runtime overview (DOC24 + EC split, position, consumed schemas, entry points) §2 Group I — SessionProfile schema + state machine §3 Group I — SessionKind + identity_mode + capability_policy + INV-I-CAP-1 (V4-I-2) §4 Group I — SharedCorpusView (V4-I-2 + V4-I-4) + INV-I-SHARE-VIEW-1 + INV-I-SHARE-VIEW-2 (V4-I-1 deny-wins) §5 Group I — ShareTokenPolicy + ShareTokenRevocation (V4-I-5) + active_session_disposition + downloaded_copies_disposition + cached_response_disposition §6 Group I — NativeSessionScopeBinding (V4-I-3 expanded: context_inheritance_policy + auth_inheritance_policy + transcript_visibility_policy + watermark_policy + child_spawn_constraint) + INV-I-NATIVE-SESSION-1 §7 Group I — UtilitySignalPolicy (V4-I-6) + DOC1GovernanceSplit (V4-§4.5-DOC1) + INV-DOC1-GOV-1 + SessionDenialMessage (V4-I-DENIAL-1) + ExternalUploadFileSafetyControls (V4-I-3.4.6) + INV-I-UPLOAD-1 §8 DOC24 capability registry (V4-§0.4-1 ownership) + namespace registry + atomic registration + EC execution gating split §9 Reason code registry consumer surface §10 Group M — Unified Search Router runtime + multi-executor fusion strategies §11 Group M — UnifiedSearchPlan (V4-M-5 multi-executor) + ExecutorAssignment + ExecutorClass + executor dispatch defaults §12 Group M — RetrievalPosture (V4-M-1 renamed) + SearchScope (V4-M-SCOPE temporal_scope) + filing_content_scope + INV-V16-TIMEZONE-1 read-time integration §13 Group M — SearchExecutionManifest + SearchCoverageReceipt internal/visible split (V4-M-2) + INV-M-COVERAGE-VISIBILITY-1 + scope_digest (V4-M-8) + ranked_top_k_not_exhaustive (V4-M-6) §14 Group M — QueryExpansion access-filtered (V4-M-3) + INV-M-EXPANSION-ACCESS-1 + SearchIndexSnapshot §15 Group M — SearchPlanFailure narrowed (V4-M-4) + INV-M-NEGATIVE-1 + INV-M-COVERAGE-INDEX-1 + INV-M-VERSION-AWARE-1 (V4-M-7) + INV-M-SESSION-1 (V4-M-INV-SESSION) + QueryIntentResolution + INV-M-INTENT-1 + INV-M-ACCESS-RANK-1 §16 Group B2 — Read-time access overlay enforcement (mirror of Artifact 3 §12) §17 Group K — Read path (BindingOutcomeRecord + CorpusBindingContribution ledger + extraction_run_id linkage + INV-EXT-7 field-level resolution consumer surface) §18 Session-orientation injection — DEFERRED TO DOC72 [R0.4 PATCH per CSA extraction 2026-05-04: previously CSAInjectionTierPolicy + tier_strategy + INV-N-ORIENTATION-1 read-time mirror; DELETED in R0.4] §19 INV-MVC-1 + INV-MVC-2 read-time mirrors §20 SearchReceiptRetentionPolicy + INV-M-RETENTION-1 (ephemeral vs durable per V4-§0.7-2) §21 Worked Examples (4): multi-executor search dispatch + SharedCorpusView deny-wins resolution + sub-agent context isolation + share-token revocation downloaded-copies §22 Landing Matrix entries authored by Artifact 4 (48 entries) ``` ### Drafting notes (`[V1.6 DRAFTING NOTE]` markers) ```text 1. §2.6 — Dedicated SessionProfile OP-A rows may need explicit registration in OPA V3.8.1 (Q-3-A4-SESSION-PROFILE-OP-A). 2. §8.3 — Capability namespace hierarchy depth max not enforced in V1.6 (Q-3-A4-CAPABILITY-NAMESPACE-DEPTH). 3. §9.3 — Full per-reason-code visibility table not inlined; V1.6 release wave handoff includes registry as separate deliverable. ``` ### Items surfaced during drafting that need adjudicator review ```text Q-3-A4-1 — SessionProfile OP-A row coverage Where: §2.6. Question: Should V3.8.1 add dedicated OBL-D24-SESSION-PROFILE-V16-01 and OBL-EC-SESSION-LIFECYCLE-V16-01 rows? Currently covered implicitly via Group I schema rows. Proposed: ADD the two rows to V3.8.1 for explicit traceability. Q-3-A4-2 — Capability namespace hierarchy depth cap Where: §8.3. Question: Should V1.6 enforce max depth on parent_namespace chain? Proposed: V1.6 ships without depth cap; V1.7+ adds if needed. Q-3-A4-3 — Per-reason-code visibility table location Where: §9.3. Question: V1.6 release wave includes registry as separate deliverable (per V4 §0.7.2). Should Artifact 4 inline the V1.6 initial registry for completeness? Proposed: Defer to release-wave handoff; cross-reference §0.7.2 registry from each artifact that emits reason codes. Q-3-A4-4 — Top-k default per posture Where: §13.5. Question: Default top-k = 50 for most postures; 100 for metadata_primary and cross_source_synthesis. Is this tuned to V1.6 user research or guess? Proposed: V1.6 ships these defaults; production tuning in V1.6.1 based on telemetry. Q-3-A4-5 — Result fusion strategy registry Where: §10.3. Question: V4-M-5 specifies 3 fusion strategies (rrf, weighted_sum, executor_priority). Are there others V1.6 should ship? Proposed: 3 is sufficient for V1.6; V1.7+ extensions per production need. Q-3-A4-6 — INV-M-INTENT-1 disclosure threshold Where: §15.7. Question: INTENT_DISCLOSURE_CONFIDENCE_THRESHOLD = 0.95 default; below this, model-assisted classification surfaces with user-override. Is 0.95 right? Proposed: V1.6 ships 0.95; production tuning in V1.6.1. Q-3-A4-7 — CSAInjectionTierPolicy default tier [R0.4 PATCH per CSA extraction 2026-05-04: MOOT — CSAInjectionTierPolicy REMOVED from V1.6 (§18 DELETED). Architect preference for tier_3_minimal_orientation preserved in BUILD_QUESTIONS §11.1 historical record for future DOC72 session-orientation design. Question text preserved here as historical record.] Where: §18.2. Question: V1.6 default tier_strategy unspecified. Should default be tier_2_targeted_orientation (conservative) or tier_1_full_orientation (more aggressive)? Proposed: tier_2_targeted_orientation as V1.6 default; tier_1_full_orientation as host opt-in. Q-3-A4-8 — Share-link recipient bandwidth limit Where: §5.1 ShareTokenRateLimits. Question: V1.6 ships max_recipient_sessions_concurrent without specifying default. Production guideline? Proposed: V1.6 default 1 (single concurrent session per token); host can configure higher. ``` ### V4 PATCH coverage in Artifact 4 R0.1 ```text Group I patches addressed: V3-I-1 STRIPPED (DOC75 dormant networking) ✓ §2.1 (REMOVED note) V3-I-2 SharedCorpusView ✓ §4 V3-I-3 CapabilityPattern wildcard ✓ §3.1 V3-I-4 NativeSessionScopeBinding ✓ §6 V3-I-5 SessionDenialMessage non-leakage ✓ §7.3 V3-I-6 External upload file safety ✓ §7.4-§7.5 V3-I-7 CapabilityPolicy named fields ✓ §3.1 V4-I-1 INV-I-SHARE-VIEW-2 deny-wins ✓ §4.3 V4-I-2 CapabilityPattern namespace registry ✓ §3.2 + §8.3 V4-I-2 SharedCorpusView document_scope ✓ §4.1 V4-I-3 NativeSessionScopeBinding expansion ✓ §6.1 V4-I-3.4.6 hash_reputation_check stripped ✓ §7.4 (V1.7 deferred) V4-I-4 view_temporal_mode + visibility_class_ceiling ✓ §4.1 V4-I-5 ShareTokenRevocation ✓ §5.2 V4-I-6 UtilitySignalPolicy share-link defaults ✓ §7.1 V4-I-DENIAL-1 per-reason-code visibility ✓ §7.3 + §9 V4-§4.5-DOC1 DOC1GovernanceSplit + INV-DOC1-GOV-1 ✓ §7.2 Group M patches addressed: V3-M-1 RetrievalPosture consolidation ✓ §12.1 V3-M-2 document_required → SearchPlanFailure ✓ §15.1 V3-M-3 Default rule fix (synthesis ≠ memory_primary) ✓ §12.4 V3-M-4 Stale-memory gate events ✓ §12.5 + §19.2 V3-M-5 Owner split refined ✓ §1.1 V3-M-6 SearchCoverageReceipt expansion ✓ §13.2 V3-M-7 INV-M-NEGATIVE-1 ✓ §15.2 V3-M-8 QueryIntentResolution ✓ §15.7 V3-M-9 Search Router executor classes ✓ §11 V3-M-10 INV-M-ACCESS-RANK-1 ✓ §15.4 V3-M-12 INV-M-COVERAGE-INDEX-1 ✓ §15.3 V3-M-13 INV-M-RETENTION-1 ✓ §20 V3-M-14 Search receipts as kernel receipts ✓ §20 V4-M-1 RetrievalPosture rename ✓ §12.1 V4-M-2 SearchCoverageReceipt internal vs visible ✓ §13.2 + §13.3 V4-M-3 QueryExpansion access-filtered ✓ §14.2 V4-M-4 SearchPlanFailure narrowed ✓ §15.1 V4-M-5 Multi-executor ✓ §11.1 + §10.3 V4-M-6 ranked_top_k_not_exhaustive ✓ §13.5 V4-M-7 INV-M-VERSION-AWARE-1 ✓ §15.5 V4-M-8 scope_digest ✓ §13.4 V4-M-INV-SESSION INV-M-SESSION-1 ✓ §15.6 V4-M-SCOPE SearchScope + temporal_scope ✓ §12.2 Group B2 patches addressed: V3-B2-1 AccessOverlayTarget below document level ✓ §16 (read-time) V3-B2-2 access_restriction enum ✓ §16.2 V3-B2-3 Sealed-mode default local-only ✓ §16.4 (cross-reference) V3-B2-4 redacted_only artifact pointer ✓ §16.1 V4-B2-1 INV-B2-OVERLAY-RESOLUTION-1 ✓ §16 (read-time mirror) V4-B2-2 access_ceremony_required removed ✓ §16.1 (defensive check) Group K read path: V4-K-* binding evaluation consumed (§17; kernel runtime Artifact 3) V4-K-MANIFEST-DURABLE consumed (§17.2) V4-K-PARTIAL consumed (§17.2) Mechanism 4 (consumer-side orchestration deferred to DOC72 per R0.4 CSA extraction): [R0.4 PATCH per CSA extraction 2026-05-04: previous coverage list showed V4-§0.4-2 CSAInjectionTierPolicy reclassified (✓ §18) + V4-N-1 producer/consumer split (consumed §18.3) + V4-N-2 per- artifact gating (consumed §18) + V3-N-4 tier control schema enum (✓ §18.2). All CSA-specific consumption REMOVED with §18 deletion. V4-N-1 producer/consumer split + V4-N-2 per-artifact gating semantics carry forward as RecentActivityRollup consumer contract per OBL-D73-RECENT-ACTIVITY-ROLLUP-CONSUMER-CONTRACT-01 (canonical home Artifact 1 §16.6).] Cross-cutting V16: INV-V16-TIMEZONE-1 ✓ §12.3 INV-V16-NO-LOCAL-SCHEMA-1 followed throughout INV-V16-RETENTION-EPHEMERAL-1 ✓ §20 INV-V16-RETENTION-DURABLE-1 ✓ §20 INV-V16-STORAGE-GRANULARITY-1 ✓ §20 ``` ### Landing Matrix entries authored ```text Group I: 12 entries (Row A4.1 through A4.12) DOC24 capability registry: 4 entries (Row A4.13-A4.16) Reason code registry: 2 entries (Row A4.17-A4.18) Group M: 19 entries (Row A4.19-A4.37) Group B2 read-time: 2 entries (Row A4.38-A4.39) Group K read path: 3 entries (Row A4.40-A4.42) [CSAInjectionTierPolicy: REMOVED in R0.4 per CSA extraction; previously 3 entries Row A4.43-A4.45] Cross-cutting: 3 entries (Row A4.46-A4.48) Total Artifact 4 Landing Matrix entries: 45 (R0.4; was 48 in R0.3) ``` ### Cross-references to other artifacts ```text Artifact 1 (Core) consumed by Artifact 4: §2.1.A — SimulationSupportLevel + per-operation-kind table (R0.3 NEW; consumed at §11 for executor eligibility) [§A.4 — (reserved per Artifact 1 R0.5 CSA extraction; OrientationContextEntry removed; previously consumed at §18 — §18 also REMOVED in R0.4)] §A.5 — activity entry types (WorkPhaseEntry / CorpusActivityEntry / CaseActivityEntry / ArtifactEntry / UnresolvedThreadEntry) consumed by search router for query context (per INV-N-NOT-EVIDENCE-1 + INV-N-NO-CIRCULAR-EVIDENCE-1) §A.6 — QueryIntent enum (consumed at §15.7) §A.7 — CapabilityRef / EdgeTypeRef (consumed at §8) §A.9 — ContentHashRef (cross-doc; consumed at §13) §A.11 — RecordedModelOutput (consumed at §15.7 model-assisted classification audit trail) §13.1 — VisibilityClass lattice (consumed at §4 visibility_class_ceiling) §15.X.7.A — Two-layer prompt-injection model (consumed at §12.6) §16 — Mechanism 4 RecentActivityRollup canonical [R0.4 PATCH per CSA extraction 2026-05-04: previously "consumed at §18"; §18 DELETED; consumer-side orchestration deferred to DOC72] §17.1 — PBEOperationEnvelope (consumed via Artifact 3 §1.4) §19 — V16 cross-cutting INVs Artifact 2 (Legal & Corpus Surfaces) referenced by Artifact 4: §J — TopicVisibilityPolicy + StructuredExtractionStrategy (forecast) §K — Binding entity schemas (BindingOutcomeRecord + ledger; consumed at §17 read path) §O — FilingUnit + FilingUnitVersion + FilingUnitTextVersion (forecast; consumed at §15.5 INV-M-VERSION-AWARE-1) §O — RulingDisposition + CourtDispositionObservation (forecast) Artifact 3 (EC + DOC73 Transaction Kernel) referenced by Artifact 4: §1.4 — Kernel runtime entry points (kernel.read_envelope etc.) §3.3 — SemanticVerb taxonomy §4 — KernelEffect runtime per effect_kind §6 — Audit replay (AuditReplayReceipt schema) §7 — INV-A-TAINT-INFECTIOUS-1 lattice (consumed at §16) §10 — INV-MVC-3 (consumed at §12.6) §12 — Group B2 write-time (mirror at §16) §15 — BindingEvaluationManifest (consumed at §17.2) Artifact 5 (DOC25 Legal Artifact & Materialization) referenced by Artifact 4: §2.2 — SourceArtifact schema (consumed at §16.3 + §17) §3 — ArtifactSegment (consumed at §16.3) §4 — ECF header parser output (consumed at §15 FilingUnit metadata) §5 — MaterializationState V4-O-7 + tri-state delivery (consumed at §16.3 + §21.4) §5.3 — RecipientMaterializationResolution (consumed at §16.3) §9 — INV-EXT-7 + FieldResolution (consumed at §17.4) §13 — DocumentArtifactVersionChangedEvent (consumed at §19.2) ``` ### Drafting metrics ```text Total lines (R0.1): ~5,800 lines (target 4,000-6,000; within range) Sections produced: 22 substantive sections + Drafting Summary Worked examples: 4 (multi-executor search, SharedCorpusView deny-wins, sub-agent context isolation, share-token revocation) [V1.6 DRAFTING NOTE] markers: 3 Tier B questions raised (Q-3-A4-*): 8 V4 patches addressed: ~46 distinct V4 patches (Group I + Group M + Group B2 + cross-cutting) Landing Matrix entries authored: 48 Cross-artifact references: 4 (Artifacts 1, 2, 3, 5) DOC25 V2.0 sections referenced: ~15 (consumed via Artifact 5) ``` ### Status Artifact 4 R0.1 is COMPLETE for Step 5 output. Step 6 audit follows; Step 9 cross-artifact audit will reconcile [V1.6 DRAFTING NOTE] markers + Q-3-A4-* questions across the full V1.6 release wave. **End of DOC73 V1.6 Artifact 4 R0.1.**