feat(api): list accepted temporal-context identities on loopback GET - #449
feat(api): list accepted temporal-context identities on loopback GET#449seonghobae wants to merge 1 commit into
Conversation
Publish GET /v1/temporal-context so operators enumerate metric-free LineageWeave identities minted by POST with an idempotency-key header. Event labels, actor lists, and tepp.scientific_acceptance.v1 never appear. Naruon is refused. NaruonLiveService stays POST-only. ADR 0081.
|
Warning Review limit reachedNext included review available in 49 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (11)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| } else { | ||
| self.accepted_temporal_contexts.insert(replay_key, item); | ||
| } |
There was a problem hiding this comment.
🟡 Failed posts remain listed as accepted
When response serialization exceeds its limit, accept_temporal_context records the identity before returning 413. Later collection reads falsely list the request as accepted.
Prompt for agents
In crates/tepp_api/src/analysis_run_live.rs, accept_temporal_context mutates accepted_temporal_contexts before build_temporal_context and TemporalContextResponse::to_json complete. A request can fit the 64 KiB input limit yet expand beyond the 64 KiB response limit because event identities are repeated across timeline, relation, gap, and source arrays. Build and serialize the successful response before committing the collection identity. Preserve replay/conflict behavior without recording any request whose POST response fails.
Was this helpful? React with 👍 or 👎 to provide feedback.
| if let Some(stored) = self.accepted_temporal_contexts.get(&replay_key) { | ||
| if stored.knowledge_cutoff != item.knowledge_cutoff { | ||
| return Err(ApiError::InvalidWirePayload); | ||
| } |
There was a problem hiding this comment.
🟡 Reused keys return different results
Reusing an idempotency key with the same cutoff but different events passes accept_temporal_context. One accepted identity can therefore produce conflicting results.
Prompt for agents
The temporal-context registry stores only TemporalContextCollectionItem, so replay validation can compare only knowledge_cutoff. Store the complete validated TemporalContextRequest, or a canonical digest of every request field, alongside the collection item. Accept an existing idempotency key only when the full request matches; reject changed events, subject_post_id, consumer_code, or other semantics.
Was this helpful? React with 👍 or 👎 to provide feedback.
| if payload.contains("tepp.scientific_acceptance.v1") { | ||
| return Err(ApiError::InvalidWirePayload); | ||
| } |
There was a problem hiding this comment.
🟡 Valid identity disables collection reads
An idempotency key containing tepp.scientific_acceptance.v1 passes item validation. refuse_metrics_on_temporal_context_collection_payload then rejects pages containing it, so collection reads fail.
Prompt for agents
The raw substring ban treats string values as forbidden schema artifacts, while TemporalContextCollectionItem accepts the same text as an idempotency key. Make validation consistent: either reject this reserved marker when identities are minted, before insertion, or detect scientific-acceptance structure semantically without rejecting opaque string values. Add a POST-then-GET regression test for an idempotency key containing the marker.
Was this helpful? React with 👍 or 👎 to provide feedback.
| for item in &self.contexts { | ||
| item.validate()?; | ||
| } | ||
| if let Some(cursor) = &self.next_cursor { | ||
| require_nonempty(cursor)?; | ||
| if cursor.len() > TEMPORAL_CONTEXT_COLLECTION_CURSOR_MAX_LEN { | ||
| return Err(ApiError::LimitExceeded); | ||
| } | ||
| } |
There was a problem hiding this comment.
🟡 Malformed collection pages pass validation
TemporalContextCollection::validate accepts malformed cutoffs, duplicate or unsorted identities, and unrelated cursors. Consumers can treat invalid pagination data as a valid collection response.
Prompt for agents
Strengthen TemporalContextCollection and TemporalContextCollectionItem validation in crates/tepp_api/src/temporal_context_collection_http.rs. Parse every knowledge_cutoff with the same RFC 3339 temporal type used by TemporalContextRequest. Require contexts to be strictly increasing by idempotency_key, which rejects duplicates, and require next_cursor to equal the final row identity when present. Define and validate empty-page cursor behavior, then add malformed from_json tests.
Was this helpful? React with 👍 or 👎 to provide feedback.
| next_request_serial: u64, | ||
| accepted_runs: HashMap<String, (AnalysisRunRequest, AnalysisRunAccepted)>, | ||
| accepted_project_histories: HashMap<String, (ProjectHistoryRequest, ProjectHistoryProjection)>, | ||
| accepted_temporal_contexts: HashMap<String, TemporalContextCollectionItem>, |
| let payload = to_json(self)?; | ||
| require_byte_limit(&payload, DEFAULT_PROJECT_HISTORY_BYTE_LIMIT)?; |
There was a problem hiding this comment.
|
Closing as |
Summary
GAP-003A unique operator-visible slice: loopback
GET /v1/temporal-contextenumerates accepted LineageWeave temporal-context identities onAnalysisRunLiveService/tepp-loopback.idempotency-keyheader fails closed.inference_status=temporal_association_only. Event labels, actor lists, timeline events, evidence text, findings, RMSE, bias, coverage, SE-gate, causal scores, andtepp.scientific_acceptance.v1never appear.idempotency-keystays backward compatible and is not listed.Explicitly not
Another temporal-context CLI (#414), project-history collection GET (#424), project-history cancel CLI (#448), export collection GET (#443), export cancel CLI (#446), interpretation-run collection GET (#433), interpretation-run cancel CLI (#442), Leiden, Driver p.16, GAP-010 Figma/export, persistence/Compose (#287).
Does not add GET to
NaruonLiveService. Does not open naruon on this LineageWeave-owned adapter. Does not weaken fail-closed. Does not infer causality. No Buyer language. HTTP 200 is not an ADR 0014 claim.Test plan
cargo test -p tepp_api --lib temporal_context_collectioncargo test -p tepp_api --test temporal_context_collection_http_contractcargo clippy -p tepp_api --all-targets -- -D warningscargo doc -p tepp_api --no-depspython3 scripts/validate_documentation.pypython3 scripts/check_docstrings.py