feat: connect Ask answers to canonical project histories (v2.20.0) - #342
Conversation
|
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: Pro Plus 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 |
|
Exact current head: The self-modifying PR workflow and repair scripts were removed after local application. The shipped product now attaches authorization- and cutoff-bound project-history links to post-scoped and Global Ask, reuses the canonical timeline/optional TEPP validation, persists exact Ask knowledge cutoffs through migration Verification on this head lineage: backend |
|
Documentation checkpoint added. Exact current head is now |
|
Exact current head updated to |
…ry-v2210' into HEAD
|
Stabilization ownership note for the exact current stack:
Current queued checks and repair workflows are evidence gathering only; they are not treated as a completed fix. |
Root-cause repair at
|
…ry-v2210' into codex/pr-342-global-ask-root-fix # Conflicts: # backend/app/main.py # docker/postgres-init/migrate.sh # docs/product-technical-gap-baseline.md
…s-v2200' into codex/pr-342-global-ask-root-fix
…s-v2200' into codex/pr-342-global-ask-root-fix # Conflicts: # docs/product-technical-gap-baseline.md
Merge-resolution evidence at
|
|
Remaining authorized-entity reuse from the 80ce604 cutoff repair is now stacked as #357 ( |
| answer.answer_text, | ||
| cited_ids, | ||
| ) | ||
| answer_evidence = await read_authorized_ask_evidence( | ||
| conn, | ||
| cited_post_ids=cited_ids, | ||
| corporate_entity_ids=account.corporate_entity_ids, | ||
| knowledge_cutoff=knowledge_cutoff, | ||
| ) | ||
| if not answer_evidence.all_citations_visible: | ||
| raise HTTPException( | ||
| status.HTTP_503_SERVICE_UNAVAILABLE, | ||
| "Global Ask evidence changed before the answer could be returned", | ||
| ) |
There was a problem hiding this comment.
🔍 Session can be poisoned by a persisted turn that then fails the post-persist visibility check
In ask_agent, persist_global_ask_turn writes the new turn's citations (main.py) BEFORE read_authorized_ask_evidence verifies them (:2956). If the post-persist check fails (503, "evidence changed"), the just-persisted citation stays in global_ask_turn_citation. On the next request, global_ask_session_citations_authorized re-checks all session citations including that one and returns 409, forcing a session restart. This is a narrow race and is broadly consistent with the ADR 0113 fail-closed intent, but it means a transient provider/visibility hiccup can permanently retire a session rather than being retryable. Worth confirming this is the intended fail-closed boundary.
(Refers to this code)
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
이 동작은 의도된 fail-closed 결과가 아니라 유효한 session-liveness 결함입니다. 숨겨진 citation을 반환하지 않는 계약은 유지하되, persist와 post-persist authorization check를 하나의 outer database transaction으로 묶고 all_citations_visible == false 예외를 transaction 내부에서 발생시켜 새 turn/citation insert 전체를 rollback해야 합니다. 실제 PostgreSQL 회귀 테스트는 (1) visibility race를 유도해 503을 받고, (2) 해당 session의 turn/citation 수가 증가하지 않으며, (3) 같은 session의 다음 안전한 질문이 409 없이 계속되는지 검증해야 합니다. 이 스레드는 최종 exact head에서 그 테스트와 전체 suite가 통과하기 전까지 해결하지 않습니다.
|
GitHub writes retry (2026-08-21 cycle). Exact parent head remains Independent APPROVE is still required. I will not self-approve. Remaining Global Ask maintenance defect (hardcoded sessionStorage literals in acceptAnswer/409) will ship as a separate stacked slice, not mixed into this PR. |
b3d803a
into
feat/tepp-project-history-recovery-v2210
…339) * test: specify recovered TEPP project-history boundary * test: specify TEPP project-history buyer evidence * feat: recover strict TEPP project-history client * feat: map canonical project history into TEPP contract * feat: render TEPP validation beside canonical history * style: add TEPP project-history evidence panel * docs: add TEPP project-history Storybook states * chore: stage one-shot TEPP project-history recovery * docs: record recovered TEPP project-history boundary * ci: execute verified TEPP project-history recovery * fix(i18n): cover Vietnamese TEPP project-history copy * test(red): require TEPP evidence on canonical timeline * fix(ci): make TEPP recovery red gate integration-specific * fix(ui): harden TEPP evidence semantics and accessibility * test(ui): cover TEPP evidence labels and unique regions * test(red): reject unrecognized TEPP findings and invalid responses * fix(ci): apply complete strict TEPP recovery contract * ci: format and lint TEPP recovery before commit * docs(adr): close TEPP finding vocabulary and response boundary * fix(ci): cancel stale TEPP recovery attempts * feat: materialize TEPP project history recovery * test: keep TEPP evidence type-safe * fix: fail closed on unknown TEPP findings * fix(http): let strict contracts suppress LLM metadata * fix(tepp): keep contextual metadata out of strict payloads * test(tepp): prove strict payloads suppress LLM metadata * fix(tepp): preserve strict validation while suppressing metadata * fix(tepp): normalize unexpected provider failures * fix: enforce TEPP project history byte limits * fix: order TEPP history events by timestamp * fix: sanitize TEPP transport provider errors * docs: record TEPP provider error boundary * feat: connect Ask answers to canonical project histories (v2.20.0) (#342) * test(red): require authorization-safe Ask project histories * test(red): require canonical project histories in Ask answers * chore: stage project-history Ask integration transform * ci: verify project-history Ask integration * fix(ci): repair Ask transform f-string and import anchors * fix(ci): repair generated Ask SQL before verification * test(red): persist the exact post Ask knowledge cutoff * fix(ci): preserve exact Ask cutoffs and stale-request safety * ci: verify exact persisted Ask cutoffs * ci: trigger Ask integration verification on stacked PR * ci: restack Ask integration on latest TEPP recovery * fix(ci): bind persisted Ask clocks to one application timeline * test(ask): keep persisted answer time after its cutoff * ci: verify hardened Ask cutoff persistence * test(db): reserve the next migration after project history * fix(ci): allocate Ask cutoff migration after project history * test(db): use the next available migration sequence * fix(ci): allocate the first free Ask cutoff migration * feat: connect Ask answers to project histories * docs: record Ask integration gate * docs: avoid stale self head checkpoint * fix: contain provider failures across Ask and TEPP * ci: verify PR 342 Global Ask stabilization * ci: publish verified PR 342 stabilization * fix: make global ask cutoff source-of-truth * test: reproduce Global Ask cutoff bind regression * fix: preserve global ask tenant scope * docs: assign unique ADR numbers after stack merge
* feat: name Weekly VOC and focus Event Lineage (v2.13.0) Weekly VOC keeps Voice of Customer posts for the latest ISO-8601 week. Opening that filtered post focuses Event Lineage. Home-list opens do not. * feat: open Calendar commitments onto Event Lineage (v2.14.0) Calendar names authorized commitments as current. Opening one focuses Event Lineage. Home-list opens do not. * feat: open Customer master related posts onto Event Lineage (v2.15.0) Customer master names authorized customer entities as current and to open a related post to read Event Lineage. That open focuses the popup Event Lineage heading and names Keyman and evaluation next. Home-list opens do not. No TEPP theta or customer is invented. * feat: open Ask Agent cited posts onto Event Lineage (v2.16.0) Ask Agent names authorized cited posts as current after an answer and to open one to read Event Lineage. That open focuses the popup Event Lineage heading and names Keyman and evaluation next. Home-list opens do not. No TEPP theta or cited post is invented. * feat: keep GNB Event Lineage focus on a linked DAG node (v2.17.0) Opening a linked Event Lineage node from a GNB-focused popup keeps Event Lineage focused and names Keyman and evaluation next. A home-list DAG walk does not. No TEPP theta or cited post is invented. * ci: repair analysis-run DAG cutoff context * ci: run buyer-surface cutoff repair test-first * ci: cover direct and DAG cutoff navigation * ci: restore canonical tests workflow * ci: remove temporary cutoff repair workflow * ci: repair analysis-run DAG cutoff context * ci: repair analysis-run cutoff navigation * chore: remove one-shot repair workflow * chore: remove duplicate cutoff repair workflow * ci: execute PR 264 cutoff repair * ci: run PR 264 cutoff repair on branch push * ci: repair ontology-grounded semantic paths on PR 264 * ci: run cutoff repair through canonical tests workflow * ci: stage deterministic PR 264 cutoff repair * ci: execute deterministic cutoff repair * fix(ui): preserve analysis-run cutoff across DAG navigation * ci: guard PR 264 against the unrelated ontology writer * ci: restore canonical PR 264 verification * ci: add direct ontology semantic-path repair * ci: remove completed cutoff repair helper * ci: replace stale semantic repair workflow * ci: execute ontology semantic-path repair * test: stage ontology semantic-path repair * ci: run test-first ontology semantic-path repair * ci: move semantic-path repair out of PR 264 * ci: remove relocated semantic-path repair helper * ci: consolidate PR 264 Knowledge Graph semantic repair * ci: keep semantic repair exact-head safe * test: align semantic repair fixtures with production schema * chore: stage project-history RED-GREEN payload (1/4) * chore: stage project-history RED-GREEN payload (2/4) * chore: stage project-history RED-GREEN payload (3/4) * chore: stage project-history RED-GREEN payload (4/4) * chore: run project-history RED-GREEN verification * feat: name Weekly VOC and focus Event Lineage (v2.13.0) Weekly VOC keeps Voice of Customer posts for the latest ISO-8601 week. Opening that filtered post focuses Event Lineage. Home-list opens do not. * fix: reject impossible Weekly VOC dates * feat: open Calendar commitments onto Event Lineage (v2.14.0) Calendar names authorized commitments as current. Opening one focuses Event Lineage. Home-list opens do not. * fix: stop auto-drilled Keyman panel from stealing Event Lineage focus Opening a post from Weekly VOC or Calendar (ADR 0093/0094) focuses the Event Lineage heading and merely names Keyman/evaluation as the next read. But KeymanPanel's landFirstRelated effect unconditionally auto-drilled into the first related node and, once that async chain resolved, yanked focus to the Ask panel -- even though no one asked for the Ask hand-off in that flow. That silent focus jump is exactly the behavior the report-member flow (ADR 0078) does want, so the fix threads a focusAskOnLand flag through PostDetailPopup -> KeymanPanel and only lets the drill claim focus for the report-member open. Confirmed pre-existing on this branch's own pristine tip (reproduced before merging anything else in), not introduced by any local change. * fix: keep Calendar scroll with Event Lineage * feat: open Customer master related posts onto Event Lineage (v2.15.0) Customer master names authorized customer entities as current and to open a related post to read Event Lineage. That open focuses the popup Event Lineage heading and names Keyman and evaluation next. Home-list opens do not. No TEPP theta or customer is invented. * test: keep customer master router specific * feat: open Ask Agent cited posts onto Event Lineage (v2.16.0) Ask Agent names authorized cited posts as current after an answer and to open one to read Event Lineage. That open focuses the popup Event Lineage heading and names Keyman and evaluation next. Home-list opens do not. No TEPP theta or cited post is invented. * feat: keep GNB Event Lineage focus on a linked DAG node (v2.17.0) Opening a linked Event Lineage node from a GNB-focused popup keeps Event Lineage focused and names Keyman and evaluation next. A home-list DAG walk does not. No TEPP theta or cited post is invented. * fix(ui): preserve analysis-run cutoff across DAG navigation * fix: ignore stale post detail responses * ci: make project-history repair observable on the stacked PR * feat: name Weekly VOC and focus Event Lineage (v2.13.0) Weekly VOC keeps Voice of Customer posts for the latest ISO-8601 week. Opening that filtered post focuses Event Lineage. Home-list opens do not. * fix: reject impossible Weekly VOC dates * feat: open Calendar commitments onto Event Lineage (v2.14.0) Calendar names authorized commitments as current. Opening one focuses Event Lineage. Home-list opens do not. * fix: stop auto-drilled Keyman panel from stealing Event Lineage focus Opening a post from Weekly VOC or Calendar (ADR 0093/0094) focuses the Event Lineage heading and merely names Keyman/evaluation as the next read. But KeymanPanel's landFirstRelated effect unconditionally auto-drilled into the first related node and, once that async chain resolved, yanked focus to the Ask panel -- even though no one asked for the Ask hand-off in that flow. That silent focus jump is exactly the behavior the report-member flow (ADR 0078) does want, so the fix threads a focusAskOnLand flag through PostDetailPopup -> KeymanPanel and only lets the drill claim focus for the report-member open. Confirmed pre-existing on this branch's own pristine tip (reproduced before merging anything else in), not introduced by any local change. * fix: keep Calendar scroll with Event Lineage * feat: open Customer master related posts onto Event Lineage (v2.15.0) Customer master names authorized customer entities as current and to open a related post to read Event Lineage. That open focuses the popup Event Lineage heading and names Keyman and evaluation next. Home-list opens do not. No TEPP theta or customer is invented. * test: keep customer master router specific * feat: open Ask Agent cited posts onto Event Lineage (v2.16.0) Ask Agent names authorized cited posts as current after an answer and to open one to read Event Lineage. That open focuses the popup Event Lineage heading and names Keyman and evaluation next. Home-list opens do not. No TEPP theta or cited post is invented. * feat: keep GNB Event Lineage focus on a linked DAG node (v2.17.0) Opening a linked Event Lineage node from a GNB-focused popup keeps Event Lineage focused and names Keyman and evaluation next. A home-list DAG walk does not. No TEPP theta or cited post is invented. * fix(ui): preserve analysis-run cutoff across DAG navigation * fix: ignore stale post detail responses * feat: name Weekly VOC and focus Event Lineage (v2.13.0) Weekly VOC keeps Voice of Customer posts for the latest ISO-8601 week. Opening that filtered post focuses Event Lineage. Home-list opens do not. * fix: reject impossible Weekly VOC dates * feat: open Calendar commitments onto Event Lineage (v2.14.0) Calendar names authorized commitments as current. Opening one focuses Event Lineage. Home-list opens do not. * fix: stop auto-drilled Keyman panel from stealing Event Lineage focus Opening a post from Weekly VOC or Calendar (ADR 0093/0094) focuses the Event Lineage heading and merely names Keyman/evaluation as the next read. But KeymanPanel's landFirstRelated effect unconditionally auto-drilled into the first related node and, once that async chain resolved, yanked focus to the Ask panel -- even though no one asked for the Ask hand-off in that flow. That silent focus jump is exactly the behavior the report-member flow (ADR 0078) does want, so the fix threads a focusAskOnLand flag through PostDetailPopup -> KeymanPanel and only lets the drill claim focus for the report-member open. Confirmed pre-existing on this branch's own pristine tip (reproduced before merging anything else in), not introduced by any local change. * fix: keep Calendar scroll with Event Lineage * feat: open Customer master related posts onto Event Lineage (v2.15.0) Customer master names authorized customer entities as current and to open a related post to read Event Lineage. That open focuses the popup Event Lineage heading and names Keyman and evaluation next. Home-list opens do not. No TEPP theta or customer is invented. * test: keep customer master router specific * feat: open Ask Agent cited posts onto Event Lineage (v2.16.0) Ask Agent names authorized cited posts as current after an answer and to open one to read Event Lineage. That open focuses the popup Event Lineage heading and names Keyman and evaluation next. Home-list opens do not. No TEPP theta or cited post is invented. * feat: keep GNB Event Lineage focus on a linked DAG node (v2.17.0) Opening a linked Event Lineage node from a GNB-focused popup keeps Event Lineage focused and names Keyman and evaluation next. A home-list DAG walk does not. No TEPP theta or cited post is invented. * fix(ui): preserve analysis-run cutoff across DAG navigation * fix: ignore stale post detail responses * feat: name Weekly VOC and focus Event Lineage (v2.13.0) Weekly VOC keeps Voice of Customer posts for the latest ISO-8601 week. Opening that filtered post focuses Event Lineage. Home-list opens do not. * fix: reject impossible Weekly VOC dates * feat: open Calendar commitments onto Event Lineage (v2.14.0) Calendar names authorized commitments as current. Opening one focuses Event Lineage. Home-list opens do not. * fix: stop auto-drilled Keyman panel from stealing Event Lineage focus Opening a post from Weekly VOC or Calendar (ADR 0093/0094) focuses the Event Lineage heading and merely names Keyman/evaluation as the next read. But KeymanPanel's landFirstRelated effect unconditionally auto-drilled into the first related node and, once that async chain resolved, yanked focus to the Ask panel -- even though no one asked for the Ask hand-off in that flow. That silent focus jump is exactly the behavior the report-member flow (ADR 0078) does want, so the fix threads a focusAskOnLand flag through PostDetailPopup -> KeymanPanel and only lets the drill claim focus for the report-member open. Confirmed pre-existing on this branch's own pristine tip (reproduced before merging anything else in), not introduced by any local change. * fix: keep Calendar scroll with Event Lineage * feat: open Customer master related posts onto Event Lineage (v2.15.0) Customer master names authorized customer entities as current and to open a related post to read Event Lineage. That open focuses the popup Event Lineage heading and names Keyman and evaluation next. Home-list opens do not. No TEPP theta or customer is invented. * test: keep customer master router specific * feat: open Ask Agent cited posts onto Event Lineage (v2.16.0) Ask Agent names authorized cited posts as current after an answer and to open one to read Event Lineage. That open focuses the popup Event Lineage heading and names Keyman and evaluation next. Home-list opens do not. No TEPP theta or cited post is invented. * feat: keep GNB Event Lineage focus on a linked DAG node (v2.17.0) Opening a linked Event Lineage node from a GNB-focused popup keeps Event Lineage focused and names Keyman and evaluation next. A home-list DAG walk does not. No TEPP theta or cited post is invented. * fix(ui): preserve analysis-run cutoff across DAG navigation * fix: ignore stale post detail responses * chore: restack project history on current Event Lineage head * ci: pin project history to the live parent head * test(projects): define evidence-bound project history contract * chore(projects): remove cancelled one-shot project-history workflow * chore(projects): remove cancelled project-history payload part 1 * chore(projects): remove cancelled project-history payload part 2 * test(ui): define accessible project-history timeline contract * test(projects): classify every visible VOC record * feat(projects): port evidence-bound history core for RED repair * fix(projects): keep lifecycle projection evidence-bound * fix(ui): keep project-history selection and tab semantics current * fix(ui): make project-history evidence and time semantics explicit * docs: assign unique ADR number to Valkey operation decision * ci: export exact project history source for local verification * ci: move source export off the saturated Linux queue * test(projects): expose truth and identity boundary gaps * fix(projects): preserve identity and evidence truth boundaries * fix(projects): enforce exact identity and evidence truth at the read boundary * fix(projects): render observed and inferred responsibility evidence honestly * fix(projects): expose per-evidence truth in the timeline * feat(projects): wire authorized history into buyer surfaces * test(projects): distinguish observed and inferred responsibility evidence * docs(storybook): show project-history truth states * fix(projects): keep timeline compatible with persisted evidence * fix(projects): focus timeline on opened source post * fix(project-history): preserve exact identity and isolate matches * docs: refresh project gap exact-head checkpoint * chore: remove completed project history bootstrap * chore: align project history release version * fix: preserve project history evidence truth in buyer UI * fix: bound and explain project history loading * test: align project history document clock copy * fix: preserve project history focus across key normalization * feat: recover TEPP validation on canonical Project history (v2.19.0) (#339) * test: specify recovered TEPP project-history boundary * test: specify TEPP project-history buyer evidence * feat: recover strict TEPP project-history client * feat: map canonical project history into TEPP contract * feat: render TEPP validation beside canonical history * style: add TEPP project-history evidence panel * docs: add TEPP project-history Storybook states * chore: stage one-shot TEPP project-history recovery * docs: record recovered TEPP project-history boundary * ci: execute verified TEPP project-history recovery * fix(i18n): cover Vietnamese TEPP project-history copy * test(red): require TEPP evidence on canonical timeline * fix(ci): make TEPP recovery red gate integration-specific * fix(ui): harden TEPP evidence semantics and accessibility * test(ui): cover TEPP evidence labels and unique regions * test(red): reject unrecognized TEPP findings and invalid responses * fix(ci): apply complete strict TEPP recovery contract * ci: format and lint TEPP recovery before commit * docs(adr): close TEPP finding vocabulary and response boundary * fix(ci): cancel stale TEPP recovery attempts * feat: materialize TEPP project history recovery * test: keep TEPP evidence type-safe * fix: fail closed on unknown TEPP findings * fix(http): let strict contracts suppress LLM metadata * fix(tepp): keep contextual metadata out of strict payloads * test(tepp): prove strict payloads suppress LLM metadata * fix(tepp): preserve strict validation while suppressing metadata * fix(tepp): normalize unexpected provider failures * fix: enforce TEPP project history byte limits * fix: order TEPP history events by timestamp * fix: sanitize TEPP transport provider errors * docs: record TEPP provider error boundary * feat: connect Ask answers to canonical project histories (v2.20.0) (#342) * test(red): require authorization-safe Ask project histories * test(red): require canonical project histories in Ask answers * chore: stage project-history Ask integration transform * ci: verify project-history Ask integration * fix(ci): repair Ask transform f-string and import anchors * fix(ci): repair generated Ask SQL before verification * test(red): persist the exact post Ask knowledge cutoff * fix(ci): preserve exact Ask cutoffs and stale-request safety * ci: verify exact persisted Ask cutoffs * ci: trigger Ask integration verification on stacked PR * ci: restack Ask integration on latest TEPP recovery * fix(ci): bind persisted Ask clocks to one application timeline * test(ask): keep persisted answer time after its cutoff * ci: verify hardened Ask cutoff persistence * test(db): reserve the next migration after project history * fix(ci): allocate Ask cutoff migration after project history * test(db): use the next available migration sequence * fix(ci): allocate the first free Ask cutoff migration * feat: connect Ask answers to project histories * docs: record Ask integration gate * docs: avoid stale self head checkpoint * fix: contain provider failures across Ask and TEPP * ci: verify PR 342 Global Ask stabilization * ci: publish verified PR 342 stabilization * fix: make global ask cutoff source-of-truth * test: reproduce Global Ask cutoff bind regression * fix: preserve global ask tenant scope * docs: assign unique ADR numbers after stack merge --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Buyer outcome
Post-scoped Ask and Global Ask citations now open the same authorization-first Project history used by the dedicated Buyer destination. The integration reuses the canonical project query, timeline, and optional TEPP validation rather than creating parallel authority.
Exact stack
59d687e746bfa504302e4b4a3752615c3653ec35.7d2654fb19ba7a88815edcefeb0a44f1bd05f619.Product and security boundary
Ask returns structured links only from cited posts that pass current tenant ABAC, publication eligibility, and the answer knowledge cutoff. Exact source project identity outranks inferred identity. Opening a link lazily reuses the canonical timeline and optional TEPP metadata; it never creates a second project query, classifier, timeline, or TEPP client. Persisted answers are withheld when any citation loses visibility, and stale Global Ask sessions must restart before hidden prose is reused. Citation UUIDs are validated before SQL. Unexpected contextual-orchestrator/provider errors return a generic 503 without raw provider details.
Stabilization already applied without retreat
The committed product source contains the following fixes; temporary repair workflows are absent.
cutoffas positional argument$4.authorized_entity_ids, preserving private-visibility scope even when the public API receives a one-shot iterable.0054, while canonical Project-history lookup retains0053.Remaining current-head blocker
The current implementation persists a Global Ask turn before performing its final post-persist citation reauthorization. If that reauthorization fails, the generic 503 is correct, but the rejected turn remains in the session and can force every later request to restart with 409.
Issue #362 owns the non-regressive fix: persist and final reauthorization must run inside one outer PostgreSQL transaction, and the existing 503 must be raised inside that transaction so the rejected turn and citation rows roll back. The post-persist race check, ABAC, cutoff, existing session continuity, and prior successful turns must remain intact. #342 is not merge-ready until that fix is present on the accepted stack and its real PostgreSQL rollback/session-continuity test passes.
Tracked non-blocking hardening
Verification evidence and live gate
Fresh hosted runs were created for
7d2654fb19ba7a88815edcefeb0a44f1bd05f619:32454001638)32454001628)32454001635)Queued status is not success, and these runs predate the still-required #362 product fix. The final accepted head must rerun focused tests, the real PostgreSQL contracts, complete Python and frontend suites, lint, production build, Storybook, migration replay, compile/import checks, and diff hygiene.
Merge gate
Merge only after:
Predecessor-head, queued, pending, author-only, and child-derived evidence is not transferable.