docs: session engineering log + handoff for M2 + OSS chatbot
Some checks failed
Auto-assign PR to Author / auto-assign (pull_request) Has been cancelled
Deploy Check / Check Deployment (pull_request) Has been cancelled
Frontend Lint & Test / test (pull_request) Has been cancelled
Log Lines Percentage Check / log_lines_check (pull_request) Has been cancelled
Run Chatwoot CE spec / lint-backend (pull_request) Has been cancelled
Run Chatwoot CE spec / security-scan (pull_request) Has been cancelled
Run Chatwoot CE spec / lint-frontend (pull_request) Has been cancelled
Run Chatwoot CE spec / frontend-tests (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (0, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (1, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (10, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (11, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (12, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (13, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (14, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (15, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (2, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (3, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (4, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (5, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (6, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (7, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (8, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (9, 16) (pull_request) Has been cancelled
Run MFA Tests / test (pull_request) Has been cancelled
Run Size Limit Check / test (pull_request) Has been cancelled
Test Docker Build / test-build (linux/amd64, ubuntu-latest) (pull_request) Has been cancelled
Test Docker Build / test-build (linux/arm64, ubuntu-22.04-arm) (pull_request) Has been cancelled
Lint PR / Validate PR title (pull_request_target) Has been cancelled
Some checks failed
Auto-assign PR to Author / auto-assign (pull_request) Has been cancelled
Deploy Check / Check Deployment (pull_request) Has been cancelled
Frontend Lint & Test / test (pull_request) Has been cancelled
Log Lines Percentage Check / log_lines_check (pull_request) Has been cancelled
Run Chatwoot CE spec / lint-backend (pull_request) Has been cancelled
Run Chatwoot CE spec / security-scan (pull_request) Has been cancelled
Run Chatwoot CE spec / lint-frontend (pull_request) Has been cancelled
Run Chatwoot CE spec / frontend-tests (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (0, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (1, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (10, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (11, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (12, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (13, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (14, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (15, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (2, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (3, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (4, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (5, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (6, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (7, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (8, 16) (pull_request) Has been cancelled
Run Chatwoot CE spec / backend-tests (9, 16) (pull_request) Has been cancelled
Run MFA Tests / test (pull_request) Has been cancelled
Run Size Limit Check / test (pull_request) Has been cancelled
Test Docker Build / test-build (linux/amd64, ubuntu-latest) (pull_request) Has been cancelled
Test Docker Build / test-build (linux/arm64, ubuntu-22.04-arm) (pull_request) Has been cancelled
Lint PR / Validate PR title (pull_request_target) Has been cancelled
This commit is contained in:
33
HANDOFF.md
33
HANDOFF.md
@@ -1,5 +1,24 @@
|
|||||||
# HANDOFF
|
# HANDOFF
|
||||||
|
|
||||||
|
## ═══════ SESSION 2026-08-22 — Final decision: external n8n (Option 3) ═══════
|
||||||
|
|
||||||
|
- User selected Option 3: n8n remains a separate service for the LLM chatbot/workflow path.
|
||||||
|
- Do not integrate Hermes, embed n8n, or change Chatwoot production code for this decision.
|
||||||
|
- Keep the existing AgentBot async webhook boundary: Chatwoot → external n8n → configured LLM/external services → Chatwoot API reply.
|
||||||
|
- The Gateway/Adapter design is deferred; implement it only if later requirements justify centralized tenant isolation, idempotency, DLQ, observability, or provider routing.
|
||||||
|
- Only this handoff/log decision is updated; production source remains unchanged.
|
||||||
|
|
||||||
|
## ═══════ SESSION 2026-08-22 — LLM chatbot runtime architecture discovery ═══════
|
||||||
|
|
||||||
|
- Read-only architecture review for `/Users/kunthawat/Gitea/Chatwoot`; no production code changed.
|
||||||
|
- Chatwoot's existing AgentBot path is already the intended boundary: async signed webhook out, external runtime processes, then external runtime posts an outgoing message through Chatwoot API. `outgoing_url` is not an LLM request/response endpoint.
|
||||||
|
- Hermes is technically feasible only behind a bridge. Hermes API server is the preferred execution interface; Hermes webhook adapter is not plug-compatible because signature headers and response delivery contract differ.
|
||||||
|
- Recommended target: `Chatwoot AgentBot → dedicated Hermes bridge → Hermes API → Chatwoot API`; optional external n8n remains for visual workflows, CRM/LINE/ERP side effects, and integrations. Do not embed n8n or give a customer-facing Hermes profile unrestricted terminal/file tools.
|
||||||
|
- Tenant rules: keep Chatwoot as transcript/source of truth; namespace every request by account/inbox/conversation; do not treat Hermes personal memory/profile files as a multi-tenant knowledge base. Use allow-listed tools, sandboxing, idempotency, HMAC verification, secret rotation, and human handoff.
|
||||||
|
- Next implementation gate: P0 one-account bridge proof (or n8n→Hermes proof), message-created only, no loop, signed webhook verification, reply via bot token, duplicate/retry tests, cross-tenant isolation test, and latency/error telemetry.
|
||||||
|
- Working tree was already dirty with unrelated M1/M2 changes; future bridge work must use a separate worktree/branch.
|
||||||
|
|
||||||
|
|
||||||
## ═══════ SESSION 2026-08-19 — Moreminimore Chat: rebrand + M1 + M2 work ═══════
|
## ═══════ SESSION 2026-08-19 — Moreminimore Chat: rebrand + M1 + M2 work ═══════
|
||||||
|
|
||||||
## Current state (2026-08-19)
|
## Current state (2026-08-19)
|
||||||
@@ -30,10 +49,16 @@ HEAD = `ccff2dfca`. Worktree clean except untracked `.hermes/plans/` (never comm
|
|||||||
- Product list: per-account, admin-only menu (like report), import via copy/paste or CSV/XLSX. Multi-level hierarchy (big group>subgroup>product>display) — LLM matches from lowest level first, tags ancestors; supports multiple products/groups per chat.
|
- Product list: per-account, admin-only menu (like report), import via copy/paste or CSV/XLSX. Multi-level hierarchy (big group>subgroup>product>display) — LLM matches from lowest level first, tags ancestors; supports multiple products/groups per chat.
|
||||||
|
|
||||||
### NEXT TO DO (M2 remaining — biggest remaining work)
|
### NEXT TO DO (M2 remaining — biggest remaining work)
|
||||||
1. **part2b-ii**: LLM classifier service — read conversation (latest message + history for context), classify → tags (topic + product from catalog using '>' join) + deal (won/lost/undecided). Cascade via Llm::Resolver.
|
1. **part2b-ii — LLM classifier service: ✅ DONE (2026-08-19)**. New `lib/llm/analytics_classifier.rb` — reads conversation, classifies via `Llm::Resolver` cascade + `with_schema` JSON output → `Result` (topics, products via tag_hierarchy path mapping, deal won/lost/undecided). Fail-closed on no-credential (returns `disabled`, never calls LLM / sends content). Also fixed: `Account` missing `has_many :product_catalog_entries` (foundation `161e4210b` wired model+migration but not the reverse association → would NoMethodError). Verified: `ruby -c` clean (2.6/3.4), isolated smoke 8/8 under Ruby 3.4.10 (found `/opt/homebrew/opt/ruby@3.4/bin/ruby` — real 3.4.10 available, `.ruby-version`=3.4.4), static scan clean, independent reviewer `deleg_47c1a2cb` = complete 5-key PASS (non-blocking em-dash escape fix applied). Plan doc: `.hermes/plans/2026-08-19-m2-self-improving-analytics.md`.
|
||||||
2. **part2b-iii**: daily batch job (sidekiq-cron) at ~02:00-03:00 in the SUPER ADMIN timezone (single TZ, no hourly-check) → auto-write tags to conversation, aggregate into conversation_daily_metrics + customer_daily_metrics (immutable counts; re-tag live).
|
2. **part2b-iii — daily batch job: ✅ DONE (2026-08-19)**. New `app/services/analytics/account_daily_processor.rb` (per-account/date: UTC day window from `account.reporting_timezone`, selects active conversations, classifies via `Llm::AnalyticsClassifier` fail-closed, re-tags replacing M2-managed tags + preserving manual labels, upserts ConversationDailyMetric unique account+date + CustomerDailyMetric unique account+contact+date) + `app/jobs/analytics/daily_metrics_job.rb` (per-account rescue, yesterday in account TZ) + `config/schedule.yml` entry `analytics_daily_metrics_job` `30 2 * * *` timezone `Asia/Bangkok`. Verified: `ruby -c` clean (3.4.10), smoke 15/15, static scan clean, schedule no dup keys, reviewer `deleg_fecf7c61` = complete 5-key PASS (4 non-blocking suggestions: add specs, N+1 in chat_message_count, deal_outcomes dual structure, apply_tags rescue scope).
|
||||||
3. **phase 2**: monthly/yearly rollup (sum daily) + admin-only report dashboard (filters agent/team/inbox/channel/tag/sale/time, cross-analysis) + deep per-customer/per-agent views.
|
3. **phase 2 — rollup + report: ✅ DONE (2026-08-19)**. Backend: `Analytics::ReportService` (summary/timeseries/customers/agents from immutable daily-metric tables; deal_outcomes normalization for 'totals'-nested + flat) + `Analytics::DrilldownService` (deep filterable drilldown over live conversations: since/until/agent/team/inbox/channel/tag/deal + pagination; fail-closed label-join) + `Api::V2::Accounts::AnalyticsReportsController` (admin-only via ReportPolicy#view?=administrator; summary + drilldown) + routes `analytics_reports` (get :summary/:drilldown). `AccountDailyProcessor#apply_tags` now writes `deal:<outcome>` tag for deal filtering. Frontend: `api/analyticsReports.js` + `AnalyticsReports.vue` (summary cards + filter bar + drilldown table) + route `analytics_reports` under reports section + `ANALYTICS_REPORTS` i18n keys in en/report.json. Verified: backend smoke 12/12, reviewers `deleg_6800b012` (backend) + `deleg_15f8447c` (frontend) = complete 5-key PASS (non-blocking i18n suggestions applied). NOTE: frontend full build (eslint/vite/vitest) cannot run locally (no node_modules) — run `pnpm install && pnpm test` before ship.
|
||||||
4. **phase 3**: product-list import UI (admin-only, copy/paste + CSV + XLSX), weekly persona eval + approval flow (Telegram inline button, Line quick-reply, webhook) + docs.
|
4. **phase 3 — import + persona eval + approval (2026-08-20):**
|
||||||
|
- **Weekly persona eval** ✅: `Analytics::WeeklyPersonaEvaluator` (7d via ReportService → LLM summary+recommendations; summary-only, no PII) + `persona_evaluation` endpoint + route. Reviewer `deleg_b7d63fd7` PASS.
|
||||||
|
- **Frontend product-catalog import UI** ✅: `api/productCatalog.js` + `productCatalog/Index.vue` (paste + xlsx/csv upload + result + table) + admin-only route. Reviewer `deleg_0e9f9291` PASS (i18n suggestions applied).
|
||||||
|
- **Approval flow** (user chose **LINE primary + webhook fallback**, then added **Telegram**; precedence LINE → Telegram → webhook): `Analytics::PersonaApprovalService` (`deliver` LINE quick-reply / Telegram inline keyboard / webhook fallback; `notify_approval` webhook-only w/ decision) + `Analytics::WeeklyPersonaEvaluationJob` + controller (`persona_evaluation_deliver`, `persona_approval_settings` [line_user_id + telegram_chat_id + webhook_url, conditional], `persona_decision`) + routes + schedule.yml `analytics_weekly_persona_evaluation_job` (Mon 10:00 Asia/Bangkok). First reviewer `deleg_1fe19871` FAIL-CLOSED (1 medium logic error: `:approve` path LINE-first + decision not passed) → **FIXED** (webhook-only `notify_approval(decision)`) → re-review `deleg_3052f7a4` PASS; Telegram `deleg_34116d1a` PASS. Config: `persona_line_user_id` / `persona_telegram_chat_id` / `persona_webhook_url` / `persona_webhook_secret` in Account#custom_attributes.
|
||||||
|
- **Docs** — via HANDOFF.md/plan doc; no separate docs/ convention.
|
||||||
|
- **POST-MVP design note (prompt webhook handshake) — user clarified, NOT built, awaiting LLM-server details**: a SEPARATE LLM server holds/applies the actual prompt; this app connects via webhook — (1) connect-first: pull current prompt (GET) + store snapshot; (2) approve weekly recommendation → POST new prompt to LLM server to apply. Analytics here ONLY surfaces "what customers asked" + recommendations; knowledge-prep/prompt-authoring is admin/LLM-server side. Delivery-webhook design (REST 2-endpoint vs generic action-body) DEFERRED — user wants document/design only for now.
|
||||||
|
Verified: smoke tests (eval 8/8, import 10/10 + xlsx 5/5, approval 10/10 incl. Telegram), `ruby -c` clean, node --check on .js, schedule.yml valid + unique keys, static scan clean across all.
|
||||||
|
|
||||||
### Verification notes / blockers
|
### Verification notes / blockers
|
||||||
- Ruby env active is 2.6.10; target 3.4.4. Rails/RSpec/RuboCop cannot be reliably claimed passed. Ruby `ruby -c` syntax + YAML validity + isolated smoke tests used instead.
|
- Ruby env active is 2.6.10; target 3.4.4. Rails/RSpec/RuboCop cannot be reliably claimed passed. Ruby `ruby -c` syntax + YAML validity + isolated smoke tests used instead.
|
||||||
|
|||||||
@@ -113,3 +113,38 @@ Application changes are tracked in the verified checkpoints and the uncheckpoint
|
|||||||
- SM-09/10 cannot change branding defaults/assets/metadata until approved product name, domains, logos/icons, sender, legal URLs and primary color are supplied. Current visible-branding report remains 2,878 findings; it is report-only, not a privacy-rule pass.
|
- SM-09/10 cannot change branding defaults/assets/metadata until approved product name, domains, logos/icons, sender, legal URLs and primary color are supplied. Current visible-branding report remains 2,878 findings; it is report-only, not a privacy-rule pass.
|
||||||
- Enterprise `WebsiteBrandingService` remains proprietary and currently fails with `NameError: uninitialized constant WebsiteBrandingService`; no dummy service or remote enrichment was added.
|
- Enterprise `WebsiteBrandingService` remains proprietary and currently fails with `NameError: uninitialized constant WebsiteBrandingService`; no dummy service or remote enrichment was added.
|
||||||
- SM-11/12 static inventory: repository is shallow (`git rev-parse --is-shallow-repository=true`); Docker, Syft, Trivy, Cosign and Gitleaks are unavailable; Dockerfile base images are mutable tags. Full-history fetch, isolated HTTP/DNS capture, production-like DB rehearsal, image digest and SBOM gates remain blocked. No network action was performed.
|
- SM-11/12 static inventory: repository is shallow (`git rev-parse --is-shallow-repository=true`); Docker, Syft, Trivy, Cosign and Gitleaks are unavailable; Dockerfile base images are mutable tags. Full-history fetch, isolated HTTP/DNS capture, production-like DB rehearsal, image digest and SBOM gates remain blocked. No network action was performed.
|
||||||
|
|
||||||
|
## 2026-08-22 — LLM chatbot runtime architecture discovery
|
||||||
|
|
||||||
|
### Objective
|
||||||
|
Compare Hermes, embedded n8n-like workflow functionality, and external n8n for the Chatwoot AgentBot path. This was a read-only architecture review; no production code was changed.
|
||||||
|
|
||||||
|
### Verified Chatwoot contract
|
||||||
|
- `AgentBot` currently has `bot_type: webhook`, `outgoing_url`, `bot_config`, secret, access token, account/inbox associations.
|
||||||
|
- `AgentBotListener` enqueues an asynchronous `AgentBots::WebhookJob`; it POSTs an event payload and does not wait for an LLM response.
|
||||||
|
- `Webhooks::Trigger` signs requests with `X-Chatwoot-Timestamp` and `X-Chatwoot-Signature`, retries 429/500 for agent bots, and treats the external bot as responsible for posting an outgoing message through Chatwoot API.
|
||||||
|
- Super Admin AgentBot is an admin CRUD surface. Per-account Bot Configuration is the correct customer-facing runtime boundary.
|
||||||
|
- No n8n integration exists in the current repository search.
|
||||||
|
|
||||||
|
### Verified Hermes contract
|
||||||
|
- Hermes API server exposes OpenAI-compatible `/v1/chat/completions`, Responses/Runs and Sessions APIs with bearer auth; Chat Completions is stateless unless history/response chaining is supplied.
|
||||||
|
- Hermes webhook adapter expects its own generic signature headers (`X-Webhook-Signature-V2`/`X-Webhook-Timestamp`), not Chatwoot's signature headers, and its configured delivery targets do not include Chatwoot message creation.
|
||||||
|
- Hermes memory/profiles are Hermes-scoped, not automatically Chatwoot-account-scoped. API server capabilities include terminal/tools, so a customer-facing deployment needs a restricted toolset, sandbox, and tenant isolation.
|
||||||
|
|
||||||
|
### Architecture finding
|
||||||
|
- Directly setting Chatwoot `outgoing_url` to Hermes is not a complete integration. A bridge/adapter is required to verify Chatwoot events, map account/inbox/conversation identity, invoke Hermes, enforce tool policy/idempotency, and POST the final message back to Chatwoot.
|
||||||
|
- n8n is appropriate as an external workflow/orchestration layer, but should not become the source of truth for conversation state or tenant knowledge.
|
||||||
|
- Embedding n8n UI/runtime in the product is a separate product/licensing/operations scope. n8n's official OEM docs require a commercial agreement when customers interact with the embedded editor; behind-the-scenes backend use is a distinct model.
|
||||||
|
|
||||||
|
### Decision candidate
|
||||||
|
Use a hybrid target: Chatwoot AgentBot → dedicated Hermes bridge → Hermes API for LLM/knowledge/tools; keep external n8n optional for cross-system workflows and side effects. Start with n8n as a P0 validation path only if it materially shortens learning; do not embed n8n or expose unrestricted Hermes tools to end users.
|
||||||
|
|
||||||
|
### Repository state
|
||||||
|
The worktree already contained unrelated uncommitted M1/M2 files before this review. Do not mix the future bridge implementation with those changes without an isolated worktree/branch.
|
||||||
|
|
||||||
|
## 2026-08-22 — Final decision: external n8n (Option 3)
|
||||||
|
|
||||||
|
- User selected Option 3: keep n8n as a separate service for the LLM chatbot/workflow path.
|
||||||
|
- No Hermes integration, embedded n8n/workflow builder, or Chatwoot production-code change is authorized in this decision.
|
||||||
|
- Existing Chatwoot AgentBot webhook contract remains the boundary; n8n receives the event, calls the configured LLM/external services, and posts the reply back through Chatwoot API.
|
||||||
|
- Treat the earlier Hermes hybrid architecture as analysis only, not an implementation decision. A Gateway/Adapter remains a future option if tenant isolation, idempotency, observability, or multi-runtime routing later require it.
|
||||||
|
|||||||
Reference in New Issue
Block a user