Skip to content

Derived work handoffs

Zdev may publish a small follow-up bundle without asking the user to approve work they have already authorized. This applies to direct work inside the current task’s area brief, outcome, boundaries, and testing policy. It adds no task state, lineage metadata, or worker authority over .zdev.

The coordinator owns the decision and the mutation. Each worker may return one proposal with its result. The worker never imports tasks, edits the source task, completes work, stages files, or commits.

An AFK task may split when smaller tasks make implementation or verification easier, with no new user approval for the same outcome, boundaries, and testing. Set unattended children explicitly to afk: true, since TaskDraft defaults to false. Keep human-dependent checks attended and late in the dependency graph. The source keeps its original done conditions. Watch for repeated splitting without implementation progress under the skill’s death-loop guidance.

A proposal has exactly two parts: this first line and one JSON object. Any prefix, suffix, Markdown fence, missing field, unknown field, duplicate JSON key, invalid UTF-8, or second object makes it invalid.

PROPOSE zdev-derived <area> <source-task-id>
{
"schema_version": 1,
"proposal": "investigation_follow_up",
"area": "payments",
"source_task": "payments-007",
"source_result": {
"status": "complete",
"summary": "Settled the retry boundary.",
"validation": ["Compared the design with the current retry implementation."]
},
"tasks": [
{
"key": "apply-retry-boundary",
"title": "Apply the settled retry boundary",
"blocked_by": [],
"outcome": "Use the settled boundary in the runtime path.",
"context": "The investigation settled where retries stop.",
"boundaries": ["Do not change the public retry policy."],
"done_when": ["The runtime uses the settled boundary."],
"validation": ["Run the focused retry tests."]
}
]
}

The top-level object denies unknown fields. schema_version is 1. proposal is exactly investigation_follow_up or implementation_split. The envelope area and source task must match the selected goal and first line. Every string is non-empty and single-line where the ordinary task-bundle contract requires it. tasks contains one through five complete drafts in dependency order and denies unknown draft fields. A task draft cannot contain a proposal or another task bundle.

source_result also denies unknown fields. An investigation follow-up requires status: "complete", a completion summary, and the exact validation list that will be written to the source task. A split requires status: "split", a summary of why the approved implementation must be divided, and an empty validation list. A split does not add a Result section or complete its source.

An implementation split also requires this top-level object after source_result; an investigation follow-up forbids it:

"split_ownership": {
"retained_parent_paths": ["src/payments.rs"],
"child_future_paths": [
{
"key": "extract-retry-policy",
"paths": ["src/retry_policy.rs", "tests/retry_policy.rs"]
},
{
"key": "wire-retry-policy",
"paths": ["src/retry_wiring.rs", "tests/retry_wiring.rs"]
}
]
}

split_ownership and each child entry deny unknown fields and duplicate JSON keys. retained_parent_paths equals, as a set, the paths in the coordinator’s captured attributed unstaged parent delta; neither side may omit or add a path. Automatic apply also requires that delta to be the checkout’s complete unstaged path set and requires an empty index; other existing changes stop the handoff for recovery and fresh context. child_future_paths names every proposed key exactly once and no other key, and each child has at least one path. Duplicate paths, overlap between children, and overlap with a retained parent path are invalid.

Every path is a normalized repository-relative UTF-8 path with / separators: no absolute path, empty segment, ., .., duplicate separator, directory, or symlink is allowed. A retained path and an existing future path must be a regular file. An absent future path is valid only when its existing parent is a real directory, not a symlink, and the child explicitly creates a regular file there. Deleted or renamed parent paths fail the retained regular-file check.

Staged, overlapping, incomplete, or uncertain assignments cannot apply automatically. The coordinator shows the failure and stops for recovery and fresh context. A corrected proposal is reconsidered through the ordinary gates; approval never makes an invalid path assignment valid.

Drafts use the existing TaskDraft fields, including optional complexity and slice. A declared slice must already exist in the area and passes the same slice validation as an ordinary task bundle; a proposal cannot create a slice. blocked_by may name another proposed key or an existing task ID in the same area. It may not name the source task. Existing bundle and graph validation still reject missing dependencies, cycles, self-blocking tasks, and invalid task bodies.

The source identity, proposal, result, and drafts live only in the handoff and command input. Task files keep their current schema.

