@pmelab/gtd 9.3.0 → 9.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -150,7 +150,11 @@ questions: each open question offers a couple of candidate answers plus a
150
150
  `- [ ] _your answer_` slot, and you tick exactly one per question (the gate
151
151
  won't let the phase advance while any question is unanswered) — but a phase
152
152
  whose document has no open questions skips that human stop entirely and falls
153
- straight through.
153
+ straight through. If a question's options ever come out as prose instead of
154
+ `- [ ]` rows, there is no checkbox for the gate to see, so it stays permanently
155
+ unanswered; un-wedge it yourself: hand-write the `- [ ]` rows and tick one,
156
+ delete that question, or delete the whole `## Open Questions` section to accept
157
+ the plan as-is.
154
158
 
155
159
  Once the product questions are settled, `architecture.author` picks up as a
156
160
  **cold reader** — a separate machine with its own memory scope, so it does not
@@ -185,30 +189,41 @@ alone is not a pending change, and only actually removing it from disk counts as
185
189
  a deletion). The next landing's own script closes the window before it commits.
186
190
  Tick a box as you review each hunk (ticking just records "I read this"), and
187
191
  leave a **comment** to request changes: a note on a line, an inline
188
- `// TODO`-style comment in the code, or a direct code edit. Any comment sends a
189
- build + re-review round — an agent first turns your comments into an explicit
190
- instruction list, then a build turn implements it (a re-review then covers only
191
- the follow-through, and a hand-edit is treated as your own fix the agent
192
- completes without reverting your lines; a comment can't be silently dropped — a
193
- build turn that addresses nothing is refused). The build turn that follows
194
- through on feedback and the turn that drafts the final squash message both
195
- resume the same session that built the feature in the first place, since the
196
- review tail is nested inside that build identity rather than sitting beside it.
197
- Ticking every box with no comment is the sign-off, which collapses the whole
198
- process into one commit (a **squash finale** whose message an agent drafts).
199
- Landing with a box still unticked and no comment is refused (finish reviewing
200
- first), as is deleting `.gtd/REVIEW.md`. Both refusals hold wherever the review
201
- doc lives: repointing `reviewFile` out of `.gtd/` (say to `REVIEW.md` at the
202
- repo root) changes nothing about them — your own edit to the review doc is never
203
- mistaken for a code comment, and the doc's pre-turn copy is read at the review
204
- window's saved head rather than at the rewound `HEAD`.
192
+ `// TODO`-style comment in the code, or a direct code edit. A comment sends a
193
+ FULL development lap, not a quick fix-and-re-review: an agent first judges
194
+ whether your comment is actually actionable (a genuinely approving remark with
195
+ no code edit short-circuits straight to sign-off instead), and an actionable
196
+ round is re-planned from scratch through triage, architecture, and the package
197
+ queue again — a hand-edit you made during review is treated as a **sketch**, the
198
+ same as any other change that starts a process, not a fix the agent builds on:
199
+ it is reverted out of the tree first, and your intent survives only in your own
200
+ review-round commit for triage to read. There is no baseline check on the way
201
+ back into planning. If a styled `.gtd/REVIEW.md` ever comes out malformed (a
202
+ paragraph where a `- [ ] ./path#line` row belongs), `gtd check review` refuses
203
+ the step before it commits: the file stays exactly as written in the working
204
+ tree, unlanded, and re-running the same prompt is the recovery — nothing is
205
+ lost. Only the turn that drafts the final squash message resumes the session
206
+ that built the feature in the first place (the review tail is nested inside that
207
+ build identity rather than sitting beside it) — an actionable round leaves that
208
+ identity entirely, so it starts a fresh session like any other process. Ticking
209
+ every box with no comment is the sign-off, which collapses the whole process
210
+ into one commit (a **squash finale** whose message an agent drafts). Landing
211
+ with a box still unticked and no comment is refused (finish reviewing first), as
212
+ is deleting `.gtd/REVIEW.md`. Both refusals hold wherever the review doc lives:
213
+ repointing `reviewFile` out of `.gtd/` (say to `REVIEW.md` at the repo root)
214
+ changes nothing about them — your own edit to the review doc is never mistaken
215
+ for a code comment, and the doc's pre-turn copy is read at the review window's
216
+ saved head rather than at the rewound `HEAD`.
205
217
 
206
218
  A second entry, the same review tail's own direct entry point —
207
219
  `gtd --entry review-gate.check --var reviewBase=<commitish>` starts a brand new
