@pmelab/gtd 41.0.0 → 42.0.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.
Files changed (54) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +38 -28
  3. package/dist/chunks/{reserved-Ch4LLrEj.mjs → reserved-D7MNY9QJ.mjs} +58 -14
  4. package/dist/chunks/{steering-DVILanVf.mjs → steering-oCDdQlpP.mjs} +1 -1
  5. package/dist/chunks/tail-D2o2h5cc.mjs +246 -0
  6. package/dist/flows.mjs +11 -1
  7. package/dist/gtd.bundle.mjs +12 -2
  8. package/dist/steering.mjs +1 -1
  9. package/dist/testkit.mjs +15 -3
  10. package/dist/web/main.js +1 -1
  11. package/dist/workflow-kit.mjs +1 -1
  12. package/dist/workflows/cleanup.mjs +2 -2
  13. package/dist/workflows/feature.mjs +44 -24
  14. package/dist/workflows/fix.mjs +3 -3
  15. package/dist/workflows/review.mjs +2 -2
  16. package/dist/workflows/rollout.mjs +1 -1
  17. package/dist/workflows.mjs +245 -36
  18. package/package.json +1 -1
  19. package/src/flows/scripts.ts +15 -0
  20. package/src/steering/review.test.ts +2 -20
  21. package/src/steering/review.ts +2 -1
  22. package/src/testkit/FlowScripts.test.ts +17 -0
  23. package/src/testkit/FlowScripts.ts +15 -0
  24. package/src/testkit/steps.ts +27 -0
  25. package/src/workflows/feature/coverage.feature +3 -3
  26. package/src/workflows/feature/fast-path.feature +2 -2
  27. package/src/workflows/feature/feature.test.ts +2 -37
  28. package/src/workflows/feature/feature.ts +12 -14
  29. package/src/workflows/feature/flag-mode.feature +2 -2
  30. package/src/workflows/feature/lens-review.feature +234 -0
  31. package/src/workflows/feature/one-step-land.feature +2 -2
  32. package/src/workflows/feature/quality-unresolved.feature +47 -32
  33. package/src/workflows/feature/refactor-absorbs.feature +3 -3
  34. package/src/workflows/feature/refactor-first.feature +5 -5
  35. package/src/workflows/feature/refactor-rebuild.feature +7 -7
  36. package/src/workflows/feature/refactor-review.feature +19 -100
  37. package/src/workflows/feature/refactor.test.ts +12 -27
  38. package/src/workflows/feature/refactor.ts +0 -1
  39. package/src/workflows/feature/review-gate.feature +6 -6
  40. package/src/workflows/feature/review.test.ts +29 -25
  41. package/src/workflows/feature/review.ts +53 -10
  42. package/src/workflows/feature/seam-rejection.feature +2 -2
  43. package/src/workflows/feature/seam.feature +2 -2
  44. package/src/workflows/feature/seam.test.ts +1 -1
  45. package/src/workflows/feature/slicing.feature +6 -6
  46. package/src/workflows/index.ts +1 -0
  47. package/src/workflows/shared/lenses.test.ts +39 -0
  48. package/src/workflows/shared/lenses.ts +176 -0
  49. package/src/workflows/shared/options.ts +1 -0
  50. package/src/workflows/shared/tail.ts +19 -4
  51. package/src/workflows/shared/text.test.ts +68 -1
  52. package/src/workflows/shared/text.ts +126 -13
  53. package/src/workflows/shared/vars.ts +1 -0
  54. package/dist/chunks/tail-lY1UmJrU.mjs +0 -112
