fix(cowork-service): audit flush field name mismatch + server test mock gap

BUG: flush-scheduler.ts flushAudit() read 'events' from IPC response but
Rust handle_flush_audit() returns { count, entries }. Audit events were
silently lost (always empty array). Fixed to read 'entries'.

Also fixed:
- server.test.ts: added missing flush-scheduler.js mock (new import in server.ts)
- feature-flags.ts: doc comment '12 flags' → '13 flags'
- flush-scheduler.test.ts: mock data aligned to Rust response shape

49 tests passing, 8 test files, typecheck clean.
This commit is contained in:
saravanakumardb1 2026-04-02 23:02:38 -07:00
parent 9fc5af5b2b
commit 53c3565874
8 changed files with 157 additions and 15 deletions

View File

@ -1,8 +1,12 @@
# All workspace repositories
# Single source of truth for repo-management workflows
# Reference this file in scripts instead of hardcoding repo lists
# All workspace repositories — SINGLE SOURCE OF TRUTH
# Used by all /repo_* workflows and scripts (backup, commit, push, sync, agent-docs)
# Paths are relative to ~/code/mygh/ (the workspace root)
# To add a new repo: append its path here and all workflows will pick it up automatically
# --- Platform & shared ---
learning_ai_common_plat
# --- Product repos ---
learning_voice_ai_agent
learning_multimodal_memory_agents
learning_ai_clock
@ -13,6 +17,16 @@ learning_ai_notes
learning_ai_flowmonk
learning_ai_trails
learning_ai_local_memory_gpt
learning_ai_efforise
learning_ai_local_llms
# --- Auth & identity ---
learning_ai_smart_auth
learning_ai_auth_app
# --- Web & misc ---
learning_ai_productivity_web
# --- OSS (subdirectory repos under oss/) ---
oss/learning_ai_claw-code-oss
oss/learning_ai_claw-cowork

View File

@ -1,9 +1,9 @@
Last refresh: 2026-04-02T17:27:25Z (2026-04-02 10:27:25 PDT)
Cascade conversations: 50 (330M)
Memories: 119
Last refresh: 2026-04-03T06:00:06Z (2026-04-02 23:00:06 PDT)
Cascade conversations: 50 (297M)
Memories: 121
Implicit context: 20
Code tracker dirs: 102
File edit history: 4201 entries
Code tracker dirs: 106
File edit history: 4222 entries
Workspace storage: 37 workspaces
Repo docs: 7 files across 2 repos
Repo workflows: 54 files across 12 repos

View File

@ -1,8 +1,12 @@
# All workspace repositories
# Single source of truth for repo-management workflows
# Reference this file in scripts instead of hardcoding repo lists
# All workspace repositories — SINGLE SOURCE OF TRUTH
# Used by all /repo_* workflows and scripts (backup, commit, push, sync, agent-docs)
# Paths are relative to ~/code/mygh/ (the workspace root)
# To add a new repo: append its path here and all workflows will pick it up automatically
# --- Platform & shared ---
learning_ai_common_plat
# --- Product repos ---
learning_voice_ai_agent
learning_multimodal_memory_agents
learning_ai_clock
@ -13,6 +17,16 @@ learning_ai_notes
learning_ai_flowmonk
learning_ai_trails
learning_ai_local_memory_gpt
learning_ai_efforise
learning_ai_local_llms
# --- Auth & identity ---
learning_ai_smart_auth
learning_ai_auth_app
# --- Web & misc ---
learning_ai_productivity_web
# --- OSS (subdirectory repos under oss/) ---
oss/learning_ai_claw-code-oss
oss/learning_ai_claw-cowork

View File

