feat(dedup): a note or task blocks only as a copy; a close match is surfaced for judgement (#4306)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 10s
CI & Build / TypeScript typecheck (push) Successful in 58s
CI & Build / integration (push) Successful in 1m12s
CI & Build / Python tests (push) Failing after 1m29s
CI & Build / Build & push image (push) Skipped
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 10s
CI & Build / TypeScript typecheck (push) Successful in 58s
CI & Build / integration (push) Successful in 1m12s
CI & Build / Python tests (push) Failing after 1m29s
CI & Build / Build & push image (push) Skipped
Measured on the live corpus, the 74 note pairs at or above the old 0.90 bar were almost all distinct siblings — consecutive dev-logs, sub-notes of one design, research parts — and the one clear copy sat at 0.997. The block refused the next dev-log and taught force=true, as #4134 found for rules. - The semantic arm blocks notes and tasks only at >= 0.98. The title block stays; processes keep 0.90 (not measured). - 0.87 to 0.98 comes back as `overlaps` on the create reply, from the same per-chunk searches, with a note that leaves the call to the session: fold in and delete if it is the same record, keep both if a sibling. - create_note, create_task, create_records and start_planning's steps all carry it; a batch names the record each overlap belongs to. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -183,11 +183,14 @@ async def create_note(
|
||||
"When Forgejo issues run numbers per workflow rather than per
|
||||
repository", not "in six months". Constraints expire when the
|
||||
ground moves, not on a schedule.
|
||||
force: Bypass the near-duplicate gate. By default, if a title- or
|
||||
meaning-similar note already exists in the same project, creation is
|
||||
BLOCKED and the existing note's id is returned so you update it
|
||||
instead (no duplicate bloat / no stale RAG copies). Set true only
|
||||
when you're sure this is a genuinely distinct note.
|
||||
force: Bypass the near-duplicate gate. By default, a note with the
|
||||
same title, or one that reads as a copy, in the same project BLOCKS
|
||||
the create and its id is returned so you update it instead. A note
|
||||
that reads CLOSE but not identical does not block: the note is
|
||||
created and the reply carries `overlaps` — open the top one and
|
||||
judge it. Same thing: fold into it and delete the new one. A
|
||||
sibling (the next dev-log, another part of one design): keep both.
|
||||
Set force true only when a blocked note is genuinely distinct.
|
||||
|
||||
AN ID EXISTS ONLY ONCE A CREATE RETURNS IT. A body citing a `#N` that has
|
||||
not been assigned yet is refused — every session and user draws from one
|
||||
@@ -203,10 +206,11 @@ async def create_note(
|
||||
"""
|
||||
uid = current_user_id()
|
||||
await refuse_guessed_ids(title, body)
|
||||
overlaps: list = []
|
||||
if not force:
|
||||
dup = await dedup_svc.find_duplicate_note(
|
||||
uid, title, body, project_id=project_id or None,
|
||||
is_task=False, note_type="note",
|
||||
is_task=False, note_type="note", overlaps=overlaps,
|
||||
)
|
||||
if dup is not None:
|
||||
return dedup_svc.duplicate_response(dup, "note")
|
||||
@@ -231,6 +235,7 @@ async def create_note(
|
||||
data = note.to_dict()
|
||||
await systems_tools.attach_systems(uid, uid, data, note.id, project_id or None)
|
||||
await supersession_svc.attach_relations(uid, note.id, data, hint=True)
|
||||
data.update(dedup_svc.note_overlap_response(overlaps, "note"))
|
||||
return data
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user