package/dist/steering.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { C as headingSections, S as headingSectionBodies, _ as openThreadFindings, a as unansweredQuestions, b as parseThreadsWithFindings, c as stripCodeThreads, d as reviewNotes, f as reviewRisks, g as THREAD_REPLY_ACTION_TITLE, h as FOOTNOTE_ACTION_TITLE, i as steeringFormatOrFreeForm, l as freeFormFormat, m as isAnswered, n as openThreads, o as viewOf, p as FREE_TEXT_PLACEHOLDER, r as steeringFormatFor, s as parseCodeThreads, t as BUILT_IN_MODE_NAMES, u as applySteeringEdits, v as parseFootnotes, w as formatFinding, x as getParseCount, y as parseThreads } from "./chunks/steering-DVILanVf.mjs";
1
+ import { C as headingSections, S as headingSectionBodies, _ as openThreadFindings, a as unansweredQuestions, b as parseThreadsWithFindings, c as stripCodeThreads, d as reviewNotes, f as reviewRisks, g as THREAD_REPLY_ACTION_TITLE, h as FOOTNOTE_ACTION_TITLE, i as steeringFormatOrFreeForm, l as freeFormFormat, m as isAnswered, n as openThreads, o as viewOf, p as FREE_TEXT_PLACEHOLDER, r as steeringFormatFor, s as parseCodeThreads, t as BUILT_IN_MODE_NAMES, u as applySteeringEdits, v as parseFootnotes, w as formatFinding, x as getParseCount, y as parseThreads } from "./chunks/steering-oCDdQlpP.mjs";
2
2
  export { BUILT_IN_MODE_NAMES, FOOTNOTE_ACTION_TITLE, FREE_TEXT_PLACEHOLDER, THREAD_REPLY_ACTION_TITLE, applySteeringEdits, formatFinding, freeFormFormat, getParseCount, headingSectionBodies, headingSections, isAnswered, openThreadFindings, openThreads, parseCodeThreads, parseFootnotes, parseThreads, parseThreadsWithFindings, reviewNotes, reviewRisks, steeringFormatFor, steeringFormatOrFreeForm, stripCodeThreads, unansweredQuestions, viewOf };
package/dist/testkit.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { applyScript, checkScript, configProblems, configure, installContext, isFactoryWorkflow, moveScript, protocolMismatch, removeScript, restoreScript, revertScript, showScript, t as flows_exports } from "./flows.mjs";
1
+ import { applyScript, checkScript, configProblems, configure, installContext, isFactoryWorkflow, moveScript, protocolMismatch, removeScript, restoreScript, revertScript, showScript, t as flows_exports, writeScript } from "./flows.mjs";
2
2
  import { A as beatKindOf, B as ACCESS_REFUSAL, C as renderLandPlain, D as renderBeatJson, E as beatDocument, O as statusOf, S as renderLandJson, T as renderBeatPlain, U as renderFormat, _ as selectPath, a as contextLimitFault, g as resolveSession, h as globMatches, j as demandOf, l as parseContextWindow, m as slicesDocument, o as contextShapeFault, p as renderSlicesJson, v as judgeJson, x as noopText, y as landFields } from "./chunks/wire-BJuZWR3C.mjs";
