feat(api): consolidate project-history collection GET and CLI - #428
feat(api): consolidate project-history collection GET and CLI#428seonghobae wants to merge 3 commits into
Conversation
LineageWeave operators can GET /v1/project-histories on tepp-loopback without guessing idempotency keys. Metric-free temporal_association_only identities only. tepp.scientific_acceptance.v1 never appears. Evidence text and findings stay off the page. Does not infer causality. Not project-history CLI. Stacked on protected main.
Publish tepp-project-histories list as the operator-visible client of GET /v1/project-histories. The binary mints a typed LineageWeave collection exchange onto spawned tepp-loopback TCP. Stdout stays metric-free temporal_association_only identities. Naruon is refused.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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 |
| for index in 1..collection.histories.len() { | ||
| if collection.histories[index - 1].idempotency_key | ||
| >= collection.histories[index].idempotency_key | ||
| { | ||
| return Err(ApiError::InvalidWirePayload); |
There was a problem hiding this comment.
🟡 Duplicate keys break history enumeration
When two workspaces reuse an idempotency key, render_project_history_collection_cli_stdout rejects the successful collection response. Operators cannot enumerate those histories.
Prompt for agents
Project-history storage namespaces idempotency keys by consumer, tenant workspace, and key in AnalysisRunLiveService, but collection rows and cursors expose only the idempotency key. Two tenant workspaces can therefore create accepted histories with the same key. The collection service emits duplicate sort keys, the CLI's render_project_history_collection_cli_stdout rejects them, and an exclusive key-only cursor can skip duplicates across pages. Define a globally unique stable collection ordering and cursor, or scope collection requests to one tenant. Update ProjectHistoryCollectionItem, page_project_history_collection_items, the live GET handler, CLI response binding, and contract tests consistently.
Was this helpful? React with 👍 or 👎 to provide feedback.
| if let Some(cursor) = cursor { | ||
| items.retain(|item| item.idempotency_key.as_str() > cursor); |
There was a problem hiding this comment.
🟡 Unknown cursors skip valid histories
A nonexistent cursor makes page_project_history_collection_items select a lexical position instead of rejecting it. Callers can silently skip histories or receive an empty page.
Prompt for agents
The collection contract requires unknown cursors to fail closed, but pagination accepts every bounded string and filters rows lexically. Validate a supplied cursor against the current collection before paging and return an API error when it does not identify a valid row. Update the helper or its caller to return Result and add tests for cursors before, between, and after existing keys.
Was this helpful? React with 👍 or 👎 to provide feedback.
| for item in &self.histories { | ||
| item.validate()?; | ||
| } | ||
| if let Some(cursor) = &self.next_cursor { | ||
| require_nonempty(cursor)?; | ||
| if cursor.len() > PROJECT_HISTORY_COLLECTION_CURSOR_MAX_LEN { | ||
| return Err(ApiError::LimitExceeded); | ||
| } | ||
| } |
There was a problem hiding this comment.
🟡 Malformed pages pass validation
Unsorted rows and unrelated cursors pass ProjectHistoryCollection::validate and serialize successfully. Direct API consumers can process invalid pagination state.
Prompt for agents
ProjectHistoryCollection documents histories as sorted by idempotency_key and next_cursor as the continuation token for the page, but its shared constructor, parser, and serializer validate neither invariant. Enforce strict row ordering and uniqueness during collection validation, and require any next_cursor to match the final row while rejecting cursors on empty pages. Add direct new/from_json/to_json tests rather than relying only on the CLI renderer's separate checks.
Was this helpful? React with 👍 or 👎 to provide feedback.
| let bytes = read_bounded(&mut stream, MAXIMUM_HTTP_RESPONSE_BYTES)?; | ||
| parse_http_response(&bytes) |
There was a problem hiding this comment.
seonghobae
left a comment
There was a problem hiding this comment.
Exact-head COMMENT on 9225461 (draft). Unique occupied: GET /v1/project-histories plus tepp-project-histories (ADR 0028/0065). LineageWeave consumer (tepp-consumer: lineageweave). Collection bodies stay metric-free; PROJECT_HISTORY_COLLECTION_INFERENCE_STATUS is temporal_association_only. Scientific-acceptance / causal_score / evidence text stay out. Pagination via tepp-page-cursor / tepp-page-limit with max 64.
Do not duplicate. Do not un-draft. Devin COMMENTED is not independent APPROVE. Zero current-head APPROVE. Never self-approve. Do not ship project-history by-idempotency lookup (#429 CLOSED). Persistence remains GAP-003B. Do not weaken fail-closed. No Buyer language. No PII in LineageWeave.
Consolidated landing vehicle
This PR folds predecessor #424 into one LineageWeave-facing Analysis Run / project-history collection application-adapter vehicle. The current head contains #424 as its direct ancestor, so retargeting to protected
mainpreserves the collection GET implementation/tests while eliminating one open Draft micro-PR. #424 remains immutable review/history evidence; retrieval vehicles #431/#456 retain this ancestry.Preserved GET behavior from #424:
GET /v1/project-histories, LineageWeave-only consumer boundary, empty body, bounded exclusive cursor pagination, metric-free rows (project_key,idempotency_key,knowledge_cutoff,inference_status=temporal_association_only), naruon refusal, and no scientific-acceptance/evidence-text/findings/causal-score leakage.CLI behavior on this head: published
tepp-project-histories list, typed collection exchange, empty-stdin admission, non-loopback/localhost/credential/nonempty-stdin/unpublished-consumer/non-HTTPS/hostile-pagination refusals, and metric-free rendering.This is one Analysis Run application/adapter landing vehicle, not a bounded context. The conflicting per-stack ADR 0028/0065 lineage is implementation evidence pending repository-wide normalization under #437; it is not independent architecture authority. Merge only after fresh exact-head required workflows, resolved conversations, and qualifying independent approval under live ruleset 18156473. No predecessor-head evidence transfer or bypass.