Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
f1ff05c
test: specify recovered TEPP project-history boundary
seonghobae Aug 21, 2026
93873f7
test: specify TEPP project-history buyer evidence
seonghobae Aug 21, 2026
565e531
feat: recover strict TEPP project-history client
seonghobae Aug 21, 2026
8281e6a
feat: map canonical project history into TEPP contract
seonghobae Aug 21, 2026
5c81a5e
feat: render TEPP validation beside canonical history
seonghobae Aug 21, 2026
889bddb
style: add TEPP project-history evidence panel
seonghobae Aug 21, 2026
2a2a1a7
docs: add TEPP project-history Storybook states
seonghobae Aug 21, 2026
31c2016
chore: stage one-shot TEPP project-history recovery
seonghobae Aug 21, 2026
0b03ad5
docs: record recovered TEPP project-history boundary
seonghobae Aug 21, 2026
26b83f0
ci: execute verified TEPP project-history recovery
seonghobae Aug 21, 2026
19747b6
fix(i18n): cover Vietnamese TEPP project-history copy
seonghobae Aug 21, 2026
065f962
test(red): require TEPP evidence on canonical timeline
seonghobae Aug 21, 2026
7d2fea8
fix(ci): make TEPP recovery red gate integration-specific
seonghobae Aug 21, 2026
3fd75b0
fix(ui): harden TEPP evidence semantics and accessibility
seonghobae Aug 21, 2026
f8b5826
test(ui): cover TEPP evidence labels and unique regions
seonghobae Aug 21, 2026
a1b117f
test(red): reject unrecognized TEPP findings and invalid responses
seonghobae Aug 21, 2026
704215a
fix(ci): apply complete strict TEPP recovery contract
seonghobae Aug 21, 2026
32e24c1
ci: format and lint TEPP recovery before commit
seonghobae Aug 21, 2026
8d69a34
docs(adr): close TEPP finding vocabulary and response boundary
seonghobae Aug 21, 2026
69f0a3d
fix(ci): cancel stale TEPP recovery attempts
seonghobae Aug 21, 2026
cb30c24
feat: materialize TEPP project history recovery
seonghobae Aug 21, 2026
337691a
test: keep TEPP evidence type-safe
seonghobae Aug 21, 2026
065d582
fix: fail closed on unknown TEPP findings
seonghobae Aug 21, 2026
13a3430
fix(http): let strict contracts suppress LLM metadata
seonghobae Aug 21, 2026
6dfb5d9
fix(tepp): keep contextual metadata out of strict payloads
seonghobae Aug 21, 2026
1703bf7
test(tepp): prove strict payloads suppress LLM metadata
seonghobae Aug 21, 2026
8baf402
fix(tepp): preserve strict validation while suppressing metadata
seonghobae Aug 21, 2026
43262dc
fix(tepp): normalize unexpected provider failures
seonghobae Aug 21, 2026
1df9d83
Merge remote-tracking branch 'refs/remotes/origin/feat/project-histor…
seonghobae Aug 21, 2026
87c1b01
fix: enforce TEPP project history byte limits
seonghobae Aug 21, 2026
6a4dbe7
fix: order TEPP history events by timestamp
seonghobae Aug 21, 2026
76964c0
fix: sanitize TEPP transport provider errors
seonghobae Aug 21, 2026
8d12743
docs: record TEPP provider error boundary
seonghobae Aug 21, 2026
59d687e
Merge latest project history timeline into TEPP recovery
seonghobae Aug 21, 2026
b3d803a
feat: connect Ask answers to canonical project histories (v2.20.0) (#…
seonghobae Aug 21, 2026
b450c3e
Merge branch 'feat/project-history-timeline-v2184-r3' of https://gith…
seonghobae Aug 21, 2026
9235807
docs: assign unique ADR numbers after stack merge
seonghobae Aug 21, 2026
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
5 changes: 5 additions & 0 deletions CHANGELOG.d/2.20.0-global-ask-cutoff-safety.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### Fixed

- Bind the Global Ask knowledge cutoff in the final authorized-source query.
- Give the post-chat cutoff migration a unique `0054` identity and remove
self-modifying stabilization workflows.
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,29 @@ All notable changes to this project are documented here. Format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.20.0] - 2026-08-21

### Added

- Post-scoped Ask and Global Ask now attach exact project-history links derived
only from currently authorized cited posts. Opening a link reuses the canonical
Project history timeline and its optional TEPP validation at the answer cutoff.

### Security

- Persisted post answers are withheld when any citation is no longer visible, and
stale Global Ask sessions are restarted before hidden prior prose can re-enter
conversation context (ADR 0113).

## [2.19.0] - 2026-08-21

### Added

- Recovered the credential-free TEPP project-history validation boundary on top of
the canonical Buyer timeline. TEPP may return only cutoff-safe temporal
associations over the exact authorized events; the timeline remains readable
when TEPP is absent, and no result is labelled as a cause (ADR 0127).

## [2.18.0] - 2026-08-20

### Added
Expand Down
44 changes: 20 additions & 24 deletions backend/app/analysis_run_start.py

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Analysis-run TEPP submission still forwards LLM metadata

