diff --git a/CHANGELOG.md b/CHANGELOG.md index 1263c3c1..34807b9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ ### Added +- `warp-core` optic invocation admission now has a narrow BasisResolution v0 + boundary. Identity-covered invocations with exact fixture basis bytes + `basis-request:resolved-fixture:v0` progress past basis resolution and still + obstruct at `UnsupportedApertureResolution`; all unsupported non-empty basis + shapes continue to obstruct at `UnsupportedBasisResolution`. This does not + issue admission tickets, law witnesses, scheduler work, execution, aperture + resolution, budget evaluation, runtime support checks, or successful grant + validation. - `warp-core` optic invocation admission now has a budget/runtime-support obstruction shell. Empty budget request bytes obstruct as `MissingBudgetRequest`; `UnsupportedBudgetResolution` and diff --git a/crates/warp-core/src/optic_artifact.rs b/crates/warp-core/src/optic_artifact.rs index 373d1ab5..e075839c 100644 --- a/crates/warp-core/src/optic_artifact.rs +++ b/crates/warp-core/src/optic_artifact.rs @@ -596,6 +596,8 @@ pub struct OpticInvocation { pub capability_presentation: Option, } +const OPTIC_BASIS_RESOLUTION_V0_FIXTURE_BYTES: &[u8] = b"basis-request:resolved-fixture:v0"; + /// Admission obstruction for an optic invocation. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum OpticInvocationObstruction { @@ -609,11 +611,11 @@ pub enum OpticInvocationObstruction { MissingApertureRequest, /// The invocation does not name any budget request bytes. MissingBudgetRequest, - /// The invocation reached basis resolution, but Echo has no basis resolver - /// wired into admission in this slice. + /// The invocation reached basis resolution, but the requested basis shape is + /// outside the narrow deterministic BasisResolution v0 fixture. UnsupportedBasisResolution, - /// The invocation reached aperture resolution, but Echo has no aperture - /// resolver wired into admission in this slice. + /// The invocation reached aperture resolution after BasisResolution v0, but + /// Echo has no aperture resolver wired into admission in this slice. UnsupportedApertureResolution, /// The invocation reached budget resolution, but Echo has no budget /// evaluator wired into admission in this slice. @@ -1183,7 +1185,8 @@ impl OpticArtifactRegistry { validation, CapabilityGrantValidationOutcome::IdentityCovered(_) ) { - final_obstruction = OpticInvocationObstruction::UnsupportedBasisResolution; + final_obstruction = Self::resolve_basis_v0(&invocation.basis_request) + .unwrap_or(OpticInvocationObstruction::UnsupportedApertureResolution); } } @@ -1200,6 +1203,14 @@ impl OpticArtifactRegistry { None } + fn resolve_basis_v0(basis_request: &OpticBasisRequest) -> Option { + if basis_request.bytes == OPTIC_BASIS_RESOLUTION_V0_FIXTURE_BYTES { + return None; + } + + Some(OpticInvocationObstruction::UnsupportedBasisResolution) + } + fn classify_aperture_request( aperture_request: &OpticApertureRequest, ) -> Option { diff --git a/crates/warp-core/tests/optic_invocation_admission_tests.rs b/crates/warp-core/tests/optic_invocation_admission_tests.rs index 1a3bd03d..936fda48 100644 --- a/crates/warp-core/tests/optic_invocation_admission_tests.rs +++ b/crates/warp-core/tests/optic_invocation_admission_tests.rs @@ -101,6 +101,17 @@ fn fixture_invocation(handle: OpticArtifactHandle) -> OpticInvocation { } } +fn fixture_invocation_with_resolved_basis_and_presentation( + handle: OpticArtifactHandle, + grant_id: &str, +) -> OpticInvocation { + let mut invocation = fixture_invocation_with_presentation(handle, grant_id); + invocation.basis_request = OpticBasisRequest { + bytes: b"basis-request:resolved-fixture:v0".to_vec(), + }; + invocation +} + fn expected_obstructed_posture( invocation: &OpticInvocation, obstruction: OpticInvocationObstruction, @@ -795,6 +806,56 @@ fn runtime_support_unavailable_is_defined_but_unreachable_until_basis_resolution Ok(()) } +#[test] +fn unsupported_basis_still_stops_at_unsupported_basis_resolution() -> Result<(), String> { + let (mut registry, handle) = fixture_registry_and_handle()?; + let invocation = fixture_invocation_with_presentation(handle, "grant:covered"); + let mut gate = fixture_gate_with_grant(fixture_grant("grant:covered")); + + let outcome = registry.admit_optic_invocation_with_capability_validator(&invocation, &mut gate); + + assert_eq!( + obstruction_for(&outcome), + OpticInvocationObstruction::UnsupportedBasisResolution + ); + assert!(matches!( + latest_invocation_obstruction_fact(®istry)?, + GraphFact::OpticInvocationObstructed { + obstruction, + .. + } if *obstruction == InvocationObstructionKind::UnsupportedBasisResolution + )); + Ok(()) +} + +#[test] +fn resolved_basis_still_obstructs_before_aperture_resolution() -> Result<(), String> { + let (mut registry, handle) = fixture_registry_and_handle()?; + let invocation = + fixture_invocation_with_resolved_basis_and_presentation(handle, "grant:covered"); + let mut gate = fixture_gate_with_grant(fixture_grant("grant:covered")); + + let outcome = registry.admit_optic_invocation_with_capability_validator(&invocation, &mut gate); + + assert_eq!( + obstruction_for(&outcome), + OpticInvocationObstruction::UnsupportedApertureResolution + ); + assert!(matches!( + latest_invocation_obstruction_fact(®istry)?, + GraphFact::OpticInvocationObstructed { + basis_request_digest, + obstruction, + .. + } if *basis_request_digest == digest_invocation_request_bytes( + b"echo.optic-invocation.basis-request.v0", + b"basis-request:resolved-fixture:v0" + ) + && *obstruction == InvocationObstructionKind::UnsupportedApertureResolution + )); + Ok(()) +} + #[test] fn invocation_obstruction_fact_is_not_counterfactual_candidate() -> Result<(), String> { let (mut registry, handle) = fixture_registry_and_handle()?; diff --git a/docs/design/optic-admission-ladder-checkpoint.md b/docs/design/optic-admission-ladder-checkpoint.md index 03c9639b..5965a02b 100644 --- a/docs/design/optic-admission-ladder-checkpoint.md +++ b/docs/design/optic-admission-ladder-checkpoint.md @@ -3,21 +3,22 @@ # Optic Admission Ladder Checkpoint -Status: checkpoint. -Scope: documentation-only refusal ladder before BasisResolution v0. +Status: BasisResolution v0 boundary checkpoint. +Scope: refusal ladder with one narrow controlled basis-resolution fixture. ## Doctrine -This checkpoint records the optic invocation admission ladder exactly at the -last refusal-only boundary. +This checkpoint records the optic invocation admission ladder at the first +controlled basis-resolution boundary. Echo can now explain why an optic invocation is refused, but it cannot yet admit one. There is no successful admission path in this checkpoint. A registered artifact handle is not authority. A capability presentation slot is -not a validated grant. A basis request is not a resolved basis. An aperture -request is not a resolved scope. A budget request is not spendable runtime -capacity. +not a validated grant. A basis request is not a resolved basis unless it matches +the narrow deterministic BasisResolution v0 fixture. A resolved basis is not +permission to act. An aperture request is not a resolved scope. A budget request +is not spendable runtime capacity. Refusal is causal evidence. Refusal is not admission, not execution, not a law witness, and not a counterfactual candidate. @@ -34,34 +35,40 @@ The current optic invocation admission path evaluates checks in this order: 6. Require budget request presence. 7. Classify capability presentation posture. 8. Optionally publish grant-validation obstruction evidence. -9. Obstruct identity-covered material at unsupported basis resolution. -10. Publish the invocation obstruction fact. +9. If capability validation returns identity-covered material, resolve the + narrow BasisResolution v0 fixture or obstruct unsupported basis material. +10. If that basis fixture resolves, obstruct before aperture resolution. +11. Publish the invocation obstruction fact. Presence checks come before resolution checks. Basis resolution gates aperture resolution. Aperture resolution gates budget evaluation and runtime support -checks. +checks. BasisResolution v0 accepts exactly one deterministic fixture shape: +`basis-request:resolved-fixture:v0`. ## Obstruction reachability -| Obstruction | Reachability | Meaning | -| :-------------------------------- | :---------------- | :--------------------------------------------------------------------------------------------------------- | -| `UnknownHandle` | Reachable today | Echo cannot resolve the runtime-local artifact handle. | -| `OperationMismatch` | Reachable today | The invocation operation does not match registered artifact metadata. | -| `MissingBasisRequest` | Reachable today | The caller did not provide basis request material. | -| `MissingApertureRequest` | Reachable today | Basis material is present, but aperture request material is absent. | -| `MissingBudgetRequest` | Reachable today | Basis and aperture material are present, but budget request material is absent. | -| `MissingCapability` | Reachable today | Required invocation context is present, but no capability presentation was supplied. | -| `MalformedCapabilityPresentation` | Reachable today | Capability presentation material is present but not structurally usable. | -| `UnboundCapabilityPresentation` | Reachable today | Capability presentation material is structurally usable but not bound to the invocation. | -| `CapabilityValidationUnavailable` | Reachable today | Presentation material is identity-covered, but real grant validation does not exist yet. | -| `UnsupportedBasisResolution` | Reachable today | Identity-covered material reaches the resolution boundary, but lawful basis resolution does not exist yet. | -| `UnsupportedApertureResolution` | Future vocabulary | Must remain unreachable until lawful basis resolution exists. | -| `UnsupportedBudgetResolution` | Future vocabulary | Must remain unreachable until lawful basis and aperture resolution exist. | -| `RuntimeSupportUnavailable` | Future vocabulary | Must remain unreachable until lawful basis, aperture, and budget resolution exist. | - -`UnsupportedApertureResolution`, `UnsupportedBudgetResolution`, and -`RuntimeSupportUnavailable` are deliberately defined but not lawfully reachable -at this checkpoint. +| Obstruction | Reachability | Meaning | +| :-------------------------------- | :---------------- | :------------------------------------------------------------------------------------------------------- | +| `UnknownHandle` | Reachable today | Echo cannot resolve the runtime-local artifact handle. | +| `OperationMismatch` | Reachable today | The invocation operation does not match registered artifact metadata. | +| `MissingBasisRequest` | Reachable today | The caller did not provide basis request material. | +| `MissingApertureRequest` | Reachable today | Basis material is present, but aperture request material is absent. | +| `MissingBudgetRequest` | Reachable today | Basis and aperture material are present, but budget request material is absent. | +| `MissingCapability` | Reachable today | Required invocation context is present, but no capability presentation was supplied. | +| `MalformedCapabilityPresentation` | Reachable today | Capability presentation material is present but not structurally usable. | +| `UnboundCapabilityPresentation` | Reachable today | Capability presentation material is structurally usable but not bound to the invocation. | +| `CapabilityValidationUnavailable` | Reachable today | A bound presentation exists, but no successful validation or admission has occurred yet. | +| `UnsupportedBasisResolution` | Reachable today | Identity-covered material reaches the basis boundary, but the basis shape is outside BasisResolution v0. | +| `UnsupportedApertureResolution` | Reachable today | BasisResolution v0 succeeded, but aperture resolution does not exist yet. | +| `UnsupportedBudgetResolution` | Future vocabulary | Must remain unreachable until lawful basis and aperture resolution exist. | +| `RuntimeSupportUnavailable` | Future vocabulary | Must remain unreachable until lawful basis, aperture, and budget resolution exist. | + +`UnsupportedBudgetResolution` and `RuntimeSupportUnavailable` are deliberately +defined but not lawfully reachable at this checkpoint. + +`UnsupportedApertureResolution` is reachable only after the exact +BasisResolution v0 fixture resolves. For identity-covered material, unsupported +basis shapes must still stop at `UnsupportedBasisResolution`. ## Non-behavior @@ -79,31 +86,39 @@ This checkpoint does not introduce: - runtime support enforcement - budget reservation - aperture resolution -- basis resolution The system remains obstruction-first. It records refusal; it does not authorize work. -## Next transition point +## BasisResolution v0 + +BasisResolution v0 is not general basis resolution. It recognizes exactly one +deterministic fixture shape: + +```text +basis-request:resolved-fixture:v0 +``` -The next transition point is BasisResolution v0. +Resolving that fixture establishes only the causal state under evaluation. It +does not create authority, admission, aperture scope, budget capacity, runtime +support, scheduler work, or execution. + +## Next transition point -BasisResolution v0 is the first controlled resolved-state boundary. It is the -first place where Echo may start saying something stronger than refusal about a -requested invocation context. +The next transition point is ApertureResolution v0. That transition must be narrow and explicit. It must not imply successful -admission, aperture resolution, budget spendability, runtime support, execution, -or authority validation. +admission, budget spendability, runtime support, execution, or authority +validation. ## Tripwire -If a future slice makes `UnsupportedApertureResolution`, -`UnsupportedBudgetResolution`, or `RuntimeSupportUnavailable` reachable before a -lawful basis resolution boundary exists, the admission ladder is wrong. +If a future slice makes `UnsupportedBudgetResolution` or +`RuntimeSupportUnavailable` reachable before a lawful aperture resolution +boundary exists, the admission ladder is wrong. If a future slice introduces a successful admission path before a resolved basis, resolved aperture, evaluated budget, runtime support check, and validated grant exist, the admission ladder is wrong. -This is the final refusal-only checkpoint before controlled resolved state. +BasisResolution v0 is controlled resolved state, not admission.