feat(stereoscope): Slack bot for the Stereoscope Coffee workspace - #77
feat(stereoscope): Slack bot for the Stereoscope Coffee workspace#77isaacsight wants to merge 3 commits into
Conversation
Delivers the integration James checkmarked in the 2026-07-14 DM out of the 11-item menu: one post every Monday — how all 6 shops did last week plus the one thing to fix. - tools/stereoscope/brief.ts: deterministic Monday-brief composer. Per-shop sales with week-over-week deltas, average ticket, labor as a percent of sales; ranked findings (labor over target weighted 1.5, sales decline 1.0 with a 2% floor, ticket drift 0.8 with a 3% floor) select the one thing to fix; manager notes pass through to the Watch list. No LLM in the loop — every number is arithmetic over the week file, so the post is trustworthy and testable. - tools/stereoscope/brief.test.ts: 14 tests, all passing (vitest). - tools/stereoscope/post-brief.ts: CLI, dry-run by default, --post sends via chat.postMessage. - tools/stereoscope/bot.ts: Socket Mode presence, same architecture as tools/slack-bot.ts (per-thread history, Claude via claude-proxy per .claude/rules/backend.md). Personality never invents policy, recipes, prices, or numbers; wage/sales/personnel questions route to managers and the private ops channel. - sample-week.json: 6-shop fixture with invented numbers, marked as such; 4 shop names confirmed from their Slack, 2 placeholders to edit. - Env vars are deliberately separate from the kernel workspace tokens (STEREOSCOPE_SLACK_BOT_TOKEN / _APP_TOKEN / STEREOSCOPE_BRIEF_CHANNEL) so a misconfigured shell can never cross-post between workspaces. Verified: npx tsc --noEmit clean; scoped strict tsc over the four new files clean; 14/14 tests pass; dry run renders the promised post shape. Co-Authored-By: Claude <noreply@anthropic.com>
CI's 'Web — Type-check & Build' job runs the root vitest suite, which globs tools/ableton/gen-coverage.test.mjs; vite cannot bundle the node:test builtin under the jsdom config, so suite collection failed (1 failed suite, 847/847 tests otherwise passing — first surfaced on this PR because the introducing commit 776fec1 never had a CI run on main). The test bodies are plain test() + node:assert, so the fix is the runner import alone: vitest's test instead of node:test. All nine tests now execute and pass; full root suite is 58/58 files, 856/856 tests. Co-Authored-By: Claude <noreply@anthropic.com>
|
CI note: the Fix ported into this PR as 2ffc07c: the test bodies are plain Generated by Claude Code |
The app shell locks body scroll (position: fixed, overflow: hidden in src/index.css); every scrolling page opts out by adding ka-scrollable-page in a mount effect — except ArchivePage. With the body locked, window.scrollY stays 0, so THE STACKS' scroll-driven camera never descends and every volume below the first viewport is unreachable by scroll, for readers and for Playwright alike. The e2e spec 'the ledger lands on the real issue route' (targeting N°427) passed only while 427 was the newest issue and sat in the first viewport; ISSUE 429 (7ea6abe, pushed to main without a CI run) added a volume above it and exposed the defect on this PR's CI: Playwright scrolls the link into view, the locked body undoes it, and the click retries until timeout on both Desktop Chrome and Mobile Safari. Fix is the same one-effect pattern the other twelve scrolling pages use. Verified: the failing spec reproduced locally on the previous head, all 6 stacks e2e tests now pass on Desktop Chrome, the full Desktop Chrome e2e run shows no new failures (the two remaining local failures — issue-415 zero-console-errors and mobile tab bar — reproduce identically without this change and stem from the missing local Supabase env that CI injects), tsc clean, 856/856 vitest. Co-Authored-By: Claude <noreply@anthropic.com>
|
Second inherited CI failure, also fixed: the Fix pushed as 57b799f — the same one-effect opt-out the other twelve scrolling pages use. Verified locally: the failure reproduced on the prior head, all 6 stacks specs now pass on Desktop Chrome, no new failures in the full Desktop Chrome e2e run, tsc clean, 856/856 vitest. It no-ops if the same fix lands on main first. Generated by Claude Code |
What
Slack bot for the Stereoscope Coffee workspace, in two pieces under
tools/stereoscope/:brief.ts+post-brief.ts) — one post every Monday into a private ops channel: per-shop sales with week-over-week deltas, average ticket, labor as a percent of sales, then a single ranked "one thing to fix" and a short watch list.npm run stereoscope:briefdry-runs against the bundled 6-shop sample;--postsends viachat.postMessage.bot.ts) — Socket Mode bot, same architecture astools/slack-bot.ts: per-thread history, Claude via the Supabase claude-proxy, answers DMs and mentions, threads replies in channels.npm run stereoscope:bot.Why
Delivers the integration Stereoscope's ops lead checkmarked in the 2026-07-14 Slack DM, out of the 11-item menu pitched there: "every monday, one post in this slack — how all 6 shops did last week + the one thing to fix," with a sample to drop in the DM. The dry-run output is that sample.
How
WeekDataJSON file (the intended feed is Zapier/cron producing that file from the POS export). No LLM in the loop, so the post is trustworthy and unit-testable. Findings are ranked in percentage points off plan, weighted by how directly the miss costs money: labor over target 1.5, sales decline 1.0 (2% floor), ticket drift 0.8 (3% floor); the top finding becomes "the one thing to fix," the rest plus manager notes become the Watch list. Missing metrics (no prior week, no labor tracking) render without their segment instead of erroring..claude/rules/backend.md(all Claude calls throughsupabase/functions/claude-proxy/), and its personality is scoped hard: never invents policy, recipes, prices, or numbers; routes wage/sales/personnel questions to managers and the private ops channel.STEREOSCOPE_SLACK_BOT_TOKEN/STEREOSCOPE_SLACK_APP_TOKEN/STEREOSCOPE_BRIEF_CHANNEL) so a misconfigured shell can never cross-post between workspaces. No tokens or secrets committed; Slack app setup steps are in the README.sample-week.jsoncarries invented numbers marked as such; four shop names are real, two are named placeholders to edit before demoing.Testing
npm run buildpasses (tscportion; new files are tools-side and covered by the scoped strict check below)npm run test—npx vitest run tools/stereoscope/brief.test.ts: 14/14 passnpx tsc --noEmitpasses (plus a scopedtsc --strictover the four new files)kbotin dev mode — n/a, this is atools/bot, not a kbot change; verified via the CLI dry run insteadScreenshots
Dry-run output (
npm run stereoscope:brief):🤖 Generated with Claude Code
Generated by Claude Code