diff --git a/packages/ui/README.md b/packages/ui/README.md --- a/packages/ui/README.md +++ b/packages/ui/README.md @@ -29,13 +29,18 @@ | `src/lib/store.ts`, `src/lib/idb.ts` | `RecordStore` and `SyncStateStore` over an in-memory mirror hydrated from IndexedDB. Synchronous reads, background writes, one database per space. | | `src/lib/identity.ts` | DID → PDS and DID → handle, cached. A handle is shown only when it resolves back to the DID that claimed it. | | `src/lib/units.ts` | presentation over `timeline()` — a row's line, its badges, whose disc ends it, and the two cross-target capture relations no single target's fold can see. | -| `src/lib/requests.ts`, `verdicts.ts`, `admin.ts` | what each surface may offer and what it writes, as pure functions: the ⊕ menu, the verdict and its findings, the space's own shape. Tested without rendering anything. | +| `src/lib/requests.ts`, `verdicts.ts`, `admin.ts` | what each surface may offer and what it writes, as pure functions: the ⊕ menu, the review and its findings, the space's own shape. Tested without rendering anything. | | `src/lib/diagnostics.ts` | `index.ignored` and `index.edits`, grouped for reading. | | `src/lib/keys.ts`, `focus.ts` | the keyboard map, and putting focus back where it was. | | `src/lib/directory.ts` | membership → the row an actor gets: kind, initials, disc colour. Colour is derived from the DID, never authored. | | `src/lib/prose.ts` | the comp's tiny `## ` + backtick grammar. Parses to a structure; the component interpolates it. No `{@html}` anywhere near an agent-authored body. | | `src/lib/components/` | rail, pane bar, space picker, state circle, pie, badges, discs, unit rows and drawers, compose cards, smart lists. | | `bin/serve.ts` | `radial-ui`: the built bundle on loopback, and nothing else. | + +One word for one thing: a **review** is the act, the record, the request for one and the queue of +ones owed, and that is the only word the copy uses. A **verdict** is just the review record's +`verdict` field — `approve` or `request_changes` — which is why `verdicts.ts` keeps its name and why +the UI shows that field as the badges `approved` and `changes` rather than as a bare noun. ### Opening a space diff --git a/packages/ui/src/lib/admin.ts b/packages/ui/src/lib/admin.ts --- a/packages/ui/src/lib/admin.ts +++ b/packages/ui/src/lib/admin.ts @@ -402,7 +402,7 @@ * for a review without anybody pressing anything. * * Every registry type gets a row, both scopes, because the daemon's trigger scans goals and - * projects alike — a project-scoped document lands and is owed a verdict the same way. + * projects alike — a project-scoped document lands and is owed a review the same way. */ export interface AutoReviewRow { type: string diff --git a/packages/ui/src/lib/requests.ts b/packages/ui/src/lib/requests.ts --- a/packages/ui/src/lib/requests.ts +++ b/packages/ui/src/lib/requests.ts @@ -203,7 +203,7 @@ .sort((left, right) => left.name.localeCompare(right.name)) } -/** Nothing has judged this version. Building something new on it is the soft-policy case (design §7). */ +/** Nothing has approved this version. Building something new on it is the soft-policy case (design §7). */ export const unapproved = (version: UnitVersion | undefined): boolean => version !== undefined && version.verdict !== 'approve' @@ -232,7 +232,7 @@ /** The one sentence both the drawer and the card say, so they cannot come to disagree. */ export const softPolicyNote = (label: string): string => - `${label} has no approving verdict. You can still build on it — reviews annotate, they don’t gate.` + `${label} is not approved. You can still build on it — reviews annotate, they don’t gate.` /** * The request a retraction would withdraw, or nothing. diff --git a/packages/ui/src/lib/space.test.ts b/packages/ui/src/lib/space.test.ts --- a/packages/ui/src/lib/space.test.ts +++ b/packages/ui/src/lib/space.test.ts @@ -113,7 +113,16 @@ expect(texts).toEqual(['approved', '3/3 checks', 'PR #241', 'merged']) }) - it('counts what is stopped on a person: one question, two verdicts owed', () => { + it('badges a landed artifact nothing has pinned as not reviewed', () => { + const ignored = space.index.goals.find( + (goal) => goal.target.value.title === 'Surface the records the fold ignored', + ) + const unit = ignored && unitsOf(space.index, ignored).find((u) => u.type === 'plan') + if (!unit) throw new Error('fixture unit missing') + expect(unitBadges(unit, { now: space.asOf }).map((badge) => badge.text)).toContain('not reviewed') + }) + + it('counts what is stopped on a person: one question, two reviews owed', () => { const all = unitsWithContext(space.index) expect(all.filter(({ unit }) => isAwaiting(unit))).toHaveLength(1) // Landing is not done. Both units of the ignored-records goal landed with nothing pinned to diff --git a/packages/ui/src/lib/space.ts b/packages/ui/src/lib/space.ts --- a/packages/ui/src/lib/space.ts +++ b/packages/ui/src/lib/space.ts @@ -120,7 +120,7 @@ /** * Deep link that opens one unit's drawer: what a cross-goal row points at. * - * `v` is carried only when the row stands for a particular version — a verdict owed on v1 must open + * `v` is carried only when the row stands for a particular version — a review owed on v1 must open * on v1, not on whatever has landed since. Without it the drawer follows the tip, which is what * every other row means. * diff --git a/packages/ui/src/lib/units.ts b/packages/ui/src/lib/units.ts --- a/packages/ui/src/lib/units.ts +++ b/packages/ui/src/lib/units.ts @@ -39,7 +39,7 @@ target: GoalView | ProjectView /** * The exact version this row stands for, when it stands for one rather than for the unit. A - * verdict owed is owed on one uri#cid (§3.7), so the queue's rows carry it and open the drawer + * review owed is owed on one uri#cid (§3.7), so the queue's rows carry it and open the drawer * there; every other list carries nothing and follows the tip. */ version?: UnitVersion @@ -82,12 +82,12 @@ * * Archiving says agents should skip a target, and `goalsOf()` already takes it at its word — an * archived goal is not on its project's page. A cross-goal list is the same claim seen from further - * away, so it has to honour the same rule: a verdict owed on an artifact under a shelved goal is not + * away, so it has to honour the same rule: a review owed on an artifact under a shelved goal is not * work stopped on anybody, and a list that keeps showing it is a list nobody can empty. * * Archiving a PROJECT shelves both kinds at once — its own system units, and every goal under it, the * same reach `activeGoals()` in core gives the daemon's dispatcher. Closure is deliberately NOT part - * of this: a closed goal can still owe somebody a verdict, and the daemon's rule sets it aside where + * of this: a closed goal can still owe somebody a review, and the daemon's rule sets it aside where * a reader's does not. */ export function liveUnits(index: MaterializedIndex): UnitContext[] { @@ -101,7 +101,7 @@ ) } -/** Landed, and no verdict pins the version being read. The queue's whole reason to exist. */ +/** Landed, and no review pins the version being read. The queue's whole reason to exist. */ export const needsVerdict = (unit: UnitView): boolean => unit.needsVerdict && unit.versions.length > 0 export const isAwaiting = (unit: UnitView): boolean => unit.state === 'awaiting' @@ -183,7 +183,7 @@ ? { kind: 'ok', glyph: '✓', text: 'approved' } : { kind: 'bad', glyph: '✕', text: 'changes' } -/** The tail of a unit row: state first, then verdict, then what the machines observed. */ +/** The tail of a unit row: state first, then the review, then what the machines observed. */ export function unitBadges(unit: UnitView, options: { now: string } = { now: '' }): RowBadge[] { const badges: RowBadge[] = [] if (unit.state === 'open') badges.push({ kind: 'flat', glyph: '○', text: 'open' }) @@ -196,7 +196,7 @@ if (unit.verdict) badges.push(verdictBadge(unit.verdict)) else if (unit.versions.length > 0 && !unit.retracted) - badges.push({ kind: 'flat', glyph: '◇', text: 'no verdict' }) + badges.push({ kind: 'flat', glyph: '◇', text: 'not reviewed' }) const checks = checkTally(unit.current) if (checks) @@ -212,7 +212,7 @@ return badges } -/** The state circle's shape. `landed` is the tip's state when nothing has judged it yet. */ +/** The state circle's shape. `landed` is the tip's state when nothing has reviewed it yet. */ export const dotState = (unit: UnitView): UnitState => unit.state export const stateLabel: Record = { @@ -220,8 +220,8 @@ assigned: 'assigned to an agent', claimed: 'claimed — a turn is under way', awaiting: 'awaiting your input', - landed: 'landed — awaiting your verdict', - judged: 'judged', + landed: 'landed — awaiting your review', + judged: 'reviewed', merged: 'merged', retracted: 'retracted', } diff --git a/packages/ui/src/lib/verdicts.test.ts b/packages/ui/src/lib/verdicts.test.ts --- a/packages/ui/src/lib/verdicts.test.ts +++ b/packages/ui/src/lib/verdicts.test.ts @@ -5,6 +5,7 @@ import { unitsOf } from './space.js' import { findVersion, liveUnits, unitsWithContext } from './units.js' import { + askedForReview, askReviewArgs, blankFinding, findingsOf, @@ -18,9 +19,9 @@ wroteVerdict, } from './verdicts.js' -// A verdict pins one exact version, and a request for one is a debt on that same version. Everything +// A review pins one exact version, and a request for one is a debt on that same version. Everything // here is that single rule seen from a different side: what the buttons produce, which request a -// verdict closes, and what the queue is a list of. +// review closes, and what the queue is a list of. const space = buildFixtureSpace() const goal = (title: string) => { @@ -67,7 +68,7 @@ }) }) -describe('what a verdict pins', () => { +describe('what a review pins', () => { it('names the version being read, by cid, and not the unit', () => { const plan = unit(QUEUE, 'plan') const [v1, v2] = plan.versions @@ -114,7 +115,7 @@ it('is offered on anything that landed, and on nothing that has not', () => { const plan = unit(IGNORED, 'plan') expect(judgeable(plan, plan.current)).toBe(true) - // An open request has no version to pin a verdict to. + // An open request has no version to pin a review to. const security = unit(QUEUE, 'security-review') expect(security.versions).toHaveLength(0) expect(judgeable(security, security.current)).toBe(false) @@ -136,7 +137,7 @@ }) }) -describe('the request a verdict answers', () => { +describe('the request a review answers', () => { const version = () => { const found = unit(IGNORED, 'implementation').current if (!found) throw new Error('fixture version missing') @@ -190,8 +191,8 @@ it('offers people and review-publishing agents, never the asker, never a producer of something else', () => { const reviewers = possibleReviewers(space.directory, FIXTURE_DIDS.tim).map((actor) => actor.name) - // Humans first — a verdict is a human judgement, and an agent one is a convenience. `jun` is on the - // list despite never having opened the space: asking for a verdict is membership, not attendance, + // Humans first — a review is a human judgement, and an agent one is a convenience. `jun` is on the + // list despite never having opened the space: asking for a review is membership, not attendance, // and being asked for one is a perfectly good reason to turn up. expect(reviewers).toEqual(['ana.dev', 'jun.example.com', 'reviewer']) // `builder` publishes implementations and `planner` publishes plans; neither judges. @@ -201,10 +202,19 @@ 'ana.dev', ) }) + + it('says which version was asked about, and whether anyone in particular was asked', () => { + const version = unit(IGNORED, 'plan').current + if (!version) throw new Error('fixture version missing') + expect(askedForReview(space.directory.get(FIXTURE_DIDS.ana), version)).toBe( + 'Review of v1 requested from ana.dev', + ) + expect(askedForReview(undefined, version)).toBe('Review of v1 requested — open to any member') + }) }) describe('the queue', () => { - it('lists the verdicts asked of one person, on the exact versions they were asked about', () => { + it('lists the reviews asked of one person, on the exact versions they were asked about', () => { const rows = reviewQueue(space.index, FIXTURE_DIDS.tim) expect(rows).toHaveLength(1) const [row] = rows @@ -214,7 +224,7 @@ expect(reviewQueue(space.index, FIXTURE_DIDS.ana)).toHaveLength(0) }) - it('falls back to every verdict owed by anyone when nobody is signed in', () => { + it('falls back to every review owed by anyone when nobody is signed in', () => { expect(reviewQueue(space.index)).toHaveLength(1) }) @@ -265,7 +275,7 @@ return materialize(store, { spaceUri: fixture.spaceUri, asOf: fixture.asOf }) } - it('drops both a verdict asked of somebody and one nobody asked for', () => { + it('drops both a review asked of somebody and one nobody asked for', () => { const index = archivedIndex() expect(index.goals.find((goal) => goal.target.uri === shelvedUri)?.archived).toBe(true) expect(reviewQueue(index, FIXTURE_DIDS.tim)).toEqual([]) diff --git a/packages/ui/src/lib/verdicts.ts b/packages/ui/src/lib/verdicts.ts --- a/packages/ui/src/lib/verdicts.ts +++ b/packages/ui/src/lib/verdicts.ts @@ -1,15 +1,30 @@ -// Judging one exact version. +// Reviewing one exact version. // -// A verdict is the human half of the loop: an agent lands an artifact, and nothing is done until a +// A review is the human half of the loop: an agent lands an artifact, and nothing is done until a // person says what they think of it. Everything in this file follows from one rule the fold already -// enforces (§3.7) — **a review pins a uri#cid, not a unit**. So the subject of a verdict is the +// enforces (§3.7) — **a review pins a uri#cid, not a unit**. So the subject of a review is the // version being *read*, never the unit's tip; browsing back to v1 and pressing Approve approves v1, // and a v3 landing mid-form cannot silently become what was signed. // -// The second rule is that a review request is not a unit either. It is a verdict owed on one exact +// The second rule is that a review request is not a unit either. It is a review owed on one exact // version, so it hangs off that version and the queue is a fold over versions rather than over // rows. That is why "For me" has two flavours: an artifact that landed with nothing pinned to it // (nobody asked; landing is not done), and a request that names a version and a person. +// +// ── One word for one thing ──────────────────────────────────────────────────────────────────── +// +// This file is named for the *field*, not for the act. The rule the UI keeps: +// +// A **review** is the thing — the act, the record, the request for one, and the queue of ones +// owed. All copy a person reads says review. +// +// A **verdict** is only the review record's `verdict` field, whose value is `approve` or +// `request_changes`. It stays in the lexicon, the `--verdict` flag, the types and the design +// system's colour vocabulary, and it never appears as a bare word in copy: the UI renders that +// field as the badges `approved` and `changes`. +// +// So `verdictArgs`, `Verdict`, `unit.verdict` and `needsVerdict` are right as they are, and a +// string in a template that says "verdict" is not. import type { ArtifactRequestRecord, @@ -25,11 +40,11 @@ import { liveUnits, typeLabel, type UnitContext } from './units.js' /** - * What a verdict calls the thing it is judging: the type and the version, always — `implementation + * What a review calls the thing it is judging: the type and the version, always — `implementation * v1`, not `implementation`. * * Everywhere else a lone version is written without its number, because "plan v1" where there has - * only ever been one plan is noise. Here it is the whole point: a verdict pins one uri#cid, and the + * only ever been one plan is noise. Here it is the whole point: a review pins one uri#cid, and the * card has to say which one even when saying it is redundant today and will not be tomorrow. */ export const pinnedLabel = (unit: UnitView, version: UnitVersion): string => @@ -84,7 +99,7 @@ * * Nothing about *who* is asking: anyone reading the row sees the buttons, and the card says why it * cannot be filled in — the same shape the compose card takes (6.4). What decides this is only - * whether there is something to judge: a request nobody has answered has no version to pin a verdict + * whether there is something to judge: a request nobody has answered has no version to pin a review * to, and a retracted unit was withdrawn. */ export const judgeable = (unit: UnitView, version: UnitVersion | undefined): boolean => @@ -106,7 +121,7 @@ * Preference order matters: one assigned to me, then an unassigned one, and never one assigned to * somebody else. The materializer marks a review request fulfilled when *any* trusted review names * it and pins the same subject — it does not check who wrote the review — so naming another agent's - * request would quietly cancel work that agent is doing. An unrequested verdict is always available + * request would quietly cancel work that agent is doing. An unrequested review is always available * and cancels nothing. */ export function owedBy( @@ -122,7 +137,7 @@ /** * `radial review post`. The subject is the version that was read, pinned by CID, and `--request` is - * present only when this verdict is answering one — that ref is what closes the request in the fold. + * present only when this review is answering one — that ref is what closes the request in the fold. */ export function verdictArgs( version: UnitVersion, @@ -147,7 +162,7 @@ return args } -/** What the toast says once the verdict is public. */ +/** What the toast says once the review is public. */ export const wroteVerdict = (verdict: Verdict, version: UnitVersion, fulfilled: boolean): string => { const what = verdict === 'approve' ? 'Approved' : 'Changes requested on' return `${what} v${version.version}${fulfilled ? ' — the review request is answered' : ''}` @@ -156,12 +171,12 @@ // ── asking somebody else for one ──────────────────────────────────────────────────────────────── /** - * Who can be asked for a verdict: every active member but the asker. + * Who can be asked for a review: every active member but the asker. * * Not the registry — `review` is deliberately absent from it, because it is a built-in of the turn * layer rather than a type an admin registers. So this list is *membership*, not capability: a human * judges because they are a person in this space, and an agent judges because its own - * self-description says it produces reviews. Asking yourself for a verdict is a no-op with extra + * self-description says it produces reviews. Asking yourself for a review is a no-op with extra * steps, so the asker is not on it. */ export function possibleReviewers(directory: Directory, did: string): Actor[] { @@ -177,7 +192,7 @@ * `radial request create --type review --subject …`. * * A review request carries a `subject` where every other request carries `basedOn`: it names the one - * version a verdict is owed on, rather than the provenance a new artifact is built from. That is + * version a review is owed on, rather than the provenance a new artifact is built from. That is * also why it never becomes a unit — there is no artifact coming, only a judgement. */ export function askReviewArgs(input: { @@ -205,20 +220,20 @@ export const askedForReview = (assignee: Actor | undefined, version: UnitVersion): string => assignee - ? `Verdict on v${version.version} requested from ${assignee.handle ?? assignee.name}` - : `Verdict on v${version.version} requested — open to any member` + ? `Review of v${version.version} requested from ${assignee.handle ?? assignee.name}` + : `Review of v${version.version} requested — open to any member` // ── the queue ─────────────────────────────────────────────────────────────────────────────────── /** - * Verdicts somebody was explicitly asked for: open review requests, resolved back to the unit and + * Reviews somebody was explicitly asked for: open review requests, resolved back to the unit and * the exact version each one pins. * * A fold over versions rather than over units, because that is where a review request lives. Two * requests on one version, or requests on two versions of one unit, are separate rows — each is a - * separate verdict owed. + * separate review owed. * - * With a DID it is that person's queue. Without one — nobody signed in — it is every verdict owed by + * With a DID it is that person's queue. Without one — nobody signed in — it is every review owed by * anyone, because a tab with no session still knows what this space is waiting on a human for, and * saying nothing would be less true than saying "these, by someone". */ @@ -239,7 +254,7 @@ } /** - * Verdicts nobody asked for: landed artifacts with nothing pinned to their current version and no + * Reviews nobody asked for: landed artifacts with nothing pinned to their current version and no * open review request on it either. This is the larger half of the queue in practice — an agent * delivers, and the work is with a person whether or not anyone wrote that down. */ diff --git a/packages/ui/src/lib/write.test.ts b/packages/ui/src/lib/write.test.ts --- a/packages/ui/src/lib/write.test.ts +++ b/packages/ui/src/lib/write.test.ts @@ -419,7 +419,7 @@ await write(verdictArgs(v1, { verdict: 'request_changes', findings })) - // The verdict pins v1 by cid, and the fold reads it back off the version rather than off the + // The review pins v1 by cid, and the fold reads it back off the version rather than off the // unit: this is what makes "judged" mean the same thing in a tab as it does in the daemon. const judged = unitOf('plan') expect(judged.versions[0]?.verdict).toBe('request_changes') @@ -442,7 +442,7 @@ ) // …and the turn that answers it is briefed with exactly what was said. This is the whole of the - // loop 6.5 closes: a verdict written in a browser tab is an input to the next turn, with no + // loop 6.5 closes: a review written in a browser tab is an input to the next turn, with no // daemon endpoint, no export step, and nothing between the two but the record stream. const bundle = buildTurnBundle(space().index, asked.primary.uri, asked.primary.cid) const mine = bundle.reviewFindings.filter( @@ -473,7 +473,7 @@ expect(space().index.ignored).toEqual([]) }) - it('asks somebody else for a verdict, and it is not a unit of its own', async () => { + it('asks somebody else for a review, and it is not a unit of its own', async () => { const harness = await open() signInAs(FIXTURE_DIDS.tim, harness.network) const version = unitOf('plan').current @@ -490,7 +490,7 @@ }), ) - // A verdict owed is a debt on one version, not a piece of work: it adds no row, it hangs off the + // A review owed is a debt on one version, not a piece of work: it adds no row, it hangs off the // version it pins, and it shows up in exactly one person's queue. expect(unitsOf(space().index, ignored())).toHaveLength(before) const owed = unitOf('plan').current?.reviewRequests ?? [] diff --git a/packages/ui/src/lib/components/AskReview.svelte b/packages/ui/src/lib/components/AskReview.svelte --- a/packages/ui/src/lib/components/AskReview.svelte +++ b/packages/ui/src/lib/components/AskReview.svelte @@ -49,10 +49,10 @@

