create-pmos 0.123.0 → 0.125.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/package.json +1 -1
- package/payload/KIT-VERSION +2 -2
- package/payload/planning/evals/eval-calibration.md +1 -1
- package/payload/planning/okrs/health-budgets.md +1 -1
- package/payload/scripts/nine-stages.js +81 -0
- package/payload/scripts/workflow-state.js +2 -0
- package/payload/state/discoveries.md +1 -1
- package/payload/state/log.md +1 -1
- package/workspace/c3-one-home-test.js +131 -0
- package/workspace/fixtures/initiatives-api/list.json +171 -3
- package/workspace/fixtures/initiatives-api/roadmap.json +228 -4
- package/workspace/fixtures/initiatives-api/sheet.json +57 -1
- package/workspace/fixtures/one-home-baseline.json +83 -0
- package/workspace/guide/layout.md +2 -0
- package/workspace/guide/notes.md +1 -0
- package/workspace/lib/engine/nine-stages.js +81 -0
- package/workspace/lib/engine/workflow-state.js +2 -0
- package/workspace/lib/facts-async.js +51 -0
- package/workspace/lib/item-steps.js +52 -0
- package/workspace/lib/jira-status.js +8 -3
- package/workspace/lib/jobs-to-be-done.js +52 -0
- package/workspace/lib/outbox-store.js +87 -0
- package/workspace/lib/pm-items.js +115 -0
- package/workspace/lib/route-modules.js +21 -0
- package/workspace/lib/routes-briefing.js +100 -0
- package/workspace/lib/routes-c3-init.js +53 -0
- package/workspace/lib/routes-c3-life.js +119 -0
- package/workspace/lib/routes-c3-strategy.js +169 -0
- package/workspace/lib/routes-c3-timeline.js +191 -0
- package/workspace/lib/routes-calendar-import.js +60 -0
- package/workspace/lib/routes-calendar-views.js +61 -0
- package/workspace/lib/routes-doc-health.js +79 -0
- package/workspace/lib/routes-doc-sheet.js +169 -0
- package/workspace/lib/routes-forecast.js +85 -0
- package/workspace/lib/routes-hooks.js +121 -0
- package/workspace/lib/routes-initiatives.js +3 -0
- package/workspace/lib/routes-intake.js +24 -0
- package/workspace/lib/routes-outbox.js +97 -0
- package/workspace/lib/routes-pm-items.js +216 -0
- package/workspace/lib/routes-records.js +61 -0
- package/workspace/lib/routes-releases.js +129 -0
- package/workspace/lib/routes-report-facts.js +84 -0
- package/workspace/lib/routes-report-families.js +32 -0
- package/workspace/lib/routes-roadmap-ops.js +141 -0
- package/workspace/lib/routes-runs.js +119 -0
- package/workspace/lib/routes-signals.js +50 -0
- package/workspace/lib/run-answers.js +69 -0
- package/workspace/package-lock.json +2 -2
- package/workspace/package.json +1 -1
- package/workspace/public/c3.html +26 -0
- package/workspace/public/pm/briefing-deck.js +415 -0
- package/workspace/public/pm/briefing-model.js +176 -0
- package/workspace/public/pm/c3-breakdown.js +240 -0
- package/workspace/public/pm/c3-brief.js +278 -0
- package/workspace/public/pm/c3-cal-strategy.js +528 -0
- package/workspace/public/pm/c3-case.js +173 -0
- package/workspace/public/pm/c3-demo-brief-ix.js +350 -0
- package/workspace/public/pm/c3-demo-cal-ix.js +74 -0
- package/workspace/public/pm/c3-demo-cal2.js +66 -0
- package/workspace/public/pm/c3-demo-cal3.js +173 -0
- package/workspace/public/pm/c3-demo-data.js +560 -0
- package/workspace/public/pm/c3-demo-init.js +373 -0
- package/workspace/public/pm/c3-demo-life.js +77 -0
- package/workspace/public/pm/c3-demo-misc2.js +46 -0
- package/workspace/public/pm/c3-demo-plan2.js +30 -0
- package/workspace/public/pm/c3-demo-rep-ix.js +126 -0
- package/workspace/public/pm/c3-demo-rep2.js +92 -0
- package/workspace/public/pm/c3-demo-term.js +153 -0
- package/workspace/public/pm/c3-demo-time.js +49 -0
- package/workspace/public/pm/c3-demo-work-ix.js +80 -0
- package/workspace/public/pm/c3-demo-work2.js +13 -0
- package/workspace/public/pm/c3-demo.js +113 -0
- package/workspace/public/pm/c3-doc-sheet.js +314 -0
- package/workspace/public/pm/c3-dock.js +180 -0
- package/workspace/public/pm/c3-docs.js +290 -0
- package/workspace/public/pm/c3-expand.js +96 -0
- package/workspace/public/pm/c3-init-extras.js +170 -0
- package/workspace/public/pm/c3-lifecycle-panels.js +476 -0
- package/workspace/public/pm/c3-misc-panels.js +89 -0
- package/workspace/public/pm/c3-plan-panels.js +163 -0
- package/workspace/public/pm/c3-plan.js +192 -0
- package/workspace/public/pm/c3-roadmap.js +249 -0
- package/workspace/public/pm/c3-sheet.js +107 -0
- package/workspace/public/pm/c3-shell.js +637 -0
- package/workspace/public/pm/c3-signals.js +196 -0
- package/workspace/public/pm/c3-strategy-panels.js +45 -0
- package/workspace/public/pm/c3-swipe.js +138 -0
- package/workspace/public/pm/c3-terminal-data.js +26 -0
- package/workspace/public/pm/c3-terminal-edge.js +91 -0
- package/workspace/public/pm/c3-terminal-icons.js +41 -0
- package/workspace/public/pm/c3-terminal-results.js +141 -0
- package/workspace/public/pm/c3-terminal.js +52 -0
- package/workspace/public/pm/c3-tickets.js +163 -0
- package/workspace/public/pm/c3-timeline.js +201 -0
- package/workspace/public/pm/c3-toast.js +16 -0
- package/workspace/public/pm/calendar-views.js +1015 -0
- package/workspace/public/pm/console3-lift.md +220 -0
- package/workspace/public/pm/console3.css +1480 -0
- package/workspace/public/pm/dest-initiatives.js +16 -3
- package/workspace/public/pm/dest-mywork.js +8 -1
- package/workspace/public/pm/dest-notes.js +25 -3
- package/workspace/public/pm/dest-reports.js +47 -1
- package/workspace/public/pm/dest-today.js +55 -1
- package/workspace/public/pm/doc-health-panel.js +110 -0
- package/workspace/public/pm/doc-rail.js +9 -3
- package/workspace/public/pm/lifecycle-lens-model.js +228 -0
- package/workspace/public/pm/lifecycle-lens.js +261 -0
- package/workspace/public/pm/new-initiative-sheet.js +116 -21
- package/workspace/public/pm/outbox-panel.js +125 -0
- package/workspace/public/pm/pm-work-view.js +919 -0
- package/workspace/public/pm/releases-view.js +248 -0
- package/workspace/public/pm/report-families-view.js +503 -0
- package/workspace/public/pm/run-card.js +244 -0
- package/workspace/public/pm/sessions-panel.js +149 -0
- package/workspace/public/pm/shell-bell.js +162 -0
- package/workspace/public/pm/shell-model.js +83 -0
- package/workspace/public/pm/shell-phone.js +124 -0
- package/workspace/public/pm/shell-readaloud.js +53 -0
- package/workspace/public/pm/shell-recording.js +110 -0
- package/workspace/public/pm/shell-ticker.js +90 -0
- package/workspace/public/pm/slide-confirm.js +163 -0
- package/workspace/public/pm/timeline-forecast-view.js +164 -0
- package/workspace/public/pm/today-day.js +8 -2
- package/workspace/public/pm/tokens.css +1 -0
- package/workspace/server.js +5 -2
- package/workspace/test-files.json +8 -0
- package/workspace/test-lists/browser-suites-green.json +5 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/* pm/c3-demo-plan2.js — demo fixtures of the commitments panels, the Why it slips and Dependencies cards, and the Releases of the Deliver stage
|
|
2
|
+
* (/c3.html?demo=1). It sets window.__c3planfx; c3-plan-panels.js, timeline-forecast-view.js and releases-view.js read it in demo only.
|
|
3
|
+
* The values are the mockup's (console3.html: commits 2704, C3.REL and C3.JV 4833, Why it slips 3849, Dependencies 3851), in the shapes the real code reads:
|
|
4
|
+
* rows the row shape of c3-plan-panels.js (dates as YYYY-MM-DD)
|
|
5
|
+
* why, deps the output of slipFacts()
|
|
6
|
+
* releases the answer of GET /api/releases, plus the optional `name` and `progress` of a release and the optional `tag_tickets` list (tickets per Jira tag)
|
|
7
|
+
* Real mode never loads this file. */
|
|
8
|
+
const dn = (n) => new Date(Date.UTC(2026, 9, n)).toISOString().slice(0, 10);
|
|
9
|
+
const INIT = (id, n, start, due, fc, pct, st, why) => ({ id, n, kind: 'init', start: dn(start), due: dn(due), fc: dn(fc), pct, st, why, go: id });
|
|
10
|
+
const TASK = (id, n, due, st, why, late) => ({ id, n, kind: 'task', due: dn(due), st, why, late: late || 0 });
|
|
11
|
+
const rows = [
|
|
12
|
+
INIT('checkout', 'Checkout v2', 1, 24, 31, 0.5, 'late', 'Sandbox keys and the a11y slot move the ship date.'), INIT('returns', 'Returns experience', 1, 20, 20, 0.4, 'ok', 'Discovery, interview 3 of 5.'),
|
|
13
|
+
INIT('sso', 'SSO', 1, 14, 14, 0.75, 'risk', 'Three release gates still open.'), INIT('onb', 'Self-serve onboarding', 1, -1, -1, 0.2, 'park', 'No movement in 9 days. Continue or park?'),
|
|
14
|
+
INIT('search', 'Search relevance', 1, 37, 37, 0.38, 'risk', 'EN-418 blocked on platform, no reply since Tue.'),
|
|
15
|
+
TASK('t-keys', 'Sandbox keys from the vendor', 6, 'over', 'Asked Tue. No reply in 2 days. Blocks 24 Oct.', 2), TASK('t-num', '1 Oct numbers to Priya', 8, 'ok', 'Priya asked at 07:58. Due 10:30.'),
|
|
16
|
+
TASK('t-wk', 'Weekly status to leadership', 9, 'risk', 'The draft waits for the 14:00 decision.'), TASK('t-sso', 'SSO date to Marta', 12, 'ok', "Promised after Monday's freeze."),
|
|
17
|
+
TASK('t-int5', 'Interview 5: review the stop rule', 13, 'ok', 'Decides whether returns discovery continues.'), TASK('t-a11y', 'A11y audit slot', 21, 'risk', 'No slot before 28 Oct unless scope is cut.'),
|
|
18
|
+
TASK('t-prd', 'PRD v5 sent to Dara', 7, 'done', 'Sent Wed.'), TASK('t-ssob', 'SSO beta live', 6, 'done', '3 customers, 0 incidents.'), TASK('t-srch', 'Search fix merged', 6, 'done', 'p95 420 to 300 ms.'),
|
|
19
|
+
];
|
|
20
|
+
const why = { head: 'Checkout v2, 7 days', rows: [['Scope: extra flows', 4 / 7, 'var(--destructive)', '4 d'], ['Vendor keys', 2 / 7, 'var(--warning)', '2 d'], ['A11y slot', 1 / 7, 'var(--warning)', '1 d']], note: 'Scope, not capacity: the team is not short of people.' };
|
|
21
|
+
const deps = [{ cls: 'bad', text: 'Checkout v2 and SSO billing both wait on the vendor keys.' }, { cls: 'warn', text: 'Search ranking waits on platform review.' }];
|
|
22
|
+
const releases = { ok: true, board: { name: 'Checkout board' }, releases: [
|
|
23
|
+
{ id: 'rel-sso-beta', name: 'SSO beta', type: 'both', initiative_ids: ['sso'], deploy_at: '2026-10-01T11:00:00', release_at: '2026-10-01T12:00:00', accepted_at: '2026-10-01T12:30:00', tags: { detected: ['sso-26.09.0-beta'], reason: null }, gapFlags: [], summary: [], progress: { done: 1, total: 1 } },
|
|
24
|
+
{ id: 'rel-checkout-beta', name: 'Checkout beta', type: 'both', initiative_ids: ['checkout'], deploy_at: '2026-10-14T11:00:00', release_at: '2026-10-14T12:00:00', accepted_at: null, tags: { detected: ['checkout-26.10.0-beta'], reason: null }, gapFlags: [], summary: [], progress: { done: 2, total: 2 } },
|
|
25
|
+
{ id: 'rel-sso-ga', name: 'SSO general release', type: 'both', initiative_ids: ['sso'], deploy_at: '2026-10-14T10:00:00', release_at: '2026-10-14T11:00:00', accepted_at: null, tags: { detected: ['sso-26.10.0'], reason: null }, gapFlags: [], summary: [], progress: { done: 0, total: 2 } },
|
|
26
|
+
], tag_tickets: [
|
|
27
|
+
{ tag: 'checkout-26.10.0-beta', done: 2, total: 2, date: '14 Oct' }, { tag: 'checkout-26.10.0', done: 0, total: 6, date: '24 Oct' }, { tag: 'sso-26.09.0-beta', done: 1, total: 1, date: '1 Oct' },
|
|
28
|
+
{ tag: 'sso-26.10.0', done: 0, total: 2, date: '14 Oct' }, { tag: 'search-26.11.0', done: 0, total: 2, date: '6 Nov' }],
|
|
29
|
+
rules: { freeze: 'Friday 15:00 to Monday 09:00', tag: '-YY.MM.patch' } };
|
|
30
|
+
window.__c3planfx = { rows, why, deps, releases };
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/* pm/c3-demo-rep-ix.js — DEMO fixtures for the Reports tab's interactions (/c3.html?demo=1 only).
|
|
2
|
+
* c3-demo.js loads this file as a side effect (`import './c3-demo-rep-ix.js'`). It only sets window.__c3repix, a plain data object
|
|
3
|
+
* that report-families-view.js reads when window.__c3demo is set. It has no network call and writes nothing. Real mode never loads it.
|
|
4
|
+
* Content is the console3 mockup's own (console3.html lines 4205 to 4347): the four families, their report lists and audience pills, the
|
|
5
|
+
* sections of each report with their sources, the communications queue, the who-holds-what rows and the "Sent" history.
|
|
6
|
+
* Shape of a section: { id, h, t, src: [[icon, label, kind]], st: 'ok' | 'stale' | 'check', by: 'Agent' | 'You', why, claims?: [{ text, label, source }] }. */
|
|
7
|
+
|
|
8
|
+
const SC = (id, h, t, src, st, by, why, claims) => ({ id, h, t, src: src || [], st: st || 'ok', by: by || 'Agent', why: why || '', claims: claims || null });
|
|
9
|
+
|
|
10
|
+
export const FAMS = {
|
|
11
|
+
project: { n: 'Project', i: 'tree', purpose: 'Will we hit the date, what blocks us, what do you need to decide', aud: 'Sponsors and the delivery team', intent: 'Decide and unblock', cad: 'Weekly and on change' },
|
|
12
|
+
product: { n: 'Product', i: 'target', purpose: 'Is the product moving toward the north star, and what did we learn', aud: 'Executives, board, product council', intent: 'Align and invest', cad: 'Monthly' },
|
|
13
|
+
communications: { n: 'Communications', i: 'out', purpose: 'The right people hear the right thing, in their language, at the right time', aud: 'Stakeholders, customers, sales, support', intent: 'Inform, enable, ask', cad: 'On events' },
|
|
14
|
+
periodic: { n: 'Periodic', i: 'cal', purpose: 'A steady rhythm so nobody is surprised', aud: 'Leadership and the team', intent: 'Inform and reflect', cad: 'Weekly to quarterly' },
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const PILLS = {
|
|
18
|
+
project: [{ id: 'lead', name: 'Leadership' }, { id: 'eng', name: 'Engineering' }, { id: 'cs', name: 'Customer success', external: true }],
|
|
19
|
+
product: [{ id: 'exec', name: 'Executives and board' }, { id: 'council', name: 'Product council' }, { id: 'team', name: 'Team' }],
|
|
20
|
+
communications: [{ id: 'all', name: 'All' }, { id: 'leadership', name: 'Leadership' }, { id: 'customers', name: 'Customers', external: true }, { id: 'sales', name: 'Sales and support' }, { id: 'engineering', name: 'Engineering' }],
|
|
21
|
+
periodic: [{ id: 'pe1', name: 'Weekly leadership' }, { id: 'pe2', name: 'Monthly business' }, { id: 'pe3', name: 'Quarterly board' }, { id: 'pe4', name: 'Team retro' }],
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const REPORTS = {
|
|
25
|
+
project: [{ id: 'pj1', n: 'Checkout v2 status', i: 'checkout', due: 'Fri 9 Oct, 15:00' }, { id: 'pj2', n: 'SSO beta status', i: 'sso', due: 'Fri 9 Oct, 15:00' }, { id: 'pj3', n: 'Search relevance status', i: 'search', due: 'Fri 9 Oct, 15:00' }],
|
|
26
|
+
product: [{ id: 'pd1', n: 'Product review, October', due: 'Mon 2 Nov' }, { id: 'pd2', n: 'Quarterly strategy review, Q4', due: 'Mon 7 Dec' }],
|
|
27
|
+
periodic: [{ id: 'pe1', n: 'Weekly leadership digest', due: 'Fri 9 Oct, 15:00', cad: 'Every Friday', aud: 'Leadership', pct: 0.8 }, { id: 'pe2', n: 'Monthly business review', due: 'Mon 2 Nov', cad: 'First Monday', aud: 'Leadership and finance', pct: 0.2 },
|
|
28
|
+
{ id: 'pe3', n: 'Quarterly board update', due: 'Mon 7 Dec', cad: 'Each quarter', aud: 'Board', pct: 0.05 }, { id: 'pe4', n: 'Team retro', due: 'Fri 16 Oct', cad: 'Every second Friday', aud: 'The team', pct: 0.5 }],
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const HIST = {
|
|
32
|
+
project: [['Fri 2 Oct', 'Checkout v2 status', 'Leadership', 'opened by 5 of 6', 'Said: ship 24 Oct, on track'], ['Fri 2 Oct', 'SSO beta status', 'Customer success', 'opened by 3 of 3', '']],
|
|
33
|
+
product: [['Mon 5 Oct', 'Product review, September', 'Executives', 'opened by 4 of 4', '2 questions: conversion, returns']],
|
|
34
|
+
periodic: [['Fri 2 Oct', 'Weekly leadership digest', 'Leadership', 'opened by 5 of 6', 'No questions'], ['Fri 25 Sep', 'Weekly leadership digest', 'Leadership', 'opened by 6 of 6', '1 question: SSO date']],
|
|
35
|
+
communications: [['Tue 6 Oct', 'SSO beta announcement', 'Design partners', 'opened by 3 of 3', 'Reply: asked for SCIM'], ['Mon 5 Oct', 'Interview invites', 'Customers', 'sent 5', '3 slots confirmed']],
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const projectSecs = (r, aud) => {
|
|
39
|
+
if (r.i === 'checkout') {
|
|
40
|
+
if (aud === 'lead') return [
|
|
41
|
+
SC('a', 'Bottom line', 'Checkout v2 will ship 31 Oct, 7 days after the promised 24 Oct, unless scope is cut to 3 flows today.', [['cal', 'Timeline, 8 Oct check', 'time']], 'ok', 'Agent', 'Leads with the answer, not the history.',
|
|
42
|
+
[{ text: 'Forecast 31 Oct against the 24 Oct promised', label: 'fact', source: 'Timeline, 8 Oct check' }]),
|
|
43
|
+
SC('b', 'Status against the promise', 'Red. Promised 24 Oct, forecast 31 Oct. The cause is scope, not capacity: 33 points became 46 in three additions.', [['tree', 'Breakdown history', 'wbs'], ['alert', 'Scope signal', 'sig']], 'ok', 'Agent', 'Watermelon guard: shows the red underneath any green metric.',
|
|
44
|
+
[{ text: 'Scope grew from 33 to 46 points in three additions', label: 'fact', source: 'Breakdown history' }, { text: 'The cause is scope, not capacity', label: 'fact', source: 'Scope signal' }]),
|
|
45
|
+
SC('c', 'What changed since last report', 'The a11y audit slot moved from 23 to 28 Oct. Saved-card removal and the audit were added by the agent after review gates and accepted by you.', [['clock', 'Revision history', 'wbs']], 'ok', 'Agent', 'Leaders ask what moved. This answers it first.'),
|
|
46
|
+
SC('d', 'Top risks', 'Vendor sandbox keys are 2 days late with no reply. The audit vendor has no slot before 28 Oct.', [['check', 'Tickets', 'tix']], 'ok', 'Agent', ''),
|
|
47
|
+
SC('e', 'Decision we need', 'Cut to 3 flows, which holds 24 Oct and is recommended, or accept 31 Oct. Needed by 14:00 today.', [['scale', 'Briefing decision', 'brief']], 'check', 'You', 'One ask only. Reports with many asks get no answer.',
|
|
48
|
+
[{ text: 'Cutting to 3 flows holds 24 Oct', label: 'estimate', source: 'Dara, 3 to 6 days' }]),
|
|
49
|
+
SC('f', 'Confidence', 'Medium, 78%. The vendor may deliver the keys sooner. If they do not reply by Friday the date moves again.', [], 'check', 'Agent', 'Stated as a number so it can be held to account.',
|
|
50
|
+
[{ text: 'Confidence is 78%', label: 'estimate', source: '' }])];
|
|
51
|
+
if (aud === 'eng') return [
|
|
52
|
+
SC('a', 'Bottom line', 'Critical path: keys, saved-card removal, a11y audit, ship. It ends 31 Oct. The audit slot is the binding constraint.', [['tree', 'Timeline', 'time']]),
|
|
53
|
+
SC('b', 'Critical path', 'CHK-141 keys +2 d. CHK-142 saved-card removal +2 d. CHK-144 a11y audit waits for the 28 Oct slot. CHK-145 ship follows.', [['check', 'Tickets', 'tix']]),
|
|
54
|
+
SC('c', 'Blocked or at risk', 'CHK-141 vendor silent since Tuesday. EN-418 platform review is a separate path.', [['check', 'Tickets', 'tix']]),
|
|
55
|
+
SC('d', 'Scope changes', '+5 saved-card removal (25 Sep), +3 a11y audit (30 Sep), +5 address autocomplete (5 Oct).', [['clock', 'Revision history', 'wbs']]),
|
|
56
|
+
SC('e', 'Asks of the team', 'Dara: chase the vendor today. Lee: ask for the 21 Oct audit slot if scope is cut.', [], 'check', 'Agent', 'Names an owner for every ask.')];
|
|
57
|
+
return [
|
|
58
|
+
SC('a', 'What customers can expect', 'The new checkout arrives in late October. The exact date is confirmed after today\'s decision.', [['cal', 'Timeline', 'time']]),
|
|
59
|
+
SC('b', 'What you can say', 'One-page address entry, wallet pay and guest checkout are in. Saved-card removal may follow in the next release.', [['doc', 'PRD v5', 'docs']], 'stale', 'Agent', 'PRD still says 4 flows. Confirm after the decision.'),
|
|
60
|
+
SC('c', 'What not to promise', 'Do not quote 24 Oct. Say late October.', [], 'ok', 'Agent', 'Protects trust: the date is not final.'),
|
|
61
|
+
SC('d', 'Known gaps', 'Accessibility audit is scheduled but not complete.', [['check', 'Tickets', 'tix']])];
|
|
62
|
+
}
|
|
63
|
+
if (r.i === 'sso') return [SC('a', 'Bottom line', 'SSO beta passes with findings at 78%. General release is on 14 Oct.', [['check', 'Rubric scorecard', 'life']]), SC('b', 'Adoption', '3 of 5 design partners live. Adoption is the weakest dimension at 60%.', [['target', 'Evaluation', 'life']], 'check'), SC('c', 'Next', 'Confirm the 14 Oct date to Marta on Monday. Guided setup is the fix for adoption.', [['reply', 'Communications', 'comms']])];
|
|
64
|
+
return [SC('a', 'Bottom line', 'Search relevance beta holds 30 Oct. The index fix is waiting on platform review.', [['tree', 'Timeline', 'time']]), SC('b', 'Blocked', 'EN-418 has been in platform review since Tuesday, 3 days of slip so far.', [['check', 'Tickets', 'tix']], 'check'), SC('c', 'Ask', 'Platform: review EN-418 by Monday so ranking weights can start.', [], 'check', 'Agent', '')];
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const productSecs = (aud) => {
|
|
68
|
+
const base = [
|
|
69
|
+
SC('a', 'North star', 'Weekly active accounts are 12.4k, 4% behind plan and the gap is widening. At this pace the plan tolerance is crossed in January.', [['up', 'North star chart', 'strat']], 'ok', 'Agent', 'Outcome first. Output is not the story.'),
|
|
70
|
+
SC('b', 'Outcomes by goal', 'Conversion 3.1% against 4.0% target (off course). Retention day 30 41.5% against 45% (drifting). Design partners 3 of 5 (on course). Returns discovery 2 of 5.', [['target', 'Goals', 'strat']], 'ok', 'Agent', ''),
|
|
71
|
+
SC('c', 'What we learned', 'Label printing is the main returns pain: 3 of 3 calls. Enterprise wants SCIM before audit logs. Scope churn, not capacity, drives delay.', [['notes', 'Research', 'docs']], 'ok', 'Agent', 'Learning is the product of the month, not just metrics.')];
|
|
72
|
+
if (aud === 'exec') return base.concat([SC('d', 'Bets: scale, iterate or stop', 'Iterate SSO. Park self-serve onboarding: no signal in 9 days. Pull Returns forward only if interview 5 agrees.', [['flag', 'Roadmap', 'roadmap']], 'check', 'Agent', 'Recommendations, each with its evidence.'),
|
|
73
|
+
SC('e', 'Risk to the strategy', 'Conversion has fallen six weeks. Below 3.0% for two weeks triggers a pivot review.', [['alert', 'Signals', 'sig']], 'ok', 'Agent', 'Early warning, before the numbers say it.'), SC('f', 'What we need from you', 'Approve the experiment on the address step and the freeze on scope.', [], 'check', 'You', '')]);
|
|
74
|
+
if (aud === 'council') return base.concat([SC('d', 'Benchmarks', 'Peers with one-page checkout convert at a median 3.4%, top quartile 4.3%. We are at 3.1%. The benchmark is 10 days old.', [['report', 'Benchmark', 'docs']], 'stale', 'Agent', 'Stale source: refresh before this is presented.'),
|
|
75
|
+
SC('e', 'Evaluation', 'SSO beta scored 78% against a 70% threshold. Weakest: adoption 60%.', [['check', 'Scorecard', 'life']]), SC('f', 'Experiments', 'Address-step experiment ready. Needs scope freeze to be a clean test.', [['spark', 'Ideas', 'life']], 'check')]);
|
|
76
|
+
return base.concat([SC('d', 'Wins', 'Search relevance is 28% faster. SSO beta live with 3 customers, 0 incidents.', [['up', 'Calendar', 'cal']]), SC('e', 'Agent quality', 'Human correction rate fell to 15% from 22%. Six runs in a row improved.', [['spark', 'North star for agents', 'life']])]);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const periodicSecs = (id) => {
|
|
80
|
+
if (id === 'pe1') return [SC('a', 'Headline', 'One date at risk: Checkout v2 is forecast 31 Oct against the promised 24 Oct. Everything else is on course.', [['alert', 'Timeline', 'time']], 'ok', 'Agent', 'Same first line every week.'),
|
|
81
|
+
SC('b', 'Since last week', 'Scope +5 points (address autocomplete). Audit slot moved to 28 Oct. SSO beta passed review at 78%. 2 documents went stale.', [['clock', 'Revision history', 'wbs']], 'ok', 'Agent', 'Delta, not a restatement.'),
|
|
82
|
+
SC('c', 'Dates', 'Checkout v2 31 Oct (was 28). SSO 14 Oct (unchanged). Search beta 30 Oct (unchanged).', [['cal', 'Forecast at each check', 'time']]),
|
|
83
|
+
SC('d', 'Decisions made', 'Scope cut to 3 flows pending 14:00. Interview 5 stays on 13 Oct.', [['scale', 'Decisions', 'brief']], 'check', 'You', 'Decision stays blank until it is made.'),
|
|
84
|
+
SC('e', 'Next week', 'Interview 5, SSO date to Marta, platform review for EN-418.', [['cal', 'Calendar', 'cal']]), SC('f', 'Asks', 'Leadership: confirm the cut or accept 31 Oct.', [], 'check', 'You')];
|
|
85
|
+
if (id === 'pe2') return [SC('a', 'Headline', 'Month so far: north star 4% behind plan. One bet needs a decision.', [['up', 'North star', 'strat']]), SC('b', 'Outcomes', 'Conversion off course, retention drifting, partners on course.', [['target', 'Goals', 'strat']]),
|
|
86
|
+
SC('c', 'Finance', 'Q4 forecast row 14 says growth 6%, the PRD says 4%. Align before the review.', [['sheet', 'Forecast', 'docs']], 'stale', 'Agent', 'Source conflict found.'), SC('d', 'Delivery', 'Three releases land inside 17 days.', [['cal', 'Timeline', 'time']]), SC('e', 'Asks', 'Approve the growth assumption.', [], 'check', 'You')];
|
|
87
|
+
if (id === 'pe3') return [SC('a', 'Story of the quarter', 'Evidence file started. Draft after the Q4 checkpoint.', []), SC('b', 'North star and goals', 'Pulled live from the strategy view.', [['up', 'Strategy', 'strat']]), SC('c', 'Bets and decisions', 'All decisions of the quarter with who and why.', [['scale', 'Decision log', 'brief']]), SC('d', 'Risks', 'Pulled from signals.', [['alert', 'Signals', 'sig']])];
|
|
88
|
+
return [SC('a', 'What went well', 'SSO beta live without incident. Search is 28% faster.', [['up', 'Wins', 'cal']]), SC('b', 'What did not', 'Scope changed three times in four weeks. The date slipped as a result.', [['alert', 'Signals', 'sig']]), SC('c', 'What we change', 'Freeze scope after the decision. Add a reason to every change.', [['check', 'Process', 'wbs']], 'check', 'You', '')];
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/** The sections of one report. fam: family id; rep: report id; aud: the audience pill id. Communications has none: its list is the queue. */
|
|
92
|
+
export function sections(fam, rep, aud) {
|
|
93
|
+
if (fam === 'project') return projectSecs((REPORTS.project.find((r) => r.id === rep) || REPORTS.project[0]), aud);
|
|
94
|
+
if (fam === 'product') return productSecs(aud);
|
|
95
|
+
if (fam === 'periodic') return periodicSecs(rep);
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export const COMMS = [
|
|
100
|
+
{ id: 'c1', aud: 'leadership', to: 'Priya', role: 'VP Product', ch: 'Slack', t: 'Update the Checkout v2 date', due: 'Today, 10:30', ext: 0, why: 'Priya was told ship 24 Oct on 2 Oct. The forecast is now 31 Oct unless scope is cut.', body: 'Priya, a heads-up before the 10:30 update: Checkout v2 is forecast for 31 Oct against the 24 Oct we told you. The cause is scope, not capacity. I am asking for a cut to 3 flows at 14:00, which holds 24 Oct. I will confirm either way by 15:00.', tone: 'Direct, no hedging', risk: 'She may repeat 24 Oct in the 10:30 meeting if she does not hear this first.' },
|
|
101
|
+
{ id: 'c2', aud: 'engineering', to: 'Dara and Lee', role: 'Engineering, Design', ch: 'Slack', t: 'Scope freeze after the decision', due: 'Today, 14:30', ext: 0, why: 'Scope changed 3 times in 4 weeks. A fourth re-baselines the plan.', body: 'Once the scope decision lands at 14:00, scope is frozen for Checkout v2. New items go to the next release unless they are on the critical path. Reasons are logged for every change.', tone: 'Firm and specific', risk: 'Without it, a fourth change triggers a re-baseline.' },
|
|
102
|
+
{ id: 'c3', aud: 'customers', to: 'Marta, for design partners', role: 'Customer success', ch: 'Email', t: 'SSO date confirmed', due: 'Mon 12 Oct', ext: 1, why: 'You promised Marta the SSO date on Monday after the freeze.', body: 'Marta, SSO general release is on 14 Oct. Guided setup follows in the next release to cut the setup call. Please tell the three design partners on your side.', tone: 'Warm and exact', risk: 'A missed promise costs trust with a customer.' },
|
|
103
|
+
{ id: 'c4', aud: 'customers', to: 'Design partners', role: 'Customers', ch: 'Release note', t: 'SSO beta: what is new and what is next', due: 'Tue 13 Oct', ext: 1, why: 'The beta passed review. Partners asked for SCIM before audit logs.', body: 'The SSO beta is live. You can sign in with your identity provider. SCIM provisioning is next, ahead of audit logs, because you asked for it.', tone: 'Plain, no jargon', risk: 'External: needs your approval. Never sent automatically.' },
|
|
104
|
+
{ id: 'c5', aud: 'sales', to: 'Sales and support', role: 'Sales, support', ch: 'Doc and Slack', t: 'Returns insight: label printing', due: 'Tue 13 Oct', ext: 0, why: '3 of 3 calls name label printing. Sales hears this on calls.', body: 'Customers say printing the return label is the hardest step, and two of three did not know the 30-day window exists. Ask about labels on discovery calls. Do not promise a fix yet.', tone: 'Useful, not promotional', risk: 'Do not promise a fix before interview 5.' },
|
|
105
|
+
{ id: 'c6', aud: 'sales', to: 'Support', role: 'Support', ch: 'Email', t: 'Heads-up: new checkout in late October', due: 'Wed 14 Oct', ext: 0, why: 'Support should know what changes and what to say before tickets arrive.', body: 'A new checkout arrives in late October. Customers will see one-page address entry and wallet pay. Say late October, not a date, until it is confirmed.', tone: 'Calm, practical', risk: 'Quoting 24 Oct would be wrong if the cut is not made.' },
|
|
106
|
+
];
|
|
107
|
+
/* who holds what: [person, role, told, now, days apart] */
|
|
108
|
+
export const TRUTH = [['Priya', 'VP Product', 'Ship 24 Oct, on track', '31 Oct unless the scope is cut', 7], ['Dara', 'Engineering lead', 'Ship 24 Oct', '31 Oct unless the scope is cut', 7], ['Lee', 'Design', 'Copy freeze 9 Oct', 'Copy freeze 9 Oct', 0],
|
|
109
|
+
['Marta', 'Customer success', 'SSO 14 Oct', 'SSO 14 Oct', 0], ['Sam', 'Engineer', 'Nothing recent', 'Platform review pending', 0]];
|
|
110
|
+
export const CHANNELS = [['Slack', 2 / 6, 'var(--acc)', '2'], ['Email', 2 / 6, 'var(--purple)', '2'], ['Release note', 1 / 6, 'var(--success)', '1'], ['Doc and Slack', 1 / 6, 'var(--warning)', '1']];
|
|
111
|
+
export const BENCH = [['Top quartile', 0.86, 'var(--success)', '4.3%'], ['Peer median', 0.68, 'var(--acc)', '3.4%'], ['You', 0.62, 'var(--warning)', '3.1%']];
|
|
112
|
+
export const QUESTIONS = ['Priya: what is the SSO date? (2 Oct)', 'Sam: why did scope change? (25 Sep)'];
|
|
113
|
+
|
|
114
|
+
/** The pills for a family (the mockup's R2A, or the four periodic reports). */
|
|
115
|
+
export const pills = (fam) => PILLS[fam] || [];
|
|
116
|
+
|
|
117
|
+
/** The head line of a family's page (the mockup's r2info). q = { ap, n, fl }; audName; drafts / sent counts for Communications. */
|
|
118
|
+
export function info(fam, rep, audName, q, comms) {
|
|
119
|
+
if (fam === 'project') { const r = REPORTS.project.find((x) => x.id === rep) || REPORTS.project[0]; return { h: r.n + ' for ' + audName + ': ' + q.ap + ' of ' + q.n + ' sections approved', s: FAMS.project.purpose + '.', p: [q.ap, q.n] }; }
|
|
120
|
+
if (fam === 'product') return { h: 'The review leads with the north star, 4% behind plan', s: FAMS.product.purpose + '.', p: [q.ap, q.n] };
|
|
121
|
+
if (fam === 'communications') return { h: comms.drafts + ' messages waiting. Two people hold an old date', s: FAMS.communications.purpose + '.', p: [comms.sent, COMMS.length] };
|
|
122
|
+
const p = REPORTS.periodic.find((x) => x.id === rep) || REPORTS.periodic[0];
|
|
123
|
+
return { h: p.n + ' is ' + Math.round(p.pct * 100) + '% assembled, due ' + p.due, s: FAMS.periodic.purpose + '.', p: [Math.round(p.pct * 10), 10] };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (typeof window !== 'undefined') window.__c3repix = { FAMS, REPORTS, HIST, COMMS, TRUTH, CHANNELS, BENCH, QUESTIONS, pills, sections, info };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/* pm/c3-demo-rep2.js — DEMO answers for a REPORT as a document (/c3.html?demo=1 only; real mode never loads this file).
|
|
2
|
+
* c3-demo.js loads it with a dynamic import and calls installRep2() once, after the other demo wrappers, so this wrapper answers first.
|
|
3
|
+
* A report is a document in the mockup (console3.html r2doc, line 4264): type Report, v1, a draft, "Assembled from live data.", one section per
|
|
4
|
+
* report section ([heading, text]). Its path here is planning/reports/<family>-<report>-<audience>.md; the text and the revisions are made on first
|
|
5
|
+
* read from window.__c3repix (c3-demo-rep-ix.js) and kept in memory for the page's life. Routes answered, in the REAL response shapes of
|
|
6
|
+
* workspace/lib/routes-doc-sheet.js and routes-doc-health.js:
|
|
7
|
+
* GET /api/doc, /api/doc-sheet/revisions, /api/doc-sheet/at
|
|
8
|
+
* POST /api/doc-sheet/edit, /propose, /accept, /api/doc-health/check
|
|
9
|
+
* A path outside planning/reports/ goes on to the earlier demo wrappers untouched. Nothing is saved anywhere. */
|
|
10
|
+
|
|
11
|
+
const PREFIX = 'planning/reports/';
|
|
12
|
+
const DOCS = {}; // path -> { revs: [{ rev, v, by, at, why, text }] }
|
|
13
|
+
const PROPS = {}; // id -> { path, hash, before, after, prompt }
|
|
14
|
+
let seq = 0;
|
|
15
|
+
|
|
16
|
+
const hashOf = (t) => { let h = 5381; for (const c of String(t)) h = ((h * 33) ^ c.charCodeAt(0)) >>> 0; return h.toString(16).padStart(8, '0') + String(t).length.toString(16).padStart(4, '0'); };
|
|
17
|
+
const json = (b) => new Response(JSON.stringify(b), { status: 200, headers: { 'content-type': 'application/json' } });
|
|
18
|
+
const md = (secs) => secs.map(([h, t]) => '## ' + h + '\n' + t + '\n').join('\n');
|
|
19
|
+
const mine = (p) => typeof p === 'string' && p.startsWith(PREFIX) && p.endsWith('.md');
|
|
20
|
+
|
|
21
|
+
/** The sections of the report a path names: [[heading, text]]. null when the path names nothing the fixtures know. */
|
|
22
|
+
function sectionsFor(path) {
|
|
23
|
+
const R = window.__c3repix; if (!R) return null;
|
|
24
|
+
const [fam, rep, aud] = path.slice(PREFIX.length, -3).split('-');
|
|
25
|
+
if (fam === 'communications') { const c = R.COMMS.find((x) => x.id === rep); return c ? [['Message', c.body], ['Why now', c.why], ['Tone and risk', c.tone + '. ' + c.risk]] : null; }
|
|
26
|
+
const secs = R.sections(fam, rep, aud);
|
|
27
|
+
return secs && secs.length ? secs.map((s) => [s.h, s.t]) : null;
|
|
28
|
+
}
|
|
29
|
+
function docOf(path) {
|
|
30
|
+
if (DOCS[path]) return DOCS[path];
|
|
31
|
+
const s = sectionsFor(path); if (!s) return null;
|
|
32
|
+
DOCS[path] = { revs: [{ rev: 1, v: 'v1', by: 'claude-code/session', at: '2026-10-08T08:12:00.000Z', why: 'Assembled from live data.', text: md(s) }] };
|
|
33
|
+
return DOCS[path];
|
|
34
|
+
}
|
|
35
|
+
const push = (path, by, why, text) => { const d = DOCS[path]; const rev = d.revs.length + 1; d.revs.push({ rev, v: 'v' + rev, by, at: '2026-10-08T08:12:00.000Z', why, text }); return rev; };
|
|
36
|
+
|
|
37
|
+
/* the mockup's docHealth for a report that is still a draft: Fresh passes, Complete does not (a draft), Traced passes, and the claims check. */
|
|
38
|
+
function health(path) {
|
|
39
|
+
const R = window.__c3repix; const [fam, rep, aud] = path.slice(PREFIX.length, -3).split('-');
|
|
40
|
+
const stale = fam === 'communications' || !R ? 0 : R.sections(fam, rep, aud).filter((s) => s.st === 'stale').length;
|
|
41
|
+
const C = [{ id: 'fresh', pass: true, reason: 'Updated today' },
|
|
42
|
+
{ id: 'complete', pass: false, reason: 'Draft: weights or sections missing', fix: 'Fill the missing sections' },
|
|
43
|
+
{ id: 'traced', pass: true, reason: 'Linked to the goal and its tickets' }];
|
|
44
|
+
/* the mockup adds one check for a Report (console3.html line 4266): every number traced to a source */
|
|
45
|
+
C.push({ id: 'claims', name: 'Every number traced to a source', pass: !stale, reason: stale ? stale + ' section' + (stale > 1 ? 's rest' : ' rests') + ' on a stale source' : 'All sections traced', ...(stale ? { fix: 'Refresh the stale sources and redraft' } : {}) });
|
|
46
|
+
return { passed: C.filter((c) => c.pass).length, total: C.length, checks: C };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function get(path, q) {
|
|
50
|
+
const p = q.get('path'); if (!mine(p)) return undefined;
|
|
51
|
+
const d = docOf(p);
|
|
52
|
+
if (path === '/api/doc') return d ? new Response(d.revs[d.revs.length - 1].text, { status: 200, headers: { 'content-type': 'text/markdown; charset=utf-8' } }) : new Response('could not read the document', { status: 404 });
|
|
53
|
+
if (!d) return json({ ok: false, error: 'could not read the document' });
|
|
54
|
+
if (path === '/api/doc-sheet/revisions') return json({ ok: true, path: p, revisions: d.revs.map(({ text, ...r }) => ({ ...r, before_hash: '', after_hash: hashOf(text) })) });
|
|
55
|
+
if (path === '/api/doc-sheet/at') { const r = d.revs.find((x) => x.rev === Number(q.get('rev'))); return json(r ? { ok: true, path: p, rev: r.rev, text: r.text } : { ok: false, error: 'no such revision' }); }
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
function post(path, b) {
|
|
59
|
+
if (!mine(b.path)) return undefined;
|
|
60
|
+
const d = docOf(b.path); if (!d) return json({ ok: false, error: 'could not read the document' });
|
|
61
|
+
if (path === '/api/doc-health/check') return json({ ok: true, path: b.path, health: health(b.path) });
|
|
62
|
+
if (path === '/api/doc-sheet/edit') {
|
|
63
|
+
if (typeof b.why !== 'string' || !b.why.trim()) return json({ ok: false, error: 'a why is required: say why the document changes' });
|
|
64
|
+
return json({ ok: true, path: b.path, rev: push(b.path, 'human:wawan', b.why.trim(), b.text), logged: false });
|
|
65
|
+
}
|
|
66
|
+
if (path === '/api/doc-sheet/propose') { const id = 'prop-rep2-' + (++seq); PROPS[id] = { path: b.path, prompt: b.prompt, after: b.after, hash: hashOf(b.after), before: d.revs[d.revs.length - 1].text }; return json({ ok: true, id, state: 'proposed', hash: PROPS[id].hash, diff: [], voided_hash: null }); }
|
|
67
|
+
if (path === '/api/doc-sheet/accept') {
|
|
68
|
+
const p = PROPS[b.id]; if (!p || p.path !== b.path) return json({ ok: false, error: 'no such proposal' });
|
|
69
|
+
if (b.hash !== p.hash) return json({ ok: false, error: 'the hash does not match the proposal the PM saw', reason: 'hash mismatch' });
|
|
70
|
+
if (d.revs[d.revs.length - 1].text !== p.before) return json({ ok: false, error: 'stale: the document changed since this proposal was made', reason: 'stale' });
|
|
71
|
+
return json({ ok: true, path: b.path, rev: push(b.path, 'claude-code/session', p.prompt, p.after) });
|
|
72
|
+
}
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function installRep2() {
|
|
77
|
+
const prev = window.fetch;
|
|
78
|
+
window.fetch = (input, init) => {
|
|
79
|
+
try {
|
|
80
|
+
const raw = typeof input === 'string' ? input : input instanceof URL ? input.href : input && input.url;
|
|
81
|
+
const method = String((init && init.method) || (input && input.method) || 'GET').toUpperCase();
|
|
82
|
+
const u = new URL(raw, location.origin);
|
|
83
|
+
if (u.origin === location.origin && u.pathname.startsWith('/api/doc')) {
|
|
84
|
+
let out;
|
|
85
|
+
if (method === 'GET') out = get(u.pathname, u.searchParams);
|
|
86
|
+
else { let b = {}; try { b = init && init.body ? JSON.parse(init.body) : {}; } catch { b = {}; } out = post(u.pathname, b); }
|
|
87
|
+
if (out) return Promise.resolve(out);
|
|
88
|
+
}
|
|
89
|
+
} catch { /* an unreadable request goes on as it is */ }
|
|
90
|
+
return prev(input, init);
|
|
91
|
+
};
|
|
92
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/* pm/c3-demo-term.js — DEMO fixtures of the agent surfaces (the Terminal page, the dock's sessions, the run cards), from agent-surfaces.html's own sample data.
|
|
2
|
+
* Registered by ONE line in c3-demo.js. Importing this file changes nothing by itself: it only registers makeSource (window.__c3termfx_make), which
|
|
3
|
+
* c3-terminal-data.js uses when the page is in demo mode (window.__c3demo). c3-terminal-edge.js also reads FX in real mode, as labelled example data.
|
|
4
|
+
*
|
|
5
|
+
* The data is in the REAL response shapes, and it was made by the repo's own modules, not drawn: each run is a sequence of reply lines (the mockup's runs)
|
|
6
|
+
* folded by scripts/card-state.js cardFor (-> the cards), grouped by scripts/sessions-list.js groupSessions (-> groups), with scripts/past-timeline.js
|
|
7
|
+
* pastTimeline (-> the Past timelines) and scripts/reply-contract/reply-contract.js (-> the moves, the glossary, planRequest, askFromTool, voiceReply).
|
|
8
|
+
* A script in the session scratchpad ran them and printed this literal; the times are ISO strings relative to the demo's clock (rebase()).
|
|
9
|
+
*
|
|
10
|
+
* Three things here are NOT in the real GET /api/runs answer today, and the UI marks them so (they sit under `demo` or on the card as extras):
|
|
11
|
+
* - `observed` (the CLI's own tool calls): scripts/reply-contract fold keeps vm.observed, scripts/card-state.js cardFor does not copy it;
|
|
12
|
+
* - `card.pause` (the usage-limit resume time) and the plan text of a plan approval: the same, cardFor drops them;
|
|
13
|
+
* - `timeline` (the Past timeline): routes-runs.js serves no run lines.
|
|
14
|
+
* The write side (answer, correct, send) advances an in-memory copy: a press changes the card as a real run would; nothing is saved or sent. */
|
|
15
|
+
const FX = {
|
|
16
|
+
now: 1791447120000,
|
|
17
|
+
groups: {"onCard":[{"id":"sess-101","plan_item":"c1","name":"Checkout v2: cut T7","origin":"manual","cardId":"c1","startedAt":"2026-10-08T08:06:00.000Z","endedAt":null},{"id":"sess-102","plan_item":"c3","name":"Lint fix on search ranking PR 142","origin":"manual","cardId":"c3","startedAt":"2026-10-08T08:06:00.000Z","endedAt":null},{"id":"sess-103","plan_item":"c2","name":"Reply to Dana","origin":"manual","cardId":"c2","startedAt":"2026-10-08T08:04:00.000Z","endedAt":null},{"id":"sess-104","plan_item":"decision","name":"PRD section 4 redraft","origin":"manual","cardId":"decision","startedAt":"2026-10-08T08:08:00.000Z","endedAt":null},{"id":"sess-112","plan_item":"c1b","name":"Slip options for Checkout v2","origin":"manual","cardId":"c1b","startedAt":"2026-10-08T08:07:00.000Z","endedAt":null}],"startedByMe":[{"id":"sess-105","plan_item":null,"name":"Review this week's slips","origin":"manual","cardId":null,"startedAt":"2026-10-08T07:32:00.000Z","endedAt":null}],"past":[{"id":"sess-108","plan_item":null,"name":"Review this week's slips","origin":"manual","cardId":null,"startedAt":"2026-10-08T05:42:00.000Z","endedAt":"2026-10-08T05:52:00.000Z"},{"id":"sess-107","plan_item":"c2","name":"Draft note to Dana","origin":"manual","cardId":"c2","startedAt":"2026-10-07T07:42:00.000Z","endedAt":"2026-10-07T07:57:00.000Z"},{"id":"sess-106","plan_item":"c1","name":"Re-plan Checkout v2","origin":"manual","cardId":"c1","startedAt":"2026-10-06T07:42:00.000Z","endedAt":"2026-10-06T08:02:00.000Z"}],"automatic":[{"id":"sess-109","plan_item":null,"name":"Weekly review draft","origin":"schedule","cardId":null,"startedAt":"2026-10-08T07:56:00.000Z","endedAt":"2026-10-08T07:58:00.000Z"},{"id":"sess-110","plan_item":null,"name":"Rubric check on onboarding","origin":"gate","cardId":null,"startedAt":"2026-10-08T07:10:00.000Z","endedAt":"2026-10-08T07:12:00.000Z"},{"id":"sess-111","plan_item":null,"name":"Search ranking slip","origin":"detector","cardId":null,"startedAt":"2026-10-08T08:11:00.000Z","endedAt":null}],"automaticHidden":true},
|
|
18
|
+
moves: {"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"voice":{"trusted":true,"text":"Why is the margin only one day?","confidence":0.93,"editable":true,"autosend_ms":3000,"warn":null,"local_only":true},"voice2":{"trusted":true,"text":"why is the margin won day","confidence":0.62,"editable":true,"autosend_ms":null,"warn":"low confidence; check the words","local_only":true}},
|
|
19
|
+
glossary: {"T7":"Ticket T7, saved cards. On the critical path.","forecast":"The date the plan predicts from durations and dependencies. An estimate.","promise":"The date told to Dana on 2 Oct (decision D-12)."},
|
|
20
|
+
timeline: {"since":"2026-10-01T08:12:00.000Z","entries":[{"at":"2026-10-08T05:52:00.000Z","run":"sess-108","src":"you","text":"Corrected: wrong scope"},{"at":"2026-10-08T05:47:00.000Z","run":"sess-108","src":"reported","text":"Result: evidence"},{"at":"2026-10-08T05:42:00.000Z","run":"sess-108","src":"observed","text":"Read planning/runs/ (25 views)"},{"at":"2026-10-07T07:57:00.000Z","run":"sess-107","src":"you","text":"Corrected: revise:warmer"},{"at":"2026-10-07T07:52:00.000Z","run":"sess-107","src":"you","text":"Corrected: revise:shorter"},{"at":"2026-10-07T07:46:00.000Z","run":"sess-107","src":"reported","text":"Result: draft"},{"at":"2026-10-07T07:42:00.000Z","run":"sess-107","src":"observed","text":"Read inbox/dana-2026-10-09.eml (quarantined)"},{"at":"2026-10-06T08:02:00.000Z","run":"sess-106","src":"you","text":"Accepted"},{"at":"2026-10-06T07:52:00.000Z","run":"sess-106","src":"reported","text":"Result: card.update"},{"at":"2026-10-06T07:50:00.000Z","run":"sess-106","src":"observed","text":"Bash git push origin initiative/checkout-v2"},{"at":"2026-10-06T07:47:00.000Z","run":"sess-106","src":"you","text":"Answered: T7 only"},{"at":"2026-10-06T07:46:00.000Z","run":"sess-106","src":"reported","text":"Asked: Cut T7 only, or T7 and T8?"},{"at":"2026-10-06T07:44:00.000Z","run":"sess-106","src":"observed","text":"Edit planning/prd/checkout-v2.md"},{"at":"2026-10-06T07:42:00.000Z","run":"sess-106","src":"observed","text":"Read planning/prd/checkout-v2.md"}],"observed":[{"at":"2026-10-08T05:42:00.000Z","run":"sess-108","src":"observed","text":"Read planning/runs/ (25 views)"},{"at":"2026-10-07T07:42:00.000Z","run":"sess-107","src":"observed","text":"Read inbox/dana-2026-10-09.eml (quarantined)"},{"at":"2026-10-06T07:50:00.000Z","run":"sess-106","src":"observed","text":"Bash git push origin initiative/checkout-v2"},{"at":"2026-10-06T07:44:00.000Z","run":"sess-106","src":"observed","text":"Edit planning/prd/checkout-v2.md"},{"at":"2026-10-06T07:42:00.000Z","run":"sess-106","src":"observed","text":"Read planning/prd/checkout-v2.md"}],"reported":[{"at":"2026-10-08T05:47:00.000Z","run":"sess-108","src":"reported","text":"Result: evidence"},{"at":"2026-10-07T07:46:00.000Z","run":"sess-107","src":"reported","text":"Result: draft"},{"at":"2026-10-06T07:52:00.000Z","run":"sess-106","src":"reported","text":"Result: card.update"},{"at":"2026-10-06T07:46:00.000Z","run":"sess-106","src":"reported","text":"Asked: Cut T7 only, or T7 and T8?"}],"you":[{"at":"2026-10-08T05:52:00.000Z","run":"sess-108","src":"you","text":"Corrected: wrong scope"},{"at":"2026-10-07T07:57:00.000Z","run":"sess-107","src":"you","text":"Corrected: revise:warmer"},{"at":"2026-10-07T07:52:00.000Z","run":"sess-107","src":"you","text":"Corrected: revise:shorter"},{"at":"2026-10-06T08:02:00.000Z","run":"sess-106","src":"you","text":"Accepted"},{"at":"2026-10-06T07:47:00.000Z","run":"sess-106","src":"you","text":"Answered: T7 only"}],"resume":[{"run":"sess-106","title":"Re-plan Checkout v2","command":"claude --resume sess-106"},{"run":"sess-107","title":"Draft note to Dana","command":"claude --resume sess-107"},{"run":"sess-108","title":"Review this week's slips","command":"claude --resume sess-108"}]},
|
|
21
|
+
pastMeta: [{"id":"sess-106","title":"Re-plan Checkout v2","when":"Tue 6 Oct","out":"Accepted - PR 131 merged","min":2880},{"id":"sess-107","title":"Draft note to Dana","when":"Wed 7 Oct","out":"Revised twice - not sent","min":1440},{"id":"sess-108","title":"Review this week's slips","when":"Thu 8 Oct","out":"Rejected: wrong scope","min":120}],
|
|
22
|
+
runs: {
|
|
23
|
+
"sess-101": {"card":{"state":"asking","title":"Needs your answer","steps":["Reading the PRD","Running the plan with T7 cut"],"ask":{"id":"a1","q":"Cut T7 only, or T7 and T8?","options":[{"label":"T7 only","rec":true},{"label":"T7 and T8","rec":false}]},"permission":null,"attention":null,"failure":null,"recover":[],"problems":[],"unlabelled":0,"fallbackText":null,"result":null,"claims":[],"blocked":null,"nextMoves":[],"fallback":null,"asked":"a1","permissions":[]},"observed":[{"tool":"Read","what":"planning/prd/checkout-v2.md","at":"2026-10-08T08:06:00.000Z"},{"tool":"Bash","what":"node scripts/plan.js --cut T7","at":"2026-10-08T08:08:00.000Z"},{"tool":"Edit","what":"planning/prd/checkout-v2.md","at":"2026-10-08T08:10:00.000Z"}]},
|
|
24
|
+
"sess-102": {"card":{"state":"working","title":"Working","steps":["Reading the job log","Fixing the import"],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":[],"unlabelled":0,"fallbackText":null,"result":null,"claims":[],"blocked":null,"nextMoves":[],"fallback":null,"asked":null,"permissions":[{"request":"toolu_push_01","tool":"Bash","command":"git push origin initiative/search-rank","cwd":"../pmos-wt/search-rank","at":"2026-10-08T08:11:00.000Z","why":"Push the lint fix to PR 142","remember":"initiative/search-rank"}]},"observed":[{"tool":"Read","what":"logs/lint-3f9c2e1.txt","at":"2026-10-08T08:07:00.000Z"},{"tool":"Edit","what":"src/rank.js","at":"2026-10-08T08:09:00.000Z"},{"tool":"Bash","what":"npm run lint","at":"2026-10-08T08:10:00.000Z"}]},
|
|
25
|
+
"sess-103": {"card":{"state":"done","title":"Result","steps":["Drafting the reply"],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":[],"unlabelled":0,"fallbackText":null,"result":{"type":"draft","to":"dana@partner.example","body":"Hi Dana, thank you. We can hold 14 Nov with a smaller launch: saved cards come later. Can you confirm by Friday?","hash":"fae55d","claims":[{"text":"Dana: \"I need to know by Friday\" (email 9 Oct 10:02)","basis":"reported","source":"import:email-9-oct","range":"","ok":true},{"text":"Reply needed by Fri 10 Oct","basis":"estimate","source":"","range":"one day","ok":true},{"text":"Dana means saved cards when she says smaller","basis":"assumption","source":"","range":"","ok":true}],"can_send":true,"outward":true,"flags":[],"suggest":[{"label":"Shorter and softer","prompt":"Rewrite the draft shorter and softer."}]},"claims":[{"text":"Dana: \"I need to know by Friday\" (email 9 Oct 10:02)","basis":"reported","source":"import:email-9-oct","range":"","ok":true},{"text":"Reply needed by Fri 10 Oct","basis":"estimate","source":"","range":"one day","ok":true},{"text":"Dana means saved cards when she says smaller","basis":"assumption","source":"","range":"","ok":true}],"blocked":null,"nextMoves":[{"verb":"revise","by":"ui","label":"Revise"},{"verb":"reject","by":"ui","label":"Reject"},{"verb":"suggest","by":"agent","label":"Shorter and softer","prompt":"Rewrite the draft shorter and softer."},{"verb":"say","by":"ui","label":"Say…"}],"fallback":null,"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"asked":null,"permissions":[]},"observed":[{"tool":"Read","what":"inbox/dana-2026-10-09.eml (quarantined)","at":"2026-10-08T08:05:00.000Z"},{"tool":"Read","what":"planning/plan/checkout-v2.json","at":"2026-10-08T08:06:00.000Z"}]},
|
|
26
|
+
"sess-104": {"card":{"state":"working","title":"Working","steps":["Reading the 3-flow scope","Rewriting section 4"],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":[],"unlabelled":0,"fallbackText":null,"result":null,"claims":[],"blocked":null,"nextMoves":[],"fallback":null,"asked":null,"permissions":[]},"observed":[{"tool":"Read","what":"planning/prd/checkout-v2.md","at":"2026-10-08T08:09:00.000Z"},{"tool":"Edit","what":"planning/prd/checkout-v2.md","at":"2026-10-08T08:11:00.000Z"}]},
|
|
27
|
+
"sess-112": {"card":{"state":"done","title":"Result","steps":["Running what-if on three options"],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":[],"unlabelled":0,"fallbackText":null,"result":{"type":"options","options":[{"label":"Cut T7","when":"15 Nov","cost":"costs one feature","rec":true},{"label":"Move the promise to 21 Nov","when":"21 Nov","cost":"Dana and Lee told again","rec":false},{"label":"Add a person to T3","when":"18 Nov","cost":"estimate only","rec":false}],"close_call":false,"flags":[],"suggest":[]},"claims":[],"blocked":null,"nextMoves":[{"verb":"accept","by":"ui","label":"Accept"},{"verb":"revise","by":"ui","label":"Revise"},{"verb":"reject","by":"ui","label":"Reject"},{"verb":"define","by":"ui","label":"Define"},{"verb":"say","by":"ui","label":"Say…"}],"fallback":null,"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"asked":null,"permissions":[]},"observed":[{"tool":"Bash","what":"node scripts/plan.js --what-if 3","at":"2026-10-08T08:08:00.000Z"}]},
|
|
28
|
+
"sess-105": {"card":{"state":"quiet","title":"Quiet","steps":["Reading 25 views"],"ask":null,"permission":null,"attention":null,"failure":null,"recover":["open_session","retry"],"problems":[],"unlabelled":0,"fallbackText":null,"result":null,"claims":[],"blocked":null,"nextMoves":[],"fallback":{"tier":3,"shown":"terminal only","checked":false,"canBackClaim":false,"action":"Open the session"},"asked":null,"permissions":[]},"observed":[{"tool":"Read","what":"planning/runs/2026-10-w41.jsonl","at":"2026-10-08T07:34:00.000Z"}]},
|
|
29
|
+
"sess-106": {"card":{"state":"done","title":"Result","steps":[],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":["unknown kind acceptance"],"unlabelled":0,"fallbackText":null,"result":{"type":"card.update","headline":"Promise 14 Nov holds","tag":"Small win","hero":{"t":"tl","p":14,"f":15},"claims":[{"text":"Forecast 15 Nov","basis":"fact","source":"plan run 09:41","range":"","ok":true},{"text":"Margin is 1 day","basis":"estimate","source":"","range":"plus or minus 2","ok":true}],"chip":null,"undo":false,"flags":[],"suggest":[]},"claims":[{"text":"Forecast 15 Nov","basis":"fact","source":"plan run 09:41","range":"","ok":true},{"text":"Margin is 1 day","basis":"estimate","source":"","range":"plus or minus 2","ok":true}],"blocked":null,"nextMoves":[{"verb":"accept","by":"ui","label":"Accept"},{"verb":"revise","by":"ui","label":"Revise"},{"verb":"reject","by":"ui","label":"Reject"},{"verb":"define","by":"ui","label":"Define"},{"verb":"say","by":"ui","label":"Say…"}],"fallback":null,"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"asked":null,"permissions":[]},"observed":[{"tool":"Read","what":"planning/prd/checkout-v2.md","at":"2026-10-06T07:42:00.000Z"},{"tool":"Edit","what":"planning/prd/checkout-v2.md","at":"2026-10-06T07:44:00.000Z"},{"tool":"Bash","what":"git push origin initiative/checkout-v2","at":"2026-10-06T07:50:00.000Z"}]},
|
|
30
|
+
"sess-107": {"card":{"state":"done","title":"Result","steps":[],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":["unknown kind correction","unknown kind correction"],"unlabelled":0,"fallbackText":null,"result":{"type":"draft","to":"dana@partner.example","body":"Hi Dana, confirmed: smaller launch, 14 Nov. Please reply by Friday.","hash":"4650f9","claims":[{"text":"Dana needs an answer by Friday","basis":"reported","source":"import:email","range":"","ok":true},{"text":"Reply by Fri 10 Oct","basis":"estimate","source":"","range":"one day","ok":true},{"text":"Smaller means saved cards only","basis":"assumption","source":"","range":"","ok":true}],"can_send":true,"outward":true,"flags":[],"suggest":[]},"claims":[{"text":"Dana needs an answer by Friday","basis":"reported","source":"import:email","range":"","ok":true},{"text":"Reply by Fri 10 Oct","basis":"estimate","source":"","range":"one day","ok":true},{"text":"Smaller means saved cards only","basis":"assumption","source":"","range":"","ok":true}],"blocked":null,"nextMoves":[{"verb":"revise","by":"ui","label":"Revise"},{"verb":"reject","by":"ui","label":"Reject"},{"verb":"say","by":"ui","label":"Say…"}],"fallback":null,"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"asked":null,"permissions":[]},"observed":[{"tool":"Read","what":"inbox/dana-2026-10-09.eml (quarantined)","at":"2026-10-07T07:42:00.000Z"}]},
|
|
31
|
+
"sess-108": {"card":{"state":"done","title":"Result","steps":[],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":["unknown kind correction"],"unlabelled":0,"fallbackText":null,"result":{"type":"evidence","claims":[{"text":"Checkout v2 slipped 6 days","basis":"fact","source":"plan run 09:12","range":"","ok":true},{"text":"Search ranking slipped 3 days","basis":"fact","source":"plan run 09:12","range":"","ok":true},{"text":"Onboarding is on time","basis":"estimate","source":"","range":"plus or minus 1","ok":true}],"flags":[],"suggest":[]},"claims":[{"text":"Checkout v2 slipped 6 days","basis":"fact","source":"plan run 09:12","range":"","ok":true},{"text":"Search ranking slipped 3 days","basis":"fact","source":"plan run 09:12","range":"","ok":true},{"text":"Onboarding is on time","basis":"estimate","source":"","range":"plus or minus 1","ok":true}],"blocked":null,"nextMoves":[{"verb":"accept","by":"ui","label":"Accept"},{"verb":"revise","by":"ui","label":"Revise"},{"verb":"reject","by":"ui","label":"Reject"},{"verb":"define","by":"ui","label":"Define"},{"verb":"say","by":"ui","label":"Say…"}],"fallback":null,"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"asked":null,"permissions":[]},"observed":[{"tool":"Read","what":"planning/runs/ (25 views)","at":"2026-10-08T05:42:00.000Z"}]},
|
|
32
|
+
"sess-109": {"card":{"state":"done","title":"Result","steps":[],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":[],"unlabelled":0,"fallbackText":null,"result":{"type":"draft","to":"reports","body":"Weekly review draft: three initiatives slipped.","hash":"11c60b","claims":[{"text":"Three initiatives slipped","basis":"fact","source":"plan run 09:12","range":"","ok":true}],"can_send":true,"outward":true,"flags":[],"suggest":[]},"claims":[{"text":"Three initiatives slipped","basis":"fact","source":"plan run 09:12","range":"","ok":true}],"blocked":null,"nextMoves":[{"verb":"revise","by":"ui","label":"Revise"},{"verb":"reject","by":"ui","label":"Reject"},{"verb":"say","by":"ui","label":"Say…"}],"fallback":null,"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"asked":null,"permissions":[]},"observed":[{"tool":"Read","what":"planning/reports/weekly.md","at":"2026-10-08T07:58:00.000Z"}]},
|
|
33
|
+
"sess-110": {"card":{"state":"done","title":"Result","steps":[],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":[],"unlabelled":0,"fallbackText":null,"result":{"type":"note","note":"PR 138 merged","flags":[],"suggest":[]},"claims":[],"blocked":null,"nextMoves":[{"verb":"define","by":"ui","label":"Define"},{"verb":"say","by":"ui","label":"Say…"}],"fallback":null,"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"asked":null,"permissions":[]},"observed":[{"tool":"Bash","what":"node scripts/rubric.js onboarding","at":"2026-10-08T07:12:00.000Z"}]},
|
|
34
|
+
"sess-111": {"card":{"state":"working","title":"Working","steps":["Running what-if on T6"],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":[],"unlabelled":0,"fallbackText":null,"result":null,"claims":[],"blocked":null,"nextMoves":[],"fallback":null,"asked":null,"permissions":[]},"observed":[{"tool":"Read","what":"planning/plan/search-rank.json","at":"2026-10-08T08:11:00.000Z"}]}
|
|
35
|
+
},
|
|
36
|
+
after: {
|
|
37
|
+
"sess-101": {"card":{"state":"done","title":"Result","steps":["Reading the PRD","Running the plan with T7 cut"],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":[],"unlabelled":0,"fallbackText":null,"result":{"type":"card.update","headline":"Promise 14 Nov holds after cutting T7","tag":"Small win","hero":{"t":"tl","p":14,"f":15},"claims":[{"text":"Forecast 15 Nov after the cut","basis":"fact","source":"plan run 09:41","range":"","ok":true},{"text":"Margin is 1 day","basis":"estimate","source":"","range":"plus or minus 2","ok":true},{"text":"PR 143 opened; merges when required CI is green","basis":"fact","source":"gh pr 143","range":"","ok":true}],"chip":"PR 143 - merges when green","undo":false,"flags":[],"suggest":[{"label":"Ask for evidence","prompt":"Show the evidence for the forecast."},{"label":"Make a one-page brief","prompt":"Write a one-page brief of this."}]},"claims":[{"text":"Forecast 15 Nov after the cut","basis":"fact","source":"plan run 09:41","range":"","ok":true},{"text":"Margin is 1 day","basis":"estimate","source":"","range":"plus or minus 2","ok":true},{"text":"PR 143 opened; merges when required CI is green","basis":"fact","source":"gh pr 143","range":"","ok":true}],"blocked":null,"nextMoves":[{"verb":"accept","by":"ui","label":"Accept"},{"verb":"revise","by":"ui","label":"Revise"},{"verb":"reject","by":"ui","label":"Reject"},{"verb":"define","by":"ui","label":"Define"},{"verb":"suggest","by":"agent","label":"Ask for evidence","prompt":"Show the evidence for the forecast."},{"verb":"suggest","by":"agent","label":"Make a one-page brief","prompt":"Write a one-page brief of this."},{"verb":"say","by":"ui","label":"Say…"}],"fallback":null,"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"asked":null,"permissions":[]},"observed":[{"tool":"Read","what":"planning/prd/checkout-v2.md","at":"2026-10-08T08:06:00.000Z"},{"tool":"Bash","what":"node scripts/plan.js --cut T7","at":"2026-10-08T08:08:00.000Z"},{"tool":"Edit","what":"planning/prd/checkout-v2.md","at":"2026-10-08T08:10:00.000Z"},{"tool":"Bash","what":"node scripts/plan.js --cut T7","at":"2026-10-08T08:12:00.000Z"},{"tool":"Bash","what":"gh pr create --title \"Cut T7\"","at":"2026-10-08T08:12:00.000Z"}]},
|
|
38
|
+
"sess-102": {"card":{"state":"done","title":"Result","steps":["Reading the job log","Fixing the import"],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":[],"unlabelled":0,"fallbackText":null,"result":{"type":"card.update","headline":"Lint fixed on the search ranking PR","tag":"Small win","hero":{"t":"ci","p":["ok","ok","run","wait"],"l":"CI running on 5c1d7aa"},"claims":[{"text":"Local lint passes","basis":"fact","source":"npm run lint","range":"","ok":true},{"text":"Pushed 5c1d7aa to initiative/search-rank; merge follows when CI is green","basis":"fact","source":"git push","range":"","ok":true}],"chip":"Merges when green","undo":false,"flags":[],"suggest":[{"label":"Ask for evidence","prompt":"Show the evidence."}]},"claims":[{"text":"Local lint passes","basis":"fact","source":"npm run lint","range":"","ok":true},{"text":"Pushed 5c1d7aa to initiative/search-rank; merge follows when CI is green","basis":"fact","source":"git push","range":"","ok":true}],"blocked":null,"nextMoves":[{"verb":"accept","by":"ui","label":"Accept"},{"verb":"revise","by":"ui","label":"Revise"},{"verb":"reject","by":"ui","label":"Reject"},{"verb":"define","by":"ui","label":"Define"},{"verb":"suggest","by":"agent","label":"Ask for evidence","prompt":"Show the evidence."},{"verb":"say","by":"ui","label":"Say…"}],"fallback":null,"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"asked":null,"permissions":[]},"observed":[{"tool":"Read","what":"logs/lint-3f9c2e1.txt","at":"2026-10-08T08:07:00.000Z"},{"tool":"Edit","what":"src/rank.js","at":"2026-10-08T08:09:00.000Z"},{"tool":"Bash","what":"npm run lint","at":"2026-10-08T08:10:00.000Z"},{"tool":"Bash","what":"git push origin initiative/search-rank","at":"2026-10-08T08:12:00.000Z"}]}
|
|
39
|
+
},
|
|
40
|
+
fail: {
|
|
41
|
+
"noresult": {"card":{"state":"failed","title":"Failed","steps":["Reading the PRD"],"ask":null,"permission":null,"attention":null,"failure":{"code":"no_result","why":"The session ended without a usable result."},"recover":["open_session","retry"],"problems":[],"unlabelled":0,"fallbackText":null,"result":null,"claims":[],"blocked":null,"nextMoves":[],"fallback":{"tier":3,"shown":"terminal only","checked":false,"canBackClaim":false,"action":"Open the session"},"asked":null,"permissions":[]},"observed":[]},
|
|
42
|
+
"rejected": {"card":{"state":"failed","title":"Failed","steps":["Reading the PRD"],"ask":null,"permission":null,"attention":null,"failure":{"code":"no_result","why":"The session ended without a usable result."},"recover":["open_session","retry"],"problems":["result rejected: headline is required"],"unlabelled":0,"fallbackText":null,"result":null,"claims":[],"blocked":null,"nextMoves":[],"fallback":{"tier":3,"shown":"terminal only","checked":false,"canBackClaim":false,"action":"Open the session"},"asked":null,"permissions":[]},"observed":[]},
|
|
43
|
+
"crashed": {"card":{"state":"failed","title":"Failed","steps":["Reading the PRD"],"ask":null,"permission":null,"attention":null,"failure":{"code":"crashed","why":"The session ended with an error."},"recover":["open_session","retry"],"problems":[],"unlabelled":0,"fallbackText":null,"result":null,"claims":[],"blocked":null,"nextMoves":[],"fallback":{"tier":3,"shown":"terminal only","checked":false,"canBackClaim":false,"action":"Open the session"},"asked":null,"permissions":[]},"observed":[]},
|
|
44
|
+
"quiet": {"card":{"state":"quiet","title":"Quiet","steps":["Reading the PRD"],"ask":null,"permission":null,"attention":null,"failure":null,"recover":["open_session","retry"],"problems":[],"unlabelled":0,"fallbackText":null,"result":null,"claims":[],"blocked":null,"nextMoves":[],"fallback":{"tier":3,"shown":"terminal only","checked":false,"canBackClaim":false,"action":"Open the session"},"asked":null,"permissions":[]},"observed":[]},
|
|
45
|
+
"unlabelled": {"card":{"state":"done","title":"Result","steps":[],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":["claim has no valid label"],"unlabelled":1,"fallbackText":null,"result":{"type":"evidence","claims":[{"text":"Forecast 20 Nov","basis":"fact","source":"plan run 09:12","range":"","ok":true},{"text":"Dana agreed on the phone yesterday","basis":null,"source":"","range":"","ok":false}],"flags":["claim has no valid label"],"suggest":[]},"claims":[{"text":"Forecast 20 Nov","basis":"fact","source":"plan run 09:12","range":"","ok":true},{"text":"Dana agreed on the phone yesterday","basis":null,"source":"","range":"","ok":false}],"blocked":null,"nextMoves":[{"verb":"accept","by":"ui","label":"Accept"},{"verb":"revise","by":"ui","label":"Revise"},{"verb":"reject","by":"ui","label":"Reject"},{"verb":"define","by":"ui","label":"Define"},{"verb":"say","by":"ui","label":"Say…"}],"fallback":null,"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"asked":null,"permissions":[]},"observed":[]},
|
|
46
|
+
"prose": {"card":{"state":"degraded","title":"Plain text only","steps":["Reading the PRD"],"ask":null,"permission":null,"attention":null,"failure":null,"recover":["retry_structured","open_session"],"problems":[],"unlabelled":0,"fallbackText":"Here is what I found: the slip is six days, and cutting T7 looks like the best option. The forecast would move to about 15 Nov.","result":null,"claims":[],"blocked":null,"nextMoves":[],"fallback":{"tier":2,"shown":"plain text","checked":false,"canBackClaim":false,"note":"The agent did not use the format, so nothing here is checked."},"asked":null,"permissions":[]},"observed":[]},
|
|
47
|
+
"attention": {"card":{"state":"attention","title":"Needs the terminal","steps":["Reading the PRD"],"ask":null,"permission":null,"attention":{"type":"auth_required","message":"Claude is asking you to sign in."},"failure":null,"recover":["open_session"],"problems":[],"unlabelled":0,"fallbackText":null,"result":null,"claims":[],"blocked":null,"nextMoves":[],"fallback":{"tier":3,"shown":"terminal only","checked":false,"canBackClaim":false,"action":"Open the session"},"asked":null,"permissions":[]},"observed":[]},
|
|
48
|
+
"notstarted": {"card":{"state":"not_started","title":"Not started","steps":[],"ask":null,"permission":null,"attention":null,"failure":null,"recover":["open_session"],"problems":[],"unlabelled":0,"fallbackText":null,"result":null,"claims":[],"blocked":null,"nextMoves":[],"fallback":{"tier":3,"shown":"terminal only","checked":false,"canBackClaim":false,"action":"Open the session"},"asked":null,"permissions":[]},"observed":[]},
|
|
49
|
+
"pause": {"card":{"state":"paused","title":"Paused","steps":["Reading the PRD"],"ask":null,"permission":null,"attention":null,"failure":null,"recover":["wait","open_session"],"problems":[],"unlabelled":0,"fallbackText":null,"result":null,"claims":[],"blocked":null,"nextMoves":[],"fallback":{"tier":3,"shown":"terminal only","checked":false,"canBackClaim":false,"action":"Open the session"},"asked":null,"permissions":[],"pause":{"type":"quota_auto_resume_fired","resume_at":"14:30"}},"observed":[]},
|
|
50
|
+
"api": {"card":{"state":"failed","title":"Failed","steps":["Reading the PRD"],"ask":null,"permission":null,"attention":null,"failure":{"code":"api_error","why":"The turn failed on an API error. Retrying usually works."},"recover":["open_session","retry"],"problems":[],"unlabelled":0,"fallbackText":null,"result":null,"claims":[],"blocked":null,"nextMoves":[],"fallback":{"tier":3,"shown":"terminal only","checked":false,"canBackClaim":false,"action":"Open the session"},"asked":null,"permissions":[]},"observed":[]},
|
|
51
|
+
"format": {"card":{"state":"failed","title":"Failed","steps":[],"ask":null,"permission":null,"attention":null,"failure":{"code":"format","why":"Recorded in a newer format than this workspace reads. Update the workspace, or open the session."},"recover":["open_session","retry"],"problems":["event from a newer format ignored"],"unlabelled":0,"fallbackText":null,"result":null,"claims":[],"blocked":null,"nextMoves":[],"fallback":{"tier":3,"shown":"terminal only","checked":false,"canBackClaim":false,"action":"Open the session"},"asked":null,"permissions":[]},"observed":[]}
|
|
52
|
+
},
|
|
53
|
+
edge: {
|
|
54
|
+
"deck": {"card":{"state":"done","title":"Result","steps":[],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":["1 slide bullet without a label; the deck cannot be shared"],"unlabelled":0,"fallbackText":null,"result":{"type":"deck","slides":[{"title":"Where we are","note":"","bullets":[{"text":"Forecast 20 Nov, promise 14 Nov","basis":"fact","source":"plan run 09:12","range":"","ok":true},{"text":"T7 slipped 4 days on 3 Oct","basis":"fact","source":"ticket ev_41","range":"","ok":true},{"text":"Margin after a cut is 1 day","basis":"estimate","source":"","range":"plus or minus 2","ok":true}]},{"title":"Options","note":"","bullets":[{"text":"Cut T7: forecast 15 Nov","basis":"fact","source":"plan run 09:41","range":"","ok":true},{"text":"Move the promise: 21 Nov","basis":"fact","source":"plan run 09:41","range":"","ok":true},{"text":"Dana accepts a smaller launch","basis":"assumption","source":"","range":"","ok":true}]},{"title":"Ask","note":"","bullets":[{"text":"Approve the cut by Friday","ok":false,"basis":null}]}],"unlabelled":1,"can_share":false,"flags":["1 slide bullet without a label; the deck cannot be shared"],"suggest":[]},"claims":[],"blocked":null,"nextMoves":[{"verb":"define","by":"ui","label":"Define"},{"verb":"say","by":"ui","label":"Say…"}],"fallback":null,"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"asked":null,"permissions":[]},"observed":[]},
|
|
55
|
+
"table": {"card":{"state":"done","title":"Result","steps":[],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":[],"unlabelled":0,"fallbackText":null,"result":{"type":"table","columns":[{"key":"ini","label":"Initiative","type":"text"},{"key":"slip","label":"Slip (days)","type":"number"},{"key":"st","label":"Status","type":"status"},{"key":"own","label":"Owner","type":"text"}],"rows":[["Checkout v2",6,"at risk","Lee"],["Search ranking",3,"at risk","Ana"],["Onboarding",0,"on time","Sam"],["Billing export",2,"delayed","Lee"],["Mobile login",0,"on time","Ana"],["Reports v3",1,"on time","Sam"],["Notifications",5,"overdue","Lee"]],"shown":7,"total":7,"flags":[],"suggest":[]},"claims":[],"blocked":null,"nextMoves":[{"verb":"define","by":"ui","label":"Define"},{"verb":"say","by":"ui","label":"Say…"}],"fallback":null,"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"asked":null,"permissions":[]},"observed":[]},
|
|
56
|
+
"diagram": {"card":{"state":"done","title":"Result","steps":[],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":[],"unlabelled":0,"fallbackText":null,"result":{"type":"diagram","kind":"mermaid","source":"graph LR; T3-->T7; T7-->T9; T3-->T4; T4-->T9","title":"Dependencies: T3 to T7 to T9 is the critical path; T4 has slack","render":"drawn locally, strict mode","flags":[],"suggest":[]},"claims":[],"blocked":null,"nextMoves":[{"verb":"define","by":"ui","label":"Define"},{"verb":"say","by":"ui","label":"Say…"}],"fallback":null,"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"asked":null,"permissions":[]},"observed":[]},
|
|
57
|
+
"file": {"card":{"state":"done","title":"Result","steps":[],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":[],"unlabelled":0,"fallbackText":null,"result":{"type":"file","title":"Quarterly slip report","media":"md","path":"outputs/r12/report.md","sha256":"c91d02","render":"rendered text","flags":[],"suggest":[]},"claims":[],"blocked":null,"nextMoves":[{"verb":"accept","by":"ui","label":"Accept"},{"verb":"revise","by":"ui","label":"Revise"},{"verb":"reject","by":"ui","label":"Reject"},{"verb":"define","by":"ui","label":"Define"},{"verb":"say","by":"ui","label":"Say…"}],"fallback":null,"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"asked":null,"permissions":[]},"observed":[]},
|
|
58
|
+
"fileCard": {"card":{"state":"done","title":"Result","steps":[],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":[],"unlabelled":0,"fallbackText":null,"result":{"type":"file","title":"Checkout v2 slip brief","media":"md","path":"outputs/r12/brief.md","sha256":"a41c9e","render":"rendered text","flags":[],"suggest":[]},"claims":[],"blocked":null,"nextMoves":[{"verb":"accept","by":"ui","label":"Accept"},{"verb":"revise","by":"ui","label":"Revise"},{"verb":"reject","by":"ui","label":"Reject"},{"verb":"define","by":"ui","label":"Define"},{"verb":"say","by":"ui","label":"Say…"}],"fallback":null,"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"asked":null,"permissions":[]},"observed":[]},
|
|
59
|
+
"fileBody": {"outputs/r12/report.md":"## Summary\n- Three initiatives slipped this quarter\n- Checkout v2 is the largest (6 days)\n## Detail\n- See the table in the file","outputs/r12/brief.md":"## Where we are\n- Forecast 20 Nov, promise 14 Nov: 6 days late\n- T7 slipped 4 days on 3 Oct\n## Options\n- **Cut T7**: forecast 15 Nov, costs one feature\n- **Move the promise** to 21 Nov: Dana and Lee told again\n## Assumption\n- Dana accepts a smaller launch (not checked)"},
|
|
60
|
+
"evidence": {"card":{"state":"done","title":"Result","steps":[],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":[],"unlabelled":0,"fallbackText":null,"result":{"type":"evidence","claims":[{"text":"Forecast 20 Nov: critical path T3, T7, T9","basis":"fact","source":"plan run 09:12","range":"","ok":true},{"text":"T7 slipped 4 days on 3 Oct","basis":"fact","source":"ticket event ev_41","range":"","ok":true},{"text":"Cutting T7 returns 5 days","basis":"estimate","source":"","range":"plus or minus 2","ok":true},{"text":"Dana accepts a smaller launch. Not checked.","basis":"assumption","source":"","range":"","ok":true}],"flags":[],"suggest":[]},"claims":[{"text":"Forecast 20 Nov: critical path T3, T7, T9","basis":"fact","source":"plan run 09:12","range":"","ok":true},{"text":"T7 slipped 4 days on 3 Oct","basis":"fact","source":"ticket event ev_41","range":"","ok":true},{"text":"Cutting T7 returns 5 days","basis":"estimate","source":"","range":"plus or minus 2","ok":true},{"text":"Dana accepts a smaller launch. Not checked.","basis":"assumption","source":"","range":"","ok":true}],"blocked":null,"nextMoves":[{"verb":"accept","by":"ui","label":"Accept"},{"verb":"revise","by":"ui","label":"Revise"},{"verb":"reject","by":"ui","label":"Reject"},{"verb":"define","by":"ui","label":"Define"},{"verb":"say","by":"ui","label":"Say…"}],"fallback":null,"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"asked":null,"permissions":[]},"observed":[]},
|
|
61
|
+
"note": {"card":{"state":"done","title":"Result","steps":[],"ask":null,"permission":null,"attention":null,"failure":null,"recover":[],"problems":[],"unlabelled":0,"fallbackText":null,"result":{"type":"note","note":"Nothing to change: the plan already holds the date.","flags":[],"suggest":[]},"claims":[],"blocked":null,"nextMoves":[{"verb":"define","by":"ui","label":"Define"},{"verb":"say","by":"ui","label":"Say…"}],"fallback":null,"revise":["shorter","longer","simpler","firmer","warmer","more evidence"],"reject":["wrong facts","wrong scope","not now","too long"],"asked":null,"permissions":[]},"observed":[]},
|
|
62
|
+
"question": {"kind":"question","questions":[{"id":"tq1","q":"Which database for the report store?","header":"Store","multi":false,"options":[{"label":"Postgres","detail":""},{"label":"SQLite","detail":""},{"label":"Files","detail":""}]},{"id":"tq2","q":"Which exports do you need?","header":"Exports","multi":true,"options":[{"label":"PDF","detail":""},{"label":"CSV","detail":""},{"label":"Slides","detail":""}]}],"truncated":false,"error":null,"onDeny":{"behavior":"deny","message":"waiting for the PM"}},
|
|
63
|
+
"plan": {"plan":"## Plan\n- Read the PRD and the plan run\n- Move **T7** (saved cards) to the next release\n- Update the scope table and open one PR\n## Risk\n- Dana has not accepted a smaller launch","moves":["approve","revise","reject"]},
|
|
64
|
+
"planReplies": {"approve":{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}},"revise":{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"deny","message":"The PM wants the plan revised: Make it shorter."}}},"reject":{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"deny","message":"The PM rejected the plan: wrong scope"}}}}
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/* ── the clock: the fixtures hold ISO times relative to FX.now; the page's frozen clock is the demo's "now" ── */
|
|
69
|
+
function rebase(v) {
|
|
70
|
+
if (Array.isArray(v)) return v.map(rebase);
|
|
71
|
+
if (v && typeof v === 'object') { const o = {}; for (const k of Object.keys(v)) o[k] = rebase(v[k]); return o; }
|
|
72
|
+
if (typeof v === 'string' && /^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$/.test(v)) return new Date(Date.now() - (FX.now - Date.parse(v))).toISOString();
|
|
73
|
+
return v;
|
|
74
|
+
}
|
|
75
|
+
const clone = (v) => JSON.parse(JSON.stringify(v));
|
|
76
|
+
const WORKING = (card, steps) => ({ ...card, state: 'working', title: 'Working', ask: null, permission: null, permissions: [], failure: null, recover: [], result: null, claims: [], nextMoves: [], steps: card.steps.concat(steps || []), problems: [], blocked: null });
|
|
77
|
+
const DENIED = (card) => ({ ...card, state: 'failed', title: 'Failed', permissions: [], permission: null, failure: { code: 'blocked', why: 'Push denied. The fix is committed in the worktree but not pushed. Nothing left the repo.' }, blocked: 'Push denied. The fix is committed in the worktree but not pushed. Nothing left the repo.', recover: ['open_session', 'retry'] });
|
|
78
|
+
const SUGGEST = { 'Ask for evidence': 'evidence', 'Show other options': 'options', 'Make a one-page brief': 'fileCard' };
|
|
79
|
+
|
|
80
|
+
/** The page's demo source: the same four calls the real one has (c3-terminal-data.js), answered from memory. A press advances the state; nothing is sent. */
|
|
81
|
+
export function makeSource() {
|
|
82
|
+
const T = rebase(FX);
|
|
83
|
+
const S = { runs: T.runs, groups: T.groups, corr: 0, acc: 0, next: '', subs: new Set(), seq: 0, vn: 0 };
|
|
84
|
+
const note = () => S.subs.forEach((f) => { try { f(); } catch { /* a subscriber is gone */ } });
|
|
85
|
+
const set = (id, card, observed) => { S.runs[id] = { card: { ...card }, observed: observed || (S.runs[id] && S.runs[id].observed) || [] }; note(); };
|
|
86
|
+
const finish = (id) => {
|
|
87
|
+
const k = S.next; S.next = '';
|
|
88
|
+
if (k && T.fail[k]) set(id, { ...T.fail[k].card, permissions: [] }, S.runs[id].observed);
|
|
89
|
+
else if (T.after[id]) set(id, T.after[id].card, T.after[id].observed);
|
|
90
|
+
else note();
|
|
91
|
+
};
|
|
92
|
+
const stage = (id, steps, fn, ms) => { set(id, WORKING(S.runs[id].card, steps)); setTimeout(fn || (() => finish(id)), ms || 1500); };
|
|
93
|
+
const src = {
|
|
94
|
+
demo: true, canPrompt: true, why: '',
|
|
95
|
+
async getRuns() {
|
|
96
|
+
const cards = {}; const observed = {};
|
|
97
|
+
for (const id of Object.keys(S.runs)) { cards[id] = S.runs[id].card; observed[id] = S.runs[id].observed; }
|
|
98
|
+
return { ok: true, groups: S.groups, cards, demo: { observed, timeline: T.timeline, pastMeta: T.pastMeta, glossary: T.glossary, fileBody: (p) => T.edge.fileBody[p], accepted: S.acc, corrected: S.corr } };
|
|
99
|
+
},
|
|
100
|
+
async answer(b) {
|
|
101
|
+
if (!b || !S.runs[b.run]) return { ok: false, error: 'no such run' };
|
|
102
|
+
if (b.behavior === 'accept') { S.acc += 1; return { ok: true }; }
|
|
103
|
+
if (b.behavior === 'deny') { set(b.run, DENIED(S.runs[b.run].card)); return { ok: true }; }
|
|
104
|
+
if (b.behavior === 'allow') { stage(b.run, ['Pushing the branch']); return { ok: true }; }
|
|
105
|
+
if (b.behavior === 'answer') { stage(b.run, ['Re-planning', 'Opening PR 143']); return { ok: true }; }
|
|
106
|
+
return { ok: false, error: 'behavior must be allow, deny, accept or answer' };
|
|
107
|
+
},
|
|
108
|
+
async correct(b) { if (!b || !S.runs[b.run]) return { ok: false, error: 'no such run' }; S.corr += 1; return { ok: true }; },
|
|
109
|
+
async send(id, m) {
|
|
110
|
+
if (!S.runs[id]) return { ok: false, error: 'no such run' };
|
|
111
|
+
if (m.verb === 'free') return { ok: true, say: { basis: 'estimate', text: 'The margin is 1 day because T9 starts the day T3 ends (plan run 09:41). Estimate, plus or minus 2.' } };
|
|
112
|
+
const cur = S.runs[id].card;
|
|
113
|
+
if (m.verb === 'suggest') {
|
|
114
|
+
const key = SUGGEST[m.label];
|
|
115
|
+
const to = key === 'evidence' ? T.edge.evidence : key === 'options' ? T.runs['sess-112'] : key === 'fileCard' ? T.edge.fileCard : null;
|
|
116
|
+
stage(id, [m.label], () => { const k = S.next; S.next = ''; if (k && T.fail[k]) set(id, { ...T.fail[k].card }); else if (to) set(id, { ...to.card }); else set(id, cur); }, 1500);
|
|
117
|
+
return { ok: true };
|
|
118
|
+
}
|
|
119
|
+
if (m.verb === 'revise') {
|
|
120
|
+
stage(id, ['Revising'], () => {
|
|
121
|
+
const c = clone(cur); const r = c.result;
|
|
122
|
+
if (r && r.body) r.body = m.arg === 'shorter' ? 'Hi Dana, confirmed: smaller launch, 14 Nov. Please reply by Friday.' : m.arg === 'warmer' ? 'Hi Dana, thank you for the quick reply. We can keep 14 Nov with a smaller launch and bring saved cards after. Could you confirm by Friday?' : r.body + ' (' + m.arg + ')';
|
|
123
|
+
else if (r && r.claims && m.arg === 'more evidence') { r.claims.push({ text: 'Source added', basis: 'fact', source: 'plan run 09:12 and ticket event ev_41', ok: true }); c.claims = r.claims; }
|
|
124
|
+
S.next = ''; set(id, c);
|
|
125
|
+
}, 1300);
|
|
126
|
+
return { ok: true };
|
|
127
|
+
}
|
|
128
|
+
if (m.verb === 'retry') { stage(id, ['Trying again']); return { ok: true }; }
|
|
129
|
+
return { ok: false, error: 'unknown verb' };
|
|
130
|
+
},
|
|
131
|
+
voice() { return S.vn++ % 2 === 0 ? T.moves.voice : T.moves.voice2; },
|
|
132
|
+
subscribe(f) { S.subs.add(f); return () => S.subs.delete(f); },
|
|
133
|
+
/* the mockup's two demo controls: how the next reply ends, and a detector firing */
|
|
134
|
+
setNext(k) { S.next = k || ''; },
|
|
135
|
+
fire() {
|
|
136
|
+
const id = 'sess-12' + (++S.seq); const t = new Date().toISOString();
|
|
137
|
+
S.groups = { ...S.groups, automatic: [{ id, plan_item: null, name: 'Search ranking slip', origin: 'detector', cardId: null, startedAt: t, endedAt: null }, ...S.groups.automatic] };
|
|
138
|
+
S.runs[id] = { card: WORKING({ ...clone(T.after['sess-101'].card), steps: [] }, ['Running what-if on T6']), observed: [{ tool: 'Bash', what: 'node scripts/plan.js --what-if T6', at: t }] };
|
|
139
|
+
note();
|
|
140
|
+
setTimeout(() => {
|
|
141
|
+
const cid = 'sess-13' + S.seq; const base = clone(T.after['sess-101'].card);
|
|
142
|
+
base.result = { ...base.result, headline: 'Search ranking slipped 3 days after T4', tag: 'Just in', hero: { t: 'tl', p: 20, f: 23 }, chip: null, claims: [{ text: 'Forecast 23 Nov', basis: 'fact', source: 'plan run 10:05', ok: true }, { text: 'Running T6 in parallel returns 2 days', basis: 'estimate', range: 'plus or minus 1', ok: true }] }; base.claims = base.result.claims;
|
|
143
|
+
S.groups = { ...S.groups, automatic: S.groups.automatic.map((s) => (s.id === id ? { ...s, endedAt: new Date().toISOString() } : s)), onCard: [{ id: cid, plan_item: 'new', name: 'Search ranking slipped 3 days', origin: 'manual', cardId: 'new', startedAt: t, endedAt: null }, ...S.groups.onCard] };
|
|
144
|
+
S.runs[id] = { card: { ...T.runs['sess-110'].card }, observed: [] }; S.runs[cid] = { card: base, observed: [] };
|
|
145
|
+
note();
|
|
146
|
+
}, 1500);
|
|
147
|
+
},
|
|
148
|
+
get counts() { return { accepted: S.acc, corrected: S.corr }; },
|
|
149
|
+
};
|
|
150
|
+
return src;
|
|
151
|
+
}
|
|
152
|
+
export { FX };
|
|
153
|
+
if (typeof window !== 'undefined') window.__c3termfx_make = makeSource;
|