Area lifecycle and task-queue state
An area objective and its task queue answer different questions. The area is
open until someone explicitly closes it. The queue is empty, ready, or
exhausted; task validation rejects a blocked-only graph. Finishing the current
task bundle therefore exhausts the queue but does not close the objective.
Area lifecycle is separate from task status and Git operations. Task status
is open or done; slice progress is derived from tasks.
Durable record
Section titled “Durable record”area.toml stores the lifecycle in one field:
lifecycle = "open"The only valid values are open and closed. zdev area create writes
lifecycle = "open". A record without the field reads as open, so every
existing area remains usable without migration. The next successful close or
reopen writes the field. Unknown values and unknown fields remain validation
errors.
The common area validator enforces closed => no open tasks. zdev check,
status, goal, and selection all use that validator, so a hand-edited closed
record with open tasks fails rather than hiding or selecting the tasks.
lifecycle is the field name in TOML and JSON. Human output labels it
Lifecycle. Queue projections use the JSON field queue and the human label
Queue, with these exact values:
empty: the area has no task records;ready: at least one open task is ready; blocked tasks may also exist;blocked: open tasks exist but none is ready;exhausted: at least one task exists and every task is done.
blocked is diagnostic vocabulary, not a reachable successful projection.
The current dependency rules reject missing blockers and cycles. Every valid
acyclic graph with an open task has a ready task. Commands fail task validation
instead of returning a successful blocked projection.
State matrix
Section titled “State matrix”| Lifecycle | Zero tasks (empty) |
Ready work (ready) |
Blocked-only work (blocked) |
All tasks done (exhausted) |
|---|---|---|---|---|
open |
Valid. The objective remains open for a first bundle. | Valid. Selection may return the first ready task. | Invalid task graph; validation fails without output or mutation. | Valid. The objective remains open for another reviewed bundle or an explicit close. |
closed |
Valid. Explicitly closing an empty objective is allowed. | Invalid record combination; close and task creation prevent it, and validation rejects it. | Invalid task graph and invalid closed-area combination. | Valid. The objective is explicitly closed. |
Task counts never change lifecycle. A closed area must have no open tasks.
Closing an empty area records an explicit decision that the objective needs no
queued implementation; it does not create an abandoned task or a third
lifecycle value.
Commands and mutation gates
Section titled “Commands and mutation gates”The public grammar is exactly:
zdev area close <area>zdev area reopen <area>There are no flags, reason fields, summaries, or implicit task changes. Both
commands acquire the zdev state lock, validate the project relationships and
the target area’s brief, slices, tasks, and generated index, and require
branch_status.task_work.safe = true. A stale-but-safe link is allowed and
returns the existing rebase advisory. A wrong branch, detached HEAD, active Git
operation, missing branch or anchor, invalid ancestry, or nonlinear child
history blocks the mutation. Ordinary staged, unstaged, or untracked files do
not block it. The command atomically replaces only the target area.toml.
area close accepts empty and exhausted queues. It rejects every open task,
whether ready or blocked, before writing:
Cannot close area <area>: <count> tasks are open. Complete them or keep the area openOn a change, human output is Closed area <area>. Its JSON contains
schema_version: 1, status: "closed", area, lifecycle: "closed", the
complete branch_status, and advisory (a string or null). Closing an already
closed area succeeds without writing: human output is
Area <area> is already closed, and JSON changes only status to "unchanged".
area reopen changes only the lifecycle. It does not reopen tasks. On a
change, human output is Reopened area <area> and the same JSON shape uses
status: "open" and lifecycle: "open". Reopening an open area succeeds
without writing: human output is Area <area> is already open, and JSON uses
status: "unchanged". A stale advisory follows the human status on a new line
and appears once in JSON.
Read and selection vocabulary
Section titled “Read and selection vocabulary”Successful read output always reports lifecycle and queue separately. Existing task, count, slice, branch-status, advisory, and path objects keep their current shapes.
zdev goal <area>
Section titled “zdev goal <area>”The human header is exactly:
Area: <tag> — <title>Lifecycle: <open|closed>Queue: <empty|ready|exhausted>Objective:<objective>Counts: <total> total; <open> open; <ready> ready; <blocked> blocked; <done> doneReady output then keeps the current task, slice, done-when, validation, and native-goal sections. The three no-work messages are:
The open area has no tasks. Create and approve a task, or close the area.The open area's task queue is exhausted. Add approved work, reopen a task, or close the area.The area is closed. Reopen it before adding or selecting work.They correspond to open/empty, open/exhausted, and either closed queue. Closed
output still reports whether its queue is empty or exhausted in the header.
Every human result ends with one newline.
Goal JSON removes the ambiguous top-level state field. In deterministic key
order it contains schema_version, area, lifecycle, queue, counts, and
task; native_goal follows task only for ready. The area object keeps
tag, title, objective, and path. task is exactly null for empty,
exhausted, and closed projections. native_goal is omitted for all three.
Thus neither complete nor a done count claims that the area objective closed.
zdev next <area>
Section titled “zdev next <area>”Area-specific next JSON replaces status with the two fields lifecycle and
queue. Ready and open no-work output retain the existing branch_status and
advisory fields. Ready output uses open and ready. Open no-work output
uses open with empty or exhausted. Closed output uses closed with its
actual queue and contains exactly schema_version, area, lifecycle,
queue, and task; task is null, and branch_status and advisory are
omitted.
Ready human output prefixes the existing task text with these exact lines:
Area: <area>Lifecycle: openQueue: readyOne blank line separates this header from the existing task text.
The exact no-work human messages are:
No tasks are recorded in open area <area>. Add approved tasks or run `zdev area close <area>`The task queue is exhausted in open area <area>. Add approved tasks, reopen a task, or run `zdev area close <area>`Area <area> is closed. Run `zdev area reopen <area>` before adding or selecting workAn open area still passes the existing task-work branch gate before selection,
including an empty or exhausted result. For a closed area, next loads and
validates project and area metadata, relationships, the brief, slices, task
records, and the generated index, then returns the closed result before any Git
or task-work branch check. Observing closure therefore requires neither
task_work.safe nor task_work.structurally_safe, and works on another branch,
detached HEAD, or during an unrelated Git operation. This read rule does not
weaken mutation gates: zdev area reopen <area> still requires
task_work.safe, so an off-branch caller must switch to the recorded area
branch first. Invalid records or task graphs fail before projection.
When <area> is omitted, an explicit project default still selects that area,
including a closed default, and returns its area-specific result. Without a
default, inference considers only open areas. One open area is selected even
when its queue is empty or exhausted; multiple open areas still require an
explicit area. If none is open, inference fails with
No area is open. Run \zdev area reopen ` before selecting work`.
zdev next --any
Section titled “zdev next --any”Project-wide JSON uses selection: "ready", "none", or "unsafe" instead
of status: "complete". A ready result includes the selected open area’s
lifecycle: "open" and queue: "ready". Every result includes
closed_areas, exactly a tag-sorted JSON array of area-tag strings. It is []
when no area is closed and, for example, ["alpha", "zeta"] when those areas
are closed. It never contains objects, branches, or diagnostics. Closed areas
are excluded before branch diagnostics, candidate ranking, and
unsafe-open-work calculation.
A ready human result prefixes the existing task, area, branch, and skipped-area
text with Selection: ready and one blank line. A none result includes
reason in JSON: "no-ready-open-area" when open areas exist and
"no-open-area" when every area is closed. reason is omitted from ready and
unsafe results.
When there are open areas but none has ready work, the successful result uses
selection: "none", task: null, and:
No open area has ready work. Open task queues are empty or exhaustedWhen every area is closed, it instead prints:
No area is open. Run `zdev area reopen <area>` before selecting workStructurally unsafe open work keeps selection: "unsafe", the existing
skipped evidence, and the existing No safe task is ready human wording.
This is distinct from queue exhaustion. A ready area still wins even when
other open areas are unsafe or exhausted.
For every human result with a nonempty closed_areas, append one final line:
Excluded closed areas: <comma-separated tags in tag order>Omit the line when closed_areas is empty. Thus an all-closed example is
exactly:
No area is open. Run `zdev area reopen <area>` before selecting workExcluded closed areas: alpha, zetazdev status [<area>]
Section titled “zdev status [<area>]”Selected-area human output begins with these exact lines before slice and branch diagnostics:
<title>Lifecycle: <open|closed>Queue: <empty|ready|exhausted>Counts: <total> total; <ready> ready; <blocked> blocked; <done> doneSelected JSON keeps the current object and adds top-level lifecycle and
queue; the embedded area metadata also contains lifecycle. Project-wide
human output keeps the project header and lists each area as <tag>: <open|closed>, <empty|ready|exhausted>; <branch> -> <relationship> [<diagnostics>]. Each project-wide JSON area summary contains tag, title,
lifecycle, queue, total, ready, blocked, done, and the existing
branch_status. Status includes closed areas and diagnoses their branches
normally.
Other operations
Section titled “Other operations”zdev tasks reviewmay review a bundle for a closed area. It replaces only the untracked current review in Git administrative state; it does not change.zdev, the worktree, index, refs, or lifecycle.zdev tasks import, with or without--commit, rejects a closed area before publication:Cannot add tasks to closed area <area>. Run \zdev area reopen ` first`. It never reopens the area implicitly.zdev task reopenrejects a closed area before changing the task:Cannot reopen task <task> in closed area <area>. Run \zdev area reopen ` first`. Task show and list remain available. Task completion cannot occur in a valid closed area because closure requires every task to be done.generalremains an ordinary area. A standing general area normally stays open across exhausted queues. It closes and reopens only through the same explicit commands and gates.- Parent and child lifecycle values are independent. Closing a parent neither closes its children nor removes its branch as their effective base. An open child of a closed parent remains selectable when its existing branch link is safe. Closing a child does not affect its parent. Parent assignment and managed rebase continue to use records and branches, not lifecycle.
- Slices gain no lifecycle and do not affect area closure.
- After valid preflight evidence, the implement entrypoint may return a
successful no-work result for open/empty, open/exhausted, or closed and starts
no worker. Explicit verify always requires an open/ready goal matching its
requested task ID. For every no-work goal it starts no verifier and returns
BLOCKER zdev-verify, never a successful verification. A validated closed goal is classified before status, Git, and task-work gates; open states retain their complete status, goal, and Git-baseline evidence requirements.