The coordinator may apply the proposal without another confirmation only when all of these statements are true:

  • the area is open and its task-work status is safe; the branch, goal, source task, HEAD, and three-part Git baseline still match the handoff;
  • an investigation follow-up has a matching independent PASS for the complete result; for a split, any existing delta is either empty or exactly attributed unstaged work of the open source task, and every child names only future path-disjoint work;
  • every draft is necessary to finish the approved objective and stays inside the brief, source task boundaries, and existing testing decision;
  • the proposal introduces no product choice, compatibility policy, destructive operation, new ownership claim, cross-area dependency, or uncertain scope;
  • all keys are exact, unique within the proposal, and absent from the area; and
  • this worker result contains one proposal object, no nested proposal, and this uninterrupted handoff has not applied another proposal.

The coordinator must check the proposal against repository evidence. It never infers safety from filenames, a confidence score, or a worker’s assertion that work is in-scope.

Failure of a mechanical, identity, current-state, graph, or ownership statement stops for recovery and fresh context. Only uncertainty about whether otherwise eligible work is necessary and semantically inside the approved brief and task uses manual review before mutation. Applying a proposal consumes that worker result’s automatic authority; a second object, nested proposal, or second apply in the same handoff cannot run automatically. After an interruption the old handoff has no automatic authority.

A later independently selected execution, including a derived child or the resumed parent, may produce one new proposal and automatic apply if it passes the same current scope, ownership, branch, graph, and safety gates. Each proposal must add zero scope: any wider outcome, product choice, destructive work, or uncertainty cannot apply automatically. A safe, mechanically eligible semantic choice may use manual review; unsafe or destructive state stops. Zdev stores no global or cross-session derivation count and does not infer lineage from task content or Git history.

Malformed proposals, unsafe or closed areas, duplicate keys, invalid graphs, ambiguous ownership, destructive work, widened scope, and unresolved product choices all stop before publication. A malformed handoff is shown as received; only a corrected envelope can be reconsidered. Reopening an area, changing scope, or resolving a product choice remains a user decision. Duplicate detection compares exact keys only; zdev neither guesses semantic equivalence nor renames a key.

Investigation follow-up and implementation split

Section titled “Investigation follow-up and implementation split”

An investigation follow-up completes the source and adds the accepted tasks in one transaction. The new tasks use their declared dependencies and enter the normal numeric ready order. They do not depend on the completed investigation merely to record origin.

An implementation split keeps the source open. The transaction adds every new child ID to the source task’s existing blocked_by list. Children may depend on one another as proposed, but never on the source. The source becomes the final integration and whole-task verification step: it becomes ready only after every child is done, and it can complete only after its original done conditions pass independent verification. No child replaces or relaxes those conditions.

An edited checkout does not by itself force manual review. The coordinator may retain an exact captured delta with the open source task when each child names only future work in split_ownership paths absent from that delta and none of the retained delta is staged. For each child, apply appends this canonical allocation to the rendered task:

- Initial task-owned path allocation: ["src/retry_policy.rs","tests/retry_policy.rs"]. Coordination may extend it only after checking retained parent edits and sibling assignments.

The JSON array uses normalized paths in the proposal’s order. This ordinary task context makes the initial ownership allocation actionable after the transient envelope is gone; it adds no TOML field or lineage record. The split transaction commits only the task records and leaves the parent’s unstaged bytes exactly as they were. Later child work treats that delta as pre-existing parent-owned state under the ordinary baseline rules. Coordination may extend a child’s rendered allocation only after checking the retained parent delta and every sibling allocation. Legacy children rendered with Task-owned paths (exact) remain readable and use the same coordination rule.

If a child must change a path already changed by the parent, any path is staged, another unstaged path exists, or attribution is uncertain, the split stops for recovery and fresh context. The coordinator does not divide hunks, alter the index, stash, reset, or assign partial work by guessing.

The zdev tasks derive review command reports mechanical eligibility and stores the exact proposal JSON, rendered Markdown, and internal metadata in linked-worktree-safe Git administrative state. The coordinator still compares the retained handoff context and decides whether the work is directly in scope. Its compact result identifies the current review and Markdown path without returning the proposal, Markdown, or internal fingerprint. zdev tasks derive review <area> --show presents the actual stored Markdown. Use zdev tasks derive apply to publish an accepted proposal.

