ThatAIguyA world of ideas

THE CONSCIOUSNESS ATLAS
Read. Experiment. Follow the evidence.

ConsciousnessLearn · Explore · Joseph Anady

Janady13/missionmatch / frontend/src/tools/slatematch/ScopeReview.tsx

Source identity, revision, and recovered contents.

GitHub sourceSource text recovered

Source identity

FieldRecorded value
Source typeGitHub source
Original recordJanady13/missionmatch / frontend/src/tools/slatematch/ScopeReview.tsx
DateNot specified in source
RepositoryJanady13/missionmatch
Revision720d47fae476b0d38477ae4401697d372b1ea2bc
Branchfeature/opportunity-to-outcome
Path or archive memberfrontend/src/tools/slatematch/ScopeReview.tsx
Original SHA-25618952e43aa24b0d398d81d660cb756dd2b368f191b03db585e0c377a2a4695f2
Git blob SHAcca05c21d03bcbf626d4668159cbf750346f8a8a
Reading-copy SHA-25618952e43aa24b0d398d81d660cb756dd2b368f191b03db585e0c377a2a4695f2

Original source ↗

Recovered source transcript

import { useState } from 'react' import { ArrowLeft, Check, GitMerge, Plus, Scissors, X } from 'lucide-react' import { Link, useParams } from 'react-router-dom' import { ToolHeader } from '../../components/ToolHeader' import { Modal, Panel } from '../../components/ui' import { slateBrand } from './brand' import { inputCls } from './captureConstants' import { useTrackedOpportunity } from './captureQueries' import { SCOPE_TYPES, STAFFING_SCOPE_TYPES } from './scopeConstants' import type { ScopeItem } from './scopeApi' import { useAddManualScope, useMergeScopeItems, useReviewScopeItem, useScope, useSplitScopeItem, } from './scopeQueries' // SECTION 6 SCREEN 4, REVIEW SCOPE. For every extracted item show the text, document name, page or section, // extraction method, and confidence, with accept, edit and accept, reject, split, merge, and add manually. // // THE CITATION IS THE PRODUCT. Every machine produced row on this screen carries the span it came from, and // the schema refuses one that does not. So the citation is rendered on every row, not tucked behind a hover: // a reviewer accepting an item is vouching for it, and they cannot do that against text they cannot see. // // NOTHING HERE CAN REACH THE SCORING ENGINE. Every action on this screen writes scope, and scope becomes a // requirement only through the promotion gate on the next screen, which is held one capability higher. That // separation is the whole safety design and the screen says so out loud. const ACTIVE = new Set(['extracted', 'accepted', 'edited', 'manual']) function confidenceLabel(c: number): string { if (c >= 0.999) return 'certain, literal copy' if (c >= 0.8) return `${Math.round(c * 100)} percent` return `${Math.round(c * 100)} percent, low` } function statusTone(s: string): string { switch (s) { case 'accepted': return 'bg-emerald-50 text-emerald-700' case 'edited': return 'bg-sky-50 text-sky-700' case 'manual': return 'bg-violet-50 text-violet-700' case 'rejected': return 'bg-slate-100 text-slate-500' case 'split': case 'merged': return 'bg-slate-100 text-slate-500' default: return 'bg-amber-50 text-amber-700' } } export function ScopeReview() { const { id = '' } = useParams() const opp = useTrackedOpportunity(id) const scope = useScope(id) const review = useReviewScopeItem(id) const split = useSplitScopeItem(id) const merge = useMergeScopeItems(id) const addManual = useAddManualScope(id) const [editing, setEditing] = useState<ScopeItem | null>(null) const [editTitle, setEditTitle] = useState('') const [editDesc, setEditDesc] = useState('') const [splitting, setSplitting] = useState<ScopeItem | null>(null) const [splitParts, setSplitParts] = useState<string[]>(['', '']) const [merging, setMerging] = useState(false) const [selected, setSelected] = useState<Set<string>>(new Set()) const [mergeTitle, setMergeTitle] = useState('') const [adding, setAdding] = useState(false) const [newType, setNewType] = useState('task') const [newTitle, setNewTitle] = useState('') const [newDesc, setNewDesc] = useState('') const [err, setErr] = useState('') const items = scope.data ?? [] const live = items.filter((i) => ACTIVE.has(i.review_status)) const retired = items.filter((i) => !ACTIVE.has(i.review_status)) const run = async (fn: () => Promise<unknown>) => { setErr('') try { await fn() } catch (e) { setErr(e instanceof Error ? e.message : 'the action failed') } } const toggle = (itemId: string) => { setSelected((s) => { const next = new Set(s) if (next.has(itemId)) next.delete(itemId) else next.add(itemId) return next }) } return ( <div className="space-y-6"> <ToolHeader name={slateBrand.name} tagline="Review scope" accent={slateBrand.accent} /> {/* Which opportunity this is. Every one of these screens is scoped to a single pursuit, and a reviewer arriving from a link needs to know which one before they start accepting things. */} {opp.data?.title && <p className="text-sm font-semibold text-ink">{opp.data.title}</p>} <div className="flex flex-wrap items-center justify-between gap-3"> <Link to={`/slate/capture/${id}`} className="inline-flex items-center gap-1.5 text-sm font-semibold text-muted hover:text-ink"> <ArrowLeft size={14} /> Back to the opportunity </Link> <div className="flex flex-wrap gap-2"> <button type="button" onClick={() => setAdding(true)} className="inline-flex items-center gap-1.5 rounded-md border border-slate-300 px-3 py-1.5 text-sm font-semibold text-ink hover:bg-slate-50" > <Plus size={14} /> Add manually </button> <button type="button" onClick={() => { setMerging((m) => !m) setSelected(new Set()) }} className={`inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-semibold ${ merging ? 'bg-amber-500 text-white' : 'border border-slate-300 text-ink hover:bg-slate-50' }`} > <GitMerge size={14} /> {merging ? 'Cancel merge' : 'Merge items'} </button> <Link to={`/slate/capture/${id}/requirements`} className="inline-flex items-center gap-1.5 rounded-md bg-navy px-3 py-1.5 text-sm font-semibold text-white hover:opacity-90" > Build requirements </Link> </div> </div> {err && <p className="rounded bg-rose-50 p-3 text-sm font-semibold text-rose-800">{err}</p>} {merging && ( <Panel title="Merge"> <p className="text-sm text-muted"> Select two or more items. The FIRST one you selected survives and keeps its own citation; the others are retired to merged and point at it. Nothing is deleted. </p> <div className="mt-3 flex flex-wrap items-end gap-3"> <div className="min-w-64 flex-1"> <label className="mb-1 block text-xs font-semibold uppercase tracking-wide text-muted" htmlFor="merge-title"> Combined title </label> <input id="merge-title" className={inputCls} value={mergeTitle} onChange={(e) => setMergeTitle(e.target.value)} placeholder="What the combined item now covers" /> </div> <button type="button" disabled={selected.size < 2 || !mergeTitle.trim() || merge.isPending} onClick={() => { const ids = Array.from(selected) void run(async () => { await merge.mutateAsync({ itemId: ids[0], absorb_item_ids: ids.slice(1), title: mergeTitle }) setMerging(false) setSelected(new Set()) setMergeTitle('') }) }} className="rounded-md bg-navy px-4 py-2 text-sm font-semibold text-white disabled:opacity-40" > Merge {selected.size} selected </button> </div> </Panel> )} <Panel title={`Queue, ${live.length} item${live.length === 1 ? '' : 's'}`}> {scope.isLoading && <p className="text-sm text-faint">Loading scope.</p>} {!scope.isLoading && live.length === 0 && ( <p className="text-sm text-faint"> No scope yet. Upload the package and let extraction run, or add an item manually. </p> )} <ul className="space-y-3"> {live.map((it) => ( <li key={it.id} className="rounded-md border border-slate-200 p-3"> <div className="flex items-start gap-3"> {merging && ( <input type="checkbox" className="mt-1 h-4 w-4" checked={selected.has(it.id)} onChange={() => toggle(it.id)} aria-label={`select ${it.title}`} /> )} <div className="min-w-0 flex-1"> <div className="flex flex-wrap items-center gap-2"> <span className="text-sm font-semibold text-ink">{it.title || '(no title)'}</span> <span className={`rounded-full px-2 py-0.5 text-xs font-semibold ${statusTone(it.review_status)}`}> {it.review_status} </span> <span className="rounded-full bg-slate-100 px-2 py-0.5 text-xs font-semibold text-slate-600"> {it.scope_type} </span> {STAFFING_SCOPE_TYPES.has(it.scope_type) && ( <span className="rounded-full bg-amber-50 px-2 py-0.5 text-xs font-semibold text-amber-700"> staffing </span> )} </div> {it.description && <p className="mt-1 whitespace-pre-wrap text-sm text-muted">{it.description}</p>} {/* THE CITATION. Rendered on every row because a reviewer cannot vouch for text they cannot see, and because the schema refuses a machine item that has none. */} <div className="mt-2 flex flex-wrap gap-x-4 gap-y-1 text-xs text-faint"> <span>{it.source_section_label || 'no section label'}</span> {it.source_page_number > 0 && <span>page {it.source_page_number}</span>} <span>{it.extraction_method || 'method not recorded'}</span> <span>{confidenceLabel(it.extraction_confidence)}</span> {it.source_quote_hash && <span title={it.source_quote_hash}>quote {it.source_quote_hash.slice(0, 10)}</span>} {!it.source_document_id && !it.source_quote_hash && it.review_status === 'manual' && ( <span className="font-semibold text-violet-700">authored by a human, no citation needed</span> )} </div> {!merging && ( <div className="mt-3 flex flex-wrap gap-2"> <button type="button" onClick={() => void run(() => review.mutateAsync({ itemId: it.id, patch: { review_status: 'accepted' } }))} className="inline-flex items-center gap-1 rounded border border-emerald-300 px-2 py-1 text-xs font-semibold text-emerald-700 hover:bg-emerald-50" > <Check size={12} /> Accept </button> <button type="button" onClick={() => { setEditing(it) setEditTitle(it.title) setEditDesc(it.description) }} className="rounded border border-sky-300 px-2 py-1 text-xs font-semibold text-sky-700 hover:bg-sky-50" > Edit and accept </button> <button type="button" onClick={() => void run(() => review.mutateAsync({ itemId: it.id, patch: { review_status: 'rejected' } }))} className="inline-flex items-center gap-1 rounded border border-rose-300 px-2 py-1 text-xs font-semibold text-rose-700 hover:bg-rose-50" > <X size={12} /> Reject </button> <button type="button" onClick={() => { setSplitting(it) setSplitParts([it.title, '']) }} className="inline-flex items-center gap-1 rounded border border-slate-300 px-2 py-1 text-xs font-semibold text-ink hover:bg-slate-50" > <Scissors size={12} /> Split </button> </div> )} </div> </div> </li> ))} </ul> </Panel> {retired.length > 0 && ( <Panel title={`Retired, ${retired.length}`}> <p className="mb-2 text-xs text-faint"> Rejected, split and merged items are kept, never deleted, so the review history stays readable. </p> <ul className="space-y-1"> {retired.map((it) => ( <li key={it.id} className="flex flex-wrap items-center gap-2 text-sm text-slate-500"> <span className={`rounded-full px-2 py-0.5 text-xs font-semibold ${statusTone(it.review_status)}`}> {it.review_status} </span> <span className="line-through">{it.title || '(no title)'}</span> </li> ))} </ul> </Panel> )} {editing && ( <Modal open title="Edit and accept" onClose={() => setEditing(null)}> <div className="space-y-3"> <p className="text-xs text-faint"> An edit that changes the text records the item as edited rather than accepted, so a later reader can tell what the machine said from what a human rewrote. The citation does not change. </p> <div> <label className="mb-1 block text-xs font-semibold uppercase tracking-wide text-muted" htmlFor="edit-title"> Title </label> <input id="edit-title" className={inputCls} value={editTitle} onChange={(e) => setEditTitle(e.target.value)} /> </div> <div> <label className="mb-1 block text-xs font-semibold uppercase tracking-wide text-muted" htmlFor="edit-desc"> Description </label> <textarea id="edit-desc" rows={5} className={inputCls} value={editDesc} onChange={(e) => setEditDesc(e.target.value)} /> </div> <div className="flex justify-end gap-2"> <button type="button" onClick={() => setEditing(null)} className="rounded-md border border-slate-300 px-3 py-1.5 text-sm font-semibold"> Cancel </button> <button type="button" disabled={!editTitle.trim()} onClick={() => void run(async () => { await review.mutateAsync({ itemId: editing.id, patch: { review_status: 'edited', title: editTitle, description: editDesc }, }) setEditing(null) }) } className="rounded-md bg-navy px-3 py-1.5 text-sm font-semibold text-white disabled:opacity-40" > Save and accept </button> </div> </div> </Modal> )} {splitting && ( <Modal open title="Split into separate items" onClose={() => setSplitting(null)}> <div className="space-y-3"> <p className="text-xs text-faint"> Each part inherits this item's citation, so every child stays grounded in the same source span. The original is retired to split and kept. </p> {splitParts.map((p, i) => ( <div key={i}> <label className="mb-1 block text-xs font-semibold uppercase tracking-wide text-muted" htmlFor={`part-${i}`}> Part {i + 1} </label> <input id={`part-${i}`} className={inputCls} value={p} onChange={(e) => setSplitParts((arr) => arr.map((x, j) => (j === i ? e.target.value : x)))} /> </div> ))} <button type="button" onClick={() => setSplitParts((a) => [...a, ''])} className="text-sm font-semibold text-amber-700 underline" > Add another part </button> <div className="flex justify-end gap-2"> <button type="button" onClick={() => setSplitting(null)} className="rounded-md border border-slate-300 px-3 py-1.5 text-sm font-semibold"> Cancel </button> <button type="button" disabled={splitParts.filter((p) => p.trim()).length < 2} onClick={() => void run(async () => { await split.mutateAsync({ itemId: splitting.id, parts: splitParts.filter((p) => p.trim()).map((title) => ({ title })), }) setSplitting(null) }) } className="rounded-md bg-navy px-3 py-1.5 text-sm font-semibold text-white disabled:opacity-40" > Split into {splitParts.filter((p) => p.trim()).length} </button> </div> </div> </Modal> )} {adding && ( <Modal open title="Add a scope item manually" onClose={() => setAdding(false)}> <div className="space-y-3"> <p className="text-xs text-faint"> A manual item needs no citation, because you are the source. It is recorded as manual so it is never mistaken for something extraction found. </p> <div> <label className="mb-1 block text-xs font-semibold uppercase tracking-wide text-muted" htmlFor="new-type"> Scope type </label> <select id="new-type" className={inputCls} value={newType} onChange={(e) => setNewType(e.target.value)}> {SCOPE_TYPES.map((t) => ( <option key={t} value={t}> {t} </option> ))} </select> </div> <div> <label className="mb-1 block text-xs font-semibold uppercase tracking-wide text-muted" htmlFor="new-title"> Title </label> <input id="new-title" className={inputCls} value={newTitle} onChange={(e) => setNewTitle(e.target.value)} /> </div> <div> <label className="mb-1 block text-xs font-semibold uppercase tracking-wide text-muted" htmlFor="new-desc"> Description </label> <textarea id="new-desc" rows={4} className={inputCls} value={newDesc} onChange={(e) => setNewDesc(e.target.value)} /> </div> <div className="flex justify-end gap-2"> <button type="button" onClick={() => setAdding(false)} className="rounded-md border border-slate-300 px-3 py-1.5 text-sm font-semibold"> Cancel </button> <button type="button" disabled={!newTitle.trim()} onClick={() => void run(async () => { await addManual.mutateAsync({ scope_type: newType, title: newTitle, description: newDesc }) setAdding(false) setNewTitle('') setNewDesc('') }) } className="rounded-md bg-navy px-3 py-1.5 text-sm font-semibold text-white disabled:opacity-40" > Add item </button> </div> </div> </Modal> )} </div> ) }

Search equations, builds, manuscript text, and recovered sources.