@@ -7,87 +7,116 @@ const CONF_HELP =
77
88const BUCKET_CLASS = { low : 'sev-low' , medium : 'sev-med' , high : 'sev-high' } as const
99
10+ function Playbook ( { playbook, diary } : { playbook : PlaybookEntry [ ] ; diary : DiaryEntry [ ] } ) {
11+ const diaryById = new Map ( diary . map ( ( d ) => [ d . id , d ] ) )
12+ return (
13+ < section className = "memory" >
14+ < h3 >
15+ Playbook — promoted rules ({ playbook . length } ){ ' ' }
16+ < span className = "info" title = { CONF_HELP } >
17+ ⓘ
18+ </ span >
19+ </ h3 >
20+ < div className = "scroll" >
21+ { playbook . length === 0 ? (
22+ < p className = "placeholder" >
23+ Nothing promoted yet. The janitor promotes a pattern once it recurs across ≥3 runs
24+ (confidence ≥ 40%). Patterns build up in the diary first.
25+ </ p >
26+ ) : (
27+ < ul className = "rules" >
28+ { playbook . map ( ( entry , i ) => {
29+ const cites = entry . source_ids
30+ . map ( ( id ) => diaryById . get ( id ) )
31+ . filter ( Boolean ) as DiaryEntry [ ]
32+ return (
33+ < li key = { `${ entry . page_kind } -${ entry . rec_type } -${ entry . target } -${ i } ` } className = "rule" >
34+ < div className = "rule-head" >
35+ < span className = "tag" >
36+ { entry . page_kind } · { entry . rec_type }
37+ </ span >
38+ < span
39+ className = { `conf ${ BUCKET_CLASS [ entry . confidence_bucket ] } ` }
40+ title = { CONF_HELP }
41+ >
42+ { entry . confidence } % · { entry . confidence_bucket }
43+ </ span >
44+ < span className = "seen" > seen { entry . times_seen } ×</ span >
45+ </ div >
46+ < p className = "rule-text" > { entry . rule } </ p >
47+ < details className = "cites" >
48+ < summary >
49+ learned from { entry . source_ids . length } observation
50+ { entry . source_ids . length === 1 ? '' : 's' }
51+ { entry . source_ids . length > 0 && ` (rows ${ entry . source_ids . join ( ', ' ) } )` }
52+ </ summary >
53+ < ul >
54+ { cites . map ( ( d ) => (
55+ < li key = { d . id } >
56+ < code > { d . id } </ code > · conf { d . confidence } · run { d . run }
57+ { d . keyword && ` · "${ d . keyword } "` }
58+ < br />
59+ { d . rec_type } (target: { d . target } ){ d . why && ` — ${ d . why } ` }
60+ </ li >
61+ ) ) }
62+ </ ul >
63+ </ details >
64+ </ li >
65+ )
66+ } ) }
67+ </ ul >
68+ ) }
69+ </ div >
70+ </ section >
71+ )
72+ }
73+
74+ function Diary ( { diary } : { diary : DiaryEntry [ ] } ) {
75+ return (
76+ < section className = "memory" >
77+ < h3 > Diary — raw observations ({ diary . length } )</ h3 >
78+ < div className = "scroll" >
79+ { diary . length === 0 ? (
80+ < p className = "placeholder" >
81+ Nothing observed yet. Run an audit, or turn on background learning.
82+ </ p >
83+ ) : (
84+ < ul className = "rules" >
85+ { [ ...diary ]
86+ . sort ( ( a , b ) => b . run - a . run )
87+ . map ( ( d ) => (
88+ < li key = { d . id } className = "rule" >
89+ < div className = "rule-head" >
90+ < span className = "tag" >
91+ { d . page_kind } · { d . rec_type }
92+ </ span >
93+ < span className = "conf" > conf { d . confidence } </ span >
94+ < span className = "seen" > run { d . run } </ span >
95+ </ div >
96+ < p className = "rule-text" >
97+ target: { d . target }
98+ { d . why && ` — ${ d . why } ` }
99+ </ p >
100+ </ li >
101+ ) ) }
102+ </ ul >
103+ ) }
104+ </ div >
105+ </ section >
106+ )
107+ }
108+
10109export function MemoryPanel ( {
11110 playbook,
12111 diary,
13112} : {
14113 playbook : PlaybookEntry [ ]
15114 diary : DiaryEntry [ ]
16115} ) {
17- const diaryById = new Map ( diary . map ( ( d ) => [ d . id , d ] ) )
18-
19116 return (
20- < div className = "memory" >
21- < h3 >
22- Agent B's playbook — learned rules ({ playbook . length } ){ ' ' }
23- < span className = "info" title = { CONF_HELP } > ⓘ</ span >
24- </ h3 >
25- { playbook . length === 0 ? (
26- < p className = "placeholder" >
27- No rules learned yet. B writes one structured observation per run; the janitor
28- promotes patterns that recur (≥3 runs, confidence ≥ 40%) into the playbook.
29- </ p >
30- ) : (
31- < ul className = "rules" >
32- { playbook . map ( ( entry , i ) => {
33- const cites = entry . source_ids . map ( ( id ) => diaryById . get ( id ) ) . filter ( Boolean ) as DiaryEntry [ ]
34- return (
35- < li key = { `${ entry . page_kind } -${ entry . rec_type } -${ entry . target } -${ i } ` } className = "rule" >
36- < div className = "rule-head" >
37- < span className = "tag" > { entry . page_kind } · { entry . rec_type } </ span >
38- < span className = { `conf ${ BUCKET_CLASS [ entry . confidence_bucket ] } ` } title = { CONF_HELP } >
39- { entry . confidence } % · { entry . confidence_bucket }
40- </ span >
41- < span className = "seen" > seen { entry . times_seen } ×</ span >
42- </ div >
43- < p className = "rule-text" > { entry . rule } </ p >
44- < details className = "cites" >
45- < summary >
46- learned from { entry . source_ids . length } observation
47- { entry . source_ids . length === 1 ? '' : 's' }
48- { entry . source_ids . length > 0 && ` (rows ${ entry . source_ids . join ( ', ' ) } )` }
49- </ summary >
50- < ul >
51- { cites . map ( ( d ) => (
52- < li key = { d . id } >
53- < code > { d . id } </ code > · conf { d . confidence } · run { d . run }
54- { d . keyword && ` · "${ d . keyword } "` }
55- < br />
56- { d . rec_type } (target: { d . target } ){ d . why && ` — ${ d . why } ` }
57- </ li >
58- ) ) }
59- </ ul >
60- </ details >
61- </ li >
62- )
63- } ) }
64- </ ul >
65- ) }
66-
67- < h3 > Raw observations — diary ({ diary . length } )</ h3 >
68- { diary . length === 0 ? (
69- < p className = "placeholder" > Nothing observed yet. Run an audit, or turn on background learning.</ p >
70- ) : (
71- < ul className = "rules" >
72- { [ ...diary ]
73- . sort ( ( a , b ) => b . run - a . run )
74- . map ( ( d ) => (
75- < li key = { d . id } className = "rule" >
76- < div className = "rule-head" >
77- < span className = "tag" >
78- { d . page_kind } · { d . rec_type }
79- </ span >
80- < span className = "conf" > conf { d . confidence } </ span >
81- < span className = "seen" > run { d . run } </ span >
82- </ div >
83- < p className = "rule-text" >
84- target: { d . target }
85- { d . why && ` — ${ d . why } ` }
86- </ p >
87- </ li >
88- ) ) }
89- </ ul >
90- ) }
117+ < div className = "memory-grid" >
118+ < Playbook playbook = { playbook } diary = { diary } />
119+ < Diary diary = { diary } />
91120 </ div >
92121 )
93122}
0 commit comments