Copilot is the workspace for Finance Ops, OperOps/CRM, Voice, and Miniapp surfaces. Deprecated code is archived in old_code/.
Use this as a fast guardrail before implementing anything:
- Copilot is the active Voice platform (
/voice/*+/api/voicebot/*); do not design new behavior against legacyvoice.stratospace.fun. - Session closing is REST-driven (
POST /api/voicebot/session_done, alias/close_session), with websocket used for server-to-client updates only. - Voice control semantics are fixed to
New / Rec / Cut / Pause / Doneand must stay aligned between session page toolbar and FAB. - Full-track chunks are intentionally non-uploading until diarization is introduced; do not re-enable implicit uploads.
- Runtime isolation for Voice is deployment-scoped (separate DB/instance per environment);
runtime_tagis transitional metadata and not an operational routing contract. - Realtime updates are required: uploads and workers must emit session/message events so Transcription/Categorization update without refresh.
- Session list contracts are user-facing:
- quick tabs:
Все,Без проекта,Активные,Мои, - deleted toggle
Показывать удаленные, - filter state persistence across navigation/reload.
- quick tabs:
- Possible Tasks contract:
- canonical payload shape
id/name/description/priority/..., task_type_idstays optional.
- canonical payload shape
This is the smallest set of changes agents must keep in mind when touching Voice/ontology code:
- Session close is REST-driven only (
POST /api/voicebot/session_done, alias/close_session), and websocket is receive-only for close lifecycle. Doneis expected to work from paused and recording states; failed close must not silently reset UI to closed/idle.- Realtime message/session updates are mandatory (
new_message,session_update,message_update) to avoid refresh-only workflows. - Sessions list behavior is contract-bound:
- quick tabs (
Все,Без проекта,Активные,Мои), - persisted filter/toggle state,
- forced include-deleted mode sync under load.
- quick tabs (
- Sessions status in list uses state pictograms aligned with session page semantics; legacy red-dot-only marker is deprecated.
- TS transcribe worker supports Telegram file recovery before transcription when local file path is missing.
- TypeDB tooling was hard-moved to
ontology/typedb/scripts/*; backend npm aliases call those canonical scripts.
POST /api/voicebot/upload_audioPOST /api/voicebot/session_done(legacyPOST /api/voicebot/close_sessionalias remains server-side only)POST /api/voicebot/save_summaryPOST /api/voicebot/upload_attachmentandPOST /api/voicebot/attachment(alias)- Socket namespace
/voicebotwith room subscriptionsubscribe_on_session - Canonical session links:
https://copilot.stratospace.fun/voice/session/:id
- FX rates are managed in
app/src/store/fxStore.tsand recalculate RUB values in analytics, KPIs, and plan-fact tables. - The Employees directory supports a chat-driven form fill that prompts for missing fields.
- Plan-fact months can be pinned (up to 3), and the totals row stays visible under pinned months.
- Plan-fact frontend uses API-only data (local
mockPlanFactfallback and CRM snapshot badges were removed from pages/stores). - Plan-fact project edits are persisted through
PUT /api/plan-fact/project; backend propagatescontract_typeupdates into facts/forecasts records for the sameproject_id. - The Expenses tab combines payroll and other costs, with category-level operations and sticky totals.
- Expense attachments are uploaded via
/api/uploads/expense-attachmentsand served from/uploads/expenses. - Guide directories fall back to mock data when the automation API is unavailable, and the Guide header includes a global Log sidebar.
- FinOps spec discovery/index for scope alignment is tracked in
docs/FINOPS_SPEC_DISCOVERY.md(canonical vs mirror sources + open product questions).
- CRM components migrated from
automation/appkanbanlive inapp/src/components/crm/. - CRM pages: CRMPage, PerformersPage, FinancesPerformersPage, ProjectsTree, TaskPage in
app/src/pages/operops/. - CRM stores:
kanbanStore.ts(tickets, epics, performers),crmStore.ts(UI state),projectsStore.ts(project tree),requestStore.ts(API). - Socket.IO events: TICKET_CREATED, TICKET_UPDATED, TICKET_DELETED, EPIC_UPDATED, COMMENT_ADDED, WORK_HOURS_UPDATED.
- Routes accessible at
/operops/*with OperOpsNav horizontal navigation. - CRM Kanban task details link must resolve by
id || _idto prevent/operops/task/undefinednavigation for records without publicid. - CRM project display/filtering should resolve project name from
project_data/project_id/project; performer filter must handle mixed_idand legacyidvalues. - CRM work-hours linkage is canonical by
ticket_db_id(automation_tasks._id) across CRM API, Miniapp routes, and reporting services; legacyticket_idis tolerated only as migration input. - Added backfill utility for historical work-hours rows missing
ticket_db_id:cd backend && npx tsx scripts/backfill-work-hours-ticket-db-id.ts --apply(use without--applyfor dry-run). - Short-link generation/collision/route-resolution contract is documented in
docs/OPEROPS_TASK_SHORT_LINKS.md. - OperOps TaskPage metadata now includes
Created by, resolved from task creator fields with performer-directory fallback. - OperOps TaskPage metadata now includes
Sourcewith source kind and clickable external link (Voice/Telegram/manual fallback contract). - Voice
ЗадачиandCodextabs now use a shared canonical source matcher with OperOps Kanban (source_ref/external_ref/source_data.session_*+ canonical session URL parsing), so Source->Voice navigation keeps task visibility consistent. - Shared
CodexIssuesTablecontract applies in both Voice and OperOps tabs, with strict status segmentation tabs (Open/In Progress/Deferred/Blocked/Closed/All) and per-tab counters. - Codex issue details rendering is shared between OperOps and Voice via
CodexIssueDetailsCard; Voice inline details drawer uses wide layout (min(1180px, calc(100vw - 48px))) and preserves Description/Notes paragraph breaks (whitespace-pre-wrap) for parity with OperOps task page. - Codex issue IDs now use one token renderer across
Issue IDandRelationships(blue link + copy action); relationship rows also show status pictograms (open,in_progress,blocked,deferred,closed, fallback). - Codex relationship groups are normalized in details card as
Parent,Children,Depends On (blocks/waits-for), andBlocks (dependents)for deterministic dependency reading. - Performer selectors normalize Codex assignment to canonical performer
_id=69a2561d642f3a032ad88e7a(legacy synthetic ids are rewritten) in CRM and Voice task-assignment flows.
- Voice UI is native in
app/under/voice/*(no iframe embed). - Voice API source of truth is local:
/api/voicebot/*(flat contract + legacy aliases during migration). - Runtime isolation is enforced by per-environment deployment/database boundaries;
runtime_tagis not a canonical runtime filter contract. - WebRTC FAB script should be loaded from same-origin static path (
/webrtc/webrtc-voicebot-lib.js) viaVITE_WEBRTC_VOICEBOT_SCRIPT_URL. - Upload route (
/api/voicebot/upload_audio) immediately emits socket eventsnew_message+session_updateintovoicebot:session:<session_id>so new chunks appear without waiting for polling. - Upload route returns structured oversize diagnostics (
413 file_too_largewith max-size metadata), and WebRTC upload client normalizes these payloads into concise UI-safe error messages. - Upload route propagates
request_idin success/error payloads and logs (X-Request-IDpassthrough or generated fallback), and WebRTC surfaces this id in upload diagnostics. - Upload route now has explicit upstream-failure shaping: Nginx intercepts
502/503/504for/api/voicebot/upload_audioand returns structured JSON503 backend_unavailable, while WebRTC client keeps chunk in failed/manual-retry state and shows actionable retry guidance. - Session upload flow consumes pending image anchors (
pending_image_anchor_message_id/pending_image_anchor_oid): first uploaded chunk is linked withimage_anchor_message_id, then pending anchor markers are cleared. - Categorization updates are now delivered via websocket
message_updateevents (no page refresh required): processor workers pushSEND_TO_SOCKETjobs, backend consumes them and broadcasts tovoicebot:session:<session_id>. CREATE_TASKSrealtime delivery is session-room first: workers always includesession_idintickets_prepared, optionalsocket_idis used only for targeted emit, and socket events worker preserves array payloads for this event.- Transcribe worker now emits realtime
message_updateevents for both success and failure branches, so pending/error rows appear in Transcription tab without manual refresh. - Transcription fallback rows with
transcription_errorrender metadata signature footer (mm:ss - mm:ss, file.webm, HH:mm:ss) and are replaced in place when realtimemessage_updatebrings transcript text. - Voice socket reconnect now performs session rehydrate and ordered upsert (
new_message/message_update) to prevent live-state drift after transient disconnects. - Voice websocket must use the
/voicebotnamespace (getVoicebotSocket), not the root namespace (/), otherwise session subscriptions (subscribe_on_session) are ignored. POST /api/voicebot/sessions/getfollows fail-fast lookup semantics and returns404 Session not foundwhen the session cannot be resolved in canonical scope.- Categorization table no longer renders
SrcandQuick Summarycolumns (copilot-eejo); phase-1 view is status + text +Materialswith sortable order. - Session close initiation is REST-first: clients call
POST /api/voicebot/session_doneand fail fast on errors; websocket is used for server-originated realtime updates only (session_status,session_update,new_message,message_update). - WebRTC REST close diagnostics now always include
session_idin client warning payloads (close failed,close rejected,request failed) to speed up backend correlation. Donein WebRTC now runs bounded auto-upload draining and marks remaining failed chunk uploads for explicit retry instead of indefinite automatic loops.- WebRTC close path no longer emits
session_donefrom browser Socket.IO; FAB/page/yesterday close flows use the same REST close endpoint for deterministic behavior across host/path variants. - WebRTC unload persistence now stores any non-recording state as
pausedto avoid stale auto-resume after refresh/unload races. - Full-track recording segments are represented as
full_trackin Monitor/UI with duration and timestamp metadata, but upload to backend is intentionally disabled until diarization workflow is enabled. - Voice workers schedule periodic
PROCESSINGscans in TS runtime; pending-session filtering usesis_waiting: { $ne: true }to include legacy rows without explicit flag. - TS
processingLoopnow also prioritizes sessions inferred from pending message backlog (including rows withis_messages_processed=true) and requeues categorization after quota cooldown via processors queue. - TS transcribe handler deduplicates repeated uploads by file hash (
file_hash/file_unique_id/hash_sha256) and reuses existing session transcription before new OpenAI requests. - Historical WebRTC duplicates can be collapsed by filename per session via backend script:
- dry run:
cd backend && DOTENV_CONFIG_PATH=.env.production npm run voice:dedupe:webm:dry - apply:
cd backend && DOTENV_CONFIG_PATH=.env.production npm run voice:dedupe:webm:apply - rules: only non-Telegram
*.webmmessages, grouped by(session_id, file_name), keep one most relevant message and mark the restis_deleted=true.
- dry run:
- Idle active sessions can be auto-closed via backend script:
- dry run:
cd backend && DOTENV_CONFIG_PATH=.env.production npm run voice:close-idle:dry -- --inactive-hours=4 - dry run (LLM/automation JSON):
cd backend && DOTENV_CONFIG_PATH=.env.production npm run voice:close-idle:dry -- --inactive-hours=4 --json - dry run (streaming JSONL):
cd backend && DOTENV_CONFIG_PATH=.env.production npm run voice:close-idle:dry -- --inactive-hours=4 --jsonl - apply:
cd backend && DOTENV_CONFIG_PATH=.env.production npm run voice:close-idle:apply -- --inactive-hours=4 - activity window uses latest session update/message/session-log timestamps; sessions with no movement above the threshold are closed through
DONE_MULTIPROMPTflow.
- dry run:
- Summarize MCP dependency watchdog is available for
session_ready_to_summarizeprerequisites:- dry run:
cd backend && DOTENV_CONFIG_PATH=.env.production npm run voice:summarize-mcp-watchdog:dry - dry run JSON:
cd backend && DOTENV_CONFIG_PATH=.env.production npm run voice:summarize-mcp-watchdog:dry -- --json - apply (auto-heal):
cd backend && DOTENV_CONFIG_PATH=.env.production npm run voice:summarize-mcp-watchdog:apply - checks required endpoint/service mappings:
fs,tg-ro,call,seq,tm,tgbot. - remediation is targeted: inactive
mcp@*units are started, active units with endpoint502/unreachable probes are restarted.
- dry run:
- Empty stale sessions can be cleaned in worker runtime by scheduled
CLEANUP_EMPTY_SESSIONSjobs (no-message sessions older than configured threshold are markedis_deleted=true):- env knobs:
VOICEBOT_EMPTY_SESSION_CLEANUP_INTERVAL_MS,VOICEBOT_EMPTY_SESSION_CLEANUP_AGE_HOURS,VOICEBOT_EMPTY_SESSION_CLEANUP_BATCH_LIMIT.
- env knobs:
- Voice sessions list supports deleted-session mode (
include_deleted/Показывать удаленные); creator/participant filters suppress numeric identity placeholders and keep only human-readable labels. - Voice sessions list now persists active tab + filter set in local storage and restores them on reopen; current quick tabs are
Все,Без проекта,Активные,Мои. - Voice sessions list forces a mode-sync refetch when
showDeletedSessionsintent changes during an in-flight load (force=truebypasses loading short-circuit for this case). - Voice sessions list supports bulk delete for selected active rows (
Удалить выбранные) with confirmation and safe exclusion of already deleted sessions. - Voice sessions list state marker is now a dedicated pictogram column aligned with session state semantics (
recording,cutting,paused,final_uploading,closed,ready,error). - Session read path normalizes stale categorization rows linked to deleted transcript segments (including punctuation/spacing variants) and saves cleaned
processed_data. - Session read path force-clears categorization rows when all transcript segments are deleted in a message, so UI does not show orphan categorization tails after full transcript deletion.
- Categorization table contract is now
Time | Audio | Text | Materials; the old processing (Обработка) column/renderer path was removed. - Categorization rows now use stable identity (
row_id/segment_oidpriority + deterministic fallback), so selection/actions are row-local and collision-safe. - Categorization rows support Copy/Edit/Delete actions via backend routes
POST /api/voicebot/edit_categorization_chunkandPOST /api/voicebot/delete_categorization_chunk. - Categorization mutation APIs emit realtime
message_update+session_update, and return deterministic validation/runtime errors (invalid_row_oid,message_session_mismatch,ambiguous_row_locator,row_already_deleted, etc.). - Deleting the last active categorization row cascades deletion of the linked transcript segment with compensating rollback when log persistence fails.
- Image attachments in categorization are rendered only in the Materials column; image-only blocks remain visible without image-as-text rows.
- Session-scoped taskflow parity is now canonical across backend + Voice UI + mcp@voice:
- backend route
POST /api/voicebot/possible_tasksexposes canonicalrow_idvalues, - mutations emit
session_update.taskflow_refreshflags forpossible_tasks/tasks/codex, - frontend consumes those hints with additive refresh tokens so
Возможные задачи,Задачи, andCodexrefresh without manual reload, - assistant workflow is fixed to
discuss -> preview -> apply -> verify.
- backend route
- Voice message grouping links image-anchor rows to the next transcription block and suppresses duplicate standalone anchor groups; transcription rows now show inline image previews when image attachments are present.
- Web pasted images are persisted via backend upload endpoint (
POST /api/voicebot/upload_attachment, alias/api/voicebot/attachment) intobackend/uploads/voicebot/attachments/<session_id>/<file_unique_id>.<ext>. - Session page shows
Возможные задачиtab whenprocessors_data.CREATE_TASKS.datais present and user hasPROJECTS.UPDATE; the table uses compact design (no standalone status/project/AI columns), keepsdescription, and validates required fields inline. - Possible Tasks validation no longer requires
task_type_id; blocking required fields arename,description,performer_id, andpriority. - Possible Tasks session table no longer exposes editable
task_type_idanddialogue_tagcolumns; create payload stays canonical for required operational fields. - CREATE_TASKS payloads are normalized to canonical
id/name/description/priority/...shape in both worker (createTasksFromChunks) and API utility (save_create_tasks) write paths. - Task deletion from session uses canonical locators only (
row_id,id,task_id_from_ai) without legacy human-title aliases. - Historical CREATE_TASKS legacy payload migration runbook is documented in
docs/VOICEBOT_CREATE_TASKS_MIGRATION.md(verify/apply/post-check + rollback). - Categorization metadata signature is rendered once per message block footer (
source_file_name + HH:mm:ss) instead of repeating per row; row focus uses blue selection only. - Categorization readability contract now uses larger typography in
Time/Audio/Text/Materialscolumns for dense session review. - Session summary now has a canonical persistence path:
- backend route
POST /api/voicebot/save_summaryvalidates{ session_id, md_text }and writessummary_md_text+summary_saved_at, - backend emits realtime
session_update.taskflow_refresh.summary, - frontend summary panel (
Summary) supports edit/save/conflict states bound to those canonical fields.
- backend route
- Done-flow summarize orchestration now propagates
summary_correlation_idand writes summary audit events (summary_telegram_send,summary_save) with idempotency keys to session log. - TS categorization/create-tasks chain treats non-text placeholders (
image,[Image],[Screenshot]) as non-blocking: rows are marked processed with empty categorization, andCREATE_TASKScan finalize without waiting on uncategorizable chunks. - Session toolbar and FAB keep unified control order
New / Rec / Cut / Pause / Done;Recactivates page session before routing to FAB control, while status badge follows runtime states (recording,paused,finalizing,error,closed,ready). - Transcription/Categorization tables support client-side chronological direction switching (up/down) with preference persisted in local storage.
- Screenshot attachments now display canonical absolute URLs with
public_attachmentpriority (direct_uri), and expose hover-only copy-link action in card footer. - Screenshort cards keep
https://...links fully visible, whiledata:image/...;base64,...values are displayed in truncated preview form (data:image/...;base64,...) and copied in full through the hover Copy action. - Voice task creation in Copilot runtime no longer requires
task_type_id; missing type is no longer a hard blocker in ticket/task generation. copilot-voicebot-tgbot-prodruns TypeScript runtime frombackend/dist/voicebot_tgbot/runtime.jswithbackend/.env.productionas the single env source.- TS tgbot runtime protects against duplicate pollers using env-stable Redis distributed lock key (
voicebot:tgbot:poller_lock+ env suffix); lock loss triggers controlled shutdown to prevent split Telegram update consumption. copilot-voicebot-workers-prodruns TypeScript worker runtime frombackend/dist/workers/voicebot/runtime.js(npm run start:voicebot-workers) viascripts/pm2-voicebot-cutover.ecosystem.config.js; queue workers consume allVOICEBOT_QUEUESand dispatch throughVOICEBOT_WORKER_MANIFESTwithbackend/.env.production.- Backend API process runs dedicated socket-events consumer (
startVoicebotSocketEventsWorker) forvoicebot--events-*queue and uses Socket.IO Redis adapter for cross-process room delivery. - TS transcribe handler never silently skips missing transport now: Telegram messages with
file_idbut without localfile_pathare markedtranscription_error=missing_transportwith diagnostics; text-only chunks without file path are transcribed viatranscription_method=text_fallbackand continue categorization pipeline. - TS transcribe handler additionally supports Telegram transport recovery: for
source_type=telegram+file_id+ missing local file path it resolvesgetFile, downloads audio into local storage, persistsfile_path, and continues transcription in the same job. - Voice backend exposes session-merge scaffolding (
voicebot/sessions/merge) with explicit confirmation phrase and merge-log collection support (automation_voice_bot_session_merge_log).
- Runtime entrypoints migrated to TS:
backend/src/voicebot_tgbot/runtime.ts(copilot-b2t,copilot-f1g,copilot-h84)backend/src/workers/voicebot/runtime.ts+ manifest/runner (copilot-ovg)
- Core worker handlers migrated to TS (
copilot-6jm,copilot-lnu,copilot-lcf):backend/src/workers/voicebot/handlers/{transcribe,categorize,finalization,processingLoop,summarize,questions,customPrompt,createTasksFromChunks,doneMultiprompt,...}.ts
- Legacy runtime subtree was removed from this repo under
copilot-vsen; historical implementation references live in external repo/home/strato-space/voicebot. - JS cleanup completed for confirmed dead artifact: removed
sandbox-assets/ui-miniapp/app.js(no runtime references in copilot).
- Primary frontend migration decision log:
docs/MERGING_FRONTENDS_VOICEBOT.PLAN.md - Program-level migration source:
docs/MERGING_PROJECTS_VOICEBOT_PLAN.md - Playwright parity source:
docs/PLAYWRIGHT_MIGRATION_MATRIX.md - All three docs are synced from closed
bd list --allitems and use status legend[v] / [x] / [~]. - This plan is maintained against closed
bdissues and includes an explicit contradiction section between old assumptions and implemented behavior. - Current open migration backlog is tracked only in
bd; as of the latest refresh there are no open P1 frontend migration tasks. - Legacy implementation history remains in external repo:
/home/strato-space/voicebot - Synced legacy planning references copied for context now live in
plan/session-managment.mdandplan/gpt-4o-transcribe-diarize-plan.md. - Unified draft for next implementation wave lives in
plan/voice-operops-codex-taskflow-spec.md(Voice ↔ OperOps ↔ Codex contract and rollout phases).
- OpenAI key is a shared variable:
OPENAI_API_KEY.- Copilot backend:
backend/src/api/routes/voicebot/llmgate.ts. - TS workers/tgbot runtime:
backend/src/workers/voicebot/*andbackend/src/voicebot_tgbot/*.
- Copilot backend:
- Runtime/instance settings:
APP_ENV— canonical environment discriminator for env-stable queue/lock suffixing.VOICE_RUNTIME_ENV/VOICE_RUNTIME_SERVER_NAME— transitional runtime metadata (not isolation source-of-truth).DOTENV_CONFIG_PATH,DOTENV_CONFIG_OVERRIDE— explicit env file source for cutover startup.
- Telegram identity:
TG_VOICE_BOT_TOKEN(prod family)TG_VOICE_BOT_BETA_TOKEN(non-prod runtime)
- OpenAI/LLM knobs:
OPENAI_BASE_URL(defaulthttps://api.openai.com/v1)VOICEBOT_CATEGORIZATION_MODEL(defaultgpt-4.1)VOICEBOT_TASK_CREATION_MODEL(defaultgpt-4.1)
- Transcription errors persist diagnostics (
openai_key_mask,openai_key_source,openai_api_key_env_file,server_name) for quota/file-path incident analysis; key mask format is normalized tosk-...LAST4. - Storage and services:
OPENAI_*keys are loaded frombackend/.env.productionfor backend API, TS workers, and TS tgbot runtime.MONGO_*,REDIS_*,MAX_FILE_SIZE,UPLOADS_DIRremain service-specific.
- Agent cards live in
agents/agent-cards/*and are served by Fast-Agent onhttp://127.0.0.1:8722/mcp(/home/strato-space/copilot/agents/pm2-agents.sh). - PM2 runtime launches agents through
uv run --directory /home/strato-space/copilot/agents fast-agent serve ... --model codexfor deterministic cwd + runtime model override. create_taskscard no longer hardcodes model; model selection is controlled at runtime via launch config.- Frontend trigger points:
- AI title button in
/voice/session/:idcalls MCP toolgenerate_session_title. - CRM "restart create_tasks" flow calls MCP tool
create_tasks.
- AI title button in
- Frontend MCP endpoint resolution order:
window.agents_api_url(if set at runtime),VITE_AGENTS_API_URL,- fallback
http://127.0.0.1:8722(prod safety fallback).
- MCP transport path:
- browser opens Socket.IO to backend (
/socket.io), - frontend emits
mcp_call, - backend MCP proxy (
backend/src/services/mcp/*) calls Fast-Agent MCP endpoint.
- browser opens Socket.IO to backend (
- Required tool names in agent cards:
generate_session_title(agents/agent-cards/generate_session_title.md)create_tasks(agents/agent-cards/create_tasks.md)
- Miniapp frontend sources live in
miniapp/src/and build tominiapp/dist. - Miniapp backend is served by the Copilot backend runtime (
npm run dev:miniapp/npm run start:miniapp). - PM2 mode scripts start both backend APIs (
copilot-backend-*andcopilot-miniapp-backend-*) together. - In
IS_MINIAPP_DEBUG_MODE=true, miniapp/ticketsreads from raw DB (getRawDb) to keep debug ticket visibility when runtime tags differ between test data and scoped runtime. - Miniapp backend can optionally start a Telegram bot via
TG_MINIAPP_BOT_TOKEN;/startand/miniappreturn an inline WebApp button,/get_infoprints chat metadata for diagnostics, and graceful shutdown stops the bot before process exit.
app/React + Vite frontend for Finance Ops and OperOps/CRM.miniapp/React + Vite miniapp frontend.backend/Node/Express API for FinOps, CRM, VoiceBot, and miniapp backend routes.agents/Python-based agents service and PM2 helper scripts.scripts/deployment helpers (pm2-backend.sh,check-envs.sh).docs/,specs/,projects/for product documentation and specs.deploy/Host-level Nginx config and notes.
- Synced voice migration planning docs are stored under
docs/voicebot-plan-sync/. - Keep
docs/voicebot-plan-sync/implementation-draft-v1.mdand session-level transcript versioning specs (edit-event-log-plan.md,gpt-4o-transcribe-diarize-plan.md) current with migration decisions. - Session close/finalization outcomes for voice migration should be documented in
CHANGELOG.mdand mirrored inAGENTS.md+README.md.
- SemVer policy:
MAJOR.MINOR.PATCH. MAJOR: breaking API or behavior contract changes.MINOR: backward-compatible features/endpoints.PATCH: bugfixes/refactors without intentional behavior change.- Dependency policy:
- Prefer current stable TypeScript/Node LTS and keep strict typecheck green.
- Prefer current stable
zod4.x for API schema/runtime validation. - Review lockfile changes in PRs; avoid silent transitive upgrades during hotfixes.
- Backend voice handlers must validate request payloads with Zod at route boundaries.
- Keep callback/input types derived from schemas (
z.input<typeof schema>) for compile-time safety. - Do not bypass schema validation with ad-hoc parsing for public API endpoints.
For shared dev on p2, use PM2 scripts and serve static builds to avoid Vite port conflicts.
./scripts/check-envs.sh
./scripts/pm2-backend.sh dev- Dev URL: https://copilot-dev.stratospace.fun
- Backend health: http://127.0.0.1:3002/api/health
- Agents MCP (fast-agent): http://127.0.0.1:8722 (plain HTTP; MCP endpoint is
/mcp, loopback-only bind) - Manual frontend builds:
cd app && npm install && npm run build-devcd miniapp && npm install && npm run build-dev
This repo uses bd (Beads) and the beads-sync branch to keep repository metadata consistent.
bd syncSee AGENTS.md for the full workflow (including bd doctor guidance).
- Backend proxies Voicebot auth via
/api/try_loginand/api/auth/me; setVOICEBOT_API_URLin the backend environment. - Frontend auth checks call
https://voice.stratospace.fun/auth/meby default; override withVITE_VOICEBOT_BASE_URLif needed. - Login relies on the shared
auth_tokenhttp-only cookie for.stratospace.fun.
The Finance Ops SPA is served by Nginx, and /api is proxied to the backend. For the public domain, see deploy/nginx-host.conf and deploy/README.md.
- Canonical test matrix and suite composition are declared in
platforms.json. - Unified repo-level runner:
./scripts/run-test-suite.sh baseline./scripts/run-test-suite.sh voice./scripts/run-test-suite.sh full
- Detailed structured procedure:
docs/TESTING_PROCEDURE.md. - Module-level commands:
app:npm run test,npm run test:serial,npm run e2e:install,npm run test:e2ebackend:npm run test,npm run test:parallel-safe,npm run test:serializedminiapp:npm run test,npm run test:e2e
- Default worker strategy:
app/miniappunit tests use--maxWorkers=${JEST_MAX_WORKERS:-50%}backendunit tests are split into parallel-safe + serialized groups (BACKEND_JEST_MAX_WORKERScontrols parallel-safe group)
fullsuite now executes app e2e and voice e2e as explicit shard jobs declared inplatforms.json.appE2E requires explicit target URL viaPLAYWRIGHT_BASE_URL(default config useshttp://127.0.0.1:3002).- Useful
appE2E scopes:npm run test:e2e:uinpm run test:e2e:headednpm run test:e2e:unauthnpm run test:e2e:auth
To run authenticated tests:
- Copy
app/.env.test.exampletoapp/.env.test - Fill in
TEST_USER_EMAILandTEST_USER_PASSWORD - Run tests:
npm run test:e2e
Projects:
chromium-unauth: Tests without authentication (login page, redirects)chromium: Authenticated tests (require valid credentials in.env.test)
Current scanner triage baseline:
Accepted risk / false-positive: 6
Accepted items for desloppify security scan:
security::app/src/components/voice/TranscriptionTableRow.tsx::hardcoded_secret_name(openai_api_key_missing) — UI error-code label, not a secret.security::app/src/constants/permissions.ts::hardcoded_secret_name(RESET_PASSWORD) — permission key constant, not a credential.security::backend/src/constants.ts::hardcoded_secret_name(ONE_USE_TOKENS) — collection-name constant, not a credential.security::backend/src/permissions/permissions-config.ts::hardcoded_secret_name(RESET_PASSWORD) — permission key constant, not a credential.security::backend/src/voicebot_tgbot/runtime.ts::eval_injection(line ~194) — Redis LuaEVALcommand with static script, not JSeval/new Function.security::backend/src/voicebot_tgbot/runtime.ts::eval_injection(line ~213) — Redis LuaEVALcommand with static script, not JSeval/new Function.
Rule for updates:
- Keep this section synchronized with
.desloppify/state-typescript.jsontriage notes wheneverdesloppifyscan results are refreshed.
- Close-session refresh (2026-03-04 12:22):
- Closed
copilot-w8l0epic (copilot-w8l0.1..copilot-w8l0.3) for quota-recovery realtime parity:tickets_preparednow reaches session-room subscribers without requiringsocket_id, and socket dispatch preserves array payloads for this event. - Transcription fallback rows with quota errors now show metadata signature footer and are designed for in-place replacement when retries produce transcript text.
- Added QA runbook
docs/voicebot-plan-sync/quota-recovery-realtime-qa-checklist.md. - Validation passed:
cd backend && npm run test -- __tests__/voicebot/workers/workerCreateTasksFromChunksHandler.test.ts __tests__/voicebot/workers/workerCreateTasksPostprocessingRealtime.test.ts __tests__/voicebot/socket/voicebotSocketEventsWorker.test.ts,cd app && npm run test:serial -- __tests__/voice/transcriptionFallbackErrorSignatureContract.test.ts,cd backend && npm run build,cd app && npm run build.
- Closed
- Close-session refresh (2026-03-03 20:20):
- Added
docs/MULTI_AGENT_DISTILLATION_2026-03-03.mdas the canonical session artifact for multi-agent orchestration guidance: isolated worker context,bd-native forward-only graph usage, and explicit hierarchy mappingCJM -> BPMN -> UserFlow -> Screens -> Widgets -> Atoms/Tokens. - Synchronized closeout records in
CHANGELOG.md/AGENTS.md/README.mdand accepted pending local artifacts in this closeout package:.agents/product-marketing-context.md,output/copilot-marketing-discovery-2026-03-03.pptx, andtmp/copilot-marketing-ppt/**.
- Added
- Close-session refresh (2026-03-03 13:55):
- Closed
copilot-q5cc:notify_requestedsession-log entries now derivemetadata.sourcefrom the real close/worker path instead of hardcodingsocket_session_done. - Closed
copilot-zd9x:tools/voiceclose wrappers are now strict fail-fast and do not fall back toPOST /api/voicebot/close_session.
- Closed
- Close-session refresh (2026-03-03 13:37):
- Closed
copilot-7b9yepic (copilot-7b9y.1..copilot-7b9y.10) and completed Voice session-done REST parity formcp@voiceandactions@voice. tools/voicenow closes sessions through backend RESTPOST /api/voicebot/session_donewith explicit5stimeout and no automatic retry.- Validation passed:
71targeted voice tests, a disposable close smoke, and a realactions@voicere-close of session69a527c14b07162c36957e21; downstreamCREATE_TASKSrefreshed (5 -> 15),done_atadvanced, and notify events were emitted. - Added execution evidence to
plan/69a527c14b07162c36957e21-voice-session-done-rest-parity-plan.md.
- Closed
- Close-session refresh (2026-03-02 22:03):
- Closed
copilot-7r94epic (copilot-7r94.1..copilot-7r94.11) and delivered Voice categorization cleanup: stable row identities, no processing column, materials-only rendering, typed edit/delete APIs, realtime mutation events, and last-row cascade transcript deletion. - Closed
copilot-j54y: Codex relationship IDs now match Issue-ID behavior (link + copy) with status pictograms; shared Codex status tabs now includeIn ProgressandBlocked. - Added planning artifacts for auth/video parser tracks:
voice-categorization-ux-cleanup-plan.md,plan/auth-option-a-copilot-oauth-provider-plan.md,plan/auth-option-b-google-oauth-plan.md,plan/auth-options-a-vs-b-comparison.md, andvideoparser/specs/*. - Included payout formula update in
app/src/store/kanbanStore.ts(basicBonuscoefficient0.05). - Validation passed:
cd app && npm run build,cd backend && npm run build;bd ready --jsonreturned empty queue.
- Closed
- Close-session refresh (2026-03-02 13:45):
- Closed
copilot-wtz7: shared Codex table now uses explicit status tabsOpen / Deferred / Closed / All; deferred compatibility treats bothstatus=deferredand transitionalstatus=open + defer_untilas deferred, so Open no longer mixes deferred backlog. - Closed
copilot-ai1b:/voicesessions list now renders AI-style loading placeholder and domain empty state (Пока нет сессий по текущим фильтрам) with reset-filters CTA; genericNo datatext is removed from this flow. - Added
docs/FINOPS_SPEC_DISCOVERY.mdand syncedREADME.md/AGENTS.mdreferences as progress artifact forcopilot-081q(scope remains pending product decisions). - Validation passed:
cd app && npm run test:serial -- __tests__/operops/codexIssuesTableContract.test.ts __tests__/voice/sessionCodexTasksFilterOrderContract.test.ts __tests__/voice/sessionsListEmptyStateContract.test.tsandcd app && npm run build.
- Closed
- Close-session refresh (2026-03-02 13:30):
- Closed
copilot-9ifu: Codex details card now hides empty metadata rows, normalizes escaped newlines in Description/Notes, and renders explicit relationship groups from bd payload. - Closed follow-ups
copilot-x06uandcopilot-2qne:copilot-*IDs inRelationshipsand topIssue IDare now clickable to/operops/codex/task/:idwhile keeping Issue ID copy action intact. - Added/updated Codex contracts:
- added
app/__tests__/operops/codexIssueDetailsCardContract.test.ts, - updated
app/__tests__/operops/codexIssuesTableContract.test.tsfor raw relationship payload pass-through.
- added
- Included accumulated working-tree deltas in this closeout:
app/src/components/crm/CRMKanban.tsx: clone ticket action with normalized create payload,app/src/components/PlanFactGrid.tsx: contract/subproject labels no longer forced to uppercase,app/e2e/task-create.spec.ts: unauth-friendly task-create close/cancel test with mocked CRM/auth APIs and spinner click-through handling,docs/copilot-repo-visual-recap.html: rewritten as MongoDB→TypeDB mapping-centric visual recap.
- Validation:
cd app && npm run test:serial -- __tests__/operops/codexIssueDetailsCardContract.test.ts __tests__/operops/codexIssuesTableContract.test.ts __tests__/voice/codexTasksInlineDetailsContract.test.ts __tests__/operops/codexTaskPageContract.test.tsandcd app && npm run buildpassed.
- Closed
- Close-session refresh (2026-03-01 22:02):
- Captured outstanding local docs commit
e577500(docs: fix Mermaid line breaks in visual recap diagram) into close-session artifacts and prepared final release handoff. - Added
CHANGELOG.mddate block2026-03-01with explicit problem/feature/change entries fordocs/copilot-repo-visual-recap.html. - Synced
AGENTS.mdandREADME.mdsession-closeout sections to keep closeout evidence aligned before final push and Telegram broadcast.
- Captured outstanding local docs commit
- Close-session refresh (2026-02-28 19:10):
copilot-sxq1.14.8execution hit Codex runner quota/usage-limit blocker during scoped subjective batch execution; task remainedin_progresswith explicit blocker note in issue history.- Decomposed
copilot-sxq1.14.8into six independent child tasks by file-scope to remove one-shot batch dependency:copilot-sxq1.14.8.1(app/src/store/**)copilot-sxq1.14.8.2(app/src/hooks/**)copilot-sxq1.14.8.3(app/src/services/**)copilot-sxq1.14.8.4(app/src/utils/**)copilot-sxq1.14.8.5(app/src/types/**)copilot-sxq1.14.8.6(app/src/constants/**)
- Validation rerun for reorganized test pipeline:
cd app && npm run test:e2e:voice:shard:1of2passed (13/13) after transient shard failure in one full run;- canonical gate passed:
./scripts/run-test-suite.sh full --fail-fast(10/10 PASS).
- Updated
desloppifytriage pointer for next remediation step:review::.::holistic::abstraction_fitness::overuse_unknown_in_core_contracts::5ff2ecc1(desloppify next, Tier 1).
- Closed testing modernization epic
copilot-2gs1(stages 1-8): unified runner is stage-parallel with fail-fast stage control, backend tests are split into parallel-safe/serialized groups, app+voice e2e run via shard jobs, and testing docs are synchronized (README/AGENTS/docs/TESTING_PROCEDURE.md) with benchmark history. - Final full-suite benchmark for this wave:
163.97s -> 80.01s(+51.20%). - Closed
copilot-sxq1.8and aligned contract tests with extracted voice/frontend helper modules (voicebotHttp,voicebotRuntimeConfig,codexTaskTimeline) plus sanitized TaskPage render contract updates. - Updated backend contract/runtime tests for ESM-safe execution and current route contracts:
backend/__tests__/voicebot/runtime/sessionUtilityRuntimeBehavior.validation.test.ts(jestfrom@jest/globals),backend/__tests__/entrypoints/orphanedEntrypointsContract.test.ts(import.meta.urlpath resolution),backend/__tests__/api/crmCodexRouteContract.test.tsandbackend/__tests__/voicebot/rowMaterialTargetRouteContract.test.ts(current route-shape expectations).
- Close-session validation summary:
make testtarget is absent in this repo (No rule to make target 'test');- canonical suite passed:
./scripts/run-test-suite.sh full(10/10 PASS); - type-safety builds passed:
cd app && npm run build,cd backend && npm run build.
- Current
desloppify nexttop unresolved item: Tier-2 exact duplicaterenderSanitizedHtmlbetweenapp/src/pages/operops/TaskPage.tsxandminiapp/src/components/OneTicket.tsx. - Executed swarm waves for
top_open_in_progress_ids_by_priority: closedcopilot-g0bd(Codex routing fix) andcopilot-603(placeholder cleanup), and recorded verification-only audit notes for remainingcopilot-ztlv*/copilot-ib30backlog items. - Hardened backend Codex routing in
POST /api/voicebot/create_tickets(backend/src/api/routes/voicebot/sessions.ts) so Codex aliases/labels are resolved before strict ObjectId checks and cannot leak into Mongo task inserts. - Added regression coverage for alias/name-based Codex routing and malformed non-Codex performer paths in
backend/__tests__/voicebot/sessionUtilityRuntimeBehavior.test.ts. - Documented active blocker for
copilot-ib30:POST /api/voicebot/activate_sessioncurrently fails withERR_EMPTY_RESPONSEin browser, blocking end-to-end screenshot paste verification. - Added Codex API runtime recovery for out-of-sync
bdstate:/api/crm/codex/issueand/api/crm/codex/issuesnow auto-runbd sync --import-onlyand retry once before returning an error. - Fixed OperOps Codex issue page loading for valid BD IDs (
copilot-f7w7):app/src/pages/operops/CodexTaskPage.tsxnow supports mixed/api/crm/codex/issuepayload envelopes and posts bothid+issue_id; added coverage inapp/__tests__/operops/codexTaskPageContract.test.ts. - Fixed Voice session Codex row visual artifact (
copilot-oh19): removed unintended inlineОткрыть задачу в OperOpstext fragment from row content while preserving OperOps navigation action; updatedapp/__tests__/voice/sessionCodexTasksFilterOrderContract.test.ts. - Completed Wave 1 voice-operops-codex rollout items and closed
copilot-b1k5,copilot-s33e,copilot-u976,copilot-xuec; epiccopilot-bq81stays in progress for later waves. - Canonicalized performer lifecycle filtering (
is_deletedprimary, legacyis_active/activecompatibility) across Voice/CRM selectors with historical-id passthrough for edit safety. - Added
git_repoproject contract support end-to-end (backend create/update/list + frontend types/edit form) and enforced Codex assignment guard inPOST /api/voicebot/create_tickets. - Extended Telegram
@taskingress path to persist normalized task payload to session and create Codex task from the same payload contract. - Increased Voice possible-task performer selector popup height with responsive desktop/mobile sizing and contract tests.
- Switched voice session close initiation to REST-only client path: frontend store and WebRTC runtime now call
POST /api/voicebot/session_done(with/close_sessionalias support), and no longer emit browser-sidesession_doneover Socket.IO. - Added canonical backend close route in sessions API (
backend/src/api/routes/voicebot/sessions.ts) with Zod payload validation, permission/access checks, sharedcompleteSessionDoneFlowexecution, and realtimesession_status/session_updateemissions. - Added backend regression test
backend/__tests__/voicebot/sessionDoneRoute.test.tsto lock REST close behavior and alias parity. - Updated Voice Sessions list ordering in
app/src/pages/voice/SessionsListPage.tsx: active sessions first, then latest voice activity, then creation time with mixed-format timestamp normalization. - Fixed WebRTC FAB
Doneclose reliability for/voice/session/:id: runtime now retriessession_doneacross namespace base candidates (origin, stripped/api, full API base) and treats all failed attempts as close failure. - Added fail-safe close UX: on
session_donefailure FAB stays inpausedwith toastFailed to close session. Retry Done.and does not clear active session metadata. - Updated regression contract
app/__tests__/voice/webrtcSessionDoneSocketContract.test.tsfor fallback namespace attempts and strict failed-close handling. - Fixed voice sessions deleted-mode sync (
copilot-nhwu):SessionsListPagenow forces list refetch whensessionsListIncludeDeleteddiffers from currentshowDeletedSessionsintent. - Updated store fetch guard so
fetchVoiceBotSessionsList({ force: true })can run while list loading is active for required mode synchronization. - Added regression test
app/__tests__/voice/sessionsListIncludeDeletedSyncContract.test.ts. - Restored notify transport path for voice summarize events:
actions@callcommand fixed in/home/tools/server/mcp/call.env,/notifynow healthy (200). - Added TS local notify hooks parity in
backend/src/workers/voicebot/handlers/notify.ts:VOICE_BOT_NOTIFY_HOOKS_CONFIGsupport (YAML/JSON, default./notifies.hooks.yaml, empty disables),- detached hook spawn + structured logs,
- session-log events
notify_hook_started,notify_http_sent,notify_http_failed.
- Added sample hooks config
backend/notifies.hooks.yamland targeted regression testbackend/__tests__/voicebot/notifyWorkerHooks.test.ts. - Hardened TS notify hooks diagnostics:
- per-hook stdout/stderr is persisted into
VOICE_BOT_NOTIFY_HOOKS_LOG_DIR(default./logs/voicebot-notify-hooks); notify_hook_started.metadata.log_pathnow stores exact hook log path;- hook spawn failures are persisted as
notify_hook_failedinautomation_voice_bot_session_log.
- per-hook stdout/stderr is persisted into
- Added Voice Sessions list URL-state workflow (
tab, filters, pagination) with inline project reassignment and active-project-only selectors (app/src/pages/voice/SessionsListPage.tsx). - Added MeetingCard dialogue-tag editing with remembered local tag options and persisted
dialogue_tagupdates. - Updated done UX/state flow: frontend applies immediate ack-driven close projection, listens for
session_status=done_queued, and backend socket emits immediatesession_updateonsession_done. - Added deduplicated immediate common-queue processing kick in shared done flow (
backend/src/services/voicebotSessionDoneFlow.ts) to reduce finalize lag after session close. - Hardened CREATE_TASKS postprocessing to enqueue pending CATEGORIZE jobs before delayed retry when categorization is incomplete.
- Added mixed-identifier performer normalization for CRM ticket create/update and Miniapp task performer matching compatibility (
id/_id/ObjectId). - Canonicalized Voice/TG public session links to
https://copilot.stratospace.fun/voice/session[/<id>]and addedVOICE_WEB_INTERFACE_URLsample default inbackend/.env.example. - Added
splitAudioFileByDuration(...)ffmpeg helper in backend audio utilities for deterministic segment generation. - Added deferred migration spec
plan/session-done-notify-routing-migration.mdfor immediate done notifications and routing ownership move from JSON config to Copilot DB targets. - Added tracked ontology package under
ontology/typedb/(TypeQL schema, Mongo mapping, validation query set, rollout plan) to keep TypeDB model assets versioned in Copilot. - Updated Voice transcription download flow to use
/api/voicebot/transcription/download/:session_idwith runtime-safe markdown export handling and Jest coverage. - Added backend TypeDB ontology helper tooling (canonical paths under
ontology/typedb/scripts/, npm aliases, and.envsample variables) for STR OpsPortal model ingestion. - Switched OperOps Projects Tree editing to modal-based UX and removed split-pane edit card flow.
- Synced local bd SQLite metadata/config files and stored Dolt migration import/backup artifacts in
.beads/. - Added
plan/deep-research-oss-platforms-operops-finops.report.draft.md(draft) summarizing platform research options for OperOps/FinOps/Guide/Voice and phased implementation recommendations. - Added
ontology/fpf-erd-extraction-protocol-str-opsportal.mdandontology/str-opsportal-erd-draft-v0.mdfor STR OpsPortal ERD extraction protocol definition and the initial consolidated ERD draft. - Extracted shared Voice
completeSessionDoneFlowservice and switched socketsession_donepath to it for unified close/notify behavior. - Added idle-active-session close automation script (
backend/scripts/voicebot-close-inactive-sessions.ts) and npm commandsvoice:close-idle:dry|applywith JSON/JSONL outputs for operations. - Added session-specific diagnostics helper script
backend/scripts/tmp-explain-69981f2e.tsfor transcription/chunk payload inspection. - Completed Waves 2-5 and merged all implementation commits to
main:- Wave 2 (
copilot-yqst,copilot-m2uw,copilot-8yuq,copilot-dkj6,copilot-aonw,copilot-su2v,copilot-grg4,copilot-upqs) - Wave 3 (
copilot-0t2c,copilot-03gp) - Wave 4 (
copilot-l3j6,copilot-c1xj,copilot-zwjl) - Wave 5 (
copilot-2psh,copilot-ex9q,copilot-gb72)
- Wave 2 (
- Added deferred Codex review end-to-end lifecycle:
- worker job
VOICEBOT_JOBS.common.CODEX_DEFERRED_REVIEW, - issue-note persistence and Telegram approval cards,
- Telegram callback actions
cdr:start:*/cdr:cancel:*.
- worker job
- Added Voice taskflow tabs and APIs:
- Voice
Задачиtab scoped by currentsource_ref, - Voice
Codextab backed byPOST /api/voicebot/codex_tasks, - OperOps
Codextab backed byPOST /api/crm/codex/issues(latest 500bdissues).
- Voice
- Added inline Codex task detail drawer in Voice session tab and expanded codex task payload mapping (
labels,dependencies,notes, ownership metadata). - Added canonical Codex external reference contract (
https://copilot.stratospace.fun/voice/session/<id>) across voice-created tasks. - Added transcribe trigger flow (
Codex/Кодекс) and improved@taskingestion:- auto-create Codex session when no active session exists,
- normalize and append canonical attachment links in created task descriptions.
- Completed categorization/material chain:
copilot-hfvd: hideUnknownspeaker labels,copilot-c4bd:Materialscolumn replacing quick-summary behavior,copilot-a3k0: pale metadata signature line,copilot-p31k: image/text row-group cross-link model,copilot-250m: explicit row-level material targeting withimage_anchor_linked_message_id.
- Closed dependency branch
copilot-eejo -> (copilot-a3k0,copilot-c4bd,copilot-hfvd) -> copilot-p31k -> copilot-250m. - Closed coordinating epic
copilot-bq81;bd readyqueue is empty. - Fixed
/session_donepermission compatibility inbackend/src/api/routes/voicebot/sessions.ts: replaced unavailable route-levelrequirePermissioncall with inlinegetUserPermissions+VOICEBOT_SESSIONS.UPDATEcheck. - Re-ran full test scope after the fix:
appJest (50suites,113tests) andbackendJest (76suites,365tests) both passed.