substrate-ai 0.20.49 → 0.20.50
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/package.json
CHANGED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Probe-Author State-Integrating Defect Corpus
|
|
3
|
+
#
|
|
4
|
+
# Version: v1 (2026-05-03)
|
|
5
|
+
# Substrate version when corpus authored: v0.20.49
|
|
6
|
+
#
|
|
7
|
+
# Purpose: Oracle for the state-integrating eval harness
|
|
8
|
+
# (Story 65-3, scripts/eval-probe-author-state-integrating.mjs).
|
|
9
|
+
# Each entry documents a defect class where the broken implementation
|
|
10
|
+
# reads/writes/queries external state incorrectly. The eval dispatches
|
|
11
|
+
# probe-author against each entry's source_ac and asserts that the
|
|
12
|
+
# authored probe's shape matches the entry's signature regexes.
|
|
13
|
+
#
|
|
14
|
+
# Schema (each applicable_entries item):
|
|
15
|
+
# id — unique kebab-label
|
|
16
|
+
# story_key — optional; reference only
|
|
17
|
+
# description — one-line human label
|
|
18
|
+
# source_ac — AC text sent to probe-author
|
|
19
|
+
# broken_implementation — what the broken impl does
|
|
20
|
+
# real_state_condition — the real-state condition that breaks it
|
|
21
|
+
# signature — non-empty list of regex strings; ALL must
|
|
22
|
+
# match JSON.stringify(probe) for ANY probe
|
|
23
|
+
# mock_authored_probes — ≥1 probe; used in --dry-run mode
|
|
24
|
+
##
|
|
25
|
+
|
|
26
|
+
applicable_entries:
|
|
27
|
+
- id: entry-1-obs017-git-log-wrong-cwd
|
|
28
|
+
story_key: '2-4'
|
|
29
|
+
description: git log called with cwd=fleetRoot instead of per-project directory
|
|
30
|
+
source_ac: |
|
|
31
|
+
For each project repository in the fleet, the morning briefing generator
|
|
32
|
+
reads the most recent 10 commits authored in the last 24 hours using
|
|
33
|
+
`git log --since=24h --format="%H %s" --no-merges`. Attribution must be
|
|
34
|
+
per-project: commits from repository A must not appear in the briefing
|
|
35
|
+
for repository B. The implementation invokes `git log` with the correct
|
|
36
|
+
`cwd` set to each project's root directory.
|
|
37
|
+
broken_implementation: |
|
|
38
|
+
fetchGitLog() calls `execSync('git log ...', { cwd: fleetRoot })` where
|
|
39
|
+
fleetRoot is the top-level directory containing all project subdirectories.
|
|
40
|
+
All commits from all repos are attributed to every project, causing
|
|
41
|
+
cross-project commit leakage.
|
|
42
|
+
real_state_condition: |
|
|
43
|
+
Two or more git repositories exist as sibling directories under a common
|
|
44
|
+
parent. Each repo has distinct commits. The broken implementation returns
|
|
45
|
+
all commits regardless of which project directory is requested.
|
|
46
|
+
signature:
|
|
47
|
+
- 'git\s+log'
|
|
48
|
+
- 'alpha|beta|fleet|project.?[AB]|repo.?[12]|tmpdir|mkdtemp'
|
|
49
|
+
mock_authored_probes:
|
|
50
|
+
- name: per-project-git-log-attribution
|
|
51
|
+
sandbox: host
|
|
52
|
+
command: |
|
|
53
|
+
# Create two sibling repos with distinct commits
|
|
54
|
+
PARENT=$(mktemp -d)
|
|
55
|
+
mkdir -p "$PARENT/repo-alpha" "$PARENT/repo-beta"
|
|
56
|
+
cd "$PARENT/repo-alpha" && git init && git config user.email "t@t" && git config user.name "T"
|
|
57
|
+
echo "alpha" > a.txt && git add . && git commit -m "alpha commit"
|
|
58
|
+
cd "$PARENT/repo-beta" && git init && git config user.email "t@t" && git config user.name "T"
|
|
59
|
+
echo "beta" > b.txt && git add . && git commit -m "beta commit"
|
|
60
|
+
# Probe: verify git log is called per-project, not for the fleet root
|
|
61
|
+
# Run git log for repo-alpha and confirm only alpha commits appear
|
|
62
|
+
OUTPUT=$(cd "$PARENT/repo-alpha" && git log --format="%s" 2>&1)
|
|
63
|
+
echo "$OUTPUT"
|
|
64
|
+
echo "$OUTPUT" | grep -q "alpha commit" && echo "alpha-found" || echo "alpha-missing"
|
|
65
|
+
echo "$OUTPUT" | grep -q "beta commit" && echo "beta-found" || echo "beta-missing"
|
|
66
|
+
expect_stdout_regex:
|
|
67
|
+
- 'alpha-found'
|
|
68
|
+
expect_stdout_no_regex:
|
|
69
|
+
- 'beta-found'
|
|
70
|
+
|
|
71
|
+
- id: entry-2-subprocess-synthesized-vs-real
|
|
72
|
+
story_key: '2-5'
|
|
73
|
+
description: npm outdated called with mocked input instead of real subprocess
|
|
74
|
+
source_ac: |
|
|
75
|
+
The dependency staleness checker invokes `npm outdated --json` as a real
|
|
76
|
+
subprocess in the project directory. The output JSON is parsed to identify
|
|
77
|
+
packages where the `current` version is behind `wanted` or `latest`. The
|
|
78
|
+
implementation must NOT use cached or synthetic data; it must invoke npm
|
|
79
|
+
as an external process each time.
|
|
80
|
+
broken_implementation: |
|
|
81
|
+
runDependencyCheck() returns a hardcoded JSON fixture `{ "lodash": { "current":
|
|
82
|
+
"4.17.20", "wanted": "4.17.21", "latest": "4.17.21" } }` instead of
|
|
83
|
+
spawning a real npm process. Tests pass but the feature silently shows
|
|
84
|
+
stale data in production.
|
|
85
|
+
real_state_condition: |
|
|
86
|
+
A real npm project directory with a package.json exists on disk. The
|
|
87
|
+
real npm outdated output differs from the hardcoded fixture (either
|
|
88
|
+
empty or different packages).
|
|
89
|
+
signature:
|
|
90
|
+
- 'npm\s+outdated'
|
|
91
|
+
- 'current|wanted|latest|outdated'
|
|
92
|
+
mock_authored_probes:
|
|
93
|
+
- name: npm-outdated-real-subprocess
|
|
94
|
+
sandbox: host
|
|
95
|
+
command: |
|
|
96
|
+
# Create a minimal npm project
|
|
97
|
+
TMPDIR=$(mktemp -d)
|
|
98
|
+
cd "$TMPDIR"
|
|
99
|
+
echo '{"name":"probe-test","version":"1.0.0","dependencies":{}}' > package.json
|
|
100
|
+
npm install --silent
|
|
101
|
+
# Run the implementation — it must invoke npm outdated, not return a fixture
|
|
102
|
+
node dist/cli/index.js dependency-check --project "$TMPDIR" --output json
|
|
103
|
+
expect_stdout_regex:
|
|
104
|
+
- '\{|\[|dependencies|outdated|packages'
|
|
105
|
+
expect_stdout_no_regex:
|
|
106
|
+
- 'fixture|mock|synthetic|hardcoded'
|
|
107
|
+
|
|
108
|
+
- id: entry-3-tilde-path-not-expanded
|
|
109
|
+
story_key: '2-6'
|
|
110
|
+
description: fs.readFileSync called with literal tilde path instead of expanded home directory
|
|
111
|
+
source_ac: |
|
|
112
|
+
The configuration reader reads the user's config file at `~/.config/myapp/config.json`.
|
|
113
|
+
The path must be expanded to the actual home directory before reading. The implementation
|
|
114
|
+
uses `os.homedir()` or equivalent to resolve `~` to the absolute path. A literal
|
|
115
|
+
`~` in the path passed to `fs.readFileSync` is not a valid filesystem path on Linux/macOS.
|
|
116
|
+
broken_implementation: |
|
|
117
|
+
configReader() calls `fs.readFileSync('~/.config/myapp/config.json', 'utf8')`.
|
|
118
|
+
The literal tilde is not expanded by Node.js's fs module, causing ENOENT
|
|
119
|
+
on every read even when the config file exists at the real path.
|
|
120
|
+
real_state_condition: |
|
|
121
|
+
The config file exists at the real expanded path (e.g., /home/user/.config/myapp/config.json)
|
|
122
|
+
but does NOT exist at the literal path `~/.config/myapp/config.json`. The broken
|
|
123
|
+
implementation throws ENOENT while the correct implementation reads successfully.
|
|
124
|
+
signature:
|
|
125
|
+
- 'HOME|homedir\(\)|\$HOME|home.*dir'
|
|
126
|
+
- '\.config|config\.json|tilde|~'
|
|
127
|
+
mock_authored_probes:
|
|
128
|
+
- name: config-path-tilde-expansion
|
|
129
|
+
sandbox: host
|
|
130
|
+
command: |
|
|
131
|
+
# Ensure config file exists at real expanded path
|
|
132
|
+
REAL_CONFIG="$HOME/.config/myapp/config.json"
|
|
133
|
+
mkdir -p "$(dirname "$REAL_CONFIG")"
|
|
134
|
+
echo '{"setting":"value"}' > "$REAL_CONFIG"
|
|
135
|
+
# Implementation must read it successfully
|
|
136
|
+
node dist/cli/index.js config read
|
|
137
|
+
expect_stdout_regex:
|
|
138
|
+
- 'setting|value|config'
|
|
139
|
+
expect_stdout_no_regex:
|
|
140
|
+
- 'ENOENT|no such file|tilde'
|
|
141
|
+
|
|
142
|
+
- id: entry-4-db-mocked-vs-real
|
|
143
|
+
story_key: '2-7'
|
|
144
|
+
description: DB query returns canned response instead of real Dolt wg_stories state
|
|
145
|
+
source_ac: |
|
|
146
|
+
The sprint planning report queries the `wg_stories` Dolt table for all
|
|
147
|
+
stories with `status = 'PLANNED'` in the current sprint. The query must
|
|
148
|
+
execute against the live Dolt database; the result count must reflect
|
|
149
|
+
the actual number of planned stories. Using an in-memory mock or
|
|
150
|
+
hardcoded fixture is not acceptable.
|
|
151
|
+
broken_implementation: |
|
|
152
|
+
queryPlannedStories() returns a hardcoded array `[{ id: 'fake-1', status:
|
|
153
|
+
'PLANNED', sprint: 1 }]` without connecting to Dolt. The sprint planning
|
|
154
|
+
report always shows 1 planned story regardless of actual database state.
|
|
155
|
+
real_state_condition: |
|
|
156
|
+
The Dolt database has 0 or ≥2 planned stories. The broken implementation
|
|
157
|
+
always returns exactly 1, masking the real state.
|
|
158
|
+
signature:
|
|
159
|
+
- 'dolt|mysql|wg_stories|planned.stories'
|
|
160
|
+
- 'PLANNED|status.*planned|count|rowCount'
|
|
161
|
+
mock_authored_probes:
|
|
162
|
+
- name: wg-stories-planned-count-from-db
|
|
163
|
+
sandbox: host
|
|
164
|
+
command: |
|
|
165
|
+
# Query the real Dolt database for planned stories
|
|
166
|
+
node dist/cli/index.js status --output-format json | \
|
|
167
|
+
node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); \
|
|
168
|
+
console.log(JSON.stringify({planned: (d.stories||[]).filter(s=>s.status==='PLANNED').length}))"
|
|
169
|
+
expect_stdout_regex:
|
|
170
|
+
- 'planned'
|
|
171
|
+
expect_stdout_no_regex:
|
|
172
|
+
- 'mock|fixture|fake|hardcoded'
|
|
173
|
+
|
|
174
|
+
- id: entry-5-network-mocked-vs-real
|
|
175
|
+
story_key: '2-8'
|
|
176
|
+
description: npm registry fetch intercepted by test double instead of real network call
|
|
177
|
+
source_ac: |
|
|
178
|
+
The version checker fetches the latest published version of a package from
|
|
179
|
+
the npm registry using `npm view <package> version` or `https://registry.npmjs.org/<package>/latest`.
|
|
180
|
+
The fetch must reach the real npm registry; intercepted or cached responses
|
|
181
|
+
are not acceptable. The result is compared against the locally installed version.
|
|
182
|
+
broken_implementation: |
|
|
183
|
+
getLatestVersion() returns a hardcoded version string `"1.2.3"` without
|
|
184
|
+
making any network request. The comparison always uses stale data, masking
|
|
185
|
+
cases where the registry has a newer version.
|
|
186
|
+
real_state_condition: |
|
|
187
|
+
The real npm registry has a version for the package that may differ from
|
|
188
|
+
the hardcoded `"1.2.3"`. The broken implementation always returns `"1.2.3"`.
|
|
189
|
+
signature:
|
|
190
|
+
- 'npm\s+view|registry\.npmjs|npm.*version'
|
|
191
|
+
- 'latest|version|registry|current'
|
|
192
|
+
mock_authored_probes:
|
|
193
|
+
- name: npm-registry-fetch-real-version
|
|
194
|
+
sandbox: host
|
|
195
|
+
command: |
|
|
196
|
+
# Verify the version checker reaches the real registry
|
|
197
|
+
node dist/cli/index.js check-version --package js-yaml --output json
|
|
198
|
+
expect_stdout_regex:
|
|
199
|
+
- 'version|latest|current'
|
|
200
|
+
expect_stdout_no_regex:
|
|
201
|
+
- '1\.2\.3|hardcoded|mock|fixture'
|
|
202
|
+
|
|
203
|
+
- id: entry-6-registry-scan-single-vs-multi
|
|
204
|
+
story_key: '2-9'
|
|
205
|
+
description: registry scan passes on single-package workspace but fails on multi-package monorepo
|
|
206
|
+
source_ac: |
|
|
207
|
+
The workspace version-constraint scanner reads all `package.json` files in
|
|
208
|
+
a monorepo workspace and reports packages where the declared version in one
|
|
209
|
+
workspace package conflicts with the version declared in another. The scanner
|
|
210
|
+
must handle workspaces with ≥2 packages. A single-package workspace is not
|
|
211
|
+
a valid test fixture for cross-package constraint detection.
|
|
212
|
+
broken_implementation: |
|
|
213
|
+
scanVersionConstraints() only reads the root `package.json` and ignores
|
|
214
|
+
sub-package `package.json` files. It passes on single-package workspaces
|
|
215
|
+
but misses cross-package conflicts in real multi-package monorepos.
|
|
216
|
+
real_state_condition: |
|
|
217
|
+
A workspace with ≥2 packages exists, where package A declares `"lodash": "^4.17.0"`
|
|
218
|
+
and package B declares `"lodash": "^3.10.0"`. The broken implementation
|
|
219
|
+
reports no conflicts; the correct implementation reports the constraint mismatch.
|
|
220
|
+
signature:
|
|
221
|
+
- 'mktemp|tmpdir|tmp.*dir'
|
|
222
|
+
- 'package\.json|workspace|monorepo|packages'
|
|
223
|
+
mock_authored_probes:
|
|
224
|
+
- name: multi-package-version-constraint-scan
|
|
225
|
+
sandbox: host
|
|
226
|
+
command: |
|
|
227
|
+
# Create a two-package monorepo fixture
|
|
228
|
+
ROOT=$(mktemp -d)
|
|
229
|
+
mkdir -p "$ROOT/packages/pkg-a" "$ROOT/packages/pkg-b"
|
|
230
|
+
echo '{"name":"root","workspaces":["packages/*"]}' > "$ROOT/package.json"
|
|
231
|
+
echo '{"name":"pkg-a","dependencies":{"lodash":"^4.17.0"}}' > "$ROOT/packages/pkg-a/package.json"
|
|
232
|
+
echo '{"name":"pkg-b","dependencies":{"lodash":"^3.10.0"}}' > "$ROOT/packages/pkg-b/package.json"
|
|
233
|
+
node dist/cli/index.js scan-constraints --root "$ROOT" --output json
|
|
234
|
+
expect_stdout_regex:
|
|
235
|
+
- 'conflict|mismatch|lodash|constraint'
|
|
236
|
+
expect_stdout_no_regex:
|
|
237
|
+
- 'no conflicts|clean|ok'
|
|
238
|
+
|
|
239
|
+
- id: entry-7-git-op-empty-vs-real-repo
|
|
240
|
+
story_key: '2-10'
|
|
241
|
+
description: git tag/describe returns empty on empty repo but silently passes
|
|
242
|
+
source_ac: |
|
|
243
|
+
The release versioner reads the latest git tag from the repository using
|
|
244
|
+
`git tag --sort=-version:refname` or `git describe --tags --abbrev=0`.
|
|
245
|
+
The result must be a non-empty string representing the most recent version tag.
|
|
246
|
+
On a repository with no tags, the implementation must return an explicit error
|
|
247
|
+
or default value, not an empty string silently treated as a valid version.
|
|
248
|
+
broken_implementation: |
|
|
249
|
+
getLatestTag() runs `git tag` in the repo and returns the first line of output.
|
|
250
|
+
On a fresh repository with no tags, `git tag` returns empty output, and the
|
|
251
|
+
function returns an empty string `""` which is used as a version string
|
|
252
|
+
without validation, causing downstream failures.
|
|
253
|
+
real_state_condition: |
|
|
254
|
+
A git repository with ≥1 annotated or lightweight tag exists. The probe
|
|
255
|
+
must assert that the output is a non-empty version string matching a semver
|
|
256
|
+
pattern (e.g., `v1.0.0` or `1.0.0`).
|
|
257
|
+
signature:
|
|
258
|
+
- 'git\s+tag|git\s+describe'
|
|
259
|
+
- 'v\d+\.\d+|semver|non.?empty|tag.*version|version.*tag'
|
|
260
|
+
mock_authored_probes:
|
|
261
|
+
- name: git-tag-non-empty-assertion
|
|
262
|
+
sandbox: host
|
|
263
|
+
command: |
|
|
264
|
+
# Create a git repo with a real tag
|
|
265
|
+
REPO=$(mktemp -d)
|
|
266
|
+
cd "$REPO" && git init && git config user.email "t@t" && git config user.name "T"
|
|
267
|
+
echo "init" > README.md && git add . && git commit -m "initial"
|
|
268
|
+
git tag v1.0.0
|
|
269
|
+
# Run the versioner — must return the tag, not empty
|
|
270
|
+
node dist/cli/index.js get-version --repo "$REPO"
|
|
271
|
+
expect_stdout_regex:
|
|
272
|
+
- 'v1\.0\.0|1\.0\.0'
|
|
273
|
+
expect_stdout_no_regex:
|
|
274
|
+
- '^$|empty|undefined|null'
|
|
275
|
+
|
|
276
|
+
- id: entry-8-spawn-swallows-nonzero-exit
|
|
277
|
+
story_key: '2-11'
|
|
278
|
+
description: spawn invocation ignores non-zero exit code from tsc, masking TypeScript errors
|
|
279
|
+
source_ac: |
|
|
280
|
+
The TypeScript validation step runs `tsc --noEmit` to check for compile
|
|
281
|
+
errors. If `tsc` exits with a non-zero exit code, the validation must
|
|
282
|
+
report failure. The implementation must not swallow the exit code; a
|
|
283
|
+
TypeScript compile error in the project must cause the validation to
|
|
284
|
+
return a failure result, not a success result.
|
|
285
|
+
broken_implementation: |
|
|
286
|
+
runTscCheck() spawns `tsc --noEmit` but wraps the call in a try/catch
|
|
287
|
+
that catches ENOENT and sets result.success=true on any other error
|
|
288
|
+
(including non-zero exit). TypeScript compile errors are silently
|
|
289
|
+
treated as validation success.
|
|
290
|
+
real_state_condition: |
|
|
291
|
+
A TypeScript file with a deliberate type error (e.g., `const x: number = "string"`)
|
|
292
|
+
exists. The broken implementation reports success; the correct implementation
|
|
293
|
+
reports failure with the tsc error output.
|
|
294
|
+
signature:
|
|
295
|
+
- 'tsc'
|
|
296
|
+
- 'exit.*code|exitCode|nonzero|non.zero|status.*[^0]|process\.exit'
|
|
297
|
+
mock_authored_probes:
|
|
298
|
+
- name: tsc-nonzero-exit-detected
|
|
299
|
+
sandbox: host
|
|
300
|
+
command: |
|
|
301
|
+
# Create a TS file with a deliberate type error
|
|
302
|
+
TMPDIR=$(mktemp -d)
|
|
303
|
+
echo '{"compilerOptions":{"strict":true,"noEmit":true}}' > "$TMPDIR/tsconfig.json"
|
|
304
|
+
echo 'const x: number = "this is a string error";' > "$TMPDIR/bad.ts"
|
|
305
|
+
# Run the TypeScript validation — must detect and report failure
|
|
306
|
+
node dist/cli/index.js validate-ts --project "$TMPDIR" --output json; true
|
|
307
|
+
expect_stdout_regex:
|
|
308
|
+
- 'error|fail|invalid|type.*error|tsc.*error'
|
|
309
|
+
expect_stdout_no_regex:
|
|
310
|
+
- '"success":true|"valid":true|"passed":true'
|
|
311
|
+
|
|
312
|
+
excluded_entries: []
|