# Fastify Core Audit and Remediation Roadmap

> **Date:** 2026-03-06
> **Scope:** `learning_ai_common_plat` plus all product backends currently consuming `@bytelyst/fastify-core`
> **Method:** Static code audit of service entrypoints, shared wrapper package, and adoption patterns
> **Auditor:** Cascade
> **Status:** Baseline audit complete; remediation roadmap proposed

---

## Table of Contents

1. [Executive Summary](#1-executive-summary)
2. [Scope and Files Reviewed](#2-scope-and-files-reviewed)
3. [Current State Snapshot](#3-current-state-snapshot)
4. [What Is Working Well](#4-what-is-working-well)
5. [Detailed Findings](#5-detailed-findings)
6. [Duplication Inventory](#6-duplication-inventory)
7. [Performance and Operational Assessment](#7-performance-and-operational-assessment)
8. [Target Architecture](#8-target-architecture)
9. [Remediation Roadmap](#9-remediation-roadmap)
10. [Implementation Backlog](#10-implementation-backlog)
11. [Success Metrics](#11-success-metrics)
12. [Recommended Rollout Order](#12-recommended-rollout-order)
13. [Validation and Rollout Guardrails](#13-validation-and-rollout-guardrails)
14. [Non-Goals](#14-non-goals)
15. [Appendix A: Audited Entry Points](#appendix-a-audited-entry-points)
16. [Appendix B: Proposed `fastify-core` API Evolution](#appendix-b-proposed-fastify-core-api-evolution)

---

## 1. Executive Summary

### Overall Assessment: **GOOD FOUNDATION, NOT FULLY DRY**

The ecosystem has already converged on a strong shared Fastify wrapper pattern. The common platform services and all audited product backends use `@bytelyst/fastify-core` for base app creation and service startup. This is the correct architectural direction and has already eliminated a large amount of bootstrap drift.

However, the current state is **not yet fully optimized, fully DRY, or fully standardized**.

The main issue is no longer "are services using the wrapper?" The answer to that is mostly **yes**. The real issue is that **important logic still lives above the wrapper layer and is duplicated across services**, especially:

- Optional JWT parsing hooks
- Startup sequencing and service initialization
- Route registration boilerplate
- Lifecycle and shutdown policy decisions
- Readiness and operational conventions

There are **no major request-path performance defects** identified in `@bytelyst/fastify-core` itself. The most important gaps are in **maintainability, consistency, operational ergonomics, and long-term drift prevention**.

### Bottom Line

| Area                                | Assessment          |
| ----------------------------------- | ------------------- |
| Wrapper adoption                    | Good                |
| DRY at bootstrap layer              | Partial             |
| Consistency across services         | Good but incomplete |
| Request-path performance            | Acceptable          |
| Operational maturity                | Needs improvement   |
| Test coverage for wrapper evolution | Incomplete          |
| Risk of drift                       | Medium              |

### Most Important Conclusions

- `@bytelyst/fastify-core` is already the standard entrypoint wrapper and should remain so.
- The wrapper should be expanded to absorb repeated auth, lifecycle, and bootstrap patterns.
- The next phase should focus on **centralizing duplicated service logic**, not replacing the Fastify choice.
- The immediate goal should be to remove duplicated server bootstrap code from every backend while preserving product-specific route composition.

---

## 2. Scope and Files Reviewed

### Shared Package Reviewed

- `packages/fastify-core/src/create-app.ts`
- `packages/fastify-core/src/start.ts`
- `packages/fastify-core/src/types.ts`
- `packages/fastify-core/src/index.ts`
- `packages/fastify-core/src/__tests__/fastify-core.test.ts`

### Common Platform Services Reviewed

- `services/platform-service/src/server.ts`
- `services/extraction-service/src/server.ts`
- `services/mcp-server/src/server.ts`

### Product Backend Entry Points Reviewed

- `learning_voice_ai_agent/backend/src/server.ts`
- `learning_multimodal_memory_agents/backend/src/server.ts`
- `learning_ai_clock/backend/src/server.ts`
- `learning_ai_jarvis_jr/backend/src/server.ts`
- `learning_ai_fastgap/backend/src/server.ts`
- `learning_ai_peakpulse/backend/src/server.ts`

### Supporting Evidence Reviewed

- `services/platform-service/src/server.test.ts`
- `packages/testing/src/__tests__/testing.test.ts`
- Relevant package manifests and Dockerfiles for runtime verification

### Audit Boundaries

This audit focuses on:

- Fastify app creation
- Shared wrapper adoption
- Duplication in service bootstrapping
- Operational conventions exposed by the wrapper
- High-level performance and lifecycle concerns

This audit does **not** perform load testing, production benchmarking, or live traffic profiling.

### Scope Clarification

- **This is an audited-entrypoint review, not a proof of universal adoption in every historical file.**
- Conclusions in this document refer to the service entrypoints and shared package files listed in scope.
- If additional services or legacy bootstrap files exist outside the audited list, they should be checked separately before declaring workspace-wide completion.

---

## 3. Current State Snapshot

### Current Wrapper Responsibilities

Today, `@bytelyst/fastify-core` provides:

- Fastify app creation
- Shared logger initialization
- CORS registration
- Optional Swagger registration
- Optional Swagger UI registration
- Optional Prometheus metrics registration
- `x-request-id` propagation
- `/health` endpoint
- `ServiceError`-aware error handling
- Startup helper with listen + shutdown hooks

### Current Adoption Status

All audited runtime entrypoints in scope use:

- `createServiceApp(...)`
- `startService(...)`

This includes:

- Platform service
- Extraction service
- MCP server
- All audited product-specific backends

### Current Design Pattern

Most services follow this shape:

1. Resolve secrets
2. Initialize Cosmos/datastore/cache/migrations
3. Create Fastify app via `createServiceApp(...)`
4. Attach optional JWT parsing hook
5. Register routes one-by-one
6. Start service via `startService(...)`

This pattern is stable, but the repeated steps are only partially centralized.

---

## 4. What Is Working Well

### 4.1 Shared wrapper adoption is already broad

This is the biggest positive finding. The ecosystem is not fragmented across many custom Fastify boots. The shared wrapper is already the norm.

### 4.2 `createServiceApp(...)` solves the right baseline concerns

It centralizes the correct primitives:

- base Fastify instantiation
- CORS
- health endpoint
- metrics/docs support
- shared error handling
- request ID propagation

That gives every service a common operational baseline.

### 4.3 `startService(...)` gives a unified startup path

The shared startup helper ensures every service listens in a consistent way and already attempts graceful shutdown behavior.

### 4.4 Service shape is easy to understand

Across repos, server entrypoints are highly recognizable. This improves onboarding, code review speed, and maintenance.

### 4.5 No severe hot-path performance problem was found

The wrapper does not contain an obvious throughput killer. Most of the remaining work is structural and operational, not about replacing Fastify or reworking request handling.

### 4.6 The current wrapper is intentionally small and therefore low-risk

The existing `fastify-core` package is still relatively narrow in scope. That is a strength because:

- it is easy to reason about
- it has limited hidden behavior
- service code remains explicit

This also means the next round of centralization should be done carefully to avoid turning the wrapper into an opaque framework.

---

## 5. Detailed Findings

### F-001: Wrapper adoption is good, but not sufficient for full standardization

| Field    | Value           |
| -------- | --------------- |
| Severity | Medium          |
| Category | Standardization |
| Status   | Open            |

**Description:**

All audited services are using `@bytelyst/fastify-core`, which is a strong positive. However, significant bootstrap logic still remains duplicated in service entrypoints, so wrapper adoption alone does not mean the system is fully standardized.

**Impact:**

- Shared package is under-leveraged
- Service drift can still happen above the wrapper layer
- New backends may continue copying patterns manually instead of using stronger shared abstractions

**Recommendation:**

Expand the wrapper layer to include auth, initialization, readiness, and route registration helpers.

---

### F-002: Optional JWT parsing hook is duplicated across multiple backends

| Field    | Value                      |
| -------- | -------------------------- |
| Severity | High                       |
| Category | DRY / Security Consistency |
| Status   | Open                       |

**Description:**

Multiple product backends duplicate the same pattern:

- read `Authorization`
- verify bearer format
- call `jwtVerify(...)`
- attach `req.jwtPayload`
- swallow invalid token errors

The platform service implements a slightly different version using its own `verifyToken(...)`, while the MCP server uses a separate `parseJwt` helper.

**Why this matters:**

- This is classic copy/paste drift territory
- Future changes to issuer checks, logging, claims handling, or token types must be repeated manually
- Subtle differences across services can create security and behavior inconsistencies

**Recommendation:**

Move optional JWT parsing into `@bytelyst/fastify-core`.

**Proposed direction:**

- `registerOptionalJwtContext(app, options)`
- or `createServiceApp({ auth: { mode: 'optional-bearer', verify: ... } })`

---

### F-003: Startup sequencing is duplicated across services

| Field    | Value             |
| -------- | ----------------- |
| Severity | High              |
| Category | DRY / Reliability |
| Status   | Open              |

**Description:**

Service entrypoints repeatedly implement variants of:

- `resolveSecrets(...)`
- `initCosmosIfNeeded()`
- `initDatastore()`
- `loadProductCache()`
- `runPendingMigrations()`
- seed/background startup actions

These are orchestrated manually in each service.

**Risks:**

- Initialization order drift
- Inconsistent failure behavior
- Harder service template creation
- Repeated review burden for new services

**Recommendation:**

Introduce a shared bootstrap orchestration helper in `@bytelyst/fastify-core` or a sibling package.

**Proposed shape:**

```ts
await bootstrapService({
  secrets: [...],
  init: [initCosmosIfNeeded, initDatastore],
  createApp: () => createServiceApp(...),
  register: async app => { ... },
  start: { port, host },
});
```

---

### F-004: Route registration is repetitive and hand-maintained

| Field    | Value           |
| -------- | --------------- |
| Severity | Medium          |
| Category | Maintainability |
| Status   | Open            |

**Description:**

Many services, especially `platform-service`, register routes through long, repeated sequences of:

```ts
await app.register(routeModule, { prefix: '/api' });
```

**Impact:**

- Verbose entrypoints
- Higher chance of omission when modules are added
- Harder to visually review route inventory

**Recommendation:**

Move to declarative registration arrays.

**Proposed direction:**

```ts
for (const route of routes) {
  await app.register(route.plugin, route.options);
}
```

This is primarily a maintainability improvement, not a performance fix.

---

### F-005: `startService(...)` registers process signal handlers on every invocation

| Field    | Value                   |
| -------- | ----------------------- |
| Severity | High                    |
| Category | Lifecycle / Reliability |
| Status   | Open                    |

**Description:**

`startService(...)` calls `process.on('SIGTERM', ...)` and `process.on('SIGINT', ...)` every time it runs.

**Risks:**

- Handler accumulation in repeated boot scenarios
- Duplicate shutdown behavior in tests or embedded runtimes
- Harder reuse of `startService(...)` as a library primitive

**Recommendation:**

Use one of the following:

- `process.once(...)`
- singleton guard for signal registration
- externally managed shutdown registration

This is a real shared-library quality gap.

---

### F-006: `startService(...)` is too opinionated about process termination

| Field    | Value          |
| -------- | -------------- |
| Severity | Medium         |
| Category | Library Design |
| Status   | Open           |

**Description:**

The shared startup helper directly calls:

- `process.exit(0)` on shutdown
- `process.exit(1)` on listen failure

**Why this is limiting:**

- Harder to test cleanly
- Harder to reuse in other hosts or runners
- Prevents higher-level orchestration from deciding process policy

**Recommendation:**

Refactor so the helper can:

- return errors to caller
- optionally exit if configured
- optionally register shutdown without forcing exit policy

---

### F-007: Optional plugin behavior is inconsistent

| Field    | Value                |
| -------- | -------------------- |
| Severity | Medium               |
| Category | Developer Experience |
| Status   | Open                 |

**Description:**

`createServiceApp(...)` treats optional dependencies inconsistently:

- Swagger UI missing => silently skipped
- metrics import path has no equivalent soft-failure policy

**Impact:**

- Missing dependencies may fail unclearly
- Behavior differs across optional features
- Packaging mistakes can hide silently

**Recommendation:**

Standardize plugin loading policy:

- strict mode: fail fast with a clear error
- soft mode: log a warning and skip

---

### F-008: Error responses do not include `requestId`

| Field    | Value       |
| -------- | ----------- |
| Severity | Medium      |
| Category | Operability |
| Status   | Open        |

**Description:**

The wrapper correctly propagates `x-request-id`, but error payloads do not include it.

**Impact:**

- Harder client-side support/debugging
- Users and dashboards cannot easily correlate errors to logs

**Recommendation:**

Include `requestId` in all structured error bodies.

**Proposed shape:**

```json
{
  "error": "Internal server error",
  "requestId": "..."
}
```

---

### F-009: Wrapper provides liveness but not readiness

| Field    | Value      |
| -------- | ---------- |
| Severity | Medium     |
| Category | Operations |
| Status   | Open       |

**Description:**

The shared wrapper exposes `/health` but not `/ready`.

This matters because some services have meaningful startup work:

- secrets resolution
- Cosmos initialization
- migrations
- cache loading
- background job setup

**Impact:**

- Liveness and readiness are conflated
- Harder to model startup state in containers/orchestrators

**Recommendation:**

Add explicit readiness support:

- `/health` => liveness
- `/ready` => readiness

---

### F-010: Request context is implicit and header-driven

| Field    | Value          |
| -------- | -------------- |
| Severity | Low            |
| Category | Design Quality |
| Status   | Open           |

**Description:**

`createServiceApp(...)` mutates `req.headers['x-request-id']` and uses that as the canonical request ID source.

**Impact:**

- Works, but is not the cleanest long-term request context model
- Makes typed request context evolution more awkward

**Recommendation:**

Decorate request with a first-class request context or explicit `requestId` property.

---

### F-011: Shared startup diagnostics are minimal

| Field    | Value         |
| -------- | ------------- |
| Severity | Low           |
| Category | Observability |
| Status   | Open          |

**Description:**

The wrapper does not expose much shared startup visibility:

- no boot duration
- no readiness timestamps
- no route/plugin summary
- no shared startup warnings for optional plugin skips

**Recommendation:**

Add optional startup diagnostics in debug mode.

---

### F-012: Serial startup registration is verbose but not a real performance problem

| Field    | Value         |
| -------- | ------------- |
| Severity | Informational |
| Category | Performance   |
| Status   | Accepted      |

**Description:**

Multiple services register routes serially. This is fine because route registration is startup-only work.

**Assessment:**

Not a meaningful request-time performance concern.

**Recommendation:**

Improve this for readability, not speed.

---

### F-013: Dynamic imports for optional plugins are acceptable

| Field    | Value         |
| -------- | ------------- |
| Severity | Informational |
| Category | Performance   |
| Status   | Accepted      |

**Description:**

`createServiceApp(...)` dynamically imports Swagger and metrics plugins at startup.

**Assessment:**

This is acceptable. It is startup-only cost and not a request-path issue.

**Recommendation:**

No urgent change required.

---

### F-014: Wrapper test coverage does not yet match the proposed roadmap breadth

| Field    | Value                       |
| -------- | --------------------------- |
| Severity | Medium                      |
| Category | Testability / Change Safety |
| Status   | Open                        |

**Description:**

The current `fastify-core` tests cover:

- basic app creation
- `/health`
- request ID propagation
- `ServiceError` handling

However, the roadmap proposes extending the wrapper with:

- readiness support
- auth hook helpers
- lifecycle changes in `startService(...)`
- optional plugin policy changes
- bootstrap orchestration

Those planned areas currently do not have equivalent shared-package test coverage in place.

**Impact:**

- Refactors may regress behavior across many repos at once
- Library-level changes will be harder to ship confidently
- Migration work may rely too heavily on manual verification

**Recommendation:**

Before or alongside each wrapper expansion:

- add focused tests in `packages/fastify-core`
- add at least one consumer integration test using a real service entrypoint
- verify shutdown and startup behavior without relying only on process-level side effects

---

### F-015: Centralizing too aggressively could turn the wrapper into an opaque internal framework

| Field    | Value             |
| -------- | ----------------- |
| Severity | Medium            |
| Category | Architecture Risk |
| Status   | Open              |

**Description:**

The audit recommends centralizing more behavior into shared primitives. That is directionally correct, but there is a tradeoff: if too much service-specific logic gets hidden behind the wrapper, debugging and onboarding become harder.

**Risks:**

- entrypoints become less explicit
- product-specific boot order assumptions get buried in generic helpers
- future developers may need to understand a mini-framework before changing a service

**Recommendation:**

Adopt a strict rule for shared abstractions:

- `fastify-core` should own platform-wide mechanics
- service-specific business bootstrapping should remain visible in service code
- bootstrap helpers should orchestrate explicit hooks, not hide product behavior

---

### F-016: Migration compatibility and rollout risk is not yet called out strongly enough

| Field    | Value        |
| -------- | ------------ |
| Severity | Medium       |
| Category | Rollout Risk |
| Status   | Open         |

**Description:**

Any change to `@bytelyst/fastify-core` affects multiple repositories and services. Even beneficial changes such as adding readiness, changing error response shape, or altering startup behavior can break:

- tests that snapshot response bodies
- operational scripts expecting current endpoints only
- local tooling relying on current exit behavior
- service entrypoints that assume certain startup sequencing

**Recommendation:**

Treat the wrapper as a cross-repo shared contract:

- roll out changes in additive mode first
- preserve backward-compatible defaults where possible
- migrate one reference consumer before broad rollout
- document breaking changes explicitly in the backlog

---

## 6. Duplication Inventory

### 6.1 Duplicated Patterns Observed

| Pattern                                     | Locations                                      | Current Risk |
| ------------------------------------------- | ---------------------------------------------- | ------------ |
| Optional bearer JWT parsing hook            | Product backends, platform-service, mcp-server | High         |
| Startup init orchestration                  | All service entrypoints                        | High         |
| Route registration boilerplate              | Most service entrypoints                       | Medium       |
| JWT issuer and payload handling differences | Across services                                | Medium       |
| Startup failure and shutdown policy         | Centralized but overly opinionated             | Medium       |

### 6.2 What Is Already Properly Centralized

| Concern                   | Centralized? | Notes                                     |
| ------------------------- | ------------ | ----------------------------------------- |
| Fastify app creation      | Yes          | `createServiceApp(...)`                   |
| Health endpoint           | Yes          | `/health`                                 |
| Base error handling       | Yes          | `ServiceError` support                    |
| Request ID propagation    | Yes          | `x-request-id` support                    |
| Shared startup entrypoint | Partially    | `startService(...)` exists but is limited |
| CORS configuration        | Yes          | via wrapper                               |
| Swagger setup             | Yes          | via wrapper                               |
| Metrics setup             | Yes          | via wrapper                               |

### 6.3 Net Assessment

The ecosystem has already centralized the **foundation**, but not yet the **repeated service policy layer**.

### 6.4 Duplication That Should Intentionally Remain

Not all repetition is bad. The following should remain explicit unless a concrete shared abstraction proves its value:

- service-specific route inventory
- service-specific startup tasks
- service-specific auth verifier configuration
- service-specific background jobs and caches

---

## 7. Performance and Operational Assessment

## Request-Path Performance

### Current state

- No severe wrapper hot-path issue found
- Request ID generation is fine
- Health endpoint cost is trivial
- Shared error handling is lightweight

### Verdict

**Performance is acceptable** for the current service architecture.

## Startup Performance

### Current state

- Some services do substantial work before listen
- Dynamic plugin loading is acceptable
- Startup work is more operational than performance-sensitive

### Verdict

**Startup is acceptable**, but readiness signaling is underdeveloped.

## Operational Maturity

### Current strengths

- Common health endpoint
- Shared request ID propagation
- Shared logging basis
- Shared startup function

### Current weaknesses

- No readiness endpoint
- No startup timing diagnostics
- Signal handler registration may accumulate
- Library exits process unconditionally
- Bootstrap policies still repeated in app code

### Verdict

**Operational maturity is moderate, not poor, but clearly improvable.**

---

## 8. Target Architecture

The desired end state is:

### 8.1 `@bytelyst/fastify-core` owns the standard service shell

It should provide:

- app creation
- request context
- health + readiness
- consistent error responses
- plugin loading policy
- auth hook helpers
- lifecycle registration
- startup instrumentation

### 8.2 Service entrypoints should become thin composition files

Each service should ideally only define:

- service metadata
- required secrets/init hooks
- auth verifier choice
- route inventory
- service-specific background jobs

### 8.3 Shared auth behavior should be consistent

Optional bearer parsing should be available as a standard wrapper/helper.

### 8.4 Startup should be structured, not handcrafted

Service startup should have explicit phases:

1. resolve secrets
2. infra initialization
3. app creation
4. route registration
5. readiness transition
6. listen

### 8.5 Shared abstractions should be additive first, not mandatory first

The target architecture should prefer:

- new optional helpers with safe defaults
- migration by reference implementation
- preservation of existing entrypoint readability

It should avoid:

- one-shot rewrites across all repos
- hidden magic inside wrapper internals
- required breaking changes before migration support exists

---

## 9. Remediation Roadmap

## Phase 0 — Audit Baseline and Guardrails

**Goal:** Lock in findings and make future migration measurable.

### Deliverables

- This audit document committed to repo
- Backlog created from findings
- Success metrics defined
- Target architecture agreed

### Exit Criteria

- Platform team agrees `@bytelyst/fastify-core` remains the single standard wrapper
- Roadmap accepted as implementation baseline

---

## Phase 1 — Harden `@bytelyst/fastify-core`

**Goal:** Fix wrapper-level lifecycle and observability gaps.

### Work Items

- Make signal registration idempotent or `once(...)`
- Remove hardcoded `process.exit(...)` from shared library path or make it configurable
- Add `requestId` to structured error responses
- Standardize optional plugin failure behavior
- Add readiness support (`/ready`)
- Add package-level tests for any new lifecycle/readiness behavior

### Priority

**P0 / P1**

### Expected Outcome

The shared wrapper becomes safer, cleaner, and more suitable as a long-term platform primitive.

---

## Phase 2 — Centralize repeated auth behavior

**Goal:** Eliminate duplicated optional JWT parsing hooks.

### Work Items

- Create shared optional bearer auth helper in `@bytelyst/fastify-core`
- Support verifier injection for product/service-specific token verification
- Standardize request decoration for `jwtPayload`
- Migrate all service entrypoints to shared auth helper
- Keep additive migration path so existing entrypoints can opt in incrementally

### Priority

**P0**

### Expected Outcome

Auth parsing behavior becomes consistent across:

- platform-service
- mcp-server
- extraction-service if needed
- all product backends

---

## Phase 3 — Introduce shared bootstrap orchestration

**Goal:** Remove repeated startup sequencing from service entrypoints.

### Work Items

- Create `bootstrapService(...)` or equivalent helper
- Support initialization hook arrays
- Support pre-listen async tasks
- Support startup failure policy and readiness state
- Migrate services incrementally
- Keep bootstrap helper orchestration explicit rather than hiding product-specific init logic

### Priority

**P1**

### Expected Outcome

Service entrypoints become shorter, safer, and less copy/paste driven.

---

## Phase 4 — Simplify route registration and service composition

**Goal:** Reduce repetitive entrypoint boilerplate.

### Work Items

- Introduce declarative route registration arrays
- Standardize `{ prefix: '/api' }` route metadata patterns
- Normalize route registration comments and grouping strategy

### Priority

**P2**

### Expected Outcome

Entrypoints become easier to read, review, and extend.

---

## Phase 5 — Improve startup diagnostics and platform ergonomics

**Goal:** Increase operational visibility without changing product behavior.

### Work Items

- Add startup timing logs
- Add route/plugin summary in debug mode
- Add readiness transition logging
- Add test helpers for readiness and wrapper behavior

### Priority

**P2**

### Expected Outcome

The platform gets better observability with minimal risk.

---

## Phase 6 — Rollout Verification and Cleanup

**Goal:** Ensure all migration work is actually adopted and stable across consumers.

### Work Items

- Verify every audited service entrypoint still uses `@bytelyst/fastify-core`
- Remove superseded custom auth/bootstrap code after migration completes
- Update service templates and docs to reflect the new standard pattern
- Add regression tests or CI checks for wrapper adoption where practical

### Priority

**P1 / P2**

### Expected Outcome

The ecosystem finishes with fewer duplicate patterns and fewer partial migrations left behind.

---

## 10. Implementation Backlog

## Implementation Progress Log

- [x] **Increment 1 — Phase 1 wrapper hardening**
  - Scope: readiness support, requestId in error responses, configurable startup fatal-exit behavior, idempotent signal handling, optional plugin failure policy, wrapper tests
  - Commit: `acfad8a`
  - Status: Completed
- [x] **Increment 2 — Phase 2 shared optional JWT hook and first consumer migration**
  - Scope: shared optional JWT context helper in `@bytelyst/fastify-core`, direct helper tests, `mcp-server` migrated off local `parseJwt`, obsolete local parser removed
  - Commit: `cfca118`
  - Status: Completed
- [x] **Increment 3 — Shared JWT helper migration in platform-service**
  - Scope: `platform-service` migrated from inline optional JWT parsing to `registerOptionalJwtContext`, bootstrap tests updated, shared-package and service validations passed
  - Commit: `e4baa2f`
  - Status: Completed
- [x] **Increment 4 — Product backend migration sweep**
  - Scope: shared JWT helper migration completed across product backends with committed repo updates: `learning_ai_clock` `8cc21d8`, `learning_ai_fastgap` `84b6da6`, `learning_voice_ai_agent` `547307e`, `learning_multimodal_memory_agents` `48ff90a`
  - Commit: `87f4955`
  - Status: Completed
- [x] **Increment 5 — Post-migration review fixes**
  - Scope: audit pass over recent Fastify-core rollout fixes; restored `mcp-server` issuer validation via tested local auth helper, repaired missing `platform-service` imports after helper migration, and isolated `platform-service` bootstrap tests from startup side effects
  - Commit: `63b0d20`
  - Status: Completed
- [x] **Increment 6 — Follow-up TODO resolution**
  - Scope: resolved product-repo migration ambiguity by confirming and committing remaining `LysnrAI` and `MindLyst` backend diffs; reproduced `platform-service` `EPERM kill` teardown issue under forked workers and fixed it by pinning the service Vitest pool to `threads`
  - Commit: `49db2cd`
  - Status: Completed

## P0 — Must Do

- [x] Add `requestId` to all shared error responses
- [x] Make `startService(...)` signal registration idempotent
- [x] Stop forcing unconditional `process.exit(...)` from shared startup helper or make it configurable
- [x] Create shared optional bearer JWT hook/helper
- [x] Migrate all product backends and `mcp-server` to the shared auth helper

## Open TODOs / Questions

- **TODO 1** — Resolved. `LysnrAI` and `MindLyst` still had real uncommitted backend diffs and were committed in follow-up repo commits; `JarvisJr` and `PeakPulse` were already clean because their shared-helper migrations had already been committed earlier in the sweep.
- **TODO 2** — Resolved. The `platform-service` full-suite `EPERM kill` teardown reproduced under Vitest forked workers and no longer reproduced once `services/platform-service/vitest.config.ts` pinned `test.pool = 'threads'`.

## Follow-up Findings — 2026-03-06 TODO Resolution

- **Follow-up 1 — Product repo migration ambiguity reconciled**
  - Result: confirmed that the earlier ambiguity was mixed state, not a false alarm. `learning_voice_ai_agent` and `learning_multimodal_memory_agents` still had uncommitted JWT-helper server migrations; `learning_ai_jarvis_jr` and `learning_ai_peakpulse` were already clean.
  - Fix commits: `learning_voice_ai_agent` `547307e`, `learning_multimodal_memory_agents` `48ff90a`.

- **Follow-up 2 — `platform-service` Vitest teardown issue rooted in worker mode**
  - Result: `pnpm --filter @lysnrai/platform-service exec vitest run --pool=forks` reproduced the `kill EPERM` tinypool teardown failure in this mac/Node 25 environment, while `--pool=threads` and the isolated bootstrap test passed.
  - Fix: pinned `pool: 'threads'` in `services/platform-service/vitest.config.ts` (`49db2cd`) and revalidated the full suite via the normal package test script.

## Review Findings — 2026-03-06 Follow-up Pass

- **Finding 1 — `mcp-server` auth regression risk**
  - Severity: High
  - Issue: the shared JWT helper migration temporarily dropped explicit issuer validation in `services/mcp-server/src/server.ts`.
  - Fix: moved verification into `services/mcp-server/src/lib/auth.ts` as `verifyJwtToken(...)` with `issuer: 'bytelyst-platform'` enforced; updated server usage and added direct regression tests in `services/mcp-server/src/lib/auth.test.ts`.

- **Finding 2 — `platform-service` import breakage after refactor**
  - Severity: High
  - Issue: the helper migration left `verifyToken` and `JwtPayload` unresolved in `services/platform-service/src/server.ts` after imports were shuffled.
  - Fix: restored the imports at the top of the module and revalidated bootstrap behavior.

- **Finding 3 — `platform-service` bootstrap test side effects**
  - Severity: Medium
  - Issue: `services/platform-service/src/server.test.ts` still triggered startup side effects such as seeding, migration calls, diagnostics subscriber registration, and trigger-job startup during test import.
  - Fix: mocked those startup side-effect modules directly and asserted the expected wiring instead of allowing noisy background behavior during the bootstrap test.

## P1 — Should Do

- [x] Add `/ready` endpoint support
- [x] Standardize optional plugin failure policy
- [ ] Add structured bootstrap helper for init sequencing
- [ ] Migrate platform-service, extraction-service, and at least one product backend to the bootstrap helper
- [x] Add package-level tests covering lifecycle, readiness, and error response behavior
- [ ] Add integration tests covering wrapper behavior from at least one real service consumer

## P2 — Good Improvement

- [ ] Replace manual route registration chains with declarative arrays
- [ ] Add startup timing diagnostics
- [ ] Add route/plugin summary in debug mode
- [ ] Improve typed request context model
- [ ] Add compatibility notes for any behavior changes in error shapes, readiness endpoints, or startup policy

## P3 — Nice to Have

- [ ] Add service template generator that assumes `bootstrapService(...)`
- [ ] Add lint or review checklist to discourage manual auth/bootstrap duplication
- [ ] Add CI checks for wrapper adoption in new service entrypoints
- [ ] Add a lightweight inventory script to report entrypoints not using shared helpers

---

## 11. Success Metrics

| Metric                                                  | Current       | Target           |
| ------------------------------------------------------- | ------------- | ---------------- |
| Service entrypoints using `createServiceApp(...)`       | High adoption | 100%             |
| Service entrypoints with custom optional JWT hook logic | Many          | 0                |
| Service entrypoints with custom init orchestration      | Many          | 0 or near-0      |
| Structured error responses containing `requestId`       | No            | 100%             |
| Shared readiness support                                | No            | 100% of services |
| `startService(...)` duplicate signal handler risk       | Present       | Eliminated       |
| New service templates using shared bootstrap helper     | No            | Yes              |

---

## 12. Recommended Rollout Order

### Step 1

Patch `@bytelyst/fastify-core` lifecycle and error response behavior first.

### Step 2

Add shared optional JWT hook support and migrate one backend as the reference implementation.

### Step 3

Roll shared auth migration through all product backends and `mcp-server`.

### Step 4

Add shared bootstrap orchestration and migrate `platform-service` first, since it is the most complex entrypoint.

### Step 5

Normalize route registration and operational diagnostics across the board.

### Step 6

Run a final adoption sweep and remove superseded custom bootstrap/auth code only after all consumers have migrated.

---

## 13. Validation and Rollout Guardrails

Every implementation phase should include both package-level and consumer-level verification.

### Package-Level Validation

- `pnpm --filter @bytelyst/fastify-core test`
- `pnpm --filter @bytelyst/fastify-core build`

### Service-Level Validation

- `pnpm --filter @lysnrai/platform-service test`
- `pnpm --filter @lysnrai/extraction-service test`
- `pnpm --filter @bytelyst/mcp-server test`

### Consumer Validation

At minimum, validate one representative product backend after each shared wrapper change.

### Rollout Guardrails

- make additive changes first
- avoid changing response shapes without documenting the contract change
- migrate one reference consumer before broad rollout
- remove duplicate legacy patterns only after successful adoption verification

---

## 14. Non-Goals

This roadmap does **not** currently aim to:

- replace Fastify with another backend framework
- collapse all service logic into one generic framework layer
- optimize for theoretical micro-benchmarks over maintainability
- force one-shot simultaneous migration across all repos
- hide product-specific startup logic that should remain explicit

---

## Appendix A: Audited Entry Points

### Shared Platform Services

- `learning_ai_common_plat/services/platform-service/src/server.ts`
- `learning_ai_common_plat/services/extraction-service/src/server.ts`
- `learning_ai_common_plat/services/mcp-server/src/server.ts`

### Product Backends

- `learning_voice_ai_agent/backend/src/server.ts`
- `learning_multimodal_memory_agents/backend/src/server.ts`
- `learning_ai_clock/backend/src/server.ts`
- `learning_ai_jarvis_jr/backend/src/server.ts`
- `learning_ai_fastgap/backend/src/server.ts`
- `learning_ai_peakpulse/backend/src/server.ts`

### Shared Package

- `learning_ai_common_plat/packages/fastify-core/src/create-app.ts`
- `learning_ai_common_plat/packages/fastify-core/src/start.ts`
- `learning_ai_common_plat/packages/fastify-core/src/types.ts`

---

## Appendix B: Proposed `fastify-core` API Evolution

### Current API

```ts
const app = await createServiceApp({ ... });
await startService(app, { port, host });
```

### Proposed Evolution

```ts
const app = await createServiceApp({
  name,
  version,
  description,
  corsOrigin,
  swagger,
  metrics,
  readiness: true,
  errorResponses: { includeRequestId: true },
});

await registerOptionalJwtContext(app, {
  verifyToken,
  attachAs: 'jwtPayload',
  mode: 'optional-bearer',
});

await bootstrapService({
  init: [initCosmosIfNeeded, initDatastore],
  app,
  register: async app => {
    for (const route of routes) {
      await app.register(route.plugin, route.options);
    }
  },
  start: {
    port,
    host,
    gracefulShutdown: true,
    exitOnFatal: true,
  },
});
```

### Design Goals of the Evolved API

- thinner server entrypoints
- fewer copy/paste auth hooks
- safer shutdown behavior
- explicit readiness support
- better observability
- lower drift across repos

---

## Final Recommendation

Do **not** replace the Fastify-based architecture. The foundation is solid.

Instead, make `@bytelyst/fastify-core` the true owner of:

- auth hook standardization
- startup lifecycle policy
- readiness support
- request-context consistency
- bootstrap ergonomics

This will preserve the benefits you already have while eliminating the remaining duplication and drift.
