11'use client' ;
22
3- import { useMemo , useState } from 'react' ;
3+ import { useEffect , useMemo , useState } from 'react' ;
44
55import BitcodeMetricGrid from '@/components/base/bitcode/execution/BitcodeMetricGrid' ;
66
@@ -9,6 +9,7 @@ import TerminalWorkspaceCard from './TerminalWorkspaceCard';
99import {
1010 buildTerminalFitWorkbenchDraft ,
1111 buildTerminalDepositWorkbenchDraft ,
12+ buildTerminalReadAdmissionDraft ,
1213 buildTerminalReadMeasurementDraft ,
1314 type TerminalActivityRecordDraft ,
1415} from './terminal-activity-history' ;
@@ -30,6 +31,8 @@ function readRowValue(rows: Array<{ label: string; value: string }>, label: stri
3031 return rows . find ( ( row ) => row . label === label ) ?. value || '—' ;
3132}
3233
34+ type ReadFitProgressState = 'draft' | 'measured' | 'admitted' | 'fit-recorded' ;
35+
3336interface TerminalDepositReadWorkbenchProps {
3437 repositoryContext ?: TerminalRepositoryContextState | null ;
3538 onRecordActivity ?: ( draft : TerminalActivityRecordDraft ) => Promise < unknown > ;
@@ -42,8 +45,9 @@ export default function TerminalDepositReadWorkbench({
4245 showDemonstrationWorkbench = true ,
4346} : TerminalDepositReadWorkbenchProps ) {
4447 const { snapshot } = useTerminalShellBridge ( ) ;
45- const [ recordingKey , setRecordingKey ] = useState < 'deposit' | 'read' | 'fit' | null > ( null ) ;
48+ const [ recordingKey , setRecordingKey ] = useState < 'deposit' | 'read' | 'read-admission' | ' fit' | null > ( null ) ;
4649 const [ recordMessage , setRecordMessage ] = useState < string | null > ( null ) ;
50+ const [ readFitProgress , setReadFitProgress ] = useState < ReadFitProgressState > ( 'draft' ) ;
4751 const workbenchSnapshot = useMemo ( ( ) => {
4852 if ( showDemonstrationWorkbench ) return snapshot ;
4953 return buildLiveTerminalDepositReadWorkbenchSnapshot ( repositoryContext ) ;
@@ -52,6 +56,11 @@ export default function TerminalDepositReadWorkbench({
5256 ( ) => normalizeTerminalDepositReadWorkbench ( workbenchSnapshot , repositoryContext ) ,
5357 [ repositoryContext , workbenchSnapshot ] ,
5458 ) ;
59+ const scenarioKey = workbench ?. scenarioLabel || '' ;
60+
61+ useEffect ( ( ) => {
62+ setReadFitProgress ( 'draft' ) ;
63+ } , [ scenarioKey ] ) ;
5564
5665 const selectedEntryChips = useMemo ( ( ) => {
5766 if ( ! workbench ?. deposit . selectedEntries . length ) return [ ] ;
@@ -86,10 +95,16 @@ export default function TerminalDepositReadWorkbench({
8695 ] ,
8796 } ) ,
8897 ) ;
89- setRecordMessage ( 'Read-measurement posture recorded into the Bitcode activity ledger.' ) ;
98+ setReadFitProgress ( 'measured' ) ;
99+ setRecordMessage (
100+ 'Measured Read recorded. Next admit it for source-bound fit search, or stop if the Read is too broad or unrelated to the deposited source.' ,
101+ ) ;
90102 } else {
91103 await onRecordActivity ( buildTerminalFitWorkbenchDraft ( workbench ) ) ;
92- setRecordMessage ( 'Asset-pack fit and settlement posture recorded into the Bitcode activity ledger.' ) ;
104+ setReadFitProgress ( 'fit-recorded' ) ;
105+ setRecordMessage (
106+ 'Fit posture recorded. This records current fit evidence/readiness; settlement and finality remain blocked unless a worthy fit is evidenced.' ,
107+ ) ;
93108 }
94109 } catch ( error ) {
95110 setRecordMessage ( error instanceof Error ? error . message : 'Unable to record Bitcode workbench posture.' ) ;
@@ -98,6 +113,25 @@ export default function TerminalDepositReadWorkbench({
98113 }
99114 } ;
100115
116+ const handleRecordReadAdmission = async ( ) => {
117+ if ( ! workbench || ! onRecordActivity ) return ;
118+
119+ setRecordingKey ( 'read-admission' ) ;
120+ setRecordMessage ( null ) ;
121+
122+ try {
123+ await onRecordActivity ( buildTerminalReadAdmissionDraft ( workbench ) ) ;
124+ setReadFitProgress ( 'admitted' ) ;
125+ setRecordMessage (
126+ 'Measured Read admitted for fit search. Next run or record the fit result posture as worthy_fit, no_worthy_fit, or blocked_readiness evidence.' ,
127+ ) ;
128+ } catch ( error ) {
129+ setRecordMessage ( error instanceof Error ? error . message : 'Unable to admit the measured Read for fit search.' ) ;
130+ } finally {
131+ setRecordingKey ( null ) ;
132+ }
133+ } ;
134+
101135 if ( ! workbench ) {
102136 return (
103137 < TerminalWorkspaceCard
@@ -165,8 +199,8 @@ export default function TerminalDepositReadWorkbench({
165199 metrics = { workbench . read . metrics }
166200 rows = { workbench . read . rows }
167201 chips = { workbench . read . closureCriteria . length ? workbench . read . closureCriteria : workbench . read . targetKinds }
168- actionLabel = " Focus read scenarios"
169- actionTarget = " terminalReadScenarios"
202+ actionLabel = { showDemonstrationWorkbench ? ' Focus read scenarios' : 'Review measured Read' }
203+ actionTarget = { showDemonstrationWorkbench ? ' terminalReadScenarios' : 'terminalReadWorkbench' }
170204 secondaryActionLabel = { recordingKey === 'read' ? 'Recording…' : 'Record read posture' }
171205 secondaryActionDisabled = { recordingKey !== null }
172206 onSecondaryAction = { ( ) => {
@@ -175,6 +209,65 @@ export default function TerminalDepositReadWorkbench({
175209 />
176210 </ div >
177211
212+ < section className = "mt-5 rounded-[1.45rem] border border-emerald-400/16 bg-emerald-400/[0.06] px-5 py-5" >
213+ < div className = "flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between" >
214+ < div >
215+ < p className = "text-[0.66rem] uppercase tracking-[0.2em] text-emerald-200/80" > read state</ p >
216+ < h3 className = "mt-2 text-lg font-semibold text-white" > Measured Read before fit result</ h3 >
217+ < p className = "mt-2 max-w-3xl text-sm leading-6 text-neutral-300" >
218+ Recording a Read stores the measured demand frame. It does not mean Bitcode found a fit. Fit search must then return
219+ worthy_fit, no_worthy_fit, or blocked_readiness before settlement or finality can proceed.
220+ </ p >
221+ </ div >
222+ < span className = "rounded-full border border-white/10 bg-black/20 px-3 py-2 text-[0.66rem] uppercase tracking-[0.18em] text-neutral-200" >
223+ { readFitProgress . replace ( '-' , ' ' ) }
224+ </ span >
225+ </ div >
226+
227+ < div className = "mt-5 grid gap-3 md:grid-cols-4" >
228+ { [
229+ { id : 'draft' , label : '1. Read framed' , detail : 'Repository, branch, commit, and demand frame are visible.' } ,
230+ { id : 'measured' , label : '2. Read measured' , detail : 'Read posture is persisted as ledger evidence.' } ,
231+ { id : 'admitted' , label : '3. Fit admitted' , detail : 'Measured Read may enter source-bound fit search.' } ,
232+ { id : 'fit-recorded' , label : '4. Result recorded' , detail : 'Fit result posture is reviewable before proof or settlement.' } ,
233+ ] . map ( ( step ) => {
234+ const active = step . id === readFitProgress ;
235+ return (
236+ < div
237+ key = { step . id }
238+ className = { `rounded-[1.1rem] border px-4 py-4 text-sm ${
239+ active ? 'border-emerald-300/35 bg-emerald-300/10' : 'border-white/8 bg-black/20'
240+ } `}
241+ >
242+ < p className = "font-semibold text-neutral-100" > { step . label } </ p >
243+ < p className = "mt-2 leading-6 text-neutral-400" > { step . detail } </ p >
244+ </ div >
245+ ) ;
246+ } ) }
247+ </ div >
248+
249+ < div className = "mt-5 flex flex-wrap gap-3" >
250+ < button
251+ type = "button"
252+ disabled = { recordingKey !== null || readFitProgress === 'draft' }
253+ onClick = { ( ) => {
254+ void handleRecordReadAdmission ( ) ;
255+ } }
256+ className = "rounded-[1.25rem] border border-emerald-400/30 bg-emerald-400/10 px-4 py-3 text-sm font-medium text-emerald-100 transition hover:border-emerald-300/50 hover:bg-emerald-400/15 disabled:cursor-not-allowed disabled:opacity-55"
257+ >
258+ { recordingKey === 'read-admission' ? 'Admitting Read…' : 'Admit measured Read for fit search' }
259+ </ button >
260+ < button
261+ type = "button"
262+ disabled = { recordingKey !== null }
263+ onClick = { ( ) => jumpToShellSection ( 'terminalFitWorkbench' ) }
264+ className = "rounded-[1.25rem] border border-white/10 bg-white/5 px-4 py-3 text-sm font-medium text-neutral-100 transition hover:border-white/18 hover:bg-white/10 disabled:cursor-not-allowed disabled:opacity-55"
265+ >
266+ Review fit result posture
267+ </ button >
268+ </ div >
269+ </ section >
270+
178271 < article
179272 id = "terminalFitWorkbench"
180273 className = "mt-5 rounded-[1.6rem] border border-amber-400/18 bg-amber-400/5 px-5 py-5"
@@ -199,7 +292,7 @@ export default function TerminalDepositReadWorkbench({
199292 } }
200293 className = "rounded-full border border-white/10 bg-white/5 px-3 py-2 text-[0.66rem] uppercase tracking-[0.18em] text-neutral-100 transition hover:border-white/18 hover:bg-white/10 disabled:cursor-not-allowed disabled:opacity-60"
201294 >
202- { recordingKey === 'fit' ? 'Recording…' : 'Record fit posture' }
295+ { recordingKey === 'fit' ? 'Recording…' : 'Record fit result posture' }
203296 </ button >
204297 </ div >
205298 < p className = "mt-3 text-sm leading-6 text-neutral-300" > { workbench . fit . summary } </ p >
0 commit comments