FE-674: Open downstream-review rows on hard-impact edit#115
FE-674: Open downstream-review rows on hard-impact edit#115kostandinang wants to merge 6 commits into
Conversation
2784229 to
6b94227
Compare
6b94227 to
fd82cc7
Compare
PR SummaryMedium Risk Overview Adds a V3.0 relation→need-kind mapping ( Reviewed by Cursor Bugbot for commit e77c0a6. Bugbot is set up for automated code reviews on this repo. Configure here. |
🤖 Augment PR SummarySummary: This PR activates the V3.0 “Path 1” hard-impact cascade producer by applying hard-impact edits server-side and opening Changes:
Technical Notes: The hard-impact apply contract is now “apply + enqueue needs”; UI surface for Pending review remains deferred to the next card while keeping the banner as the temporary signal. 🤖 Was this summary useful? React with 👍 or 👎 |
40b955f to
c71b58a
Compare
fd82cc7 to
9755778
Compare
Hard-impact propose_edit apply now mutates the source content/rationale and
opens one reconciliation_need row per typed dependency edge incident on the
changed item, returning openedNeedIds in the apply response. Replaces the V2
deferred no-op behavior with the substrate Path 1 producer per
docs/design/MULTI_CHAT.md §5.1 and SPEC.md D139 / I112.
Server:
- New src/server/cascade-producer.ts — table-driven relationToKind mapping
(depends_on / constrains / verifies → needs_confirmation; derived_from /
refines → supersedes). Reviewable in isolation via cascade-producer.test.ts.
- New db.getDownstreamEdges — like getDownstreamItems but preserves the edge
relation alongside each downstream item id.
- New db.openReconciliationNeedIfAbsent — wraps openReconciliationNeed with a
pre-check on the (source, target, kind) partial unique index so re-applying
the same hard-impact edit reports openedNeedIds: [] rather than throwing.
- handlePatchKnowledgeItem hard branch: applies source change, enumerates
downstream edges, opens one need per (downstream, relation), returns
{ impact: 'hard', updated: true, previousContent, previousRationale,
openedNeedIds, affectedItems }.
- Optional causedByTurnId in the request payload threads side-chat turn
provenance into the new reconciliation_need rows.
Client:
- edit-api EditItemResponse: hard variant flips updated: false → true and
carries previousContent / previousRationale / openedNeedIds.
- edit-applier deferred-banner trigger moves from !response.updated to
response.impact === 'hard'. The banner stays as the user-visible signal
until card 2 ships the Pending review surface in patch-list-overlay.
Tests:
- 5 new cases in edit-route.test.ts cover the new contract (apply, kind
mapping, idempotent re-apply, caused_by_turn_id provenance, prior values
on hard apply).
- cascade-producer.test.ts asserts every relation enum value table-driven.
- edit-applier.test.ts updated for the new deferred trigger and undo error
message.
Verified: npm run verify (1047 tests).
Wrap the source-content mutation and the per-edge reconciliation_need inserts in a single db.transaction so a partial failure (FK violation, write error) can't leave the knowledge item updated without its cascade needs. Without the transaction, the source would mutate, the first insert could fail, and the client would never see those rows in pending review. Also validate causedByTurnId before any write: the foreign key with foreign_keys = ON would otherwise throw at insert time on a stale or wrong-spec turn id and surface as a 500. We now look the turn up and require it to belong to this specificationId, returning 400 on mismatch. (A wrong-spec turn is just as broken as a missing one — it would attribute the cascade to an unrelated chat.)
The V3.0 server contract always applies the content change and, for hard-impact edits, also opens reconciliation_need rows. When an undo's restore request gets reclassified as hard, the server has already restored previousContent and opened cascade needs — but the client was throwing 'Edit undo blocked' and skipping invalidateEntityQueriesAfterEdit, leaving the page-visible item stale and silently swallowing the new cascade needs (the undo failure surfaces from patch-list-host as a silent return-false). Drop the throw and invalidate unconditionally so the UI matches server state. Newly-opened cascade needs land naturally in card 2's Pending review surface.
9755778 to
9944024
Compare
c71b58a to
4ae654f
Compare
The undo path no longer throws when the restore edit comes back as hard-impact; the server always applies and the applier invalidates unconditionally.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1337891. Configure here.


What
When the user applies a hard-impact edit, the server now writes one pending review row per downstream item that depends on the edited source.
Stacked on #105. First of three V3.0 PRs.
Why
Before this, hard-impact apply was a no-op: the server returned
{ updated: false }and the client showed a "coming in V3" banner. Nothing actually changed in the spec or the queue.How
cascade-producer.tsmaps relation → need kind:depends_on / constrains / verifies → needs_confirmation;derived_from / refines → supersedes.Test plan