> For the complete documentation index, see [llms.txt](https://ai-os-and-trend-finder.gitbook.io/ai-os-and-trend-finder-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ai-os-and-trend-finder.gitbook.io/ai-os-and-trend-finder-docs/.spec_system/archive/sessions/phase15-session01-scheduler-config-contract/spec.md).

# Session Specification

**Session ID**: `phase15-session01-scheduler-config-contract` **Phase**: 15 - Scheduler Config And Aggregate Split **Status**: Completed **Created**: 2026-05-31

***

## 1. Session Overview

This session adds the scheduler configuration contract that later Phase 15 sessions need before the aggregate path can be split safely. The current registry in `scripts/lib/scheduler/registry.ts` is still the reviewed source of approved scheduler jobs and cadence candidates; local config under `data/` should only select reviewed values and should never introduce raw commands, private paths, or arbitrary systemd expressions.

The implementation should make `bun run scheduler:status` report effective settings for valid config, gracefully fall back to registry defaults when config is missing, and surface invalid config through sanitized warning/status details. It must not add the scoped `agent-aggregate` or Trend Finder handlers, change `bun run aggregate`, or implement live-data merge locking. Those are later Phase 15 sessions.

Because the source plan names future split jobs that are not registered yet, this session must keep the contract explicit: current validation is against the registered job IDs available during implementation, and docs/templates should avoid making not-yet-registered jobs look executable.

***

## 2. Objectives

1. Add a sanitized scheduler config template and private-file boundary under `data/`.
2. Implement a typed scheduler config reader/validator that treats the registry as the approved job and cadence source.
3. Extend scheduler status to distinguish registry defaults from valid local timer intent and invalid local config.
4. Add focused tests for missing config, valid config, invalid JSON, invalid cadence, invalid time, unknown jobs, unsafe fields, and output redaction.

***

## 3. Prerequisites

### Required Sessions

* [x] Phase 14 completed - current PRD and security records mark it complete.

### Required Tools/Knowledge

* Current scheduler registry, status builder, CLI status command, and run-state tests.
* Existing data template/private-file pattern in `data/README_data.md`.
* Existing scheduler privacy rules in `docs/CONSIDERATIONS.md` and `docs/SECURITY-COMPLIANCE.md`.

### Environment Requirements

* Bun dependencies installed.
* Work from repository root.
* No real local scheduler config or private credentials committed.

***

## 4. Scope

### In Scope (MVP)

* AI OS operators can copy a sanitized scheduler config template from `data/` to a private local file.
* Scheduler status can report valid configured cadence/timer intent while preserving registry defaults as fallback.
* Scheduler status can report invalid local config without throwing and without printing raw file contents.
* Scheduler config validation rejects unknown job IDs, unsupported cadence selections, unsafe raw fields, and invalid Dream `HH:MM` values.

### Out of Scope (Deferred)

* Scoped `agent-aggregate` and Trend Finder scheduler job handlers - Reason: Sessions 04 and 05 own executable split jobs.
* Live-data merge writer and shared generated-data lock - Reason: Session 02 owns write safety.
* Timer unit rendering or installation - Reason: Session 07 owns optional systemd reconciliation.
* Public aggregate behavior changes - Reason: compatibility must hold until the orchestration split is deliberately scoped.

***

## 5. Technical Approach

### Architecture

Add `scripts/lib/scheduler/config.ts` as a script-side contract module that reads `data/ai-os.scheduler.json` by default, validates it against `listSchedulerJobs()`/`requireSchedulerJob()`, and returns a discriminated state such as missing, loaded, or invalid. It should expose sanitized issue summaries that can be projected by `operator-status.ts` without raw config content.

Extend `SchedulerOperatorStatus` types to include config/timer intent fields without changing run-state semantics. `buildSchedulerOperatorStatus()` should use registry defaults when config is missing, prefer valid configured cadence when present, and include sanitized config warnings when invalid.

### Design Patterns

* Registry-as-contract: local config selects from registered job IDs and candidate IDs only.
* Typed degradation: invalid config returns a warning/status state rather than crashing operator status.
* Sanitized summaries: output contains codes, labels, and counts, not raw file contents, paths, shell, secrets, prompts, or command bodies.

### Technology Stack

* TypeScript script modules under `scripts/lib/scheduler/`
* Bun/Vitest tests under `scripts/lib/__tests__/`
* Markdown docs under `data/`, `.env.local.example`, and `docs/runbooks/`

***

## 6. Deliverables

### Files to Create

| File                                             | Purpose                                                          | Est. Lines |
| ------------------------------------------------ | ---------------------------------------------------------------- | ---------- |
| `data/ai-os.scheduler.example.json`              | Sanitized scheduler config template                              | \~20       |
| `scripts/lib/scheduler/config.ts`                | Scheduler config parsing, validation, and sanitized result types | \~180      |
| `scripts/lib/__tests__/scheduler-config.test.ts` | Focused config parser/validator coverage                         | \~220      |

### Files to Modify

| File                                                      | Changes                                                      | Est. Lines |
| --------------------------------------------------------- | ------------------------------------------------------------ | ---------- |
| `.gitignore`                                              | Ignore private `data/ai-os.scheduler.json`                   | \~3        |
| `data/README_data.md`                                     | Document template/private scheduler config pair              | \~10       |
| `scripts/lib/scheduler/types.ts`                          | Add status/config projection types                           | \~40       |
| `scripts/lib/scheduler/index.ts`                          | Export config module                                         | \~1        |
| `scripts/lib/scheduler/operator-status.ts`                | Read config state and project effective cadence/timer intent | \~120      |
| `scripts/lib/__tests__/scheduler-operator-status.test.ts` | Cover config-aware status and redaction                      | \~120      |
| `scripts/lib/__tests__/scheduler-status-cli.test.ts`      | Cover CLI status with config-aware output                    | \~80       |
| `docs/runbooks/scheduled-aggregate.md`                    | Document scheduler config path and status behavior           | \~50       |
| `docs/runbooks/ai-os-dream.md`                            | Document Dream timer intent config boundary                  | \~35       |
| `.env.local.example`                                      | Point scheduler settings to `data/`, not env secrets         | \~10       |

***

## 7. Success Criteria

### Functional Requirements

* [ ] Missing `data/ai-os.scheduler.json` falls back to registry defaults.
* [ ] Valid local config can override the displayed cadence/timer intent for a registered job.
* [ ] Invalid local config produces sanitized warnings/status details and does not fail `bun run scheduler:status`.
* [ ] Unknown job IDs, unsupported cadence IDs, invalid Dream `time`, unsafe raw fields, and invalid JSON are rejected by the config validator.

### Testing Requirements

* [ ] Unit tests cover config parser/validator states.
* [ ] Operator status tests cover missing, valid, and invalid config projection.
* [ ] CLI status tests prove human and JSON output remain sanitized.

### Non-Functional Requirements

* [ ] No private config contents, machine paths, shell commands, prompts, auth material, or source dumps are printed by status.
* [ ] Registry metadata remains the source of approved jobs and cadence candidates.

### Quality Gates

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

***

## 8. Implementation Notes

### Key Considerations

* The existing registry currently lists `aggregate` and `dream`; do not make future split job IDs appear runnable before their sessions add registry entries and handlers.
* Keep `enabledByDefault` separate from local `timerEnabled`; one is starter metadata, the other is operator intent.
* Treat Dream `time` as strict `HH:MM`; convert to safe display text only after validation.

### Potential Challenges

* Future job names in the source plan conflict with current registry validation: document the current-session boundary and update templates later when those jobs are registered.
* Status output already has stable copy and tests: extend it additively to avoid breaking existing consumers.

### Relevant Considerations

* \[P11] **Scheduler state/log privacy boundary**: Config/status output may expose only safe labels, counts, statuses, cadence IDs, and command hints.
* \[P12] **Dream browser/service surfaces stay narrow**: Dream config is timer intent only, not a browser gateway or automatic install path.
* \[P11] **Command-first scheduler closeout works**: Preserve CLI-first status and run behavior.

### Behavioral Quality Focus

Checklist active: Yes Top behavioral risks for this session:

* Invalid local config crashes status instead of degrading to a warning.
* Status output leaks raw local config values or private paths.
* Local timer intent is confused with actual installed systemd timers.

***

## 9. Testing Strategy

### Unit Tests

* `scripts/lib/__tests__/scheduler-config.test.ts` for all parser states and validator issue codes.
* Existing operator status tests extended for config-aware cadence, timer intent, missing config fallback, invalid config warnings, and no raw-content leakage.

### Integration Tests

* Scheduler status CLI tests with temp `data/ai-os.scheduler.json` roots or injected config readers.

### Manual Testing

* Run `bun run scheduler:status`.
* Run `bun run scripts/scheduler-status.ts --job dream --json`.
* Confirm missing config still reports registry defaults.

### Edge Cases

* Invalid JSON.
* Unknown job ID.
* Unsupported cadence.
* Dream `time` not matching `HH:MM`.
* Config containing unsafe keys like `command`, `path`, `env`, `token`, or raw `systemdCalendar`.

***

## 10. Dependencies

### External Libraries

* None new.

### Other Sessions

* **Depends on**: Phase 10-12 scheduler foundations and Phase 14 completion.
* **Depended by**: Phase 15 Sessions 02-08.

***

## 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://ai-os-and-trend-finder.gitbook.io/ai-os-and-trend-finder-docs/.spec_system/archive/sessions/phase15-session01-scheduler-config-contract/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.
