forge-orkes 0.80.1 → 0.80.3
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/bin/create-forge.js
CHANGED
|
@@ -588,12 +588,21 @@ function extractDetectionBlock(guideContent) {
|
|
|
588
588
|
* with the exact guide pointer. There are NO per-version code branches: a new
|
|
589
589
|
* guide that ships with a conformant Detection block is auto-covered.
|
|
590
590
|
*
|
|
591
|
-
* Range: installed
|
|
591
|
+
* Range: installed <= v <= source. `installedVersion` is the project's
|
|
592
592
|
* settings.json forge.version captured BEFORE the version stamp; `source` is
|
|
593
593
|
* pkgVersion (this package's package.json) — never the template settings.json
|
|
594
594
|
* literal, which is a placeholder the installer stamps at write time. Non-
|
|
595
595
|
* interactive: the bin only warns and points at the guide; it never applies.
|
|
596
596
|
*
|
|
597
|
+
* Lower bound is INCLUSIVE (issue #43): the version stamp always advances
|
|
598
|
+
* unconditionally, even when a MIGRATE hit was surfaced but declined that
|
|
599
|
+
* run — so an exclusive `installed < v` permanently hides a same-numbered
|
|
600
|
+
* guide the moment its own version gets stamped without being applied. This
|
|
601
|
+
* is safe to widen because the guide's own `## Detection` block is the real
|
|
602
|
+
* gate (repo-state-based: tracked file, size, absence of the post-migration
|
|
603
|
+
* artifact) — the version range only decides which guides are worth asking;
|
|
604
|
+
* a genuinely-already-applied guide's Detection block reports a no-op.
|
|
605
|
+
*
|
|
597
606
|
* Returns the applying guides as [{version, guide, reason}] — the human warning
|
|
598
607
|
* and the --json `migrations` key render the same findings.
|
|
599
608
|
*/
|
|
@@ -606,7 +615,7 @@ function runPostUpgradeMigrationChecks(installedVersion) {
|
|
|
606
615
|
installedVersion && installedVersion !== 'unknown' ? installedVersion : '0.0.0';
|
|
607
616
|
const source = pkgVersion;
|
|
608
617
|
|
|
609
|
-
// Select in-range guides: installed
|
|
618
|
+
// Select in-range guides: installed <= v <= source. Parse {v} from the filename.
|
|
610
619
|
let guides;
|
|
611
620
|
try {
|
|
612
621
|
guides = fs
|
|
@@ -618,7 +627,7 @@ function runPostUpgradeMigrationChecks(installedVersion) {
|
|
|
618
627
|
.filter(Boolean)
|
|
619
628
|
.filter(
|
|
620
629
|
(g) =>
|
|
621
|
-
compareVersions(installed, g.version)
|
|
630
|
+
compareVersions(installed, g.version) <= 0 &&
|
|
622
631
|
compareVersions(g.version, source) <= 0
|
|
623
632
|
)
|
|
624
633
|
.sort((a, b) => compareVersions(a.version, b.version));
|
package/package.json
CHANGED
|
@@ -135,7 +135,12 @@ function extract_id(line, w, arr, n, tok, digits, suffix) {
|
|
|
135
135
|
# normalization. Labelled ids (M-EVT01, m-SEQPRIM01) must NOT be digit-
|
|
136
136
|
# stripped — that would collapse distinct labelled ids onto the same
|
|
137
137
|
# numeric suffix (m-EVT01 and m-SEQPRIM01 would both become m-01) — so
|
|
138
|
-
# their alphanumeric suffix is preserved
|
|
138
|
+
# their alphanumeric suffix is preserved VERBATIM, case included (issue
|
|
139
|
+
# #44): only the "m-" prefix is normalized, exactly like the numeric path
|
|
140
|
+
# never invents a digit convention of its own. Forge doesn't own the
|
|
141
|
+
# label's spelling — a project's own casing convention (e.g. m-EVT01, all
|
|
142
|
+
# caps) must survive the shard, or citations elsewhere in the repo stop
|
|
143
|
+
# matching the shard filename.
|
|
139
144
|
if (tok !~ /^[Mm]-?[A-Za-z0-9]+$/) return ""
|
|
140
145
|
suffix = tok
|
|
141
146
|
sub(/^[Mm]-?/, "", suffix)
|
|
@@ -145,7 +150,7 @@ function extract_id(line, w, arr, n, tok, digits, suffix) {
|
|
|
145
150
|
gsub(/[^0-9]/, "", digits)
|
|
146
151
|
return "m-" digits
|
|
147
152
|
}
|
|
148
|
-
return "m-"
|
|
153
|
+
return "m-" suffix
|
|
149
154
|
}
|
|
150
155
|
|
|
151
156
|
function add_id(id) {
|
|
@@ -163,6 +168,7 @@ BEGIN {
|
|
|
163
168
|
cur_noid_key = ""
|
|
164
169
|
n_ids = 0
|
|
165
170
|
n_noid = 0
|
|
171
|
+
n_other_headings = 0
|
|
166
172
|
}
|
|
167
173
|
|
|
168
174
|
/^## / {
|
|
@@ -174,6 +180,10 @@ BEGIN {
|
|
|
174
180
|
if ($0 ~ /^## Needs Resolution/) { section = "NEEDS_RESOLUTION"; next }
|
|
175
181
|
if ($0 ~ /^## Amendment Log/) { section = "AMENDMENT"; next }
|
|
176
182
|
section = "OTHER"
|
|
183
|
+
n_other_headings++
|
|
184
|
+
w = $0
|
|
185
|
+
sub(/^## /, "", w)
|
|
186
|
+
other_heading_order[n_other_headings] = w
|
|
177
187
|
other_buf = other_buf $0 "\n"
|
|
178
188
|
next
|
|
179
189
|
}
|
|
@@ -308,6 +318,23 @@ END {
|
|
|
308
318
|
exit 1
|
|
309
319
|
}
|
|
310
320
|
|
|
321
|
+
# Unrecognized top-level `## ` sections (issue #45) are preserved verbatim
|
|
322
|
+
# in context-log.md's "Other Sections" by design — never guessed onto a
|
|
323
|
+
# milestone — but a large or multi-heading OTHER bucket usually means the
|
|
324
|
+
# source context.md uses a section vocabulary this tool doesn't know about
|
|
325
|
+
# (e.g. a project-specific "## Active Streams"), and that content silently
|
|
326
|
+
# missing its own per-milestone home is easy to overlook. Loud, not fatal:
|
|
327
|
+
# nothing is lost (it's right there in context-log.md), so this warns
|
|
328
|
+
# without changing the exit code.
|
|
329
|
+
if (n_other_headings > 0 && length(other_buf) > 500) {
|
|
330
|
+
headings_list = other_heading_order[1]
|
|
331
|
+
for (i = 2; i <= n_other_headings; i++) headings_list = headings_list ", " other_heading_order[i]
|
|
332
|
+
print "forge-context-migrate: WARNING — " length(other_buf) " byte(s) across " \
|
|
333
|
+
n_other_headings " unrecognized heading(s) (" headings_list ") landed in" \
|
|
334
|
+
" context-log.md's \"Other Sections\" instead of a per-milestone file — review" \
|
|
335
|
+
" it; if that content is milestone-scoped, re-file it into context/{id}.md by hand" > "/dev/stderr"
|
|
336
|
+
}
|
|
337
|
+
|
|
311
338
|
print "forge-context-migrate: " n_ids " milestone id(s) processed"
|
|
312
339
|
}
|
|
313
340
|
AWKEOF
|
|
@@ -159,11 +159,14 @@ src_after="$(cat "$SOURCE" | wc -c)"
|
|
|
159
159
|
[ -n "$src_after" ] && pass "source context.md still readable after migration" || fail "source context.md unreadable after migration"
|
|
160
160
|
grep -q "### M7 — Widget Registry" "$SOURCE" && pass "source context.md left untouched" || fail "source context.md was modified"
|
|
161
161
|
|
|
162
|
-
# --- labelled milestone ids (issue #42)
|
|
162
|
+
# --- labelled milestone ids (issue #42, case preservation issue #44) --------
|
|
163
163
|
# Non-numeric ids (M-EVT01, m-SEQPRIM01) must shard into distinct files —
|
|
164
164
|
# digit-stripping them onto a shared "m-01" was the exact silent-collision
|
|
165
165
|
# bug reported upstream. Purely-numeric ids must keep their existing
|
|
166
|
-
# normalization (m-53 stays m-53, unaffected by the labelled-id path).
|
|
166
|
+
# normalization (m-53 stays m-53, unaffected by the labelled-id path). The
|
|
167
|
+
# label's own casing must survive verbatim (issue #44) — only the "m-"
|
|
168
|
+
# prefix is normalized — since a project's own convention (e.g. an
|
|
169
|
+
# all-caps label) is what the rest of its repo actually cites.
|
|
167
170
|
|
|
168
171
|
LBLROOT="$(mktemp -d)"
|
|
169
172
|
trap 'rm -rf "$ROOT" "$LBLROOT"' EXIT INT TERM
|
|
@@ -203,15 +206,22 @@ LBLOUT="$("$MIGRATE" --source "$LBLSRC" --dest "$LBLDEST" 2>&1)"
|
|
|
203
206
|
LBLRC=$?
|
|
204
207
|
[ "$LBLRC" -eq 0 ] && pass "labelled-id migration exits 0" || fail "labelled-id migration exits 0 (exit $LBLRC)"
|
|
205
208
|
|
|
206
|
-
check_file "$LBLDEST/context/m-
|
|
207
|
-
check_file "$LBLDEST/context/m-
|
|
209
|
+
check_file "$LBLDEST/context/m-EVT01.md" "context/m-EVT01.md created (labelled id, prefix normalized)"
|
|
210
|
+
check_file "$LBLDEST/context/m-SEQPRIM01.md" "context/m-SEQPRIM01.md created (distinct from m-EVT01, not digit-collapsed)"
|
|
208
211
|
check_file "$LBLDEST/context/m-53.md" "context/m-53.md still created (numeric id unaffected by labelled-id path)"
|
|
209
212
|
|
|
213
|
+
# check_file alone can't prove case survived — macOS's default case-insensitive
|
|
214
|
+
# FS makes m-evt01.md and m-EVT01.md the same lookup. `ls` returns the actual
|
|
215
|
+
# stored name; grep -x is case-sensitive regardless of the FS.
|
|
216
|
+
lbl_listing="$(ls "$LBLDEST/context" 2>/dev/null)"
|
|
217
|
+
echo "$lbl_listing" | grep -qx "m-EVT01.md" && pass "m-EVT01.md label case preserved verbatim on disk (issue #44)" || fail "label case NOT preserved — directory listing: $lbl_listing"
|
|
218
|
+
echo "$lbl_listing" | grep -qx "m-SEQPRIM01.md" && pass "m-SEQPRIM01.md label case preserved verbatim on disk (issue #44)" || fail "label case NOT preserved — directory listing: $lbl_listing"
|
|
219
|
+
|
|
210
220
|
lbl_count="$(ls "$LBLDEST"/context/*.md 2>/dev/null | wc -l | tr -d ' ')"
|
|
211
221
|
[ "$lbl_count" -eq 3 ] && pass "labelled + numeric ids produce 3 distinct files, none collapsed" || fail "labelled-id run produced $lbl_count file(s), want 3"
|
|
212
222
|
|
|
213
|
-
evt="$(cat "$LBLDEST/context/m-
|
|
214
|
-
check_has "m-
|
|
223
|
+
evt="$(cat "$LBLDEST/context/m-EVT01.md" 2>/dev/null)"
|
|
224
|
+
check_has "m-EVT01.md carries its own Deferred entry (labelled-prefix match)" "$evt" "a follow-up scoped to the labelled id"
|
|
215
225
|
|
|
216
226
|
# --- unresolvable id scheme guard (issue #42) --------------------------------
|
|
217
227
|
# A context.md whose Locked Decisions headings don't match m-<number> or a
|
|
@@ -241,6 +251,56 @@ BADRC=$?
|
|
|
241
251
|
[ "$BADRC" -ne 0 ] && pass "unresolvable id scheme exits non-zero instead of silently producing 0 shards" || fail "unresolvable id scheme should exit non-zero (exit $BADRC)"
|
|
242
252
|
check_has "unresolvable id scheme prints an ERROR line" "$BADOUT" "ERROR"
|
|
243
253
|
|
|
254
|
+
# --- large unrecognized-section warning (issue #45) -------------------------
|
|
255
|
+
# A project-specific top-level heading (e.g. "## Active Streams") this tool
|
|
256
|
+
# doesn't know about is preserved verbatim in context-log.md's "Other
|
|
257
|
+
# Sections" by design — but silently doing that with a large amount of
|
|
258
|
+
# content is easy to overlook. Must warn (not fail — nothing is lost) when
|
|
259
|
+
# the OTHER bucket is substantial, and stay silent when it's small/absent.
|
|
260
|
+
# Deliberately alongside a resolving Locked Decisions id, so this warning
|
|
261
|
+
# fires independent of (and isn't masked by) the zero-shards guard above.
|
|
262
|
+
|
|
263
|
+
WARNROOT="$(mktemp -d)"
|
|
264
|
+
trap 'rm -rf "$ROOT" "$LBLROOT" "$BADROOT" "$WARNROOT"' EXIT INT TERM
|
|
265
|
+
WARNSRC="$WARNROOT/context.md"
|
|
266
|
+
WARNDEST="$WARNROOT/.forge"
|
|
267
|
+
mkdir -p "$WARNDEST"
|
|
268
|
+
|
|
269
|
+
{
|
|
270
|
+
printf '## Locked Decisions\n\n### m-53 — numeric decision\n\n- **Decision**: fine.\n\n'
|
|
271
|
+
printf '## Active Streams\n\n### m-HC01 — some stream\n\n'
|
|
272
|
+
# 600 bytes — over the 500-byte warn floor
|
|
273
|
+
printf 'x%.0s' $(seq 1 600)
|
|
274
|
+
printf '\n\n## Needs Resolution\n\n(none)\n\n## Amendment Log\n\n(none)\n'
|
|
275
|
+
} > "$WARNSRC"
|
|
276
|
+
|
|
277
|
+
WARNOUT="$("$MIGRATE" --source "$WARNSRC" --dest "$WARNDEST" --dry-run 2>&1)"
|
|
278
|
+
WARNRC=$?
|
|
279
|
+
[ "$WARNRC" -eq 0 ] && pass "large unrecognized-section run still exits 0 (warning, not a failure)" || fail "large unrecognized-section run should exit 0 (exit $WARNRC)"
|
|
280
|
+
check_has "large unrecognized-section run prints a WARNING line" "$WARNOUT" "WARNING"
|
|
281
|
+
check_has "warning names the unrecognized heading" "$WARNOUT" "Active Streams"
|
|
282
|
+
|
|
283
|
+
SMALLROOT="$(mktemp -d)"
|
|
284
|
+
trap 'rm -rf "$ROOT" "$LBLROOT" "$BADROOT" "$WARNROOT" "$SMALLROOT"' EXIT INT TERM
|
|
285
|
+
SMALLSRC="$SMALLROOT/context.md"
|
|
286
|
+
SMALLDEST="$SMALLROOT/.forge"
|
|
287
|
+
mkdir -p "$SMALLDEST"
|
|
288
|
+
|
|
289
|
+
cat > "$SMALLSRC" <<'FIXTURE'
|
|
290
|
+
## Locked Decisions
|
|
291
|
+
|
|
292
|
+
### m-53 — numeric decision
|
|
293
|
+
|
|
294
|
+
- **Decision**: fine.
|
|
295
|
+
|
|
296
|
+
## Some Small Aside
|
|
297
|
+
|
|
298
|
+
A short unrecognized note, well under the warn floor.
|
|
299
|
+
FIXTURE
|
|
300
|
+
|
|
301
|
+
SMALLOUT="$("$MIGRATE" --source "$SMALLSRC" --dest "$SMALLDEST" --dry-run 2>&1)"
|
|
302
|
+
check_absent "a small unrecognized section stays silent (no WARNING)" "$SMALLOUT" "WARNING"
|
|
303
|
+
|
|
244
304
|
# --- summary -----------------------------------------------------------------
|
|
245
305
|
|
|
246
306
|
printf '\n%s passed, %s failed\n' "$PASSED" "$FAILED"
|