@ -174,6 +174,28 @@ set_meta() {
LINT2="cd android && ./gradlew :app:assembleDebug 2>&1 | tail -20"
AIDER_READ2="README.md"
;;
learning_ai_efforise)
NAME="EffoRise"
ID="efforise"
TAGLINE="Identity-based habit tracker"
STACK="Vite + React 19 SPA (client/) + Fastify 5 backend (backend/) + React Native/Expo (mobile/) + @bytelyst/* shared packages"
BUILD_VFY="cd backend && pnpm test && pnpm run typecheck && pnpm run build"
LINT1="cd backend && pnpm test 2>&1 | tail -10"
LINT2="cd backend && pnpm run typecheck 2>&1 | tail -10"
LINT3="cd backend && pnpm run build 2>&1 | tail -10"
AIDER_READ2="README.md"
;;
learning_ai_local_llms)
NAME="Local LLM Lab"
ID="localllmlab"
TAGLINE="Personal local AI inference toolkit"
STACK="Next.js 16 (dashboard) + Ollama + @bytelyst/llm-router + Python (TTS)"
BUILD_VFY="cd dashboard && pnpm test && pnpm typecheck && pnpm build"
LINT1="cd dashboard && pnpm test 2>&1 | tail -10"
LINT2="cd dashboard && pnpm typecheck 2>&1 | tail -10"
LINT3="cd dashboard && pnpm build 2>&1 | tail -10"
AIDER_READ2="README.md"
;;
learning_ai_productivity_web)
NAME="Productivity Web"
ID="(internal)"
@ -184,6 +206,28 @@ set_meta() {
LINT2="npm run build 2>&1 | tail -10"
AIDER_READ2="README.md"
;;
oss/learning_ai_claw-code-oss)
NAME="Claw Code OSS"
ID="(upstream)"
TAGLINE="Upstream Claude Code OSS fork — runtime, API, and tools crates"
STACK="Rust (workspace) + Python + TypeScript"
BUILD_VFY="cargo build --workspace && cargo test --workspace"
LINT1="cargo fmt --check 2>&1 | tail -10"
LINT2="cargo clippy --workspace --all-targets -- -D warnings 2>&1 | tail -10"
LINT3="cargo test --workspace 2>&1 | tail -10"
AIDER_READ2="README.md"
;;
oss/learning_ai_claw-cowork)
NAME="Claw Cowork"
ID="clawcowork"
TAGLINE="Desktop agent for complex multi-step knowledge work with Docker sandboxing"
STACK="Rust (workspace) + React/TypeScript (Tauri frontend) + Python (skills server)"
BUILD_VFY="cargo build --workspace && cargo test --workspace"
LINT1="cargo fmt --check 2>&1 | tail -10"
LINT2="cargo clippy --workspace --all-targets -- -D warnings 2>&1 | tail -10"
LINT3="cargo test --workspace 2>&1 | tail -10"
AIDER_READ2="COWORK.md"
;;
*)
warn "Unknown repo: $1 — skipping"
return 1
@ -299,6 +343,22 @@ repo_rules() {
echo "- Theme via BLAuthUIConfig (iOS) / MaterialTheme (Android)"
echo "- Never create a separate backend — app talks to platform-service"
;;
learning_ai_efforise)
echo "- Backend follows the ByteLyst product-backend pattern with Fastify 5 + TypeScript ESM"
echo "- Use @bytelyst/* shared packages instead of reimplementing common infrastructure"
echo "- Fastify modules follow types.ts → repository.ts → routes.ts"
echo "- Use req.log / app.log — never console.log"
echo "- Every Cosmos document MUST include productId: \"efforise\""
echo "- Theme tokens use --er-* CSS custom properties — never hardcode colors"
;;
learning_ai_local_llms)
echo "- Dashboard uses server-side routing — keep UI as thin client"
echo "- @bytelyst/llm-router from Gitea npm registry (not file: ref)"
echo "- Never commit model weights (.gguf, .bin, .safetensors)"
echo "- Never hardcode Ollama URLs — use OLLAMA_HOST env var"
echo "- Corporate proxy: use hf-mirror.com instead of huggingface.co"
echo "- CSS tokens use --llm-* prefix"
;;
learning_ai_productivity_web)
echo "- App Router pages live in src/app/"
echo "- Reusable UI lives in src/components/"
@ -306,6 +366,21 @@ repo_rules() {
echo "- Keep UI changes thin and tool-registry-driven where possible"
echo "- Avoid inventing APIs or hidden backend contracts"
;;
oss/learning_ai_claw-code-oss)
echo "- Upstream claw-code fork — do NOT add custom features here"
echo "- Periodically pull from upstream and merge"
echo "- Rust crates: runtime, api, tools (consumed by claw-cowork)"
echo "- Python client: tests/, scripts/"
echo "- TypeScript SDK: ts-sdk/"
;;
oss/learning_ai_claw-cowork)
echo "- Docker-first sandbox — native VM backends are stubs"
echo "- Python skills inside sandbox for document processing"
echo "- Tauri v2 for desktop GUI — Rust backend + React frontend"
echo "- Async architecture — bollard (Docker API) is async"
echo "- Base64 encoding for file content passed to sandbox"
echo "- Use conventional commit prefixes: feat(), fix(), docs:, test:, refactor:"
;;
esac
}
@ -405,12 +480,42 @@ repo_paths() {
echo "- shared/product.json — canonical product identity"
echo "- ios/project.yml and android/ build files — native project wiring"
;;
learning_ai_efforise)
echo "- client/ — Vite + React 19 SPA"
echo "- backend/ — Fastify 5 + TypeScript ESM backend (port 4020)"
echo "- backend/src/modules/ — identities, efforts, habits, streaks, insights"
echo "- mobile/ — React Native + Expo (SDK 55) companion app"
echo "- mobile/src/app/(tabs)/ — 5-tab navigator (Home, Identity, Log, Insights, Settings)"
;;
learning_ai_local_llms)
echo "- dashboard/ — Mission Control Next.js 16 app"
echo "- dashboard/src/app/api/ — Ollama proxy, Whisper, TTS, system info"
echo "- dashboard/src/app/(mission-control)/ — System overview, model management"
echo "- tts/ — TTS setup scripts + experiments"
echo "- scripts/ — start-dashboard.sh + windows setup"
echo "- experiments/ — oss-llm, open-claw, voicebox"
;;
learning_ai_productivity_web)
echo "- src/app/ — App Router pages and routes"
echo "- src/components/ — Navbar and tool cards"
echo "- src/lib/ — utility and tool registry helpers"
echo "- next.config.ts, tailwind.config.ts — web app configuration"
;;
oss/learning_ai_claw-code-oss)
echo "- rust/crates/runtime/ — ConversationRuntime, Session, PermissionPolicy"
echo "- rust/crates/api/ — AnthropicClient, AuthSource, SSE streaming"
echo "- rust/crates/tools/ — ToolSpec, tool dispatch"
echo "- python/ — Python client SDK"
echo "- ts-sdk/ — TypeScript SDK"
;;
oss/learning_ai_claw-cowork)
echo "- crates/cowork-vm/ — Sandbox lifecycle (Docker, VZ abstraction)"
echo "- crates/cowork-orchestrator/ — Task coordination, LLM planner, plugins, MCP"
echo "- crates/cowork-skills/ — Rust↔Python bridge for document processing"
echo "- crates/cowork-desktop/ — Tauri v2 desktop app (Rust + React)"
echo "- docker/ — Dockerfile + Python skills server"
echo "- connectors/ — MCP connector servers (Google Drive, Gmail, GCal, Slack)"
;;
esac
}