When the proposal meets the automatic-approval rules, the coordinator sends it directly to apply. Only semantic authority uncertainty uses manual review, after the proposal, current state, and ownership are otherwise safe and mechanically eligible. zdev tasks derive review validates and stores the complete envelope and returns an opaque review identity. The coordinator requires mechanically_eligible to remain true, shows the stored rendering, and asks for approval. Any replacement invalidates the earlier identity. Manually authored bundles use ordinary stored zdev tasks review and tasks import --reviewed; direct --from and compatibility --approval input remain available.

zdev tasks derive apply accepts either the unchanged envelope directly or the current stored review through --reviewed <review-id>. Automatic use remains one direct --from operation. Before writing, the command acquires the existing state lock, rereads the area, source task, slices, tasks, branch state, Git operation, worktree, and index, allocates IDs, renders all files, and validates the complete hypothetical graph and index. For a split it also requires an empty index, recaptures the complete unstaged path set, requires exact equality with retained_parent_paths, validates every path and disjoint child assignment, and renders the canonical ownership boundary. It runs the same check before committing. An invalid proposal, unsafe or drifted state, staged or incomplete ownership, or another mechanical failure stops without review or publication; the stored review cannot waive any of these gates.

For an investigation follow-up, the coordinator first stages only the verified task-owned artifact paths. Because the proposal has no artifact-path allowlist, the binary treats the entire pre-existing index as the coordinator-authorized artifact set; it does not prove semantic attribution. The coordinator must use retained verifier and baseline evidence to ensure that index exactly equals the verified artifact set. Apply then includes it with the completed source task, child task files, and TASKS.md in the same existing stable-change-ID commit. A split commits only the changed open source task, children, and index; any retained parent delta stays in its exact prior index and worktree state. Thus a successful investigation never has a committed Result without its follow-ups or committed follow-ups without its Result.

Proposal, dependency, graph, check, write, staging, or commit failure leaves no accepted partial result. The command removes every new task, restores the source task and TASKS.md byte for byte, and restores the exact prior index. Pre-existing worktree bytes and unrelated staged or unstaged changes remain unchanged. If rollback itself fails, the command reports every affected path and stops; it never reports the proposal as accepted. Publication success leaves managed paths clean and returns one JSON result with the exact source result, allocated IDs in proposal order, post-import ready frontier, commit, stable change ID, and committed paths.

The success result has this exact field set. Arrays preserve proposal, ready, and committed-path order:

{
"schema_version": 1,
"status": "committed",
"area": "payments",
"source_task": "payments-007",
"proposal": "investigation_follow_up",
"source_result": {
"status": "complete",
"summary": "Settled the retry boundary.",
"validation": ["Compared the design with the current retry implementation."]
},
"tasks": ["payments-008"],
"ready": ["payments-008"],
"commit": "<full-commit-id>",
"change_id": "<stable-change-id>",
"paths": [
"docs/retry-boundary.md",
".zdev/payments/tasks/007-investigate-retry-boundary.md",
".zdev/payments/tasks/008-apply-the-settled-retry-boundary.md",
".zdev/payments/TASKS.md"
]
}

This investigation result forbids split_ownership. A split success result has the same field set and order but requires split_ownership immediately after source_result, copied unchanged from the accepted proposal; its source_result.status is split. The paths array contains only the changed source task, new child task files, and TASKS.md; retained and future source paths are not committed by the split.

After success, the coordinator shows that JSON unchanged. The user can inspect both the proposed work and the result without another confirmation turn.

Scenario Result
Successful investigation Matching PASS; source completion, one to five children, index, artifact, and commit succeed together.
Investigation with no follow-up No proposal is emitted; use ordinary verified completion and commit.
Safe implementation split Empty delta, or exact unstaged parent-owned delta with path-disjoint future child work; task records commit, retained bytes stay unchanged, and the open source is blocked by every child.
Product-choice split Automatic authority fails; show the exact proposal and ask through manual review; write nothing.
Duplicate proposal An existing or repeated key fails before ID allocation or writing; never rename it automatically.
Invalid dependency Missing, source-task, cyclic, or self dependency fails hypothetical graph validation; write nothing.
Publication or commit failure Restore every managed byte and the prior index; preserve unrelated work and report rollback failure explicitly if restoration is incomplete.
Nested or repeated handoff proposal Reject a nested object or second automatic apply from the same worker result; applying consumes that handoff. A later independently selected execution gets one new proposal only after all current gates pass again.