@gotcos/glasses-server 6.94.4 → 6.98.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +147 -0
- package/README.md +52 -0
- package/managed-runtime-contract.json +13 -0
- package/package.json +3 -1
- package/server/index.ts +19 -1
- package/server/lib/attached-provider-adapter.ts +35 -1
- package/server/lib/claude-bridge.ts +47 -0
- package/server/lib/codex-bridge.ts +11 -1
- package/server/lib/codex-rollout-watermark.ts +42 -0
- package/server/lib/cursor-bridge.ts +2 -1
- package/server/lib/dictation-clean-models.ts +2 -0
- package/server/lib/dictation-clean.ts +2 -2
- package/server/lib/dictation-polish-pipeline.ts +22 -2
- package/server/lib/dictation-prewarm.ts +16 -0
- package/server/lib/direct-bridge.ts +14 -2
- package/server/lib/direct-sse.ts +6 -1
- package/server/lib/display-bus.ts +1 -1
- package/server/lib/fork-thread.ts +32 -1
- package/server/lib/held-naming-batches.ts +36 -0
- package/server/lib/job-audit-caller.ts +20 -0
- package/server/lib/lens-gist-engines.ts +17 -5
- package/server/lib/live-cos-ask.ts +29 -6
- package/server/lib/live-cue-verdicts.ts +43 -8
- package/server/lib/live-cues-engine.ts +4 -1
- package/server/lib/live-cues-filter.ts +50 -0
- package/server/lib/live-cues-general-prompts.ts +137 -0
- package/server/lib/live-cues-general-topic.ts +245 -0
- package/server/lib/live-cues-general.ts +715 -0
- package/server/lib/live-cues-v2-data.ts +453 -0
- package/server/lib/live-cues-v2-grounded.ts +262 -0
- package/server/lib/live-cues-v2-judge-b.ts +59 -0
- package/server/lib/live-cues-v2-names.ts +49 -0
- package/server/lib/live-cues-v2-notes.ts +8 -4
- package/server/lib/live-cues-v2-open-items.ts +132 -0
- package/server/lib/live-cues-v2-pacing.ts +45 -0
- package/server/lib/live-cues-v2-prompts-kinds.ts +9 -4
- package/server/lib/live-cues-v2-settings.ts +89 -10
- package/server/lib/live-cues-v2.ts +570 -47
- package/server/lib/mac-recording-asr.ts +6 -3
- package/server/lib/mac-speaker-call-human.ts +371 -0
- package/server/lib/mac-speaker-call-interval-human.ts +499 -0
- package/server/lib/mac-speaker-call-interval-projection.ts +233 -0
- package/server/lib/mac-speaker-call-original-view.ts +328 -0
- package/server/lib/mac-speaker-call-producer-worker.ts +615 -0
- package/server/lib/mac-speaker-call-producer.ts +539 -0
- package/server/lib/mac-speaker-call-store.ts +264 -0
- package/server/lib/mac-speaker-call-view.ts +373 -0
- package/server/lib/mac-speaker-live-compute.ts +72 -0
- package/server/lib/mac-speaker-live-memory.ts +414 -0
- package/server/lib/mac-speaker-live-projection.ts +126 -0
- package/server/lib/mac-speaker-live-save.ts +90 -0
- package/server/lib/mac-speaker-live-store.ts +71 -0
- package/server/lib/mac-speaker-live-worker.ts +58 -0
- package/server/lib/mac-speaker-live.ts +175 -0
- package/server/lib/mac-speaker-profile-extractor.ts +15 -10
- package/server/lib/mac-speaker-shadow-repair.ts +307 -0
- package/server/lib/mac-voice-assignment.ts +44 -26
- package/server/lib/mac-voice-display.ts +195 -0
- package/server/lib/mac-voice-naming-batch.ts +1067 -0
- package/server/lib/mac-voice-suggestions.ts +548 -0
- package/server/lib/maintenance-lifecycle.ts +2 -0
- package/server/lib/media-store.ts +2 -1
- package/server/lib/meeting-ask-pasted.ts +135 -0
- package/server/lib/meeting-ask-review.ts +8 -1
- package/server/lib/meeting-ask-runner.ts +4 -1
- package/server/lib/meeting-ask-runtime.ts +189 -17
- package/server/lib/meeting-ask-store.ts +2 -0
- package/server/lib/meeting-ask-web.ts +284 -13
- package/server/lib/meeting-batch-progress.ts +51 -5
- package/server/lib/meeting-batch-transcribe.ts +35 -2
- package/server/lib/meeting-fact-check.ts +3 -0
- package/server/lib/meeting-finalization-jobs.ts +69 -2
- package/server/lib/meeting-public-topic.ts +6 -1
- package/server/lib/meeting-speaker-review.ts +182 -17
- package/server/lib/meeting-store.ts +6 -1
- package/server/lib/parakeet.ts +51 -5
- package/server/lib/pending-batch-retention.ts +58 -0
- package/server/lib/private-reference.ts +38 -0
- package/server/lib/provider-usage.ts +561 -0
- package/server/lib/public-https-url.ts +32 -0
- package/server/lib/query-job-runtime.ts +3 -0
- package/server/lib/rich-media-safety.ts +23 -2
- package/server/lib/speaker-shadow-decide.ts +503 -0
- package/server/lib/speaker-shadow-models.ts +150 -0
- package/server/lib/speaker-shadow-numeric.ts +143 -0
- package/server/lib/speaker-shadow-pair-source.ts +91 -0
- package/server/lib/speaker-shadow-paired.ts +268 -0
- package/server/lib/speaker-shadow-report.ts +113 -0
- package/server/lib/speaker-shadow-timeline.ts +210 -0
- package/server/lib/speaker-shadow-worker.ts +312 -0
- package/server/lib/speaker-shadow.ts +788 -0
- package/server/lib/token-audit.ts +36 -6
- package/server/lib/transcript-cleanup.ts +3 -2
- package/server/lib/voice-directory.ts +8 -4
- package/server/lib/web-lookup-ledger.ts +151 -0
- package/server/lib/work-review-runtime.ts +2 -0
- package/server/lib/work-search.ts +3 -1
- package/server/lib/xlsx-text.ts +277 -0
- package/server/routes/health.ts +5 -0
- package/server/routes/live-cues.ts +36 -14
- package/server/routes/meeting.ts +506 -49
- package/server/routes/speaker-shadow.ts +79 -0
- package/server/routes/transcribe-stream.ts +114 -33
- package/server/routes/voice.ts +3 -0
- package/server/scripts/live-cues-v3-mutation-gate.mjs +311 -0
- package/server/scripts/mac-voice-assignment-6930-mutation-gate.mjs +5 -5
- package/shared/live-cues-v2.ts +38 -5
- package/shared/media-attachment.ts +2 -0
- package/shared/meeting-ask.ts +11 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Live cues v3 mutation gate: grounded retrieval and judge B, the sources contract and the cue log schema, settings v3 (cue mode,
|
|
3
|
+
// grounding, general limits) and the public https validator. Mutations run only in a disposable copy of the checkout; the live
|
|
4
|
+
// checkout is never rewritten.
|
|
5
|
+
//
|
|
6
|
+
// What it proves, in order:
|
|
7
|
+
// 0. The target suites are GREEN unmutated. A gate over a red suite reads every mutant as killed and proves nothing.
|
|
8
|
+
// 1. Each target string appears EXACTLY ONCE in its file, so the mutation is unambiguous.
|
|
9
|
+
// 2. The mutated file differs from the original, so the edit landed.
|
|
10
|
+
// 3. A NAMED test fails ("FAIL server/x.test.ts > name"); a build error or a harness failure is not a kill.
|
|
11
|
+
// 4. The file is restored byte for byte (compared) before the next mutant.
|
|
12
|
+
// Usage: node server/scripts/live-cues-v3-mutation-gate.mjs [--list] [--check] [name…]
|
|
13
|
+
import { mkdtempSync, cpSync, readFileSync, writeFileSync, symlinkSync, rmSync } from 'node:fs'
|
|
14
|
+
import { tmpdir } from 'node:os'
|
|
15
|
+
import { resolve, join, dirname, basename } from 'node:path'
|
|
16
|
+
import { fileURLToPath } from 'node:url'
|
|
17
|
+
import { spawnSync } from 'node:child_process'
|
|
18
|
+
|
|
19
|
+
const root = resolve(dirname(fileURLToPath(import.meta.url)), '../..')
|
|
20
|
+
const GROUNDED_T = ['server/lib/live-cues-v2-grounded.test.ts']
|
|
21
|
+
const GROUNDING_T = ['server/lib/live-cues-v2-grounding.test.ts']
|
|
22
|
+
const PIN_T = ['server/lib/live-cues-v2-classic-pin.test.ts']
|
|
23
|
+
const ROUTE_T = ['server/routes/live-cues-v3-settings-route.test.ts']
|
|
24
|
+
const SETTINGS_T = ['server/lib/live-cues-v2-settings.test.ts']
|
|
25
|
+
const VERDICT_T = ['server/lib/live-cue-verdicts.test.ts']
|
|
26
|
+
const KINDS_T = ['server/lib/live-cues-v2-kinds.test.ts']
|
|
27
|
+
const URL_T = ['server/lib/public-https-url.test.ts']
|
|
28
|
+
const ALL = [...GROUNDED_T, ...GROUNDING_T, ...PIN_T, ...ROUTE_T, ...SETTINGS_T, ...VERDICT_T, ...KINDS_T, ...URL_T,
|
|
29
|
+
'server/lib/live-cues-v2.test.ts', 'server/lib/live-cues-v2-notes.test.ts', 'server/routes/live-cues-v2-limits-route.test.ts', 'server/routes/live-cues-v2-settings-route.test.ts',
|
|
30
|
+
'server/routes/live-cue-verdicts-route.test.ts']
|
|
31
|
+
const GR = 'server/lib/live-cues-v2-grounded.ts', JB = 'server/lib/live-cues-v2-judge-b.ts', EN = 'server/lib/live-cues-v2.ts', ST = 'server/lib/live-cues-v2-settings.ts'
|
|
32
|
+
const RT = 'server/routes/live-cues.ts', VD = 'server/lib/live-cue-verdicts.ts', SH = 'shared/live-cues-v2.ts', UR = 'server/lib/public-https-url.ts', NT = 'server/lib/live-cues-v2-notes.ts'
|
|
33
|
+
const m = (name, file, edits, tests) => ({ name, file, edits: typeof edits[0] === 'string' ? [edits] : edits, tests })
|
|
34
|
+
|
|
35
|
+
const mutations = [
|
|
36
|
+
// ── Judge B ──
|
|
37
|
+
m('judgeb-yes-inclusive', JB, ['.filter(x => x.p >= threshold)', '.filter(x => x.p > threshold)'], GROUNDED_T),
|
|
38
|
+
m('judgeb-cap', JB, [' .slice(0, max)\n', ''], GROUNDED_T),
|
|
39
|
+
m('judgeb-best-first', JB, ['b.p - a.p || a.order - b.order', 'a.p - b.p || a.order - b.order'], GROUNDED_T),
|
|
40
|
+
m('judgeb-ties-keep-order', JB, ['b.p - a.p || a.order - b.order', 'b.p - a.p || b.order - a.order'], GROUNDED_T),
|
|
41
|
+
m('judgeb-probability-range', JB, ['Number.isFinite(v) && v >= 0 && v <= 1 ? v : 0', 'Number.isFinite(v) ? v : 0'], GROUNDED_T),
|
|
42
|
+
m('judgeb-probability-number', JB, ["(typeof v === 'number' && Number.isFinite(v) && v >= 0 && v <= 1 ? v : 0)", '(Number(v) >= 0 && Number(v) <= 1 ? Number(v) : 0)'], GROUNDED_T),
|
|
43
|
+
m('judgeb-note-300', JB, ['c.notes.slice(0, JUDGE_B_NOTE_CHARS)', 'c.notes'], GROUNDED_T),
|
|
44
|
+
m('judgeb-one-question-per-candidate', JB, ["questions['rel_' + c.id] = {", "questions['rel' + c.id] = {"], GROUNDED_T),
|
|
45
|
+
m('judgeb-reads-own-yes', JB, ["answers?.['rel_' + id]?.probabilities?.yes", "answers?.same?.probabilities?.yes"], GROUNDED_T),
|
|
46
|
+
m('judgeb-same-diagnostic', JB, ['same[id] = prob(answers?.same?.probabilities?.[id])', 'same[id] = 0'], GROUNDED_T),
|
|
47
|
+
m('judgeb-none-criterion', JB, ['criteria.none = CUE_JUDGE_NONE\n', ''], GROUNDED_T),
|
|
48
|
+
// ── Grounded retrieval ──
|
|
49
|
+
m('history-lowercase', GR, ['const wordsOf = (text: string): string[] => text.toLowerCase().match(', 'const wordsOf = (text: string): string[] => text.match('], GROUNDED_T),
|
|
50
|
+
m('history-boundary-tail', GR, ['this.tail = words.slice(-(n - 1))', 'this.tail = []'], GROUNDED_T),
|
|
51
|
+
m('history-boundary-tail-short', GR, ['this.tail = words.slice(-(n - 1))', 'this.tail = words.slice(-(n - 2))'], GROUNDED_T),
|
|
52
|
+
m('history-cap-default', GR, ['historyShingles: 50_000,', 'historyShingles: 5_000,'], GROUNDED_T),
|
|
53
|
+
m('history-cap-holds-cap', GR, ['while (this.seen.size > this.cap)', 'while (this.seen.size >= this.cap)'], GROUNDED_T),
|
|
54
|
+
m('history-cap-evicts-oldest', GR, ['this.seen.delete(this.seen.values().next().value as string)', 'this.seen.delete([...this.seen].pop() as string)'], GROUNDED_T),
|
|
55
|
+
m('history-clear-empties', GR, ['clear(): void { this.seen.clear(); this.tail = [] }', 'clear(): void { this.tail = [] }'], GROUNDED_T),
|
|
56
|
+
m('history-clear-forgets-tail', GR, ['clear(): void { this.seen.clear(); this.tail = [] }', 'clear(): void { this.seen.clear() }'], GROUNDED_T),
|
|
57
|
+
m('history-fed-by-every-chunk', EN, ['if (this.groundingOn()) s.said.add(cleanWindow(text.trim()))', 'if (false) s.said.add(cleanWindow(text.trim()))'], GROUNDING_T),
|
|
58
|
+
m('history-fed-only-while-grounded', EN, ['if (this.groundingOn()) s.said.add(cleanWindow(text.trim()))', 's.said.add(cleanWindow(text.trim()))'], GROUNDING_T),
|
|
59
|
+
m('history-fed-clean-text', EN, ['s.said.add(cleanWindow(text.trim()))', 's.said.add(text.trim())'], GROUNDING_T),
|
|
60
|
+
m('history-window-added-at-evaluation', EN, [" s.said.add(cleanWindow(s.chunks.join('\\n')))\n", ''], GROUNDING_T),
|
|
61
|
+
m('history-used-for-self-copies', EN, ['transcript: s.said.shingles, window,', 'transcript: new Set<string>(), window,'], GROUNDING_T),
|
|
62
|
+
m('history-cleared-at-end', EN, [' s?.said.clear()\n', ''], GROUNDING_T),
|
|
63
|
+
m('self-overlap-threshold', GR, ['sixGramOverlap(c.notes, transcript) >= GROUNDED_LIMITS.selfOverlap', 'sixGramOverlap(c.notes, transcript) > GROUNDED_LIMITS.selfOverlap'], GROUNDED_T),
|
|
64
|
+
m('self-overlap-share-of-candidate', GR, ['return shared / own.size', 'return shared / Math.max(own.size, 40)'], GROUNDED_T),
|
|
65
|
+
m('self-record-id', GR, ['if ((c.recordId && selfIds.has(c.recordId)) || (c.sessionId && selfIds.has(c.sessionId))) return true', 'if (c.sessionId && selfIds.has(c.sessionId)) return true'], GROUNDED_T),
|
|
66
|
+
m('self-session-id', GR, ['if ((c.recordId && selfIds.has(c.recordId)) || (c.sessionId && selfIds.has(c.sessionId))) return true', 'if (c.recordId && selfIds.has(c.recordId)) return true'], GROUNDED_T),
|
|
67
|
+
m('self-standalone-form', GR, ['out.add(id); out.add(`standalone:${id}`)', 'out.add(id)'], GROUNDED_T),
|
|
68
|
+
m('self-exclusion-applied', GR, ['if (isSelfCopy(note, transcript, i.selfIds)) {', 'if (false) {'], GROUNDED_T),
|
|
69
|
+
m('self-exclusion-counted', GR, ['seen.add(id); excludedSelf += 1; continue }', 'seen.add(id); continue }'], GROUNDED_T),
|
|
70
|
+
m('self-exclusion-remembers-identity', GR, ['{ for (const id of identities) seen.add(id); excludedSelf += 1; continue }', '{ excludedSelf += 1; continue }'], GROUNDED_T),
|
|
71
|
+
m('malformed-note-skipped', GR, [' if (!wellFormed(raw)) continue\n', ''], GROUNDED_T),
|
|
72
|
+
m('note-id-is-a-string', GR, ["typeof r.id === 'string' && typeof r.date === 'string'", "typeof r.date === 'string'"], GROUNDED_T),
|
|
73
|
+
m('note-date-is-a-string', GR, ["typeof r.date === 'string' && typeof r.title === 'string'", "typeof r.title === 'string'"], GROUNDED_T),
|
|
74
|
+
m('note-title-is-a-string', GR, ["typeof r.title === 'string' && typeof r.notes === 'string'", "typeof r.notes === 'string'"], GROUNDED_T),
|
|
75
|
+
m('note-notes-is-a-string', GR, ["typeof r.title === 'string' && typeof r.notes === 'string'", "typeof r.title === 'string'"], GROUNDED_T),
|
|
76
|
+
m('note-key-is-a-string', GR, ["const key = typeof note.key === 'string' ? note.key : ''", "const key = (note.key ?? '') as string"], GROUNDED_T),
|
|
77
|
+
m('note-domain-is-a-string', GR, ['...(nonEmpty(note.domain) ? { domain: note.domain } : {}),', "...(note.domain ? { domain: note.domain as string } : {}),"], GROUNDED_T),
|
|
78
|
+
m('note-session-id-kept', GR, ['...(nonEmpty(note.sessionId) ? { sessionId: note.sessionId } : {}) }', '}'], GROUNDED_T),
|
|
79
|
+
m('note-session-id-is-a-string', GR, ['...(nonEmpty(note.sessionId) ? { sessionId: note.sessionId } : {}) }', '...(note.sessionId ? { sessionId: note.sessionId as string } : {}) }'], GROUNDED_T),
|
|
80
|
+
m('domain-unknown-counted', GR, ["const domainUnknown = out.filter(c => c.arm !== 'files' && !c.domain).length", 'const domainUnknown = 0'], GROUNDED_T),
|
|
81
|
+
m('domain-unknown-not-files', GR, ["out.filter(c => c.arm !== 'files' && !c.domain)", 'out.filter(c => !c.domain)'], GROUNDED_T),
|
|
82
|
+
m('files-list-is-an-array', GR, [' if (!Array.isArray(raw)) return []\n', ''], GROUNDED_T),
|
|
83
|
+
m('file-id-is-a-string', GR, ["typeof f.id === 'string' && typeof f.name === 'string'", "typeof f.name === 'string'"], GROUNDED_T),
|
|
84
|
+
m('file-name-is-a-string', GR, ["typeof f.name === 'string' && typeof f.status === 'string'", "typeof f.status === 'string'"], GROUNDED_T),
|
|
85
|
+
m('file-status-is-a-string', GR, ["typeof f.status === 'string' && typeof f.text === 'string')", "typeof f.text === 'string')"], GROUNDED_T),
|
|
86
|
+
m('file-text-is-a-string', GR, ["typeof f.status === 'string' && typeof f.text === 'string')", "typeof f.status === 'string')"], GROUNDED_T),
|
|
87
|
+
m('file-row-is-an-object', GR, ["raw.filter((f): f is GroundedFile => !!f && typeof f === 'object' && ", "raw.filter((f): f is GroundedFile => "], GROUNDED_T),
|
|
88
|
+
m('candidates-use-usable-files', GR, ['bestFilePassage(usableFiles(i.files), i.window)', 'bestFilePassage(i.files as GroundedFile[], i.window)'], GROUNDED_T),
|
|
89
|
+
m('domain-compare-strings-only', GR, ["const norm = (v: unknown) => (typeof v === 'string' ? v.trim().toLowerCase() : '')", "const norm = (v: unknown) => String(v ?? '').trim().toLowerCase()"], GROUNDED_T),
|
|
90
|
+
m('domain-compare-trims', GR, ["v.trim().toLowerCase() : '')", "v.toLowerCase() : '')"], GROUNDED_T),
|
|
91
|
+
m('domain-personal-only', GR, ["return norm(noteDomain) === 'personal' && norm(meetingDomain) !== 'personal'", "return norm(noteDomain) === 'personal'"], GROUNDED_T),
|
|
92
|
+
m('domain-personal-meeting-only', GR, ["return norm(noteDomain) === 'personal' && norm(meetingDomain) !== 'personal'", "return norm(meetingDomain) !== 'personal'"], GROUNDED_T),
|
|
93
|
+
m('domain-filter-applied', GR, ['if (isForeignPersonal(note.domain, i.meetingDomain)) continue', 'if (false) continue'], GROUNDED_T),
|
|
94
|
+
m('dedupe-applied', GR, ['if (identities.some(id => seen.has(id))) continue', 'if (false) continue'], GROUNDED_T),
|
|
95
|
+
m('dedupe-remembers', GR, ['for (const id of identities) seen.add(id)\n', ''], GROUNDED_T),
|
|
96
|
+
m('dedupe-normalised-title', GR, ['ids.push(`meeting:${c.date}|${normalizeMeetingTitle(c.title)}`)', 'ids.push(`meeting:${c.date}|${c.title}`)'], GROUNDED_T),
|
|
97
|
+
m('file-identity-is-not-a-meeting', GR, ['if (c.date && c.title && !c.fileId) ids.push(', 'if (c.date && c.title) ids.push('], GROUNDED_T),
|
|
98
|
+
m('dedupe-record-id', GR, ["if (c.recordId) ids.push(`record:${c.recordId}`)", ''], GROUNDED_T),
|
|
99
|
+
m('dedupe-memory-id', GR, ["if (c.memoryId) ids.push(`memory:${c.memoryId}`)", ''], GROUNDED_T),
|
|
100
|
+
m('title-punctuation', GR, ["title.toLowerCase().replace(/[!-/:-@[-`{-~]/g, ' ')", "title.toLowerCase().replace(/[!-/]/g, ' ')"], GROUNDED_T),
|
|
101
|
+
m('cue-memory-four', GR, ["take(i.cueMemory, 'cue_memory', GROUNDED_LIMITS.cueMemoryTop, 'M')", "take(i.cueMemory, 'cue_memory', GROUNDED_LIMITS.cueMemoryRaw, 'M')"], GROUNDED_T),
|
|
102
|
+
m('notes-one', GR, ["take(i.notes, 'notes', GROUNDED_LIMITS.notesTop, 'N')", "take(i.notes, 'notes', GROUNDED_LIMITS.cueMemoryTop, 'N')"], GROUNDED_T),
|
|
103
|
+
m('candidates-six', GR, ['maxCandidates: 6,', 'maxCandidates: 5,'], GROUNDED_T),
|
|
104
|
+
m('file-ready-only', GR, ["if (file.status !== 'ready' || typeof file.text", 'if (typeof file.text'], GROUNDED_T),
|
|
105
|
+
m('file-needs-two-terms', GR, ['score >= GROUNDED_LIMITS.fileMinTerms', 'score >= 1'], GROUNDED_T),
|
|
106
|
+
m('file-first-best-wins', GR, ['(!best || score > best.score)', '(!best || score >= best.score)'], GROUNDED_T),
|
|
107
|
+
m('file-dated-with-the-meeting', GR, ["out.push({ id: 'F1', date: i.today,", "out.push({ id: 'F1', date: '',"], GROUNDED_T),
|
|
108
|
+
m('file-not-self-checked', GR, [" out.push({ id: 'F1'", " if (isSelfCopy({ notes: hit.passage }, transcript, i.selfIds)) return { candidates: out, excludedSelf: excludedSelf + 1 }\n out.push({ id: 'F1'"], GROUNDED_T),
|
|
109
|
+
m('file-passage-cap', GR, ['fileChars: 300,', 'fileChars: 600,'], GROUNDED_T),
|
|
110
|
+
m('file-window-terms', GR, ['fileWindowTerms: 12,', 'fileWindowTerms: 1,'], GROUNDED_T),
|
|
111
|
+
m('kind-from-memory-key', GR, ["return { ...base, kind: 'memory', memoryId: key.slice('memory:'.length) }", "return { ...base, kind: 'meeting', memoryId: key.slice('memory:'.length) }"], GROUNDED_T),
|
|
112
|
+
m('kind-from-meeting-key', GR, ["return { ...base, kind: 'meeting', recordId: key.slice('meeting:'.length) }", "return { ...base, kind: 'meeting' }"], GROUNDED_T),
|
|
113
|
+
m('source-memory-locator', GR, ["if (note.kind === 'memory' && note.memoryId) return { ...base, memoryId: note.memoryId }\n", ''], GROUNDED_T),
|
|
114
|
+
m('source-file-locator', GR, ["if (note.kind === 'file' && note.fileId) return { ...base, fileId: note.fileId }\n", ''], GROUNDED_T),
|
|
115
|
+
m('source-record-locator', GR, ["if (note.kind === 'meeting' && note.recordId) return { ...base, recordId: note.recordId }\n", ''], GROUNDED_T),
|
|
116
|
+
m('source-kind', GR, ['const base: CueSourceRef = { id, date: note.date, title: note.title, kind: note.kind }', 'const base: CueSourceRef = { id, date: note.date, title: note.title }'], GROUNDED_T),
|
|
117
|
+
// ── Engine: grounded evaluation ──
|
|
118
|
+
m('grounding-reads-setting', EN, ["return resolveLiveCuesGrounding(this.deps.env, this.deps.settings).value === 'grounded'", "return resolveLiveCuesGrounding(this.deps.env, null).value === 'grounded'"], GROUNDING_T),
|
|
119
|
+
m('grounding-off-is-classic', EN, ["return resolveLiveCuesGrounding(this.deps.env, this.deps.settings).value === 'grounded'", 'return true'], [...GROUNDING_T, ...PIN_T]),
|
|
120
|
+
m('grounded-skips-classic-memory', EN, ['let mem: MemoryResult = grounded ? { notes: [] } : await this.deps.memory(', 'let mem: MemoryResult = await this.deps.memory('], GROUNDING_T),
|
|
121
|
+
m('grounded-skips-classic-judge', EN, ['if (!grounded && mem.notes.length && !abort.signal.aborted) {', 'if (mem.notes.length && !abort.signal.aborted) {'], GROUNDING_T),
|
|
122
|
+
m('grounded-arms-in-parallel', EN, [
|
|
123
|
+
[" const [cm, nt] = await Promise.all([\n timed(() => this.deps.memory(window, before, signal, GROUNDED_LIMITS.cueMemoryRaw), 'memory_threw'),\n timed(() => this.deps.notes(window, before, signal, s.sessionId), 'notes_threw'),\n ])",
|
|
124
|
+
" const cm = await timed(() => this.deps.memory(window, before, signal, GROUNDED_LIMITS.cueMemoryRaw), 'memory_threw')\n const nt = await timed(() => this.deps.notes(window, before, signal, s.sessionId), 'notes_threw')"]], GROUNDING_T),
|
|
125
|
+
m('grounded-asks-for-eight', EN, ["this.deps.memory(window, before, signal, GROUNDED_LIMITS.cueMemoryRaw), 'memory_threw')", "this.deps.memory(window, before, signal, 4), 'memory_threw')"], GROUNDING_T),
|
|
126
|
+
m('grounded-notes-always', EN, ["timed(() => this.deps.notes(window, before, signal, s.sessionId), 'notes_threw'),", "timed(async () => ({ notes: [] }), 'notes_threw'),"], GROUNDING_T),
|
|
127
|
+
m('grounded-twins', EN, ['const twins = [...this.sessions.keys()].filter(id => id !== s.sessionId)', 'const twins: string[] = []'], GROUNDING_T),
|
|
128
|
+
m('grounded-orientation-caught', EN, ['catch (e) { trace.orientationError = codeOf(e) }', 'catch (e) { throw e }'], GROUNDING_T),
|
|
129
|
+
m('grounded-files-caught', EN, ['catch (e) { trace.filesError = codeOf(e) }', 'catch (e) { throw e }'], GROUNDING_T),
|
|
130
|
+
m('grounded-error-code-reason', EN, ["typeof r?.reason === 'string' ? r.reason : typeof r?.code === 'string' ? r.code : 'threw'", "typeof r?.code === 'string' ? r.code : 'threw'"], GROUNDING_T),
|
|
131
|
+
m('grounded-arm-failure-traced', EN, ['catch { return { res: { notes: [], denseError: threw }, ms: null } }', 'catch { return { res: { notes: [] }, ms: null } }'], GROUNDING_T),
|
|
132
|
+
m('grounded-arm-failure-null-ms', EN, ['catch { return { res: { notes: [], denseError: threw }, ms: null } }', 'catch { return { res: { notes: [], denseError: threw }, ms: 0 } }'], GROUNDING_T),
|
|
133
|
+
m('grounded-trace-flag', EN, [" trace.grounding = 'grounded'\n", ''], GROUNDING_T),
|
|
134
|
+
m('grounded-trace-ready-files', EN, ["files: files.filter(f => f.status === 'ready').length }, excludedSelf, domainUnknown })", 'files: files.length }, excludedSelf, domainUnknown })'], GROUNDING_T),
|
|
135
|
+
m('grounded-trace-excluded-self', EN, ["files: files.filter(f => f.status === 'ready').length }, excludedSelf, domainUnknown })", "files: files.filter(f => f.status === 'ready').length }, domainUnknown })"], GROUNDING_T),
|
|
136
|
+
m('grounded-trace-domain-unknown', EN, ["files: files.filter(f => f.status === 'ready').length }, excludedSelf, domainUnknown })", "files: files.filter(f => f.status === 'ready').length }, excludedSelf })"], GROUNDING_T),
|
|
137
|
+
m('grounded-orientation-title-is-a-string', EN, ["calendarTitle = typeof o?.title === 'string' ? o.title : null", 'calendarTitle = (o?.title ?? null) as string | null'], GROUNDING_T),
|
|
138
|
+
m('grounded-files-are-usable', EN, ['files = usableFiles(this.deps.files?.(s.sessionId))', 'files = (this.deps.files?.(s.sessionId) ?? []) as GroundedFile[]'], GROUNDING_T),
|
|
139
|
+
m('cue-memory-keeps-domain', EN, ["typeof n.notes === 'string').slice(0, top)", "typeof n.notes === 'string').map(({ domain: _d, ...rest }) => rest as MemoryNote).slice(0, top)"], GROUNDING_T),
|
|
140
|
+
m('grounded-trace-judge', EN, ['yes: round(judged.yes[c.id] ?? 0), same: round(judged.same[c.id] ?? 0) })) })', 'yes: 0, same: 0 })) })'], GROUNDING_T),
|
|
141
|
+
m('grounded-trace-kept-ids', EN, [' if (run) trace.keptIds = kept.map(m => m.id)', ' if (false) trace.keptIds = kept.map(m => m.id)'], GROUNDING_T),
|
|
142
|
+
m('grounded-trace-kept-count', EN, ['trace.kept = kept.length\n', 'trace.kept = run ? kept.map(m => m.id) : kept.length\n'], [...GROUNDING_T, ...PIN_T]),
|
|
143
|
+
m('classic-trace-has-no-kept-ids', EN, [' if (run) trace.keptIds = kept.map(m => m.id)', ' trace.keptIds = kept.map(m => m.id)'], PIN_T),
|
|
144
|
+
m('grounded-source-arm', EN, ["const source: LiveCuesV2MemorySource = candidates.some(c => c.arm === 'cue_memory') ? 'cue_memory' : candidates.some(c => c.arm === 'notes') ? 'notes' : 'none'", "const source: LiveCuesV2MemorySource = 'cue_memory'"], GROUNDING_T),
|
|
145
|
+
m('grounded-arms-contributed', EN, ["(['cue_memory', 'notes', 'files'] as const).filter(a => candidates.some(c => c.arm === a))", "(['cue_memory', 'notes', 'files'] as const)"], GROUNDING_T),
|
|
146
|
+
m('grounded-arms-logged', EN, ['...(run ? { arms: run.arms } : {}) })', '...({}) })'], GROUNDING_T),
|
|
147
|
+
m('classic-log-has-no-arms', EN, ['...(run ? { arms: run.arms } : {}) })', '...({ arms: run?.arms ?? [] }) })'], PIN_T),
|
|
148
|
+
m('grounded-sources-carry-kind', EN, ['.map(m => (run ? groundedSource(m as GroundedNote, sourceId(m)) : { id: sourceId(m), date: m.date, title: m.title }))', '.map(m => ({ id: sourceId(m), date: m.date, title: m.title }))'], GROUNDING_T),
|
|
149
|
+
m('grounded-no-candidates-no-judge', EN, ['if (candidates.length && !signal.aborted) {', 'if (!signal.aborted) {'], GROUNDING_T),
|
|
150
|
+
m('grounded-cancelled-no-judge', EN, ['if (candidates.length && !signal.aborted) {', 'if (candidates.length) {'], GROUNDING_T),
|
|
151
|
+
m('grounded-judge-title', EN, ['await this.deps.judgeB(s.title, window, candidates, signal, provider)', 'await this.deps.judgeB(writerTitle, window, candidates, signal, provider)'], GROUNDING_T),
|
|
152
|
+
m('grounded-writer-title', EN, ['meetingTitle: run?.writerTitle ?? s.title', 'meetingTitle: s.title'], GROUNDING_T),
|
|
153
|
+
m('grounded-writer-title-120', EN, ["const title = (calendarTitle ?? '').replace(/\\s+/g, ' ').trim().slice(0, 120)", "const title = (calendarTitle ?? '').replace(/\\s+/g, ' ').trim().slice(0, 300)"], GROUNDING_T),
|
|
154
|
+
m('grounded-writer-title-trimmed', EN, ["const title = (calendarTitle ?? '').replace(/\\s+/g, ' ').trim().slice(0, 120)", "const title = (calendarTitle ?? '').slice(0, 120)"], GROUNDING_T),
|
|
155
|
+
m('grounded-keep-bar', EN, ['kept = selectJudgeB(candidates, judged.yes, liveCuesV2JudgeYes(this.deps.env), LIVE_CUES_V2_LIMITS.judgeMaxNotes)', 'kept = selectJudgeB(candidates, judged.yes, LIVE_CUES_V2_LIMITS.judgeKeep, LIVE_CUES_V2_LIMITS.judgeMaxNotes)'], GROUNDING_T),
|
|
156
|
+
m('grounded-keep-env-bar', EN, ['kept = selectJudgeB(candidates, judged.yes, liveCuesV2JudgeYes(this.deps.env), LIVE_CUES_V2_LIMITS.judgeMaxNotes)', 'kept = selectJudgeB(candidates, judged.yes, LIVE_CUES_V2_LIMITS.judgeYes, LIVE_CUES_V2_LIMITS.judgeMaxNotes)'], GROUNDING_T),
|
|
157
|
+
m('grounded-keep-two', EN, ['kept = selectJudgeB(candidates, judged.yes, liveCuesV2JudgeYes(this.deps.env), LIVE_CUES_V2_LIMITS.judgeMaxNotes)', 'kept = selectJudgeB(candidates, judged.yes, liveCuesV2JudgeYes(this.deps.env), 4)'], GROUNDING_T),
|
|
158
|
+
m('judge-yes-default', EN, ['judgeYes: 0.65,', 'judgeYes: 0.7,'], GROUNDING_T),
|
|
159
|
+
m('judge-yes-min-inclusive', EN, ['return yes >= 0.5 && yes <= 0.95 ? yes : knobFallback(', 'return yes > 0.5 && yes <= 0.95 ? yes : knobFallback('], GROUNDING_T),
|
|
160
|
+
m('judge-yes-max-inclusive', EN, ['return yes >= 0.5 && yes <= 0.95 ? yes : knobFallback(', 'return yes >= 0.5 && yes < 0.95 ? yes : knobFallback('], GROUNDING_T),
|
|
161
|
+
m('judge-yes-empty-is-default', EN, ["if (raw === undefined || raw.trim() === '') return LIVE_CUES_V2_LIMITS.judgeYes", 'if (raw === undefined) return LIVE_CUES_V2_LIMITS.judgeYes'], GROUNDING_T),
|
|
162
|
+
m('memory-top-on-the-wire', EN, ['keywordText: window, before, top }))', 'keywordText: window, before, top: 4 }))'], GROUNDING_T),
|
|
163
|
+
m('memory-top-kept', EN, ["typeof n.notes === 'string').slice(0, top)", "typeof n.notes === 'string').slice(0, 4)"], GROUNDING_T),
|
|
164
|
+
m('end-no-insight-twin', EN, ['cues.flatMap(c => (isCueKind(c.kind) ? [{', 'cues.flatMap(c => (true ? [{'], KINDS_T),
|
|
165
|
+
// ── Engine: settings view and apply ──
|
|
166
|
+
m('view-v3-version', EN, ['return { ...v2, v: 3, cueMode:', 'return { ...v2, v: 2 as never, cueMode:'], ROUTE_T),
|
|
167
|
+
m('view-v3-cue-mode', EN, ['cueMode: resolveLiveCuesCueMode(env, settings), grounding:', 'cueMode: resolveLiveCuesCueMode(env, null), grounding:'], ROUTE_T),
|
|
168
|
+
m('view-v3-grounding', EN, ['grounding: resolveLiveCuesGrounding(env, settings),\n', 'grounding: resolveLiveCuesGrounding(env, null),\n'], ROUTE_T),
|
|
169
|
+
m('view-v3-public-topics', EN, ['publicTopics = new MeetingAskStore().publicTopics()', 'publicTopics = false'], ROUTE_T),
|
|
170
|
+
m('view-v3-home-area', EN, ['homeArea = getOwnerHomeArea()', 'homeArea = null'], ROUTE_T),
|
|
171
|
+
m('view-v3-today-provider', EN, ['today = generalTodayProvider ? generalTodayProvider() : {', 'today = {'], ROUTE_T),
|
|
172
|
+
m('view-v3-today-provider-throws', EN, ['} catch { today = { day: v2.today.day, topicCalls: 0, webSearches: 0, breakerOpenUntil: null } }', "} catch { throw new Error('provider') }"], ROUTE_T),
|
|
173
|
+
m('apply-env-forced-mode', EN, ["resolveLiveCuesCueMode(env, liveCuesV2Settings()).locked) forced.push('cueMode')", "false) forced.push('cueMode')"], ROUTE_T),
|
|
174
|
+
m('apply-env-forced-mode-allows-focused', EN, ["patch.cueMode !== undefined && patch.cueMode !== 'focused' && resolveLiveCuesCueMode", 'patch.cueMode !== undefined && resolveLiveCuesCueMode'], ROUTE_T),
|
|
175
|
+
m('apply-env-forced-grounding', EN, ["resolveLiveCuesGrounding(env, liveCuesV2Settings()).locked) forced.push('grounding')", "false) forced.push('grounding')"], ROUTE_T),
|
|
176
|
+
m('apply-env-forced-grounding-allows-classic', EN, ["patch.grounding !== undefined && patch.grounding !== 'classic' && resolveLiveCuesGrounding", 'patch.grounding !== undefined && resolveLiveCuesGrounding'], ROUTE_T),
|
|
177
|
+
m('apply-env-locked-general', EN, ['...(Object.keys(patch.general ?? {}) as LiveCuesGeneralLimitName[]).filter(name => generalNow[name].locked).map(name => LIVE_CUES_GENERAL_LIMIT_BOUNDS[name].field),', ''], ROUTE_T),
|
|
178
|
+
m('apply-env-locked-wire-name', EN, ['.filter(name => generalNow[name].locked).map(name => LIVE_CUES_GENERAL_LIMIT_BOUNDS[name].field)', '.filter(name => generalNow[name].locked)'], ROUTE_T),
|
|
179
|
+
m('general-env-integers', EN, ['if (b.integer) e = envWhole(env, b.env, b.min, b.max)', 'if (b.integer) e = null'], ROUTE_T),
|
|
180
|
+
m('general-env-trigger-range', EN, ['e = n === null ? null : n >= b.min && n <= b.max ? n : knobFallback', 'e = n === null ? null : n >= b.min ? n : knobFallback'], ROUTE_T),
|
|
181
|
+
m('general-env-locks', EN, ["out[name] = e !== null ? { value: e, source: 'env', locked: true, min: b.min, max: b.max, default: b.default }\n : v !== undefined ? { value: v, source: 'setting', locked: false, min: b.min, max: b.max, default: b.default }\n : { value: b.default, source: 'default', locked: false, min: b.min, max: b.max, default: b.default }\n }\n return out\n}\nexport function liveCuesV2JudgeKeep", "out[name] = e !== null ? { value: e, source: 'env', locked: false, min: b.min, max: b.max, default: b.default }\n : v !== undefined ? { value: v, source: 'setting', locked: false, min: b.min, max: b.max, default: b.default }\n : { value: b.default, source: 'default', locked: false, min: b.min, max: b.max, default: b.default }\n }\n return out\n}\nexport function liveCuesV2JudgeKeep"], ROUTE_T),
|
|
182
|
+
// ── Settings store and resolution ──
|
|
183
|
+
m('store-schema-3', ST, ['hasV3 ? 3 : hasLimits ? 2 : 1', 'hasLimits ? 2 : 1'], SETTINGS_T),
|
|
184
|
+
m('store-keeps-cue-mode', ST, ['const cueMode = patch.cueMode ?? current.cueMode', 'const cueMode = patch.cueMode ?? null'], SETTINGS_T),
|
|
185
|
+
m('store-keeps-grounding', ST, ['const grounding = patch.grounding ?? current.grounding', 'const grounding = patch.grounding ?? null'], SETTINGS_T),
|
|
186
|
+
m('store-merges-general', ST, ['const general = { ...current.general, ...patch.general }', 'const general = { ...patch.general }'], SETTINGS_T),
|
|
187
|
+
m('store-writes-wire-names', ST, ['[LIVE_CUES_GENERAL_LIMIT_BOUNDS[n].field, general[n]]', '[n, general[n]]'], SETTINGS_T),
|
|
188
|
+
m('store-reads-wire-names', ST, ['const field = LIVE_CUES_GENERAL_LIMIT_BOUNDS[name].field\n if (generalLimitInBounds(name, r[field]))', 'const field = name\n if (generalLimitInBounds(name, r[field]))'], SETTINGS_T),
|
|
189
|
+
m('store-validates-cue-mode', ST, ['if (isCueMode(r.cueMode)) cueMode = r.cueMode', 'if (r.cueMode !== undefined) cueMode = r.cueMode as LiveCuesCueMode'], SETTINGS_T),
|
|
190
|
+
m('store-validates-grounding', ST, ['if (isGrounding(r.grounding)) grounding = r.grounding', 'if (r.grounding !== undefined) grounding = r.grounding as LiveCuesGrounding'], SETTINGS_T),
|
|
191
|
+
m('store-validates-general-bounds', ST, ['if (generalLimitInBounds(name, r[field])) general[name] = r[field] as number', 'general[name] = r[field] as number'], SETTINGS_T),
|
|
192
|
+
m('resolve-mode-env-only-focused', ST, ["if (env.COS_LIVE_CUES_MODE === 'focused')", 'if (env.COS_LIVE_CUES_MODE)'], SETTINGS_T),
|
|
193
|
+
m('resolve-grounding-env-only-classic', ST, ["if (env.COS_LIVE_CUES_GROUNDING === 'classic')", 'if (env.COS_LIVE_CUES_GROUNDING)'], SETTINGS_T),
|
|
194
|
+
m('resolve-mode-validated', ST, ['try { const v = settings?.cueMode?.(); stored = isCueMode(v) ? v : null } catch { stored = null }', 'try { const v = settings?.cueMode?.(); stored = (v ?? null) as LiveCuesCueMode | null } catch { stored = null }'], SETTINGS_T),
|
|
195
|
+
m('resolve-grounding-validated', ST, ['try { const v = settings?.grounding?.(); stored = isGrounding(v) ? v : null } catch { stored = null }', 'try { const v = settings?.grounding?.(); stored = (v ?? null) as LiveCuesGrounding | null } catch { stored = null }'], [...SETTINGS_T, ...PIN_T]),
|
|
196
|
+
m('resolve-mode-reader-throws', ST, ['try { const v = settings?.cueMode?.(); stored = isCueMode(v) ? v : null } catch { stored = null }', '{ const v = settings?.cueMode?.(); stored = isCueMode(v) ? v : null }'], SETTINGS_T),
|
|
197
|
+
m('resolve-grounding-reader-throws', ST, ['try { const v = settings?.grounding?.(); stored = isGrounding(v) ? v : null } catch { stored = null }', '{ const v = settings?.grounding?.(); stored = isGrounding(v) ? v : null }'], [...SETTINGS_T, ...PIN_T]),
|
|
198
|
+
m('general-limit-default-interval', ST, ["intervalSeconds: { field: 'generalIntervalSeconds', min: 120, max: 1800, default: 300,", "intervalSeconds: { field: 'generalIntervalSeconds', min: 120, max: 1800, default: 360,"], SETTINGS_T),
|
|
199
|
+
m('general-limit-bound-trigger', ST, ["trigger: { field: 'generalTrigger', min: 0.4, max: 0.9,", "trigger: { field: 'generalTrigger', min: 0.4, max: 0.95,"], SETTINGS_T),
|
|
200
|
+
// ── Route ──
|
|
201
|
+
m('route-get-v3', RT, ["v === '3' ? liveCuesV2SettingsViewV3() : v === '2'", "v === '3' ? liveCuesV2SettingsViewV2() : v === '2'"], ROUTE_T),
|
|
202
|
+
m('route-v2-refuses-v3-fields', RT, ['!(v3 ? V3_SETTINGS_KEYS : V2_SETTINGS_KEYS).has(k)', '!V3_SETTINGS_KEYS.has(k)'], ROUTE_T),
|
|
203
|
+
m('route-v3-takes-v3-fields', RT, ['!(v3 ? V3_SETTINGS_KEYS : V2_SETTINGS_KEYS).has(k)', '!V2_SETTINGS_KEYS.has(k)'], ROUTE_T),
|
|
204
|
+
m('route-cue-mode-enum', RT, ['if (v3 && body.cueMode !== undefined && !isCueMode(body.cueMode))', 'if (false)'], ROUTE_T),
|
|
205
|
+
m('route-grounding-enum', RT, ['if (v3 && body.grounding !== undefined && !isGrounding(body.grounding))', 'if (false)'], ROUTE_T),
|
|
206
|
+
m('route-general-bounds', RT, ['if (!generalLimitInBounds(name, body[b.field])) return res.status(400)', 'if (false) return res.status(400)'], ROUTE_T),
|
|
207
|
+
m('route-general-bounds-wire-field', RT, ["reason: 'out_of_bounds', field: b.field, min: b.min", "reason: 'out_of_bounds', field: name, min: b.min"], ROUTE_T),
|
|
208
|
+
m('route-env-forced-fields', RT, ["result.fields ? { error: 'env_forced', fields: result.fields } : { error: result.error }", '{ error: result.error }'], ROUTE_T),
|
|
209
|
+
m('route-answers-v3', RT, ['return res.json(v3 ? liveCuesV2SettingsViewV3() : liveCuesV2SettingsViewV2())', 'return res.json(liveCuesV2SettingsViewV2())'], ROUTE_T),
|
|
210
|
+
m('route-passes-cue-mode', RT, ['...(isCueMode(body.cueMode) ? { cueMode: body.cueMode } : {}),', ''], ROUTE_T),
|
|
211
|
+
m('route-passes-general', RT, ['...(Object.keys(general).length ? { general } : {}) })', '})'], ROUTE_T),
|
|
212
|
+
// ── Cue log schema ──
|
|
213
|
+
m('log-source-extras', VD, ['if (!isCueSourceExtras(s)) return false', ''], VERDICT_T),
|
|
214
|
+
m('log-source-url-public', VD, ['return s.url === undefined || publicHttpsUrl(s.url) !== null', 'return true'], VERDICT_T),
|
|
215
|
+
m('log-source-base-strings', VD, ['if (!(str(s.id) && str(s.date) && str(s.title))) return false', ''], VERDICT_T),
|
|
216
|
+
m('log-arms-enum', VD, ['a.every(x => (LIVE_CUE_ARMS as readonly unknown[]).includes(x))', 'true'], VERDICT_T),
|
|
217
|
+
m('log-arms-unique', VD, ['new Set(a).size === a.length && ', ''], VERDICT_T),
|
|
218
|
+
m('log-arms-array', VD, ["optional(r.arms, a => Array.isArray(a) && ", "optional(r.arms, a => "], VERDICT_T),
|
|
219
|
+
m('log-general-category', VD, ['(LIVE_CUE_GENERAL_CATEGORIES as readonly unknown[]).includes(g.category) && ', ''], VERDICT_T),
|
|
220
|
+
m('log-general-query-not-empty', VD, ['str(g.query) && g.query.length > 0 && ', 'str(g.query) && '], VERDICT_T),
|
|
221
|
+
m('log-general-query-length', VD, [' && g.query.length <= LIVE_CUE_GENERAL_QUERY_MAX', ''], VERDICT_T),
|
|
222
|
+
m('log-general-checked', VD, ['&& optional(r.general, isGeneral)', ''], VERDICT_T),
|
|
223
|
+
m('log-arms-checked', VD, ['&& optional(r.arms, a =>', '&& optional(r.arms, a => true || '], VERDICT_T),
|
|
224
|
+
// ── Shared contract ──
|
|
225
|
+
m('contract-one-locator', SH, ['if (locators.length > 1) return false\n', ''], KINDS_T),
|
|
226
|
+
m('contract-locator-matches-kind', SH, ['if (locators.length === 1 && locators[0] !== CUE_SOURCE_LOCATOR[source.kind]) return false\n', ''], KINDS_T),
|
|
227
|
+
m('contract-no-kind-no-locator', SH, ['if (source.kind === undefined) return locators.length === 0', 'if (source.kind === undefined) return true'], KINDS_T),
|
|
228
|
+
m('contract-known-kind', SH, ['if (!(CUE_SOURCE_KINDS as readonly string[]).includes(source.kind)) return false\n', ''], KINDS_T),
|
|
229
|
+
m('contract-web-needs-url', SH, ["if (source.kind === 'web' && source.url === undefined) return false\n", ''], [...KINDS_T, ...VERDICT_T]),
|
|
230
|
+
m('contract-url-https', SH, ["return source.url === undefined || source.url.startsWith('https://')", 'return true'], KINDS_T),
|
|
231
|
+
m('contract-locator-nonempty', SH, ["if (value !== undefined && (typeof value !== 'string' || value.length === 0 || value.length > 2048)) return false", ''], KINDS_T),
|
|
232
|
+
m('contract-insight-is-a-log-kind', SH, ['(GENERAL_CUE_KINDS as readonly string[]).includes(value))', 'false)'], KINDS_T),
|
|
233
|
+
m('contract-live-cue-checks-extras', SH, ["typeof (s as CueSourceRef).title === 'string'\n && isCueSourceExtras(s as CueSourceRef))", "typeof (s as CueSourceRef).title === 'string')"], KINDS_T),
|
|
234
|
+
m('contract-live-cue-takes-insight', SH, [' && isLogCueKind(v.kind)\n', ' && isCueKind(v.kind)\n'], KINDS_T),
|
|
235
|
+
// ── Public https validator ──
|
|
236
|
+
m('url-https-only', UR, ["u.protocol !== 'https:' ||", "(u.protocol !== 'https:' && u.protocol !== 'http:') ||"], URL_T),
|
|
237
|
+
m('url-no-credentials', UR, ['|| u.username || u.password ||', '||'], URL_T),
|
|
238
|
+
m('url-public-host', UR, ['!publicAddress(host) ||', ''], URL_T),
|
|
239
|
+
m('url-default-port-only', UR, ["u.port && u.port !== '443'", 'false'], URL_T),
|
|
240
|
+
m('url-port-80-is-not-https', UR, ["u.port && u.port !== '443'", "u.port && !['80', '443'].includes(u.port)"], URL_T),
|
|
241
|
+
m('url-trailing-dot', UR, ["const host = u.hostname.replace(/\\.$/, '')", 'const host = u.hostname'], URL_T),
|
|
242
|
+
m('url-empty-label-end', UR, ["if (host.endsWith('.') || host.includes('..')) return null", "if (host.includes('..')) return null"], URL_T),
|
|
243
|
+
m('url-empty-label-inside', UR, ["if (host.endsWith('.') || host.includes('..')) return null", "if (host.endsWith('.')) return null"], URL_T),
|
|
244
|
+
m('url-length', UR, ["value.length > 2048", 'false'], URL_T),
|
|
245
|
+
// ── Notes arm: domain and session ride along ──
|
|
246
|
+
m('notes-carry-meeting-domain', NT, ['...domainOf(hit.domain), ...(hit.sessionId ? { sessionId: hit.sessionId } : {}) }', '...(hit.sessionId ? { sessionId: hit.sessionId } : {}) }'], [...GROUNDED_T, ...GROUNDING_T, 'server/lib/live-cues-v2-notes.test.ts']),
|
|
247
|
+
m('notes-carry-bridge-domain', NT, ['key: `memory:${row.id}`, ...domainOf(row.domain) }', 'key: `memory:${row.id}` }'], [...GROUNDED_T, ...GROUNDING_T, 'server/lib/live-cues-v2-notes.test.ts']),
|
|
248
|
+
m('notes-domain-trimmed', NT, ['{ domain: v.trim() }', '{ domain: v }'], [...GROUNDED_T, ...GROUNDING_T, 'server/lib/live-cues-v2-notes.test.ts']),
|
|
249
|
+
m('notes-blank-domain-is-none', NT, ["typeof v === 'string' && v.trim() ? { domain: v.trim() } : {}", "typeof v === 'string' ? { domain: v.trim() } : {}"], [...GROUNDED_T, ...GROUNDING_T, 'server/lib/live-cues-v2-notes.test.ts']),
|
|
250
|
+
m('notes-carry-domain', NT, ['key: `memory:${hit.id}`, ...domainOf(hit.domain) }', 'key: `memory:${hit.id}` }'], [...GROUNDED_T, ...GROUNDING_T, 'server/lib/live-cues-v2-notes.test.ts']),
|
|
251
|
+
m('notes-carry-session', NT, ["...(hit.sessionId ? { sessionId: hit.sessionId } : {}) }", '}'], [...GROUNDED_T, ...GROUNDING_T, 'server/lib/live-cues-v2-notes.test.ts']),
|
|
252
|
+
]
|
|
253
|
+
|
|
254
|
+
const args = process.argv.slice(2)
|
|
255
|
+
const names = args.filter(a => !a.startsWith('--'))
|
|
256
|
+
if (args.includes('--list')) { for (const { name } of mutations) console.log(name); process.exit(0) }
|
|
257
|
+
const selected = names.length ? mutations.filter(({ name }) => names.includes(name)) : mutations
|
|
258
|
+
if (names.length && selected.length !== names.length) throw new Error('Unknown mutation name in: ' + names.join(' '))
|
|
259
|
+
if (new Set(mutations.map(x => x.name)).size !== mutations.length) throw new Error('Duplicate mutation name')
|
|
260
|
+
|
|
261
|
+
/** The edits applied to one file's text. Each target must match exactly once and the result must differ. */
|
|
262
|
+
function mutate(original, { name, file, edits }) {
|
|
263
|
+
let mutated = original
|
|
264
|
+
for (const [find, replacement] of edits) {
|
|
265
|
+
if (mutated.split(find).length !== 2) throw new Error(`Mutation ${name} does not match exactly once in ${file}: ${find.slice(0, 80)}`)
|
|
266
|
+
mutated = mutated.replace(find, () => replacement)
|
|
267
|
+
}
|
|
268
|
+
if (mutated === original) throw new Error(`Mutation ${name} did not change ${file}`)
|
|
269
|
+
return mutated
|
|
270
|
+
}
|
|
271
|
+
// --check: prove every target matches exactly once in the live checkout, without running a test (the baseline is the slow part).
|
|
272
|
+
if (args.includes('--check')) {
|
|
273
|
+
let bad = 0
|
|
274
|
+
for (const mutation of selected) {
|
|
275
|
+
try { mutate(readFileSync(join(root, mutation.file), 'utf8'), mutation) } catch (error) { bad += 1; console.log(error.message) }
|
|
276
|
+
}
|
|
277
|
+
console.log(`${selected.length - bad} of ${selected.length} mutation targets match exactly once`)
|
|
278
|
+
process.exit(bad ? 1 : 0)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const scratch = mkdtempSync(join(tmpdir(), 'cue-v3-mutations-'))
|
|
282
|
+
try {
|
|
283
|
+
const skip = new Set(['data', 'models', 'certs', 'node_modules'])
|
|
284
|
+
cpSync(join(root, 'server'), join(scratch, 'server'), { recursive: true, filter: src => !(skip.has(basename(src)) && dirname(src) === join(root, 'server')) })
|
|
285
|
+
for (const dir of ['shared', 'work-task-runtime', 'bin', 'docs', 'memory-runtime']) cpSync(join(root, dir), join(scratch, dir), { recursive: true })
|
|
286
|
+
for (const file of ['vitest.config.ts', 'package.json', 'managed-runtime-contract.json']) cpSync(join(root, file), join(scratch, file))
|
|
287
|
+
symlinkSync(join(root, 'node_modules'), join(scratch, 'node_modules'), 'dir')
|
|
288
|
+
const run = tests => spawnSync(process.execPath, [join(root, 'node_modules/vitest/vitest.mjs'), 'run', '--maxWorkers=1', ...tests], {
|
|
289
|
+
cwd: scratch, env: { PATH: process.env.PATH, HOME: scratch, TMPDIR: process.env.TMPDIR, COS_DATA_DIR: join(scratch, 'data'), COS_PROFILE_PATH: join(scratch, 'data', 'profile.json') },
|
|
290
|
+
encoding: 'utf8', timeout: 300000,
|
|
291
|
+
})
|
|
292
|
+
const baseline = run(ALL)
|
|
293
|
+
if (baseline.status !== 0) throw new Error('Baseline failed; a gate over a red suite proves nothing:\n' + baseline.stdout + '\n' + baseline.stderr)
|
|
294
|
+
const totals = /Tests\s+(\d+) passed/.exec(baseline.stdout)
|
|
295
|
+
console.log(`baseline PASS (${totals ? totals[1] : '?'} tests in ${ALL.length} files)`)
|
|
296
|
+
let killed = 0
|
|
297
|
+
for (const { name, file, edits, tests } of selected) {
|
|
298
|
+
const target = join(scratch, file), original = readFileSync(target, 'utf8')
|
|
299
|
+
const mutated = mutate(original, { name, file, edits })
|
|
300
|
+
writeFileSync(target, mutated)
|
|
301
|
+
let result
|
|
302
|
+
try { result = run(tests) } finally { writeFileSync(target, original) }
|
|
303
|
+
if (readFileSync(target, 'utf8') !== original) throw new Error(`Restore failed for ${file} after ${name}`)
|
|
304
|
+
const output = result.stdout + '\n' + result.stderr
|
|
305
|
+
const killers = [...new Set([...output.matchAll(/FAIL\s+((?:server|shared)\/\S+\.test\.ts > [^\n]+)/g)].map(x => x[1].trim()))]
|
|
306
|
+
if (result.status === 0 || result.error || !killers.length) { console.log(`${name} SURVIVED or harness failed\n${output.slice(-3000)}`); process.exitCode = 1; continue }
|
|
307
|
+
killed += 1
|
|
308
|
+
console.log(`${name} KILLED by ${killers.slice(0, 2).join(' | ')}${killers.length > 2 ? ` (+${killers.length - 2} more)` : ''}`)
|
|
309
|
+
}
|
|
310
|
+
console.log(`${killed} of ${selected.length} live cues v3 mutations killed`)
|
|
311
|
+
} finally { rmSync(scratch, { recursive: true, force: true }) }
|
|
@@ -53,20 +53,20 @@ const mutations = [
|
|
|
53
53
|
m('selection-not-trimmed-to-room', A, ['Math.min(MAX_ENROL_PER_CORRECTION, capacity)).slice(0, capacity)', 'Math.min(MAX_ENROL_PER_CORRECTION, capacity))'], ROUTE_T),
|
|
54
54
|
m('selection-ignores-mac-cap', A, ['Math.min(MAX_ENROL_PER_CORRECTION, capacity)).slice(0, capacity)', 'MAX_ENROL_PER_CORRECTION)'], ROUTE_T),
|
|
55
55
|
// ── Which audio ──
|
|
56
|
-
m('mixed-chunk-used-whole', A, [
|
|
57
|
-
m('other-voices-turns-sliced', A, ['
|
|
56
|
+
m('mixed-chunk-used-whole', A, ["if (turns.length === 0 || turns.every(t => t.speaker === voice)) return 'whole'", "if (true) return 'whole'"], ROUTE_T),
|
|
57
|
+
m('other-voices-turns-sliced', A, ['.filter(t => t.speaker === voice\n', '.filter(t => true\n'], ROUTE_T),
|
|
58
58
|
m('slice-min-ignored', A, ['>= MAC_ASSIGN_MIN_SLICE_SEC)', '>= 0)'], ROUTE_T),
|
|
59
59
|
m('slice-min-off-by-one', A, ['export const MAC_ASSIGN_MIN_SLICE_SEC = 3.0', 'export const MAC_ASSIGN_MIN_SLICE_SEC = 2.0'], ROUTE_T),
|
|
60
60
|
m('slice-inset-removed', A, ['export const MAC_ASSIGN_SLICE_INSET_SEC = 0.15', 'export const MAC_ASSIGN_SLICE_INSET_SEC = 0'], ROUTE_T),
|
|
61
|
-
m('slice-start-inset-removed', A, ['
|
|
61
|
+
m('slice-start-inset-removed', A, ['({ startSec: (t.startSec as number) + MAC_ASSIGN_SLICE_INSET_SEC,', '({ startSec: (t.startSec as number),'], ROUTE_T),
|
|
62
62
|
m('slice-end-inset-removed', A, ['endSec: (t.endSec as number) - MAC_ASSIGN_SLICE_INSET_SEC }', 'endSec: (t.endSec as number) }'], ROUTE_T),
|
|
63
63
|
m('final-segments-ignored', A, ['const list = Array.isArray(final) && final.length > 0 ? final : Array.isArray(live) ? live : []', 'const list = Array.isArray(live) ? live : []'], ROUTE_T),
|
|
64
64
|
m('short-chunk-not-skipped', A, [' if (sec < VOICEPRINT_MIN_AUDIO_SEC) { report.shortSkipped += 1; continue }\n', ''], ROUTE_T),
|
|
65
|
-
m('unit-cap-ignored', A, ['const picked =
|
|
65
|
+
m('unit-cap-ignored', A, ['const picked = spreadMacVoiceUnits(units, MAC_ASSIGN_MAX_UNITS)', 'const picked = units'], ROUTE_T),
|
|
66
66
|
m('spread-takes-the-first', A, ['out.push(items[Math.floor((k * items.length) / max)])', 'out.push(items[k])'], ROUTE_T),
|
|
67
67
|
m('missing-audio-not-counted', A, [' if (!path) { report.missingAudio += 1; continue }\n', ' if (!path) continue\n'], [...LIB_T, ...ROUTE_T]),
|
|
68
68
|
m('audio-gone-reads-as-unusable', A, ["report.skipped = units.length === 0 ? 'no_usable_audio' : 'audio_not_retained'", "report.skipped = 'no_usable_audio'"], [...LIB_T, ...ROUTE_T]),
|
|
69
|
-
m('wrong-sample-rate-accepted', A, ['
|
|
69
|
+
m('wrong-sample-rate-accepted', A, [' if (!pcm || pcm.sampleRate !== SAMPLE_RATE) return null\n', ' if (!pcm) return null\n'], ROUTE_T),
|
|
70
70
|
// ── The same gates a glasses rename uses ──
|
|
71
71
|
m('coherence-gate-skipped', A, ['greedyDiversitySelect(cluster.members.map(m => embeddings[m]), Math.min(', 'greedyDiversitySelect(embeddings, Math.min('], ROUTE_T),
|
|
72
72
|
m('coherence-skips-not-reported', A, ['report.clusterSkipped = embeddings.length - cluster.members.length', 'report.clusterSkipped = 0'], ROUTE_T),
|
package/shared/live-cues-v2.ts
CHANGED
|
@@ -26,8 +26,39 @@ export function legacyCueKind(kind: CueKind): 'reinforce' | 'challenge' {
|
|
|
26
26
|
return kind === 'reinforce' || kind === 'decision' || kind === 'promise' ? 'reinforce' : 'challenge'
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
/**
|
|
30
|
-
|
|
29
|
+
/** Live cues v3: general cues carry one kind of their own, `insight` (a short public fact with its source). It is separate from
|
|
30
|
+
* CUE_KINDS on purpose: CUE_KINDS decides what a meeting may receive and what health advertises, and the three arrays above
|
|
31
|
+
* and legacyCueKind do not know it. Only an extended (Mac) meeting ever gets one; a legacy meeting never does, and an insight
|
|
32
|
+
* never has a v1 `coaching_nudge` twin. */
|
|
33
|
+
export const GENERAL_CUE_KINDS = ['insight'] as const
|
|
34
|
+
export type GeneralCueKind = typeof GENERAL_CUE_KINDS[number]
|
|
35
|
+
/** Any kind a cue row (the log, a verdict, an extended meeting's stream) may carry. */
|
|
36
|
+
export function isLogCueKind(value: unknown): value is CueKind | GeneralCueKind {
|
|
37
|
+
return isCueKind(value) || (typeof value === 'string' && (GENERAL_CUE_KINDS as readonly string[]).includes(value))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** What a cue source is: a past meeting, a COS memory, a file attached to this meeting, or a public web page. */
|
|
41
|
+
export const CUE_SOURCE_KINDS = ['meeting', 'memory', 'file', 'web'] as const
|
|
42
|
+
export type CueSourceKind = typeof CUE_SOURCE_KINDS[number]
|
|
43
|
+
/** A past meeting the cue drew on (0 to 2 per cue). Live cues v3 adds an optional kind and at most ONE locator matching it:
|
|
44
|
+
* meeting `recordId` (when known), memory `memoryId`, file `fileId`, web `url` (https only, and required for a web source).
|
|
45
|
+
* Older readers ignore them. */
|
|
46
|
+
export interface CueSourceRef { id: string; date: string; title: string; kind?: CueSourceKind; recordId?: string; memoryId?: string; fileId?: string; url?: string }
|
|
47
|
+
/** The locator field each source kind uses. */
|
|
48
|
+
export const CUE_SOURCE_LOCATOR = { meeting: 'recordId', memory: 'memoryId', file: 'fileId', web: 'url' } as const
|
|
49
|
+
/** Are the optional kind and locator of a source well formed: a known kind, no locator without it, at most one, and it matches
|
|
50
|
+
* the kind. A web url must be https (the server also checks it is a public address before it writes a row). */
|
|
51
|
+
export function isCueSourceExtras(source: CueSourceRef): boolean {
|
|
52
|
+
const locators = (['recordId', 'memoryId', 'fileId', 'url'] as const).filter(k => source[k] !== undefined)
|
|
53
|
+
if (source.kind === undefined) return locators.length === 0
|
|
54
|
+
if (!(CUE_SOURCE_KINDS as readonly string[]).includes(source.kind)) return false
|
|
55
|
+
if (locators.length > 1) return false
|
|
56
|
+
if (source.kind === 'web' && source.url === undefined) return false
|
|
57
|
+
if (locators.length === 1 && locators[0] !== CUE_SOURCE_LOCATOR[source.kind]) return false
|
|
58
|
+
const value = locators.length === 1 ? source[locators[0]] : undefined
|
|
59
|
+
if (value !== undefined && (typeof value !== 'string' || value.length === 0 || value.length > 2048)) return false
|
|
60
|
+
return source.url === undefined || source.url.startsWith('https://')
|
|
61
|
+
}
|
|
31
62
|
|
|
32
63
|
/** SSE named event `coaching_nudge_v2` (emitted BEFORE its v1 `coaching_nudge` twin), and the rows of GET /api/live-cues/status?sessionId=. */
|
|
33
64
|
export interface LiveCueV2 {
|
|
@@ -38,7 +69,8 @@ export interface LiveCueV2 {
|
|
|
38
69
|
headline: string
|
|
39
70
|
/** <= 220 chars: the full cue, shown on tap and in the phone Cues sheet. */
|
|
40
71
|
detail: string
|
|
41
|
-
|
|
72
|
+
/** An extended (Mac) meeting may also receive `insight` (live cues v3); a legacy meeting never does. */
|
|
73
|
+
kind: CueKind | GeneralCueKind
|
|
42
74
|
sources: CueSourceRef[]
|
|
43
75
|
/** Admission probability from the gate, 0 to 1. */
|
|
44
76
|
gate: number
|
|
@@ -91,8 +123,9 @@ export function isLiveCueV2(value: unknown): value is LiveCueV2 {
|
|
|
91
123
|
return v.protocol === 2 && typeof v.cueId === 'string' && v.cueId.length > 0 && typeof v.sessionId === 'string'
|
|
92
124
|
&& typeof v.headline === 'string' && v.headline.length > 0 && v.headline.length <= CUE_HEADLINE_MAX
|
|
93
125
|
&& typeof v.detail === 'string' && v.detail.length > 0 && v.detail.length <= CUE_DETAIL_MAX
|
|
94
|
-
&&
|
|
126
|
+
&& isLogCueKind(v.kind)
|
|
95
127
|
&& Array.isArray(v.sources) && v.sources.length <= 2
|
|
96
|
-
&& v.sources.every(s => !!s && typeof (s as CueSourceRef).id === 'string' && typeof (s as CueSourceRef).date === 'string' && typeof (s as CueSourceRef).title === 'string'
|
|
128
|
+
&& v.sources.every(s => !!s && typeof (s as CueSourceRef).id === 'string' && typeof (s as CueSourceRef).date === 'string' && typeof (s as CueSourceRef).title === 'string'
|
|
129
|
+
&& isCueSourceExtras(s as CueSourceRef))
|
|
97
130
|
&& typeof v.gate === 'number' && typeof v.createdAt === 'number' && typeof v.model === 'string'
|
|
98
131
|
}
|
|
@@ -17,6 +17,7 @@ export type MediaMime =
|
|
|
17
17
|
| 'text/csv'
|
|
18
18
|
| 'application/json'
|
|
19
19
|
| 'application/pdf'
|
|
20
|
+
| 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
20
21
|
| 'video/mp4'
|
|
21
22
|
| 'video/quicktime'
|
|
22
23
|
|
|
@@ -88,6 +89,7 @@ const VALID_KINDS: ReadonlySet<string> = new Set([
|
|
|
88
89
|
const IMAGE_MIMES: ReadonlySet<string> = new Set(['image/jpeg', 'image/png'])
|
|
89
90
|
const DOCUMENT_MIMES: ReadonlySet<string> = new Set([
|
|
90
91
|
'text/plain', 'text/markdown', 'text/csv', 'application/json', 'application/pdf',
|
|
92
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
91
93
|
])
|
|
92
94
|
const VIDEO_MIMES: ReadonlySet<string> = new Set(['video/mp4', 'video/quicktime'])
|
|
93
95
|
const VALID_MIMES: ReadonlySet<string> = new Set([...IMAGE_MIMES, ...DOCUMENT_MIMES, ...VIDEO_MIMES])
|
package/shared/meeting-ask.ts
CHANGED
|
@@ -247,6 +247,17 @@ export interface MeetingAskConfig {
|
|
|
247
247
|
engine?: string;
|
|
248
248
|
};
|
|
249
249
|
capabilities: MeetingAskCapabilities;
|
|
250
|
+
/** 6.97.8, additive: today's public web lookups by feature, from the server's daily ledger. Older servers omit it. */
|
|
251
|
+
webToday?: MeetingAskWebToday;
|
|
252
|
+
}
|
|
253
|
+
export interface MeetingAskWebToday {
|
|
254
|
+
day: string;
|
|
255
|
+
/** False when the ledger file could not be read: the counts are then zero and do not describe today. */
|
|
256
|
+
readable: boolean;
|
|
257
|
+
cues: { searches: number; pagesRead: number; pagesFailed: number };
|
|
258
|
+
ask: { searches: number; pagesRead: number; pagesFailed: number };
|
|
259
|
+
factCheck: { searches: number; pagesRead: number; pagesFailed: number };
|
|
260
|
+
withheld: { total: number; byReason: Record<string, number>; byFeature: { cues: number; ask: number; factCheck: number } };
|
|
250
261
|
}
|
|
251
262
|
/** All paths under /api/meeting-ask. GET config; PUT config {engine,model} and/or {cosSearch} (6.71.1); either part may come alone.
|
|
252
263
|
* POST requests MeetingAskSubmit -> 202 {exchange}; GET requests/:requestId -> {exchange}.
|