DOC73_Artifact4_R0.4.md
Current Specs/DOC73/DOC73_Artifact4_R0.4.md
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<SessionProfileState, SessionProfileState[]> = {
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<string, ReasonCodeRegistryEntry>; // 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 <reason>") 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 <share-time>."
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: <subset of host's policy>
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: <revoke_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.**