Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 26 additions & 0 deletions docs/JOURNAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,32 @@ or files, and the "so-what" for future readers.

---

## 2026-07-16 — Hypothesis identity is the label; case delete doesn't cascade the map (26 H.1)

Tags: `design`.

Two H.1 choices a contributor might second-guess
(`src/shared/hypothesis-model.js`, `hypothesis-map.js`):

**Label-derived ids + normalized-label merge.** A hypothesis id hashes
`(case_id | normalized label)` — not the statement — and the map
builder merges brief-seeded positions with persisted records by
normalized label. Position labels are already the join key inside the
brief itself (`cruxes[].sides[].position_label`), and label-as-identity
lets a seed and its later human promotion converge on one record
without persisting anything at seed time. Cost: labels are immutable
(rename = delete + re-create), stated in the module header.

**Case delete leaves the map in place.** The sidepanel's entity delete
preserves dependents everywhere else (claims keep `about` refs, briefs
stay in `xray-audits`), and case entity ids are name-derived — so a
deleted-then-recreated case reattaches its hypotheses. Claim delete
DOES cascade edges (the reader flow calls
`HypothesisEdgeModel.deleteForClaim` beside the EvidenceLinker hook);
`deleteForCase` exists as the explicit clear-the-map seam for H.3 UI.

---

## 2026-07-16 — xray-network stays out of WORKSPACE_DATABASES (25.2b)

Tags: `design`.
Expand Down
6 changes: 6 additions & 0 deletions src/reader/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { recordAccount, extractPostAuthor } from '../shared/identity/account-reg
import { selectAccountsToPublish } from '../shared/identity/account-publish.js';
import { ClaimModel, exactFromAnchor } from '../shared/claim-model.js';
import { EvidenceLinker } from '../shared/evidence-linker.js';
import { HypothesisEdgeModel } from '../shared/hypothesis-model.js';
import * as ArchiveCache from '../shared/archive-cache.js';
import { recordAlias, resolveAlias } from '../shared/url-aliases.js';
import { installEntityTagger, rehydrateEntityMarks, renderEntitiesBar, extractParagraphContext } from './entity-tagger.js';
Expand Down Expand Up @@ -2605,6 +2606,7 @@ async function confirmDeleteClaim(id) {
// user sees the blast radius before confirming.
const links = await EvidenceLinker.getForClaim(id);
const assessment = await AssessmentModel.getByClaimRef(id);
const hypothesisEdges = await HypothesisEdgeModel.getForClaim(id);
const lines = [];
if (claim.publishedAt) {
lines.push('Already-published kind-30040 stays on relays until NIP-09 delete (later phase).');
Expand All @@ -2615,6 +2617,9 @@ async function confirmDeleteClaim(id) {
if (assessment) {
lines.push('Your assessment of it will also be removed.');
}
if (hypothesisEdges.length > 0) {
lines.push(`${hypothesisEdges.length} hypothesis attachment${hypothesisEdges.length === 1 ? '' : 's'} will also be removed.`);
}
const msg = lines.length > 0
? `Delete claim? ${lines.join(' ')}`
: 'Delete claim?';
Expand All @@ -2623,6 +2628,7 @@ async function confirmDeleteClaim(id) {
// registry, so it must still see the claim while matching.
if (links.length > 0) await EvidenceLinker.deleteForClaim(id);
if (assessment) await AssessmentModel.delete(assessment.id);
if (hypothesisEdges.length > 0) await HypothesisEdgeModel.deleteForClaim(id);
// 13.6's dependent: a prediction promoted into this claim holds a
// claim_ref — left dangling it defers the 30058 at every publish
// forever and the audit panel shows a permanent "claim ✓".
Expand Down
Loading