# PRD: Shipped Scheduling Timeline Contract in `SF.rail.createTimeline()`
## Status
Implemented in the current `0.6.4` release line.
This document is now a current-state product contract, not a future
implementation plan. `README.md` remains the public API source of truth, and
`WIREFRAME.md` remains the component-level visual and DOM reference.
## Summary
`solverforge-ui` ships one canonical read-only scheduling surface:
- `SF.rail.createTimeline(config)`
The component is a generic dense scheduling timeline for SolverForge
applications. It is intentionally numeric-axis only: consumers normalize domain
timestamps, time zones, lane ordering, labels, badges, stats, overlays, and
tones before passing a model to the library.
The low-level rail helpers remain shipped primitives for custom furnace-style
resource layouts, but they are not the recommended dense scheduling integration
path.
## Public API Contract
The public entrypoint is:
- `SF.rail.createTimeline(config)`
Returned API:
- `el`
- `setModel(model)`
- `setViewport(viewport)`
- `expandCluster(laneId, clusterId | null)`
- `destroy()`
The component is read-only. It does not parse timestamps, own timezone policy,
or support direct drag-rescheduling in this release line.
## Model Contract
The model must already be normalized to integer minutes.
Rejected inputs include:
- string timestamps
- `Date` objects
- numeric strings
- fractional minutes
- malformed tick objects
- malformed overlay spans
Required model shape:
- `model.axis`: `startMinute`, `endMinute`, `days[]`, `ticks[]`, `initialViewport`
- `model.lanes[]`: `id`, `label`, optional `badges`, optional `stats`,
optional `overlays`, `mode`, `items[]`
- `items[]`: `id`, `startMinute`, `endMinute`, `label`, optional `meta`,
optional `summary`, `tone`, optional `clusterId`, optional `detailItems[]`
Each lane may produce at most one overview group for a given `clusterId`.
Reusing the same `clusterId` for disjoint groups in the same lane is invalid
because `expandCluster(laneId, clusterId)` would be ambiguous.
## Shipped Behavior
### Overview Lanes
Overview mode is for scanning dense schedules.
Shipped behavior:
- overlapping or tightly adjacent overview items collapse into aggregate blocks
- aggregate blocks can show direct summary labels, count, open state, and tone
composition
- omitted summary fields are derived only when backing detail is available
- omitted `openCount` and `toneSegments` stay unknown when the supplied
aggregate `count` exceeds inspectable backing items
- expanded clusters remain inline and keep the aggregate block visible as the
collapse affordance
- focus and hover expose equivalent tooltip content
### Detailed Lanes
Detailed mode is for exact inspection.
Shipped behavior:
- detailed blocks preserve exact interval geometry
- adjacent intervals stay visually disjoint on one track
- true overlaps are packed onto separate track rows
- lane height follows the number of packed tracks
- timeline-specific minimum-width inflation is not applied to detailed blocks
### Viewport And Layout
Shipped behavior:
- sticky time header
- sticky lane labels
- one scrollable body viewport for dense solved schedules
- synchronized horizontal header/body movement
- drag-to-pan from the timeline viewport
- weekend shading and overlay bands behind schedule content
- `zoomPresets` defaults to `['1w', '2w', '4w', 'reset']`
- `zoomPresets: []` intentionally removes zoom controls for fixed-horizon
app surfaces
- `labelWidth` defaults to `280`
- supported embeds with a body viewport of `500px` or wider compact the label
column when needed to preserve at least `320px` of visible schedule track
- timelines created or updated before DOM attachment resynchronize layout after
mount
## Validation Surface
The shipped validation surface includes:
- Node frontend tests for numeric-only normalization, overview grouping,
detailed packing, cluster identity, viewport sync, zoom controls, detached
mount resync, and dense fixture rendering
- browser smoke tests for `demos/full-surface.html`,
`demos/timeline.html`, `demos/timeline-dense.html`, and `demos/rail.html`
- acceptance screenshots under `screenshots/`
- README and wireframe coverage for the public contract
Use these focused commands while working on the timeline:
```bash
make lint-frontend
make test-frontend
make test-browser
```
Use `make test-quick` or `make test` before release work.
## Documentation Requirements
Whenever `SF.rail.createTimeline()` behavior changes, update the same release
surface together:
- `README.md`
- `WIREFRAME.md`
- `demos/README.md`
- runnable demos under `demos/`
- focused tests under `tests/`
- generated assets under `static/sf/`
Do not document planned scheduling behavior as shipped unless it is wired into
the generated assets and covered by README API reference text.
## Non-Negotiables
- Do not add a second scheduling namespace such as `SF.schedule`,
`SF.timeline`, or `SF.scheduler`.
- Do not move shared scheduling layout semantics back into a consuming app.
- Do not add timestamp parsing or timezone policy to the library.
- Do not add compatibility-only layout branches.
- Do not make overview readability depend on showing every raw item label at
once.
- Do not call a timeline behavior shipped without tests, demos, docs, and
generated assets staying synchronized.