instar 1.3.625 → 1.3.627
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/core/PostUpdateMigrator.d.ts +1 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +42 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +2 -1
- package/dist/scaffold/templates.js.map +1 -1
- package/package.json +4 -2
- package/scripts/lint-scrape-fixture-realness.js +327 -0
- package/scripts/pre-push-gate.js +6 -0
- package/scripts/redact-captured-fixture.mjs +182 -0
- package/src/data/builtin-manifest.json +28 -20
- package/src/scaffold/templates.ts +2 -1
- package/src/templates/scripts/load-assess.sh +113 -0
- package/upgrades/{1.3.625.md → 1.3.626.md} +7 -0
- package/upgrades/1.3.627.md +23 -0
- package/upgrades/side-effects/robust-load-assessment-fleet.md +74 -0
- package/upgrades/side-effects/scrape-fixture-realness.md +49 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-06-
|
|
5
|
-
"instarVersion": "1.3.
|
|
6
|
-
"entryCount":
|
|
4
|
+
"generatedAt": "2026-06-19T20:44:32.422Z",
|
|
5
|
+
"instarVersion": "1.3.627",
|
|
6
|
+
"entryCount": 202,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
9
9
|
"id": "hook:session-start",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"domain": "identity",
|
|
12
12
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
13
13
|
"installedPath": ".instar/hooks/instar/session-start.sh",
|
|
14
|
-
"contentHash": "
|
|
14
|
+
"contentHash": "922bf0f5c403a51a5eaa0dd73a276219f3be302aa1cd122cdd1d0f279a019a12",
|
|
15
15
|
"since": "2025-01-01"
|
|
16
16
|
},
|
|
17
17
|
"hook:dangerous-command-guard": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"domain": "safety",
|
|
21
21
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
22
22
|
"installedPath": ".instar/hooks/instar/dangerous-command-guard.sh",
|
|
23
|
-
"contentHash": "
|
|
23
|
+
"contentHash": "922bf0f5c403a51a5eaa0dd73a276219f3be302aa1cd122cdd1d0f279a019a12",
|
|
24
24
|
"since": "2025-01-01"
|
|
25
25
|
},
|
|
26
26
|
"hook:grounding-before-messaging": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"domain": "safety",
|
|
30
30
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
31
31
|
"installedPath": ".instar/hooks/instar/grounding-before-messaging.sh",
|
|
32
|
-
"contentHash": "
|
|
32
|
+
"contentHash": "922bf0f5c403a51a5eaa0dd73a276219f3be302aa1cd122cdd1d0f279a019a12",
|
|
33
33
|
"since": "2025-01-01"
|
|
34
34
|
},
|
|
35
35
|
"hook:compaction-recovery": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"domain": "identity",
|
|
39
39
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
40
40
|
"installedPath": ".instar/hooks/instar/compaction-recovery.sh",
|
|
41
|
-
"contentHash": "
|
|
41
|
+
"contentHash": "922bf0f5c403a51a5eaa0dd73a276219f3be302aa1cd122cdd1d0f279a019a12",
|
|
42
42
|
"since": "2025-01-01"
|
|
43
43
|
},
|
|
44
44
|
"hook:external-operation-gate": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"domain": "safety",
|
|
48
48
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
49
49
|
"installedPath": ".instar/hooks/instar/external-operation-gate.js",
|
|
50
|
-
"contentHash": "
|
|
50
|
+
"contentHash": "922bf0f5c403a51a5eaa0dd73a276219f3be302aa1cd122cdd1d0f279a019a12",
|
|
51
51
|
"since": "2025-01-01"
|
|
52
52
|
},
|
|
53
53
|
"hook:deferral-detector": {
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"domain": "safety",
|
|
57
57
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
58
58
|
"installedPath": ".instar/hooks/instar/deferral-detector.js",
|
|
59
|
-
"contentHash": "
|
|
59
|
+
"contentHash": "922bf0f5c403a51a5eaa0dd73a276219f3be302aa1cd122cdd1d0f279a019a12",
|
|
60
60
|
"since": "2025-01-01"
|
|
61
61
|
},
|
|
62
62
|
"hook:self-stop-guard": {
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"domain": "coherence",
|
|
66
66
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
67
67
|
"installedPath": ".instar/hooks/instar/self-stop-guard.js",
|
|
68
|
-
"contentHash": "
|
|
68
|
+
"contentHash": "922bf0f5c403a51a5eaa0dd73a276219f3be302aa1cd122cdd1d0f279a019a12",
|
|
69
69
|
"since": "2025-01-01"
|
|
70
70
|
},
|
|
71
71
|
"hook:post-action-reflection": {
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"domain": "evolution",
|
|
75
75
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
76
76
|
"installedPath": ".instar/hooks/instar/post-action-reflection.js",
|
|
77
|
-
"contentHash": "
|
|
77
|
+
"contentHash": "922bf0f5c403a51a5eaa0dd73a276219f3be302aa1cd122cdd1d0f279a019a12",
|
|
78
78
|
"since": "2025-01-01"
|
|
79
79
|
},
|
|
80
80
|
"hook:external-communication-guard": {
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"domain": "safety",
|
|
84
84
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
85
85
|
"installedPath": ".instar/hooks/instar/external-communication-guard.js",
|
|
86
|
-
"contentHash": "
|
|
86
|
+
"contentHash": "922bf0f5c403a51a5eaa0dd73a276219f3be302aa1cd122cdd1d0f279a019a12",
|
|
87
87
|
"since": "2025-01-01"
|
|
88
88
|
},
|
|
89
89
|
"hook:scope-coherence-collector": {
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"domain": "coherence",
|
|
93
93
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
94
94
|
"installedPath": ".instar/hooks/instar/scope-coherence-collector.js",
|
|
95
|
-
"contentHash": "
|
|
95
|
+
"contentHash": "922bf0f5c403a51a5eaa0dd73a276219f3be302aa1cd122cdd1d0f279a019a12",
|
|
96
96
|
"since": "2025-01-01"
|
|
97
97
|
},
|
|
98
98
|
"hook:scope-coherence-checkpoint": {
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"domain": "coherence",
|
|
102
102
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
103
103
|
"installedPath": ".instar/hooks/instar/scope-coherence-checkpoint.js",
|
|
104
|
-
"contentHash": "
|
|
104
|
+
"contentHash": "922bf0f5c403a51a5eaa0dd73a276219f3be302aa1cd122cdd1d0f279a019a12",
|
|
105
105
|
"since": "2025-01-01"
|
|
106
106
|
},
|
|
107
107
|
"hook:free-text-guard": {
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"domain": "safety",
|
|
111
111
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
112
112
|
"installedPath": ".instar/hooks/instar/free-text-guard.sh",
|
|
113
|
-
"contentHash": "
|
|
113
|
+
"contentHash": "922bf0f5c403a51a5eaa0dd73a276219f3be302aa1cd122cdd1d0f279a019a12",
|
|
114
114
|
"since": "2025-01-01"
|
|
115
115
|
},
|
|
116
116
|
"hook:claim-intercept": {
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"domain": "coherence",
|
|
120
120
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
121
121
|
"installedPath": ".instar/hooks/instar/claim-intercept.js",
|
|
122
|
-
"contentHash": "
|
|
122
|
+
"contentHash": "922bf0f5c403a51a5eaa0dd73a276219f3be302aa1cd122cdd1d0f279a019a12",
|
|
123
123
|
"since": "2025-01-01"
|
|
124
124
|
},
|
|
125
125
|
"hook:claim-intercept-response": {
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"domain": "coherence",
|
|
129
129
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
130
130
|
"installedPath": ".instar/hooks/instar/claim-intercept-response.js",
|
|
131
|
-
"contentHash": "
|
|
131
|
+
"contentHash": "922bf0f5c403a51a5eaa0dd73a276219f3be302aa1cd122cdd1d0f279a019a12",
|
|
132
132
|
"since": "2025-01-01"
|
|
133
133
|
},
|
|
134
134
|
"hook:stop-gate-router": {
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
"domain": "safety",
|
|
138
138
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
139
139
|
"installedPath": ".instar/hooks/instar/stop-gate-router.js",
|
|
140
|
-
"contentHash": "
|
|
140
|
+
"contentHash": "922bf0f5c403a51a5eaa0dd73a276219f3be302aa1cd122cdd1d0f279a019a12",
|
|
141
141
|
"since": "2025-01-01"
|
|
142
142
|
},
|
|
143
143
|
"hook:auto-approve-permissions": {
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
"domain": "safety",
|
|
147
147
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
148
148
|
"installedPath": ".instar/hooks/instar/auto-approve-permissions.js",
|
|
149
|
-
"contentHash": "
|
|
149
|
+
"contentHash": "922bf0f5c403a51a5eaa0dd73a276219f3be302aa1cd122cdd1d0f279a019a12",
|
|
150
150
|
"since": "2025-01-01"
|
|
151
151
|
},
|
|
152
152
|
"job:health-check": {
|
|
@@ -1189,6 +1189,14 @@
|
|
|
1189
1189
|
"contentHash": "c258707dafb41518f376ffbab4ea3c5a824d6ab7dc9b1df5f8b8a2f7f99fbaee",
|
|
1190
1190
|
"since": "2025-01-01"
|
|
1191
1191
|
},
|
|
1192
|
+
"template:load-assess.sh": {
|
|
1193
|
+
"id": "template:load-assess.sh",
|
|
1194
|
+
"type": "template",
|
|
1195
|
+
"domain": "operations",
|
|
1196
|
+
"sourcePath": "src/templates/scripts/load-assess.sh",
|
|
1197
|
+
"contentHash": "0d8c335b167a7e46099b8636692849a48d4c0ca5722853a453d1a963427c9b88",
|
|
1198
|
+
"since": "2025-01-01"
|
|
1199
|
+
},
|
|
1192
1200
|
"template:secret-drop-retrieve.mjs": {
|
|
1193
1201
|
"id": "template:secret-drop-retrieve.mjs",
|
|
1194
1202
|
"type": "template",
|
|
@@ -1554,7 +1562,7 @@
|
|
|
1554
1562
|
"type": "subsystem",
|
|
1555
1563
|
"domain": "updates",
|
|
1556
1564
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
1557
|
-
"contentHash": "
|
|
1565
|
+
"contentHash": "922bf0f5c403a51a5eaa0dd73a276219f3be302aa1cd122cdd1d0f279a019a12",
|
|
1558
1566
|
"since": "2025-01-01"
|
|
1559
1567
|
},
|
|
1560
1568
|
"subsystem:scheduler": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// existing-agent migration there) so the two can never drift. Imported as a runtime
|
|
15
15
|
// function call inside generateClaudeMd — no module-init cycle (PostUpdateMigrator
|
|
16
16
|
// never imports templates).
|
|
17
|
-
import { PLAYWRIGHT_PROFILE_REGISTRY_CLAUDEMD_SECTION } from '../core/PostUpdateMigrator.js';
|
|
17
|
+
import { PLAYWRIGHT_PROFILE_REGISTRY_CLAUDEMD_SECTION, MACHINE_LOAD_ASSESSMENT_CLAUDEMD_SECTION } from '../core/PostUpdateMigrator.js';
|
|
18
18
|
|
|
19
19
|
export interface AgentIdentity {
|
|
20
20
|
name: string;
|
|
@@ -828,6 +828,7 @@ I declare owner/blockedOn at commitment creation; a later state change goes thro
|
|
|
828
828
|
- **The autonomous balancer surface** — \`GET /credentials/rebalancer\` (the use-it-or-lose-it drainer is Increment B; this surfaces the env-token applicability gate's verdict + WHY re-pointing would refuse, when enabled).
|
|
829
829
|
- **When to use** (PROACTIVE — these are the triggers): "flip my default account to X" / "make X my default" → \`POST /credentials/set-default\`; "which account is this session/slot on?" / "where does ~/.claude point?" → \`GET /credentials/locations\` (read it, don't infer from \`claude auth status\` — that reads a metadata file, not the live credential). Single-account agents are a no-op. (Spec: \`docs/specs/live-credential-repointing-rebalancer.md\`.)
|
|
830
830
|
${PLAYWRIGHT_PROFILE_REGISTRY_CLAUDEMD_SECTION(port)}
|
|
831
|
+
${MACHINE_LOAD_ASSESSMENT_CLAUDEMD_SECTION()}
|
|
831
832
|
**Per-Feature LLM Metrics & LLM Activity (Observable Intelligence)** — Audit what each of your LLM-driven gates/sentinels actually does: WHICH provider + model ran it, how often it ACTED (fired) vs found nothing (noop), how often it was skipped to save rate limits (shed), cost, and latency. This is the *Observable Intelligence* standard — no autonomous AI action the system takes is allowed to be invisible. Read-only observability — it never gates anything.
|
|
832
833
|
- Check: \`curl -H "Authorization: Bearer $AUTH" "http://localhost:${port}/metrics/features?sinceHours=24"\`
|
|
833
834
|
- Returns \`{ totals, features: [{ feature, frameworks, models, byModel, calls, realCalls, tokensIn, tokensOut, tokensCached, fired, noop, shed, fireRate, p50LatencyMs, p95LatencyMs, ... }] }\` — one row per system (e.g. MessagingToneGate, MessageSentinel). \`frameworks\`/\`models\` = which provider(s) actually served the call; \`fireRate\` = how often it acts; \`shed\` = skipped by the rate-limit guard. Filter with \`?feature=<name>\`.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# load-assess.sh — the DURABLE go-to method for evaluating machine load.
|
|
3
|
+
#
|
|
4
|
+
# WHY THIS EXISTS: `uptime` 1-minute load average is the WRONG signal for "can I
|
|
5
|
+
# do work / is the machine genuinely loaded." It is (a) spike-susceptible (the
|
|
6
|
+
# 1-min figure swings wildly) and (b) on macOS INFLATED by threads stuck in
|
|
7
|
+
# uninterruptible disk I/O (e.g. Spotlight/mds reindex after a cold boot) — so a
|
|
8
|
+
# high load average can coexist with a mostly-idle CPU. On 2026-06-19 a load avg
|
|
9
|
+
# of ~40 was quoted as "heavy load" when the CPU was actually 62% IDLE and the
|
|
10
|
+
# load was Spotlight reindexing, not the agent. Never repeat that.
|
|
11
|
+
#
|
|
12
|
+
# THIS reports the RIGHT signals: real CPU idle% (sampled, not instantaneous),
|
|
13
|
+
# instar's time-windowed ResourceLedger (agent-attributed CPU avg/peak over the
|
|
14
|
+
# last hour), per-core load normalization, and WHAT is consuming CPU (so you can
|
|
15
|
+
# tell "my work" from external/transient like Spotlight). Then it emits a verdict.
|
|
16
|
+
#
|
|
17
|
+
# SCOPE HONESTY: the verdict is a CPU-CAPACITY signal. It does NOT assess
|
|
18
|
+
# memory/swap, thermal throttling, or disk-I/O saturation — OK means "CPU has
|
|
19
|
+
# headroom," not "everything is fine." Memory/pressure is covered separately by
|
|
20
|
+
# the ResourceLedger / reaper-pressure surfaces.
|
|
21
|
+
#
|
|
22
|
+
# Usage: load-assess.sh (human-readable verdict)
|
|
23
|
+
# load-assess.sh --json (machine-readable; human-diagnostic only,
|
|
24
|
+
# unversioned — a programmatic consumer must
|
|
25
|
+
# add a schemaVersion first, not assume shape)
|
|
26
|
+
set -uo pipefail
|
|
27
|
+
cd "$(dirname "$0")/../.." 2>/dev/null || true # agent home (.instar/scripts -> home)
|
|
28
|
+
|
|
29
|
+
JSON=0; [ "${1:-}" = "--json" ] && JSON=1
|
|
30
|
+
OS=$(uname -s 2>/dev/null || echo unknown)
|
|
31
|
+
|
|
32
|
+
# --- cores ---
|
|
33
|
+
if [ "$OS" = "Darwin" ]; then CORES=$(sysctl -n hw.ncpu 2>/dev/null || echo 0)
|
|
34
|
+
else CORES=$(nproc 2>/dev/null || grep -c ^processor /proc/cpuinfo 2>/dev/null || echo 0); fi
|
|
35
|
+
|
|
36
|
+
# --- real CPU idle%: sampled (NOT a single instantaneous read) ---
|
|
37
|
+
IDLE=""
|
|
38
|
+
if [ "$OS" = "Darwin" ]; then
|
|
39
|
+
# macOS: top -l 2, SECOND sample is the real one (first is bogus)
|
|
40
|
+
CPU_LINE=$(top -l 2 -n 0 -s 1 2>/dev/null | grep "CPU usage" | tail -1)
|
|
41
|
+
IDLE=$(echo "$CPU_LINE" | sed -n 's/.*[, ]\([0-9.]*\)% idle.*/\1/p')
|
|
42
|
+
elif [ -r /proc/stat ]; then
|
|
43
|
+
# Linux: TWO-SAMPLE /proc/stat delta. A single read CANNOT compute idle%.
|
|
44
|
+
read_stat() { awk '/^cpu /{idle=$5+$6; tot=0; for(i=2;i<=NF;i++)tot+=$i; print idle, tot}' /proc/stat; }
|
|
45
|
+
S1=$(read_stat); sleep 1; S2=$(read_stat)
|
|
46
|
+
IDLE=$(awk -v a="$S1" -v b="$S2" 'BEGIN{
|
|
47
|
+
split(a,x," "); split(b,y," ");
|
|
48
|
+
di=y[1]-x[1]; dt=y[2]-x[2];
|
|
49
|
+
if(dt>0) printf "%.1f", 100*di/dt; else print "";
|
|
50
|
+
}')
|
|
51
|
+
fi
|
|
52
|
+
[ -z "$IDLE" ] && IDLE="" # empty => CPU read unavailable (e.g. unknown OS / no top)
|
|
53
|
+
# Test-only seam: force the sampled idle% so the verdict-threshold boundaries can be
|
|
54
|
+
# exercised deterministically (the real CPU read is environment-dependent). Read-only,
|
|
55
|
+
# affects only the printed verdict; never set in production.
|
|
56
|
+
[ -n "${LOAD_ASSESS_FORCE_IDLE:-}" ] && IDLE="$LOAD_ASSESS_FORCE_IDLE"
|
|
57
|
+
if [ -n "$IDLE" ]; then BUSY=$(awk -v i="$IDLE" 'BEGIN{printf "%.1f", 100-i}'); else BUSY=""; fi
|
|
58
|
+
|
|
59
|
+
# --- load averages (CONTEXT ONLY — never the basis of the verdict) ---
|
|
60
|
+
LOADS=$(uptime 2>/dev/null | sed -n 's/.*load average[s]*: *//p')
|
|
61
|
+
L1=$(echo "$LOADS" | awk -F'[ ,]+' '{print $1}')
|
|
62
|
+
L5=$(echo "$LOADS" | awk -F'[ ,]+' '{print $2}')
|
|
63
|
+
LOAD_PER_CORE=$(awk -v l="${L5:-0}" -v c="${CORES:-0}" 'BEGIN{if(c+0>0)printf "%.2f", l/c; else print "?"}')
|
|
64
|
+
|
|
65
|
+
# --- instar ResourceLedger: time-windowed agent-attributed CPU (the durable signal) ---
|
|
66
|
+
LEDGER="unavailable"
|
|
67
|
+
AUTH=$(node .instar/scripts/secret-get.mjs authToken 2>/dev/null || echo "")
|
|
68
|
+
PORT=$(node -pe "require('./.instar/config.json').port" 2>/dev/null || echo 4042)
|
|
69
|
+
AGENT_ID="${INSTAR_AGENT_ID:-$(node -pe "require('./.instar/config.json').projectName" 2>/dev/null || echo "")}"
|
|
70
|
+
if [ -n "$AUTH" ]; then
|
|
71
|
+
LEDGER=$(curl -s -m 8 -H "Authorization: Bearer $AUTH" -H "X-Instar-AgentId: ${AGENT_ID}" "http://localhost:${PORT}/resources/summary?sinceHours=1" 2>/dev/null \
|
|
72
|
+
| node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{const j=JSON.parse(d);const a=(j.sources||[]).find(s=>s.source==='aggregate')||{};console.log('avg='+(a.avgCpuPercent??'?')+' peak='+(a.peakCpuPercent??'?')+' current='+(a.currentCpuPercent??'?')+' samples='+(j.sampleCount??'?'))}catch(e){console.log('unavailable')}})" 2>/dev/null || echo "unavailable")
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
# --- top CPU consumers + classify my-work vs external ---
|
|
76
|
+
TOP=$(ps -Ao pcpu,comm -r 2>/dev/null | sed -n '2,4p')
|
|
77
|
+
TOP1=$(echo "$TOP" | head -1 | awk '{print $2}')
|
|
78
|
+
EXTERNAL="unknown"
|
|
79
|
+
case "$TOP1" in
|
|
80
|
+
*mds*|*mdworker*|*Spotlight*|*WindowServer*|*backupd*|*photoanalysisd*|*mediaanalysisd*) EXTERNAL="external-transient (macOS: $(basename "$TOP1" 2>/dev/null))";;
|
|
81
|
+
*instar*|*node*|*claude*|*tmux*|*python*) EXTERNAL="agent-work ($(basename "$TOP1" 2>/dev/null))";;
|
|
82
|
+
"") EXTERNAL="unknown";;
|
|
83
|
+
*) EXTERNAL="other ($(basename "$TOP1" 2>/dev/null))";;
|
|
84
|
+
esac
|
|
85
|
+
|
|
86
|
+
# --- VERDICT (based on real idle%, NOT load average) ---
|
|
87
|
+
awk_lt() { awk -v a="$1" -v b="$2" 'BEGIN{exit !(a+0<b+0)}'; }
|
|
88
|
+
if [ -z "$IDLE" ]; then
|
|
89
|
+
VERDICT="UNKNOWN"; REASON="CPU idle% unavailable on this platform; rely on the agent CPU ledger + load context"
|
|
90
|
+
elif awk_lt "$IDLE" 12; then VERDICT="SATURATED"; REASON="CPU genuinely saturated (idle <12%)";
|
|
91
|
+
elif awk_lt "$IDLE" 30; then VERDICT="ELEVATED"; REASON="CPU busy but not saturated";
|
|
92
|
+
else VERDICT="OK"; REASON="CPU mostly idle"; fi
|
|
93
|
+
|
|
94
|
+
if [ "$JSON" = "1" ]; then
|
|
95
|
+
printf '{"verdict":"%s","reason":"%s","cpuIdlePercent":%s,"cpuBusyPercent":%s,"cores":%s,"loadAvg1":"%s","loadAvg5":"%s","loadPerCore":"%s","ledger":"%s","topConsumer":"%s","topClass":"%s","scope":"cpu-capacity-only","os":"%s"}\n' \
|
|
96
|
+
"$VERDICT" "$REASON" "${IDLE:-null}" "${BUSY:-null}" "${CORES:-0}" "${L1:-}" "${L5:-}" "$LOAD_PER_CORE" "$LEDGER" "${TOP1:-}" "$EXTERNAL" "$OS"
|
|
97
|
+
else
|
|
98
|
+
echo "=== MACHINE LOAD ASSESSMENT ==="
|
|
99
|
+
echo "VERDICT: $VERDICT — $REASON"
|
|
100
|
+
echo " (scope: CPU capacity only — does NOT assess memory/swap/thermal/disk-IO)"
|
|
101
|
+
echo ""
|
|
102
|
+
echo "Real CPU: ${BUSY:-?}% busy / ${IDLE:-?}% idle (sampled, the primary signal)"
|
|
103
|
+
echo "Cores: ${CORES:-?} logical"
|
|
104
|
+
echo "Agent CPU (1h): $LEDGER (instar ResourceLedger, time-windowed)"
|
|
105
|
+
echo "Top consumer: ${TOP1:-?} → $EXTERNAL"
|
|
106
|
+
echo "Load avg (ctx): 1m=${L1:-?} 5m=${L5:-?} (per-core ${LOAD_PER_CORE}) ← context only; spike-prone + I/O-inflated, NOT the verdict"
|
|
107
|
+
echo ""
|
|
108
|
+
echo "Top 3 CPU:"; echo "$TOP" | sed 's/^/ /'
|
|
109
|
+
echo ""
|
|
110
|
+
echo "Interpretation: trust the real CPU idle% + the time-windowed agent CPU."
|
|
111
|
+
echo "A high load average with high idle% = external/transient (e.g. Spotlight), NOT agent pressure."
|
|
112
|
+
fi
|
|
113
|
+
exit 0
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
Adds a machine × account matrix on the dashboard Subscriptions tab — the on-demand "put account X on machine Y" surface that was missing (the account-follow-me Approve cards are quota-driven and never offered accounts on demand, so adding accounts to another machine meant a clunky chat dance). Rows are accounts, columns are machines; each cell is a ✓ (active there), a "Set up" button (not yet), or an honest in-progress / needs-reauth / offline / held state. Tapping "Set up" runs the whole sign-in IN the dashboard: it PIN-checks (operator presence — the agent shares the Bearer token, so the dashboard PIN is what proves a human is acting), drives the existing PIN→mandate→enroll-start chain to start a fresh login on the target machine (that machine re-mints its own login, ToS-safe), shows the auth link + a code box, and the shipped code-paste-back relay finishes it — flipping the cell to ✓. The wrong-account safety (S7 email-gate) and cross-machine delivery are reused unchanged. Dev-gated (`multiMachine.accountFollowMe`), dark on the fleet.
|
|
9
9
|
|
|
10
|
+
Structurally enforces the `code=t` lesson (the broken account-follow-me sign-in link, 2026-06-18): a parser of untrusted real-world text must be tested against a byte-for-byte REAL captured fixture, not a hand-authored clean string. Adds a Testing-Integrity standard, a `tests/fixtures/captured/` convention (structural bytes sacrosanct; secrets swapped for same-shape, grammar-valid placeholders via a tested redaction helper; one provenance sidecar per capture), and a registry-driven lint `scripts/lint-scrape-fixture-realness.js`. Each registered parser (seeded with `FrameworkLoginDriver.parseArtifact`) must have a test that loads a captured fixture through the single `loadCapturedFixture` helper, feeds it to the parser, and asserts — and the suite runs that test, so the realness is executed, not grepped. A non-blocking `parse*`/`scrape*` register-or-justify warning re-surfaces new parsers. The original `code=t` capture is migrated to disk (secrets redacted, hard-wrap preserved). No runtime code changes.
|
|
11
|
+
|
|
10
12
|
## What to Tell Your User
|
|
11
13
|
|
|
12
14
|
There's now a grid on the Subscriptions tab showing which of your accounts are signed in on which machines, at a glance. To add an account to another machine, tap the empty cell, enter your dashboard PIN, sign in on the page it opens, and paste the code right there — it sets up that machine and the cell turns into a check mark. No more routing sign-in codes through chat.
|
|
@@ -21,3 +23,8 @@ There's now a grid on the Subscriptions tab showing which of your accounts are s
|
|
|
21
23
|
- `tests/unit/subscriptions-render.test.ts` — matrix renders ✓ for active, "Set up" for empty, a disabled offline column for a `pool.failed` machine (no fabricated ✓), in-progress for a pending login.
|
|
22
24
|
- `tests/unit/follow-me-controller-wiring.test.ts` — a "Set up" tap with a PIN POSTs start-cell {accountId, machineId, pin}; no-PIN does not POST.
|
|
23
25
|
- `npx tsc --noEmit` clean; `npm run lint` (full battery) clean; 47 tests green.
|
|
26
|
+
|
|
27
|
+
- `tests/unit/lint-scrape-fixture-realness.test.ts` (10) — both boundary sides: the shipped registry entry passes; tampered cases (missing test, removed loader, missing/invalid sidecar) fail.
|
|
28
|
+
- `tests/unit/redact-captured-fixture.test.ts` (8) — same-length, line-position/wrap preservation, redacted URL still parses, length-changing redaction rejected.
|
|
29
|
+
- `tests/unit/framework-login-driver.test.ts` (17) — the migrated realness test loads the disk fixture, asserts the full de-wrapped URL ≠ `code=t`.
|
|
30
|
+
- `node scripts/lint-scrape-fixture-realness.js` exits 0 (seed entry clean + register-or-justify warning); `npm run lint` (full battery) exits 0; `tsc --noEmit` clean.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
Added `load-assess.sh` — a robust, durable, go-to method for an agent to evaluate machine load — and shipped it fleet-wide. It reports the RIGHT signals (real CPU idle% sampled, instar's time-windowed ResourceLedger agent-CPU, per-core load, and what's actually consuming CPU) and emits a verdict (OK / ELEVATED / SATURATED), instead of the spike-prone, macOS-Spotlight-I/O-inflated `uptime` 1-minute load average. A static "use load-assess.sh, never trust the load average" reminder is wired into the session-start hook ABOVE its compact-`exec` delegate, so it survives compaction (not just session start), and a Machine Load Assessment section is added to the CLAUDE.md template (generate + migrate) so every agent knows the capability exists.
|
|
9
|
+
|
|
10
|
+
## What to Tell Your User
|
|
11
|
+
|
|
12
|
+
Your agent now judges whether the machine is genuinely busy using real CPU idle% (and its own recent CPU use), not the misleading 1-minute load average — so it won't mistake a quiet-but-disk-indexing machine for an overloaded one and unnecessarily hold off on work. It's read-only: it measures and reports, changing nothing.
|
|
13
|
+
|
|
14
|
+
## Summary of New Capabilities
|
|
15
|
+
|
|
16
|
+
- `.instar/scripts/load-assess.sh` (`--json` to parse) — go-to machine-load assessment with a verdict; CPU-capacity-scoped (does not assess memory/thermal). Installed on every agent on update.
|
|
17
|
+
|
|
18
|
+
## Evidence
|
|
19
|
+
|
|
20
|
+
- 14 new tests pass: verdict thresholds (both sides of each boundary via a `LOAD_ASSESS_FORCE_IDLE` test seam), `--json` contract, fail-soft when the ResourceLedger is unreachable, the compaction-survival property (`blockIdx < execIdx` in `getSessionStartHook()`), `migrateScripts` install (always-overwrite, executable), and `migrateClaudeMd` idempotent append.
|
|
21
|
+
- 568 existing PostUpdateMigrator + scaffold tests still green (no regression).
|
|
22
|
+
- Independent second-pass review (touches compaction) concurred after live simulation — bash builtin `echo` writes directly to fd 1, so the awareness block's stdout reaches the captured output before the process-replacing `exec` on the compact path.
|
|
23
|
+
- Spec converged through `/spec-converge` (2 rounds, `cross-model-review: codex-cli:gpt-5.5`); the review caught two critical bugs in the first draft (editing a dead template file; a mechanically-false compaction guarantee) before any code was written.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Side-Effects Review — Robust Load Assessment (fleet-wide + compaction-surviving)
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `robust-load-assessment-fleet`
|
|
4
|
+
**Date:** 2026-06-19
|
|
5
|
+
**Author:** echo
|
|
6
|
+
**Second-pass reviewer:** echo-spawned reviewer subagent (required — touches compaction)
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Ships a read-only machine-load diagnostic (`load-assess.sh`) to every agent as a script template, wires a static "use load-assess.sh / never trust the uptime load average" awareness block into the in-code session-start hook ABOVE its compact-`exec` delegate (so it survives compaction), and adds an Agent-Awareness CLAUDE.md section (generate + migrate). Born from a 2026-06-19 incident where the agent misread the spike-prone, Spotlight-I/O-inflated 1-minute load average as "heavy load" while the CPU was ~60% idle. Three source files + two test files; 14 new tests, 568 existing PostUpdateMigrator/scaffold tests still green.
|
|
11
|
+
|
|
12
|
+
## Decision-point inventory
|
|
13
|
+
|
|
14
|
+
- `load-assess.sh` verdict (OK/ELEVATED/SATURATED) — **add** — produces a SIGNAL (a load verdict printed to stdout); holds **zero** blocking authority. Nothing consumes it as a gate.
|
|
15
|
+
- session-start hook output — **modify** (additive) — adds a static doc block; no conditional logic, no decision.
|
|
16
|
+
- `migrateScripts` / `migrateClaudeMd` — **add** (install + append) — idempotent, content-sniffed; no decision surface.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. Over-block
|
|
21
|
+
No block/allow surface — over-block not applicable. The script reads CPU/ledger and prints; the hook emits a static string. Nothing is rejected or gated.
|
|
22
|
+
|
|
23
|
+
## 2. Under-block
|
|
24
|
+
No block/allow surface — under-block not applicable. The change adds no enforcement, so there is no failure mode to "miss." (The script's verdict is advisory: a human/agent reading "OK" still makes the call. Scope honesty is built in — the verdict explicitly states it is CPU-capacity only, not a universal health oracle, so a reader does not over-trust an OK on a memory/thermal-pressured box.)
|
|
25
|
+
|
|
26
|
+
## 3. Level-of-abstraction fit
|
|
27
|
+
Right layer. A diagnostic script lives in `.instar/scripts/` alongside `secret-get.mjs`/`emit-session-clock.sh` (the established sibling pattern); the awareness lives in the session-start hook (the existing always-fires-on-lifecycle surface) and the CLAUDE.md template (the canonical agent-awareness surface). No smarter gate should own this — there is no gate; it is read-only observability feeding the agent's own judgment. The time-windowed signal it surfaces (ResourceLedger) is consumed, not duplicated.
|
|
28
|
+
|
|
29
|
+
## 4. Signal vs authority compliance
|
|
30
|
+
Compliant (`docs/signal-vs-authority.md`). `load-assess.sh` is a pure **detector/signal** — it computes a load verdict and prints it, with no power to block, delay, or rewrite anything. It does not add brittle logic with blocking authority; it adds a read-only signal a smart authority (the agent) consumes. The hook block and CLAUDE.md section are documentation, not decision points.
|
|
31
|
+
|
|
32
|
+
## 5. Interactions
|
|
33
|
+
- The hook block is placed ABOVE the `exec compaction-recovery.sh` branch so it is emitted on every event (startup/resume/clear/compact); it does not shadow or get shadowed by the recovery delegation (verified by a test asserting `blockIdx < execIdx`). It adds a few lines of static stdout to a hook that already emits many — no latency (no network), and the block precedes no `exit N` (the hook ends on an `echo`, which exits 0), so it cannot change the exit code. (Compaction-survival rests on bash builtin `echo` writing directly to fd 1 with no userspace stdio buffer for the subsequent `exec` to discard — verified empirically by the second-pass reviewer across tty/pipe/file-redirect.)
|
|
34
|
+
- `migrateScripts` adds a sibling install next to `secret-get.mjs`; independent try/catch, cannot affect the other script installs.
|
|
35
|
+
- `migrateClaudeMd` appends a content-sniffed section (`!includes('Machine Load Assessment')`) — idempotent, does not duplicate on re-run (tested), does not edit other sections in place.
|
|
36
|
+
- The CLAUDE.md section text is single-sourced (`MACHINE_LOAD_ASSESSMENT_CLAUDEMD_SECTION()`) and used by BOTH generate (new agents) and migrate (existing) — they cannot drift (tested).
|
|
37
|
+
|
|
38
|
+
## 6. External surfaces
|
|
39
|
+
- The script reads the existing `GET /resources/summary` endpoint (read-only; no new surface) and degrades to local-only if it is unreachable (fail-soft, tested). No new external API.
|
|
40
|
+
- `--json` is documented human-diagnostic-only and unversioned — no system consumes it; a future programmatic consumer must add a `schemaVersion` first (stated in the script + spec).
|
|
41
|
+
- The hook output is agent-internal stdout, not visible to other agents/users/systems.
|
|
42
|
+
- No timing/conversation-state dependence: the script samples CPU on demand; the hook block is static. A test-only `LOAD_ASSESS_FORCE_IDLE` env seam exists (read-only, affects only the printed verdict for boundary testing; never set in production).
|
|
43
|
+
|
|
44
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
45
|
+
- `load-assess.sh` — **machine-local BY DESIGN**: load is a property of the machine the script runs on; there is nothing to replicate. Cross-machine load reads are already served separately by `/guards?scope=pool` and `/resources/summary`.
|
|
46
|
+
- The hook block and CLAUDE.md section — **machine-local static template content**, installed identically on every machine by each machine's own migration; no replication needed, no strand-on-transfer risk (no durable per-topic state), no generated URLs.
|
|
47
|
+
|
|
48
|
+
## 8. Rollback cost
|
|
49
|
+
Low. Revert the PR (3 source files). The change is additive and idempotent: reverting stops shipping the script template + hook block + CLAUDE.md section to future migrations. Agents that already migrated keep a harmless read-only `load-assess.sh` on disk (no cleanup required; it gates nothing). No data migration, no agent-state repair. A hot-fix release is sufficient if needed.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Second-pass review (required — touches compaction)
|
|
54
|
+
|
|
55
|
+
**Reviewer:** echo-spawned independent reviewer subagent. **Verdict: Concur with the review.**
|
|
56
|
+
|
|
57
|
+
The reviewer independently audited the 4 additive blocks, ran the 14 tests, AND ran live simulations rather than trusting the framing:
|
|
58
|
+
1. **Compaction-survival — TRUE (verified by execution):** simulated the hook with stdout to a tty, a pipe, and a file redirect with the compact `exec` actually firing — the MACHINE LOAD block appeared before the delegate's output in every case. Robust because bash builtin `echo` writes via `write(2)` directly to fd 1 (no userspace stdio buffer for `exec` to discard); bytes are in the kernel before `exec` runs. The non-executable-recovery fallback also behaves correctly (exec skipped, block still emitted, hook continues).
|
|
59
|
+
2. **Timeout/exit code — no risk:** static echoes, zero network; precedes no `exit N`.
|
|
60
|
+
3. **Script safety — sound:** `set -uo pipefail` with NO `set -e`; ran under stripped env / empty-IDLE / faked unknown-OS — all exit 0 with a clean verdict (UNKNOWN + null JSON on genuine no-CPU-read, never a crash). All `set -u`-sensitive vars assigned before use; verdict chain exhaustive (VERDICT+REASON on every branch); `bash -n` clean.
|
|
61
|
+
4. **Test `blockIdx < execIdx`** pins the real property; combined with both-boundary script tests + the empirically-confirmed flush-survives-exec behavior, the guarantee is covered.
|
|
62
|
+
5. **Packaging — sound:** `loadRelayTemplate('load-assess.sh')` resolves via `src/templates/scripts/`, which IS in package.json `files` (ships to npm) — the same proven mechanism as `secret-get.mjs`. Content-sniff anchor `'Machine Load Assessment'` is unique (no cross-section collision); idempotency confirmed count==1 after repeated runs.
|
|
63
|
+
|
|
64
|
+
No concerns raised.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## CI-conformance follow-up (post-open, #1231)
|
|
69
|
+
|
|
70
|
+
CI shard 4/4 surfaced two required-conformance gaps (caught by the full suite, not my local subset run):
|
|
71
|
+
- `load-assess.sh`'s localhost API call to `/resources/summary` lacked the `X-Instar-AgentId` header that `template-agent-id-header.test.ts` requires of every Bearer call in a template. Added (AGENT_ID derived from `INSTAR_AGENT_ID`/config.json projectName, same as session-start.sh). No behavior change — the header is identification only; the call already fail-softs.
|
|
72
|
+
- The `Machine Load Assessment` migrateClaudeMd section was not registered in `feature-delivery-completeness.test.ts`'s `legacyMigratorSections` tracking list. Added (observe-only, ships ON, no framework-shadow marker → legacy migrator list, not featureSections). No runtime change — a test-registry entry.
|
|
73
|
+
|
|
74
|
+
Both are conformance fixes to the same change; the design + second-pass review above stand unchanged.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Side-effects review — Scrape/Parser fixture-realness enforcement
|
|
2
|
+
|
|
3
|
+
Spec: `docs/specs/scrape-fixture-realness.md` (converged @ iter 4, approved) · ELI16: `docs/specs/scrape-fixture-realness.eli16.md`
|
|
4
|
+
Parent principle: Testing Integrity
|
|
5
|
+
|
|
6
|
+
## What the change is
|
|
7
|
+
|
|
8
|
+
Structural enforcement of the `code=t` lesson: a parser of untrusted real-world text must be tested against a byte-for-byte REAL captured fixture, not a hand-authored clean string. Adds (1) a registry standard, (2) a `tests/fixtures/captured/` convention with secret-redaction + provenance sidecars, (3) a registry-driven lint `scripts/lint-scrape-fixture-realness.js` that requires each registered parser's test to load a captured fixture via `loadCapturedFixture`, feed it to the parser, and assert — plus a non-blocking register-or-justify warning for un-registered `parse*`/`scrape*` exports. No runtime code changes.
|
|
9
|
+
|
|
10
|
+
Files: `scripts/lint-scrape-fixture-realness.js`, `scripts/redact-captured-fixture.mjs`, `tests/helpers/loadCapturedFixture.ts`, `tests/fixtures/captured/**`, `docs/STANDARDS-REGISTRY.md`, `package.json` (lint chain), `scripts/pre-push-gate.js` (direct invocation), `tests/unit/framework-login-driver.test.ts` (migrated), + tests for the lint and the redaction helper.
|
|
11
|
+
|
|
12
|
+
## 1. Over-block — legitimate inputs rejected that shouldn't be
|
|
13
|
+
The lint only enforces realness for parsers EXPLICITLY in the `SCRAPE_PARSERS` registry (seeded with one). It never fires on un-registered code — so it cannot false-positive a normal test. The register-or-justify check is a non-blocking WARNING (exit code unaffected). Near-zero over-block by construction (FD1).
|
|
14
|
+
|
|
15
|
+
## 2. Under-block — failure modes still missed
|
|
16
|
+
- The lint proves the registered test loads-feeds-asserts; it cannot prove the assertion is non-trivial (a deliberately weak `expect`) — owned as a review concern (FD6).
|
|
17
|
+
- It cannot prove un-redacted bytes were genuinely real (provenance is review-checkable, not machine-verifiable) — owned (FD2).
|
|
18
|
+
- Inline/method/private parsers aren't caught by the `parse*`/`scrape*` export scan — the PR register-or-justify trigger (review) is primary; the warning is a backstop (FD3). This is the conformance gate's noted Structure-vs-Willpower residual, accepted because full coverage needs the unbounded heuristic FD1 rejects.
|
|
19
|
+
|
|
20
|
+
## 3. Level-of-abstraction fit
|
|
21
|
+
Correct layer: a build-time lint alongside the existing `lint-*` family, run via `npm run lint` (the real battery) + the pre-push gate. The redaction helper sits in `scripts/` with its peers. The fixture convention sits under `tests/fixtures/`. No runtime layer touched.
|
|
22
|
+
|
|
23
|
+
## 4. Signal vs authority compliance
|
|
24
|
+
A hard-blocking lint over a CURATED registry — legitimate per Signal-vs-Authority because the false-positive surface is near-zero by construction (identical posture to `lint-no-direct-llm-http` / `lint-dev-agent-dark-gate`, both hard-block on curated lists). The register-or-justify check is signal-only (warning, never blocks). No brittle blocking authority over messages/sessions.
|
|
25
|
+
|
|
26
|
+
## 5. Interactions
|
|
27
|
+
- Adds one entry to the `npm run lint` `&&`-chain (ordering-independent; each lint is self-contained) + a direct pre-push invocation (mirrors the two existing direct lints). No shadowing/double-fire.
|
|
28
|
+
- The migrated `framework-login-driver` realness test now loads from disk via `loadCapturedFixture` instead of an inline const; the de-wrap assertion (full URL ≠ `code=t`) is unchanged, so the regression guard and the realness convention reinforce each other.
|
|
29
|
+
- The redaction helper is a new dependency of the fixture-authoring flow; it carries its own unit tests so a redaction bug can't silently produce a passing-but-fake fixture.
|
|
30
|
+
|
|
31
|
+
## 6. External surfaces
|
|
32
|
+
None at runtime. Build-time only: a new lint contributors run via `npm run lint`; a new standard in the registry; a new fixtures dir. Nothing visible to users, other agents, or other systems.
|
|
33
|
+
|
|
34
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
35
|
+
Machine-local by design (FD4): build-time lint over the committed source tree + committed fixtures. No runtime surface, no state, no cross-machine behavior. Every machine builds the identical repo and runs the identical lint over the identical fixtures.
|
|
36
|
+
|
|
37
|
+
## 8. Rollback cost
|
|
38
|
+
Cheap. Revert the new files + the three small wiring edits (package.json, pre-push-gate.js, the migrated test). No data migration, no runtime/state. The migrated fixture can revert to an inline const if ever needed (the assertion is unchanged).
|
|
39
|
+
|
|
40
|
+
## Second-pass (high-risk: "lint"/gate)
|
|
41
|
+
The lint's core (`checkTest`) was independently re-read against the spec: it requires, within the registry-named test, a `loadCapturedFixture('<slug>')` assigned to a var, that var passed as the first arg to the registered parser symbol (member-expression accepted), and an `expect(`. The sidecar check validates required fields + ISO timestamp. Matches the spec's canonical-shape matcher; the realness is executed (the suite runs the named test). Concur.
|
|
42
|
+
|
|
43
|
+
## Follow-up fix (CI regressions)
|
|
44
|
+
|
|
45
|
+
Two regressions this PR introduced were caught by CI (not the 3 files I first ran) and fixed:
|
|
46
|
+
1. **Dangling ref:** the standard cited the `SCRAPE_PARSERS` token; the standards-enforcement-auditor resolves backticked `FOO_BAR` tokens as `src/**` symbols, and this one lives in `scripts/`, so it never resolved → danglingCount 0→1. Rephrased the standard to "a curated parser registry" (no marker token). Re-verified danglingCount=0.
|
|
47
|
+
- Over-block/Under-block: none — the lint's behavior is unchanged; only the registry prose changed.
|
|
48
|
+
2. **Pre-push-gate scratch test:** the direct lint invocation added to `scripts/pre-push-gate.js` ran against the gate's resolved ROOT, which is a scratch dir in the gate's own unit tests (where the registered fixtures don't exist) → status 1. Removed the redundant direct invocation; the lint is enforced via the `npm run lint` chain that CI runs (authoritative). No loss of enforcement.
|
|
49
|
+
- Rollback cost: trivial (re-add the block if a future need arises, guarded for scratch).
|