208
- process reviewing `<commitish>..HEAD` with no build of its own, e.g. a
209
- colleague's PR branch (`review-gate.check`'s `reviewBase:` is a template bound
210
- to the `reviewBase` var, so supplying it via `--var` fixes the whole process's
211
- diff base to that commitish). Its squash keeps and describes only the fixes made
220
+ process reviewing `<commitish>..HEAD` with no build of its own on a clean
221
+ sign-off, e.g. a colleague's PR branch (`review-gate.check`'s `reviewBase:` is a
222
+ template bound to the `reviewBase` var, so supplying it via `--var` fixes the
223
+ whole process's diff base to that commitish) — though an actionable round on
224
+ this entry runs the same full triage → gates → architecture → package-queue lap
225
+ as any other, same as `re-unwind` re-plans a build process's own review
226
+ feedback. A clean sign-off's squash keeps and describes only the fixes made
212
227
  _during_ the review (not the reviewed changeset); a clean sign-off with no fixes
213
228
  becomes an empty `chore: human review` commit. A third entry,
214
229
  `gtd --entry fix-precheck`, starts from a clean `idle` and goes straight into
@@ -240,7 +255,18 @@ per-file var gtd never writes and never reads, since it names your own sketch
240
255
  pad, not a file any state produces. A separate `stateDir` var (default `.gtd`)
241
256
  names only where the check scripts keep their own scratch/bookkeeping,
242
257
  independent of the per-file vars — relocate one steering file without touching
243
- it.
258
+ it. The workflow declares its plumbing directory once, at the top level of the
259
+ `workflow:` value (`stateDir: <%= it.vars.stateDir %>` in the bundled template),
260
+ rendered from that same `stateDir` var — this is what the engine itself reads to
261
+ tell gtd's own bookkeeping apart from your code (e.g. the review window's revert
262
+ pathspec, the step guards' code-vs-plumbing check), not just a value the
263
+ templates happen to share. The rendered value is constrained: it must name a
264
+ directory inside the repository — not the repo root, not an absolute path, and
265
+ not a path that escapes the repository via `..` — and it must be spelled
266
+ canonically: no `.` and no empty path segments (`a/./state` or `a//state` are
267
+ rejected, not rewritten), though a leading `./` and a trailing `/` are accepted
268
+ — or the next `gtd next`/`gtd status`/`gtd land` fails loudly with that message,
269
+ rather than silently excluding the whole tree from the review window's revert.
244
270
 
