ELNOR REPO READER TEXT MIRROR Original path: Memory Rebuild Docs/Stage_6_Charters/E1_E2_DOC81_Scope_Policy/Reviews/E1_E2_Design_Review_Claude_Opus_4.8.md Source repo: /Users/OpenClaw1/Elnor/Elnor Specs Git branch: main Git commit: dbaa25962edc11ab30e8d4ca1715f9ae5bf77331 Generated: 2026-06-09T01:23:58.539Z --- # DOC81 (E1/E2) Scope & Policy Plane — Consolidated Design Red-Team Review + Corrected-Spec Package **Reviewer:** Claude Opus 4.8 — independent design red-teamer (substantive; CODEX did the fidelity audit, in this folder). **Subject:** `…/Stage_6_Charters/E1_E2_DOC81_Scope_Policy/DOC81_Scope_Policy_Charter_Draft.md` (R1, 1,382 lines, §0–§14). **Repo:** `wbrody/Elnor-Specs@main`, DOC81 blob `8084899`. Verified against E0, the Skeletal/Owner Map/Import Graph, Round D R0.2, PropA R6.3, EC Core Add A V3.3, and the ADQ ledger. **Commission:** `…/E1_E2_Design_Review_Prompt.md`. This document follows its structure and answers §3.1–§3.10 + §4.1–§4.6. **Status of this file:** finished review incorporating the post-review architect discussion on privilege/egress (see §1.5 and the B20/B12 dispositions). Review/tracking artifact — not an operative spec edit. --- ## 0. Bottom line & verdict > **Verdict: `DESIGN_REVISION_NEEDED`** — *scoped, not alarming.* The **architecture, ownership, and E0 binding are A-grade and stand** (best E0-fidelity in the family; every `E0 §x.y` citation resolves at field level and nothing is redefined). What needs a revision pass is the **policy-meet algebra** and the **scope-topology algebra**. The central contract accumulated **nine Blocking-class defects**; two change the *shape* of the meet (**B6** coherence, **B7** monotonicity) and two are silent cross-matter-firewall / non-termination vectors (**B13**, **B14**). None re-architects the family; all fixes are paste-ready (§2). > > **Single biggest strength:** E0 binding integrity. **Single biggest weakness:** the `EffectiveMemoryPolicy` meet (§3.2) — correct *shape*, incomplete *algebra* (no ceiling schema; `tighten_to_floor` for 1 of 5 floors; the domain restrictiveness vector never enters; no cross-axis/obligation coherence; not history-aware; not bitemporal). > **Most important fix:** **B7** (sticky-restrictive effective policy → make the monotonicity law true), then **B6** (disclosure coherence), then **B13** (firewall-safe equivalence). One focused revision of §2.1–§2.2, §3.2–§3.4, §4.1/§4.4, §5–§6 + a new `PolicyLattice` module, then a **delta re-review of the changed sections only**. --- ## 1. Findings catalog ### 1.1 BLOCKING (9) — not implementable / not safe as written | ID | Type | §+line | Defect | Impact | |---|---|---|---|---| | **B1** | BUG/GAP | §3.4 L445; §6.3 L1053 | `PolicyCeiling` has **no schema** — `original_ceiling_ref` is a dangling `PolicyCeilingRef` (L38 bare `string`). | `ceiling_compliance_attested` (E0 §3.3) unenforceable. | | **B2** | GAP | §3.2 L467; §2.4 L299 | `tighten_to_floor` defined only for `fail_closed_candidate`; undefined for 4 floors. | Half the meet unimplementable; 3 floors tag-but-don't-restrict. | | **B3** | GAP | §3.2; E0 §2.2 | 9-axis `DomainProfileRestrictivenessVector` neither owned nor wired into the meet. | `legal.litigation`'s `disclosure: restricted` never reaches the meet; no always-present default ⇒ usability cliff. | | **B4** | BUG | §3.2 L448 | Meet never asserts scope + decisions share the active `policy_generation_id`. | Stale scope met with fresh decisions → mixed-generation policy. | | **B6** | BUG | §4.1 L705; §3.2 | Capability/disclosure not orthogonal in the reveal direction; meet emits incoherent pairs (`reference_only` + `not_disclosable`). | A citation that names a doc you may not acknowledge = leak. | | **B7** | BUG | §3.2 L482; §6.3 L1053 | Stateless `MIN` meet widens on input removal; L1 ("adding any input can only lower") is false for the full op set. | Revoked/expired inputs silently loosen policy with no restamp; contradicts L4. | | **B12** | BUG (reframed) | §3.1 L370; §3.2 step 4 | Render actions destination-blind; egress gate covers only `{export,delegate,carryover}` though E0 §22 makes `render_to_model→cloud_api` egress. | See §1.5: kept for local-model support + class distinction, **not** per-query confirms. | | **B13** | BUG | §2.1 L139 | `ScopeEquivalenceBinding` collapse is transitive with no confidence composition and no firewall guard. | Weak chain (A≡B .85, B≡C .85) merges A≡C at no aggregate confidence and can cross a `firewalled` boundary → silent cross-matter breach. | | **B14** | BUG | §2.2 L169; §8 L1197 | `ScopeContainerRelation` + §8 traversal have no acyclicity invariant, no depth bound. | `ScopeBoundary` derivation / relation traversal can cycle / not terminate. | ### 1.2 SUBSTANTIVE (18) — fold all | ID | Type | §+line | Defect | Fix → | |---|---|---|---|---| | **B5** | GAP | §5.1 L933 | 5-plane cascade: no ordering / idempotency / resumability. | §2.8 | | **B8** | GAP | §2.1 L147; §4.4 | `scope_confidence_floor` + `contamination_ceiling` referenced as `DomainProfileId` but no defining field. | §2.7 | | **B9** | GAP | §3.2 L470; §3.3 | Obligation `union` accumulates contradictory obligations (prior fix was non-transitive — corrected). | §2.6 | | **B10** | GAP | §4.4 L810 | `eligibility_ceiling` "derived from the meet" but derivation unspecified. | §2.7 | | **B11** | INCONSISTENCY | §2.4 L299; §3.1 | `minimum_conservatism_floor` has no order; §2.4 list order contradicts the `content_fidelity` chain. | §2.2 | | **B15** | GAP | §6.3 | Policy-tightening propagation unstated; in-flight handled but not re-gate of prior learning/UI outputs. | §2.9 | | **B16** | BUG | §3.2 | Post-meet steps have a required order; coherence must run last. | §2.4 | | **B17** | GAP | §5; §6.1 L1006 | Cascade↔legal-hold not explicit — revocation-triggered erasure must defer to an active hold. | §2.8 | | **B19** | GAP | §3.2 L448 | Meet's `applicable` filter has no bitemporal validity predicate; generation-selection not valid-time-aware. | §2.4 | | **B21** | GAP | §3.4 L600 | Restamp trigger-authority unspecified (ceiling-bounded, but ungated decision). | §2.5 | | **S1** | GAP | §10; E0 §12.1 | Portability/separation invariant (cross-principal bleed) not landed. | §2.9 | | **S2** | GAP | §14.3; RD §3.8 | Project↔scope seam (hint-only) not landed (§14.3 stops at §3.7). | §2.10 | | **S3** | GAP | §6.1; E0 §3.3 | `LegalHoldClearance`/`Ref` unowned/undefined (dangling E0 brand on destruction path). | §2.9 | | **S4** | GAP | §14.3 | ~9 new DOC81 schemas lack Owner Map rows; §6.1 miscites "Owner Map" for `LegalHoldState`. | §2.12 | | **S5** | GAP | §14; E0 §6 | No memory-object classification rows; `E0DurableRecord` applied to per-request/derived objects. | §2.12 | | **S6** | BUG | §4.2 L726 | `disclosure_class` ordinal vs `may_disclose_*` booleans unreconciled. | §2.6 | | **S7** | INCONSISTENCY | §2–§9 | ~16 own-object primary IDs are plain `string` — violates E0 §8.5. | §2.3 | | **M4↑** | GAP | §13.5; §3.2 | `relation_to_destination` ↔ `E0OutboundDestinationClass` crosswalk needed for the fail-closed gate. | §2.4 | ### 1.3 MINOR (11) — fold (cheap) M1 (§11: "all 11 §17.4 lints" — plan has 16; 5 are E10/DOC86's, unrouted → reword + name). M2 (§3.1: `model_class?`/`client_kind?` dropped vs RD §1.4 → restore optional). M3 (§5.1: cascade refs unbranded → E0 brands). M5 (§12; E0 §18/§20: declare golden-scenario phases 2/8/11.5 + complete §20 row). M6 (§3.5 L648: `fallback_if_unanswered:'defer'` no terminal resolution; add request `expires_at`). M7 (§3.6 L682: `superseding_epoch_ref` can fork → EC CAS linear chain). M8 (§9: UI→policy is a command/event, not an import). M9 (§2.1 L148: bind reason-codes to E0 `ReasonCodeRegistry`, L20). M10 (§4.2: count/aggregate disclosure inference → forward-flag, Phase-2). M11 (§3.1: `content_fidelity` merges content-quantity with identity-disclosure → document as content-quantity; identity → disclosure_class). ### 1.4 CONSIDERED AND DECLINED / CONFIRMED - **§13.2 disclosure-order swap** (`existence_only ⊏ generic_safe_label_only`): sound — keep. - **§13.1 `ScopeAffinity` union** (`+shared,+unrelated,+uncertain`): correct no-loss reconciliation — keep. - **B18 disambiguation timeout**: already handled (`fallback_if_unanswered` + `timed_out` + `unanswered_applies_fallback_not_allow`, §3.5). Declined; only M6 refinement remains. - **ADQ-221 DOC8→DOC85**, **ADQ-316 EC keep/downgrade/block table** (correctly EC's; DOC81 supplies the ceiling), **per-dimension loop is not a collapse** — accepted B6 instead. ### 1.5 Privilege & egress controls — SCOPE BOUNDARY (post-review architect discussion) The original B20 ("a synthesized output inherits the meet of its sources' privilege") is **WITHDRAWN**. Privilege cannot be composed from source privilege: facts are not privileged even when learned from a privileged communication (the *attorney* cannot be compelled to disclose the communication, but freely uses the facts); the synthesis act can itself create work-product protection regardless of source status; and once a fact/document is disclosed elsewhere it is no longer privileged — a status the system cannot know from provenance. The 100%-fidelity requirement for privilege means **the system must never make a privilege determination with legal effect.** This also matched ELNOR's standing principle: *privilege is an egress concern, not an internal access barrier.* **What stays in DOC81 (small, mostly already in the findings):** - The memory-policy axes (`locality`, `disclosure_class`, `mutation_authority`), the meet, scope objects, and stamps — DOC81's owned plane. - The **egress decision shape** (B12 + M4↑): distinguish destination classes — *controlled-infrastructure* (the user's LLM, firm cloud) vs *external recipient* vs *public* vs *court* — at decision time, and emit a **"confirmation-required" disposition** (same shape as the existing `PolicyDisambiguationRequest`, §3.5). DOC81 decides *that* confirmation is required; it does not run the confirmation. **Reframe B12:** the local-vs-cloud render distinction exists to (i) support a local-model deployment and (ii) feed the egress controls — **not** to confirm every cloud render. - The **sensitivity/privilege characterization as a consumed input-seam** — referenced exactly like `VisibilityClass` (§2.1, "PropA/DOC82-owned; referenced, not redefined"). DOC81 declares the seam (a memory/source may carry a sensitivity characterization that contributes to the conservatism floor and egress gating) and the policy behavior; it does **not** own the taxonomy. - **No-save / Incognito rides on the existing `mutation_authority` axis** (=`none` at scope/episode). No new DOC81 surface. **What is OUT of DOC81 → the security/authorization plane (DOC5, being rebuilt) and memory governance** (per the Flattening Plan §1.2 non-absorption rule — DOC81 must not absorb DOC23/DOC24/DOC20/DOC25 domains): - The **egress guard** (warn / check / block), the default-on light **third-party warning**, the **Local Only** mode, the **autonomous-send checkpoint**, and the **"remember until tomorrow" standing grant**. - The **destination classifier** (firm domain + matter participant roster + channel type → classes). - The **privilege/sensitivity characterization taxonomy + provenance derivation + user override** (incl. the "disclosed-elsewhere → not privileged" override) — Phase-II weight per the architect's roadmap. - The **confirmation UI** (DOC20/Q). **Firewall principle (B13/B14):** firewall machinery is **dormant until a screen is explicitly declared** — never computed, never defaulted, never surfaced in the work path. For a solo user it never fires (no boundary is ever `firewalled`); it costs nothing. B13/B14 are pure correctness backstops that only bite when a screen actually exists (the multi-firm/lateral-screen case). No user-facing steps, prompts, or blocks are added for firewalls. --- ## 2. Corrected specification — paste-ready (full coding & implementation) Drop-in. One new module (`PolicyLattice`, §2.1 = DOC81 **§3.0**) that the meet, floors, coherence, and DAMS ceiling all call; then corrected/added schemas section-by-section. Targets the OpenClaw/Node + TS convention already in DOC81. ### 2.1 NEW DOC81 §3.0 — `PolicyLattice` (the single typed algebra) — closes B2/B6/B10/B11 ```typescript // DOC81 §3.0 PolicyLattice — schema_owner = DOC81. Total-order chains, ⊥ first; "most restrictive wins" = MIN. class PolicyLatticeError extends Error {} export const CONTENT_FIDELITY = ['none','safe_label','reference_only','redacted','full'] as const; export const LOCALITY = ['blocked','local_only','approved_external'] as const; export const LEARNING_SCOPE = ['none','audit_only','same_scope_only','partitioned','global_allowed'] as const; export const MUTATION_AUTHORITY = ['none','candidate_only','durable_requires_review','durable_allowed'] as const; export const DISCLOSURE_CLASS = ['not_disclosable','existence_only','generic_safe_label_only','redacted_summary','full'] as const; export type ContentFidelity = typeof CONTENT_FIDELITY[number]; export type Locality = typeof LOCALITY[number]; export type LearningScope = typeof LEARNING_SCOPE[number]; export type MutationAuthority = typeof MUTATION_AUTHORITY[number]; export type DisclosureClass = typeof DISCLOSURE_CLASS[number]; export class Chain { constructor(private readonly order: readonly T[]) {} readonly bottom: T = this.order[0]; readonly top: T = this.order[this.order.length - 1]; rank(v: T): number { const i = this.order.indexOf(v); if (i < 0) throw new PolicyLatticeError(`value '${v}' not on chain [${this.order.join(',')}]`); // unknown ⇒ fail-closed return i; } leq(a: T, b: T): boolean { return this.rank(a) <= this.rank(b); } meet(a: T, b: T): T { return this.rank(a) <= this.rank(b) ? a : b; } // MIN = most restrictive meetAll(vs: readonly T[]): T { return vs.length ? vs.reduce((x,y)=>this.meet(x,y)) : this.bottom; } // empty ⇒ ⊥ clampDown(v: T, ceiling: T): T { return this.meet(v, ceiling); } } export const LAT = { content: new Chain(CONTENT_FIDELITY), locality: new Chain(LOCALITY), learning: new Chain(LEARNING_SCOPE), mutation: new Chain(MUTATION_AUTHORITY), disclosure: new Chain(DISCLOSURE_CLASS), } as const; export interface PolicyPoint { content_fidelity: ContentFidelity; locality: Locality; learning_scope: LearningScope; mutation_authority: MutationAuthority; disclosure_class: DisclosureClass; } export const BOTTOM: PolicyPoint = { content_fidelity:'none', locality:'blocked', learning_scope:'none', mutation_authority:'none', disclosure_class:'not_disclosable' }; export const TOP: PolicyPoint = { content_fidelity:'full', locality:'approved_external', learning_scope:'global_allowed', mutation_authority:'durable_allowed', disclosure_class:'full' }; export function meetPoints(a: PolicyPoint, b: PolicyPoint): PolicyPoint { return { content_fidelity: LAT.content.meet(a.content_fidelity,b.content_fidelity), locality: LAT.locality.meet(a.locality,b.locality), learning_scope: LAT.learning.meet(a.learning_scope,b.learning_scope), mutation_authority: LAT.mutation.meet(a.mutation_authority,b.mutation_authority), disclosure_class: LAT.disclosure.meet(a.disclosure_class,b.disclosure_class), }; } export function meetAllPoints(ps: readonly PolicyPoint[]): PolicyPoint { return ps.length ? ps.reduce(meetPoints) : {...BOTTOM}; } export function leqPoint(a: PolicyPoint, b: PolicyPoint): boolean { return LAT.content.leq(a.content_fidelity,b.content_fidelity) && LAT.locality.leq(a.locality,b.locality) && LAT.learning.leq(a.learning_scope,b.learning_scope) && LAT.mutation.leq(a.mutation_authority,b.mutation_authority) && LAT.disclosure.leq(a.disclosure_class,b.disclosure_class); } // B6: capability that reveals content/identity forces a disclosure floor. Resolve by capping CAPABILITY down to the // disclosure ceiling — NEVER by raising disclosure (preserves L1). Single-pass, monotone-down, terminating. export const MAX_CONTENT_FOR_DISCLOSURE: Record = { not_disclosable:'none', existence_only:'safe_label', generic_safe_label_only:'reference_only', redacted_summary:'redacted', full:'full', }; export function isCoherent(p: PolicyPoint): boolean { return LAT.content.leq(p.content_fidelity, MAX_CONTENT_FOR_DISCLOSURE[p.disclosure_class]); } export function makeCoherent(p: PolicyPoint): PolicyPoint { return { ...p, content_fidelity: LAT.content.clampDown(p.content_fidelity, MAX_CONTENT_FOR_DISCLOSURE[p.disclosure_class]) }; } ``` Single-pass/terminating: `makeCoherent` only lowers `content_fidelity`; lowering capability never raises the disclosure floor. No reverse coupling (capability `none` + disclosure `full` is coherent). Hence B16 only requires coherence to run **after** the disclosure-tightening steps. > **Note (B20 withdrawn):** an earlier draft of this module included a `composeOutputPolicy(sources)` that met the policies of multiple contributing source objects into one output policy. That is removed — per §1.5, a synthesized output's *privilege* cannot be composed from its sources, and the *confidentiality/egress* posture of an output is an action-gate concern owned by the security plane (DOC5), not a DOC81 memory-policy operation. ### 2.2 §2.4 `ScopeResolutionResult` — floor crosswalk + floor order (B2, B11) ```typescript // floor total order (B11), ALIGNED to the content_fidelity chain. ⊏ = more restrictive. // safe_label_candidate is MORE restrictive than reference_only_candidate (matches CONTENT_FIDELITY). Reorder the §2.4 list to match. export const FLOOR_ORDER = ['fail_closed_candidate','user_disambiguation_candidate','safe_label_candidate','reference_only_candidate','normal_policy_check'] as const; export type MinimumConservatismFloor = typeof FLOOR_ORDER[number]; const FLOOR_CHAIN = new Chain(FLOOR_ORDER); export function meetFloors(fs: readonly MinimumConservatismFloor[]): MinimumConservatismFloor { return fs.length ? fs.reduce((a,b)=>FLOOR_CHAIN.meet(a,b)) : 'fail_closed_candidate'; // multiple ⇒ MIN } // floor → per-axis CEILING (B2). tighten_to_floor(eff,floor) := meetPoints(eff, FLOOR_CEILING[floor]). export const FLOOR_CEILING: Record = { normal_policy_check: { ...TOP }, reference_only_candidate: { content_fidelity:'reference_only', locality:'local_only', learning_scope:'audit_only', mutation_authority:'candidate_only', disclosure_class:'redacted_summary' }, safe_label_candidate: { content_fidelity:'safe_label', locality:'local_only', learning_scope:'none', mutation_authority:'candidate_only', disclosure_class:'generic_safe_label_only' }, user_disambiguation_candidate: { content_fidelity:'reference_only', locality:'blocked', learning_scope:'none', mutation_authority:'none', disclosure_class:'existence_only' }, // + MUST raise PolicyDisambiguationRequest (§3.5) fail_closed_candidate: { ...BOTTOM }, }; ``` > Intermediate floor *values* are a proposal needing architect sign-off (only `fail_closed→⊥` and `user_disambiguation→raise a request` are strongly implied by the draft). Add to `ScopeResolutionResult`: `evaluated_under_policy_generation_id: PolicyGenerationId` (B4); `effective_time: string` RFC3339 (B19); `relation_to_destination_class?: E0OutboundDestinationClass` (M4↑); `thresholds_ref: DomainProfileId` (B8). Lints: `policy.floor_not_applied_to_all_axes`; `scope.multiple_floors_not_min`. ### 2.3 §3.1 `MemoryPolicyDecision` — branded IDs, restored egress inputs, render destination, valid-time (S7, M2, B12, B19) ```typescript // brand ALL DOC81-owned primary IDs (E0 §8.5). S7. (16 ids; representative set.) export type PolicyCeilingRef = string & { readonly __b:'PolicyCeilingRef' }; // was bare string (L38) export type ScopeEquivalenceClusterRef = string & { readonly __b:'ScopeEquivalenceClusterRef' }; export type LegalHoldClearanceRef = string & { readonly __b:'LegalHoldClearanceRef' }; export type EpisodePolicyEpochId = string & { readonly __b:'EpisodePolicyEpochId' }; export type PolicyStampRestampId = string & { readonly __b:'PolicyStampRestampId' }; // … LegalHoldStateId, ContaminationRiskThresholdRuleId, PolicyCappedDAMSInputId, PolicyUIExportId, etc. lint: schema.primary_id_not_branded export type MemoryPolicyAction = | 'retrieve' | 'render_inline' | 'render_reference_only' | 'render_safe_label' | 'learn' | 'mutate' | 'export' | 'delegate' | 'carryover'; export interface MemoryPolicyDecision extends PolicyPoint { // carries the 5 axes decision_id: string; object_ref: MemoryObjectRef; action: MemoryPolicyAction; policy_generation_id: PolicyGenerationId; valid_from: string; valid_to?: string; // B19 — bitemporal in-force window (RFC3339-UTC, E0 §8.5) destination?: E0OutboundDestinationClass; // REQUIRED for {export,delegate,carryover}; and {render_*} when locality may leave the machine (B12) model_class?: ModelClass; // M2 — restored (RD §1.4) client_kind?: ClientKind; // M2 — restored obligations: PolicyObligation[]; reason_codes: ReasonCodeId[]; } function toPolicyPoint(d: MemoryPolicyDecision): PolicyPoint { const { content_fidelity, locality, learning_scope, mutation_authority, disclosure_class } = d; return { content_fidelity, locality, learning_scope, mutation_authority, disclosure_class }; } function isInForce(d: MemoryPolicyDecision, t: string): boolean { // B19 return d.valid_from <= t && (d.valid_to === undefined || t < d.valid_to); } ``` ### 2.4 §3.2 `EffectiveMemoryPolicy` + the corrected meet (B3,B4,B6,B7,B9,B12,B16,B19,M4↑) Full ordered pipeline; each numbered step cites the finding it closes. **Order is normative** (B16): coherence is last among tightening steps. ```typescript export interface EffectiveMemoryPolicy extends PolicyPoint { effective_policy_ref: EffectiveMemoryPolicyRef; schema_owner: 'DOC81'; object_ref: MemoryObjectRef; action: MemoryPolicyAction; destination?: E0OutboundDestinationClass; policy_generation_id: PolicyGenerationId; effective_time: string; // B19 obligations: PolicyObligation[]; original_ceiling_ref?: PolicyCeilingRef; // §3.4 / B1 contributing_decision_refs: string[]; domain_contribution_ref: string; reason_codes: ReasonCodeId[]; // populated per tightening step (auditability) } type EffectiveResult = | { status:'OK'; effective: EffectiveMemoryPolicy } | { status:'RE_PLAN_REQUIRED'; reason:'generation_mismatch' }; // B4 export function computeEffectivePolicy(args: { object_ref: MemoryObjectRef; action: MemoryPolicyAction; destination?: E0OutboundDestinationClass; effectiveTime: string; // B19 — the request's as-of time activeEpoch: EpisodePolicyEpoch; // §3.6 — active policy_generation_id (selected for effectiveTime, B19) scopeResolution: ScopeResolutionResult; // §2.4 decisions: MemoryPolicyDecision[]; // §3.1 domainContribution: PolicyPoint; // B3 — DomainProfilePolicyContribution (ALWAYS present) priorEffective?: PolicyPoint; // B7 — last effective for (object,action) IF no restamp since; else undefined }): EffectiveResult { const g = args.activeEpoch.policy_generation_id; // 0. Generation-consistency precondition (B4). Generation itself is selected for effectiveTime (B19). if (args.scopeResolution.evaluated_under_policy_generation_id !== g) return { status:'RE_PLAN_REQUIRED', reason:'generation_mismatch' }; if (!args.decisions.every(d => d.policy_generation_id === g)) return { status:'RE_PLAN_REQUIRED', reason:'generation_mismatch' }; // 1. Applicable: object/action match, destination wildcard (unset ⇒ all), AND in force at effectiveTime (B19). const applicable = args.decisions.filter(d => d.object_ref === args.object_ref && d.action === args.action && (d.destination === undefined || d.destination === args.destination) && isInForce(d, args.effectiveTime)); // 2. Per-axis meet INCLUDING the always-present domain contribution (B3) ⇒ set never empty ⇒ ⊥ reserved for "no policy". let eff: PolicyPoint = meetAllPoints([args.domainContribution, ...applicable.map(toPolicyPoint)]); // 3. Scope conservatism floor (B2). Monotone-down. eff = meetPoints(eff, FLOOR_CEILING[args.scopeResolution.minimum_conservatism_floor]); // 4. Sticky-restrictive (B7): cannot rise above the prior effective absent a restamp ⇒ removal can't widen. if (args.priorEffective) eff = meetPoints(eff, args.priorEffective); // 5. Coherence (B6) — MUST BE LAST among tightening steps (B16): reads the FINAL disclosure to cap capability. eff = makeCoherent(eff); // 6. Obligations: union + transitive-closure conflict resolution (B9); reconcile obligation↔axis (B6 facet). const obligations = resolveObligations(applicable.flatMap(d => d.obligations)); eff = reconcileObligationAxis(eff, obligations); // e.g. hide_existence ⇒ disclosure_class=not_disclosable ⇒ re-cohere // 7. Egress destination-typing gate (B12 + M4↑) — covers external render too; fail-closed on untyped destination. const EGRESS = new Set(['export','delegate','carryover','render_inline','render_reference_only','render_safe_label']); const couldLeave = EGRESS.has(args.action) && (args.action.startsWith('render') ? eff.locality === 'approved_external' : true); if (couldLeave && !isTypedDestination(args.destination)) eff = { ...eff, locality:'blocked' }; return { status:'OK', effective: assemble(eff, obligations, g, args) }; } ``` - Determinism: `MIN` + set-union are commutative/associative/idempotent → order-independent. - **B12/M4↑:** the egress gate distinguishes destination *classes* and emits a **"confirmation-required" disposition** where policy permits external egress but the security plane (DOC5) must confirm. DOC81 produces the disposition; the security plane runs the confirmation (see §1.5). M4↑: state the `relation_to_destination` ↔ `E0OutboundDestinationClass` crosswalk in §13.5. - **B19:** the active epoch/generation must be the one in force at `effectiveTime`; superseded/future decisions are excluded by `isInForce`. - Lints: `policy.meet_inputs_cross_generation`, `policy.capability_exceeds_disclosure_ceiling`, `monotonicity.effective_widened_on_input_removal_without_restamp`, `policy.external_render_without_destination`, `policy.conflicting_obligations_unresolved`, `policy.meet_included_out_of_force_decision`. ### 2.5 §3.4 `PolicyCeiling` + restamp authority (B1, B21) ```typescript // high-water capability captured at the ORIGINATING generation; the cap a restamp may never exceed (E0 §3.3). B1. export interface PolicyCeiling extends E0DurableRecord { ceiling_id: PolicyCeilingRef; schema_owner:'DOC81'; object_ref: MemoryObjectRef; action: MemoryPolicyAction; // per-action (L3) origin_policy_generation_id: PolicyGenerationId; ceiling: PolicyPoint; // the POLICY GRANT — meet over decisions + DomainProfile BEFORE the scope floor captured_from_effective_policy_ref: EffectiveMemoryPolicyRef; reason_codes: ReasonCodeId[]; } // Restamp legality (the only widening path — L4'): ≤ MIN(ceiling, CURRENT scope floor) on every axis. export function restampIsLegal(newEff: PolicyPoint, ceiling: PolicyPoint, currentScopeFloor: PolicyPoint): boolean { return leqPoint(newEff, meetPoints(ceiling, currentScopeFloor)); } // B21 — restamp TRIGGER-AUTHORITY. Gate the DECISION, not just the mechanism. export interface RestampAuthority { authorized_by: PrincipalRef; authority_tier: 'agent_autonomous'|'architect_batched'|'human_required'; } // RULE: a restamp that RAISES disclosure_class OR crosses a `firewalled` boundary REQUIRES authority_tier='human_required'. // A same-scope restamp that only restores capability up to the ceiling under the CURRENT generation may be agent_autonomous. // lints: policy.disclosure_raising_restamp_without_human_authority ; policy.cross_firewall_restamp_without_human_authority ``` Capture rule: EC captures a `PolicyCeiling` at the first `PolicyStamp` for `(object,action)`, snapshotting the policy grant (step-2 meet, before the step-3 floor). Immutable; restamp-of-restamp inherits the originating `ceiling_id` (no ratcheting). B7 dependency: EC must durably persist the effective policy per `(object,action)` (derived from the stamp/invalidation history — single source of truth) so step 4 can read `priorEffective`. ### 2.6 §4.1/§4.2 coherence + obligation precedence (corrected) + ordinal/boolean (B6, B9, S6) ```typescript // obligation conflict resolution (B9). CORRECTED: domination is a TRANSITIVE strict partial order; keep maximal (most-restrictive). const OBLIGATION_DOMINANCE: ReadonlyArray = [ ['require_ui_warning','hide_existence'], ['show_generic_existence_only','hide_existence'], ['render_inline','require_redaction'], ]; const DOMINATES_CLOSURE: Record> = (() => { // transitive closure: dominator → all kinds it dominates const direct: Record> = {}; for (const [dom, dr] of OBLIGATION_DOMINANCE) (direct[dr] ??= new Set()).add(dom); const close = (k: string, seen = new Set()): Set => { for (const d of direct[k] ?? []) if (!seen.has(d)) { seen.add(d); close(d, seen); } return seen; }; return Object.fromEntries(Object.keys(direct).map(k => [k, close(k)])); })(); export function resolveObligations(obs: PolicyObligation[]): PolicyObligation[] { const kept = dedupeMergeSameKind(obs); // same-kind ⇒ strictest parameter (e.g. union redaction spans) const present = new Set(kept.map(o => o.kind)); const removed = new Set(); for (const o of kept) for (const d of DOMINATES_CLOSURE[o.kind] ?? []) if (present.has(d)) removed.add(d); return kept.filter(o => !removed.has(o.kind)); // order-independent, transitive } // B6 facet — reconcile obligations WITH the disclosure axis, then re-cohere. const OBLIGATION_DISCLOSURE_CEILING: Record = { hide_existence:'not_disclosable', show_generic_existence_only:'generic_safe_label_only' }; export function reconcileObligationAxis(p: PolicyPoint, obs: PolicyObligation[]): PolicyPoint { let disc = p.disclosure_class; for (const o of obs) { const c = OBLIGATION_DISCLOSURE_CEILING[o.kind]; if (c) disc = LAT.disclosure.meet(disc, c); } return makeCoherent({ ...p, disclosure_class: disc }); } // S6 — may_disclose_* booleans bounded by the ordinal disclosure_class (ordinal is the CEILING). const DISCLOSURE_ALLOWS: Record> = { not_disclosable: [], existence_only: ['may_disclose_existence'], generic_safe_label_only: ['may_disclose_existence','may_disclose_container_type','may_disclose_topic_label'], redacted_summary: ['may_disclose_existence','may_disclose_container_type','may_disclose_topic_label','may_disclose_count','may_disclose_reason_summary'], full: ['may_disclose_existence','may_disclose_container_type','may_disclose_topic_label','may_disclose_source_title','may_disclose_count','may_disclose_reason_summary'], }; // lint: disclosure.granular_flag_exceeds_disclosure_class ``` §4.1 prose: "orthogonal in the block direction; capability is bounded by the disclosure ceiling in the reveal direction, including obligation-induced ceilings." ### 2.7 §4.4 thresholds + eligibility derivation + domain contribution (B8, B10, B3) ```typescript export interface DomainPolicyThresholds extends E0DurableRecord { // B8 thresholds_id: DomainProfileId; schema_owner:'DOC81'; scope_confidence_floor: number; // 0..1 — below ⇒ no collapse / floor rises contamination_ceiling: number; // 0..1 — above ⇒ contamination veto fires reason_codes: ReasonCodeId[]; } export const THRESHOLD_DEFAULTS = { scope_confidence_floor: 1.0, contamination_ceiling: 0.0 } as const; // fail-closed // lint: policy.threshold_referenced_but_undefined export interface DomainProfilePolicyContribution extends E0DurableRecord { // B3 — DOC81 owns RestrictivenessLevel semantics + the 9→5 crosswalk contribution_id: string; schema_owner:'DOC81'; domain_profile_id: DomainProfileId; action: MemoryPolicyAction; contribution: PolicyPoint; // per-axis ceiling from the 9-axis restrictiveness vector (E0 §2.2) reason_codes: ReasonCodeId[]; } // an object may carry MULTIPLE profiles ⇒ the meet includes ALL contributions. lints: policy.domain_profile_restrictiveness_not_in_meet ; domain_profile.restrictiveness_level_semantics_undefined export type EligibilityCeiling = 'inline_allowed'|'reference_only_max'|'search_only_max'|'notice_only_max'|'blocked'; export function eligibilityCeiling(eff: PolicyPoint): EligibilityCeiling { // B10 — deterministic if (eff.locality === 'blocked' || eff.content_fidelity === 'none') return 'blocked'; if (eff.content_fidelity === 'safe_label') return 'notice_only_max'; if (eff.content_fidelity === 'reference_only' && LAT.disclosure.leq(eff.disclosure_class,'existence_only')) return 'search_only_max'; if (eff.content_fidelity === 'reference_only') return 'reference_only_max'; return 'inline_allowed'; } // lint: dams.eligibility_ceiling_not_derived_from_effective_policy ``` ### 2.8 §5 cascade — ordering, idempotency, monotone-down, hold dominance (B5, B17) ```typescript export interface CascadeAdditions { // add to CascadingSourceInvalidation cascade_sequence: ['doc82_support_edges','doc87_memberships','doc84_delivery_artifacts','doc85_learning_signals','doc86_surfaces']; idempotency_key: string; // EC re-fire is a no-op if applied (E0 §10.5) per_plane_completion: Partial>; // each plane outcome is an idempotent monotone-DOWN STATE transition (set-to-floor), NOT a relative delta ⇒ concurrent/re-fired cascades COMMUTE. } ``` **B17 — legal-hold dominance:** the cascade's erasure/destruction outcomes defer to `LegalHoldState` (§6.1) — a held object is invalidated/suppressed but never destroyed; the destruction plane is a no-op-with-defer while `held`. Lints: `revocation.cascade_plane_out_of_order`; `revocation.cascade_not_idempotent`; `revocation.cascade_partial_not_resumable`; `revocation.cascade_destroyed_held_object`. ### 2.9 §6 `LegalHoldClearance`, tightening re-gate, portability (S3, B15, S1) ```typescript export interface LegalHoldClearance extends E0DurableRecord { // S3 — affirmative authorization to destruct a HELD object (E0 §3.3) clearance_id: LegalHoldClearanceRef; schema_owner:'DOC81'; hold_ref: LegalHoldStateId; object_refs: MemoryObjectRef[]; authorized_by: PrincipalRef; // human (litigation-grade) clearance_basis: 'hold_released' | 'court_order' | 'explicit_authorized_destruction'; reason_codes: ReasonCodeId[]; } // make the destructive-job gate STRUCTURAL at EC job-registration. lint: legal_hold.destructive_job_skipped_check (E0 §12.1) ``` **B15 — policy-tightening propagation (bitemporal; §6.3):** a tightening is NOT retroactive claw-back (prior outputs were legitimate under their generation). Every CONSUMPTION re-gates against the CURRENT effective policy — delivery (DOC84), learning replay (DOC85), and UI display (DOC86), not only plan→render. Durable outputs carry their originating `policy_generation_id`; the sticky/ceiling logic applies at consumption time. Lint `policy.stale_generation_output_consumed_without_regate`. **S1 — portability/separation:** §6.5 — an export/portable bundle MUST preserve scope/principal separation; it MUST NOT carry memory eligible only under a different principal/scope than the export's `destination_scope_ref`/principal. §10 gate = `EC §8 export + DOC81 locality/disclosure meet`; lint `portability.cross_principal_bleed`. ### 2.10 §2.1–§2.2 equivalence transitivity + topology acyclicity + Project seam (B13, B14, S2) ```typescript export interface ScopeEquivalenceCluster extends E0DurableRecord { // B13 — litigation-critical cluster_id: ScopeEquivalenceClusterRef; schema_owner:'DOC81'; member_scope_refs: ScopeRef[]; // transitive closure of CONFIRMED bindings spanning_binding_refs: ScopeEquivalenceBindingRef[]; cluster_confidence: number; // = MIN over spanning bindings (weakest link — no laundering) reason_codes: ReasonCodeId[]; } export const MAX_SCOPE_TRAVERSAL_DEPTH = 16; // B14 — ScopeBoundary derivation + §8 relation traversal bound ``` **B13 rules (§2.1):** (1) transitive collapse only within a cluster whose `cluster_confidence ≥ strictest member domain threshold`; `cluster_confidence = MIN(spanning)`. (2) a transitive merge MUST NOT join scopes separated by a `firewalled` boundary — a firewall is crossed only by an `explicit_user_binding` naming both, never by inference. Lints: `scope.transitive_equivalence_below_cluster_threshold`; `scope.transitive_merge_crossed_firewall`; `scope.equivalence_cluster_confidence_not_min`. **B14 rules (§2.2/§8):** (1) `contains` edges form a DAG; EC rejects a cycle-creating edge. (2) only `{contains,source_membership,topic_membership}` traverse for containment; `{linked_library,analogical_relation}` are affinity, not traversed. (3) `ScopeBoundary` derivation + §8 traversal bounded by `MAX_SCOPE_TRAVERSAL_DEPTH`; exceeding fails closed (`boundary_kind='unknown'` ⇒ floor rises); visited-set cycle detection. Lints: `scope.container_cycle_created`; `scope.traversal_depth_exceeded_not_fail_closed`; `relation.traversal_cycle_detected`. **S2 — Project↔scope seam (RD §3.8):** a Project may seed scope identity as a hint but may not create truth identity, override boundaries, broaden policy, or count as proof. Lints `scope.project_membership_created_truth_identity`, `scope.project_mode_broadened_policy`, `scope.project_membership_used_as_proof`, `scope.project_overrode_scope_boundary`. ### 2.11 §3.5 / §3.6 refinements (M6, M7) - `fallback_if_unanswered:'defer'` resolves to a concrete terminal fallback on a hard timeout; add `expires_at` to `PolicyDisambiguationRequest`. Lint `policy.disambiguation_defer_without_hard_timeout`. - `EpisodePolicyEpoch.superseding_epoch_ref` = a linear chain under EC CAS (no fork). Lint `policy.epoch_supersession_forked`. ### 2.12 Discharge notes (tracking) - **S4** — add ~9 Owner Map rows (`PolicyCeiling`, `DomainProfilePolicyContribution`, `DomainPolicyThresholds`, `LegalHoldClearance`, `ScopeEquivalenceCluster`, `CollectionModeSuppressionGovernance`, `SourceExclusionFilterRule`, `RelationTraversalScopeCheckPolicy`, `PolicyUIExport`, `PolicyStampRestamp`); correct §6.1's `LegalHoldState` citation to "Skeletal §10.3" only. - **S5** — classification rows (E0 §6.1) for all ~25 objects; drop `extends E0DurableRecord` from per-request/derived ones (`ScopeResolutionResult`, `ScopeBoundary`, the meet result, `PolicyMembraneDecision`, `PolicyCappedDAMSInput`) or mark `derived-projection=true`. Lint `classification.doc81_object_without_classification_row`. - **M5** — §12-bis: DOC81 owns golden-scenario step 2 (preflight) + step 8 (re-check), contributes step 11.5 (egress); §20 row = `MemoryCoordinationTrace` obligations (policy/scope refs + `policy_generation_id`), degraded states `policy_disambiguation_pending`/`scope_unresolved→conservative`. - **M1** — reword "all 11 §17.4 lints" → "the 11 policy/scope §17.4 lints that are DOC81's; the other 5 route to E10/DOC86" + name them. --- ## 3. Better patterns / new ideas - **NI-1 — Property-based fixtures for the algebraic laws (auto-catch B6/B7/B11/B9-transitivity).** `fixture.property.*` over generated decision sets: meet idempotence/commutativity/associativity; monotone-down under add AND remove (B7); coherence always holds (B6); obligation-resolution idempotence + transitivity (B9); floor-clamp idempotence. Turns L1–L4 from prose into enforced invariants — the antidote to the all-pass-fixture risk (commission §2.H). A property test can't pass while the law is broken — it caught my own B9 bug. - **NI-2 — Sticky-restrictive effective policy as a bounded meet-semilattice with a privileged reset (CRDT-style) → Phase-2 networking readiness for free.** Monotone-meet state is conflict-free under replication; multi-node sync merges by `meet` with no coordination, and `restamp` is the single consensus point. Serves the "Phase-1 readiness for complex networking" doctrine at zero Phase-1 behavior cost — it's how you type §3.2 (the `PolicyLattice` already is that semilattice). - **NI-3 — DIFC / declassification framing (Myers/Liskov).** capability+disclosure = an information-flow label lattice; "restamp = the only widening path, ceiling-bounded, re-floored by scope, human-authorized for disclosure-raising" *is* bounded declassification. Studied soundness argument + multi-principal readiness (the S1 separation seam). - **NI-4 — Cedar/XACML obligations + deny-overrides; OPA deny-by-default — as the named reference model.** The dimensional decision + accumulating obligations + deny-overrides meet *is* Cedar/XACML; naming it supplies battle-tested obligation-combining (corrected B9) + the ordinal/boolean reconciliation (S6). - **NI-5 — The `PolicyLattice` module (§2.1) is the highest-leverage move** — converts B2/B6/B10/B11 from ad-hoc enum logic into typed lattice calls, removing every "what should X be here?" guess-point. Takes §3.2 from B-with-holes to A+-with-no-guess-points. ## 4. Schema grades (A–D, load-bearing) | Schema | § | Grade | Note | |---|---|---|---| | Scope identity/topology | §2.1–2.2 | **B** | Topology discipline clean; equivalence transitivity (B13) + acyclicity/depth (B14) unspecified — both safety-relevant. | | `ScopeAffinity` | §2.3 | **A** | Union reconciliation correct (§13.1). | | `ScopeResolutionResult`/`…Trace`/`Health` | §2.4–2.5 | **A−** | Faithful; durable/derived ambiguity (S5); missing generation stamp (B4) + effective_time (B19). | | **`EffectiveMemoryPolicy` + meet** | §3.2 | **B** | Strongest target, weakest algebra: B1/B2/B3/B4/B6/B7/B16/B19. Lifts to **A+** with §2.1+§2.4. | | `PolicyMembraneDecision`/`Obligation` | §3.3 | **A−** | ADQ-221 handled; obligation precedence missing + non-trivial (B9). | | `PolicyStamp*`/`Restamp` | §3.4 | **B+** | Restamp contract good; ceiling has no schema (B1); trigger-authority ungated (B21). | | `PolicyDisambiguationRequest` | §3.5 | **A** | Fail-closed defaults exemplary; `defer`/`expires_at` refinement (M6). | | `EpisodePolicyEpoch` | §3.6 | **A−** | Mid-episode re-gate correct; supersession fork (M7). | | Capability/disclosure + `SafeLabelDisclosurePolicy` | §4.1–4.2 | **B+** | Orthogonality false in reveal direction (B6); ordinal/boolean unreconciled (S6). | | Extraction/DAMS/Contamination/TopicRisk | §4.3–4.5 | **A−** | DAMS clamp faithful; eligibility derivation (B10) + threshold home (B8) missing. | | `CascadingSourceInvalidation` + 5-plane | §5 | **B+** | Outcomes mirror E0 §12.1; ordering/idempotency/hold-dominance (B5/B17). | | Cross-cutting (`LegalHoldState`, monotonicity, re-gate) | §6 | **B+** | `LegalHoldClearance` unowned (S3); portability missing (S1); tightening re-gate (B15). | | Topic privacy / PropA fold | §7 | **A** | §7.3 reconciliation is model work. | | DOC81→DOC86 export / enforcement / sources | §8–§14 | **A−** | §10 invariant-gate table excellent; M4↑ crosswalk; M1 count. | ## 5. The commission's questions, answered **§3.1 Meet walk** — per-axis `MIN` correct + deterministic; obligations union (now transitive, B9); destination gate blocks untyped egress. Goes wrong at: floor tighten if floor ≠ fail_closed (B2), cross-generation/out-of-force inputs (B4/B19), domain profile never consulted (B3), incoherent pair (B6). Correct after §2. **§3.2 Restamp + monotonicity** — only widening path but unenforceable (B1), the law is false under removal (B7), trigger ungated (B21). Restamp-of-restamp correctly inherits the originating ceiling. **§3.3 5-plane cascade** — complete + composes with E0's cascade (no double-coverage); no ordering/idempotency (B5), hold-dominance unstated (B17). **§3.4 `LegalHoldState`** — binds the *named* destructive jobs; make the gate structural at EC job-registration + define the dangling `LegalHoldClearance` (S3). **§3.5 `collection_mode` suppression** — watertight; EC seam real. Sound. **§3.6 PropA fold (§7.3)** — clean for all 8 rows + DSPy + exclusion + suppression; no over-reach. **§3.7 `AssertionRelationEdge` (§8)** — dense enough for per-edge gating; add cycle guard + depth bound + "unknown relation_kind ⇒ fail-closed" (B14). **§3.8 DOC81→DOC86 export (§9)** — downward-only, no B1-cycle; clean separation. Sound (UI→policy is a command, M8). **§3.9 Scope model (§2)** — sound + right-sized; B13/B14/B4/B19 close the seams. **§3.10 Ratification readiness** — **not yet**: B1, B2, B3, B4, B6, B7, B12, B13, B14 are each an undefined/unsafe seam. With §2 applied: **yes**. **§4.1** strong fidelity-audited first attempt; A-architecture, B-algebra; not production-grade as written. **§4.2** weakness = incomplete, non-history-aware, non-bitemporal meet; improvement = the typed `PolicyLattice` + sticky semilattice. **§4.3** first runtime bug: B4/B19 (stale/out-of-force inputs) or B2 (a floor that tags but doesn't restrict) or B13 (a transitive merge across a firewall). **§4.4** skeptical authors: "where's `PolicyCeiling` and the floor bounds?" / "can't fixture the cascade or meet without ordering + the generation/time guard" / "five+ invariants had no lint and the §17.4 count is wrong." **§4.5** I'd write §3.2 as a typed lattice + domain contribution + generation/time precondition + coherence from the start, §2 with cluster-confidence + acyclic topology, §5 ordered/idempotent. **§4.6 — Revise**, one focused pass + the `PolicyLattice` module, then a delta re-review. ## 6. The A → A+ gap (ordered) - **To A:** B1, B2, B3, B4, B6, B7, B12, B13, B14 (the Blocking nine). - **To A+:** + B5, B8, B9, B10, B11, B15, B16, B17, B19, B21, S1–S7, M1–M11, and adopt NI-1 (property fixtures) + NI-5 (`PolicyLattice`) + the NI-2/NI-3 framing. Highest leverage: NI-5/§2.1 — discharges B2/B6/B10/B11 structurally. ## 7. Ranked top changes (1 = first) 1. **B7** sticky-restrictive (make L1 true). 2. **B6** disclosure coherence (axis + obligation). 3. **B1** `PolicyCeiling` + capture. 4. **B2** floor crosswalk. 5. **B3** own `RestrictivenessLevel` + wire domain into the meet (+ non-empty default). 6. **B13** firewall-safe equivalence. 7. **B14** acyclic topology + depth bound. 8. **B4** generation precondition. 9. **B19** bitemporal in-force filter. 10. **B12** render destination + egress gate (decision-only; controls → DOC5). 11. **B21** restamp trigger-authority. 12. **B5/B17** cascade ordering/idempotency + hold-dominance. 13. **S1/S2/S3** portability, Project↔scope seam, `LegalHoldClearance`. 14. the rest (B8–B11/B15/B16/S4–S7/M1–M11) + NI-1/NI-5. ## 8. Disposition ledger (for architect-batched adjudication) | ID | Type | Tier | Proposed disposition | |---|---|---|---| | B1 | BUG/GAP | Blocking | ACCEPT — `PolicyCeiling` (§2.5). | | B2 | GAP | Blocking | ACCEPT — floor crosswalk (§2.2); **confirm intermediate values**. | | B3 | GAP | Blocking | ACCEPT — own semantics + meet step-2 (§2.7). | | B4 | BUG | Blocking | ACCEPT — generation precondition (§2.4). | | B6 | BUG | Blocking | ACCEPT — coherence cap + obligation↔axis (§2.1/§2.6). | | B7 | BUG | Blocking | ACCEPT — sticky-restrictive + L1' (§2.4). | | B12 | BUG | Blocking | ACCEPT (reframed) — egress decision + class distinction; **controls → DOC5** (§1.5/§2.4). | | B13 | BUG | Blocking | ACCEPT — equivalence cluster + firewall guard (§2.10). | | B14 | BUG | Blocking | ACCEPT — acyclicity + depth bound (§2.10). | | B20 | GAP | — | **WITHDRAWN** — privilege not composable from sources (§1.5); kernel → DOC5 + sensitivity-input seam (referenced, not owned). | | B5 | GAP | Substantive | ACCEPT — cascade ordering/idempotency (§2.8). | | B8 | GAP | Substantive | ACCEPT — `DomainPolicyThresholds` (§2.7). | | B9 | GAP | Substantive | ACCEPT — transitive obligation precedence (§2.6). | | B10 | GAP | Substantive | ACCEPT — eligibility derivation (§2.7). | | B11 | INCONSISTENCY | Substantive | ACCEPT — floor order + reorder enum (§2.2). | | B15 | GAP | Substantive | ACCEPT — consumption-time re-gate (§2.9). | | B16 | BUG | Substantive | ACCEPT — coherence-last ordering (§2.4). | | B17 | GAP | Substantive | ACCEPT — hold dominates cascade (§2.8). | | B19 | GAP | Substantive | ACCEPT — bitemporal in-force filter (§2.4). | | B21 | GAP | Substantive | ACCEPT — restamp trigger-authority (§2.5); **confirm tier mapping**. | | S1 | GAP | Substantive | ACCEPT — portability invariant (§2.9). | | S2 | GAP | Substantive | ACCEPT — Project↔scope seam (§2.10). | | S3 | GAP | Substantive | ACCEPT — `LegalHoldClearance` (§2.9). | | S4 | GAP | Substantive | ACCEPT — Owner Map rows + citation fix (§2.12). | | S5 | GAP | Substantive | ACCEPT — classification rows + drop `E0DurableRecord` on derived (§2.12). | | S6 | BUG | Substantive | ACCEPT — booleans bounded by ordinal (§2.6). | | S7 | INCONSISTENCY | Substantive | ACCEPT — brand IDs (§2.3). | | M4↑ | GAP | Substantive | ACCEPT — destination crosswalk in §13.5 (§2.4). | | M1 | BUG(acc.) | Minor | ACCEPT — reword + route 5 E10 lints. | | M2 | GAP | Minor | ACCEPT — restore `model_class`/`client_kind`. | | M3 | SUGGESTION | Minor | ACCEPT — brand cascade refs. | | M5 | GAP | Minor | ACCEPT — golden-scenario phases + §20 row. | | M6 | SUGGESTION | Minor | ACCEPT — `defer` terminal + `expires_at`. | | M7 | SUGGESTION | Minor | ACCEPT — serialize epoch chain. | | M8 | SUGGESTION | Minor | ACCEPT — UI→policy command note. | | M9 | SUGGESTION | Minor | ACCEPT — bind to E0 `ReasonCodeRegistry`. | | M10 | SUGGESTION | Minor | FORWARD-FLAG — count/aggregate inference (Phase-2). | | M11 | SUGGESTION | Minor | ACCEPT — document content_fidelity as content-quantity. | | §13.2 / §13.1 / B18 / ADQ-221 / ADQ-316 | CONFIRMED | — | CONFIRM (B18 declined as finding; only M6). | --- *Finished review. Findings are typed, value-tiered, and traced to §+line; all code is paste-ready against the cited sections. The privilege/egress controls and the privilege-characterization taxonomy are out of DOC81 scope (§1.5) and route to the DOC5 security/authorization rebuild + memory governance.*