# gantt@0.1

**Status:** normative. **Inherits:** [`../conventions.md`](../conventions.md) and the shared item
model defined by [`todo@0.1`](../todo/SPEC.md). It extends an item with schedule, progress, and
dependency properties without redefining or dropping inherited meaning.
**Schema:** [`schema.json`](schema.json), which `$ref`s todo's item properties.
**Fixtures:** [`fixtures/`](fixtures/). **Owns diagnostic codes:** `MDTO700`–`MDTO799`.

**Companion skill:** [Authoring and editorial guidance](https://markdownto.ai/specs/gantt.skill.md) (non-normative).

---

## 1. Purpose

`gantt@0.1` describes a **project schedule**: level-2 headings are workstreams, task items are
scheduled bars, and sparse inline fields carry dates, progress, and dependencies. The Markdown is a
useful work breakdown on its own; the renderer adds a shared time axis without inventing schedule.

---

## 2. Grammar

### 2.1 Envelope

```yaml
---
markdownto: gantt@0.1
title: Observatory opening
today-line: true
---
```

`today-line` is optional, accepts the YAML boolean `true` or `false`, and defaults to `true`.
When enabled, the HTML renderer draws the viewer's current local date as a red vertical rule when
that date falls inside the schedule window. A non-boolean value is `MDTO715`. The rendered window
is derived from the earliest `start` and latest `end` and is never written back.

### 2.2 Workstreams

`##` means a **workstream**. There is no implicit workstream: at least one is required (`MDTO700`),
and a task before the first one is `MDTO701`. One optional leading `#` title heading is allowed;
another heading level is `MDTO702`. A workstream name must be non-empty (`MDTO703`) and unique after
trimmed, case-insensitive comparison (`MDTO704`). Workstreams and tasks stay in document order.

### 2.3 Scheduled tasks

A scheduled task is the shared todo item plus these recognized fields:

| Field | Required | Meaning |
|---|---:|---|
| `[start:: YYYY-MM-DD]` | yes | First calendar day occupied by the bar. |
| `[end:: YYYY-MM-DD]` | yes | Last calendar day occupied by the bar, inclusive. |
| `[progress:: 0..100]` | no | Effective completion percentage; default 100 for `[x]`, otherwise 0. |
| `[depends:: ^id, ^id]` | no | Comma-separated pinned task identifiers that must finish first. |

Missing schedule fields are `MDTO705` / `MDTO706`; invalid calendar dates are `MDTO707`; `end`
before `start` is `MDTO708`; progress must be an integer from 0 through 100 (`MDTO709`). A dependency
list accepts only comma-separated `^id`s, once each (`MDTO710`). Every target must exist (`MDTO711`),
a task cannot name itself (`MDTO712`), and a dependency cycle is `MDTO714` (warning): the file still
describes a schedule, but no topological order can satisfy it.

The checkbox remains the inherited done flag. A written `progress` that contradicts it — `[x]` below
100 or `[ ]` at 100 — is `MDTO713` (warning). The `progress` verb keeps the pair coupled; hand-written
files are preserved and shown exactly as claimed.

Nested shared-model items are subtasks. They carry full schedules of their own and render indented
beneath their parent; no parent's dates or progress are derived from its children.

### 2.4 Canonical IR and operations

The IR sits at `result.gantt`, beside `result.document`. Each `GanttTask` carries every inherited item
property plus typed `start`, `end`, effective `progress`, and `dependencies` (ids without carets).

The typed patch dialect is `addTask`, `scheduleTask`, `progressTask`, `dependTask`, `moveTask`, and
`removeTask`. Batches require an `expect` source hash, apply all-or-nothing through the shared
`runBatch` engine, and re-parse after every semantic operation. Unrelated source bytes are invariant.

### 2.5 Diagnostics

| Code | Severity | Meaning |
|---|---|---|
| `MDTO700` | error | Document has no workstream. |
| `MDTO701` | error | Task appears before the first workstream. |
| `MDTO702` | error | Heading level is invalid. |
| `MDTO703` | error | Workstream heading has no name. |
| `MDTO704` | error | Workstream name is duplicated. |
| `MDTO705` | error | Task has no `start`. |
| `MDTO706` | error | Task has no `end`. |
| `MDTO707` | error | `start` or `end` is not a real RFC 3339 full-date. |
| `MDTO708` | error | `end` is before `start`. |
| `MDTO709` | error | `progress` is not an integer from 0 through 100. |
| `MDTO710` | error | `depends` is malformed or repeats a target. |
| `MDTO711` | error | Dependency target does not exist. |
| `MDTO712` | error | Task depends on itself. |
| `MDTO713` | warning | Checkbox and written progress disagree. |
| `MDTO714` | warning | Dependency graph contains a cycle. |
| `MDTO715` | error | `today-line` is not a boolean. |

---

## 3. Rationale

**Why dates are fields.** The task sentence remains readable, while dates stay machine-addressable
and editable without parsing prose. An inclusive `end` matches how people write project plans and
makes a one-day task `start == end`.

**Why dependencies require pinned ids.** Text is pleasant for ad-hoc addressing and wrong for a
durable graph: task wording changes. Requiring `^id` makes every edge explicit and stable, and a
missing target becomes a precise diagnostic instead of a fuzzy match.

**Why workstreams are not phases.** The horizontal axis already carries time. Reading heading order
as time would create two clocks that can disagree; headings therefore answer ownership or area, and
dates alone answer when.

**Relationship to the shared item model.** A Gantt task is a todo item extended property-by-property.
Its checkbox, text, raw source, tags, ordinary typed fields, children, lazy id, and position are the
same definitions and schemas. Schedule properties add meaning; none replaces inherited meaning.

---

## 4. Examples

```markdown
---
markdownto: gantt@0.1
title: Observatory opening
---

## Site
- [x] Survey the ridge [start:: 2026-09-01] [end:: 2026-09-03] [progress:: 100] ^survey
- [ ] Pour foundations [start:: 2026-09-04] [end:: 2026-09-18] [depends:: ^survey]
```

`- [ ] Pour foundations [end:: 2026-09-18]` is `MDTO705`: it has no start.

---

## 5. Verb reference

`gantt@0.1` owns the vocabulary **add, schedule, progress, depend, move, rm**.

| Verb | Signature | Source edit | Operation |
|---|---|---|---|
| `add` | `mdto gantt add <text> --workstream <name> --start <date> --end <date>` | Inserts one task with required start/end fields. | `addTask` |
| `schedule` | `mdto gantt schedule <ref> --start <date> --end <date>` | Adds or replaces start/end atomically. | `scheduleTask` |
| `progress` | `mdto gantt progress <ref> <progress>` | Writes progress (an integer 0..100) and couples the checkbox (`100` checks; lower unchecks). | `progressTask` |
| `depend` | `mdto gantt depend <ref> <id>… [--clear]` | Adds/replaces `depends`, or removes it with `--clear`. | `dependTask` |
| `move` | `mdto gantt move <ref> <workstream>` | Reinserts the task block verbatim in another workstream/position. | `moveTask` |
| `rm` | `mdto gantt rm <ref>…` | Removes the task and all nested subtasks. | `removeTask` |

Every verb supports the shared patch flags: `--dry-run`, `--json`, `--expect`, `--pin`, `--force`,
and `--file`. The HTML timeline is deliberately read-only in 0.1: schedule mutation remains in the
typed operation layer and CLI, where fixture-backed tests freeze each edit against the exact source
bytes. A future direct-manipulation timeline must call those operations rather than reimplementing
their date, progress, dependency, or minimal-diff rules in the browser.

### Common flags

`--file <path>` · `--dry-run` · `--json` · `--expect <hash>` · `--pin` · `--force` · `--help`