245
271
  To inspect or change the machine itself, see [Configuration](#configuration) —
246
272
  the workflow is just `.gtdrc` config.
@@ -460,11 +486,15 @@ started FROM. Entering a **descendant** scope (e.g. dipping from `build` into
460
486
  a nested child machine, then back to the parent, still resumes the SAME parent
461
487
  conversation; entering a **sibling or unrelated** scope does start a fresh one.
462
488
  The bundled template's `build.review` (the human review tail) is a worked
463
- example: it is nested INSIDE `build` (the builder's own machine) precisely
464
- because that descendant relationship is what lets `build.addressing` and
465
- `build.squashing` resume the session that built the feature across a full review
466
- round-trip, instead of a root-level sibling breaking that run on every pass
467
- through the tail. Two instances of the same reusable machine (e.g.
489
+ example: it is nested INSIDE `build` (the builder's own machine) so that a
490
+ `gtd --entry fix-precheck` run — `build.fix` -> `build.health.check` ->
491
+ `build.review.*` -> `build.squashing` — stays inside one subtree, letting
492
+ `build.squashing` resume the SAME session that made the fixes instead of a
493
+ root-level sibling forcing it to re-derive the range from scratch on every pass
494
+ through the tail. (An actionable review round breaks the run on purpose instead
495
+ — it leaves `build` entirely through a root-level `re-unwind` state and a full
496
+ re-plan, since a hand-edit made during review is a sketch to reconsider, not a
497
+ fix to build on.) Two instances of the same reusable machine (e.g.
468
498
  `build.health` and `packages.item.health`, both instantiating `healthGate`) get
469
499
  different scopes and so never share a key, even though they're the "same shaped"
470
500
  machine. One consequence is a structural guarantee: **a reviewer's turn never
@@ -830,18 +860,19 @@ its own retry/resume logic beyond "if the script failed, ask gtd again."
830
860
  A mode's `format:` command may reformat a steering file — whitespace, wrapping,
831
861
  reordering — but must NEVER change what a land-capture guard would decide. gtd's
832
862
  guards (the review sign-off check, the feedback-progress check, the
833
- answer-completeness check — `src/StepGuards.ts`) decide ONCE, against whichever
834
- bytes are on disk at the moment `gtd land` runs, which may be before OR after an
835
- emitted script's own `format:` line has run (the script runs `format:` then
836
- `validate:` then the commit — see `src/SteeringMode.ts`'s
837
- `renderSteeringCommands` — but gtd's decision and the driver's script execution
838
- are different processes at different times, so there's no guaranteed ordering
839
- between "gtd decided" and "the script formatted"). That's only safe because
840
- every built-in guard judges content, not incidental formatting (e.g. it
841
- normalizes `[ ]`/`[x]` checkboxes before comparing). If you plug in your own
842
- `format:` command, the same rule binds it: a formatter that also changes meaning
843
- — ticking a box, stripping a paragraph — makes the guard's decision and the
844
- file's actual content disagree, and gtd will not catch that for you.
863
+ answer-completeness check, the require-revert check — `src/StepGuards.ts`)
864
+ decide ONCE, against whichever bytes are on disk at the moment `gtd land` runs,
865
+ which may be before OR after an emitted script's own `format:` line has run (the
866
+ script runs `format:` then `validate:` then the commit — see
867
+ `src/SteeringMode.ts`'s `renderSteeringCommands` — but gtd's decision and the
868
+ driver's script execution are different processes at different times, so there's
869
+ no guaranteed ordering between "gtd decided" and "the script formatted"). That's
870
+ only safe because every built-in guard judges content, not incidental formatting
871
+ (e.g. it normalizes `[ ]`/`[x]` checkboxes before comparing). If you plug in
872
+ your own `format:` command, the same rule binds it: a formatter that also
873
+ changes meaning — ticking a box, stripping a paragraph — makes the guard's
874
+ decision and the file's actual content disagree, and gtd will not catch that for
875
+ you.
845
876
 
846
877
  One case never runs your `format:` (or `validate:`) at all: a step whose diff
847
878
  DELETES the state's own `file:`. Deleting it is a legitimate outcome — a review
@@ -928,6 +959,7 @@ workflow:
928
959
  <name>:
929
960
  format: <shell command> # both optional — {} is the format-only tier
930
961
  validate: <shell command>
962
+ stateDir: <string> # optional, an Eta template naming where this workflow keeps its own plumbing (default ".gtd") — the definition-level declaration the engine reads, distinct from the `vars.stateDir` var the bundled template renders it from
931
963
  entry:
932
964
  default: <machine name> # which machine is the ROOT instance
933
965
  machines:
@@ -960,6 +992,7 @@ workflow:
960
992
  # reviewBase: <Eta template> # OR a template — rendered (only meaningful entering via --entry) to a commitish that fixes the WHOLE PROCESS's diff base
961
993
  requireProgress: true # optional, requires "file" — refuse a turn whose only change deletes this state's own `file:`
962
994
  answerGate: true # optional, requires "file" — refuse a turn until every open question in the (qa-mode) `file:` is answered
995
+ requireRevert: true # optional, requires "file" — refuse a turn until the human's review-round paths actually match the review base's parent
963
996
  entry: true # optional — an EXTRA reachability root (`entries.manual`), enterable via `gtd --entry <this state's qualified name>` — NOT a precondition for `--entry` (any declared, non-commit state is a valid target)
964
997
  <local>: { machine: <name>, with: { <param>: <value> } } # a REFERENCE — instantiates <name> as a child, qualified as `<local>.<childLocal>`
965
998
  ```
@@ -972,7 +1005,11 @@ derives a driver's session id).
972
1005
  The top-level `entry:` key (naming the root machine, `entry.default`) and a
973
1006
  state's own `entry: true` flag are the same word at two different levels, by
974
1007
  design: one selects the workflow's root machine, the other opts one state in as
975
- an extra manual entry point.
1008
+ an extra manual entry point. The top-level `stateDir:` key and the
1009
+ `vars.stateDir` var it renders from are the same call: the definition-level
1010
+ declaration is what the engine reads (e.g. to tell gtd's own plumbing apart from
1011
+ your code), while the var is the knob you actually override — repointing
1012
+ `vars.stateDir` moves both.
976
1013
 
977
1014
  A workflow is authored as a TREE of reusable, parameterized machines — a
978
1015
  gate/loop written once and instantiated several times with different `with:`
@@ -992,7 +1029,12 @@ Besides `it.vars` (below), a `script`/`prompt`/`message`/`commit` template sees:
992
1029
  - **`it.startCommit`** — the process's diff base (the commit the current process
993
1030
  started from, or the base a `--var reviewBase=<commitish>` entry resolved to).
994
1031
  - **`it.reviewBase`** — the previous review round's boundary, falling back to
995
- `it.startCommit` on a first review.
1032
+ `it.startCommit` on a first review. In the bundled template, an actionable
1033
+ round's NEXT review therefore covers the revert of the human's own lines
1034
+ (`re-unwind`) followed by the whole lap that re-derives and re-implements them
1035
+ — the net diff is the final implementation, the right thing to review, but no
1036
+ longer the tiny "just the fixes" delta a quick fix-and-re-review would have
1037
+ shown.
996
1038
  - **`it.retainedBase`** — the process's trace/retry boundary, what a squash
997
1039
  actually keeps (never moved by a review entry's fixed base).
998
1040
  - **`it.currentCommit`** / **`it.previousCommit`** — HEAD's hash and its parent,
@@ -1095,6 +1137,16 @@ model, pattern grammar, load-time rules, and how to verify a change compiles.
1095
1137
  > `gtd abandon` it (or finish it on the pre-upgrade workflow version) before
1096
1138
  > upgrading.
1097
1139
 
1140
+ > **Upgrading a `workflow:` that still references `build.addressing`?** That
1141
+ > state is REMOVED, not renamed — the implementer's own follow-through on review
1142
+ > feedback is gone outright, since an actionable review round is now re-planned
1143
+ > from scratch through a new root-level `re-unwind` state (reverting the human's
1144
+ > hand-edit) instead of being built upon. A non-actionable round (an approving
1145
+ > remark with no code edit) short-circuits straight to `build.squashing` instead
1146
+ > of spending a lap on nothing. As with every rename above, an in-flight process
1147
+ > resting at `build.addressing` can no longer be resumed after upgrading;
1148
+ > `gtd abandon` it (or finish it on the pre-upgrade workflow version) first.
1149
+
1098
1150
  ### Variables
1099
1151
 
1100
1152
  Every template — `script`/`prompt`/`message`/`commit`, a machine's own `model:`,
@@ -1134,6 +1186,52 @@ vars:
1134
1186
  GTD_TESTCOMMAND="npm run test -- --bail" gtd next
1135
1187
  ```
1136
1188
 
1189
+ #### The voice
1190
+
1191
+ gtd ships its own writing voice for the files it generates — the default, not an
1192
+ opt-in. It is a specialisation of the "Spartan" output style from
1193
+ [alexgreensh/attention-span](https://github.com/alexgreensh/attention-span)
1194
+ (AGPL-3.0), written from a reading of that project's version `0.6`: gtd's own
1195
+ prose stating the same density discipline, rewritten for deliverables (files
1196
+ that run as long as the work needs) rather than chat replies. No upstream text
1197
+ ships in gtd's bundle. This is a point-in-time derivation with no refresh
1198
+ mechanism — it will silently go stale as upstream moves on, and nothing in gtd
1199
+ will notice.
1200
+
1201
+ It is two independently-overridable variables, each an ordinary `vars:` entry
1202
+ that can be overridden or blanked through the same layers as any other (a
1203
+ top-level `.gtdrc` `vars:` key, or the matching `GTD_STYLEBLOCK` /
1204
+ `GTD_STYLEFORMATCONTRACT` environment variable):
1205
+
1206
+ - **`styleBlock`** — the voice itself, injected at all seven prompt states that
1207
+ generate content, not just three: the free-prose ones — the `packagesDir`
1208
+ package files (`architecture.decompose`), `specFeedbackFile`
1209
+ (`packages.item.spec.review`), and `commitMsgFile` (`build.squashing`) — plus
1210
+ the four machine-parsed states named in the next bullet. Blanking
1211
+ `GTD_STYLEBLOCK` strips the voice from all seven, including the machine-parsed
1212
+ ones, not only the free-prose three. In short: why density matters before any
1213
+ rule, answer-first with no preamble or restatement, blunt and imperative,
1214
+ plain words, bold carries the load, ship the artifact bare, compressing is not
1215
+ dropping, one idea per block, flag risk in one blunt line, never narrate the
1216
+ work — and never-trim outranks every other rule in the set.
1217
+ - **`styleFormatContract`** — the structural override for machine-parsed files:
1218
+ the format contract (headings, checkbox rows, marker lines) outranks the
1219
+ voice, and a violation refuses the turn. It renders at the top of the prompt,
1220
+ ahead of the role sentence and well before any state-specific format-contract
1221
+ text — `styleBlock` first, then `styleFormatContract`, at the four prompt
1222
+ states whose output a parser reads: the two `qa`-mode steering files
1223
+ (`requirementsFile` at `design.triage`, `architectureFile` at
1224
+ `architecture.author`) and the `review`-mode one (`reviewFile` at
1225
+ `build.review.reviewing`), plus `requirementsFile` again at
1226
+ `build.review.collecting`, which classifies a review round straight into it.
1227
+
1228
+ Three more generated files carry no injected voice, because a script — not an
1229
+ agent — writes them: `feedbackFile` (verbatim test-suite output plus a HEAD
1230
+ stamp — the tool's content, not gtd's prose), `nextFile` (a bare path, no prose
1231
+ to style), and `reviewRawFile` (gtd's own prose, hand-tightened in the voice
1232
+ directly in `build.review.deciding`'s script rather than templated in through
1233
+ either variable).
1234
+
1137
1235
  ### Lookup and precedence
1138
1236
 
1139
1237
  gtd walks from the current working directory **up to your home directory** (or