LogisticsRnD now reports its failures to Chief
One logger, wired into every entry point, sends labelled warning and error events from any user to Chief, so Chief can group them into issues. Merging and deploying are up to Chief's test gate; nothing here is live in production yet.
~100API routes covered through one wrapper
38existing error/warn logs converted
13of them downgraded or marked expected
366/366tests passing (10 new)
Before → after
- API failures: only 5xx were printed, as raw stack traces → every failure is a labelled event, e.g.
api.logistics.desk.requests.deliver, with the route pattern and status in ctx. - Failed analyses, drafts, B/L requests, assistant runs, dashboard builds and syncs: recorded only as a status on screen → each also sends an event with its ids. Failed analyses include the stage, the Python step and the traceback tail.
- Browser crashes: never reached the server → relayed to Chief through an authenticated endpoint.
- Log text: raw messages that included addresses and ids → scrubbed templates. The Telegram pairing code is no longer printed at startup.
How it works
src/lib/chiefLog.tsbuilds Chief's event format, writes the same scrubbed line to the server log, and in production sends events in batches every 3 seconds.- If Chief can't be reached, events wait in a file on the data volume and are sent once it answers. This buffer only guarantees delivery: every event is already in the server log, and the outage itself is reported there.
- When the same error object is caught and logged at several layers, only the first log line opens an issue in Chief. The later ones are kept as info.
- Each event carries the deployed commit (
release) and the workspace id (user, a random UUID, never a name or address).
What reports what
| Area | Events |
|---|---|
| Every API route | api.<route>: refusals warn, defects and 5xx error, signed-out/stale tab expected |
| Pages, server actions, proxy, process | unhandled.*, process.uncaught_exception, process.unhandled_rejection |
| Browser | client.uncaught_error, client.unhandled_rejection (React render crashes arrive this way too) |
| Logistics | analysis created/queued/ready/failed, upload completed, checklist, document drafts, B/L request drafted/delivered/refused by Outlook |
| Claude runs | llm.subscription_run (every failed model run, limits are warnings), llm.tool_failed |
| Assistant, dashboards, knowledge | request failed/succeeded, build and refresh failures, extraction and indexing failures |
| Approved external writes | proposals.execution_failed, proposals.invite_email_failed, proposals.executed |
| Background jobs | jobs.<job> per workspace; a busy lease is expected |
| Integrations | sync, Composio rate limits, GitHub, data connections, Recall webhooks and calls, Telegram, Browser Use, voice |
| Auth and health | sign-in, sign-in failed, sign-out revoke failed, health check failed |
Existing logs: audit result
All 38 server-side console.error/console.warn calls are now Chief events with fixed message templates. The error text goes to ctx and the stack.
- 13 downgraded or marked expected where they were the system working. Examples: Composio not answering on the status page; Telegram poll outages, now one event for the first failure and every tenth after; a refused card edit; OpenAI rate limits; voice tool refusals; a workspace still being prepared (503); busy leases in background ticks; Telegram login-code typos.
- Values moved out of the message: workspace id, analysis id, report path, HTTP status, tool name and counts. Repositories and chats are identified by a short hash.
Verification
npm test: 366/366 passed. The 10 new tests cover the event format, size caps, scrubbing, batching, spool-and-drain, refusals being dropped, one-error-one-issue, route classification, and route/page lists matching the files.eslint .andtscare clean.next buildsucceeds with only the 9 warnings that were already there.- Live ingest: one info smoke event was accepted by Chief (HTTP 202,
accepted: 1), once by curl and once through the logger's own transport, with nothing spooled. - Real browser (local Browser Use, local dev server): an error and a promise rejection thrown in
/logisticsand/logistics/documentsarrived asclient.*events. The test name, email address and UUID in them were masked.
Not done or not verified
- Not deployed. Production shipping starts with the next
deploy/deploy-logistics.shrun after Chief merges, and has not been observed there yet. - The React render-crash path was checked by reading Next 16's code (it calls
window.reportError), not by crashing a page. - Not logged: proxy refusals (exceptions there are logged), the voice tool's input refusals, and the local-only codex test runner. The Python pipeline reports through the Node step that runs it.
- Scrubbing masks addresses, URLs, quoted text, file names, ids and tokens. A multi-word name written without quotes inside an error sentence can still get through.
- The existing mail-sync run log still prints lines to the server's stdout. Those lines can include addresses; they stay on the server and are not sent to Chief.
Tradeoffs
- The ingest token is written into the code instead of an environment variable. It can only append log events, and the repository is private. This way production logging can't silently go dark because a server setting is missing.
- A failed Outlook send or approved write is logged as an error even when the provider refused, because the person's action did not happen.
- The server log shows the scrubbed text rather than raw messages. Nothing local holds raw personal data, at some cost to local debugging.
Branch and commits
- chief/38c18fdf1d (private repository)
b056b39logger and entry points ·78041d1feature instrumentation ·797988edocs