@techgoblin/gobstack 0.5.0-beta.5 → 0.5.0-beta.7
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/README.md +5 -2
- package/bin/goblin-init +4 -1
- package/bin/goblin-lib.sh +25 -1
- package/bin/goblin-verify +108 -6
- package/docs/ENFORCEMENT.md +2 -2
- package/docs/GLOSSARY.md +40 -0
- package/docs/GUIDE.md +57 -22
- package/docs/LIMITS.md +2 -1
- package/docs/RECORD-NOTES.md +21 -0
- package/manifest/enforcement.tsv +2 -2
- package/manifest/glossary.tsv +8 -0
- package/package.json +1 -1
- package/docs/w6-tty-redraw-pty-transcript.txt +0 -334
package/README.md
CHANGED
|
@@ -62,7 +62,8 @@ After installing, in this order:
|
|
|
62
62
|
**A default software-class install (no agent skills — those are `gob emit`'s job) verifies green —
|
|
63
63
|
`38 passed, 0 failed, 11 advisory, 33 skipped`, exit 0 — once
|
|
64
64
|
`HANDOFF.md` names a commit that exists. Before that edit the scaffold's `0000000` placeholder is
|
|
65
|
-
the one expected red: `37 passed, 1 failed`, `HP-05`. Both numbers measured at
|
|
65
|
+
the one expected red: `37 passed, 1 failed`, `HP-05`. Both numbers measured at the 0.5.0 neutral-first
|
|
66
|
+
revision (see `docs/RECORD-NOTES.md`, V3);
|
|
66
67
|
the run and the fix are step 2 of `docs/GUIDE.md`.**
|
|
67
68
|
Thirty-three rows skip — the five skill rows (`SK-01`..`SK-04`, `AU-04`) skip on the `playbooks`
|
|
68
69
|
opt-out a skills-free install records, then the not-yet rows (`HS-02` has no pinned pre-change
|
|
@@ -155,6 +156,8 @@ below is the reference material the guide points into, so the two do not compete
|
|
|
155
156
|
| `docs/RISKS.md` | the risk register, the advisory rows named, the non-goals |
|
|
156
157
|
| `docs/CI.md` | the CI lane: what makes a workflow a gate, the four settings a repository cannot set, and the electron opt-in |
|
|
157
158
|
| `docs/LOOP.md` | the judge role and the loop contract: what a goal-mode loop actually does, the record, and what neither can see |
|
|
159
|
+
| `docs/RECORD-NOTES.md` | the wave codes the changelog and the matrix parentheticals use, one line each |
|
|
160
|
+
| `docs/GLOSSARY.md` | every term of art in one table (rendered from the shipped `.goblin/manifest/glossary.tsv`) |
|
|
158
161
|
| `docs/ADOPTION.md` | the five classes, the preset matrix, the adoption order |
|
|
159
162
|
| `docs/LIMITS.md` | where this is weaker than its sources, and what is unproven |
|
|
160
163
|
|
|
@@ -174,7 +177,7 @@ run · `3` the manifest is broken. Every run prints what it cannot see.
|
|
|
174
177
|
bash tests/run-tests.sh
|
|
175
178
|
|
|
176
179
|
Runs the source-scope rules (PR-01..PR-05) and the test scripts, including `t-verify-red.sh` —
|
|
177
|
-
one control per target-scope row (
|
|
180
|
+
one control per target-scope row (172 over 82 target rows), each required to go RED and then
|
|
178
181
|
restored, plus `t-audit.sh` for the SC-07 producer. **A verifier that only ever prints GREEN is a
|
|
179
182
|
failure**, so that file is the one that matters most.
|
|
180
183
|
|
package/bin/goblin-init
CHANGED
|
@@ -752,7 +752,10 @@ elif [ "$DRYRUN" -eq 0 ]; then
|
|
|
752
752
|
if [ "$VERIFY_RC" -eq 0 ]; then
|
|
753
753
|
printf ' %s▙ the goblin sees you. keep the gate green.%s\n' "$C_ACCENT" "$C_RESET"
|
|
754
754
|
else
|
|
755
|
-
|
|
755
|
+
# Red runs end on the concrete first command, not the mascot: the day-one verdict IS the
|
|
756
|
+
# FAIL list, and the first row's remedy line is the thing to act on (UX minor polish —
|
|
757
|
+
# the "the goblin sees you" sign-off stays a green-run line only).
|
|
758
|
+
printf ' %sstart with the first FAIL above — its remedy line says the fix.%s\n' "$C_RED" "$C_RESET"
|
|
756
759
|
fi
|
|
757
760
|
fi
|
|
758
761
|
|
package/bin/goblin-lib.sh
CHANGED
|
@@ -58,7 +58,31 @@ g_pass() {
|
|
|
58
58
|
printf 'PASS %-6s (ok)\n' "$1"
|
|
59
59
|
fi
|
|
60
60
|
}
|
|
61
|
-
|
|
61
|
+
# FAIL keeps its row line whole in every mode, and the matrix's remedy column rides under it.
|
|
62
|
+
# The remedy is the TSV's own cell (IN-01/IN-02/GT-03/CM-01 carry prose there; the pre-remedy
|
|
63
|
+
# rows carry `—`, which prints nothing) — the JG-02 judge-lane `remedy:` line, brought to every
|
|
64
|
+
# row that names one, so the fix a failure needs is printed where the failure is read. A missing
|
|
65
|
+
# column (a manifest written before the column existed) is no remedy, not an error: empty is the
|
|
66
|
+
# same as `—`.
|
|
67
|
+
g_fail() {
|
|
68
|
+
printf 'FAIL %-6s %s\n' "$1" "$2"
|
|
69
|
+
local rem
|
|
70
|
+
rem=$(g_remedy "$1")
|
|
71
|
+
case "$rem" in
|
|
72
|
+
—*) return 0 ;; # an em-dash cell: history and blindness, never a remedy
|
|
73
|
+
esac
|
|
74
|
+
# Whole in verbose/--only mode (the mode that reads, not scans), width-folded otherwise —
|
|
75
|
+
# the same contract the row printers keep.
|
|
76
|
+
if [ "${GOB_VERIFY_VERBOSE:-0}" -eq 1 ]; then
|
|
77
|
+
[ -n "$rem" ] && printf 'remedy: %s\n' "$rem"
|
|
78
|
+
else
|
|
79
|
+
[ -n "$rem" ] && printf 'remedy: %s\n' "$(g_trunc "${GOB_REPORT_COLS:-100}" "$rem")"
|
|
80
|
+
fi
|
|
81
|
+
}
|
|
82
|
+
g_remedy() {
|
|
83
|
+
[ -f "${_GOB_MANIFEST:-}" ] || return 0
|
|
84
|
+
awk -F'\t' -v id="$1" 'NR>1 && $1==id { r = $7; if (r != "") print r; exit }' "${_GOB_MANIFEST:-}"
|
|
85
|
+
}
|
|
62
86
|
g_adv() {
|
|
63
87
|
# Multi-line ADV payloads print whole: tests pin phrases on the SECOND line of a lane
|
|
64
88
|
# advisory (the W5-6 family statement), and the fold must not eat them. Single-line
|
package/bin/goblin-verify
CHANGED
|
@@ -268,7 +268,17 @@ if [ -n "$ONLY" ]; then
|
|
|
268
268
|
fi
|
|
269
269
|
|
|
270
270
|
if [ ! -f "$CONFIG" ]; then
|
|
271
|
-
|
|
271
|
+
# Not installed. When PWD is not the target's own project root, the FIRST suggestion is to
|
|
272
|
+
# go to the repo you meant, and the install command is named second WITH its target spelled
|
|
273
|
+
# out — an out-of-context `goblin-install --target $PWD` is how a scratch directory gets
|
|
274
|
+
# initialized by accident (review 2 §1.6). Exit stays 2.
|
|
275
|
+
if [ "$ROOT" != "$PWD" ]; then
|
|
276
|
+
g_err "not installed: $CONFIG is absent — and $PWD is not the installed repo ($ROOT)."
|
|
277
|
+
g_err "fix: cd to your project repo, then re-run gob verify."
|
|
278
|
+
g_err " (installing here would initialize $PWD: goblin-install --target $PWD --class <software|service|game|research|fleet>)"
|
|
279
|
+
else
|
|
280
|
+
g_err "not installed: $CONFIG is absent. Run: goblin-install --target $ROOT --class <software|service|game|research|fleet>"
|
|
281
|
+
fi
|
|
272
282
|
exit 2
|
|
273
283
|
fi
|
|
274
284
|
|
|
@@ -367,9 +377,12 @@ fi
|
|
|
367
377
|
# The default listing is one line per row: PASS payloads collapse to (ok) and long ADV
|
|
368
378
|
# sentences fold to the report width; --verbose (or --only) prints every payload
|
|
369
379
|
# full-width. The lib's row printers read these.
|
|
380
|
+
# The report width and the manifest path the row printers read (the remedy lookup is
|
|
381
|
+
# manifest-driven: the tsv is the source of truth, the engine only renders it).
|
|
370
382
|
export GOB_VERIFY_VERBOSE="$VERBOSE"
|
|
371
383
|
export GOB_REPORT_COLS="${COLUMNS:-100}"
|
|
372
384
|
[ "$GOB_REPORT_COLS" -ge 40 ] 2>/dev/null || GOB_REPORT_COLS=100
|
|
385
|
+
export _GOB_MANIFEST="$MANIFEST"
|
|
373
386
|
export GOBLIN_ROOT="$ROOT"
|
|
374
387
|
export GOBLIN_CONFIG="$CONFIG"
|
|
375
388
|
|
|
@@ -467,7 +480,10 @@ check_in_01() {
|
|
|
467
480
|
fi
|
|
468
481
|
[ -s "$INSTALLED" ] && grep -q '"version"' "$INSTALLED" \
|
|
469
482
|
&& { printf 'the install record exists and names its version\n'; return 0; }
|
|
483
|
+
# IN-01 recovery line (review 1, scope 4): the record is corrupt or missing; name the two
|
|
484
|
+
# restores. The matrix's remedy: line rides under the payload via g_fail.
|
|
470
485
|
printf 'installed.json is absent or records no version\n'
|
|
486
|
+
printf 'recover: gob install --upgrade, or git checkout -- .goblin/installed.json\n'
|
|
471
487
|
return 1
|
|
472
488
|
}
|
|
473
489
|
|
|
@@ -543,6 +559,7 @@ check_in_02() {
|
|
|
543
559
|
# The engine hash itself is printed in the footer on every run (see the footer, below);
|
|
544
560
|
# this row proves the REPO-LOCAL bytes, and a global engine answers elsewhere.
|
|
545
561
|
local p h cur n=0 bad=0 pin="" detail=""
|
|
562
|
+
local DRIFTED=""
|
|
546
563
|
while IFS=$'\t' read -r p h; do
|
|
547
564
|
[ -n "$p" ] || continue
|
|
548
565
|
if [ "$ENGINE_MODE" = "global" ]; then
|
|
@@ -568,6 +585,7 @@ check_in_02() {
|
|
|
568
585
|
cur=$(g_sha256_file "$ROOT/$p")
|
|
569
586
|
if [ "$cur" != "$h" ]; then
|
|
570
587
|
printf 'drift: %s recorded %s now %s\n' "$p" "$h" "$cur"
|
|
588
|
+
DRIFTED="$p"
|
|
571
589
|
bad=1
|
|
572
590
|
fi
|
|
573
591
|
done < <(g_installed_files_strict "$INSTALLED")
|
|
@@ -603,6 +621,12 @@ check_in_02() {
|
|
|
603
621
|
return
|
|
604
622
|
fi
|
|
605
623
|
printf '%d installed files hashed%s\n' "$n" "$pin"
|
|
624
|
+
# IN-02 recovery line (review 1, scope 4): a drift FAIL carries the exact restore commands,
|
|
625
|
+
# naming the drifted file the payload above reported. Sits between the row's own lines and
|
|
626
|
+
# the summary; g_fail appends the matrix's remedy: line under the whole payload.
|
|
627
|
+
if [ "$bad" -ne 0 ] && [ -n "$DRIFTED" ]; then
|
|
628
|
+
printf 'recover: git checkout -- %s, or gob install --upgrade\n' "$DRIFTED"
|
|
629
|
+
fi
|
|
606
630
|
[ "$bad" -eq 0 ]
|
|
607
631
|
}
|
|
608
632
|
|
|
@@ -716,14 +740,41 @@ check_gt_01() {
|
|
|
716
740
|
}
|
|
717
741
|
|
|
718
742
|
# run the declared gates; optionally write the one-line measured numbers
|
|
743
|
+
# GT-02 stderr (review 2, scope 2): a gate that fails with nothing on screen (`cmd: false`,
|
|
744
|
+
# exit 127) fails in silence. The LAST ~20 lines of the failing gate's combined output are
|
|
745
|
+
# kept in GT02_TAIL, and the row's FAIL payload carries them indented under the FAIL line,
|
|
746
|
+
# attributed to the gate that produced them. The counts line and every other row's payload
|
|
747
|
+
# are untouched (byte-stable where no gate fails).
|
|
748
|
+
GT02_TAIL=""
|
|
719
749
|
run_gates() {
|
|
720
|
-
local write_line="$1" name cmd rc bad=0 line=""
|
|
750
|
+
local write_line="$1" name cmd rc bad=0 line="" out
|
|
751
|
+
GT02_TAIL=""
|
|
721
752
|
while IFS=$'\t' read -r name cmd; do
|
|
722
753
|
[ -n "$name" ] || continue
|
|
723
|
-
( cd "$ROOT" && bash -c "$cmd"
|
|
754
|
+
out=$( cd "$ROOT" && bash -c "$cmd" 2>&1 )
|
|
724
755
|
rc=$?
|
|
725
756
|
line="$line $name=$rc"
|
|
726
|
-
[ "$rc" -
|
|
757
|
+
if [ "$rc" -ne 0 ]; then
|
|
758
|
+
printf 'gate %s: %s -> exit %d\n' "$name" "$cmd" "$rc"
|
|
759
|
+
bad=1
|
|
760
|
+
local tail_lines
|
|
761
|
+
tail_lines=$(printf '%s\n' "$out" | grep -v '^[[:space:]]*$' | tail -n 20)
|
|
762
|
+
if [ -n "$tail_lines" ]; then
|
|
763
|
+
if [ -n "$GT02_TAIL" ]; then GT02_TAIL="$GT02_TAIL
|
|
764
|
+
"; fi
|
|
765
|
+
GT02_TAIL="${GT02_TAIL}gate ${name} output (last 20 lines):"
|
|
766
|
+
while IFS= read -r tl; do
|
|
767
|
+
GT02_TAIL="$GT02_TAIL
|
|
768
|
+
$tl"
|
|
769
|
+
done <<EOF_TAIL
|
|
770
|
+
$tail_lines
|
|
771
|
+
EOF_TAIL
|
|
772
|
+
else
|
|
773
|
+
[ -n "$GT02_TAIL" ] && GT02_TAIL="$GT02_TAIL
|
|
774
|
+
"
|
|
775
|
+
GT02_TAIL="${GT02_TAIL}gate ${name} printed nothing on stdout or stderr before exit ${rc} (a silent failure - the command itself is the diagnostic)"
|
|
776
|
+
fi
|
|
777
|
+
fi
|
|
727
778
|
done < <(g_yaml_gates "$CONFIG")
|
|
728
779
|
if [ "$write_line" = "yes" ]; then
|
|
729
780
|
local rname rcmd rval
|
|
@@ -739,7 +790,12 @@ run_gates() {
|
|
|
739
790
|
return $bad
|
|
740
791
|
}
|
|
741
792
|
|
|
742
|
-
check_gt_02() {
|
|
793
|
+
check_gt_02() {
|
|
794
|
+
local _s=0
|
|
795
|
+
run_gates yes || _s=$?
|
|
796
|
+
if [ "$_s" -ne 0 ] && [ -n "$GT02_TAIL" ]; then printf '%s\n' "$GT02_TAIL"; fi
|
|
797
|
+
return "$_s"
|
|
798
|
+
}
|
|
743
799
|
|
|
744
800
|
check_gt_04() {
|
|
745
801
|
local n c ceil
|
|
@@ -2671,6 +2727,33 @@ rc_hdr_field() {
|
|
|
2671
2727
|
'
|
|
2672
2728
|
}
|
|
2673
2729
|
|
|
2730
|
+
# ---- the day-one framing (review 1, scope 3) ----------------------------------
|
|
2731
|
+
# Two shapes are undeserved reds for a person who just cloned a repo. They are DETECTED and
|
|
2732
|
+
# framed — the verdict's exit semantics, the counts and every row's payload are untouched:
|
|
2733
|
+
# (a) owner_email in goblin.yaml is not the current git identity -> the CM-01 red names
|
|
2734
|
+
# whose email the repo actually expects (the remedy column says where to point it);
|
|
2735
|
+
# (b) the repo looks freshly cloned (.goblin committed, but fewer than 3 commits) -> one
|
|
2736
|
+
# banner line after the verdict. Commit count only: an mtime comparison against the
|
|
2737
|
+
# reflog fired after every ordinary GT-02 write, so the banner lingered on aged repos
|
|
2738
|
+
# (the verify itself refreshes last-gate-line forever); a repo under 3 commits is the
|
|
2739
|
+
# only unambiguous fresh-clone shape.
|
|
2740
|
+
owner_mismatch() {
|
|
2741
|
+
[ -f "$CONFIG" ] || return 1
|
|
2742
|
+
local declared cur
|
|
2743
|
+
declared=$(grep '^owner_email:' "$CONFIG" | head -n 1 | sed 's/^owner_email:[[:space:]]*//' | tr -d '"')
|
|
2744
|
+
cur=$(cd "$ROOT" && git config user.email 2>/dev/null)
|
|
2745
|
+
[ -n "$declared" ] && [ -n "$cur" ] && [ "$declared" != "$cur" ]
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
fresh_clone() {
|
|
2749
|
+
[ -f "$INSTALLED" ] || return 1
|
|
2750
|
+
[ -d "$ROOT/.git" ] || return 1
|
|
2751
|
+
local n
|
|
2752
|
+
n=$(cd "$ROOT" && git rev-list --count HEAD 2>/dev/null) || return 1
|
|
2753
|
+
[ "$n" -lt 3 ] && return 0
|
|
2754
|
+
return 1
|
|
2755
|
+
}
|
|
2756
|
+
|
|
2674
2757
|
# ================================================================ runner ======
|
|
2675
2758
|
|
|
2676
2759
|
PASS=0; FAIL=0; ADV=0; SKIP=0; BAD=0
|
|
@@ -2752,7 +2835,14 @@ while IFS=$'\t' read -r id scope rule enforced_by artifact check why; do
|
|
|
2752
2835
|
if [ "$rc" -eq 0 ]; then
|
|
2753
2836
|
[ -n "$detail" ] || detail="($check)"
|
|
2754
2837
|
else
|
|
2755
|
-
|
|
2838
|
+
# GT-03's one-liner is self-explaining now (review 1, scope 5): the raw `test -f
|
|
2839
|
+
# ... -nt ...` invocation dump told the reader the mechanics and nothing about what
|
|
2840
|
+
# to do; the human line says both. The TSV remedy column carries the same sentence.
|
|
2841
|
+
if [ "$id" = "GT-03" ]; then
|
|
2842
|
+
detail="GT-03 the gate line is older than the last commit — re-run gob verify to refresh it (it rewrites .goblin/last-gate-line)"
|
|
2843
|
+
else
|
|
2844
|
+
detail="($check -> exit $rc)"
|
|
2845
|
+
fi
|
|
2756
2846
|
rc=1
|
|
2757
2847
|
fi
|
|
2758
2848
|
;;
|
|
@@ -2772,6 +2862,18 @@ if [ "$JSON" -eq 1 ]; then
|
|
|
2772
2862
|
"$(json_escape "$ROOT")" "$(json_escape "$CLASS")" "$PASS" "$FAIL" "$ADV" "$SKIP" "${JSON_ROWS%,}"
|
|
2773
2863
|
else
|
|
2774
2864
|
printf ' %d passed, %d failed, %d advisory, %d skipped\n' "$PASS" "$FAIL" "$ADV" "$SKIP"
|
|
2865
|
+
# Day-one framing, part (a) (review 1, scope 3): the owner mismatch names whose email the
|
|
2866
|
+
# repo expects, under the verdict, before the row detail. One line, no exit semantics.
|
|
2867
|
+
if [ "$FAIL" -gt 0 ] && owner_mismatch; then
|
|
2868
|
+
_owner_declared=$(grep '^owner_email:' "$CONFIG" | head -n 1 | sed 's/^owner_email:[[:space:]]*//' | tr -d '"')
|
|
2869
|
+
printf ' note: this repo records a different owner (you are probably new here) — commit with --author or update owner_email: %s\n' "$_owner_declared"
|
|
2870
|
+
unset _owner_declared
|
|
2871
|
+
fi
|
|
2872
|
+
# Day-one framing, part (b): a fresh clone is not your debt. One banner line, after the
|
|
2873
|
+
# verdict; counts and exit codes untouched.
|
|
2874
|
+
if [ "$FAIL" -gt 0 ] && fresh_clone; then
|
|
2875
|
+
printf ' fresh clone detected: some of these fails are not yours — see docs/GUIDE.md §9 (day one for a new teammate)\n'
|
|
2876
|
+
fi
|
|
2775
2877
|
# Z1-7: the advisory number above counts TWO different things - the rows the matrix LABELS
|
|
2776
2878
|
# advisory, and a row that is not advisory-labelled but whose lane cannot be resolved here
|
|
2777
2879
|
# (JG-02's unresolved judge lane returns 2 = ADV by design). SK-03 counts the first, the ADV
|
package/docs/ENFORCEMENT.md
CHANGED
|
@@ -31,7 +31,7 @@ Measured shape of this table: **87 rows** - 82 target, 5 source; advisory 10, ga
|
|
|
31
31
|
| id | scope | enforced by | rule | check | if it cannot be enforced, why |
|
|
32
32
|
|---|---|---|---|---|---|
|
|
33
33
|
| `IN-01` | target | script | The install exists and records its version + every file's hash. | goblin-verify --only IN-01 | — (W1: the check is a builtin so the engine.mode=global clause can run — a global, declaration-only repo has no install record and SKIPs with `global engine mode — no per-repo install record`; the vendored clauses are the old one-liner: the record exists and names its version) |
|
|
34
|
-
| `IN-02` | target | script | Every installed file still matches its recorded hash. | `goblin-verify --only IN-02` (builtin) |
|
|
34
|
+
| `IN-02` | target | script | Every installed file still matches its recorded hash. | `goblin-verify --only IN-02` (builtin) | recover: `gob install --upgrade`, or `git checkout -- .goblin/installed.json`; for a file it names drifted: `git checkout -- <path>` (if the edit is yours and intended, re-pin it: `gob install --target <dir> --re-pin`) |
|
|
35
35
|
| `IN-03` | target | script | The verifier's own manifest is complete: every rule has a check or is advisory. | `goblin-verify --only IN-03` (builtin) | — (this row is the reason the matrix cannot rot; the second clause is D6's shape in general: a row that carries no check must be labelled advisory, or it claims verification it does not perform. The third clause is Z1-5: `enforced_by` is documented as a closed enum in docs/ENFORCEMENT.md and was read by NOTHING, so a typo in that cell changed nothing - `script\|lint\|gate\|advisory` plus `test`, the source-scope value whose check is tests/run-tests.sh. W1: the check runs against whichever manifest the engine actually resolved (the chain in `bin/goblin-verify`), no longer the hardcoded per-repo path — the rule's meaning is untouched, only the path input follows the engine) |
|
|
36
36
|
| `IN-04` | target | script | No file goblin-stack did not create has been overwritten. | `goblin-verify --only IN-04` (builtin) | Detects a file the installer recorded as pre-existing (a `refused` entry) that has since vanished, or that is listed as installed anyway. The second clause is an internal-consistency guard: with correct code a refused path is never written, so it fires only if the installer regresses. The negative control exercises the vanished branch. |
|
|
37
37
|
| `HP-01` | target | gate | HANDOFF.md exists at the root. | `test -f HANDOFF.md` | — |
|
|
@@ -50,7 +50,7 @@ Measured shape of this table: **87 rows** - 82 target, 5 source; advisory 10, ga
|
|
|
50
50
|
| `HS-01` | target | lint | Asserting harnesses follow the house shape. | `goblin-verify --only HS-01` (builtin) | A declared harness_dir that is absent FAILS when the class scaffolds one (config `scaffold_checks: yes`, classes A and C); a class that ships no harness dir (B/D/E) SKIPs with a reason. Keying the skip off the path alone let one config line switch this row and HS-02 off. A report utility in the same dir is counted and reported separately rather than failing the run. |
|
|
51
51
|
| `HS-02` | target | gate | A check green on both trees proves nothing - the REPLAY must show RED pre-change. | `goblin-verify --only HS-02` (builtin) | The declared `replay.cmd` is EXECUTED with `{name}` replaced by each harness's name, in the pre-change worktree, with `replay.env=<commit>` set (Z1-4). Two clauses that used to be unheard: a command that interpolates no `{name}` FAILs (it cannot be running the harness it names, so nothing was replayed), and a command that cannot be executed at all - exit 126 or 127 - FAILs rather than counting as a RED harness. The harness's name is substituted SHELL-QUOTED (`printf %q`), because the name is part of the command text the shell parses; unquoted, a name carrying `;` or `#` reached the shell as syntax (Z2-3, the G8-1 surface class), and the control for it carries a metacharacter-bearing file name. What it cannot see: a command that runs *something else* under the harness's name and exits non-zero, and whether the harness tests the right path rather than merely failing on this tree. |
|
|
52
52
|
| `HS-03` | target | advisory | Source probes read text with comments blanked first. | `advisory` | Recognising 'this probe reads source text' is semantic; a grep for the blanking helper produces false FAILs on harnesses that do not probe source. |
|
|
53
|
-
| `CM-01` | target | gate | Commits carry the owner identity, not an ambient one. Current scope: this gates the identity of HEAD (the last commit) at the moment of the run - earlier commits by other authors are not scanned. | `test "$(git log -1 --format='%ae')" = "$(grep '^owner_email:' .goblin/goblin.yaml \| cut -d' ' -f2)"` | — |
|
|
53
|
+
| `CM-01` | target | gate | Commits carry the owner identity, not an ambient one. Current scope: this gates the identity of HEAD (the last commit) at the moment of the run - earlier commits by other authors are not scanned. | `test "$(git log -1 --format='%ae')"` = `"$(grep '^owner_email:' .goblin/goblin.yaml \| cut -d' ' -f2)"` | note: this repo records a different owner (you are probably new here) — commit with `git -c user.email=<owner_email> --author=<owner_email>`, or update `owner_email:` in `.goblin/goblin.yaml` |
|
|
54
54
|
| `CM-02` | target | advisory | The commit message was written to a file, not passed with -m. | `advisory` | A backtick lost to command substitution leaves no trace a later check can read. Reported as a heuristic (unbalanced backticks in a body) only. |
|
|
55
55
|
| `CM-03` | target | script | Commit-as-you-go: the working tree is not carrying a dead run's work. | `goblin-verify --only CM-03` (builtin) | — |
|
|
56
56
|
| `MD-01` | target | lint | No model name is hardcoded in any reusable rule. | `for d in skills manifest bin templates presets .goblin .hermes; do [ -d "$d" ] \|\| continue; grep -rniE '(d[e]epseek\|cl[a]ude\|g[p]t-[0-9]\|gr[o]k\|g[e]mini\|g[l]m-[0-9]\|k[i]mi)[a-z0-9.:_-]*' "$d" && exit 1; done; exit 0` | — (the pattern is written with character classes so this row cannot match itself; tests/t-verify-red.sh proves it still catches a real model name. SCOPE, stated so a repo-wide grep is not re-reported as a hole (G8-10): this row reads the seven directories an install writes rules into - skills/ manifest/ bin/ templates/ presets/ .goblin/ .hermes/. It does NOT read tests/, docs/, or the source automations/ directory; tests/ is where a control must be free to WRITE the thing it guards, and the source directories are covered by MD-01's own body in tests/run-tests.sh, which scans skills manifest bin templates presets automations. Both control strings are assembled at run time, so a repo-wide grep over the whole tree is 0 and the row's own scope is 0 by construction.) |
|
package/docs/GLOSSARY.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Glossary
|
|
2
|
+
|
|
3
|
+
Every term of art in one table, rendered from `manifest/glossary.tsv` — that file is the source;
|
|
4
|
+
edit it there and re-render (or hand-render: one row per term, alphabetical, the definition one
|
|
5
|
+
sentence). A term a new reader might trip on belongs here, not in a footnote.
|
|
6
|
+
|
|
7
|
+
| term | definition | source |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| advisory | A rule with no executable check. Counted in the verify summary and capped by advisory_ceiling; never a silent pass. | R6 sec.5 |
|
|
10
|
+
| archive | A class-D flag: verify requires no HANDOFF and no gates, and the summary says so. | R7 sec.2.4 |
|
|
11
|
+
| class | A project category A-E that selects which parts are required, optional or off. See manifest/classes.tsv. | R7 sec.4 |
|
|
12
|
+
| drift | A file whose current bytes no longer match the hash recorded at install time. IN-02 reports it; the remedy column says how to recover. | UX-review-2026-10-06 |
|
|
13
|
+
| engine | The bash programs plus the manifest a verify run actually resolved: per-repo (.goblin/bin) or global (engine_dir:). Named in every run's footer. | UX-review-2026-10-06 |
|
|
14
|
+
| forge | The hosting platform a repo pushes to (GitHub, GitLab, ...). PG-05 and PG-06 read the workflow text but can never see what the forge itself enforces. | UX-review-2026-10-06 |
|
|
15
|
+
| foreman | The orchestrating agent that delegates work to the fleet; the role that reads HANDOFF.md first and writes it last. | UX-review-2026-10-06 |
|
|
16
|
+
| gate | A declared command that must exit 0. Declared per project, never inferred from the stack. | PP sec.4 |
|
|
17
|
+
| HANDOFF | The session-boundary contract at the repo root: START HERE / State / Gates / Next steps / NOT verified. | PP sec.1 |
|
|
18
|
+
| harness | An asserting check file: a failures counter, an assert(name, ok, detail) printer, and a non-zero exit on failure. | PP sec.3 |
|
|
19
|
+
| judge | A role that decides whether a PROCESS met its own predicate, from a command's output and a pointer it can resolve - never from a report. One lane per verdict; never the author's lane. | docs/LOOP.md |
|
|
20
|
+
| lane | A family of rules that share a mechanism and a blind spot: the ban lane, the judge/loop lane, the CI lane, the reference lane. The cannot-see footer reports per lane. | UX-review-2026-10-06 |
|
|
21
|
+
| loop | One unattended run over a predicate, recorded in the committed .goblin/loop/ (predicate, pin, first-run, budget, one decisions.tsv row per iteration). | docs/LOOP.md |
|
|
22
|
+
| never-relax | The predicate's digest is recorded at loop start and never updates itself; relaxing it is closing this loop and opening another, with the old predicate archived under .goblin/loop/closed-<date>/. | docs/LOOP.md |
|
|
23
|
+
| opt-out | A part recorded in disabled: so its required checks report SKIP (opt-out) instead of failing. | R6 sec.6.3 |
|
|
24
|
+
| overnight | P10: an unattended run over a checkable predicate written before iteration 1. | R6 sec.3 |
|
|
25
|
+
| part | One installable unit a class requires or forbids: handoff, spec, gate, replay, ratchet, pr-gate, review-panel, playbooks, tokens. | R7 sec.5 |
|
|
26
|
+
| patch-id | git patch-id --stable of base..head. A new head voids a verdict; a matching commit message does not restore it. | R1 sec.10 |
|
|
27
|
+
| playbook | A named, ordered procedure with a measurable verification step. goblin-stack ships 15. | R6 sec.3 |
|
|
28
|
+
| predicate | One shell command that exits 0 when the loop is finished. Written before iteration 1 and run once before it, so its first state is known to be red. A duration is not a predicate. | docs/LOOP.md + pstack guide/07 |
|
|
29
|
+
| preimage | The input that produces a known hash. The hash checks here prove non-drift, not preimage resistance - they are tamper-evidence, not signatures (docs/LIMITS.md #18). | UX-review-2026-10-06 |
|
|
30
|
+
| profile | A worker identity in the Hermes fleet (architect, coder, reviewer, ...). Owns memory and skills. | R4 |
|
|
31
|
+
| review-panel | N independent verdict lanes, each its own card with its own resolved model. Only at stakes S3+. | R6 sec.4.3 |
|
|
32
|
+
| REPLAY | Re-running each assertion against the pinned pre-change commit and requiring it to be RED there. A check green on both trees proves nothing. | PP sec.3 |
|
|
33
|
+
| ratchet | A count that must not rise, with a declared ceiling; a rise is allowed only when re-anchored with the arithmetic (old + N new = new). | PP sec.4 |
|
|
34
|
+
| role | What the work needs: code \| judgment \| review-panel \| synthesis \| investigate \| judge. A role maps to a profile; it never names a model. | R6 sec.4.1 |
|
|
35
|
+
| round | One full pass of the work cycle: plan, implement, gate, replay, hand off. The unit a wave code counts. | UX-review-2026-10-06 |
|
|
36
|
+
| skill | A Hermes SKILL.md directory. goblin-stack installs its skills into the target repo at .hermes/skills/ (project tier), never into a profile. | R6 sec.0.1 / sec.7.3 |
|
|
37
|
+
| SPEC | A per-round document written before implementation: measured root cause plus an AC: list checkable without a human. | PP sec.2 |
|
|
38
|
+
| stakes | The S0-S4 ladder that chooses the review gate strength by the change, not by the repo. | R5 sec.3.2 |
|
|
39
|
+
| sweep | P11: the same change or question across many projects, enumerated by glob, one card each. | R6 sec.3 |
|
|
40
|
+
| vendored | Copied into the repo rather than read from the package, so it survives offline and is hashed by IN-02 like any installed file. | UX-review-2026-10-06 |
|
package/docs/GUIDE.md
CHANGED
|
@@ -58,6 +58,10 @@ Everything else in gobstack follows from that sentence. If you remember one thin
|
|
|
58
58
|
guide, remember that one — it is also the standard the harness holds itself to, and the reason it
|
|
59
59
|
ships a file of things it *cannot* check (`docs/LIMITS.md`).
|
|
60
60
|
|
|
61
|
+
**Words this guide uses** — gate, ratchet, class, part, replay and the rest are defined in one
|
|
62
|
+
sentence each in `docs/GLOSSARY.md` (rendered from the glossary table the install ships:
|
|
63
|
+
`.goblin/manifest/glossary.tsv`).
|
|
64
|
+
|
|
61
65
|
---
|
|
62
66
|
|
|
63
67
|
## 2. Before you begin
|
|
@@ -78,8 +82,9 @@ You need node ≥ 18 (for the npm shim only), beyond the row above.
|
|
|
78
82
|
|
|
79
83
|
npm i -g @techgoblin/gobstack
|
|
80
84
|
|
|
81
|
-
This puts
|
|
82
|
-
|
|
85
|
+
This puts **two** commands on your PATH — `gob` and `goblin`, both the same node shim over the
|
|
86
|
+
bash engine. The docs say `gob` throughout; `goblin` remains as a legacy alias for existing
|
|
87
|
+
scripts.
|
|
83
88
|
|
|
84
89
|
---
|
|
85
90
|
|
|
@@ -113,7 +118,8 @@ or the plain installer this wizard drives, if you prefer the one-shot shape:
|
|
|
113
118
|
|
|
114
119
|
Expected output (this is a real transcript, trimmed):
|
|
115
120
|
|
|
116
|
-
created
|
|
121
|
+
created 24 · updated 0 · unchanged 0 · skipped 0
|
|
122
|
+
recorded opt-out: ci-gate
|
|
117
123
|
|
|
118
124
|
next:
|
|
119
125
|
1. cd /tmp/gs-try && git add -A && git commit # the install is a change like any other
|
|
@@ -121,12 +127,13 @@ Expected output (this is a real transcript, trimmed):
|
|
|
121
127
|
3. edit .goblin/goblin.yaml: replace the default gate with your real commands (P8 step 3)
|
|
122
128
|
4. agent skills are opt-in: gob sync --platform <p> # hermes, claude, copilot, cursor, opencode, codex, gemini
|
|
123
129
|
|
|
124
|
-
**`created
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
+
**`created 24`** is the installer's count of the files it **tracks** — one fewer than the plain
|
|
131
|
+
installer's 25, because the wizard's unanswered ci screen defaults to an explicit **no**, which is
|
|
132
|
+
recorded as an opt-out and suppresses `.github/workflows/goblin-gate.yml`. It writes **25**: the
|
|
133
|
+
25th is `.goblin/installed.json`, the record it keeps for itself, which it writes but does not
|
|
134
|
+
count. It has written nothing outside this directory. The default install ships **no agent
|
|
135
|
+
skills** — the harness is neutral, and `gob sync --platform <p>` is the per-platform opt-in
|
|
136
|
+
(`gob emit` is the same command under its original name; the old `--skills yes` default is
|
|
130
137
|
still there for repos that want the Hermes project tier vendored).
|
|
131
138
|
|
|
132
139
|
### Why `git init -b main` matters
|
|
@@ -150,15 +157,16 @@ branch** (unless you want to).
|
|
|
150
157
|
|
|
151
158
|
You will see one line per rule. The shape:
|
|
152
159
|
|
|
153
|
-
PASS IN-01
|
|
154
|
-
PASS IN-02
|
|
160
|
+
PASS IN-01 the install record exists and names its version
|
|
161
|
+
PASS IN-02 15 installed files hashed
|
|
155
162
|
FAIL HP-05 HANDOFF.md names no commit that exists in this repo
|
|
163
|
+
FAIL GT-02 gate commit: bash tests/run-tests.sh -> exit 127
|
|
156
164
|
SKIP HS-02 no pinned pre-change commit yet - the REPLAY is not provable
|
|
157
165
|
ADV HP-04 A stale sentence is corrected in place... (advisory)
|
|
158
166
|
|
|
159
167
|
and a summary line at the bottom:
|
|
160
168
|
|
|
161
|
-
|
|
169
|
+
35 passed, 2 failed, 11 advisory, 34 skipped # HP-05 and GT-02, below
|
|
162
170
|
|
|
163
171
|
### How to read that output
|
|
164
172
|
|
|
@@ -178,6 +186,25 @@ one. The list of what is still skipping *is* your onboarding checklist.
|
|
|
178
186
|
telling you the HANDOFF does not yet name a commit — fix it by naming your HEAD in the `State`
|
|
179
187
|
section.
|
|
180
188
|
|
|
189
|
+
### The day-one table, measured on this exact walk
|
|
190
|
+
|
|
191
|
+
| Step | Command | Verify prints | The FAILs |
|
|
192
|
+
|---|---|---|---|
|
|
193
|
+
| 1. the wizard ran | `gob init ... --yes` | `31 passed, 6 failed, 11 advisory, 34 skipped` | the install is uncommitted (`CM-03`), `HP-05`, `GT-02` exit 127, and the identity/branch rows if you skipped the flags |
|
|
194
|
+
| 2. the first commit | `git add -A && git commit` | `35 passed, 2 failed, 11 advisory, 34 skipped` | `HP-05` (the placeholder) and `GT-02` |
|
|
195
|
+
| 3. name a real HEAD — and **commit that too** | edit `HANDOFF.md`, then `git add -A && git commit` | `36 passed, 1 failed, 11 advisory, 34 skipped` | `GT-02` only |
|
|
196
|
+
| 4. your real gate | edit `gates:` in `.goblin/goblin.yaml` (§5) | `36 passed, 0 failed, ...` | none — green |
|
|
197
|
+
|
|
198
|
+
Two of those deserve their name spelled out:
|
|
199
|
+
|
|
200
|
+
- **`GT-02` exit 127 is the guide's own teaching point, not a defect.** The default gate is
|
|
201
|
+
`bash tests/run-tests.sh`, and a throwaway repo has no `tests/` — the shell's own
|
|
202
|
+
*command not found*. It stays red until §5's most valuable edit (your real `gates:`) replaces
|
|
203
|
+
it. The failure line tells you this: `gate commit: bash tests/run-tests.sh -> exit 127`.
|
|
204
|
+
- **Step 3 is two steps on purpose.** Naming a real HEAD in `HANDOFF.md` without committing it
|
|
205
|
+
re-reds `CM-03` (`1 dirty entr(y|ies)`) — commit-as-you-go starts on minute one. Edit, commit,
|
|
206
|
+
then verify.
|
|
207
|
+
|
|
181
208
|
### The three-day-one failures, and why they are not a broken harness
|
|
182
209
|
|
|
183
210
|
If you ran step 1 without `-b main`, or with the wrong git identity, you will see:
|
|
@@ -194,8 +221,9 @@ against a declared expectation. That is exactly what you want it to do.
|
|
|
194
221
|
`HP-05` deserves one sentence more, because it surprises people: the scaffold ships
|
|
195
222
|
`HEAD when this file was written: `0000000``, and `HP-05` **rejects that placeholder on purpose**.
|
|
196
223
|
A file that names a commit which does not exist is worse than one that names none — it looks like a
|
|
197
|
-
record. Commit first, then write the real short SHA in. Measured: with the placeholder
|
|
198
|
-
verify reports `
|
|
224
|
+
record. Commit first, then write the real short SHA in. Measured on this walk: with the placeholder
|
|
225
|
+
left in, verify reports `35 passed, 2 failed`; with the real SHA (and the edit committed),
|
|
226
|
+
`36 passed, 1 failed` — the one FAIL being the `GT-02` exit 127 above.
|
|
199
227
|
|
|
200
228
|
---
|
|
201
229
|
|
|
@@ -402,16 +430,20 @@ the next session.
|
|
|
402
430
|
|
|
403
431
|
## 9. What to expect on day one (so you do not misread it)
|
|
404
432
|
|
|
405
|
-
A software-class install lands on a specific shape.
|
|
406
|
-
`0000000` placeholder in `HANDOFF.md` (§4)
|
|
433
|
+
A software-class install through the wizard lands on a specific shape. Two of the first reds are
|
|
434
|
+
the scaffold teaching on purpose — `HP-05`, the `0000000` placeholder in `HANDOFF.md` (§4), and
|
|
435
|
+
`GT-02`, the default gate pointing at a test script a throwaway repo does not have. The walk in §4
|
|
436
|
+
measured, step by step:
|
|
407
437
|
|
|
408
|
-
|
|
438
|
+
31 passed, 6 failed, 11 advisory, 34 skipped # straight after the wizard, nothing committed
|
|
439
|
+
35 passed, 2 failed, 11 advisory, 34 skipped # first commit: HP-05 and GT-02 left
|
|
440
|
+
36 passed, 1 failed, 11 advisory, 34 skipped # real HEAD named and committed: GT-02 left
|
|
409
441
|
|
|
410
|
-
Name a real commit in `HANDOFF.md
|
|
442
|
+
Name a real commit in `HANDOFF.md`, commit, and give `gates:` real commands (§5), and it is green:
|
|
411
443
|
|
|
412
|
-
|
|
444
|
+
36 passed, 0 failed, 11 advisory, 34 skipped (on a real project; your numbers will differ)
|
|
413
445
|
|
|
414
|
-
**Thirty-
|
|
446
|
+
**Thirty-four rows skipping is correct**, and each skip prints its reason. In plain terms: the
|
|
415
447
|
harness is telling you which of its rules have nothing to read yet. It is a checklist, not a
|
|
416
448
|
scolding.
|
|
417
449
|
|
|
@@ -440,13 +472,14 @@ Two readings that are easy to get wrong:
|
|
|
440
472
|
| `gob install: unknown subcommand` (exit 2) | you ran a bare `gob install` without the npm package installed | install the npm package first: `npm i -g @techgoblin/gobstack`, then `gob install` |
|
|
441
473
|
| `IN-03` fails, "manifest is broken" | a row has a broken check column | fix the row; this is a source defect, not yours |
|
|
442
474
|
| a `FAIL` you believe is wrong | the check may be weak, or your belief may be | run `--only <id>` and read the command it prints |
|
|
475
|
+
| a changelog or matrix note says `W6` or `Z1-4` | that is a revision wave code | `docs/RECORD-NOTES.md` is the legend, one line per code |
|
|
443
476
|
|
|
444
477
|
**The `HANDOFF.md` refusal is the most common one, and `--force` is never the answer.** `--force`
|
|
445
478
|
replaces your project's own record with a blank scaffold — the exact act the refusal exists to
|
|
446
479
|
prevent. Reconcile instead: keep your file, and add the five sections it is missing. The measured
|
|
447
480
|
cost of that edit, on a real 2450-line handoff, was **15 lines added, none removed**.
|
|
448
481
|
|
|
449
|
-
**One engine, many repos
|
|
482
|
+
**One engine, many repos:** the rule table does not have to live in every repo. A repo can
|
|
450
483
|
point at a shared engine with one line in `.goblin/goblin.yaml`:
|
|
451
484
|
|
|
452
485
|
engine_dir: ~/.goblin/engine # absolute or ~/-prefixed; absent = per-repo engine
|
|
@@ -458,7 +491,7 @@ every run's footer (`engine: mode=… cli_sha256=… enforcement_tsv_sha256=…`
|
|
|
458
491
|
available outside any repo through the npm CLI: `gob verify` / `gob bans` / `gob audit` /
|
|
459
492
|
`gob doctor` / `gob sync` / `gob upgrade` / `gob --version`.
|
|
460
493
|
|
|
461
|
-
**Migrating a repo to the global engine
|
|
494
|
+
**Migrating a repo to the global engine:**
|
|
462
495
|
|
|
463
496
|
gob upgrade # 8 steps, two commits, one report
|
|
464
497
|
|
|
@@ -532,6 +565,8 @@ Named procedures, installed as project-local skills. Each has a measurable verif
|
|
|
532
565
|
| File | Read it for |
|
|
533
566
|
|---|---|
|
|
534
567
|
| `docs/DESIGN.md` | the thesis and every rejected alternative |
|
|
568
|
+
| `docs/GLOSSARY.md` | every term of art in one table (rendered from `.goblin/manifest/glossary.tsv`) |
|
|
569
|
+
| `docs/RECORD-NOTES.md` | the wave codes the changelog uses, one line each |
|
|
535
570
|
| `docs/FLOWS.md` | the playbooks in full, with reasons |
|
|
536
571
|
| `docs/ENFORCEMENT.md` | the rule matrix, rendered for a human |
|
|
537
572
|
| `docs/LIMITS.md` | **what this cannot check** — read this one early |
|
package/docs/LIMITS.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# Limits — where this is weaker, and what is unproven
|
|
2
2
|
|
|
3
3
|
Honest accounting. Nothing here is a hedge for a defect that could be fixed; each is either a
|
|
4
|
-
deliberate trade or an unfilled gap.
|
|
4
|
+
deliberate trade or an unfilled gap. (This file keeps the revision wave codes — `W6`, `Z1`, and
|
|
5
|
+
the rest — in its dated parentheticals; `docs/RECORD-NOTES.md` is the legend.)
|
|
5
6
|
|
|
6
7
|
## Weaker than the Cursor harness it learns from
|
|
7
8
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Record notes — the wave codes
|
|
2
|
+
|
|
3
|
+
The CHANGELOG, the enforcement matrix's parentheticals, and the older commit messages name
|
|
4
|
+
revisions by a short wave code. This file is the legend: one line each, oldest last. The prose
|
|
5
|
+
documents (README, GUIDE) do not use the codes; when one of these revisions matters to a reader,
|
|
6
|
+
the docs name it by what it changed and point here.
|
|
7
|
+
|
|
8
|
+
| code | revision | in one line |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| W1 | engine mode | the rule table can live in a shared engine (`engine_dir:`), not only per-repo; declared-but-unusable is exit 2 with no fallback |
|
|
11
|
+
| W3 | `gob upgrade` | the 8-step migration of a repo to the global engine, two commits, refusal on every unsafe tree |
|
|
12
|
+
| W4 | class + ci-gate | the five domain classes replaced the A–E letters (read-time aliases kept), and `ci-gate` became a declared part with its own workflow |
|
|
13
|
+
| W5 | report width | the verify report learned columns: payloads fold at the report width, multi-line payloads print whole, `--verbose` prints everything |
|
|
14
|
+
| W6 | neutral-first | a default install ships no agent skills (`gob sync --platform <p>` is the opt-in), the desktop class merged into software, and the wizard got its health-check screen |
|
|
15
|
+
| G8 | audit finding 8 | the verify-UX audit's surface classes: refusals that print nothing, rows that pass vacuously, `--only` selections that run nothing |
|
|
16
|
+
| G8-2 | stdout discipline | the engine banner moved to stderr; stdout carries verdict lines and the run's own annotations only |
|
|
17
|
+
| X1 | exit-code audit | every refusal and every silent path got a distinct exit code and a stated reason (0 green, 1 red, 2 refusal/config, 3 skip-by-design) |
|
|
18
|
+
| AB3 | claims pinned | every count a document states about this artifact is asserted against a real install (file maps, row counts, summary lines) |
|
|
19
|
+
| Z1 | record integrity | the loop/judge record contract: pins, digests, the never-relax rule, and what a record proves versus what it cannot |
|
|
20
|
+
| V3 | day-one framing | the verify run explains its reds to a newcomer: remedy lines under FAILs, the owner-mismatch note, the fresh-clone banner, recovery lines |
|
|
21
|
+
| G9 | guide re-walk | docs/GUIDE.md re-walked on the wizard path with every number re-measured (see t-doc-guide-init.sh) |
|
package/manifest/enforcement.tsv
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
id scope rule enforced_by artifact check if_not_why
|
|
2
2
|
IN-01 target The install exists and records its version + every file's hash. script .goblin/installed.json goblin-verify --only IN-01 — (W1: the check is a builtin so the engine.mode=global clause can run — a global, declaration-only repo has no install record and SKIPs with `global engine mode — no per-repo install record`; the vendored clauses are the old one-liner: the record exists and names its version)
|
|
3
|
-
IN-02 target Every installed file still matches its recorded hash. script .goblin/installed.json goblin-verify --only IN-02
|
|
3
|
+
IN-02 target Every installed file still matches its recorded hash. script .goblin/installed.json goblin-verify --only IN-02 recover: gob install --upgrade, or git checkout -- .goblin/installed.json; for a file it names drifted: git checkout -- <path> (if the edit is yours and intended, re-pin it: gob install --target <dir> --re-pin)
|
|
4
4
|
IN-03 target The verifier's own manifest is complete: every rule has a check or is advisory. script manifest/enforcement.tsv goblin-verify --only IN-03 — (this row is the reason the matrix cannot rot; the second clause is D6's shape in general: a row that carries no check must be labelled advisory, or it claims verification it does not perform. The third clause is Z1-5: `enforced_by` is documented as a closed enum in docs/ENFORCEMENT.md and was read by NOTHING, so a typo in that cell changed nothing - `script|lint|gate|advisory` plus `test`, the source-scope value whose check is tests/run-tests.sh. W1: the check runs against whichever manifest the engine actually resolved (the chain in bin/goblin-verify), no longer the hardcoded per-repo path — the rule's meaning is untouched, only the path input follows the engine)
|
|
5
5
|
IN-04 target No file goblin-stack did not create has been overwritten. script .goblin/installed.json goblin-verify --only IN-04 Detects a file the installer recorded as pre-existing (a `refused` entry) that has since vanished, or that is listed as installed anyway. The second clause is an internal-consistency guard: with correct code a refused path is never written, so it fires only if the installer regresses. The negative control exercises the vanished branch.
|
|
6
6
|
HP-01 target HANDOFF.md exists at the root. gate HANDOFF.md test -f HANDOFF.md —
|
|
@@ -19,7 +19,7 @@ GT-05 target The ratchet has not risen. gate ratchet.cmd goblin-verify --only GT
|
|
|
19
19
|
HS-01 target Asserting harnesses follow the house shape. lint harness_dir/* goblin-verify --only HS-01 A declared harness_dir that is absent FAILS when the class scaffolds one (config `scaffold_checks: yes`, classes A and C); a class that ships no harness dir (B/D/E) SKIPs with a reason. Keying the skip off the path alone let one config line switch this row and HS-02 off. A report utility in the same dir is counted and reported separately rather than failing the run.
|
|
20
20
|
HS-02 target A check green on both trees proves nothing - the REPLAY must show RED pre-change. gate harness_dir/*, replay.env, replay.cmd goblin-verify --only HS-02 The declared `replay.cmd` is EXECUTED with `{name}` replaced by each harness's name, in the pre-change worktree, with `replay.env=<commit>` set (Z1-4). Two clauses that used to be unheard: a command that interpolates no `{name}` FAILs (it cannot be running the harness it names, so nothing was replayed), and a command that cannot be executed at all - exit 126 or 127 - FAILs rather than counting as a RED harness. The harness's name is substituted SHELL-QUOTED (`printf %q`), because the name is part of the command text the shell parses; unquoted, a name carrying `;` or `#` reached the shell as syntax (Z2-3, the G8-1 surface class), and the control for it carries a metacharacter-bearing file name. What it cannot see: a command that runs *something else* under the harness's name and exits non-zero, and whether the harness tests the right path rather than merely failing on this tree.
|
|
21
21
|
HS-03 target Source probes read text with comments blanked first. advisory harness_dir/* advisory Recognising 'this probe reads source text' is semantic; a grep for the blanking helper produces false FAILs on harnesses that do not probe source.
|
|
22
|
-
CM-01 target Commits carry the owner identity, not an ambient one. Current scope: this gates the identity of HEAD (the last commit) at the moment of the run - earlier commits by other authors are not scanned. gate git log test "$(git log -1 --format='%ae')" = "$(grep '^owner_email:' .goblin/goblin.yaml | cut -d' ' -f2)" —
|
|
22
|
+
CM-01 target Commits carry the owner identity, not an ambient one. Current scope: this gates the identity of HEAD (the last commit) at the moment of the run - earlier commits by other authors are not scanned. gate git log test "$(git log -1 --format='%ae')" = "$(grep '^owner_email:' .goblin/goblin.yaml | cut -d' ' -f2)" note: this repo records a different owner (you are probably new here) — commit with git -c user.email=<owner_email> --author=<owner_email>, or update owner_email: in .goblin/goblin.yaml
|
|
23
23
|
CM-02 target The commit message was written to a file, not passed with -m. advisory git log advisory A backtick lost to command substitution leaves no trace a later check can read. Reported as a heuristic (unbalanced backticks in a body) only.
|
|
24
24
|
CM-03 target Commit-as-you-go: the working tree is not carrying a dead run's work. script git status --porcelain goblin-verify --only CM-03 —
|
|
25
25
|
MD-01 target No model name is hardcoded in any reusable rule. lint skills/ manifest/ bin/ templates/ presets/ .goblin/ .hermes/ for d in skills manifest bin templates presets .goblin .hermes; do [ -d "$d" ] || continue; grep -rniE '(d[e]epseek|cl[a]ude|g[p]t-[0-9]|gr[o]k|g[e]mini|g[l]m-[0-9]|k[i]mi)[a-z0-9.:_-]*' "$d" && exit 1; done; exit 0 — (the pattern is written with character classes so this row cannot match itself; tests/t-verify-red.sh proves it still catches a real model name. SCOPE, stated so a repo-wide grep is not re-reported as a hole (G8-10): this row reads the seven directories an install writes rules into - skills/ manifest/ bin/ templates/ presets/ .goblin/ .hermes/. It does NOT read tests/, docs/, or the source automations/ directory; tests/ is where a control must be free to WRITE the thing it guards, and the source directories are covered by MD-01's own body in tests/run-tests.sh, which scans skills manifest bin templates presets automations. Both control strings are assembled at run time, so a repo-wide grep over the whole tree is 0 and the row's own scope is 0 by construction.)
|
package/manifest/glossary.tsv
CHANGED
|
@@ -23,3 +23,11 @@ judge A role that decides whether a PROCESS met its own predicate, from a comman
|
|
|
23
23
|
predicate One shell command that exits 0 when the loop is finished. Written before iteration 1 and run once before it, so its first state is known to be red. A duration is not a predicate. docs/LOOP.md + pstack guide/07
|
|
24
24
|
loop One unattended run over a predicate, recorded in the committed .goblin/loop/ (predicate, pin, first-run, budget, one decisions.tsv row per iteration). docs/LOOP.md
|
|
25
25
|
never-relax The predicate's digest is recorded at loop start and never updates itself; relaxing it is closing this loop and opening another, with the old predicate archived under .goblin/loop/closed-<date>/. docs/LOOP.md
|
|
26
|
+
round One full pass of the work cycle: plan, implement, gate, replay, hand off. The unit a wave code counts. UX-review-2026-10-06
|
|
27
|
+
vendored Copied into the repo rather than read from the package, so it survives offline and is hashed by IN-02 like any installed file. UX-review-2026-10-06
|
|
28
|
+
forge The hosting platform a repo pushes to (GitHub, GitLab, ...). PG-05 and PG-06 read the workflow text but can never see what the forge itself enforces. UX-review-2026-10-06
|
|
29
|
+
drift A file whose current bytes no longer match the hash recorded at install time. IN-02 reports it; the remedy column says how to recover. UX-review-2026-10-06
|
|
30
|
+
preimage The input that produces a known hash. The hash checks here prove non-drift, not preimage resistance - they are tamper-evidence, not signatures (docs/LIMITS.md #18). UX-review-2026-10-06
|
|
31
|
+
lane A family of rules that share a mechanism and a blind spot: the ban lane, the judge/loop lane, the CI lane, the reference lane. The cannot-see footer reports per lane. UX-review-2026-10-06
|
|
32
|
+
foreman The orchestrating agent that delegates work to the fleet; the role that reads HANDOFF.md first and writes it last. UX-review-2026-10-06
|
|
33
|
+
engine The bash programs plus the manifest a verify run actually resolved: per-repo (.goblin/bin) or global (engine_dir:). Named in every run's footer. UX-review-2026-10-06
|
package/package.json
CHANGED
|
@@ -1,334 +0,0 @@
|
|
|
1
|
-
Script started on 2026-10-02 00:53:48+07:00 [COMMAND="bash /home/harvey/projects/goblin-stack/bin/goblin-init --target /tmp/ptyfinal/repo --yes" <not executed on terminal>]
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
[2K[91m▄███▄ ▄██▄ ██▄ █ ▄█▄ █ █ ▄██▀ █████ ▄███▄ ▄███ █ █[0m
|
|
11
|
-
[2K[91m█ █ █ █ █▄▀█ █ █ █▄ █ ▀██▄ █ █ █ █ █ █[0m
|
|
12
|
-
[2K[91m█ ▄██ █ █ █▄▀█ █ █ █ ▄█ ▄█▀ █ █████ █ ██[0m
|
|
13
|
-
[2K[91m▀██▀▀ ▀██▀ ██▀ ▀▀▀▀ ▀█▀ █ █ ██▀▀ ▀ █ █ ▀██▀ █ █[0m
|
|
14
|
-
[2K [90mdiscipline around whatever executes[0m
|
|
15
|
-
[2K
|
|
16
|
-
[2K[97m gob init[0m [90m— first-run setup (gobstack v0.4.4)[0m
|
|
17
|
-
[2K [90m6 steps · every step has a flag · nothing is written until the plan is confirmed[0m
|
|
18
|
-
[2K
|
|
19
|
-
[2K [91m◆[0m 1. platforms [97m[0m
|
|
20
|
-
[2K [90m○[0m 2. class [97m[0m
|
|
21
|
-
[2K [90m○[0m 3. branch/email [97m[0m
|
|
22
|
-
[2K [90m○[0m 4. first gate [97m[0m
|
|
23
|
-
[2K [90m○[0m 5. emit [97m[0m
|
|
24
|
-
[2K [90m○[0m 6. done [97m[0m
|
|
25
|
-
[9A[J[2K[91m▄███▄ ▄██▄ ██▄ █ ▄█▄ █ █ ▄██▀ █████ ▄███▄ ▄███ █ █[0m
|
|
26
|
-
[2K[91m█ █ █ █ █▄▀█ █ █ █▄ █ ▀██▄ █ █ █ █ █ █[0m
|
|
27
|
-
[2K[91m█ ▄██ █ █ █▄▀█ █ █ █ ▄█ ▄█▀ █ █████ █ ██[0m
|
|
28
|
-
[2K[91m▀██▀▀ ▀██▀ ██▀ ▀▀▀▀ ▀█▀ █ █ ██▀▀ ▀ █ █ ▀██▀ █ █[0m
|
|
29
|
-
[2K [90mdiscipline around whatever executes[0m
|
|
30
|
-
[2K
|
|
31
|
-
[2K[97m gob init[0m [90m— first-run setup (gobstack v0.4.4)[0m
|
|
32
|
-
[2K [90m6 steps · every step has a flag · nothing is written until the plan is confirmed[0m
|
|
33
|
-
[2K
|
|
34
|
-
[2K [92m✔[0m 1. platforms [97m[0m
|
|
35
|
-
[2K [91m◆[0m 2. class [97m[0m
|
|
36
|
-
[2K [90m○[0m 3. branch/email [97m[0m
|
|
37
|
-
[2K [90m○[0m 4. first gate [97m[0m
|
|
38
|
-
[2K [90m○[0m 5. emit [97m[0m
|
|
39
|
-
[2K [90m○[0m 6. done [97m[0m
|
|
40
|
-
[2K
|
|
41
|
-
[2K ✔ 1. platforms [97m0 detected[0m
|
|
42
|
-
[2K [93mno platform detected here — the wizard will still install the harness; emit later with gob emit[0m
|
|
43
|
-
[12A[J[2K[91m▄███▄ ▄██▄ ██▄ █ ▄█▄ █ █ ▄██▀ █████ ▄███▄ ▄███ █ █[0m
|
|
44
|
-
[2K[91m█ █ █ █ █▄▀█ █ █ █▄ █ ▀██▄ █ █ █ █ █ █[0m
|
|
45
|
-
[2K[91m█ ▄██ █ █ █▄▀█ █ █ █ ▄█ ▄█▀ █ █████ █ ██[0m
|
|
46
|
-
[2K[91m▀██▀▀ ▀██▀ ██▀ ▀▀▀▀ ▀█▀ █ █ ██▀▀ ▀ █ █ ▀██▀ █ █[0m
|
|
47
|
-
[2K [90mdiscipline around whatever executes[0m
|
|
48
|
-
[2K
|
|
49
|
-
[2K[97m gob init[0m [90m— first-run setup (gobstack v0.4.4)[0m
|
|
50
|
-
[2K [90m6 steps · every step has a flag · nothing is written until the plan is confirmed[0m
|
|
51
|
-
[2K
|
|
52
|
-
[2K
|
|
53
|
-
[2K ✔ 1. platforms [97m0 detected[0m
|
|
54
|
-
[2K [93mno platform detected here — the wizard will still install the harness; emit later with gob emit[0m
|
|
55
|
-
[2K [92m✔[0m 1. platforms [97m[90m0 detected[0m[0m
|
|
56
|
-
[2K [92m✔[0m 2. class [97m[0m
|
|
57
|
-
[2K [91m◆[0m 3. branch/email [97m[0m
|
|
58
|
-
[2K [90m○[0m 4. first gate [97m[0m
|
|
59
|
-
[2K [90m○[0m 5. emit [97m[0m
|
|
60
|
-
[2K [90m○[0m 6. done [97m[0m
|
|
61
|
-
[2K
|
|
62
|
-
[2K [90mwhat kind of work does this repo do?[0m
|
|
63
|
-
[2K [97m 1 ▸ app shipped features, PRs, review gates [90m(class A)[0m
|
|
64
|
-
[2K [97m 2 service backend jobs, config, unattended runs [90m(class B)[0m
|
|
65
|
-
[2K [97m 3 game playable builds, perf budgets [90m(class C)[0m
|
|
66
|
-
[2K [97m 4 research specs, replays, reference corpora [90m(class D)[0m
|
|
67
|
-
[2K [97m 5 agent fleets, loops, unattended automation [90m(class E)[0m
|
|
68
|
-
[2K [97m 6 desktop the shell you live in, perf budget [90m(class F)[0m
|
|
69
|
-
[2K [90m↑ number + Enter · Enter = app · the class letter works too (A-F)[0m
|
|
70
|
-
[2K
|
|
71
|
-
[2K ✔ 2. class [97mA — shipped-software[0m
|
|
72
|
-
[23A[J[2K[91m▄███▄ ▄██▄ ██▄ █ ▄█▄ █ █ ▄██▀ █████ ▄███▄ ▄███ █ █[0m
|
|
73
|
-
[2K[91m█ █ █ █ █▄▀█ █ █ █▄ █ ▀██▄ █ █ █ █ █ █[0m
|
|
74
|
-
[2K[91m█ ▄██ █ █ █▄▀█ █ █ █ ▄█ ▄█▀ █ █████ █ ██[0m
|
|
75
|
-
[2K[91m▀██▀▀ ▀██▀ ██▀ ▀▀▀▀ ▀█▀ █ █ ██▀▀ ▀ █ █ ▀██▀ █ █[0m
|
|
76
|
-
[2K [90mdiscipline around whatever executes[0m
|
|
77
|
-
[2K
|
|
78
|
-
[2K[97m gob init[0m [90m— first-run setup (gobstack v0.4.4)[0m
|
|
79
|
-
[2K [90m6 steps · every step has a flag · nothing is written until the plan is confirmed[0m
|
|
80
|
-
[2K
|
|
81
|
-
[2K
|
|
82
|
-
[2K ✔ 1. platforms [97m0 detected[0m
|
|
83
|
-
[2K [93mno platform detected here — the wizard will still install the harness; emit later with gob emit[0m
|
|
84
|
-
[2K
|
|
85
|
-
[2K [90mwhat kind of work does this repo do?[0m
|
|
86
|
-
[2K [97m 1 ▸ app shipped features, PRs, review gates [90m(class A)[0m
|
|
87
|
-
[2K [97m 2 service backend jobs, config, unattended runs [90m(class B)[0m
|
|
88
|
-
[2K [97m 3 game playable builds, perf budgets [90m(class C)[0m
|
|
89
|
-
[2K [97m 4 research specs, replays, reference corpora [90m(class D)[0m
|
|
90
|
-
[2K [97m 5 agent fleets, loops, unattended automation [90m(class E)[0m
|
|
91
|
-
[2K [97m 6 desktop the shell you live in, perf budget [90m(class F)[0m
|
|
92
|
-
[2K [90m↑ number + Enter · Enter = app · the class letter works too (A-F)[0m
|
|
93
|
-
[2K
|
|
94
|
-
[2K ✔ 2. class [97mA — shipped-software[0m
|
|
95
|
-
[2K [92m✔[0m 1. platforms [97m[90m0 detected[0m[0m
|
|
96
|
-
[2K [92m✔[0m 2. class [97m[97mA (shipped-software)[0m[0m
|
|
97
|
-
[2K [92m✔[0m 3. branch/email [97m[0m
|
|
98
|
-
[2K [91m◆[0m 4. first gate [97m[0m
|
|
99
|
-
[2K [90m○[0m 5. emit [97m[0m
|
|
100
|
-
[2K [90m○[0m 6. done [97m[0m
|
|
101
|
-
[2K
|
|
102
|
-
[2K [90mthe forge contract — the identity this repo commits with (CM-01)[0m
|
|
103
|
-
[97mdefault branch[0m [90m─ main[2K
|
|
104
|
-
[97mowner email[0m [90m─ t@t.co[2K
|
|
105
|
-
[2K ✔ 3. branch/email [97mmain · t@t.co[0m
|
|
106
|
-
[28A[J[2K[91m▄███▄ ▄██▄ ██▄ █ ▄█▄ █ █ ▄██▀ █████ ▄███▄ ▄███ █ █[0m
|
|
107
|
-
[2K[91m█ █ █ █ █▄▀█ █ █ █▄ █ ▀██▄ █ █ █ █ █ █[0m
|
|
108
|
-
[2K[91m█ ▄██ █ █ █▄▀█ █ █ █ ▄█ ▄█▀ █ █████ █ ██[0m
|
|
109
|
-
[2K[91m▀██▀▀ ▀██▀ ██▀ ▀▀▀▀ ▀█▀ █ █ ██▀▀ ▀ █ █ ▀██▀ █ █[0m
|
|
110
|
-
[2K [90mdiscipline around whatever executes[0m
|
|
111
|
-
[2K
|
|
112
|
-
[2K[97m gob init[0m [90m— first-run setup (gobstack v0.4.4)[0m
|
|
113
|
-
[2K [90m6 steps · every step has a flag · nothing is written until the plan is confirmed[0m
|
|
114
|
-
[2K
|
|
115
|
-
[2K
|
|
116
|
-
[2K ✔ 1. platforms [97m0 detected[0m
|
|
117
|
-
[2K [93mno platform detected here — the wizard will still install the harness; emit later with gob emit[0m
|
|
118
|
-
[2K
|
|
119
|
-
[2K [90mwhat kind of work does this repo do?[0m
|
|
120
|
-
[2K [97m 1 ▸ app shipped features, PRs, review gates [90m(class A)[0m
|
|
121
|
-
[2K [97m 2 service backend jobs, config, unattended runs [90m(class B)[0m
|
|
122
|
-
[2K [97m 3 game playable builds, perf budgets [90m(class C)[0m
|
|
123
|
-
[2K [97m 4 research specs, replays, reference corpora [90m(class D)[0m
|
|
124
|
-
[2K [97m 5 agent fleets, loops, unattended automation [90m(class E)[0m
|
|
125
|
-
[2K [97m 6 desktop the shell you live in, perf budget [90m(class F)[0m
|
|
126
|
-
[2K [90m↑ number + Enter · Enter = app · the class letter works too (A-F)[0m
|
|
127
|
-
[2K
|
|
128
|
-
[2K ✔ 2. class [97mA — shipped-software[0m
|
|
129
|
-
[2K
|
|
130
|
-
[2K [90mthe forge contract — the identity this repo commits with (CM-01)[0m
|
|
131
|
-
[2K
|
|
132
|
-
[2K
|
|
133
|
-
[2K ✔ 3. branch/email [97mmain · t@t.co[0m
|
|
134
|
-
[2K [92m✔[0m 1. platforms [97m[90m0 detected[0m[0m
|
|
135
|
-
[2K [92m✔[0m 2. class [97m[97mA (shipped-software)[0m[0m
|
|
136
|
-
[2K [92m✔[0m 3. branch/email [97m[97mmain · t@t.co[0m[0m
|
|
137
|
-
[2K [92m✔[0m 4. first gate [97m[0m
|
|
138
|
-
[2K [91m◆[0m 5. emit [97m[0m
|
|
139
|
-
[2K [90m○[0m 6. done [97m[0m
|
|
140
|
-
[2K
|
|
141
|
-
[2K [90mone real command that must stay green — suggested for a bash suite:[0m
|
|
142
|
-
[2K [90mbash tests/run-tests.sh[0m
|
|
143
|
-
[97mgate command[0m [90m─ bash tests/run-tests.sh[2K
|
|
144
|
-
[2K ✔ 4. first gate [97mbash tests/run-tests.sh[0m
|
|
145
|
-
[33A[J[2K[91m▄███▄ ▄██▄ ██▄ █ ▄█▄ █ █ ▄██▀ █████ ▄███▄ ▄███ █ █[0m
|
|
146
|
-
[2K[91m█ █ █ █ █▄▀█ █ █ █▄ █ ▀██▄ █ █ █ █ █ █[0m
|
|
147
|
-
[2K[91m█ ▄██ █ █ █▄▀█ █ █ █ ▄█ ▄█▀ █ █████ █ ██[0m
|
|
148
|
-
[2K[91m▀██▀▀ ▀██▀ ██▀ ▀▀▀▀ ▀█▀ █ █ ██▀▀ ▀ █ █ ▀██▀ █ █[0m
|
|
149
|
-
[2K [90mdiscipline around whatever executes[0m
|
|
150
|
-
[2K
|
|
151
|
-
[2K[97m gob init[0m [90m— first-run setup (gobstack v0.4.4)[0m
|
|
152
|
-
[2K [90m6 steps · every step has a flag · nothing is written until the plan is confirmed[0m
|
|
153
|
-
[2K
|
|
154
|
-
[2K
|
|
155
|
-
[2K ✔ 1. platforms [97m0 detected[0m
|
|
156
|
-
[2K [93mno platform detected here — the wizard will still install the harness; emit later with gob emit[0m
|
|
157
|
-
[2K
|
|
158
|
-
[2K [90mwhat kind of work does this repo do?[0m
|
|
159
|
-
[2K [97m 1 ▸ app shipped features, PRs, review gates [90m(class A)[0m
|
|
160
|
-
[2K [97m 2 service backend jobs, config, unattended runs [90m(class B)[0m
|
|
161
|
-
[2K [97m 3 game playable builds, perf budgets [90m(class C)[0m
|
|
162
|
-
[2K [97m 4 research specs, replays, reference corpora [90m(class D)[0m
|
|
163
|
-
[2K [97m 5 agent fleets, loops, unattended automation [90m(class E)[0m
|
|
164
|
-
[2K [97m 6 desktop the shell you live in, perf budget [90m(class F)[0m
|
|
165
|
-
[2K [90m↑ number + Enter · Enter = app · the class letter works too (A-F)[0m
|
|
166
|
-
[2K
|
|
167
|
-
[2K ✔ 2. class [97mA — shipped-software[0m
|
|
168
|
-
[2K
|
|
169
|
-
[2K [90mthe forge contract — the identity this repo commits with (CM-01)[0m
|
|
170
|
-
[2K
|
|
171
|
-
[2K
|
|
172
|
-
[2K ✔ 3. branch/email [97mmain · t@t.co[0m
|
|
173
|
-
[2K
|
|
174
|
-
[2K [90mone real command that must stay green — suggested for a bash suite:[0m
|
|
175
|
-
[2K [90mbash tests/run-tests.sh[0m
|
|
176
|
-
[2K
|
|
177
|
-
[2K ✔ 4. first gate [97mbash tests/run-tests.sh[0m
|
|
178
|
-
[2K [92m✔[0m 1. platforms [97m[90m0 detected[0m[0m
|
|
179
|
-
[2K [92m✔[0m 2. class [97m[97mA (shipped-software)[0m[0m
|
|
180
|
-
[2K [92m✔[0m 3. branch/email [97m[97mmain · t@t.co[0m[0m
|
|
181
|
-
[2K [92m✔[0m 4. first gate [97m[97mbash tests/run-tests.sh[0m[0m
|
|
182
|
-
[2K [92m✔[0m 5. emit [97m[0m
|
|
183
|
-
[2K [91m◆[0m 6. done [97m[0m
|
|
184
|
-
[2K ✔ 5. emit [97m0 platform(s) · scope project[0m
|
|
185
|
-
|
|
186
|
-
[90mrunning: goblin-install --target /tmp/ptyfinal/repo --class A[0m
|
|
187
|
-
created 50 · updated 0 · unchanged 0 · skipped 0
|
|
188
|
-
|
|
189
|
-
next:
|
|
190
|
-
1. cd /tmp/ptyfinal/repo && git add -A && git commit # the install is a change like any other
|
|
191
|
-
2. .goblin/bin/goblin-verify # or add .goblin/bin to PATH
|
|
192
|
-
3. edit .goblin/goblin.yaml: replace the default gate with your real commands (P8 step 3)
|
|
193
|
-
4. hermes skills trust /tmp/ptyfinal/repo # one-time, so the project-tier skills load
|
|
194
|
-
|
|
195
|
-
automations (optional; neither writes outside this repo, and A-02 has no agent in it):
|
|
196
|
-
bash /tmp/ptyfinal/repo/.goblin/automations/drift-audit.sh --dry-run # read the record first
|
|
197
|
-
cp /tmp/ptyfinal/repo/.goblin/automations/drift-audit.sh ~/.hermes/scripts/
|
|
198
|
-
hermes cron create "0 9 * * 1" --name "Drift audit - weekly" --no-agent \
|
|
199
|
-
--script drift-audit.sh --deliver <channel>
|
|
200
|
-
P13/P14 in docs/FLOWS.md; the whole model in automations/README.md
|
|
201
|
-
[92mPASS IN-01 the install record exists and names its version[0m
|
|
202
|
-
[92mPASS IN-02 41 installed files hashed[0m
|
|
203
|
-
[92mPASS IN-03 the manifest is complete: every rule carries a check or is advisory, inside the enum[0m
|
|
204
|
-
[92mPASS IN-04 0 pre-existing file(s) left untouched[0m
|
|
205
|
-
[92mPASS HP-01 (test -f HANDOFF.md)[0m
|
|
206
|
-
[92mPASS HP-02 (for h in 'START HERE' 'STATE|STATUS' 'GATES?' 'NEXT STEPS|NEXT' 'NOT VERIFIED|UNVERIFIED|NOT PROVEN|UNPROVEN|PENDING[^.]*DEVICE TEST'; do grep -qiE "^#{2,3}[[:space:]]+[^[:alpha:]]*($h)\b" HANDOFF.md || { echo "missing section: $h"; exit 1; }; done)[0m
|
|
207
|
-
[92mPASS HP-03 1 gate line(s) inside the Gates section, each with a measured date (anchored on the declared gate name(s): commit todo_ceiling)[0m
|
|
208
|
-
[93mADV HP-04 A stale sentence is corrected in place with a dated parenthetical, never deleted. (advisory)[0m
|
|
209
|
-
[92mPASS HP-05 names 3c96403 (ancestor of HEAD 3c96403)[0m
|
|
210
|
-
[92mPASS SP-01 (ls ./*-SPEC.md >/dev/null 2>&1)[0m
|
|
211
|
-
[91mFAIL SP-02 (test -z "$(git ls-files --others --exclude-standard -- '*-SPEC.md')" -> exit 1)[0m
|
|
212
|
-
[92mPASS SP-03 (awk '/^[[:space:]]*[-*][[:space:]]/ && /AC[0-9]*:/ && !/`|==|===|exit|<|>/ {print; bad=1} END{exit bad}' ./*-SPEC.md)[0m
|
|
213
|
-
[92mPASS GT-01 2 declared gate(s), each with a cmd[0m
|
|
214
|
-
[92mPASS GT-02 commit=0 todo_ceiling=0 · client_js_bytes 0 (ceiling 0) · measured 2026-10-02[0m
|
|
215
|
-
[92mPASS GT-03 (test -f .goblin/last-gate-line && [ .goblin/last-gate-line -nt "$(git rev-parse --git-dir)/logs/HEAD" ])[0m
|
|
216
|
-
[92mPASS GT-04 ratchet client_js_bytes ceiling 0[0m
|
|
217
|
-
[92mPASS GT-05 client_js_bytes 0 (ceiling 0)[0m
|
|
218
|
-
[92mPASS HS-01 not an asserting harness (report utility): gate.sh[0m
|
|
219
|
-
1 asserting harness(es), 1 report utility(ies)
|
|
220
|
-
[90mSKIP HS-02 no pinned pre-change commit yet (replay.commit empty or unknown) - REPLAY not provable[0m
|
|
221
|
-
[93mADV HS-03 Source probes read text with comments blanked first. (advisory)[0m
|
|
222
|
-
[92mPASS CM-01 (test "$(git log -1 --format='%ae')" = "$(grep '^owner_email:' .goblin/goblin.yaml | cut -d' ' -f2)")[0m
|
|
223
|
-
[93mADV CM-02 The commit message was written to a file, not passed with -m. (advisory)[0m
|
|
224
|
-
[91mFAIL CM-03 9 dirty entr(y|ies), max_dirty 0[0m
|
|
225
|
-
[92mPASS MD-01 (for d in skills manifest bin templates presets .goblin .hermes; do [ -d "$d" ] || continue; grep -rniE '(d[e]epseek|cl[a]ude|g[p]t-[0-9]|gr[o]k|g[e]mini|g[l]m-[0-9]|k[i]mi)[a-z0-9.:_-]*' "$d" && exit 1; done; exit 0)[0m
|
|
226
|
-
[93mADV MD-02 no model mapping configured (/tmp/ptyfinal/home/projects/fleet-model.yaml absent) - advisory[0m
|
|
227
|
-
[93mADV MD-03 Role-pinned fan-out goes through kanban, not a model-less subagent spawn. (advisory)[0m
|
|
228
|
-
[92mPASS PG-01 0 review note(s)[0m
|
|
229
|
-
[92mPASS PG-02 0 review note(s) classified[0m
|
|
230
|
-
[92mPASS PG-03 0 review note(s) patch-id checked[0m
|
|
231
|
-
[93mADV PG-04 Never bypass what the forge enforces. (advisory)[0m
|
|
232
|
-
[92mPASS PG-05 1 workflow file(s) checked for a self-skipping required check[0m
|
|
233
|
-
[92mPASS PG-06 goblin-gate.yml: runs the verifier, which executes every declared gate[0m
|
|
234
|
-
1 workflow file(s) compared with the 2 declared gate(s)
|
|
235
|
-
[92mPASS DS-01 unchanged: .goblin/state.json=missing[0m
|
|
236
|
-
[92mPASS DS-02 snapshot .goblin/state.json=missing[0m
|
|
237
|
-
[93mADV DOC-01 A significant change updates the docs that teach it. (advisory)[0m
|
|
238
|
-
[93mADV DOC-02 System-level changes are recorded wherever the project's standard says they live. (advisory)[0m
|
|
239
|
-
[92mPASS SK-01 [0m
|
|
240
|
-
[92mPASS SK-02 20 installed skill file(s) hashed[0m
|
|
241
|
-
[92mPASS SK-03 advisory 10 of ceiling 10 (0 free slots: the next advisory row FAILs)[0m
|
|
242
|
-
[92mPASS SK-04 [0m
|
|
243
|
-
[92mPASS PT-01 (for d in skills manifest bin templates presets .goblin .hermes; do [ -d "$d" ] || continue; grep -rniE --exclude=goblin.yaml --exclude=installed.json '(h[a]rvey|tech-g[o]blin|/h[o]me/[a-z]+|g[o]blin-ui|op[e]n-door|sup[r]eme|bb[t]ech|c[l]v)' "$d" && exit 1; done; exit 0)[0m
|
|
244
|
-
[92mPASS PT-02 declared main, actual main[0m
|
|
245
|
-
[92mPASS CL-01 part pr-gate: optional, present[0m
|
|
246
|
-
part review-panel: optional, present
|
|
247
|
-
part tokens: optional, absent
|
|
248
|
-
[92mPASS CL-02 archive: false - the full class requirement applies[0m
|
|
249
|
-
[92mPASS SC-01 0 tracked secret file(s)[0m
|
|
250
|
-
[92mPASS SC-02 the whole secret family is ignored (.env, .env.local, .env.production proved by git)[0m
|
|
251
|
-
[92mPASS SC-03 0 client-visible secret-shaped name(s); no build output to scan for clause 2[0m
|
|
252
|
-
[92mPASS SC-04 0 cookie write(s) checked; a JS-written cookie is readable by any script - reported, not failed[0m
|
|
253
|
-
[92mPASS SC-05 0 write handler(s), 0 waived; 11 dir(s) declared[0m
|
|
254
|
-
[90mSKIP SC-06 no package.json - there is no dependency manifest to lock[0m
|
|
255
|
-
[90mSKIP SC-07 no audit record yet. Run .goblin/bin/goblin-audit once, deliberately, then commit[0m
|
|
256
|
-
.goblin/audit.tsv: SC-07 reads the record and never the network
|
|
257
|
-
[90mSKIP SC-08 no package-lock.json - there is no install-hook surface to enumerate[0m
|
|
258
|
-
[93mADV SC-09 Auth is applied consistently across sibling routes. (advisory)[0m
|
|
259
|
-
[90mSKIP PF-01 no perf baseline recorded yet: run `find .next/static dist/assets dist -type f -name '*.js' -exec cat {} + 2>/dev/null | wc -c` on a pinned commit, then write[0m
|
|
260
|
-
perf.baseline_commit, perf.baseline_value, perf.measured and the matching ratchet ceiling
|
|
261
|
-
[92mPASS AU-01 2 automation producer(s) scanned, none opens with a network or forge verb[0m
|
|
262
|
-
[90mSKIP AU-02 no reports/*/report.yaml - nothing to dedup[0m
|
|
263
|
-
[90mSKIP AU-03 no reports/ - no reporter run in this repo to audit[0m
|
|
264
|
-
[92mPASS AU-04 [0m
|
|
265
|
-
[92mPASS BN-00 8 ban(s), each with an enforcement row and a named replacement[0m
|
|
266
|
-
[90mSKIP BN-01 No `any` in application TypeScript. (no matching files: src) [0m
|
|
267
|
-
[90mSKIP BN-02 No `@ts-ignore` / `@ts-expect-error` suppressions. (no matching files: src) [0m
|
|
268
|
-
[90mSKIP BN-03 No direct network call from a component. (not enabled in bans: - add BN-03 to .goblin/goblin.yaml to turn it on) [0m
|
|
269
|
-
[90mSKIP BN-05 No import across a declared layer boundary. (no matching files: src) [0m
|
|
270
|
-
[90mSKIP BN-06 No renderer with Node access (`nodeIntegration: true`). (not enabled in bans: - add BN-06 to .goblin/goblin.yaml to turn it on) [0m
|
|
271
|
-
[90mSKIP BN-07 No renderer with context isolation or the process sandbox turned off. (not enabled in bans: - add BN-07 to .goblin/goblin.yaml to turn it on) [0m
|
|
272
|
-
[90mSKIP BN-08 No dangerous webPreferences. (not enabled in bans: - add BN-08 to .goblin/goblin.yaml to turn it on) [0m
|
|
273
|
-
[90mSKIP BN-09 No synchronous IPC and no `@electron/remote`. (not enabled in bans: - add BN-09 to .goblin/goblin.yaml to turn it on) [0m
|
|
274
|
-
[90mSKIP FM-01 feature_map: is empty - no map is declared, so there is nothing to index[0m
|
|
275
|
-
[90mSKIP FM-02 feature_map: is empty - no map is declared, so there are no entry paths to resolve[0m
|
|
276
|
-
[90mSKIP VA-01 verify_doctor: is empty - no doctor is declared, so "the generated skill was executed once" is not provable here[0m
|
|
277
|
-
[90mSKIP JG-01 no loop record in this repo - no judge verdict to check[0m
|
|
278
|
-
[93mADV JG-02 no model mapping configured (/tmp/ptyfinal/home/projects/fleet-model.yaml absent) - advisory[0m
|
|
279
|
-
remedy: add a `judge:` entry beside the code lane in the file declared as models_file: in /tmp/ptyfinal/repo/.goblin/goblin.yaml
|
|
280
|
-
[93mADV JG-03 A judge lane that has never returned a non-`done` verdict is escalated. (advisory)[0m
|
|
281
|
-
[90mSKIP LP-01 no loop has run in this repo[0m
|
|
282
|
-
[90mSKIP LP-02 no loop has run in this repo[0m
|
|
283
|
-
[90mSKIP LP-03 no loop has run in this repo[0m
|
|
284
|
-
[90mSKIP LP-04 no loop has run in this repo[0m
|
|
285
|
-
[90mSKIP LP-05 no loop has run in this repo[0m
|
|
286
|
-
[90mSKIP RC-01 reference_manifest: is empty - no reference corpus is declared, so there is nothing for a build to match against[0m
|
|
287
|
-
[90mSKIP RC-02 reference_manifest: is empty - there is no manifest to shape-check (RC-01 skips for the same reason)[0m
|
|
288
|
-
[90mSKIP RC-03 no manifests/ directory - this is not a lab repo with a reference corpus, so there are no tracked bytes to check[0m
|
|
289
|
-
[90mSKIP RC-04 no manifests/*.sha256 - no acquisition record is declared, so there is none to read[0m
|
|
290
|
-
41 passed, 2 failed, 11 advisory, 28 skipped
|
|
291
|
-
of those 11 advisory: the matrix labels 10 row(s) advisory; the difference is the non-advisory row(s) reporting ADV by design (an unresolved lane) and any labelled row skipped by an opt-out
|
|
292
|
-
cannot see: whether a check in the harness dir tests the right path rather than
|
|
293
|
-
merely passing; whether the forge is bound by the workflow CL-01 found; whether a human
|
|
294
|
-
read the diff;
|
|
295
|
-
whether the model mapping names a family that actually differs (MD-02 reports it
|
|
296
|
-
and cannot change it); and whether .goblin/installed.json — the record every drift
|
|
297
|
-
check trusts — was itself rewritten. It is not signed, so one edit to it (with the
|
|
298
|
-
matching edit to the file it protects) defeats IN-02, SK-02 and HS-01 at once
|
|
299
|
-
(docs/LIMITS.md #18). The ban lane carries the same blind spot and two of its own:
|
|
300
|
-
the ban table is a manifest file under the same unsigned record, so a defanged ban
|
|
301
|
-
passes BN-00 (docs/LIMITS.md #28); a ban probe is a TEXT probe with no AST, so a
|
|
302
|
-
`Record<string, any>` is missed and a `: any` inside a string is reported
|
|
303
|
-
(docs/LIMITS.md #27); and no check here can reach a ban IN CONTEXT — the row proves
|
|
304
|
-
the forbidden path fails mechanically, never that the ban reached the agent that
|
|
305
|
-
wrote the line. The judge/loop lane adds its own: every JG-/LP- row reads a RECORD, so
|
|
306
|
-
it proves a handle, a pin, a budget and a pointer exist — never that the loop made
|
|
307
|
-
progress (a changed pointer is a proxy, docs/LIMITS.md #33), never which lane returned
|
|
308
|
-
a verdict, and never that the predicate was the right one or was really run. The CI lane
|
|
309
|
-
adds its own: PG-05 and PG-06 read a workflow's TEXT, so PG-05 sees a job whose gate step is
|
|
310
|
-
conditional and cannot see branch protection, the required-check list, or a forge that never
|
|
311
|
-
ran the job at all, and PG-06 proves a declared gate is INVOKED in a file under
|
|
312
|
-
.github/workflows/ — never that the forge marks that job required, never that it is the job
|
|
313
|
-
the forge waits on, and never that the workflow can fail (that is PG-05). A required check
|
|
314
|
-
that reports Success after skipping its gate is a green light for a commit whose gate never
|
|
315
|
-
ran (docs/CI.md). The reference-corpus lane adds its own: RC-01 matches EXACT sha256 only,
|
|
316
|
-
so a resized, recoloured or re-encoded reference asset, or copied text inside a shipped
|
|
317
|
-
string, passes it unseen; RC-02 proves the manifest is well-shaped, never that its entries
|
|
318
|
-
are the right hashes (as strong as tamper hashing, and installed.json is unsigned); RC-03
|
|
319
|
-
reads the tracked tree and cannot see a payload renamed and re-encoded; and RC-04 proves an
|
|
320
|
-
acquisition record EXISTS, never that the number beside it came from the store (HP-03's
|
|
321
|
-
defect, one artifact over). No row here reaches a reference asset in CONTEXT either.
|
|
322
|
-
engine: mode=vendored cli_sha256=2d37cf1c9f38a582ad60f3f75d2fcd53d10b743905dc3274eab6511c5c5ea008 enforcement_tsv_sha256=fd474c268b0852587c632910c503144fbcfe5e211ed2182902949a79fc5282b1
|
|
323
|
-
|
|
324
|
-
[91mgob verify: 41 passed, 2 failed, 28 skipped · exit 1[0m
|
|
325
|
-
|
|
326
|
-
[90mnext:[0m
|
|
327
|
-
1. [97mthe 28 skipped checks ARE your checklist — gob verify names each one[0m
|
|
328
|
-
2. [97mreplace the placeholder gate in .goblin/goblin.yaml with your real commands (P8 step 3)[0m
|
|
329
|
-
3. [97mnot emitted here: gob emit --platform <p> --scope global[0m
|
|
330
|
-
4. [97mhermes skills trust /tmp/ptyfinal/repo # one-time, so the project-tier skills load[0m
|
|
331
|
-
|
|
332
|
-
[91m▙ the goblin sees you. the gate is RED — start there.[0m
|
|
333
|
-
|
|
334
|
-
Script done on 2026-10-02 00:53:50+07:00 [COMMAND_EXIT_CODE="0"]
|