The platform-service build was failing with 3 unrelated TS errors,
surfaced while running the Gitea outdated-package detector earlier
in this session:
src/server.ts(18,8): Cannot find module '@bytelyst/devops/server'
src/server.ts(318,61): Property 'cosmosEndpoint' does not exist on type 'ProductIdentity'
src/server.ts(321,42): Property 'platformServiceUrl' does not exist on type 'ProductIdentity'
Root causes (two distinct bugs):
1. Stale install. '@bytelyst/devops' was already declared as
'workspace:*' in services/platform-service/package.json (line 24),
but node_modules/@bytelyst/devops/ did not exist. Re-running
'pnpm install' at the workspace root materialised the symlink.
2. Variable shadowing. In the GET /devops/info handler the code
declared a local 'const config' from loadProductIdentity() that
shadowed the module-level 'config' (env vars) imported from
'./lib/config.js' at line 112. The author then tried to read
'config.cosmosEndpoint' and 'config.platformServiceUrl' off the
ProductIdentity, where those keys never exist:
ProductIdentity = {
productId, displayName, licensePrefix, configDirName,
envVarPrefix, bundleIdSuffix, packageName
}
The intended values live on the env config:
config.COSMOS_ENDPOINT (Zod-validated, required at boot)
config.HOST + config.PORT (defaults '0.0.0.0' / 4003)
There is no 'platformServiceUrl' field anywhere in the codebase —
it only appeared in this single buggy line. Reconstructed as
'\${HOST}:\${PORT}' which is the URL admins would use to reach
this service for the devops/info diagnostic dashboard.
Fix (services/platform-service/src/server.ts:310-339):
- Rename local 'const config' to 'const productIdentity' to break
the shadowing.
- Use productIdentity.productId for the devops productId field.
- Use config.COSMOS_ENDPOINT (the env config) for the cosmos
dependency health check URL.
- Use `http://${config.HOST}:${config.PORT}` for the extra
platformServiceUrl field.
- Add a doc comment block explaining the two-config distinction
so future contributors don't reintroduce the shadow.
Verified:
pnpm --filter @lysnrai/platform-service build OK (0 errors)
pnpm --filter @lysnrai/platform-service test 1511/1512 pass
The 1 remaining failure (src/modules/products/cache.test.ts line 104,
'returns all cached products' expects 2 products but got 3) is a
PRE-EXISTING product-registry test drift on main, verified by
stashing this commit's changes and re-running the same test against
the unmodified tree. It will be addressed separately.
Baseline pnpm-lock.yaml on origin/main was missing entries for
packages/billing-client and packages/webhook-dispatch (their
package.json files list typescript + vitest devDependencies that the
lockfile didn't reflect). Any pnpm install --frozen-lockfile — in CI,
in services/platform-service/Dockerfile, in services/mcp-server/Dockerfile,
in services/extraction-service/Dockerfile — therefore failed with
ERR_PNPM_OUTDATED_LOCKFILE.
Ran pnpm install which regenerated the lockfile deterministically; the
net diff cleans up a large amount of stale phantom entries while adding
the two missing package entries. After the refresh,
pnpm install --frozen-lockfile succeeds.
This is W1 baseline-repair scope (similar to commit a954f434 for lint).
It does NOT fully restore the full-stack docker compose smoke because
services/platform-service/Dockerfile also has a separate pre-existing
bug: @bytelyst/react-native-platform-sdk runs `tsc` in its prepare
script, but pnpm install runs prepare scripts before the Dockerfile
COPY packages/ step brings in source — so tsc has nothing to compile
and fails. That Dockerfile is outside W1's Files-You-Own and needs
a separate fix (either remove/no-op the prepare script, use pnpm
install --ignore-scripts, or COPY source before install).
Gap: none (baseline repair supporting INFRA-gap-01)
Verified: pnpm install --frozen-lockfile (clean), pnpm -r typecheck /
lint / build / test (all green), docker compose build
cowork-service + docker compose up -d cowork-service --wait
(still Healthy), curl localhost:4009/health (200 OK).
Added LLM routing module to cowork-service:
- lib/llm-router.ts — singleton LlmRouter with cloud + local Ollama support
- modules/llm/types.ts — Zod request schemas
- modules/llm/routes.ts — POST /api/llm/chat, GET /api/llm/providers, GET /api/llm/health
- All endpoints gated by llm_multi_model_enabled feature flag
- Best-effort init: service works without API keys (router stays uninitialized)
- 8 new tests (routes), server test updated for 3 route modules
- 57 total tests passing, typecheck clean
- GET /auth/mfa/totp/secret — retrieve decrypted TOTP secret for auth app
- POST /auth/mfa/push/create, GET /pending, POST /:id/respond, GET /:id/status
- POST /auth/qr/create, POST /auth/qr/confirm, GET /auth/qr/:id/status
- Kotlin SDK: getTotpSecret, getPendingApprovals, respondToApproval, confirmQrLogin
- Swift SDK: getTotpSecret, getPendingApprovals, respondToApproval, confirmQrLogin
- All 53 auth tests passing
- Update kill-switch-client and feature-flag-client tests to use
expect.objectContaining for headers to handle x-request-id
- Move React Native SDK roadmap to completed/
Total: 44 client-side package tests passing
- add idb dependency and create typed db layer (conversations/messages/agents/etc)
- extend app/lib/types.ts with v4 workspace interfaces
- move existing dashboard to /mission-control route group
- create / workspace route group with sidebar shell and conversation pages
- implement conversation list grouping + search in sidebar
- implement conversation view with streaming via /api/ollama/chat
- add context bar and token/context utilities
- add /api/ollama/title endpoint for auto-title generation
- add v3->v4 migration utility (llm-inference-log + llm-chat-* to indexeddb)
- wire migration in workspace layout and cmd+/ sidebar toggle
Implements roadmap Phase A tasks A1-A8.