task-pipeline-skill 1.62.0 → 1.64.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/CHANGELOG.md +70 -0
- package/SKILL-CARD.md +1 -1
- package/package.json +1 -1
- package/plugins/task-pipeline/.claude-plugin/plugin.json +1 -1
- package/plugins/task-pipeline/skills/task-pipeline/references/knowledge-sources.md +31 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/exposure.sh +128 -26
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,75 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.64.0 — the exposure line reported a clean bill on ledgers it could not read
|
|
4
|
+
|
|
5
|
+
**The exposure command reported a clean bill on ledgers it could not read.** Shipped two
|
|
6
|
+
releases ago keyed on POSITION — `NF >= 7`, status in field 7. Run against the family
|
|
7
|
+
umbrella's four-column ledger it found **four rows out of 298**, because those four happen
|
|
8
|
+
to contain a `|` inside inline code and so crossed the field count by accident, and from
|
|
9
|
+
them printed:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
exposure: 0 unverified · never checked · 125 releases carry one
|
|
13
|
+
every shipped row carries a human confirmation
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The most reassuring sentence available, derived from punctuation, in the one tool whose
|
|
17
|
+
stated purpose is to stop silent greens. Its own two halves contradict each other and the
|
|
18
|
+
fixtures did not notice.
|
|
19
|
+
|
|
20
|
+
**The status column is now found by name, per section, and the order matters.**
|
|
21
|
+
`sheleg-design` carries both `Last verified` (a date and the thing watched) and `Status`
|
|
22
|
+
(which holds `**green**`); preferring `status` read the gate instead of the person and
|
|
23
|
+
reported 174 confirmations. Preference is `Human`, then `Last verified`, then
|
|
24
|
+
`Status`/`State`. **`Verified by`, `Confirmed` and `How it is checked` are deliberately not
|
|
25
|
+
status names** — five members hold shell commands under those headers, and a column of
|
|
26
|
+
commands read as a column of statuses is how `python3 test/validate.py` became a status
|
|
27
|
+
nobody could parse.
|
|
28
|
+
|
|
29
|
+
Three further corrections, each of which was hiding a real row:
|
|
30
|
+
|
|
31
|
+
- **Bold is stripped before matching.** These ledgers write `**never**`, not `never`.
|
|
32
|
+
- **A shrug is not a clean bill.** A status that is neither a date nor a known word gets
|
|
33
|
+
its own count and its own list, and no clean bill prints over it.
|
|
34
|
+
- **Only a `Human` column licenses the word "human".** The umbrella's ledger defines
|
|
35
|
+
`verified` as *a person **or** a command*, so a confirmation drawn from `Status` now says
|
|
36
|
+
which column it came from.
|
|
37
|
+
|
|
38
|
+
Measured across the family afterwards: `task-pipeline` **126 unverified**, `sheleg-design`
|
|
39
|
+
1, and `seo-aeo-audit`, `super-ux` and `agent-sync` **dormant — no status column at all**,
|
|
40
|
+
which is the truth their shapes support and not a zero.
|
|
41
|
+
|
|
42
|
+
Fixtures 14 → **18**, the four new ones named for the exact silent green.
|
|
43
|
+
|
|
44
|
+
Guards: 349 → **349**. No new plant: every one of these is a behaviour of the seeded
|
|
45
|
+
script, which the fixtures exercise directly by running it.
|
|
46
|
+
|
|
47
|
+
## v1.63.0 — the row you are about to work is a claim, and it has a date
|
|
48
|
+
|
|
49
|
+
**A board row states the world at its `Source` date and says nothing about now.** Three
|
|
50
|
+
rows expired inside one day on 2026-08-16 — one recorded a script and thirteen green
|
|
51
|
+
fixtures as *built and parked* when every artifact had been deleted, one named six files
|
|
52
|
+
belonging to another repository where a sweep found eleven, one said the graphs were
|
|
53
|
+
frozen at a date nine days old when every one had been rebuilt. None was wrong when
|
|
54
|
+
written. Each was caught only because the cycle that picked it up happened to measure
|
|
55
|
+
first; nothing required it.
|
|
56
|
+
|
|
57
|
+
`references/knowledge-sources.md` gains the rule beside *Carried-in claims*, which covers
|
|
58
|
+
the sibling case of what a run inherits about itself: **re-derive the row's checkable
|
|
59
|
+
claims before acting on them, and correct the row in the same run.** Most name something a
|
|
60
|
+
command settles — a file, a count, a commit, a version, a green suite. What no command can
|
|
61
|
+
settle is acted on as an assumption, out loud.
|
|
62
|
+
|
|
63
|
+
It also names the sharper half, which is arithmetic rather than prose: **a row's derived
|
|
64
|
+
columns decay and nothing notices, because the number still looks like a number.** A rank
|
|
65
|
+
computed from an age term is wrong the moment the age moves. If a board computes a
|
|
66
|
+
priority, something must recompute it — a promise in the header that it happens at stage 10
|
|
67
|
+
is not a mechanism.
|
|
68
|
+
|
|
69
|
+
Guards: 349 → **349**. No new plant, and the reason is measured rather than asserted:
|
|
70
|
+
across the seven open rows the family carries, the checkable claims total **two file paths
|
|
71
|
+
and one count**. A gate over that corpus would pass everything and read like coverage.
|
|
72
|
+
|
|
3
73
|
## v1.62.0 — a board row that says work exists names where it lives
|
|
4
74
|
|
|
5
75
|
**`open` claims nothing exists. `parked` claims something does — and now has to say
|
package/SKILL-CARD.md
CHANGED
|
@@ -12,7 +12,7 @@ harmless.
|
|
|
12
12
|
|---|---|
|
|
13
13
|
| **Purpose** | Runs a substantial task through ten gated delivery stages — intake grill, docs study, brainstorm, spec, plan, subagent build, tests, lint/deploy, post-deploy, docs+registers, acceptance — refusing to advance until each gate passes |
|
|
14
14
|
| **Owner** | ssheleg ([github.com/ssheleg/task-pipeline](https://github.com/ssheleg/task-pipeline)) |
|
|
15
|
-
| **Version** | 1.
|
|
15
|
+
| **Version** | 1.64.0 |
|
|
16
16
|
| **Surface** | Claude Code (filesystem skill + plugin) and the vercel `skills` CLI. **Not** uploaded to the Skills API; custom Skills do not sync across surfaces |
|
|
17
17
|
| **Dependencies** | None required. Optional: `context7` (MCP), `figma` (MCP), super-ux, agent-sync, graphify, obsidian-wiki, and **one of two browser channels** — `playwright` (CLI or MCP) or `chrome-devtools` (MCP); either satisfies the browser step and neither is required. Every stage's doctrine ships in-repo; the one conditional requirement is super-ux for the stage-3 UX track on a user-facing task |
|
|
18
18
|
| **Evaluation status** | Suite authored, 5 categories. One recorded run, **self-observed by the author**; **zero blind runs on zero of three models** — the split, and the numbers, live in [`evals/RESULTS.md`](evals/RESULTS.md) and are computed by `evals/run.py` |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "task-pipeline-skill",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.64.0",
|
|
4
4
|
"description": "Full-cycle delivery pipeline for coding agents: a mandatory built-in intake grill, then 10 gated stages (docs, brainstorm+decompose, spec, plan, build, tests, lint/deploy, post-deploy, docs/wiki, acceptance). Every stage's doctrine ships inside the skill — no companion plugin required. This package is the installer CLI.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"task-pipeline": "bin/task-pipeline.js"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "task-pipeline",
|
|
3
3
|
"displayName": "Task Pipeline",
|
|
4
4
|
"description": "Runs a substantial task through a mandatory built-in intake grill, then 10 gated stages (docs, brainstorm+decompose, spec, plan, subagent build, tests, lint/deploy, post-deploy, docs/wiki, acceptance). Every stage's doctrine is built into the skill — no companion plugin required — with typed auto/manual gates, a frozen requirement spine that closes with evidence, a work board and a verification ledger that outlive a run, an exposure line naming what shipped unconfirmed, a progress rail computed from the project's own config, a loop guard whose review ceiling measures rather than stops, and stage-3 tracks for what a product does, how it sounds and how it looks. Two modes need no task: `checkup` (what is unverified) and `setup` (audit existing docs). Retro insights can publish upstream as issues, opt-in and redacted.",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.64.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ssheleg",
|
|
8
8
|
"url": "https://x.com/sshlg93"
|
|
@@ -18,6 +18,7 @@ that goes stale when the answer changes.
|
|
|
18
18
|
- How to harvest — retrieval, not reading
|
|
19
19
|
- Record it — the source ledger
|
|
20
20
|
- The harvest is a convergence, so it needs a check across its sources
|
|
21
|
+
- The row you are about to work is a claim, and it has a date
|
|
21
22
|
- The source is not the copy you have
|
|
22
23
|
- Carried-in claims — measured or recalled
|
|
23
24
|
- Phase 2 — validate the answers against the harvest
|
|
@@ -210,6 +211,36 @@ a check whose silence is indistinguishable from not having run is not evidence.
|
|
|
210
211
|
found here is a stage-9 obligation — the ledger's row is what stage 9 goes back and
|
|
211
212
|
fixes.
|
|
212
213
|
|
|
214
|
+
## The row you are about to work is a claim, and it has a date
|
|
215
|
+
|
|
216
|
+
*Carried-in claims* below covers what **this run** inherited. This covers what an **earlier
|
|
217
|
+
run wrote down** — a board row, which reads like a finding because it was one, on the day
|
|
218
|
+
it was filed.
|
|
219
|
+
|
|
220
|
+
Three rows expired inside a single day on 2026-08-16, and each was caught only because the
|
|
221
|
+
cycle that picked it up happened to measure before building:
|
|
222
|
+
|
|
223
|
+
- one recorded a script and thirteen green fixtures as *built and parked*; every artifact
|
|
224
|
+
had been deleted, and the row had read as ready-to-merge for two days;
|
|
225
|
+
- one named six files belonging to another repository; a sweep found **eleven**;
|
|
226
|
+
- one said the graphs were frozen at a date nine days old; every one had been rebuilt.
|
|
227
|
+
|
|
228
|
+
None of the three was wrong when written. **A row states the world at its `Source` date and
|
|
229
|
+
says nothing about now**, and the run that acts on it is the first reader in a position to
|
|
230
|
+
tell the difference.
|
|
231
|
+
|
|
232
|
+
**So: re-derive the row's checkable claims before acting on them, and correct the row in
|
|
233
|
+
the same run.** Most claims name something a command can settle — a file, a count, a
|
|
234
|
+
commit, a version, a green suite. What a command cannot settle stays as written and is
|
|
235
|
+
acted on as an assumption, out loud.
|
|
236
|
+
|
|
237
|
+
**The row's own derived columns decay too, and that one is pure arithmetic.** A rank
|
|
238
|
+
computed from an age term is wrong the moment the age moves, and nothing notices because
|
|
239
|
+
the number still looks like a number. This repository's own board carried a constant age
|
|
240
|
+
for eleven days — the four oldest rows sat at the bottom of a ranking whose stated purpose
|
|
241
|
+
was to raise them. If a board computes a priority, something must recompute it; a promise
|
|
242
|
+
in the header that it happens at stage 10 is not a mechanism.
|
|
243
|
+
|
|
213
244
|
## The source is not the copy you have
|
|
214
245
|
|
|
215
246
|
`learned.md` rule 17. The harvest reads the project's own files, and one property of them is
|
|
@@ -47,43 +47,122 @@ fi
|
|
|
47
47
|
TMP=$(mktemp -d 2>/dev/null || mktemp -d -t exposure)
|
|
48
48
|
trap 'rm -rf "$TMP"' EXIT
|
|
49
49
|
|
|
50
|
-
# ---------- the ledger's rows ----------
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
50
|
+
# ---------- the ledger's rows, resolved BY HEADER ----------
|
|
51
|
+
# The first draft keyed on position — `NF >= 7`, status in field 7 — and on a ledger with
|
|
52
|
+
# four columns it did not report a shape mismatch. It found FOUR rows out of 298, because
|
|
53
|
+
# those four happened to contain a `|` inside inline code and so crossed the field count by
|
|
54
|
+
# accident, then printed **"0 unverified · every shipped row carries a human confirmation"**.
|
|
55
|
+
# The most reassuring sentence available, derived from punctuation. In a tool whose whole
|
|
56
|
+
# purpose is to stop silent greens.
|
|
57
|
+
#
|
|
58
|
+
# So the status column is found by NAME, per section, and a ledger with no such column is
|
|
59
|
+
# DORMANT rather than clean. Three shapes exist in this family already — `Human`, `Status`,
|
|
60
|
+
# `Watched` — and a fourth will arrive without asking.
|
|
54
61
|
awk -F'|' '
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
function trim(s) { gsub(/^[ \t]+|[ \t]+$/, "", s); return s }
|
|
63
|
+
function lower(s) { return tolower(s) }
|
|
64
|
+
# A header is a row whose first cell names the id column. Everything after it, until the
|
|
65
|
+
# next header, is read with THAT header shape.
|
|
66
|
+
{
|
|
67
|
+
if (NF < 3) next
|
|
68
|
+
c1 = lower(trim($2))
|
|
69
|
+
if (c1 == "req" || c1 == "id" || c1 == "#") {
|
|
70
|
+
nf = NF; scol = 0; sname = ""
|
|
71
|
+
for (i = 2; i < NF; i++) {
|
|
72
|
+
n = lower(trim($i))
|
|
73
|
+
# `human` is the specific one and wins outright; the others are accepted so a
|
|
74
|
+
# differently-shaped ledger is read rather than declared unreadable.
|
|
75
|
+
# ORDER MATTERS, and getting it wrong reads the gate instead of the person.
|
|
76
|
+
# `sheleg-design`'"'"'s ledger carries BOTH `Last verified` (a date and what was
|
|
77
|
+
# watched) and `Status` (which holds `**green**`); preferring `status` reported
|
|
78
|
+
# 174 confirmed rows from the column that says the suite passed.
|
|
79
|
+
if (n == "human") { scol = i; sname = n; break }
|
|
80
|
+
if (n == "last verified" && sname != "human") { scol = i; sname = n }
|
|
81
|
+
if (scol == 0 && (n == "status" || n == "state")) { scol = i; sname = n }
|
|
82
|
+
# `Verified by`, `Confirmed` and `How it is checked` name the EVIDENCE, not the
|
|
83
|
+
# state — five members hold shell commands there. A column of commands read as a
|
|
84
|
+
# column of statuses is how `python3 test/validate.py` became an unreadable status.
|
|
85
|
+
}
|
|
86
|
+
next
|
|
87
|
+
}
|
|
88
|
+
if (nf == 0) next # rows before any header
|
|
89
|
+
if (trim($2) ~ /^[-: ]+$/) next # the |---| separator
|
|
90
|
+
if (NF != nf) next # a row of another shape
|
|
91
|
+
if (scol == 0) { headerless++; next } # counted, so the caller can say so
|
|
92
|
+
print trim($2) "\t" trim($(scol)) "\t" trim($3) "\t" (nf > 5 ? trim($5) : "")
|
|
93
|
+
}
|
|
94
|
+
END { print "##HEADERLESS " headerless+0 > "/dev/stderr"
|
|
95
|
+
print "##COLUMN " (sname == "" ? "-" : sname) > "/dev/stderr" }
|
|
96
|
+
' "$LEDGER" > "$TMP/rows" 2>"$TMP/meta"
|
|
97
|
+
|
|
63
98
|
ROWS=$(grep -c '' "$TMP/rows" 2>/dev/null) || ROWS=0
|
|
99
|
+
HEADERLESS=$(sed -n 's/^##HEADERLESS //p' "$TMP/meta" 2>/dev/null)
|
|
100
|
+
HEADERLESS=${HEADERLESS:-0}
|
|
101
|
+
SCOL=$(sed -n 's/^##COLUMN //p' "$TMP/meta" 2>/dev/null)
|
|
102
|
+
SCOL=${SCOL:--}
|
|
103
|
+
|
|
64
104
|
if [ "$ROWS" -eq 0 ]; then
|
|
105
|
+
if [ "$HEADERLESS" -gt 0 ]; then
|
|
106
|
+
# THE CASE THAT WAS SILENTLY GREEN. Rows exist and none can be read, which is the one
|
|
107
|
+
# answer that must never be spelled "0 unverified".
|
|
108
|
+
echo "dormant: exposure — $LEDGER has $HEADERLESS row(s) but no column named Human,"
|
|
109
|
+
echo " Last verified, Status or State. Columns like Verified by or How it is"
|
|
110
|
+
echo " checked name the EVIDENCE, not the state, and are deliberately not read."
|
|
111
|
+
echo " Nothing here can say whether anybody looked, so this reports no number."
|
|
112
|
+
exit 0
|
|
113
|
+
fi
|
|
65
114
|
echo "dormant: exposure — $LEDGER has no REQ rows yet"
|
|
66
115
|
exit 0
|
|
67
116
|
fi
|
|
117
|
+
if [ "$HEADERLESS" -gt 0 ]; then
|
|
118
|
+
echo "note: $HEADERLESS row(s) sit under a header with no status column and are not counted"
|
|
119
|
+
fi
|
|
68
120
|
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
|
|
72
|
-
|
|
121
|
+
# Unconfirmed is a small closed vocabulary, and the empty cell is in it: a blank status is
|
|
122
|
+
# the commonest way a row means "nobody has said", and reading it as confirmed inverts the
|
|
123
|
+
# file's purpose.
|
|
124
|
+
# NORMALISED first: these ledgers write `**never**`, not `never`. Bold hid three real
|
|
125
|
+
# unverified rows in one member and seven in another, and both reported zero.
|
|
126
|
+
awk -F'\t' '{ s=tolower($2); gsub(/[*`]/, "", s); gsub(/^[ \t]+|[ \t]+$/, "", s);
|
|
127
|
+
if (s=="never" || s=="" || s=="-" || s=="no" || s=="unverified" ||
|
|
128
|
+
s=="pending" || s=="none") print }' \
|
|
73
129
|
"$TMP/rows" > "$TMP/unverified"
|
|
74
130
|
UNVERIFIED=$(grep -c '' "$TMP/unverified" 2>/dev/null) || UNVERIFIED=0
|
|
75
131
|
|
|
132
|
+
# A THIRD BUCKET, because two are not enough. A status that is neither a known
|
|
133
|
+
# unconfirmed word nor a date is UNREADABLE — `last tuesday`, `soon`, `ask Ben`. Counting
|
|
134
|
+
# it as confirmed is how a shrug becomes a clean bill, which the fixture for this line
|
|
135
|
+
# caught the moment it was written.
|
|
136
|
+
awk -F'\t' '{ s=tolower($2); gsub(/[*`]/, "", s); gsub(/^[ \t]+|[ \t]+$/, "", s);
|
|
137
|
+
if (s=="never" || s=="" || s=="-" || s=="no" || s=="unverified" ||
|
|
138
|
+
s=="pending" || s=="none") next;
|
|
139
|
+
if ($2 ~ /[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/) next;
|
|
140
|
+
if (s=="pass" || s=="yes" || s=="verified" || s=="ok" || s=="observed" ||
|
|
141
|
+
s=="confirmed" || s=="green") next;
|
|
142
|
+
print }' "$TMP/rows" > "$TMP/unreadable"
|
|
143
|
+
UNREADABLE=$(grep -c '' "$TMP/unreadable" 2>/dev/null) || UNREADABLE=0
|
|
144
|
+
|
|
76
145
|
# ---------- since: a date, or the literal `never checked` ----------
|
|
77
146
|
# ZERO WOULD BE A LIE IN THE DANGEROUS DIRECTION. "0 days" reads as *checked today*,
|
|
78
147
|
# which is the exact opposite of "nobody has ever looked", so the two cases print
|
|
79
148
|
# different words rather than different numbers.
|
|
80
|
-
awk -F'
|
|
81
|
-
|
|
149
|
+
awk -F'\t' '{ if ($2 ~ /[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/) {
|
|
150
|
+
match($2, /[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/);
|
|
151
|
+
print substr($2, RSTART, RLENGTH) } }' \
|
|
82
152
|
"$TMP/rows" | sort > "$TMP/dates"
|
|
83
153
|
NEWEST=$(tail -1 "$TMP/dates" 2>/dev/null)
|
|
84
154
|
|
|
85
155
|
if [ -z "$NEWEST" ]; then
|
|
86
|
-
|
|
156
|
+
# THREE FACTS, NOT TWO. "nobody has ever looked", "this shape records no dates" and
|
|
157
|
+
# "somebody wrote something nobody can read" are different, and the first draft printed
|
|
158
|
+
# the middle one for the last — a clean bill two lines under a shrug.
|
|
159
|
+
if [ "$UNREADABLE" -gt 0 ]; then
|
|
160
|
+
SINCE="never checked ($UNREADABLE status(es) this script cannot read)"
|
|
161
|
+
elif [ "$UNVERIFIED" -eq 0 ]; then
|
|
162
|
+
SINCE="no confirmation dates recorded"
|
|
163
|
+
else
|
|
164
|
+
SINCE="never checked"
|
|
165
|
+
fi
|
|
87
166
|
else
|
|
88
167
|
# Portable day arithmetic: BSD date and GNU date disagree on every flag that matters,
|
|
89
168
|
# so ask python, which both platforms have and which will not silently return today.
|
|
@@ -97,10 +176,16 @@ print((datetime.date.today() - d).days)
|
|
|
97
176
|
PY
|
|
98
177
|
)
|
|
99
178
|
if [ -z "${DAYS:-}" ]; then
|
|
100
|
-
echo "FAIL: exposure — $LEDGER has a
|
|
179
|
+
echo "FAIL: exposure — $LEDGER has a confirmation date this script cannot parse: $NEWEST"
|
|
101
180
|
exit 1
|
|
102
181
|
fi
|
|
103
|
-
|
|
182
|
+
# The same discipline as the clean bill below: only a `Human` column licenses the word
|
|
183
|
+
# "human". Any other column records that something looked, not that somebody did.
|
|
184
|
+
if [ "$SCOL" = "human" ]; then
|
|
185
|
+
SINCE="$DAYS days since the last human confirmation"
|
|
186
|
+
else
|
|
187
|
+
SINCE="$DAYS days since the last \`$SCOL\` entry"
|
|
188
|
+
fi
|
|
104
189
|
fi
|
|
105
190
|
|
|
106
191
|
# ---------- releases: what has gone out on top of it ----------
|
|
@@ -134,18 +219,35 @@ esac
|
|
|
134
219
|
echo "$LINE"
|
|
135
220
|
|
|
136
221
|
# ---------- the check-list: a number without it says there is a problem, not where ----------
|
|
222
|
+
# A SHRUG IS NOT A CLEAN BILL. A status that is neither a date nor a known word means
|
|
223
|
+
# somebody wrote something and nobody can act on it; printing "every shipped row is
|
|
224
|
+
# confirmed" over that is the failure this whole file exists to prevent.
|
|
225
|
+
if [ "$UNREADABLE" -gt 0 ]; then
|
|
226
|
+
echo " $UNREADABLE row(s) carry a status that is neither a date nor a known word,"
|
|
227
|
+
echo " so no clean bill is printed over them:"
|
|
228
|
+
cut -f1,2 "$TMP/unreadable" | head -"$LIST_MAX" | sed 's/^/ /'
|
|
229
|
+
if [ "$UNVERIFIED" -eq 0 ]; then exit 0; fi
|
|
230
|
+
fi
|
|
231
|
+
|
|
137
232
|
if [ "$UNVERIFIED" -eq 0 ]; then
|
|
138
|
-
|
|
233
|
+
# NAME THE COLUMN. `Human` means a person; `Status`, `State` and `Watched` do not
|
|
234
|
+
# distinguish a person from a command — the umbrella's own ledger says `verified` means
|
|
235
|
+
# "a person **or a command** looked", so claiming a human confirmation from that column
|
|
236
|
+
# is a stronger sentence than the data supports.
|
|
237
|
+
if [ "$SCOL" = "human" ]; then
|
|
238
|
+
echo " every shipped row carries a human confirmation"
|
|
239
|
+
else
|
|
240
|
+
echo " every shipped row is confirmed in its \`$SCOL\` column — which does not"
|
|
241
|
+
echo " separate a person from a command; only a \`Human\` column does that"
|
|
242
|
+
fi
|
|
139
243
|
exit 0
|
|
140
244
|
fi
|
|
141
245
|
|
|
142
246
|
# Oldest first by `Shipped in`, which is the only ordering this repository can defend.
|
|
143
247
|
# Version sort, so v1.9.0 precedes v1.10.0 — a lexical sort puts the newer one first and
|
|
144
248
|
# hands the operator the wrong end of the list.
|
|
145
|
-
awk -F'
|
|
146
|
-
|
|
147
|
-
gsub(/^[ \t]+|[ \t]+$/, "", ship);
|
|
148
|
-
gsub(/^[ \t]+|[ \t]+$/, "", what);
|
|
249
|
+
awk -F'\t' '{ req=$1; what=$3; ship=$4;
|
|
250
|
+
if (ship == "") ship = "—";
|
|
149
251
|
# Truncated on a WORD boundary, never mid-character: awk counts bytes
|
|
150
252
|
# here, so `substr(what, 1, 56)` cut a Cyrillic letter in half and printed
|
|
151
253
|
# a replacement glyph. Appending whole words cannot land inside one.
|