This PR added include_llm_metadata to post_json precisely so a closed non-LLM contract cannot leak an unpublished metadata member (http_client.py), and the project-history client opts out via _post. The pre-existing analysis-run TEPP transport in configured_tepp_client (analysis_run_start.py) was not updated and still calls post_json with the default include_llm_metadata=True, so if an LLM context is active during submission it would append metadata to TEPP's AnalysisRunRequest wire payload. The worker delivery path is unlikely to have an active LLM context, so impact is probably nil today, but the closed-contract rationale applies equally here.

(Refers to this code)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import hashlib
import json
from datetime import datetime, timezone
from datetime import UTC, datetime
from typing import Any
from uuid import UUID

Expand All @@ -21,13 +21,13 @@
AnalysisRunCreateError,
fetch_visible_analysis_run,
)
from backend.app.post_eligibility import SOURCE_POST_ELIGIBILITY_SQL
from backend.app.analysis_run_outbox import (
latest_outbox_delivery_is_claimed,
latest_outbox_delivery_is_delivered,
outbox_request_digest,
)
from backend.app.lineage_ingestion import records_from_source_posts
from backend.app.post_eligibility import SOURCE_POST_ELIGIBILITY_SQL
from lineageweave.adjudication_client import AdjudicationClient
from lineageweave.http_client import HttpClientError, post_json
from lineageweave.lineage_persistence import lineage_edge_specs
Expand Down Expand Up @@ -119,12 +119,12 @@ def tepp_run_request(
"""Build TEPP's published request from the frozen run, never a theta."""
cutoff = knowledge_cutoff
if cutoff.tzinfo is None:
cutoff = cutoff.replace(tzinfo=timezone.utc)
cutoff = cutoff.replace(tzinfo=UTC)
return AnalysisRunRequest(
idempotency_key=idempotency_key,
tenant_workspace_id=str(corporate_entity_id),
snapshot_id=snapshot_sha256,
knowledge_cutoff=cutoff.astimezone(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
knowledge_cutoff=cutoff.astimezone(UTC).strftime("%Y-%m-%dT%H:%M:%SZ"),
model_contract_version=_TEPP_MODEL_CONTRACT,
output_profile=_TEPP_OUTPUT_PROFILE,
)
Expand Down Expand Up @@ -610,7 +610,7 @@ async def deliver_queued_analysis_run(
return await _visible_or_404(
conn, analysis_run_id, account_id, affiliated_entity_ids
)
now = datetime.now(timezone.utc)
now = datetime.now(UTC)
try:
if not latest_outbox_delivery_is_claimed(latest):
await _append_outbox_delivery(
Expand All @@ -636,9 +636,8 @@ async def deliver_queued_analysis_run(
affiliated_entity_ids=affiliated_entity_ids,
adjudication_client=adjudication_client,
)
finished = datetime.now(timezone.utc)
if finished < now:
finished = now
finished = datetime.now(UTC)
finished = max(finished, now)
await _append_outbox_delivery(
conn,
analysis_run_id,
Expand Down Expand Up @@ -699,7 +698,7 @@ async def _deliver_lineage_reconstruction(
adjudication_client: AdjudicationClient | None = None,
) -> None:
"""Persist ThreadWeave parent choices for the frozen bag."""
now = datetime.now(timezone.utc)
now = datetime.now(UTC)
member_rows = await _snapshot_member_posts(
conn,
locked["analysis_source_snapshot_id"],
Expand All @@ -715,9 +714,8 @@ async def _deliver_lineage_reconstruction(
)
edges = lineage_edge_specs(records_from_source_posts(rows), llm=adjudication_client)
digest = reconstruction_result_digest(edges)
finished = datetime.now(timezone.utc)
if finished < now:
finished = now
finished = datetime.now(UTC)
finished = max(finished, now)
await conn.execute(
"""
insert into analysis_run_reconstruction
Expand Down Expand Up @@ -759,25 +757,23 @@ async def _deliver_tepp_measurement(
tepp_client: TeppClient,
) -> None:
"""Submit the frozen snapshot through ``tepp_client``. Never persist a theta."""
now = datetime.now(timezone.utc)
now = datetime.now(UTC)
request = tepp_run_request(
idempotency_key=str(locked["idempotency_key"]),
snapshot_sha256=str(locked["snapshot_sha256"]),
knowledge_cutoff=locked["knowledge_cutoff"],
corporate_entity_id=str(locked["corporate_entity_id"]),
)
status_code, failure_code, envelope = _tepp_submission(tepp_client, request)
if status_code == _SUCCEEDED and envelope is not None:
if not await _persist_tepp_result(
conn,
analysis_run_id=analysis_run_id,
envelope=envelope,
):
status_code = _FAILED
failure_code = "tepp_result_not_persisted"
finished = datetime.now(timezone.utc)
if finished < now:
finished = now
if status_code == _SUCCEEDED and envelope is not None and not await _persist_tepp_result(
conn,
analysis_run_id=analysis_run_id,
envelope=envelope,
):
status_code = _FAILED
failure_code = "tepp_result_not_persisted"
finished = datetime.now(UTC)
finished = max(finished, now)
await _append_status(
conn,
analysis_run_id,
Expand Down
Loading