> For the complete documentation index, see [llms.txt](https://faction-os.gitbook.io/faction-os-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://faction-os.gitbook.io/faction-os-docs/.spec_system/archive/sessions/phase18-session04-idle-lifecycle-engine-parity/spec.md).

# Session Specification

**Session ID**: `phase18-session04-idle-lifecycle-engine-parity` **Phase**: 18 - Quest Board Suggestion Parity **Status**: Not Started **Created**: 2026-06-10 **Package**: apps/server **Package Stack**: TypeScript

***

## 1. Session Overview

This session moves idle suggestions from a manual, request-body-only LLM route into the server runtime lifecycle. Sessions 01-03 already established the shared suggestion contracts, manager-owned persistence, REST mutation routes, and WebSocket snapshot hydration. The current idle engine still only consumes caller-provided `lastUserTask` and `recentActivity`, returns transient suggestion objects, and emits only string compatibility frames from `POST /llm/idle-suggestion`.

The work creates automatic Quest Board generation when a hero transitions to `idle` through the existing event ingest route. It builds bounded context from the hero session, completed mission summary, recent tool activity, and sanitized in-memory event messages, then stores schema-valid typed idle suggestions through `SuggestionManager`. Each generated suggestion update uses the existing Session 03 broadcast path so connected clients receive canonical `suggestion_update` snapshots plus current web-store compatibility frames.

This session deliberately stays server-only. It does not implement session summary follow-ups, codebase scanners, scan orchestration, analysis engines, project scans, or typed web cards. It also keeps the Phase 18 exclusions: no historical telemetry, no entitlement gates, no hosted storage, and no provider transfer unless the existing two-level LLM opt-in is enabled.

***

## 2. Objectives

1. Trigger idle suggestion generation when an existing hero transitions to `idle` through server event ingestion.
2. Build privacy-bounded idle context from session and mission activity, including recent message fallback and modified-file extraction.
3. Add cooldown, in-flight, timeout, and shutdown cleanup behavior so idle transitions cannot stack or orphan async generation work.
4. Ensure LLM failures, missing provider transfer, empty responses, and parse mismatches still produce schema-valid deterministic fallback suggestions.
5. Store generated suggestions through `SuggestionManager` and broadcast canonical plus compatibility Quest Board updates.

***

## 3. Prerequisites

### Required Sessions

* [x] `phase18-session01-protocol-suggestion-contract-parity` - provides typed idle suggestion contracts, priorities, validation helpers, `suggestion_update`, and compatibility event types.
* [x] `phase18-session02-server-suggestion-manager-and-persistence` - provides server-owned persisted Quest Board state, typed idle suggestion creation, and manager shutdown flush behavior.
* [x] `phase18-session03-suggestion-routes-and-websocket-parity` - provides REST mutation routes, WebSocket hydration, and the shared suggestion broadcast helper for canonical and compatibility frames.
* [x] `phase17-session09-automatic-mission-lifecycle-posts` - provides the established pattern for automatic server lifecycle publishers that preserve privacy boundaries.

### Required Tools/Knowledge

* Node 26.2.0 or newer with npm workspaces.
* Express 5 event ingest flow in `apps/server/src/routes/event.ts`.
* Existing `HeroRoster`, `MissionManager`, `SuggestionManager`, and `Broadcaster` patterns.
* Existing `llmClient` and `llmPrivacy` two-level provider transfer rules.
* Phase 18 PRD Appendix A as traceability evidence only; do not import, copy, or transform historical code.

### Environment Requirements

* Work from the repository root.
* Use package-relative monorepo paths from the repo root.
* Keep all generated and edited files ASCII-only with Unix LF line endings.

***

## 4. Scope

### In Scope (MVP)

* Server runtime can react to a hero status transition to `idle` from the existing `/event` `hero_idle` dispatch path.
* Automatic generation uses the hero session ID when available and falls back to the hero ID for local-only sessions.
* Idle context includes completed mission summary, original mission prompt, recent tool summaries, safe file paths from tool use records, sanitized recent event messages, and modified-file hints.
* Context and prompts are redacted with the existing LLM privacy helpers before any provider-boundary call.
* Generation has a 60-second per-session cooldown and an in-flight guard so repeated idle transitions do not stack duplicate work.
* Generation has an about 18-second timeout and clears all pending timers or abort resources during server shutdown.
* Fallback suggestions are schema-valid typed objects with title, text, prompt, category, priority, session ID, and hero ID.
* LLM parse handling accepts either a direct JSON array or the current canned fallback object shape containing `suggestions`.
* Existing guardrails stay active: max 3 suggestions, forbidden generic suggestion filtering, sanitized text, bounded prompt lengths, and local fallback behavior when provider transfer is unavailable.
* Generated suggestions are stored through `SuggestionManager.createIdleSuggestion` and emitted through `emitSuggestionMutationUpdate`.
* `POST /llm/idle-suggestion` remains available and returns typed suggestion objects from the upgraded engine while keeping compatibility broadcast behavior.
* Focused tests cover lifecycle trigger, cooldown, in-flight, timeout, shutdown cleanup, fallback generation, parsing, manager persistence input, and broadcast emissions.

### Out of Scope (Deferred)

* Session summaries and follow-up tasks - *Reason: Session 05 owns summary generation and noise filtering.*
* Codebase issue scanners - *Reason: Session 06 owns scanner logic.*
* Scan orchestration and quest ignore patterns - *Reason: Session 07 owns orchestration and ignore behavior.*
* On-demand analysis and project scan engines - *Reason: Session 08 owns engine behavior.*
* Web typed Quest Board cards, hero assignment, action buttons, and keyboard shortcuts - *Reason: Sessions 09-10 own web consumption and actions.*
* Prompt documentation reconciliation for the old mission-complete wording - *Reason: Session 11 owns validation, documentation, and parity handoff.*
* Historical telemetry and entitlement gates - *Reason: Phase 18 explicitly excludes analytics capture and entitlement gating.*
* New real executor behavior for accepting suggestions - *Reason: real execution remains deferred and guarded separately.*

***

## 5. Technical Approach

### Architecture

Create an idle lifecycle coordinator in `apps/server/src/lib/idleSuggestionLifecycle.ts`. The coordinator should receive `SuggestionManager`, `Broadcaster`, a clock, optional timeout values for tests, and a generation function from the idle engine. It should expose methods for recording bounded session messages, handling a hero-idle transition, and destroying pending work on server shutdown. The coordinator owns cooldown and in-flight maps by session ID, not by hero name or display state.

Create `apps/server/src/lib/idleSuggestionContext.ts` for pure context building. It should accept the current hero, completed mission when available, ingest metadata, and a bounded recent-message slice. It should return sanitized context with last user task, recent activity text, modified files, and a stable session ID. Modified-file extraction should prefer mission tool-use paths and fall back to path-like tokens in recent messages after sanitization. Absolute paths, secrets, command bodies, raw patches, broad transcripts, and provider payloads must not be stored or emitted.

Upgrade `apps/server/src/llm/engines/idleSuggestionEngine.ts` so generation is usable by both the lifecycle coordinator and the existing `POST /llm/idle-suggestion` route. The parser should accept the existing JSON array shape and the current `llmClient` fallback object shape. The fallback path should create specific, schema-valid typed candidates from modified-file or mission context when LLM output is missing, malformed, generic, or empty.

Wire the coordinator in `apps/server/src/server.ts` and `apps/server/src/routes/event.ts`. The event route should record compact session activity for relevant hook events and call the coordinator only after the hero state is actually updated to `idle`. The route should not block the HTTP response on LLM generation; generation should run asynchronously with failure-path handling and compact warning toasts only when useful.

### Design Patterns

* Lifecycle coordinator boundary: async timers, in-flight locks, cooldowns, and cleanup live in one injectable class.
* Pure context builder: path extraction, text bounding, and privacy filtering are tested without server startup.
* Manager-owned state: generated cards are stored only through `SuggestionManager`; no direct persisted-file writes occur.
* Single broadcast path: automatic generation uses the same `emitSuggestionMutationUpdate` helper as REST mutations.
* Local fallback first: the existing two-level LLM provider transfer rules remain the only path to external provider calls.
* Explicit failure mapping: timeout, parse failure, empty output, unavailable provider, and manager validation errors have deterministic fallback or compact error behavior.

### Technology Stack

* TypeScript in `apps/server`.
* Existing Express 5 event route and server lifecycle wiring.
* Existing `@factionos/protocol` idle suggestion and event types.
* Existing `llmClient`, `llmPrivacy`, and `SuggestionManager`.
* Vitest server tests with fake timers and temporary state directories.

***

## 6. Deliverables

### Files to Create

| File                                                | Purpose                                                                                                                     | Est. Lines |
| --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ---------- |
| `apps/server/src/lib/idleSuggestionContext.ts`      | Pure context builder for hero idle sessions, recent messages, mission data, and modified-file extraction                    | \~220      |
| `apps/server/src/lib/idleSuggestionLifecycle.ts`    | Async lifecycle coordinator for idle triggers, cooldown, in-flight guard, timeout, manager storage, broadcasts, and cleanup | \~260      |
| `apps/server/tests/idleSuggestionContext.test.ts`   | Unit tests for context building, privacy filtering, path extraction, and fallback labels                                    | \~220      |
| `apps/server/tests/idleSuggestionLifecycle.test.ts` | Unit tests for trigger, cooldown, in-flight, timeout, fallback, manager writes, broadcasts, and destroy cleanup             | \~320      |

### Files to Modify

| File                                                  | Changes                                                                                                                                       | Est. Lines |
| ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| `apps/server/src/llm/engines/idleSuggestionEngine.ts` | Add typed generation inputs, fallback parsing for array and object shapes, deterministic fallback candidates, and timeout-friendly call seams | \~180      |
| `apps/server/src/routes/llm.ts`                       | Keep `POST /llm/idle-suggestion` working with upgraded typed engine output and compatibility broadcast behavior                               | \~35       |
| `apps/server/src/routes/event.ts`                     | Record bounded session activity and trigger idle lifecycle generation after hero state becomes idle                                           | \~70       |
| `apps/server/src/server.ts`                           | Instantiate lifecycle coordinator, inject it into event routes, and destroy it during shutdown before manager teardown                        | \~30       |
| `apps/server/tests/llm.test.ts`                       | Update idle route tests for typed fallback output and parse mismatch regression coverage                                                      | \~70       |
| `apps/server/tests/routes.test.ts`                    | Add integration coverage that a full lifecycle can enqueue typed Quest Board suggestions after idle transition                                | \~70       |
| `apps/server/README_server.md`                        | Document automatic idle lifecycle generation, local fallback behavior, provider opt-in, and current server-only scope                         | \~45       |

***

## 7. Success Criteria

### Functional Requirements

* [ ] A hero entering `idle` through `/event` starts one asynchronous generation attempt for the resolved session.
* [ ] A repeated idle transition inside 60 seconds does not enqueue duplicate generation for the same session.
* [ ] An already-running generation for a session suppresses duplicate work until the first attempt completes or times out.
* [ ] Generated idle suggestions are stored as typed manager suggestions with session ID, hero ID, title, text, prompt, category, priority, and created timestamp.
* [ ] Generated manager mutations emit `suggestion_update` and current `idle_suggestion` compatibility frames.
* [ ] Missing provider transfer, LLM failure, timeout, malformed output, and empty output all fall back to schema-valid deterministic suggestions or an intentional empty result when context is insufficient.
* [ ] Modified-file hints prefer safe relative paths from mission tool-use records and never expose absolute paths.
* [ ] `POST /llm/idle-suggestion` remains compatible and returns a suggestions array for valid input.

### Testing Requirements

* [ ] Context-builder tests are written and passing.
* [ ] Lifecycle coordinator tests are written and passing.
* [ ] Idle engine parser and fallback tests are written and passing.
* [ ] Route integration tests are updated and passing.
* [ ] `npm --workspace apps/server run typecheck` passes.

### Non-Functional Requirements

* [ ] Provider transfer still requires both `ANTHROPIC_API_KEY` and `FACTIONOS_ALLOW_LLM_PROVIDER_TRANSFER=true`.
* [ ] No raw prompts, secrets, absolute paths, command bodies, provider payloads, or broad transcript content are persisted or emitted.
* [ ] All async timers, timeouts, and in-flight records are cleaned up on server shutdown.
* [ ] Automatic generation does not block the `/event` HTTP response path.
* [ ] The server does not add historical telemetry, entitlement checks, hosted storage, or executor behavior.

### Quality Gates

* [ ] All files ASCII-encoded.
* [ ] Unix LF line endings.
* [ ] Code follows project conventions.

***

## 8. Implementation Notes

### Key Considerations

* Session 04 should trigger from `hero_idle` state transition, not from the mission-complete callback alone. In the current event route, mission completion happens immediately before the hero state is updated to `idle`.
* The current `llmClient` fallback for `idleSuggestionEngine` returns an object with a `suggestions` array of strings, while the current parser only accepts a top-level array. Fix that mismatch in the engine before relying on fallback behavior.
* `SuggestionManager.createIdleSuggestion` caps active idle suggestions per session. Multiple suggestions from one generation attempt may need stable handling so the final active state is intentional and tests document it.
* The lifecycle coordinator should call `emitSuggestionMutationUpdate` after each accepted manager write, or after a deliberate batch helper if one is added in this session.

### Potential Challenges

* Context can become noisy: keep the context builder bounded, pure, and explicit about which fields are allowed.
* Async generation can make tests flaky: inject the clock, timeout, and generator function, and use fake timers where appropriate.
* Shutdown can race with generation: destroy should mark the coordinator closed, clear timers, and ignore or abort late results before manager teardown.
* Fallback suggestions can become generic: derive them from mission prompt, summary, or safe file hints, and keep the existing forbidden-pattern filter.

### Relevant Considerations

* \[P01-apps/server] **Anthropic transfer is two-level opt-in**: automatic idle generation must not send prompts, paths, or transcript text unless the provider key and transfer flag are both enabled.
* \[P03-apps/server] **Local server boundary must stay conservative**: the idle lifecycle must inherit existing validation, rate-limit, body-size, and auth boundaries and avoid new unbounded inputs.
* \[P07] **Redaction is boundary-specific**: suggestion text, file hints, and persisted snapshots must be minimized separately from raw ingest, archive, and provider prompts.
* \[P17-apps/server] **Manager-owned persistence and cleanup**: keep suggestion state and shutdown flush behind the manager, and keep lifecycle timers behind the lifecycle coordinator.
* \[P17] **Do not expose raw lifecycle telemetry in coordination posts**: automatic suggestions should be privacy-filtered derived work, not raw hook event dumps or transcript excerpts.
* \[P03] **Stable docs are the current contract**: use PRD Appendix A and `EXAMPLES/` only as traceability evidence.

### Behavioral Quality Focus

Checklist active: Yes Top behavioral risks for this session:

* Duplicate idle transitions could create repeated Quest Board cards unless cooldown and in-flight guards are explicit and tested.
* Provider or parser failure could silently produce no useful fallback unless fallback shapes are schema-valid and tested.
* Lifecycle async work could outlive server shutdown unless timeout and cleanup behavior is centralized.

***

## 9. Testing Strategy

### Unit Tests

* Test context building with mission prompt, mission summary, tool-use paths, sanitized recent messages, absent session IDs, and unsafe absolute paths.
* Test idle engine parsing for a direct JSON array, fenced JSON, current canned fallback object shape, malformed output, generic suggestions, and max 3 cap.
* Test lifecycle coordinator cooldown, in-flight guard, timeout, destroy cleanup, fallback generation, manager writes, and broadcast calls.

### Integration Tests

* Extend route tests to run a full `SessionStart -> UserPromptSubmit -> PreToolUse -> Stop` flow and assert that a typed suggestion appears in the injected manager state after asynchronous generation settles.
* Keep `/llm/idle-suggestion` route coverage for request validation and typed response shape.

### Manual Testing

* Start the server with `FACTIONOS_MOCK=false`, send a minimal lifecycle flow through `/event`, then inspect `/suggestions/summary` and WebSocket frames for the new typed snapshot.
* Repeat the idle event within 60 seconds and confirm no duplicate generation appears.

### Edge Cases

* Missing session ID.
* Hero not found.
* No active or completed mission.
* Empty recent activity.
* Unsafe absolute paths or secret-like text in ingest data.
* LLM provider blocked by missing transfer flag.
* LLM timeout.
* Manager validation error after generation.
* Server shutdown while generation is pending.

***

## 10. Dependencies

### External Libraries

* None. Use existing Node, TypeScript, Express, Vitest, and `@factionos/protocol` dependencies.

### Other Sessions

* **Depends on**: `phase18-session01-protocol-suggestion-contract-parity`, `phase18-session02-server-suggestion-manager-and-persistence`, `phase18-session03-suggestion-routes-and-websocket-parity`
* **Depended by**: `phase18-session05-session-summary-engine-and-noise-filtering`, `phase18-session09-web-quest-board-typed-cards`, `phase18-session10-quest-actions-and-keyboard-shortcuts`

***

## Next Steps

Run the implement workflow step to begin AI-led implementation.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://faction-os.gitbook.io/faction-os-docs/.spec_system/archive/sessions/phase18-session04-idle-lifecycle-engine-parity/spec.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
