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:
parent
9fc5af5b2b
commit
53c3565874
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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>);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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(() => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user