@plot-pm/board 0.11.0 → 0.12.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/dist/board-server.mjs +124 -124
- package/package.json +5 -1
- package/plot-agent-monitor.sh +37 -13
- package/plot-approve.sh +6 -3
- package/plot-build-monitor.sh +435 -0
- package/plot-config.sh +8 -1
- package/plot-default-branch.sh +109 -0
- package/plot-deliver.sh +4 -2
- package/plot-dispatch.sh +500 -5
- package/plot-fleet-scan.sh +498 -175
- package/plot-host.sh +116 -13
- package/plot-monitor-subject.sh +194 -0
- package/plot-plan-meta.sh +111 -7
- package/plot-pr-merged.sh +180 -0
- package/plot-reap.sh +45 -5
- package/plot-release-refs.sh +188 -46
- package/plot-resolve-artifact.sh +115 -22
package/plot-resolve-artifact.sh
CHANGED
|
@@ -9,10 +9,11 @@
|
|
|
9
9
|
# THE ONLY AUTOMATIC WRITE THIS SYSTEM GRANTS, and it is granted for three
|
|
10
10
|
# verified reasons rather than for convenience:
|
|
11
11
|
#
|
|
12
|
-
# 1. `-merge` KEEPS THE FILE VALID. `.gitattributes` marks
|
|
12
|
+
# 1. `-merge` KEEPS THE FILE VALID. `.gitattributes` marks every bundle
|
|
13
13
|
# `-merge`, so git keeps one side whole and writes NO conflict markers.
|
|
14
14
|
# The artifact stays buildable JavaScript *through* a conflict — which is
|
|
15
|
-
# why a script may touch it at all.
|
|
15
|
+
# why a script may touch it at all. `scripts/check-bundle-attributes.sh`
|
|
16
|
+
# is the gate that keeps that true of every bundle rather than of one.
|
|
16
17
|
# 2. THE REBUILD IS DETERMINISTIC. Measured: `build.mjs` embeds no timestamp
|
|
17
18
|
# and no randomness, so the output does not depend on which side was kept.
|
|
18
19
|
# 3. CI PROVES IT. The no-diff gate fails the build if the committed artifact
|
|
@@ -52,7 +53,7 @@
|
|
|
52
53
|
# AN EMPTY CONFLICT SET IS NOT A REFUSAL ABOUT FILES. Three cases, named apart,
|
|
53
54
|
# because two of them were once one:
|
|
54
55
|
#
|
|
55
|
-
#
|
|
56
|
+
# bundles only → the licensed case → repair
|
|
56
57
|
# other files present → needs judgement → not-artifact-only
|
|
57
58
|
# empty, no merge ran → nothing was observed → not-observed
|
|
58
59
|
#
|
|
@@ -70,10 +71,45 @@ set -uo pipefail
|
|
|
70
71
|
|
|
71
72
|
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
|
72
73
|
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
|
|
74
|
+
# THE FILES THIS SCRIPT MAY RESOLVE — a SET, and derived rather than listed.
|
|
75
|
+
#
|
|
76
|
+
# It was one hardcoded filename until 2026-09-06, and that cost a repair the
|
|
77
|
+
# same day: PR #727 conflicted in `plot-registryd.mjs` — a `-merge` bundle with
|
|
78
|
+
# a deterministic rebuild, exactly the licensed case — and this script refused
|
|
79
|
+
# `not-artifact-only` against a list naming only `board-server.mjs`. The refusal
|
|
80
|
+
# was correct behaviour against a stale list. Hours later the same branch
|
|
81
|
+
# conflicted in `board-server.mjs` and was repaired automatically: same class of
|
|
82
|
+
# conflict, opposite outcome, one filename apart.
|
|
83
|
+
#
|
|
84
|
+
# DERIVED FROM `build.mjs`'S OWN DECLARATIONS, by the same pipeline
|
|
85
|
+
# `scripts/check-bundle-attributes.sh` uses, because a hand-written list here
|
|
86
|
+
# would be a fourth place to drift — and drift is the defect this replaces. The
|
|
87
|
+
# build declares each output as `const shippedX = path.join(here, '…')`, which
|
|
88
|
+
# is what an author writes when adding a bundle; nothing else has to be
|
|
89
|
+
# remembered. Nine bundles today; `plot-landed.mjs` arrived while the plan that
|
|
90
|
+
# asked for this was still in draft, and the derivation found it.
|
|
91
|
+
#
|
|
92
|
+
# `plot-monitor.mjs` IS DELIBERATELY ABSENT. It is committed and documented, and
|
|
93
|
+
# no `outfile` names it — nothing rebuilds it. Property 2 above is the whole
|
|
94
|
+
# licence, so a file with no deterministic rebuild cannot be on this list. The
|
|
95
|
+
# derivation reads the build, so it cannot ask for it.
|
|
96
|
+
#
|
|
97
|
+
# Still named in the board's contract as well, because the two run in different
|
|
98
|
+
# languages and neither can import the other's constant. The pairing is asserted
|
|
99
|
+
# by a test rather than trusted — and that test now asserts SET EQUALITY, since
|
|
100
|
+
# a set that agrees on one member and differs on another is exactly the drift
|
|
101
|
+
# this replaces.
|
|
102
|
+
#
|
|
103
|
+
# READ FROM THE REPOSITORY BEING REPAIRED, not from this script's own checkout.
|
|
104
|
+
# The script is vendored into the published package, where `packages/` does not
|
|
105
|
+
# exist — and it rebuilds with `pnpm build:board` inside the target repo, so the
|
|
106
|
+
# build that defines the set is the one that will run. Resolved below, once
|
|
107
|
+
# `repo_root` is known.
|
|
108
|
+
bundle_set() { # $1=repo root → one path per line, sorted
|
|
109
|
+
grep -aoE "shipped[A-Za-z]* = path\.join\([^)]*'[^']*'\)" "$1/packages/board/build.mjs" 2>/dev/null \
|
|
110
|
+
| sed -E "s|.*'\.\./\.\./([^']*)'.*|\1|" \
|
|
111
|
+
| sort -u
|
|
112
|
+
}
|
|
77
113
|
|
|
78
114
|
dry_run=0
|
|
79
115
|
branch=""
|
|
@@ -109,6 +145,19 @@ MAIN=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's#^o
|
|
|
109
145
|
|
|
110
146
|
repo_root=$(git rev-parse --show-toplevel)
|
|
111
147
|
|
|
148
|
+
# THE SET, resolved against the repository this run will rebuild.
|
|
149
|
+
ARTIFACT_PATHS=$(bundle_set "$repo_root")
|
|
150
|
+
|
|
151
|
+
# AN EMPTY DERIVATION REFUSES, and it must: the guard below asks whether every
|
|
152
|
+
# unmerged path is in this set, and against an empty set that question has no
|
|
153
|
+
# true answer to give — but a guard written the other way round would have said
|
|
154
|
+
# yes to everything. The build changing shape, or a checkout with no
|
|
155
|
+
# `packages/`, is a reason to stop rather than a reason to repair blind.
|
|
156
|
+
if [ -z "$ARTIFACT_PATHS" ]; then
|
|
157
|
+
echo "step: no bundles derived from packages/board/build.mjs — refusing"
|
|
158
|
+
finish refused no-bundle-set
|
|
159
|
+
fi
|
|
160
|
+
|
|
112
161
|
# WHICH WORKTREE HOLDS THIS BRANCH — ASK GIT, do not reconstruct the path from
|
|
113
162
|
# the branch name.
|
|
114
163
|
#
|
|
@@ -151,7 +200,10 @@ fi
|
|
|
151
200
|
|
|
152
201
|
if [ "$dry_run" = 1 ]; then
|
|
153
202
|
echo "step: would use worktree $wt"
|
|
154
|
-
echo "step: would merge origin/$MAIN, take a side of
|
|
203
|
+
echo "step: would merge origin/$MAIN, take a side of each conflicted bundle, rebuild, test"
|
|
204
|
+
printf 'step: bundle set (%s): %s\n' \
|
|
205
|
+
"$(printf '%s\n' "$ARTIFACT_PATHS" | grep -c .)" \
|
|
206
|
+
"$(printf '%s' "$ARTIFACT_PATHS" | tr '\n' ' ')"
|
|
155
207
|
echo "step: would push only if pnpm run test:board passes"
|
|
156
208
|
finish refused dry-run
|
|
157
209
|
fi
|
|
@@ -274,23 +326,53 @@ if [ "$n_unmerged" = "0" ]; then
|
|
|
274
326
|
finish refused not-observed
|
|
275
327
|
fi
|
|
276
328
|
|
|
277
|
-
#
|
|
278
|
-
# among the conflicts" — an
|
|
279
|
-
#
|
|
280
|
-
|
|
329
|
+
# EVERY unmerged path is a bundle: the conflict set is a SUBSET of the bundle
|
|
330
|
+
# set, and nothing else is in it. NOT "a bundle is among the conflicts" — an
|
|
331
|
+
# implementation asking that passes every bundle-only case and silently repairs
|
|
332
|
+
# merges that need judgement as a whole. The claim stayed exact when the list
|
|
333
|
+
# grew from one file to nine; only the thing each path is checked against
|
|
334
|
+
# changed. A merge conflicting in a bundle AND anything else still needs a
|
|
335
|
+
# person, even though one of its files does not.
|
|
336
|
+
#
|
|
337
|
+
# WALKED PER PATH rather than compared as a whole, because the conflict set is
|
|
338
|
+
# an arbitrary subset of nine and there is no single string to compare it to.
|
|
339
|
+
# The direction is what keeps it exact: every element of the observed set must
|
|
340
|
+
# appear in the licensed set, so an unlicensed path can only ever refuse.
|
|
341
|
+
outside=""
|
|
342
|
+
while IFS= read -r conflict; do
|
|
343
|
+
[ -n "$conflict" ] || continue
|
|
344
|
+
if ! printf '%s\n' "$ARTIFACT_PATHS" | grep -qxF -- "$conflict"; then
|
|
345
|
+
outside="${outside}${outside:+ }$conflict"
|
|
346
|
+
fi
|
|
347
|
+
done <<EOF
|
|
348
|
+
$unmerged
|
|
349
|
+
EOF
|
|
350
|
+
|
|
351
|
+
if [ -n "$outside" ]; then
|
|
281
352
|
git -C "$wt" merge --abort >/dev/null 2>&1 || true
|
|
282
|
-
echo "step: conflict set is not
|
|
353
|
+
echo "step: conflict set is not bundles only — refusing"
|
|
283
354
|
printf 'step: unmerged: %s\n' "$(printf '%s' "$unmerged" | tr '\n' ' ')"
|
|
355
|
+
printf 'step: outside the bundle set: %s\n' "$outside"
|
|
284
356
|
finish refused not-artifact-only
|
|
285
357
|
fi
|
|
286
358
|
|
|
287
|
-
# 3. Take a side. WHICH SIDE CANNOT MATTER — the
|
|
288
|
-
# diff is never read. `--theirs` because the
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
359
|
+
# 3. Take a side of EACH conflicted bundle. WHICH SIDE CANNOT MATTER — the
|
|
360
|
+
# rebuild overwrites it — and the diff is never read. `--theirs` because the
|
|
361
|
+
# command needs a word.
|
|
362
|
+
#
|
|
363
|
+
# Only the paths that actually conflicted, never the whole set: a bundle git
|
|
364
|
+
# merged cleanly has no side to take, and `checkout --theirs` on an unmerged-
|
|
365
|
+
# stage-free path errors rather than doing nothing useful.
|
|
366
|
+
while IFS= read -r conflict; do
|
|
367
|
+
[ -n "$conflict" ] || continue
|
|
368
|
+
git -C "$wt" checkout --theirs -- "$conflict" 2>/dev/null \
|
|
369
|
+
|| git -C "$wt" checkout --ours -- "$conflict" 2>/dev/null \
|
|
370
|
+
|| true
|
|
371
|
+
git -C "$wt" add -- "$conflict" 2>/dev/null || true
|
|
372
|
+
echo "step: took a side of $conflict (either — the rebuild decides)"
|
|
373
|
+
done <<EOF
|
|
374
|
+
$unmerged
|
|
375
|
+
EOF
|
|
294
376
|
|
|
295
377
|
# 4. Rebuild, in the branch's OWN worktree. This is what makes the kept side
|
|
296
378
|
# irrelevant, and it is the property CI's no-diff gate then re-checks.
|
|
@@ -299,8 +381,19 @@ if ! (cd "$wt" && pnpm build:board >/dev/null 2>&1); then
|
|
|
299
381
|
echo "step: rebuild failed — pushing nothing"
|
|
300
382
|
finish abandoned build-failed
|
|
301
383
|
fi
|
|
302
|
-
|
|
303
|
-
|
|
384
|
+
# EVERY bundle is staged after the rebuild, not just the ones that conflicted.
|
|
385
|
+
# `pnpm build:board` regenerates all nine, and a rebuild triggered by one
|
|
386
|
+
# conflict can legitimately move another — the merge brought in source changes
|
|
387
|
+
# for the whole package. Staging only the conflicted paths would leave those
|
|
388
|
+
# modifications unstaged, and CI's no-diff gate would then fail the push for a
|
|
389
|
+
# file this run had already rebuilt correctly.
|
|
390
|
+
while IFS= read -r bundle; do
|
|
391
|
+
[ -n "$bundle" ] || continue
|
|
392
|
+
git -C "$wt" add -- "$bundle" 2>/dev/null || true
|
|
393
|
+
done <<EOF
|
|
394
|
+
$ARTIFACT_PATHS
|
|
395
|
+
EOF
|
|
396
|
+
printf 'step: rebuilt and staged %s bundle(s)\n' "$(printf '%s\n' "$ARTIFACT_PATHS" | grep -c .)"
|
|
304
397
|
|
|
305
398
|
# The merge commit exists only once the rebuild has produced the artifact it
|
|
306
399
|
# will carry. Committing before the build would leave a commit holding a stale
|