@plot-pm/board 0.6.0-rc.21 → 0.6.0-rc.210
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/dist/board-server.mjs +123 -104
- package/package.json +2 -2
- package/plot-config.sh +11 -0
- package/plot-plan-meta.sh +140 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plot-pm/board",
|
|
3
|
-
"version": "0.6.0-rc.
|
|
3
|
+
"version": "0.6.0-rc.210",
|
|
4
4
|
"description": "Local Kanban board for Plot — a glanceable view of plan phases from docs/plans, with sprint and story filters",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"build": "pnpm run build:client && pnpm run build:server",
|
|
33
33
|
"prepack": "pnpm run build",
|
|
34
34
|
"typecheck": "tsc --noEmit",
|
|
35
|
-
"test": "node --test test/*.test.mjs",
|
|
35
|
+
"test": "node --test --test-concurrency=4 test/*.test.mjs",
|
|
36
36
|
"test:integration": "pnpm build && vitest run"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
package/plot-config.sh
CHANGED
|
@@ -40,6 +40,17 @@
|
|
|
40
40
|
# Approve command how the board runs `/plot-approve <slug>`; the prompt is
|
|
41
41
|
# appended as one argument. Absent = the board's Approve
|
|
42
42
|
# button renders disabled, naming this key as the fix.
|
|
43
|
+
# Idea command how the board runs `/plot-idea` on a tracker issue; the
|
|
44
|
+
# prompt is appended as one argument, and it names a FILE
|
|
45
|
+
# the board wrote (an issue body is free text from anyone
|
|
46
|
+
# who can file an issue, so no part of it is ever a shell
|
|
47
|
+
# word). REQUIRED for the issue row's `Create plan`
|
|
48
|
+
# action, unlike `Approve command`: approving has a
|
|
49
|
+
# script to fall back to, and creating a plan does not —
|
|
50
|
+
# every step of /plot-idea is judgement, and no script
|
|
51
|
+
# here can invoke a skill. Absent (or `none`) = the button
|
|
52
|
+
# refuses and names this key as the fix, rather than
|
|
53
|
+
# accepting the click and doing nothing.
|
|
43
54
|
# Plot 2 posture keys (repo-declared ceremony bounds; all optional):
|
|
44
55
|
# Plan PRs required | never | optional (never = hard gate)
|
|
45
56
|
# Implementation home this repo | <repo/path list> | none
|
package/plot-plan-meta.sh
CHANGED
|
@@ -45,8 +45,14 @@
|
|
|
45
45
|
# file the path given
|
|
46
46
|
# format canonical | frontmatter | none
|
|
47
47
|
# phase_raw primary phase value as written ("" if absent)
|
|
48
|
-
# phase normalized: draft|approved|delivered|released|
|
|
49
|
-
# superseded|UNKNOWN|NONE
|
|
48
|
+
# phase normalized: draft|design|approved|delivered|released|
|
|
49
|
+
# rejected|superseded|UNKNOWN|NONE
|
|
50
|
+
# `design` is a phase of its own, not a synonym for anything:
|
|
51
|
+
# a plan in Design cannot yet be handed to development because
|
|
52
|
+
# it needs a spec, a spike or a tracer bullet first. That is a
|
|
53
|
+
# different statement from "approved and nobody has started",
|
|
54
|
+
# which is a queue. (`ready-for-review`/`in-review` DO
|
|
55
|
+
# normalize onto `approved` — those are synonyms; this is not.)
|
|
50
56
|
# phase_alt_raw secondary value when the file carries two (front matter
|
|
51
57
|
# status: AND phase:), else ""
|
|
52
58
|
# phase_alt normalized phase_alt_raw (NONE when absent)
|
|
@@ -66,8 +72,26 @@
|
|
|
66
72
|
# `<!-- claimed: ... -->`) bind to the LINE carrying the
|
|
67
73
|
# backticked branch name. An annotation on a wrapped
|
|
68
74
|
# continuation line is not seen — keep it on the branch line.
|
|
75
|
+
# `<!-- deferred -->` (bare, no colon) sets the flag with no
|
|
76
|
+
# reason; `waves[].branches[].deferred_reason` carries the
|
|
77
|
+
# sentence after the colon, "" where none was written.
|
|
69
78
|
# prs PR numbers from `→ #NNN` links in the `## Branches`
|
|
70
79
|
# section (sorted, unique)
|
|
80
|
+
# changelog the plan's `## Changelog` entries, one string per bullet, in
|
|
81
|
+
# document order; [] when the plan has no changelog or an
|
|
82
|
+
# unfilled one. This is the one field that says WHAT A PLAN
|
|
83
|
+
# CHANGES, which title and story do not.
|
|
84
|
+
# ENTRIES, not lines: a bullet wrapped across several lines is
|
|
85
|
+
# one entry with the continuation lines joined by a single
|
|
86
|
+
# space (9 of the 34 changelogs in the origin repo wrap, so
|
|
87
|
+
# line-per-line would have shredded a quarter of them). An
|
|
88
|
+
# INDENTED bullet folds into the entry above it the same way:
|
|
89
|
+
# a sub-point is not a release note of its own.
|
|
90
|
+
# Non-bullet prose in the section is NOT an entry — 8 plans
|
|
91
|
+
# close their changelog with a "Board impact:" paragraph, which
|
|
92
|
+
# is a note to a reviewer rather than a release note. Comment
|
|
93
|
+
# interiors stay non-content, as everywhere else in this parser,
|
|
94
|
+
# so the template's guidance block contributes nothing.
|
|
71
95
|
# issues tracker issue numbers this plan answers, from the `## Status`
|
|
72
96
|
# `Issue:` line or front matter `issue:` (sorted, unique).
|
|
73
97
|
# A DEDICATED field, never a scan of the body for `#NNN`: a
|
|
@@ -86,6 +110,12 @@
|
|
|
86
110
|
# `Released:` or front matter `released:` — date and version).
|
|
87
111
|
# Empty until /plot-release records it; the tag stays the git
|
|
88
112
|
# truth and this merely reflects it.
|
|
113
|
+
# design_raw the design transition record as written (`## Status`
|
|
114
|
+
# `Design:` or front matter `design:` — who/when, and what the
|
|
115
|
+
# design work is); "" if absent. Reported for any plan that
|
|
116
|
+
# carries the line, whatever its phase: a plan that WENT
|
|
117
|
+
# THROUGH design keeps the record after moving on, exactly as
|
|
118
|
+
# `approved_raw` outlives the Approved phase.
|
|
89
119
|
# approved_raw the approval transition record as written (`## Status`
|
|
90
120
|
# `Approved:` or front matter `approved:` — who/when/channel,
|
|
91
121
|
# e.g. "2026-07-30, alice, in-session"); "" if absent
|
|
@@ -138,7 +168,7 @@ if [ ${#files[@]} -eq 0 ] && [ ${#missing[@]} -eq 0 ]; then
|
|
|
138
168
|
fi
|
|
139
169
|
|
|
140
170
|
for f in ${missing[@]+"${missing[@]}"}; do
|
|
141
|
-
printf '{"file":"%s","format":"none","error":"file not found","phase_raw":"","phase":"NONE","phase_alt_raw":"","phase_alt":"NONE","type":"","title":"","sprint":"","story":"","assignee":"","branches":[],"prs":[],"issues":[],"review_raw":"","review":"NONE","impl_raw":"","impl":"NONE","approved_raw":"","released_raw":"","delivered_raw":"","started_raw":[]}\n' \
|
|
171
|
+
printf '{"file":"%s","format":"none","error":"file not found","phase_raw":"","phase":"NONE","phase_alt_raw":"","phase_alt":"NONE","type":"","title":"","sprint":"","story":"","assignee":"","branches":[],"prs":[],"issues":[],"changelog":[],"review_raw":"","review":"NONE","impl_raw":"","impl":"NONE","design_raw":"","approved_raw":"","released_raw":"","delivered_raw":"","started_raw":[]}\n' \
|
|
142
172
|
"$(printf '%s' "$f" | sed 's/\\/\\\\/g; s/"/\\"/g')"
|
|
143
173
|
done
|
|
144
174
|
|
|
@@ -166,7 +196,7 @@ function norm_phase(raw, lower, toks, n, i, t) {
|
|
|
166
196
|
for (i = 1; i <= n; i++) {
|
|
167
197
|
t = toks[i]
|
|
168
198
|
gsub(/^[^a-z]+/, "", t); gsub(/[^a-z-]+$/, "", t)
|
|
169
|
-
if (t ~ /^(draft|approved|delivered|released|rejected|superseded)$/) return t
|
|
199
|
+
if (t ~ /^(draft|design|approved|delivered|released|rejected|superseded)$/) return t
|
|
170
200
|
if (t == "ready-for-review" || t == "in-review") return "approved"
|
|
171
201
|
}
|
|
172
202
|
return "UNKNOWN"
|
|
@@ -211,11 +241,11 @@ function reset_state() {
|
|
|
211
241
|
fm_status = ""; fm_phase = ""; fm_type = ""
|
|
212
242
|
fm_title = ""; fm_sprint = ""; fm_story = ""; fm_assignee = ""
|
|
213
243
|
fm_review = ""; fm_impl = ""; fm_approved = ""; fm_started = ""; fm_released = ""
|
|
214
|
-
fm_delivered = ""
|
|
244
|
+
fm_delivered = ""; fm_design = ""
|
|
215
245
|
canon_phase = ""; canon_type = ""
|
|
216
246
|
canon_sprint = ""; canon_story = ""; canon_assignee = ""
|
|
217
247
|
canon_review = ""; canon_impl = ""; canon_approved = ""; canon_released = ""
|
|
218
|
-
canon_delivered = ""
|
|
248
|
+
canon_delivered = ""; canon_design = ""
|
|
219
249
|
h1_title = ""
|
|
220
250
|
# "" means the plan carries no readable round — NOT zero. Emitted by omitting
|
|
221
251
|
# the field, so a consumer cannot mistake "never interrogated" for "asked
|
|
@@ -227,10 +257,12 @@ function reset_state() {
|
|
|
227
257
|
fm_issue = ""; canon_issue = ""
|
|
228
258
|
delete issues; n_issues = 0
|
|
229
259
|
delete wave_names; delete wave_of; delete wave_seq; delete wave_count
|
|
230
|
-
delete deferred_of; delete claimed_of; delete ordered_b; n_waves = 0
|
|
260
|
+
delete deferred_of; delete deferred_why; delete claimed_of; delete ordered_b; n_waves = 0
|
|
231
261
|
delete started; n_started = 0
|
|
262
|
+
fm_changelog = ""
|
|
263
|
+
delete changelog; n_changelog = 0; changelog_seen = 0; cl_open = 0
|
|
232
264
|
}
|
|
233
|
-
function emit_record( fmt, praw, palt_raw, traw, title, sprint, story, assignee, review, impl, approved, delivered, issue, i, j, out, sorted_b, sorted_p, sorted_i, nb, np, ni) {
|
|
265
|
+
function emit_record( fmt, praw, palt_raw, traw, title, sprint, story, assignee, review, impl, design, approved, delivered, issue, i, j, out, sorted_b, sorted_p, sorted_i, nb, np, ni) {
|
|
234
266
|
if (fm_status != "" || fm_phase != "") {
|
|
235
267
|
fmt = "frontmatter"
|
|
236
268
|
praw = (fm_status != "") ? fm_status : fm_phase
|
|
@@ -249,6 +281,7 @@ function emit_record( fmt, praw, palt_raw, traw, title, sprint, story, assigne
|
|
|
249
281
|
assignee = strip_placeholder((fm_assignee != "") ? fm_assignee : canon_assignee)
|
|
250
282
|
review = strip_placeholder((fm_review != "") ? fm_review : canon_review)
|
|
251
283
|
impl = strip_placeholder((fm_impl != "") ? fm_impl : canon_impl)
|
|
284
|
+
design = strip_placeholder((fm_design != "") ? fm_design : canon_design)
|
|
252
285
|
approved = strip_placeholder((fm_approved != "") ? fm_approved : canon_approved)
|
|
253
286
|
released = strip_placeholder((fm_released != "") ? fm_released : canon_released)
|
|
254
287
|
delivered = strip_placeholder((fm_delivered != "") ? fm_delivered : canon_delivered)
|
|
@@ -302,6 +335,15 @@ function emit_record( fmt, praw, palt_raw, traw, title, sprint, story, assigne
|
|
|
302
335
|
out = out "],\"issues\":["
|
|
303
336
|
for (i = 1; i <= ni; i++) out = out (i > 1 ? "," : "") sorted_i[i]
|
|
304
337
|
out = out "]"
|
|
338
|
+
# Document order, never sorted: a changelog is a narrative sequence, and the
|
|
339
|
+
# first entry is the headline. Front matter wins, as it does for every other
|
|
340
|
+
# field, and contributes exactly one entry.
|
|
341
|
+
if (fm_changelog != "" && strip_placeholder(fm_changelog) != "") {
|
|
342
|
+
delete changelog; n_changelog = 1; changelog[1] = strip_placeholder(fm_changelog)
|
|
343
|
+
}
|
|
344
|
+
out = out ",\"changelog\":["
|
|
345
|
+
for (i = 1; i <= n_changelog; i++) out = out (i > 1 ? "," : "") "\"" jesc(changelog[i]) "\""
|
|
346
|
+
out = out "]"
|
|
305
347
|
# waves[]: branches grouped by `### ` subheading, in document order. A plan
|
|
306
348
|
# with no subheadings yields one wave with an empty name.
|
|
307
349
|
out = out ",\"waves\":["
|
|
@@ -311,6 +353,7 @@ function emit_record( fmt, praw, palt_raw, traw, title, sprint, story, assigne
|
|
|
311
353
|
for (i = 1; i <= n_branches; i++) {
|
|
312
354
|
if (wave_of[i] != w) continue
|
|
313
355
|
out = out (first ? "" : ",") "{\"branch\":\"" jesc(ordered_b[i]) "\",\"deferred\":" deferred_of[i] \
|
|
356
|
+
",\"deferred_reason\":\"" jesc(deferred_why[i]) "\"" \
|
|
314
357
|
",\"claimed\":\"" jesc(claimed_of[i]) "\"}"
|
|
315
358
|
first = 0
|
|
316
359
|
}
|
|
@@ -319,6 +362,7 @@ function emit_record( fmt, praw, palt_raw, traw, title, sprint, story, assigne
|
|
|
319
362
|
out = out "]"
|
|
320
363
|
out = out ",\"review_raw\":\"" jesc(review) "\",\"review\":\"" norm_review(review) "\""
|
|
321
364
|
out = out ",\"impl_raw\":\"" jesc(impl) "\",\"impl\":\"" norm_impl(impl) "\""
|
|
365
|
+
out = out ",\"design_raw\":\"" jesc(design) "\""
|
|
322
366
|
out = out ",\"approved_raw\":\"" jesc(approved) "\""
|
|
323
367
|
out = out ",\"released_raw\":\"" jesc(released) "\""
|
|
324
368
|
out = out ",\"delivered_raw\":\"" jesc(delivered) "\""
|
|
@@ -350,10 +394,15 @@ in_fm {
|
|
|
350
394
|
else if (lower ~ /^assignee:/ && fm_assignee == "") fm_assignee = val_after_colon($0)
|
|
351
395
|
else if (lower ~ /^review:/ && fm_review == "") fm_review = val_after_colon($0)
|
|
352
396
|
else if (lower ~ /^impl:/ && fm_impl == "") fm_impl = val_after_colon($0)
|
|
397
|
+
else if (lower ~ /^design:/ && fm_design == "") fm_design = val_after_colon($0)
|
|
353
398
|
else if (lower ~ /^approved:/ && fm_approved == "") fm_approved = val_after_colon($0)
|
|
354
399
|
else if (lower ~ /^released:/ && fm_released == "") fm_released = val_after_colon($0)
|
|
355
400
|
else if (lower ~ /^delivered:/ && fm_delivered == "") fm_delivered = val_after_colon($0)
|
|
356
401
|
else if (lower ~ /^started:/ && fm_started == "") fm_started = val_after_colon($0)
|
|
402
|
+
# A scalar `changelog:` in front matter is one entry. A YAML list is NOT read
|
|
403
|
+
# here: front matter in this repo is a flat key/value surface, and guessing a
|
|
404
|
+
# list grammar the format never promised would invent a contract.
|
|
405
|
+
else if (lower ~ /^changelog:/ && fm_changelog == "") fm_changelog = val_after_colon($0)
|
|
357
406
|
next
|
|
358
407
|
}
|
|
359
408
|
# Interior of multi-line HTML comments is non-content (template guidance
|
|
@@ -391,6 +440,10 @@ in_comment {
|
|
|
391
440
|
# section in prose, and those later headings are illustration, not contract.
|
|
392
441
|
else if ($0 ~ /^## Branches/) { section = branches_seen ? "" : "branches"; branches_seen = 1 }
|
|
393
442
|
else if ($0 ~ /^## Approval/) section = "approval"
|
|
443
|
+
# First `## Changelog` wins, for the same reason `## Branches` does: a plan
|
|
444
|
+
# about the plan format quotes the section in prose, and the later heading is
|
|
445
|
+
# illustration rather than contract.
|
|
446
|
+
else if ($0 ~ /^## Changelog/) { section = changelog_seen ? "" : "changelog"; changelog_seen = 1 }
|
|
394
447
|
else section = ""
|
|
395
448
|
next
|
|
396
449
|
}
|
|
@@ -403,6 +456,7 @@ section == "status" {
|
|
|
403
456
|
else if (lower ~ /^[ \t]*[-*]?[ \t]*\**issue[:*]/ && canon_issue == "") canon_issue = val_after_colon($0)
|
|
404
457
|
else if (lower ~ /^[ \t]*[-*]?[ \t]*\**review[:*]/ && canon_review == "") canon_review = val_after_colon($0)
|
|
405
458
|
else if (lower ~ /^[ \t]*[-*]?[ \t]*\**impl[:*]/ && canon_impl == "") canon_impl = val_after_colon($0)
|
|
459
|
+
else if (lower ~ /^[ \t]*[-*]?[ \t]*\**design[:*]/ && canon_design == "") canon_design = val_after_colon($0)
|
|
406
460
|
else if (lower ~ /^[ \t]*[-*]?[ \t]*\**approved[:*]/ && canon_approved == "") canon_approved = val_after_colon($0)
|
|
407
461
|
else if (lower ~ /^[ \t]*[-*]?[ \t]*\**released[:*]/ && canon_released == "") canon_released = val_after_colon($0)
|
|
408
462
|
else if (lower ~ /^[ \t]*[-*]?[ \t]*\**delivered[:*]/ && canon_delivered == "") canon_delivered = val_after_colon($0)
|
|
@@ -417,6 +471,47 @@ section == "approval" {
|
|
|
417
471
|
if (lower ~ /^[ \t]*[-*]?[ \t]*\**assignee[:*]/ && canon_assignee == "") canon_assignee = val_after_colon($0)
|
|
418
472
|
next
|
|
419
473
|
}
|
|
474
|
+
# `## Changelog` — the release-note entries. One entry per bullet, wrapped
|
|
475
|
+
# continuation lines folded into the entry they belong to.
|
|
476
|
+
#
|
|
477
|
+
# A bullet opens an entry. An indented non-bullet line continues the open one.
|
|
478
|
+
# A blank line or a line at column zero closes it: the flush-left prose that 8
|
|
479
|
+
# plans use for a "Board impact:" note is a remark to a reviewer, not a release
|
|
480
|
+
# note, so it ends the entry rather than joining it.
|
|
481
|
+
section == "changelog" {
|
|
482
|
+
# A line that is nothing but an HTML comment is not content, at any
|
|
483
|
+
# indentation. Multi-line comments are already swallowed upstream; an INDENTED
|
|
484
|
+
# single-liner would otherwise land in the continuation branch below and paste
|
|
485
|
+
# its own markup into the entry above it.
|
|
486
|
+
if ($0 ~ /^[ \t]*<!--.*-->[ \t]*$/) next
|
|
487
|
+
# An INDENTED bullet is a sub-point of the entry above, not a release note of
|
|
488
|
+
# its own, so it continues rather than opens. No changelog in the repo nests
|
|
489
|
+
# today; the rule is here because the alternative silently promotes a
|
|
490
|
+
# sub-point to a headline the moment one does.
|
|
491
|
+
if (cl_open && $0 ~ /^[ \t]+[-*][ \t]/) {
|
|
492
|
+
_n = $0
|
|
493
|
+
sub(/^[ \t]*[-*][ \t]+/, "", _n)
|
|
494
|
+
changelog[n_changelog] = changelog[n_changelog] " " trim(_n)
|
|
495
|
+
next
|
|
496
|
+
}
|
|
497
|
+
if ($0 ~ /^[ \t]*[-*][ \t]/) {
|
|
498
|
+
_e = $0
|
|
499
|
+
sub(/^[ \t]*[-*][ \t]+/, "", _e)
|
|
500
|
+
_e = strip_placeholder(trim(_e))
|
|
501
|
+
if (_e != "") { changelog[++n_changelog] = _e; cl_open = 1 }
|
|
502
|
+
else cl_open = 0 # an unfilled bullet opens nothing to continue
|
|
503
|
+
next
|
|
504
|
+
}
|
|
505
|
+
if (cl_open && $0 ~ /^[ \t]+[^ \t]/) {
|
|
506
|
+
changelog[n_changelog] = changelog[n_changelog] " " trim($0)
|
|
507
|
+
next
|
|
508
|
+
}
|
|
509
|
+
# Blank line, or prose at column zero: whatever entry was open is finished.
|
|
510
|
+
# The flag matters — without it a continuation-shaped line after a break would
|
|
511
|
+
# glue itself onto an entry it never belonged to.
|
|
512
|
+
cl_open = 0
|
|
513
|
+
next
|
|
514
|
+
}
|
|
420
515
|
section == "branches" {
|
|
421
516
|
# `### <name>` opens a wave. Branches before any subheading belong to an
|
|
422
517
|
# unnamed wave, so a pre-wave plan parses as exactly one wave.
|
|
@@ -435,6 +530,30 @@ section == "branches" {
|
|
|
435
530
|
sub(/[ \t]*-->.*$/, "", _c)
|
|
436
531
|
claim_note = trim(_c)
|
|
437
532
|
}
|
|
533
|
+
# THE REASON FOR THE DEFERRAL, and not merely the fact of one.
|
|
534
|
+
#
|
|
535
|
+
# `<!-- deferred: verified already implemented 2026-08-17 — startRepair() at
|
|
536
|
+
# fleet.ts:806 -->` was tested for presence and the sentence after the colon
|
|
537
|
+
# was dropped on the floor. So the board could say `deferred` beside `no
|
|
538
|
+
# commits` and never say that the first is the REASON for the second — a
|
|
539
|
+
# reader with no access to the plan file saw a branch nobody started and no
|
|
540
|
+
# statement that nobody should.
|
|
541
|
+
#
|
|
542
|
+
# Extracted the same way and in the same place as the claim note, for the same
|
|
543
|
+
# reason: `match()` in the branch loop below clobbers RSTART/RLENGTH, so
|
|
544
|
+
# anything read from the whole line must be read before it runs.
|
|
545
|
+
#
|
|
546
|
+
# Newlines are already impossible here — awk hands this rule one line, and the
|
|
547
|
+
# documented contract is that an annotation binds to the line carrying the
|
|
548
|
+
# branch name. A deferral whose text is wrapped onto a continuation line is
|
|
549
|
+
# not seen, exactly as `deferred` itself was not.
|
|
550
|
+
defer_note = ""
|
|
551
|
+
if (index($0, "deferred:") > 0) {
|
|
552
|
+
_d = $0
|
|
553
|
+
sub(/^.*<!--[ \t]*deferred:[ \t]*/, "", _d)
|
|
554
|
+
sub(/[ \t]*-->.*$/, "", _d)
|
|
555
|
+
defer_note = trim(_d)
|
|
556
|
+
}
|
|
438
557
|
line = $0
|
|
439
558
|
while (match(line, branch_re)) {
|
|
440
559
|
b = substr(line, RSTART + 1, RLENGTH - 2)
|
|
@@ -442,7 +561,19 @@ section == "branches" {
|
|
|
442
561
|
if (n_waves == 0) { wave_names[++n_waves] = "" }
|
|
443
562
|
wave_of[n_branches] = n_waves
|
|
444
563
|
wave_seq[n_branches] = ++wave_count[n_waves]
|
|
445
|
-
|
|
564
|
+
# THE FLAG accepts the bare form as well as the annotated one.
|
|
565
|
+
#
|
|
566
|
+
# It matched `deferred:` only, so `<!-- deferred -->` — the annotation with
|
|
567
|
+
# nothing after it — read as NOT deferred at all: the strongest statement a
|
|
568
|
+
# plan can make about a branch, dropped for want of a colon. A reader
|
|
569
|
+
# writing the shorter form has said the branch will not be built; the
|
|
570
|
+
# parser now hears it.
|
|
571
|
+
deferred_of[n_branches] = ($0 ~ /<!--[ \t]*deferred[ \t]*(:|-->)/) ? "true" : "false"
|
|
572
|
+
# The reason travels with the flag. Empty on every non-deferred branch, and
|
|
573
|
+
# empty is also the honest answer for the bare form: the branch IS deferred
|
|
574
|
+
# and no reason was recorded, which is a different statement from a reason
|
|
575
|
+
# of "".
|
|
576
|
+
deferred_why[n_branches] = defer_note
|
|
446
577
|
# Claim reflection, written by the worker after its ref push succeeds. This
|
|
447
578
|
# is a reflection, not the claim: git refs remain authoritative.
|
|
448
579
|
claimed_of[n_branches] = claim_note
|