Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.d/analysis-run-cancel-consumer-parity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- `tepp_api` adds `lineageweave_analysis_run_cancel_exchange`, Naruon compatibility-listener cancel, and a `tepp-loopback` TCP cancel proof (ADR 0030). Metric-free cancelled status is unchanged from ADR 0029. Not GET status, not lifecycle POST, not an ADR 0014 claim.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ All notable changes to TEPP are documented here. The format follows Keep a Chang

## [Unreleased]

- `tepp_api` adds `lineageweave_analysis_run_cancel_exchange`, Naruon compatibility-listener cancel, and a `tepp-loopback` TCP cancel proof (ADR 0030). Metric-free cancelled status is unchanged from ADR 0029. Not GET status, not lifecycle POST, not an ADR 0014 claim.

- `tepp_api` serves `POST /v1/analysis-runs/{run_id}/cancel` on the shared loopback listener (ADR 0029). Accepted and running runs become metric-free `cancelled` status. Succeeded, failed, and unknown runs cannot be cancelled. Cancel bodies refuse RMSE/bias/coverage/SE-gate/scientific-acceptance keys. GET status and running/terminal POST remain later GAP-003A slices; this is not an ADR 0014 claim.

- `event_core` adds bounded Allen interval-consistency classification, atomic path-consistency closure, contradiction/resource refusals, and an explicit dependency-error fallback without claiming unrestricted global satisfiability.
Expand Down
1 change: 1 addition & 0 deletions DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ TEPP's approved PRD v0.4 and implementation plan are the primary product baselin
| contextual-orchestrator interpretation port | [`docs/connectors/contextual-orchestrator-interpretation-port.md`](docs/connectors/contextual-orchestrator-interpretation-port.md) |
| Orchestrator live HTTP doctoring | [`docs/research/orchestrator-live-http.md`](docs/research/orchestrator-live-http.md) |
| Analysis-run cancel HTTP doctoring | [`docs/research/analysis-run-cancel-http.md`](docs/research/analysis-run-cancel-http.md) |
| Analysis-run cancel consumer-parity doctoring | [`docs/research/analysis-run-cancel-consumer-parity.md`](docs/research/analysis-run-cancel-consumer-parity.md) |
| UML/runtime/scientific flows | [`docs/UML.md`](docs/UML.md) |
| Logical/physical ERD | [`docs/ERD.md`](docs/ERD.md) |
| Security policy | [`SECURITY.md`](SECURITY.md) |
Expand Down
2 changes: 2 additions & 0 deletions crates/tepp_api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ pub use lineage_pair_criterion::LineageTemporalProvenance;
pub use lineageweave_http::LINEAGEWEAVE_CONSUMER_CODE;
/// Published Naruon modular-consumer identity.
pub use lineageweave_http::NARUON_CONSUMER_CODE;
/// Build a `LineageWeave` analysis-run cancel exchange without credentials.
pub use lineageweave_http::lineageweave_analysis_run_cancel_exchange;
/// Build a `LineageWeave` analysis-run exchange without provider credentials.
pub use lineageweave_http::lineageweave_analysis_run_exchange;
/// Build a `LineageWeave` project-history exchange without provider credentials.
Expand Down
63 changes: 58 additions & 5 deletions crates/tepp_api/src/lineageweave_http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
use crate::naruon_http::compose_https_target;
use crate::project_history::build_project_history_exchange;
use crate::{
AnalysisRunRequest, ApiError, NaruonHttpExchange, ProjectHistoryHttpExchange,
ProjectHistoryRequest, TEMPORAL_CONTEXT_CONTRACT_VERSION, TEMPORAL_CONTEXT_PATH,
TemporalContextRequest, naruon_analysis_run_exchange,
AnalysisRunCancelRequest, AnalysisRunRequest, ApiError, NaruonHttpExchange,
ProjectHistoryHttpExchange, ProjectHistoryRequest, TEMPORAL_CONTEXT_CONTRACT_VERSION,
TEMPORAL_CONTEXT_PATH, TemporalContextRequest, naruon_analysis_run_cancel_exchange,
naruon_analysis_run_exchange,
};

/// Stable consumer identity used by the Naruon adapter.
Expand Down Expand Up @@ -38,6 +39,29 @@ pub fn lineageweave_analysis_run_exchange(
Ok(exchange)
}

/// Build a `LineageWeave` → TEPP analysis-run cancel exchange without credentials.
///
/// The function reuses TEPP's existing origin, body, and header validation,
/// then replaces only the published modular-consumer identity. Cancellation
/// remains a metric-free lifecycle command, not a measurement result.
///
/// # Errors
///
/// Returns the same fail-closed errors as [`naruon_analysis_run_cancel_exchange`].
pub fn lineageweave_analysis_run_cancel_exchange(
origin: &str,
request: &AnalysisRunCancelRequest,
) -> Result<NaruonHttpExchange, ApiError> {
let mut exchange = naruon_analysis_run_cancel_exchange(origin, request)?;
let consumer_header = exchange
.headers
.iter_mut()
.find(|(name, _)| name.eq_ignore_ascii_case("tepp-consumer"))
.ok_or(ApiError::InvalidWirePayload)?;
LINEAGEWEAVE_CONSUMER_CODE.clone_into(&mut consumer_header.1);
Ok(exchange)
}

/// Build a credential-free `LineageWeave` temporal-context exchange.
///
/// # Errors
Expand Down Expand Up @@ -94,9 +118,11 @@ pub(crate) fn consumer_is_supported(consumer_code: &str) -> bool {
mod tests {
use super::{
LINEAGEWEAVE_CONSUMER_CODE, NARUON_CONSUMER_CODE, consumer_is_supported,
lineageweave_analysis_run_exchange,
lineageweave_analysis_run_cancel_exchange, lineageweave_analysis_run_exchange,
};
use crate::{
ANALYSIS_RUN_CONTRACT_VERSION, AnalysisRunCancelRequest, AnalysisRunRequest, ApiError,
};
use crate::{ANALYSIS_RUN_CONTRACT_VERSION, AnalysisRunRequest, ApiError};

fn sample_run() -> AnalysisRunRequest {
AnalysisRunRequest {
Expand Down Expand Up @@ -132,4 +158,31 @@ mod tests {
Err(ApiError::InvalidWirePayload)
);
}

#[test]
fn lineageweave_cancel_exchange_swaps_only_the_consumer_header() {
let request = AnalysisRunCancelRequest::new("tepp-run-1", "idem-1").expect("cancel");
let exchange =
lineageweave_analysis_run_cancel_exchange("https://tepp.example.test", &request)
.expect("exchange");
assert_eq!(exchange.method, "POST");
assert_eq!(
exchange.target_url,
"https://tepp.example.test/v1/analysis-runs/tepp-run-1/cancel"
);
assert!(
exchange
.headers
.contains(&("tepp-consumer".into(), LINEAGEWEAVE_CONSUMER_CODE.into()))
);
assert!(
!exchange
.headers
.contains(&("tepp-consumer".into(), NARUON_CONSUMER_CODE.into()))
);
assert_eq!(
lineageweave_analysis_run_cancel_exchange("http://tepp.example.test", &request),
Err(ApiError::InvalidWirePayload)
);
}
}
Loading
Loading