View File

@ -1,7 +1,7 @@
/**
* Feature flag registry for cowork-service.
*
* Defaults match the 12 platform flags seeded in H.1
* Defaults match the 13 platform flags seeded in H.1
* (platform-service/src/modules/flags/seed.ts clawcowork entry).
*/
import { createFlagRegistry } from '@bytelyst/backend-flags';

View File

@ -45,7 +45,7 @@ const mockLog = {
function createMockBridge(running = true) {
return {
isRunning: running,
flushAudit: vi.fn().mockResolvedValue({ result: { count: 2, events: [
flushAudit: vi.fn().mockResolvedValue({ result: { count: 2, entries: [
{ userId: 'u1', action: 'task.submit', category: 'task', details: {} },
{ userId: 'u2', action: 'task.cancel', category: 'task', details: {} },
] } }),
@ -133,7 +133,7 @@ describe('FlushScheduler', () => {
it('handles empty IPC responses', async () => {
const bridge = createMockBridge(true);
bridge.flushAudit.mockResolvedValue({ result: { count: 0, events: [] } });
bridge.flushAudit.mockResolvedValue({ result: { count: 0, entries: [] } });
bridge.flushTelemetry.mockResolvedValue({ result: { count: 0, events: [] } });
bridge.flushBudget.mockResolvedValue({ result: { count: 0, records: [] } });
vi.mocked(getIpcBridge).mockReturnValue(bridge as unknown as ReturnType<typeof getIpcBridge>);

View File

@ -115,7 +115,8 @@ export class FlushScheduler {
return null;
}
const r = resp.result as Record<string, unknown> | undefined;
const entries: AuditEntry[] = (r?.events as AuditEntry[]) ?? [];
// Rust flush_audit returns { count, entries } — NOT "events"
const entries: AuditEntry[] = (r?.entries as AuditEntry[]) ?? [];
if (entries.length === 0) return { drained: 0, posted: 0, errors: 0 };
const { posted, errors } = await postAuditEvents(entries);

View File

@ -54,6 +54,14 @@ vi.mock('./lib/ipc-bridge.js', () => ({
shutdown: vi.fn(async () => undefined),
})),
}));
vi.mock('./lib/flush-scheduler.js', () => ({
getFlushScheduler: vi.fn(() => ({
isRunning: false,
start: vi.fn(),
stop: vi.fn(),
finalFlush: vi.fn(async () => undefined),
})),
}));
describe('cowork-service bootstrap', () => {
beforeEach(() => {