3
- import { C as headingSections, S as headingSectionBodies, a as unansweredQuestions, b as parseThreadsWithFindings, n as openThreads, r as steeringFormatFor, s as parseCodeThreads, t as BUILT_IN_MODE_NAMES, w as formatFinding } from "./chunks/steering-DVILanVf.mjs";
3
+ import { C as headingSections, S as headingSectionBodies, a as unansweredQuestions, b as parseThreadsWithFindings, n as openThreads, r as steeringFormatFor, s as parseCodeThreads, t as BUILT_IN_MODE_NAMES, w as formatFinding } from "./chunks/steering-oCDdQlpP.mjs";
4
4
  import { $ as logWarning, $i as BaseProto, $n as map$5, $r as make$19, $t as provide$1, A as catchIf, Ai as add$1, An as scopeMake, Ar as flatMap$3, At as suspend$5, B as flatMap$4, Bi as getOrElse, Bn as get$3, Br as sync$1, Bt as unsafeMakeLatch, C as all$1, Ci as toArray, Cn as isInterrupted, Cr as exitFail, Ct as sandbox, D as async, Di as GenericTag, Dn as squash, Dr as exitZipRight, Dt as scopedWith$1, E as asVoid$1, Ei as unsafeHead, En as reduceWithContext, Er as exitVoid, Et as scoped$4, F as ensuring$2, Fi as fromIterable, Fn as join$3, Fr as map$3, Ft as tryMap, G as forkIn, Gi as match$4, Gn as TypeId$10, Gr as whenEffect, Gt as zipLeft, H as fnUntraced, Hi as isNone, Hn as modify$1, Hr as uninterruptible, Ht as when, I as exit, Ii as splitAt, In as sequential, Ir as onInterrupt, It as tryPromise, J as ignore, Ji as isLeft, Jn as all, Jr as DeferredTypeId$1, Jt as spaced$1, K as forkScoped, Ki as none, Kn as Class, Kr as withFiberRuntime, Kt as zipRight$3, L as fail$5, Li as filter$1, Ln as bind, Lr as scopeClose, Lt as try_, M as die$2, Mi as getOption, Mn as _await$2, Mr as interruptAsFiber, Mt as tap, N as dieMessage, Ni as omit, Nn as inheritAll$1, Nr as interruptFiber, Nt as tapErrorCause, O as catchAll$1, Oi as Reference, On as ensuring$3, Or as fiberId, Ot as serviceOption, P as either, Pi as empty$5, Pn as interruptAllAs$1, Pr as interruptible$1, Pt as timeout, Q as isEffect, Qi as pipeArguments, Qn as isFailure, Qr as ids, Qt as mergeAll$2, R as failCause$4, Ri as flatMap$5, Rn as bindTo, Rr as succeed$4, Rt as uninterruptible$1, S as addFinalizer$1, Si as takeRight, Sn as isDieType, Sr as exitAs, St as runtime, T as as, Ti as unsafeGet, Tn as map$6, Tr as exitSucceed, Tt as scopeWith, U as forEach$2, Ui as isSome, Un as set$1, Ur as uninterruptibleMask$1, Ut as withFiberRuntime$1, V as flatten$4, Vi as getOrUndefined, Vn as make$16, Vr as tap$1, Vt as unsafeMakeSemaphore$1, W as forkDaemon, Wi as map$8, Wn as update$1, Wr as void_$2, Wt as zip$1, X as interruptible, Xi as match$2, Xn as fail$4, Xr as combine, Xt as tagged, Y as interrupt$4, Yi as left, Yn as die, Yr as empty$6, Yt as TaggedError$1, Z as intoDeferred, Zi as right, Zn as failCause$3, Zr as combineAll, Zt as fromEffect$5, _ as decodeSync, _i as of, _n as fail$3, _r as deferredIsDone, _t as raceWith, a as Literal, aa as constFalse, ai as size$2, an as updateContext$1, ar as zipRight$2, at as matchCause, b as acquireRelease, bi as reverse, bn as interrupt$3, br as deferredUnsafeDone, bt as runPromise, c as String$, ca as constVoid, ci as append$1, cn as Scope, cr as asyncInterrupt, ct as negate, d as Union, da as pipe, di as empty$4, dn as close, dr as deferredAwait, dt as orElse, ea as NodeInspectSymbol, ei as none$1, en as provideMerge$1, er as mapBoth, et as makeSemaphore, f as between, fi as filter, fn as extend, fr as deferredComplete, ft as orElseSucceed, gi as map$7, gn as die$1, gr as deferredInterruptWith, gt as race, hi as isEmpty$2, hn as NoSuchElementException, hr as deferredInterrupt, ht as provideService, i as Defect, ia as hasProperty, ii as has, in as unsafeRunPromiseExit, ir as zip$2, it as match$5, j as catchTag, ji as get$5, jn as scopeTag, jr as interrupt$2, jt as sync$2, k as catchAllCause, ki as Tag, kn as forEachConcurrentDiscard, kr as fiberRefLocally, kt as succeed$6, l as Struct, la as dual, li as appendAll, ln as addFinalizer, lr as catchAll, lt as onError, m as optional$1, mi as isChunk, mn as make$18, mr as deferredFailCause, mt as provide$2, n as Boolean$, na as toJSON, ni as make$17, nn as succeed$3, nr as succeed$5, nt as mapBoth$1, o as Never, oa as constTrue, oi as decode, on as forkIn$1, or as as$1, ot as matchCauseEffect, p as decodeUnknown, pi as fromIterable$1, pn as fork, pr as deferredFail, pt as promise, q as gen, qi as some, qn as spanTag, qr as zipRight$1, qt as zipWith, r as Cause, ra as equals, ri as set$2, rn as unsafeFork, rr as void_$3, rt as mapError, s as Number$, sa as constUndefined, si as isFinite, sn as unsafeMakeSemaphore, sr as asVoid, st as matchEffect, t as Array$, ta as format, ti as get$4, tn as scoped$3, tr as match$3, tt as map$4, u as TaggedError, ua as identity, ui as drop, un as addFinalizerExit, ur as currentContext$1, ut as orDie, v as encodeSync, vi as prepend, vn as failureOrCause, vr as deferredMake, vt as repeat, w as annotateLogs, wi as unsafeFromArray, wn as isInterruptedOnly, wr as exitFailCause, wt as scope, x as acquireUseRelease$2, xi as take$2, xn as interruptors, xr as deferredUnsafeMake, xt as runPromiseExit$1, y as _void, yi as reduce, yn as flipCauseOption, yr as deferredSucceed, yt as retry, z as fiberIdWith, zi as fromNullable, zn as sleep, zr as suspend$4, zt as uninterruptibleMask } from "./chunks/Schema-C6fLlQzx.mjs";