- Ask for a verdict on {pinnedLabel(unit, version)} + Ask for a review of {pinnedLabel(unit, version)}

- A verdict owed on one exact version. It shows up in the assignee's queue and disappears from it + One exact version, put in front of one person. It shows up in the assignee's queue and leaves it the moment a review pins this version — it never becomes a row of its own, because nothing is being produced.

@@ -102,7 +102,7 @@ - +
{#if error} diff --git a/packages/ui/src/lib/components/Badge.svelte b/packages/ui/src/lib/components/Badge.svelte --- a/packages/ui/src/lib/components/Badge.svelte +++ b/packages/ui/src/lib/components/Badge.svelte @@ -1,7 +1,7 @@ diff --git a/packages/ui/src/lib/components/CrossRow.svelte b/packages/ui/src/lib/components/CrossRow.svelte --- a/packages/ui/src/lib/components/CrossRow.svelte +++ b/packages/ui/src/lib/components/CrossRow.svelte @@ -28,7 +28,7 @@ {entry.unit.type} - {#if entry.version && entry.unit.versions.length > 1} v{entry.version.version} diff --git a/packages/ui/src/lib/components/GoalRow.svelte b/packages/ui/src/lib/components/GoalRow.svelte --- a/packages/ui/src/lib/components/GoalRow.svelte +++ b/packages/ui/src/lib/components/GoalRow.svelte @@ -40,7 +40,7 @@ {/if} {#if toJudge > 0} - + {/if} {#each actors as actor (actor.did)} diff --git a/packages/ui/src/lib/components/Pie.svelte b/packages/ui/src/lib/components/Pie.svelte --- a/packages/ui/src/lib/components/Pie.svelte +++ b/packages/ui/src/lib/components/Pie.svelte @@ -3,7 +3,7 @@ // // It fills on the same rule the row circles use (`tally()` in core counts a unit that landed AND // was judged), so a goal cannot read "finished" while it still has an artifact waiting on a human - // verdict. + // review. interface Props { judged: number total: number @@ -14,7 +14,7 @@ const radius = 6.6 const circumference = Math.PI * radius const fraction = $derived(total ? judged / total : 0) - const label = $derived(total ? `${judged} of ${total} judged` : 'nothing requested yet') + const label = $derived(total ? `${judged} of ${total} reviewed` : 'nothing requested yet') diff --git a/packages/ui/src/lib/components/SmartList.svelte b/packages/ui/src/lib/components/SmartList.svelte --- a/packages/ui/src/lib/components/SmartList.svelte +++ b/packages/ui/src/lib/components/SmartList.svelte @@ -38,7 +38,7 @@

{group.hint}

{/if}
    - + {#each group.rows as entry (`${entry.unit.key}#${entry.version?.artifact.cid ?? ''}`)} {/each} diff --git a/packages/ui/src/lib/components/StateDot.svelte b/packages/ui/src/lib/components/StateDot.svelte --- a/packages/ui/src/lib/components/StateDot.svelte +++ b/packages/ui/src/lib/components/StateDot.svelte @@ -4,8 +4,8 @@ // The state circle: read-only. The network fills it in, the human judges it. // - // The ladder that matters: an OUTLINE tick means the work landed and nobody has judged it; a - // FILLED disc means a verdict is pinned to it. Landed is not done. + // The ladder that matters: an OUTLINE tick means the work landed and nobody has reviewed it; a + // FILLED disc means a review is pinned to it. Landed is not done. // // The one thing this draws that the comp did not: `assigned` and `claimed` are different circles. // A claim is the only signal the index has that a turn is genuinely under way, so it — and only diff --git a/packages/ui/src/lib/components/UnitDetail.svelte b/packages/ui/src/lib/components/UnitDetail.svelte --- a/packages/ui/src/lib/components/UnitDetail.svelte +++ b/packages/ui/src/lib/components/UnitDetail.svelte @@ -45,7 +45,7 @@ unit: UnitView view: GoalView | ProjectView space: Space - /** 1-based, from a link that stands for one version — a verdict owed on v1 opens on v1. */ + /** 1-based, from a link that stands for one version — a review owed on v1 opens on v1. */ startVersion?: number | undefined } const { unit, view, space, startVersion }: Props = $props() @@ -97,7 +97,7 @@ // an admin put `implementation` in the registry, not because this component knows what a plan is. // // They are asked against the version being READ, not the unit's tip — browsing back to v1 and - // asking for an implementation asks for one built on v1, which is the same rule the verdicts + // asking for an implementation asks for one built on v1, which is the same rule the reviews // follow. The card that opens carries that exact strongref. const scope = $derived<'goal' | 'project'>(isGoalView(view) ? 'goal' : 'project') const buildable = $derived(version && !unit.retracted ? buildableTypes(space.index, unit, scope) : []) @@ -124,19 +124,19 @@ } // ── judging it ──────────────────────────────────────────────────────────────────────────────── - // The verdict is on the version being READ, which is the same rule the successor buttons follow + // The review is on the version being READ, which is the same rule the successor buttons follow // and the rule the fold already enforces: a review pins a uri#cid (§3.7). One card at a time. let judging = $state(null) let asking = $state(false) const canJudge = $derived(judgeable(unit, version)) - // The verdict this reader was explicitly asked for, if any — what turns the button into an answer. + // The review this reader was explicitly asked for, if any — what turns the button into an answer. const owed = $derived(owedBy(version, account.did)) const judge = (verdict: Verdict): void => { asking = false judging = verdict } - // A written verdict re-reads the author's repo, so the version this drawer is showing already + // A written review re-reads the author's repo, so the version this drawer is showing already // holds it by the time the card closes. const closeCards = (): void => { judging = null @@ -361,14 +361,14 @@ /> by {reviewer.handle ?? reviewer.name} · {stamp(verdictReview.value.createdAt)} · pinned to - v{version.version}{#if !isCurrent} — superseded, but the verdict still stands on what it judged{/if} + v{version.version}{#if !isCurrent} — superseded, but the review still stands on what it judged{/if} {/if} {#if version?.reviewRequests.length}
    - + {#each version.reviewRequests as request, position (request.uri)} {@const from = space.directory.get(request.did)} @@ -382,7 +382,7 @@ {:else} any member {/if} - for a verdict on v{version.version} + for a review of v{version.version} {/each}
    @@ -391,7 +391,7 @@ {#if canJudge || canSucceed || retractable}
    {#if canJudge && version} - {#if canSucceed}{/if} {/if} diff --git a/packages/ui/src/lib/components/UnitRow.svelte b/packages/ui/src/lib/components/UnitRow.svelte --- a/packages/ui/src/lib/components/UnitRow.svelte +++ b/packages/ui/src/lib/components/UnitRow.svelte @@ -18,7 +18,7 @@ /** System rows lead with the record's identity rather than with its age. */ system?: boolean startOpen?: boolean - /** 1-based, from a link that stands for one version — a verdict owed on v1 opens on v1. */ + /** 1-based, from a link that stands for one version — a review owed on v1 opens on v1. */ startVersion?: number | undefined } const { unit, view, space, system = false, startOpen = false, startVersion }: Props = $props() diff --git a/packages/ui/src/lib/components/Verdict.svelte b/packages/ui/src/lib/components/Verdict.svelte --- a/packages/ui/src/lib/components/Verdict.svelte +++ b/packages/ui/src/lib/components/Verdict.svelte @@ -20,7 +20,7 @@ import UriChip from './UriChip.svelte' // The human half of the loop. It sits inside the drawer rather than at the top of the route the - // way a compose card does, because a verdict is not a new row — it is an annotation on the exact + // way a compose card does, because a review is not a new row — it is an annotation on the exact // version being read, and it belongs next to what it judges. interface Props { unit: UnitView @@ -32,7 +32,7 @@ } const { unit, version, space, initial, done }: Props = $props() - // Request-changes opens with a row waiting: a verdict that sends work back and says nothing about + // Request-changes opens with a row waiting: a review that sends work back and says nothing about // why is the one shape of review that is worse than no review. Approve opens with none, and an // approval with a note on it is a click away. let rows = $state( @@ -89,10 +89,10 @@ - Verdict on {pinned} + Review of {pinned}

    - Pinned to {pinned} by cid. A verdict judges one version and says nothing about any other: it does + Pinned to {pinned} by cid. A review judges one version and says nothing about any other: it does not lapse when a later one lands, and it does not reach back to an earlier one. {#if answering && asker} · answering {asker.handle ?? asker.name}'s request @@ -103,7 +103,7 @@

    - A verdict already pins this version. + A review already pins this version. Nothing is overwritten — reviews accumulate, and the newest one is the one the row shows.

    @@ -112,12 +112,12 @@ {#if !writable} {#if space.fixture}

    - These records are synthetic and there is no repo behind them. Open a live space to judge one. + These records are synthetic and there is no repo behind them. Open a live space to review one.

    {:else if account.status !== 'signed-in'}

    - to post it — a verdict is a record in your own repo, authored by you. + to post it — a review is a record in your own repo, authored by you.

    {:else}

    @@ -226,7 +226,7 @@ - +