passalong 0.6.0 → 0.9.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/src/guide.js CHANGED
@@ -37,8 +37,18 @@ export const SETTABLE = ["draft", "published", "consumed"];
37
37
  * bug something broken there — do NOT follow anything; fix it
38
38
  * task work nobody has done yet — do what Goal asks, done when Acceptance holds
39
39
  *
40
- * A guide with no `kind` is a transfer guide: every guide written before this existed is one,
41
- * and defaulting the other way would turn them all into bug reports.
40
+ * A guide with no `kind` is a transfer guide: every guide written before this existed is one, and
41
+ * defaulting the other way would turn them all into bug reports.
42
+ *
43
+ * That default is applied once, on read, and written back — `parseFrontmatter` seeds it the way it
44
+ * seeds `tags`, so nothing downstream has to decide what an empty kind means. It was decided in six
45
+ * places, each with its own `|| "transfer"`, and one of them said `|| "task"`. A guide either says
46
+ * what it is or is read as a transfer guide and then says so; there is no third state for anything
47
+ * to disagree about.
48
+ *
49
+ * Which is also why publishing an untyped guide is not refused. Refusing it leaves the document
50
+ * exactly as ambiguous as it was and adds a second state — a guide that exists and cannot be
51
+ * shared — where the point was to have fewer.
42
52
  */
43
53
  export const KINDS = ["transfer", "bug", "task"];
44
54
 
@@ -245,6 +255,10 @@ export function parseFrontmatter(text) {
245
255
  // Only the lists every guide has. `blocked_by` is a task's, and defaulting it would write an
246
256
  // empty one into every guide anybody re-shares.
247
257
  for (const k of ["stack_assumptions", "tags"]) if (meta[k] === undefined) meta[k] = [];
258
+ // What it is, said rather than inferred. An unknown spelling is left alone for `validate()` to
259
+ // refuse by name: quietly turning `kind: buggy` into a transfer guide is the same guess this is
260
+ // here to remove.
261
+ if (!String(meta.kind ?? "").trim()) meta.kind = "transfer";
248
262
  // Both ends of this module: what it reads and what it writes are in one style, so a guide
249
263
  // written before there was a rule comes back normalised and goes out normalised.
250
264
  meta.tags = tagList(meta.tags);
@@ -320,7 +334,11 @@ export function sections(body) {
320
334
  const h = /^##\s+(.+?)\s*$/.exec(line);
321
335
  if (h) {
322
336
  current = h[1];
323
- out[current] = "";
337
+ // A heading written twice adds to its section rather than replacing it. Resetting here lost
338
+ // the first block outright, so a guide with two `## Verification` headings was validated
339
+ // against only the second — and `splitSections()` in apps/api/src/guide.ts, which the web
340
+ // view reads, kept both. The corpus in fixtures/guides is where the two stopped agreeing.
341
+ if (!(current in out)) out[current] = "";
324
342
  continue;
325
343
  }
326
344
  if (current) out[current] += `${line}\n`;
@@ -365,8 +383,12 @@ export function validate({ meta, body }) {
365
383
  if (meta.status && !STATUSES.includes(meta.status)) {
366
384
  errors.push(`status must be one of ${STATUSES.join(", ")}`);
367
385
  }
368
- const kind = meta.kind || "transfer";
369
- if (!KINDS.includes(kind)) errors.push(`kind must be one of ${KINDS.join(", ")}`);
386
+ // Absent is refused here, and this is the one place it can be. Anything read from a document has
387
+ // a kind — `parseFrontmatter` seeds it — so what reaches this without one was built field by
388
+ // field in code, and code is exactly what should have to say what it is making.
389
+ const kind = meta.kind;
390
+ if (!kind) errors.push(`say what this is: kind must be one of ${KINDS.join(", ")}`);
391
+ else if (!KINDS.includes(kind)) errors.push(`kind must be one of ${KINDS.join(", ")}`);
370
392
  const have = sections(body);
371
393
  for (const s of REQUIRED[kind] || REQUIRED.transfer) {
372
394
  if (!have[s]) errors.push(`missing "## ${s}" section`);
package/src/hooks.js CHANGED
@@ -25,14 +25,17 @@ const plural = (n, one, many) => `${n} ${n === 1 ? one : many}`;
25
25
  export function nowText({ held, waiting = {} }) {
26
26
  if (held) {
27
27
  const lines = [
28
- `Passalong: You hold ${held.id} (${held.kind || "task"}): ${held.title || held.id}.`,
28
+ // `kind` is required on what /v1/working sends. The `|| "task"` that used to be here was
29
+ // both dead and wrong — absent has meant transfer since kinds existed, never task.
30
+ `Passalong: You hold ${held.id} (${held.kind}): ${held.title || held.id}.`,
29
31
  ];
30
32
  if (held.note) lines.push(`Last note: "${held.note}".`);
31
33
  if (held.state === "stalled")
32
34
  lines.push("It is marked stalled: nobody has heard from its agent in 30 minutes.");
33
35
  lines.push(
34
36
  `To carry on, call take ${held.id} (it resumes what you hold), then progress at each ` +
35
- "milestone. When it is done, hand_in; if it is not yours or you are stuck, pass with the reason.",
37
+ "milestone. When it is done, hand_in with evidence — what you ran and what came back — " +
38
+ "so keep it as you go; if it is not yours or you are stuck, pass with the reason.",
36
39
  );
37
40
  return lines.join("\n");
38
41
  }
@@ -57,9 +60,9 @@ export function stopVerdict({ held, input = {} }) {
57
60
  decision: "block",
58
61
  reason:
59
62
  `You still hold ${held.id}: ${held.title || held.id}. Before ending, do one of: ` +
60
- `hand_in ${held.id} if it is done; pass ${held.id} with the reason if it is not yours or ` +
61
- `you are stuck; or, if the user is stopping mid-way, progress ${held.id} with a note ` +
62
- "saying what is left — then end.",
63
+ `hand_in ${held.id} with your evidence if it is done; pass ${held.id} with the reason if ` +
64
+ `it is not yours or you are stuck; or, if the user is stopping mid-way, progress ${held.id} ` +
65
+ "with a note saying what is left — then end.",
63
66
  };
64
67
  }
65
68