5
5
  import { createRequire } from "node:module";
6
6
  import * as Crypto from "node:crypto";
@@ -13068,6 +13068,18 @@ const recognizeMove = (repo, script) => {
13068
13068
  repo.writeFile(to, content);
13069
13069
  return ok();
13070
13070
  };
13071
+ const recognizeWrite = (repo, script) => {
13072
+ const lines = shellLines(script.split("\n"));
13073
+ if (!lines[3]?.startsWith("printf '%s' ")) return void 0;
13074
+ const [path] = words$1(lines[2] ?? "");
13075
+ const [, content, to] = words$1(lines[3]);
13076
+ const remove = words$1(lines.find((l) => l.startsWith("rm -rf -- ")) ?? "");
13077
+ if (path === void 0 || content === void 0 || to !== path) return void 0;
13078
+ if (writeScript(path, content, remove) !== script) return void 0;
13079
+ repo.writeFile(path, content);
13080
+ removeAll(repo, remove);
13081
+ return ok();
13082
+ };
13071
13083
  const recognizeShow = (repo, script) => {
13072
13084
  const line = script.split("\n").find((l) => l.startsWith("git show ")) ?? "";
13073
13085
  const [source, to] = words$1(line);
@@ -13312,7 +13324,7 @@ const recognizeCheck = (repo, commands, script) => {
13312
13324
  */
13313
13325
  const applyFlowScript = (repo, commands, script) => {
13314
13326
  if (!script.startsWith(`${SHEBANG}\n`)) return void 0;
13315
- return recognizeRemove(repo, script) ?? recognizeMove(repo, script) ?? recognizeShow(repo, script) ?? recognizePatch(repo, script) ?? recognizeRestore(repo, script) ?? recognizeCheck(repo, commands, script);
13327
+ return recognizeRemove(repo, script) ?? recognizeMove(repo, script) ?? recognizeShow(repo, script) ?? recognizeWrite(repo, script) ?? recognizePatch(repo, script) ?? recognizeRestore(repo, script) ?? recognizeCheck(repo, commands, script);
13316
13328
  };
13317
13329
  //#endregion
13318
13330
  //#region src/testkit/EmittedScriptRecognizer.ts
package/dist/web/main.js CHANGED
@@ -31891,7 +31891,7 @@ const parseChangesets = (tree, content, lines) => {
31891
31891
  const title = headingText$1(content, heading);
31892
31892
  const { description, descriptionNodes, descriptionInline, files, errors: bodyErrors } = parseChunkBody(content, lines, title, body);
31893
31893
  errors.push(...bodyErrors);
31894
- if (files.length === 0) errors.push({
31894
+ if (files.length === 0 && body.some((n) => taskItems(n).length > 0)) errors.push({
31895
31895
  message: `Chunk "${title}" has no file pointers`,
31896
31896
  line: headingLine,
31897
31897
  range: nodeRange(heading)
@@ -1,5 +1,5 @@
1
1
  import { changes, changesSince, hasThreadFor, head, read, refuse, requireReplies, requireThreadsClosed, scope } from "./flows.mjs";
2
- import { c as stripCodeThreads, d as reviewNotes, f as reviewRisks, y as parseThreads } from "./chunks/steering-DVILanVf.mjs";
2
+ import { c as stripCodeThreads, d as reviewNotes, f as reviewRisks, y as parseThreads } from "./chunks/steering-oCDdQlpP.mjs";
3
3
  //#region src/workflow-kit/health.ts
4
4
  /** Hand a red suite that repeated attempts could not fix to a person, until `limit` rounds are spent. */
5
5
  const escalation = async (count, steps) => {
@@ -1,6 +1,6 @@
1
1
  import { agent, changes, glob, read, refuse, scope, start, vars } from "../flows.mjs";
2
- import { Dt as registryEntry, Ot as requireFlag, S as coder, St as envDefaults, Tt as flagReferences, i as skills, n as summary, o as flagShipped, r as access, t as steering, xt as defaults } from "../chunks/reserved-Ch4LLrEj.mjs";
3
- import { a as refusePendingHandOff, r as handOffTail } from "../chunks/tail-lY1UmJrU.mjs";
2
+ import { At as registryEntry, Ot as flagReferences, S as coder, Tt as envDefaults, i as skills, jt as requireFlag, n as summary, o as flagShipped, r as access, t as steering, wt as defaults } from "../chunks/reserved-D7MNY9QJ.mjs";
3
+ import { a as refusePendingHandOff, r as handOffTail } from "../chunks/tail-D2o2h5cc.mjs";
4
4
  //#region src/workflows/cleanup/cleanup.ts
5
5
  const removingPrompt = (name, registry) => `Clean up the release flag "${name}", which is default-on: delete its entry in ${registry}, and remove every \`GTD_FLAG_${name.toUpperCase()}\` check from the shipped sources. Keep the flag-on path; delete code only the off path reached, including tests that pin the off path.`;
6
6
  const cleanupFlow = async () => {
@@ -1,7 +1,7 @@
1
- import { agent, answered, applyScript, changes, changesSince, check, codeChanges, env, hasThreadFor, head, human, judge, judgeDiffShape, kept, mark, matches, numeric, quote, read, refuse, removeScript, requireAnswers, requireProgress, requireReplies, requireRevert, requireThreadsClosed, restoreScript, revertScript, run, scope, slice, start, vars, wrote } from "../flows.mjs";
2
- import { lensEntriesOf, review as review$1 } from "../workflow-kit.mjs";
3
- import { $ as naiveApplyFailure, A as agentWithSkills, B as coverageQuestion, C as fixCheck, Ct as testFileGlobs, D as reviewMissing, E as planner, F as buildReviewTriageMessage, G as designSystem, H as criterionLine, I as builderSystem, K as designTriagePrompt, L as clearCriteriaMessage, M as buildReviewAwaitAfterDeferMessage, N as buildReviewCollectingPrompt, P as buildReviewFixNitsPrompt, Q as implementFixPrompt, R as clearCriteriaQuestion, S as coder, St as envDefaults, T as fixRisks, U as deferNotesScript, V as coveringPrompt, W as designGateAnswerMessage, X as idleMessage, Z as implementBuildingPrompt, _ as REFACTOR_NOTE, _t as startGateBlockedMessage, a as flagModeOn, at as refactorDroppedRefusal, b as SLICES, bt as unwindFailure, ct as refactorRules, d as guarded, et as naivePassPrompt, f as healthy, ft as reviewNotesCapture, g as REFACTOR, gt as slicingPrompt, h as QUALITY, ht as seamSteerMessage, i as skills, it as refactorBuildingPrompt, j as buildReviewAnswerQuestionsPrompt, k as reviewing, lt as reviewEditNotesCapture, m as HANDOFF, mt as seamByHandMessage, n as summary, nt as oversizedMessage, ot as refactorFixPrompt, p as FEEDBACK, pt as reviewerSystem, r as access, rt as qualityUnresolvedMessage, s as shipped, st as refactorNotePrompt, t as steering, tt as normaliseCriteriaScript, u as gate, ut as reviewEditsCapture, v as REQUIREMENTS, vt as uncoveredMessage, x as awaitReview, xt as defaults, y as REVIEW, yt as unwindFailedMessage, z as coverageMessage } from "../chunks/reserved-Ch4LLrEj.mjs";
4
- import { a as refusePendingHandOff, i as isOptionalObject, n as closeReview, o as tail } from "../chunks/tail-lY1UmJrU.mjs";
1
+ import { agent, answered, applyScript, changes, changesSince, check, codeChanges, env, hasThreadFor, head, human, judge, judgeDiffShape, kept, mark, matches, numeric, quote, read, refuse, removeScript, requireAnswers, requireProgress, requireReplies, requireRevert, requireThreadsClosed, restoreScript, revertScript, run, scope, showScript, slice, start, vars, writeScript, wrote } from "../flows.mjs";
2
+ import { lensEntriesOf, removedAssertions, review as review$1 } from "../workflow-kit.mjs";
3
+ import { $ as implementFixPrompt, A as agentWithSkills, B as coverageMessage, C as fixCheck, Ct as unwindFailure, D as reviewMissing, E as planner, Et as testFileGlobs, F as buildReviewTriageMessage, G as designGateAnswerMessage, H as coveringPrompt, I as builderSystem, K as designSystem, L as clearCriteriaMessage, M as buildReviewAwaitAfterDeferMessage, N as buildReviewCollectingPrompt, P as buildReviewFixNitsPrompt, Q as implementBuildingPrompt, R as clearCriteriaQuestion, S as coder, St as unwindFailedMessage, T as fixRisks, Tt as envDefaults, U as criterionLine, V as coverageQuestion, W as deferNotesScript, Z as idleMessage, _ as REFACTOR_NOTE, _t as seamByHandMessage, a as flagModeOn, b as SLICES, bt as startGateBlockedMessage, ct as refactorDroppedRefusal, d as guarded, dt as refactorRules, et as naiveApplyFailure, f as healthy, ft as reviewEditNotesCapture, g as REFACTOR, gt as reviewerSystem, h as QUALITY, ht as reviewNotesCapture, i as skills, j as buildReviewAnswerQuestionsPrompt, lt as refactorFixPrompt, m as HANDOFF, n as summary, nt as normaliseCriteriaScript, ot as qualityUnresolvedMessage, p as FEEDBACK, pt as reviewEditsCapture, q as designTriagePrompt, r as access, rt as oversizedMessage, s as shipped, st as refactorBuildingPrompt, t as steering, tt as naivePassPrompt, u as gate, ut as refactorNotePrompt, v as REQUIREMENTS, vt as seamSteerMessage, wt as defaults, x as awaitReview, xt as uncoveredMessage, y as REVIEW, yt as slicingPrompt, z as composedReview } from "../chunks/reserved-D7MNY9QJ.mjs";
4
+ import { a as refusePendingHandOff, i as isOptionalObject, n as closeReview, o as tail, s as NO_FINDINGS } from "../chunks/tail-D2o2h5cc.mjs";
5
5
  import { posix } from "node:path";
6
6
  //#region src/workflows/shared/fences.ts
7
7
  const markFenced = (text) => {
@@ -409,10 +409,24 @@ const triage$1 = (severities) => async (notes) => {
409
409
  };
410
410
  const isCode$1 = (path) => path !== ".gtd" && !path.startsWith(".gtd/");
411
411
  /**
412
- * A reviewer writes `.gtd/REVIEW.md` over everything since `base`, a human
413
- * reviews and signs off or comments, and each note is judged: edits go to
414
- * another planning lap, questions are answered in place, nits fixed in one
415
- * batch, praise dropped.
412
+ * gtd writes `.gtd/REVIEW.md` from the quality lap's `report` — no reviewer
413
+ * turn — and removes what the fixer left in `.gtd/QUALITY.md`. A re-review
414
+ * after fixed nits restores the doc as committed at `carry`, answers kept.
415
+ */
416
+ const composing = (base, report, carry, nitFix) => run("review.composing", carry === void 0 ? writeScript(REVIEW, composedReview(base, {
417
+ ...report,
418
+ weakened: removedAssertions(changesSince(base)),
419
+ nitFix
420
+ }), [QUALITY]) : showScript(carry, REVIEW, REVIEW), {
421
+ label: "Composing the review",
422
+ file: REVIEW,
423
+ base
424
+ });
425
+ /**
426
+ * The quality lap's notes reach a human over everything since `base`, who
427
+ * signs off or comments, and each note is judged: edits go to another
428
+ * planning lap, questions are answered in place, nits fixed in one batch,
429
+ * praise dropped.
416
430
  */
417
431
  const review = (base, escalations = { rounds: 0 }, options = {}) => {
418
432
  const { guard, guardRests, fixAccess, rules } = options;
@@ -423,13 +437,16 @@ const review = (base, escalations = { rounds: 0 }, options = {}) => {
423
437
  };
424
438
  const severities = /* @__PURE__ */ new Map();
425
439
  let deferred = [];
440
+ let nitFix;
426
441
  return review$1(base, {
427
442
  file: REVIEW,
428
443
  feedback: feedback.file,
429
444
  isCode: isCode$1,
430
445
  reviewing: (b, carry) => {
431
446
  deferred = [];
432
- return reviewing(b, carry, options.lap);
447
+ const fixedAt = nitFix;
448
+ nitFix = void 0;
449
+ return composing(b, options.report ?? NO_FINDINGS, carry, fixedAt);
433
450
  },
434
451
  fixRisks: guarded((notes) => fixRisks(notes, fixAccess, rules), guard),
435
452
  keepGreen: () => healthy(() => fixCheck(rules), {
@@ -456,7 +473,10 @@ const review = (base, escalations = { rounds: 0 }, options = {}) => {
456
473
  return deferNotes(deferred, head());
457
474
  },
458
475
  answerQuestions: answerReviewQuestions,
459
- fixNits: guarded((notes) => fixNits(notes, fixAccess, rules), guard),
476
+ fixNits: async (notes) => {
477
+ await guarded((n) => fixNits(n, fixAccess, rules), guard)(notes);
478
+ nitFix = head();
479
+ },
460
480
  close: closeReview,
461
481
  captures: {
462
482
  edits: reviewEditsCapture,
@@ -483,7 +503,13 @@ function buildTail(first, second, ...rest) {
483
503
  const options = callForm(first, second, rest);
484
504
  if (options === void 0) return Promise.reject(/* @__PURE__ */ new Error("buildTail takes buildTail(base, options?) or the deprecated buildTail(fixFirst, base, green?, options?); this call fits neither"));
485
505
  const [base, form] = options;
486
- return tail((escalations) => review(base, escalations, form), form);
506
+ return tail((escalations, report) => review(base, escalations, {
507
+ ...form,
508
+ report
509
+ }), {
510
+ ...form,
511
+ triage: true
512
+ });
487
513
  }
488
514
  const isOptionalBoolean = (value) => value == null || typeof value === "boolean";
489
515
  const legacyForm = (fixFirst, base, green, options) => isOptionalBoolean(fixFirst) && isOptionalBoolean(green) && isOptionalObject(options) ? [base, {
@@ -818,8 +844,7 @@ const reviewedRefactor = async (shape, options = {}) => {
818
844
  feedback,
819
845
  fixAccess: strayAccess(p.strays),
820
846
  lensBase: entry,
821
- rules: refactorRules(p.strays, p.pattern),
822
- lap: "refactor"
847
+ rules: refactorRules(p.strays, p.pattern)
823
848
  });
824
849
  if (outcome.verdict === "signoff") return true;
825
850
  await reUnwind(outcome);
@@ -1430,13 +1455,11 @@ const settleQuality = async () => {
1430
1455
  }
1431
1456
  if (rested) await healthy(() => fixCheck());
1432
1457
  };
1433
- /** The quality lap, then the human review since `base`. */
1434
- const reviewedTail = (base, lensBase, lap) => tail(async (escalations) => {
1435
- await settleQuality();
1436
- return review(base, escalations, { lap });
1437
- }, {
1458
+ /** The triaged quality lap, then the human review since `base`. */
1459
+ const reviewedTail = (base, lensBase) => tail((escalations, report) => review(base, escalations, { report }), {
1438
1460
  green: true,
1439
- lensBase
1461
+ lensBase,
1462
+ triage: true
1440
1463
  });
1441
1464
  const featureFeedback = async (first, lensBase, ids) => {
1442
1465
  let outcome = first;
@@ -1456,7 +1479,7 @@ const featureFeedback = async (first, lensBase, ids) => {
1456
1479
  tier: riskTierOn() ? recordRisk() : void 0,
1457
1480
  amend: true
1458
1481
  });
1459
- outcome = await reviewedTail(outcome.base, lensBase, "feedback");
1482
+ outcome = await reviewedTail(outcome.base, lensBase);
1460
1483
  }
1461
1484
  };
1462
1485
  /** Design — skipped when the sketch's own criteria are judged clear — then `buildFeature`. */
@@ -1474,10 +1497,7 @@ const afterTail = async (first) => {
1474
1497
  tier: riskTierOn() ? recordRisk() : void 0,
1475
1498
  amend: true
1476
1499
  });
1477
- outcome = await buildTail(outcome.base, {
1478
- green: true,
1479
- lap: "feedback"
1480
- });
1500
+ outcome = await buildTail(outcome.base, { green: true });
1481
1501
  }
1482
1502
  };
1483
1503
  /** An ordinary start: wait at `idle`, unwind the sketch, check the baseline, then plan and build. */
@@ -1,7 +1,7 @@
1
1
  import { read, refuse, removeScript, run, scope, start } from "../flows.mjs";
2
- import { d as reviewNotes, f as reviewRisks } from "../chunks/steering-DVILanVf.mjs";
3
- import { A as agentWithSkills, J as fixReviewNotesPrompt, S as coder, St as envDefaults, c as baseline, i as skills, n as summary, q as finisherSystem, r as access, s as shipped, t as steering, xt as defaults, y as REVIEW } from "../chunks/reserved-Ch4LLrEj.mjs";
4
- import { r as handOffTail, t as REVIEW_ORIG } from "../chunks/tail-lY1UmJrU.mjs";
2
+ import { d as reviewNotes, f as reviewRisks } from "../chunks/steering-oCDdQlpP.mjs";
3
+ import { A as agentWithSkills, J as finisherSystem, S as coder, Tt as envDefaults, Y as fixReviewNotesPrompt, c as baseline, i as skills, n as summary, r as access, s as shipped, t as steering, wt as defaults, y as REVIEW } from "../chunks/reserved-D7MNY9QJ.mjs";
4
+ import { r as handOffTail, t as REVIEW_ORIG } from "../chunks/tail-D2o2h5cc.mjs";
5
5
  //#region src/workflows/fix/fix.ts
6
6
  /**
7
7
  * Fix every note a human left in a handed-off `.gtd/REVIEW.md` and every
@@ -1,6 +1,6 @@
1
1
  import { start } from "../flows.mjs";
2
- import { St as envDefaults, dt as reviewGateBlockedMessage, i as skills, n as summary, r as access, s as shipped, t as steering, u as gate, xt as defaults } from "../chunks/reserved-Ch4LLrEj.mjs";
3
- import { a as refusePendingHandOff, r as handOffTail } from "../chunks/tail-lY1UmJrU.mjs";
2
+ import { Tt as envDefaults, i as skills, mt as reviewGateBlockedMessage, n as summary, r as access, s as shipped, t as steering, u as gate, wt as defaults } from "../chunks/reserved-D7MNY9QJ.mjs";
3
+ import { a as refusePendingHandOff, r as handOffTail } from "../chunks/tail-D2o2h5cc.mjs";
4
4
  //#region src/workflows/review/review.ts
5
5
  /**
6
6
  * Pure review of everything since `reviewBase`: a green gate, the quality
@@ -1,5 +1,5 @@
1
1
  import { agent, changesSince, glob, head, mark, read, refuse, removeScript, run, scope, vars } from "../flows.mjs";
2
- import { Et as flipProblems, Ot as requireFlag, S as coder, St as envDefaults, i as skills, n as summary, o as flagShipped, p as FEEDBACK, r as access, t as steering, u as gate, wt as flagMentions, xt as defaults } from "../chunks/reserved-Ch4LLrEj.mjs";
2
+ import { Dt as flagMentions, S as coder, Tt as envDefaults, i as skills, jt as requireFlag, kt as flipProblems, n as summary, o as flagShipped, p as FEEDBACK, r as access, t as steering, u as gate, wt as defaults } from "../chunks/reserved-D7MNY9QJ.mjs";
3
3
  //#region src/workflows/rollout/rollout.ts
4
4
  const flippingPrompt = (name, registry) => `Roll out the release flag "${name}": in ${registry}, set \`defaultOn: true\` on its entry. Change nothing else — no other entry, no other field, no other file, no comments.`;
5
5
  const suiteBlockedMessage = () => "The suite is red after the rollout. Fix it by hand — a rollout may only touch the flag's registry entry — then land.";