From b7f8fcde2cecf267885245e0ba646d9ae864b9fd Mon Sep 17 00:00:00 2001 From: James Ross Date: Tue, 19 May 2026 00:02:41 -0700 Subject: [PATCH 1/2] feat(core): add scheduler admission v0 boundary --- crates/warp-core/src/causal_facts.rs | 45 +++- crates/warp-core/src/optic_artifact.rs | 111 ++++++++- .../tests/causal_fact_publication_tests.rs | 80 ++++++ .../tests/optic_invocation_admission_tests.rs | 235 ++++++++++++++++++ 4 files changed, 464 insertions(+), 7 deletions(-) diff --git a/crates/warp-core/src/causal_facts.rs b/crates/warp-core/src/causal_facts.rs index 3c8ccb24..c6053711 100644 --- a/crates/warp-core/src/causal_facts.rs +++ b/crates/warp-core/src/causal_facts.rs @@ -66,9 +66,11 @@ pub enum InvocationObstructionKind { /// Echo proved runtime support, but this slice still has no lawful /// invocation admission path. InvocationAdmissionUnavailable, - /// Echo proved invocation admission, but scheduler admission/work enqueueing - /// does not exist in this slice. + /// Echo proved invocation admission, but has no scheduler admission fact. SchedulerAdmissionUnavailable, + /// Echo proved scheduler admission, but this slice still has no scheduler + /// work candidate or queue item. + SchedulerWorkUnavailable, /// Invocation supplied no capability presentation. MissingCapability, /// Invocation supplied a malformed capability presentation. @@ -116,6 +118,7 @@ impl InvocationObstructionKind { Self::RuntimeSupportUnavailable => b"runtime-support-unavailable", Self::InvocationAdmissionUnavailable => b"invocation-admission-unavailable", Self::SchedulerAdmissionUnavailable => b"scheduler-admission-unavailable", + Self::SchedulerWorkUnavailable => b"scheduler-work-unavailable", Self::MissingCapability => b"missing-capability", Self::MalformedCapabilityPresentation => b"malformed-capability-presentation", Self::UnboundCapabilityPresentation => b"unbound-capability-presentation", @@ -195,6 +198,20 @@ pub enum GraphFact { /// Digest of the Echo-owned invocation admission material. admission_digest: [u8; 32], }, + /// Echo recorded runtime-owned scheduler admission evidence for a + /// registered artifact handle. + SchedulerAdmissionRecorded { + /// Echo-owned runtime-local artifact handle id covered by the scheduler + /// admission fact. + artifact_handle_id: String, + /// Registered operation id covered by the scheduler admission fact. + operation_id: String, + /// Registered requirements digest covered by the scheduler admission + /// fact. + requirements_digest: String, + /// Digest of the Echo-owned scheduler admission material. + scheduler_admission_digest: [u8; 32], + }, /// Echo refused optic invocation before admission success. OpticInvocationObstructed { /// Echo-owned runtime-local artifact handle id named by the invocation. @@ -308,6 +325,30 @@ impl GraphFact { ); push_digest_field(&mut bytes, b"admission-digest", admission_digest); } + Self::SchedulerAdmissionRecorded { + artifact_handle_id, + operation_id, + requirements_digest, + scheduler_admission_digest, + } => { + push_digest_field(&mut bytes, b"variant", b"scheduler-admission-recorded"); + push_digest_field( + &mut bytes, + b"artifact-handle-id", + artifact_handle_id.as_bytes(), + ); + push_digest_field(&mut bytes, b"operation-id", operation_id.as_bytes()); + push_digest_field( + &mut bytes, + b"requirements-digest", + requirements_digest.as_bytes(), + ); + push_digest_field( + &mut bytes, + b"scheduler-admission-digest", + scheduler_admission_digest, + ); + } Self::OpticInvocationObstructed { artifact_handle_id, operation_id, diff --git a/crates/warp-core/src/optic_artifact.rs b/crates/warp-core/src/optic_artifact.rs index e90e0700..fb189781 100644 --- a/crates/warp-core/src/optic_artifact.rs +++ b/crates/warp-core/src/optic_artifact.rs @@ -606,6 +606,10 @@ const OPTIC_INVOCATION_ADMISSION_V0_FIXTURE_BYTES: &[u8] = b"invocation-admission:resolved-fixture:v0"; const OPTIC_INVOCATION_ADMISSION_V0_FIXTURE_DIGEST_DOMAIN: &[u8] = b"echo.optic-invocation-admission.fixture.v0"; +const OPTIC_SCHEDULER_ADMISSION_V0_FIXTURE_BYTES: &[u8] = + b"scheduler-admission:resolved-fixture:v0"; +const OPTIC_SCHEDULER_ADMISSION_V0_FIXTURE_DIGEST_DOMAIN: &[u8] = + b"echo.optic-scheduler-admission.fixture.v0"; /// Admission obstruction for an optic invocation. #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -636,9 +640,11 @@ pub enum OpticInvocationObstruction { /// Echo proved runtime support, but this slice still cannot lawfully admit /// the invocation. InvocationAdmissionUnavailable, - /// Echo proved invocation admission, but scheduler admission/work enqueueing - /// does not exist in this slice. + /// Echo proved invocation admission, but has no scheduler admission fact. SchedulerAdmissionUnavailable, + /// Echo proved scheduler admission, but scheduler work candidates do not + /// exist in this slice. + SchedulerWorkUnavailable, /// The invocation does not carry authority to use the registered artifact. MissingCapability, /// The invocation carries a presentation that is structurally unusable. @@ -1048,6 +1054,13 @@ fn invocation_admission_v0_fixture_digest() -> [u8; 32] { ) } +fn scheduler_admission_v0_fixture_digest() -> [u8; 32] { + digest_invocation_request_bytes( + OPTIC_SCHEDULER_ADMISSION_V0_FIXTURE_DIGEST_DOMAIN, + OPTIC_SCHEDULER_ADMISSION_V0_FIXTURE_BYTES, + ) +} + /// Echo-owned runtime-local registry for Wesley-compiled optic artifacts. #[derive(Clone, Debug, Default)] pub struct OpticArtifactRegistry { @@ -1055,6 +1068,7 @@ pub struct OpticArtifactRegistry { artifacts_by_handle: BTreeMap, runtime_support_v0_by_requirements: BTreeMap, invocation_admission_v0_by_artifact: BTreeMap, + scheduler_admission_v0_by_artifact: BTreeMap, published_graph_facts: Vec, artifact_registration_receipts: Vec, } @@ -1159,6 +1173,33 @@ impl OpticArtifactRegistry { Ok(()) } + /// Records Echo-owned SchedulerAdmission v0 fixture evidence for a + /// registered artifact handle. + /// + /// This is runtime context, not invocation context. Callers cannot provide + /// scheduler admission evidence through [`OpticInvocation`]; the admission + /// ladder only consults facts recorded on this registry. + /// + /// # Errors + /// + /// Returns [`OpticArtifactRegistrationError::UnknownHandle`] if Echo did not + /// issue the handle in this registry instance. + pub fn record_scheduler_admission_v0_fixture_for_artifact( + &mut self, + handle: &OpticArtifactHandle, + ) -> Result<(), OpticArtifactRegistrationError> { + let registered = self.resolve_optic_artifact_handle(handle)?; + let artifact_handle_id = registered.handle.id.clone(); + let operation_id = registered.operation_id.clone(); + let requirements_digest = registered.requirements_digest.clone(); + self.record_scheduler_admission_v0_fixture_for_artifact_id( + artifact_handle_id, + operation_id, + requirements_digest, + ); + Ok(()) + } + fn record_runtime_support_v0_fixture_for_requirements_digest( &mut self, requirements_digest: String, @@ -1194,6 +1235,27 @@ impl OpticArtifactRegistry { } } + fn record_scheduler_admission_v0_fixture_for_artifact_id( + &mut self, + artifact_handle_id: String, + operation_id: String, + requirements_digest: String, + ) { + let scheduler_admission_digest = scheduler_admission_v0_fixture_digest(); + if self + .scheduler_admission_v0_by_artifact + .insert(artifact_handle_id.clone(), scheduler_admission_digest) + .is_none() + { + self.publish_scheduler_admission_recorded_fact( + artifact_handle_id, + operation_id, + requirements_digest, + scheduler_admission_digest, + ); + } + } + /// Resolves an opaque Echo handle to registered artifact metadata. /// /// # Errors @@ -1315,9 +1377,14 @@ impl OpticArtifactRegistry { self.resolve_invocation_admission_v0_for_artifact( ®istered.handle.id, ) - .unwrap_or( - OpticInvocationObstruction::SchedulerAdmissionUnavailable, - ) + .unwrap_or_else(|| { + self.resolve_scheduler_admission_v0_for_artifact( + ®istered.handle.id, + ) + .unwrap_or( + OpticInvocationObstruction::SchedulerWorkUnavailable, + ) + }) }) }, ) @@ -1396,6 +1463,20 @@ impl OpticArtifactRegistry { Some(OpticInvocationObstruction::InvocationAdmissionUnavailable) } + fn resolve_scheduler_admission_v0_for_artifact( + &self, + artifact_handle_id: &str, + ) -> Option { + if self + .scheduler_admission_v0_by_artifact + .contains_key(artifact_handle_id) + { + return None; + } + + Some(OpticInvocationObstruction::SchedulerAdmissionUnavailable) + } + fn classify_aperture_request( aperture_request: &OpticApertureRequest, ) -> Option { @@ -1589,6 +1670,23 @@ impl OpticArtifactRegistry { )); } + fn publish_scheduler_admission_recorded_fact( + &mut self, + artifact_handle_id: String, + operation_id: String, + requirements_digest: String, + scheduler_admission_digest: [u8; 32], + ) { + self.published_graph_facts.push(PublishedGraphFact::new( + GraphFact::SchedulerAdmissionRecorded { + artifact_handle_id, + operation_id, + requirements_digest, + scheduler_admission_digest, + }, + )); + } + fn publish_invocation_obstruction_fact( &mut self, invocation: &OpticInvocation, @@ -1675,6 +1773,9 @@ fn invocation_obstruction_kind( OpticInvocationObstruction::SchedulerAdmissionUnavailable => { InvocationObstructionKind::SchedulerAdmissionUnavailable } + OpticInvocationObstruction::SchedulerWorkUnavailable => { + InvocationObstructionKind::SchedulerWorkUnavailable + } OpticInvocationObstruction::MissingCapability => { InvocationObstructionKind::MissingCapability } diff --git a/crates/warp-core/tests/causal_fact_publication_tests.rs b/crates/warp-core/tests/causal_fact_publication_tests.rs index fb5d1251..142cb2c8 100644 --- a/crates/warp-core/tests/causal_fact_publication_tests.rs +++ b/crates/warp-core/tests/causal_fact_publication_tests.rs @@ -283,6 +283,75 @@ fn invocation_admission_v0_fixture_rejects_unknown_handle_without_graph_fact() - Ok(()) } +#[test] +fn scheduler_admission_fixture_publishes_graph_fact_once() -> Result<(), String> { + let mut registry = OpticArtifactRegistry::new(); + let handle = registry + .register_optic_artifact(fixture_artifact(), fixture_descriptor()) + .map_err(|err| format!("fixture descriptor should register: {err:?}"))?; + + registry + .record_scheduler_admission_v0_fixture_for_artifact(&handle) + .map_err(|err| format!("registered handle should record scheduler admission: {err:?}"))?; + registry + .record_scheduler_admission_v0_fixture_for_artifact(&handle) + .map_err(|err| format!("repeated handle should remain idempotent: {err:?}"))?; + + let scheduler_facts = registry + .published_graph_facts() + .iter() + .filter_map(|published| match &published.fact { + GraphFact::SchedulerAdmissionRecorded { + artifact_handle_id, + operation_id, + requirements_digest, + scheduler_admission_digest, + } => Some(( + artifact_handle_id, + operation_id, + requirements_digest, + scheduler_admission_digest, + )), + _ => None, + }) + .collect::>(); + assert_eq!(scheduler_facts.len(), 1); + let (artifact_handle_id, operation_id, requirements_digest, scheduler_admission_digest) = + scheduler_facts[0]; + assert_eq!(artifact_handle_id, &handle.id); + assert_eq!(operation_id, "operation:textWindow:v0"); + assert_eq!( + requirements_digest, + "requirements-digest:stack-witness-0001" + ); + assert_ne!(*scheduler_admission_digest, [0_u8; 32]); + Ok(()) +} + +#[test] +fn scheduler_admission_fixture_rejects_unknown_handle_without_graph_fact() -> Result<(), String> { + let mut registry = OpticArtifactRegistry::new(); + registry + .register_optic_artifact(fixture_artifact(), fixture_descriptor()) + .map_err(|err| format!("fixture descriptor should register: {err:?}"))?; + let unknown_handle = OpticArtifactHandle { + kind: "optic-artifact-handle".to_owned(), + id: "unregistered-handle".to_owned(), + }; + + let err = registration_err_or_panic( + registry.record_scheduler_admission_v0_fixture_for_artifact(&unknown_handle), + "unknown artifact handle should reject scheduler admission recording", + )?; + + assert!(matches!(err, OpticArtifactRegistrationError::UnknownHandle)); + assert_eq!(registry.published_graph_facts().len(), 1); + assert!(!registry.published_graph_facts().iter().any(|published| { + matches!(published.fact, GraphFact::SchedulerAdmissionRecorded { .. }) + })); + Ok(()) +} + #[test] fn graph_fact_digest_is_deterministic_and_kind_separated() { let registered = GraphFact::ArtifactRegistered { @@ -309,15 +378,26 @@ fn graph_fact_digest_is_deterministic_and_kind_separated() { admission_digest: [8_u8; 32], }; let repeated_admission = admission.clone(); + let scheduler = GraphFact::SchedulerAdmissionRecorded { + artifact_handle_id: "handle-1".to_owned(), + operation_id: "operation".to_owned(), + requirements_digest: "requirements".to_owned(), + scheduler_admission_digest: [9_u8; 32], + }; + let repeated_scheduler = scheduler.clone(); assert_eq!(registered.digest(), repeated.digest()); assert_ne!(registered.digest(), obstructed.digest()); assert_eq!(support.digest(), repeated_support.digest()); assert_eq!(admission.digest(), repeated_admission.digest()); + assert_eq!(scheduler.digest(), repeated_scheduler.digest()); assert_ne!(registered.digest(), support.digest()); assert_ne!(obstructed.digest(), support.digest()); assert_ne!(support.digest(), admission.digest()); + assert_ne!(support.digest(), scheduler.digest()); + assert_ne!(admission.digest(), scheduler.digest()); assert_ne!(registered.digest(), admission.digest()); + assert_ne!(registered.digest(), scheduler.digest()); } #[test] diff --git a/crates/warp-core/tests/optic_invocation_admission_tests.rs b/crates/warp-core/tests/optic_invocation_admission_tests.rs index 4f63dfcc..b070cedc 100644 --- a/crates/warp-core/tests/optic_invocation_admission_tests.rs +++ b/crates/warp-core/tests/optic_invocation_admission_tests.rs @@ -1416,6 +1416,241 @@ fn resolved_invocation_admission_advances_to_scheduler_admission_unavailable() - Ok(()) } +#[test] +fn resolved_invocation_admission_still_requires_scheduler_admission() -> Result<(), String> { + let (mut registry, handle) = fixture_registry_and_handle()?; + registry + .record_runtime_support_v0_fixture_for_artifact(&handle) + .map_err(|err| format!("registered handle should record runtime support: {err:?}"))?; + registry + .record_invocation_admission_v0_fixture_for_artifact(&handle) + .map_err(|err| format!("registered handle should record invocation admission: {err:?}"))?; + let invocation = fixture_invocation_with_resolved_basis_aperture_budget_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::SchedulerAdmissionUnavailable + ); + assert!(matches!( + latest_invocation_obstruction_fact(®istry)?, + GraphFact::OpticInvocationObstructed { + obstruction, + .. + } if *obstruction == InvocationObstructionKind::SchedulerAdmissionUnavailable + )); + Ok(()) +} + +#[test] +fn caller_cannot_supply_scheduler_admission_testimony() -> Result<(), String> { + let (mut registry, handle) = fixture_registry_and_handle()?; + registry + .record_runtime_support_v0_fixture_for_artifact(&handle) + .map_err(|err| format!("registered handle should record runtime support: {err:?}"))?; + registry + .record_invocation_admission_v0_fixture_for_artifact(&handle) + .map_err(|err| format!("registered handle should record invocation admission: {err:?}"))?; + let mut invocation = fixture_invocation_with_resolved_basis_aperture_budget_and_presentation( + handle, + "scheduler-admission:resolved-fixture:v0", + ); + invocation.canonical_variables_digest = b"scheduler-admission:resolved-fixture:v0".to_vec(); + invocation.capability_presentation = Some(OpticCapabilityPresentation { + presentation_id: "scheduler-admission:resolved-fixture:v0".to_owned(), + bound_grant_id: Some("scheduler-admission:resolved-fixture:v0".to_owned()), + }); + let mut gate = + fixture_gate_with_grant(fixture_grant("scheduler-admission:resolved-fixture:v0")); + + let outcome = registry.admit_optic_invocation_with_capability_validator(&invocation, &mut gate); + assert_eq!( + obstruction_for(&outcome), + OpticInvocationObstruction::SchedulerAdmissionUnavailable + ); + + registry + .record_scheduler_admission_v0_fixture_for_artifact(&invocation.artifact_handle) + .map_err(|err| format!("registered handle should record scheduler admission: {err:?}"))?; + let outcome = registry.admit_optic_invocation_with_capability_validator(&invocation, &mut gate); + assert_eq!( + obstruction_for(&outcome), + OpticInvocationObstruction::SchedulerWorkUnavailable + ); + Ok(()) +} + +#[test] +fn scheduler_admission_uses_echo_owned_fixture_only() -> Result<(), String> { + let (mut registry, handle) = fixture_registry_and_handle()?; + registry + .record_runtime_support_v0_fixture_for_artifact(&handle) + .map_err(|err| format!("registered handle should record runtime support: {err:?}"))?; + registry + .record_invocation_admission_v0_fixture_for_artifact(&handle) + .map_err(|err| format!("registered handle should record invocation admission: {err:?}"))?; + let mut invocation = fixture_invocation_with_resolved_basis_aperture_budget_and_presentation( + handle, + "grant:covered", + ); + invocation.canonical_variables_digest = b"caller-claims:scheduler-admission-resolved".to_vec(); + 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::SchedulerAdmissionUnavailable + ); + + registry + .record_scheduler_admission_v0_fixture_for_artifact(&invocation.artifact_handle) + .map_err(|err| format!("registered handle should record scheduler admission: {err:?}"))?; + let outcome = registry.admit_optic_invocation_with_capability_validator(&invocation, &mut gate); + assert_eq!( + obstruction_for(&outcome), + OpticInvocationObstruction::SchedulerWorkUnavailable + ); + Ok(()) +} + +#[test] +fn scheduler_admission_is_checked_only_after_invocation_admission() -> Result<(), String> { + let (mut registry, handle) = fixture_registry_and_handle()?; + registry + .record_scheduler_admission_v0_fixture_for_artifact(&handle) + .map_err(|err| format!("registered handle should record scheduler admission: {err:?}"))?; + let mut gate = fixture_gate_with_grant(fixture_grant("grant:covered")); + + let mut unsupported_basis = + fixture_invocation_with_resolved_basis_aperture_budget_and_presentation( + handle.clone(), + "grant:covered", + ); + unsupported_basis.basis_request = OpticBasisRequest { + bytes: b"basis-request:unsupported".to_vec(), + }; + let outcome = + registry.admit_optic_invocation_with_capability_validator(&unsupported_basis, &mut gate); + assert_eq!( + obstruction_for(&outcome), + OpticInvocationObstruction::UnsupportedBasisResolution + ); + + let mut unsupported_aperture = + fixture_invocation_with_resolved_basis_aperture_budget_and_presentation( + handle.clone(), + "grant:covered", + ); + unsupported_aperture.aperture_request = OpticApertureRequest { + bytes: b"aperture-request:unsupported".to_vec(), + }; + let outcome = + registry.admit_optic_invocation_with_capability_validator(&unsupported_aperture, &mut gate); + assert_eq!( + obstruction_for(&outcome), + OpticInvocationObstruction::UnsupportedApertureResolution + ); + + let mut unsupported_budget = + fixture_invocation_with_resolved_basis_aperture_budget_and_presentation( + handle.clone(), + "grant:covered", + ); + unsupported_budget.budget_request = OpticBudgetRequest { + bytes: b"budget-request:unsupported".to_vec(), + }; + let outcome = + registry.admit_optic_invocation_with_capability_validator(&unsupported_budget, &mut gate); + assert_eq!( + obstruction_for(&outcome), + OpticInvocationObstruction::UnsupportedBudgetResolution + ); + + let supported_shape_without_support_fact = + fixture_invocation_with_resolved_basis_aperture_budget_and_presentation( + handle.clone(), + "grant:covered", + ); + let outcome = registry.admit_optic_invocation_with_capability_validator( + &supported_shape_without_support_fact, + &mut gate, + ); + assert_eq!( + obstruction_for(&outcome), + OpticInvocationObstruction::RuntimeSupportUnavailable + ); + + registry + .record_runtime_support_v0_fixture_for_artifact(&handle) + .map_err(|err| format!("registered handle should record runtime support: {err:?}"))?; + let supported_shape_without_invocation_admission = + fixture_invocation_with_resolved_basis_aperture_budget_and_presentation( + handle, + "grant:covered", + ); + let outcome = registry.admit_optic_invocation_with_capability_validator( + &supported_shape_without_invocation_admission, + &mut gate, + ); + assert_eq!( + obstruction_for(&outcome), + OpticInvocationObstruction::InvocationAdmissionUnavailable + ); + Ok(()) +} + +#[test] +fn resolved_scheduler_admission_advances_to_scheduler_work_unavailable() -> Result<(), String> { + let (mut registry, handle) = fixture_registry_and_handle()?; + registry + .record_runtime_support_v0_fixture_for_artifact(&handle) + .map_err(|err| format!("registered handle should record runtime support: {err:?}"))?; + registry + .record_invocation_admission_v0_fixture_for_artifact(&handle) + .map_err(|err| format!("registered handle should record invocation admission: {err:?}"))?; + registry + .record_scheduler_admission_v0_fixture_for_artifact(&handle) + .map_err(|err| format!("registered handle should record scheduler admission: {err:?}"))?; + let invocation = fixture_invocation_with_resolved_basis_aperture_budget_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!(matches!( + outcome, + OpticInvocationAdmissionOutcome::Obstructed(OpticAdmissionTicketPosture { + obstruction: OpticInvocationObstruction::SchedulerWorkUnavailable, + .. + }) + )); + assert!(matches!( + latest_invocation_obstruction_fact(®istry)?, + GraphFact::OpticInvocationObstructed { + obstruction, + .. + } if *obstruction == InvocationObstructionKind::SchedulerWorkUnavailable + )); + assert!(registry.published_graph_facts().iter().all(|published| { + matches!( + published.fact, + GraphFact::ArtifactRegistered { .. } + | GraphFact::RuntimeSupportRecorded { .. } + | GraphFact::InvocationAdmissionRecorded { .. } + | GraphFact::SchedulerAdmissionRecorded { .. } + | GraphFact::OpticInvocationObstructed { .. } + ) + })); + Ok(()) +} + #[test] fn invocation_obstruction_fact_is_not_counterfactual_candidate() -> Result<(), String> { let (mut registry, handle) = fixture_registry_and_handle()?; From d266303f2a57dde6d7fe639516817121f7538b9b Mon Sep 17 00:00:00 2001 From: James Ross Date: Tue, 19 May 2026 00:03:23 -0700 Subject: [PATCH 2/2] docs: record scheduler admission v0 boundary --- CHANGELOG.md | 13 ++++ ...get-and-runtime-support-optic-admission.md | 41 +++++++---- .../optic-admission-ladder-checkpoint.md | 72 ++++++++++++++----- 3 files changed, 97 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4531283c..0dcd38de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ ### Added +- `warp-core` optic invocation admission now has a narrow SchedulerAdmission v0 + boundary. After BasisResolution v0, ApertureResolution v0, BudgetResolution + v0, RuntimeSupport v0, capability identity coverage, and InvocationAdmission + v0 all resolve, Echo checks runtime-owned scheduler admission facts for the + registered artifact handle. Without that Echo-owned scheduler admission fact, + the ladder obstructs at `SchedulerAdmissionUnavailable`; with the exact + `scheduler-admission:resolved-fixture:v0` scheduler admission fixture, the + ladder advances to `SchedulerWorkUnavailable`. Scheduler admission fixture + recording is scoped through Echo-issued artifact handles, publishes + idempotent graph facts, and rejects unknown handles without publishing + scheduler admission evidence. This does not add admission tickets, law + witnesses, scheduler work, scheduler enqueueing, handler dispatch, execution, + or caller-supplied scheduler admission testimony. - `warp-core` optic invocation admission now has a narrow InvocationAdmission v0 boundary. After BasisResolution v0, ApertureResolution v0, BudgetResolution v0, RuntimeSupport v0, and capability identity coverage all resolve, Echo diff --git a/docs/design/budget-and-runtime-support-optic-admission.md b/docs/design/budget-and-runtime-support-optic-admission.md index c5902f38..5905f681 100644 --- a/docs/design/budget-and-runtime-support-optic-admission.md +++ b/docs/design/budget-and-runtime-support-optic-admission.md @@ -36,7 +36,9 @@ resolved basis + unsupported aperture -> UnsupportedApertureResolution resolved aperture + unsupported budget -> UnsupportedBudgetResolution resolved budget + no Echo-owned runtime support fact -> RuntimeSupportUnavailable resolved runtime support + no Echo-owned admission fact -> InvocationAdmissionUnavailable -resolved invocation admission -> SchedulerAdmissionUnavailable +resolved invocation admission + no Echo-owned scheduler admission fact + -> SchedulerAdmissionUnavailable +resolved scheduler admission -> SchedulerWorkUnavailable ``` `UnsupportedBudgetResolution` and `RuntimeSupportUnavailable` are current @@ -66,11 +68,12 @@ handle -> budget evaluation -> runtime support evaluation -> invocation admission evaluation --> scheduler admission unavailable +-> scheduler admission evaluation +-> scheduler work unavailable ``` -This slice reaches the narrow fixture gates through RuntimeSupport v0. It still -has no successful scheduler admission, no scheduler work, and no execution. +This slice reaches the narrow fixture gates through SchedulerAdmission v0. It +still has no scheduler work and no execution. ## Flow @@ -90,6 +93,7 @@ flowchart TD BudgetResolution[BudgetResolution v0] RuntimeSupport[RuntimeSupport v0] InvocationAdmission[InvocationAdmission v0] + SchedulerAdmission[SchedulerAdmission v0] Fact[GraphFact::OpticInvocationObstructed] Posture[OpticAdmissionTicketPosture] @@ -116,7 +120,9 @@ flowchart TD RuntimeSupport -->|missing support fact| Fact RuntimeSupport -->|resolved| InvocationAdmission InvocationAdmission -->|missing admission fact| Fact - InvocationAdmission -->|resolved| Fact + InvocationAdmission -->|resolved| SchedulerAdmission + SchedulerAdmission -->|missing scheduler admission fact| Fact + SchedulerAdmission -->|resolved| Fact Fact --> Posture ``` @@ -139,8 +145,9 @@ sequenceDiagram alt presentation structurally available Registry->>Validator: validate_capability_presentation(artifact, invocation, presentation) Validator->>Facts: publish grant validation obstruction when validation fails - Registry->>Registry: resolve basis, aperture, budget, runtime support, and admission fixtures - Registry->>Registry: obstruct resolved admission before scheduler admission + Registry->>Registry: resolve basis, aperture, budget, runtime support, admission + Registry->>Registry: resolve scheduler admission fixtures + Registry->>Registry: obstruct resolved scheduler admission before scheduler work else missing, malformed, or unbound presentation Registry->>Registry: skip validator end @@ -172,6 +179,7 @@ classDiagram RuntimeSupportUnavailable InvocationAdmissionUnavailable SchedulerAdmissionUnavailable + SchedulerWorkUnavailable } class RegisteredOpticArtifact { @@ -184,6 +192,7 @@ classDiagram class EchoRuntimeSupportSurface { +runtime-owned support facts +runtime-owned admission facts + +runtime-owned scheduler admission facts } OpticInvocation --> OpticBudgetRequest @@ -234,17 +243,23 @@ Echo must not accept caller testimony about runtime support. Support checks compare registered artifact requirements against Echo-owned runtime support facts recorded by the registry. -As of InvocationAdmission v0, Echo also records a narrow runtime-owned -invocation admission fixture through Echo-issued artifact handles. That -admission fact advances the ladder past `InvocationAdmissionUnavailable`, but -only to `SchedulerAdmissionUnavailable`; it still does not schedule work or -execute an invocation. +As of InvocationAdmission v0, Echo records a narrow runtime-owned invocation +admission fixture through Echo-issued artifact handles. That admission fact +advances the ladder past `InvocationAdmissionUnavailable`, but only to +SchedulerAdmission v0. + +As of SchedulerAdmission v0, Echo records a narrow runtime-owned scheduler +admission fixture through Echo-issued artifact handles. That scheduler +admission fact advances the ladder past `SchedulerAdmissionUnavailable`, but +only to `SchedulerWorkUnavailable`; it still does not schedule work or execute +an invocation. ## Non-goals - no `MissingSupportRequest`; +- no `MissingSchedulerAdmissionRequest`; - no support request bytes; -- no successful scheduler admission; +- no scheduler admission request bytes; - no successful `AdmissionTicket`; - no `LawWitness`; - no scheduler work; diff --git a/docs/design/optic-admission-ladder-checkpoint.md b/docs/design/optic-admission-ladder-checkpoint.md index 0328ea13..f3e61217 100644 --- a/docs/design/optic-admission-ladder-checkpoint.md +++ b/docs/design/optic-admission-ladder-checkpoint.md @@ -3,19 +3,19 @@ # Optic Admission Ladder Checkpoint -Status: InvocationAdmission v0 boundary checkpoint. +Status: SchedulerAdmission v0 boundary checkpoint. Scope: refusal ladder with narrow controlled basis, aperture, budget, and runtime-owned admission fixtures. ## Doctrine This checkpoint records the optic invocation admission ladder at the first -controlled invocation-admission boundary. +controlled scheduler-admission boundary. Echo can now explain why an optic invocation is refused and can positively -resolve a narrow Echo-owned invocation admission fixture. It still cannot issue -a successful `AdmissionTicket`, enqueue scheduler work, dispatch a handler, or -execute the invocation. +resolve narrow Echo-owned invocation admission and scheduler admission +fixtures. It still cannot issue a successful `AdmissionTicket`, create +scheduler work, dispatch a handler, or execute the invocation. A registered artifact handle is not authority. A capability presentation slot is not a validated grant. A basis request is not a resolved basis unless it matches @@ -30,6 +30,9 @@ registry; it is not caller-provided testimony. Resolved runtime support is not permission to act. Invocation admission is Echo-owned context recorded by the registry; it is not caller-provided testimony. Resolved invocation admission is not scheduler admission, scheduler work, handler dispatch, or execution. +Scheduler admission is Echo-owned context recorded by the registry; it is not +caller-provided testimony. Resolved scheduler admission is not scheduler work, +handler dispatch, or execution. Refusal is causal evidence. Refusal is not admission, not execution, not a law witness, and not a counterfactual candidate. @@ -57,9 +60,12 @@ The current optic invocation admission path evaluates checks in this order: 13. If RuntimeSupport v0 resolves, check Echo-owned InvocationAdmission v0 facts for the registered artifact handle or obstruct at `InvocationAdmissionUnavailable`. -14. If InvocationAdmission v0 resolves, obstruct at +14. If InvocationAdmission v0 resolves, check Echo-owned SchedulerAdmission v0 + facts for the registered artifact handle or obstruct at `SchedulerAdmissionUnavailable`. -15. Publish the invocation obstruction fact. +15. If SchedulerAdmission v0 resolves, obstruct at + `SchedulerWorkUnavailable`. +16. Publish the invocation obstruction fact. Presence checks come before resolution checks. Basis resolution gates aperture resolution. Aperture resolution gates budget evaluation and runtime support @@ -83,6 +89,12 @@ registry through an Echo-issued artifact handle for that artifact's registered operation and requirements. Recording the fixture is idempotent per artifact handle, and invocation admission evidence is not carried by `OpticInvocation`. +The current Echo-owned scheduler admission fixture is +`scheduler-admission:resolved-fixture:v0`. It is recorded by the runtime +registry through an Echo-issued artifact handle for that artifact's registered +operation and requirements. Recording the fixture is idempotent per artifact +handle, and scheduler admission evidence is not carried by `OpticInvocation`. + ## Obstruction reachability | Obstruction | Reachability | Meaning | @@ -101,7 +113,8 @@ handle, and invocation admission evidence is not carried by `OpticInvocation`. | `UnsupportedBudgetResolution` | Reachable today | ApertureResolution v0 succeeded, but the budget shape is outside BudgetResolution v0. | | `RuntimeSupportUnavailable` | Reachable today | BudgetResolution v0 succeeded, but Echo has no runtime support fact for the registered requirements. | | `InvocationAdmissionUnavailable` | Reachable today | RuntimeSupport v0 succeeded, but Echo has no invocation admission fact for the artifact handle. | -| `SchedulerAdmissionUnavailable` | Reachable today | InvocationAdmission v0 succeeded, but scheduler admission/work enqueueing does not exist yet. | +| `SchedulerAdmissionUnavailable` | Reachable today | InvocationAdmission v0 succeeded, but Echo has no scheduler admission fact for the artifact handle. | +| `SchedulerWorkUnavailable` | Reachable today | SchedulerAdmission v0 succeeded, but scheduler work enqueueing does not exist yet. | `RuntimeSupportUnavailable` is lawfully reachable after BasisResolution v0, ApertureResolution v0, and BudgetResolution v0 all resolve when Echo has no @@ -111,9 +124,12 @@ runtime-owned support fact for the registered requirements. resolves when Echo has no runtime-owned admission fact for the artifact handle. `SchedulerAdmissionUnavailable` is lawfully reachable after InvocationAdmission -v0 resolves. It is the current terminal refusal after Echo proves invocation -admission but before any scheduler admission, scheduler work, handler dispatch, -or execution exists. +v0 resolves when Echo has no runtime-owned scheduler admission fact for the +artifact handle. + +`SchedulerWorkUnavailable` is lawfully reachable after SchedulerAdmission v0 +resolves. It is the current terminal refusal after Echo proves scheduler +admission but before any scheduler work, handler dispatch, or execution exists. `UnsupportedApertureResolution` is reachable only after the exact BasisResolution v0 fixture resolves. For identity-covered material, unsupported @@ -129,8 +145,8 @@ This checkpoint does not introduce: - successful `AdmissionTicket` issuance - `LawWitness` -- scheduler admission - scheduler work +- scheduler work enqueueing - handler dispatch - execution behavior - storage behavior @@ -139,7 +155,9 @@ This checkpoint does not introduce: - authority success - caller-supplied runtime support testimony - caller-supplied invocation admission testimony +- caller-supplied scheduler admission testimony - general runtime support enforcement +- general scheduler admission enforcement - budget reservation The system remains obstruction-first. It records refusal; it does not authorize @@ -201,7 +219,7 @@ invocation request field, not caller testimony, not authority, not admission, not scheduler work, and not execution. If runtime support resolves, the next boundary is InvocationAdmission v0: absent Echo-owned admission evidence obstructs at `InvocationAdmissionUnavailable`; resolved admission evidence -advances to `SchedulerAdmissionUnavailable`. +advances to SchedulerAdmission v0. ## InvocationAdmission v0 @@ -217,12 +235,29 @@ admission evidence for the artifact handle's registered operation and requirements. It is not an invocation request field, not caller testimony, not an `AdmissionTicket`, not a law witness, not scheduler admission, not scheduler work, not handler dispatch, and not execution. If invocation admission resolves, -the only lawful next refusal in this slice is -`SchedulerAdmissionUnavailable`. +the next boundary is SchedulerAdmission v0: absent Echo-owned scheduler +admission evidence obstructs at `SchedulerAdmissionUnavailable`; resolved +scheduler admission evidence advances to `SchedulerWorkUnavailable`. + +## SchedulerAdmission v0 + +SchedulerAdmission v0 is not general scheduler admission. It recognizes exactly +one Echo-owned fixture for a registered artifact handle: + +```text +scheduler-admission:resolved-fixture:v0 +``` + +Scheduler admission establishes only that Echo has recorded runtime-owned +scheduler admission evidence for the artifact handle's registered operation and +requirements. It is not an invocation request field, not caller testimony, not +an `AdmissionTicket`, not a law witness, not scheduler work, not handler +dispatch, and not execution. If scheduler admission resolves, the only lawful +next refusal in this slice is `SchedulerWorkUnavailable`. ## Next transition point -The next transition point is SchedulerAdmission v0. +The next transition point is SchedulerWork v0. That transition must be narrow and explicit. It must not imply successful execution, handler dispatch, or unconstrained authority validation. @@ -243,6 +278,11 @@ If a future slice makes `SchedulerAdmissionUnavailable` reachable before a lawful Echo-owned invocation admission fact exists, the admission ladder is wrong. +If a future slice makes `SchedulerWorkUnavailable` reachable before a lawful +Echo-owned scheduler admission fact exists, the admission ladder is wrong. + RuntimeSupport v0 is controlled resolved runtime context, not admission. InvocationAdmission v0 is controlled resolved admission context, not scheduler admission or execution. +SchedulerAdmission v0 is controlled resolved scheduler context, not scheduler +work or execution.