claude-dev-env 8.85.0 → 8.85.2
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/.agents/skills/efficient-review/SKILL.md +79 -0
- package/.agents/skills/efficient-review/defaults.json +12 -0
- package/.agents/skills/efficient-review/reference/cloud-session.md +13 -0
- package/bin/codex-skill-load-block.mjs +27 -28
- package/bin/codex-skill-load-block.test.mjs +62 -30
- package/bin/codex-trimmed-sol.test.mjs +1 -0
- package/bin/ever-shipped-skills.mjs +1 -0
- package/bin/install-deepstack-plugin.mjs +300 -0
- package/bin/install-deepstack-plugin.test.mjs +98 -0
- package/bin/install-pstack-plugin.mjs +3 -5
- package/bin/install-pstack-plugin.test.mjs +28 -0
- package/bin/install.agents-home.test.mjs +1 -0
- package/bin/install.codex-rules.test.mjs +2 -0
- package/bin/install.cursor-rules.test.mjs +1 -0
- package/bin/install.mjs +27 -3
- package/bin/install.profile-settings.test.mjs +1 -0
- package/bin/install.prune.test.mjs +20 -0
- package/bin/install.question-presentation.test.mjs +7 -3
- package/bin/install.settings-defaults.test.mjs +1 -0
- package/bin/install.shared-settings.test.mjs +1 -0
- package/bin/install.test.mjs +79 -10
- package/bin/install.transaction.test.mjs +8 -0
- package/bin/install.uninstall-transaction.test.mjs +2 -0
- package/bin/install.update-keeps-hooks.test.mjs +1 -0
- package/docs/decisions/deepstack-install.md +9 -0
- package/docs/rule-guides/deepstack-wording.md +23 -0
- package/package.json +1 -1
- package/rules/deepstack-wording.md +15 -0
- package/scripts/deepstack_inventory.py +348 -0
- package/scripts/dev_env_scripts_constants/deepstack_inventory_constants.py +42 -0
- package/scripts/test_deepstack_inventory.py +137 -0
- package/scripts/test_deepstack_wording_rule.py +20 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Diff the DeepStack retirement manifest against the active tree.
|
|
3
|
+
|
|
4
|
+
Each row names a retired path, the behavior it required, the trigger that
|
|
5
|
+
covers it, and the requirement that stays. The eval row keeps a
|
|
6
|
+
reproducible check. An instruction or a manifest cell that marks evals
|
|
7
|
+
optional, or that drops that check, is a finding.
|
|
8
|
+
|
|
9
|
+
This script reads the manifest and the active files. It does not rewrite them.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import sys
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
from active_capability_references import unresolved_active_capabilities
|
|
20
|
+
from dev_env_scripts_constants.deepstack_inventory_constants import (
|
|
21
|
+
ALL_EVAL_OPTIONAL_MARKERS,
|
|
22
|
+
ALL_TRUST_CARD_LINES,
|
|
23
|
+
DEEPSTACK_SECTION_HEADING,
|
|
24
|
+
DEEPSTACK_SKILL_RELATIVE_PATH,
|
|
25
|
+
EVAL_GUIDE_PATH_SUFFIX,
|
|
26
|
+
FINDING_BEHAVIOR_STILL_ACTIVE,
|
|
27
|
+
FINDING_DROPS_FIRST_ACTION_NOTE,
|
|
28
|
+
FINDING_DROPS_REPRODUCIBLE_CHECK,
|
|
29
|
+
FINDING_DROPS_TRUST_LINE,
|
|
30
|
+
FINDING_MARKS_EVALS_OPTIONAL,
|
|
31
|
+
FINDING_TRIGGER_MISSING,
|
|
32
|
+
FIRST_ACTION_BEHAVIOR_PREFIX,
|
|
33
|
+
FIRST_ACTION_RETIRED_SENTENCE,
|
|
34
|
+
MANIFEST_RELATIVE_PATH,
|
|
35
|
+
PATH_NONE,
|
|
36
|
+
REPRODUCIBLE_CHECK_SENTENCE,
|
|
37
|
+
RETIRED_PATH_HEADER,
|
|
38
|
+
SHORTEST_BACKTICKED_CELL,
|
|
39
|
+
TABLE_COLUMN_COUNT,
|
|
40
|
+
UTF8_ENCODING,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass(frozen=True)
|
|
45
|
+
class ReplacementRow:
|
|
46
|
+
"""One retired behavior and the trigger that covers it."""
|
|
47
|
+
|
|
48
|
+
retired_path: str
|
|
49
|
+
behavior: str
|
|
50
|
+
trigger: str
|
|
51
|
+
requirement_that_stays: str
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass(frozen=True)
|
|
55
|
+
class InventoryFinding:
|
|
56
|
+
"""One place the active tree still carries a retired behavior."""
|
|
57
|
+
|
|
58
|
+
retired_path: str
|
|
59
|
+
code: str
|
|
60
|
+
detail: str
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _unquote(cell: str) -> str:
|
|
64
|
+
text = cell.strip()
|
|
65
|
+
if len(text) >= SHORTEST_BACKTICKED_CELL and text.startswith("`") and text.endswith("`"):
|
|
66
|
+
return text[1:-1]
|
|
67
|
+
return text
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _table_cells(line: str) -> tuple[str, ...] | None:
|
|
71
|
+
stripped = line.strip()
|
|
72
|
+
if not stripped.startswith("|"):
|
|
73
|
+
return None
|
|
74
|
+
cells = [_unquote(each_cell) for each_cell in stripped.strip("|").split("|")]
|
|
75
|
+
if len(cells) != TABLE_COLUMN_COUNT:
|
|
76
|
+
return None
|
|
77
|
+
if cells[0].startswith("-") or cells[0].lower() == RETIRED_PATH_HEADER:
|
|
78
|
+
return None
|
|
79
|
+
return tuple(cells)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _row_from_line(each_line: str) -> ReplacementRow | None:
|
|
83
|
+
cells = _table_cells(each_line)
|
|
84
|
+
if cells is None:
|
|
85
|
+
return None
|
|
86
|
+
return ReplacementRow(
|
|
87
|
+
retired_path=cells[0],
|
|
88
|
+
behavior=cells[1],
|
|
89
|
+
trigger=cells[2],
|
|
90
|
+
requirement_that_stays=cells[3],
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def replacement_rows(manifest_text: str) -> tuple[ReplacementRow, ...]:
|
|
95
|
+
"""Return the rows under the DeepStack heading, or none when it is absent.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
manifest_text: The archive manifest text.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
One row per table line under the heading.
|
|
102
|
+
"""
|
|
103
|
+
all_lines = manifest_text.splitlines()
|
|
104
|
+
is_in_section = False
|
|
105
|
+
all_rows: list[ReplacementRow] = []
|
|
106
|
+
for each_line in all_lines:
|
|
107
|
+
if each_line.startswith(DEEPSTACK_SECTION_HEADING):
|
|
108
|
+
is_in_section = True
|
|
109
|
+
continue
|
|
110
|
+
if is_in_section and each_line.startswith("## "):
|
|
111
|
+
break
|
|
112
|
+
if not is_in_section:
|
|
113
|
+
continue
|
|
114
|
+
each_row = _row_from_line(each_line)
|
|
115
|
+
if each_row is None:
|
|
116
|
+
continue
|
|
117
|
+
all_rows.append(each_row)
|
|
118
|
+
return tuple(all_rows)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _is_eval_retirement(row: ReplacementRow) -> bool:
|
|
122
|
+
return row.retired_path.endswith(EVAL_GUIDE_PATH_SUFFIX) or row.behavior.startswith(
|
|
123
|
+
FIRST_ACTION_BEHAVIOR_PREFIX
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _optional_eval_finding(
|
|
128
|
+
each_text: str, each_surface: str, retired_path: str
|
|
129
|
+
) -> InventoryFinding | None:
|
|
130
|
+
"""Return a finding when the text marks evals optional."""
|
|
131
|
+
lowered = each_text.lower()
|
|
132
|
+
if any(each_marker in lowered for each_marker in ALL_EVAL_OPTIONAL_MARKERS):
|
|
133
|
+
return InventoryFinding(
|
|
134
|
+
retired_path=retired_path,
|
|
135
|
+
code=FINDING_MARKS_EVALS_OPTIONAL,
|
|
136
|
+
detail=each_surface,
|
|
137
|
+
)
|
|
138
|
+
return None
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _dropped_check_finding(
|
|
142
|
+
each_text: str, each_surface: str, retired_path: str
|
|
143
|
+
) -> InventoryFinding | None:
|
|
144
|
+
"""Return a finding when the reproducible-check sentence is absent."""
|
|
145
|
+
if REPRODUCIBLE_CHECK_SENTENCE in each_text:
|
|
146
|
+
return None
|
|
147
|
+
return InventoryFinding(
|
|
148
|
+
retired_path=retired_path,
|
|
149
|
+
code=FINDING_DROPS_REPRODUCIBLE_CHECK,
|
|
150
|
+
detail=each_surface,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _trust_line_findings(
|
|
155
|
+
each_text: str, each_surface: str, retired_path: str
|
|
156
|
+
) -> tuple[InventoryFinding, ...]:
|
|
157
|
+
"""Return one finding per trust-card line the text omits."""
|
|
158
|
+
all_findings: list[InventoryFinding] = []
|
|
159
|
+
for each_trust_line in ALL_TRUST_CARD_LINES:
|
|
160
|
+
if each_trust_line not in each_text:
|
|
161
|
+
all_findings.append(
|
|
162
|
+
InventoryFinding(
|
|
163
|
+
retired_path=retired_path,
|
|
164
|
+
code=FINDING_DROPS_TRUST_LINE,
|
|
165
|
+
detail=f"{each_surface}:{each_trust_line}",
|
|
166
|
+
)
|
|
167
|
+
)
|
|
168
|
+
return tuple(all_findings)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _surface_findings(
|
|
172
|
+
each_text: str, each_surface: str, retired_path: str
|
|
173
|
+
) -> tuple[InventoryFinding, ...]:
|
|
174
|
+
"""Return the optional-eval, dropped-check, and trust-line findings for one surface."""
|
|
175
|
+
all_findings: list[InventoryFinding] = []
|
|
176
|
+
optional_eval = _optional_eval_finding(each_text, each_surface, retired_path)
|
|
177
|
+
if optional_eval is not None:
|
|
178
|
+
all_findings.append(optional_eval)
|
|
179
|
+
dropped_check = _dropped_check_finding(each_text, each_surface, retired_path)
|
|
180
|
+
if dropped_check is not None:
|
|
181
|
+
all_findings.append(dropped_check)
|
|
182
|
+
all_findings.extend(_trust_line_findings(each_text, each_surface, retired_path))
|
|
183
|
+
return tuple(all_findings)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def eval_retirement_findings(
|
|
187
|
+
instruction_text: str, requirement_text: str, retired_path: str
|
|
188
|
+
) -> tuple[InventoryFinding, ...]:
|
|
189
|
+
"""Reject an eval retirement that makes the reproducible check optional.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
instruction_text: The active instruction the row points at.
|
|
193
|
+
requirement_text: The manifest cell for the requirement that stays.
|
|
194
|
+
retired_path: Path named by the row, used on each finding.
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
Findings for an optional eval or a dropped reproducible check.
|
|
198
|
+
"""
|
|
199
|
+
all_findings: list[InventoryFinding] = []
|
|
200
|
+
for each_text, each_surface in (
|
|
201
|
+
(instruction_text, "instruction"),
|
|
202
|
+
(requirement_text, "manifest"),
|
|
203
|
+
):
|
|
204
|
+
all_findings.extend(_surface_findings(each_text, each_surface, retired_path))
|
|
205
|
+
if FIRST_ACTION_RETIRED_SENTENCE not in requirement_text:
|
|
206
|
+
all_findings.append(
|
|
207
|
+
InventoryFinding(
|
|
208
|
+
retired_path=retired_path,
|
|
209
|
+
code=FINDING_DROPS_FIRST_ACTION_NOTE,
|
|
210
|
+
detail="manifest",
|
|
211
|
+
)
|
|
212
|
+
)
|
|
213
|
+
return tuple(all_findings)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _read_text(path: Path) -> str:
|
|
217
|
+
if not path.is_file():
|
|
218
|
+
return ""
|
|
219
|
+
return path.read_text(encoding=UTF8_ENCODING)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _instruction_text(package_root: Path, retired_path: str) -> str:
|
|
223
|
+
"""Return the active file for a retired path, or empty text for the none row."""
|
|
224
|
+
if retired_path == PATH_NONE:
|
|
225
|
+
return ""
|
|
226
|
+
return _read_text(package_root / retired_path)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _missing_trigger_finding(
|
|
230
|
+
each_row: ReplacementRow, skill_text: str
|
|
231
|
+
) -> InventoryFinding | None:
|
|
232
|
+
if each_row.trigger in skill_text:
|
|
233
|
+
return None
|
|
234
|
+
return InventoryFinding(
|
|
235
|
+
retired_path=each_row.retired_path,
|
|
236
|
+
code=FINDING_TRIGGER_MISSING,
|
|
237
|
+
detail=each_row.trigger,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def _live_behavior_finding(
|
|
242
|
+
each_row: ReplacementRow, instruction_text: str
|
|
243
|
+
) -> InventoryFinding | None:
|
|
244
|
+
if not each_row.behavior or each_row.behavior not in instruction_text:
|
|
245
|
+
return None
|
|
246
|
+
return InventoryFinding(
|
|
247
|
+
retired_path=each_row.retired_path,
|
|
248
|
+
code=FINDING_BEHAVIOR_STILL_ACTIVE,
|
|
249
|
+
detail=each_row.behavior,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _row_findings(
|
|
254
|
+
package_root: Path, each_row: ReplacementRow, skill_text: str
|
|
255
|
+
) -> tuple[InventoryFinding, ...]:
|
|
256
|
+
"""Return the trigger, behavior, and eval findings for one manifest row."""
|
|
257
|
+
instruction_text = _instruction_text(package_root, each_row.retired_path)
|
|
258
|
+
all_findings: list[InventoryFinding] = []
|
|
259
|
+
missing_trigger = _missing_trigger_finding(each_row, skill_text)
|
|
260
|
+
if missing_trigger is not None:
|
|
261
|
+
all_findings.append(missing_trigger)
|
|
262
|
+
live_behavior = _live_behavior_finding(each_row, instruction_text)
|
|
263
|
+
if live_behavior is not None:
|
|
264
|
+
all_findings.append(live_behavior)
|
|
265
|
+
if _is_eval_retirement(each_row):
|
|
266
|
+
all_findings.extend(
|
|
267
|
+
eval_retirement_findings(
|
|
268
|
+
instruction_text,
|
|
269
|
+
each_row.requirement_that_stays,
|
|
270
|
+
each_row.retired_path,
|
|
271
|
+
)
|
|
272
|
+
)
|
|
273
|
+
return tuple(all_findings)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def findings_for_rows(
|
|
277
|
+
package_root: Path,
|
|
278
|
+
all_rows: tuple[ReplacementRow, ...],
|
|
279
|
+
skill_text: str,
|
|
280
|
+
) -> tuple[InventoryFinding, ...]:
|
|
281
|
+
"""Return findings for retired behaviors that the active tree still requires.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
package_root: Package directory that holds the active files.
|
|
285
|
+
all_rows: Manifest rows under the DeepStack heading.
|
|
286
|
+
skill_text: Install note that must name each trigger.
|
|
287
|
+
|
|
288
|
+
Returns:
|
|
289
|
+
Findings for missing triggers, live behaviors, and eval rows.
|
|
290
|
+
"""
|
|
291
|
+
all_findings: list[InventoryFinding] = []
|
|
292
|
+
for each_row in all_rows:
|
|
293
|
+
all_findings.extend(_row_findings(package_root, each_row, skill_text))
|
|
294
|
+
return tuple(all_findings)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def inventory_findings(package_root: Path) -> tuple[InventoryFinding, ...]:
|
|
298
|
+
"""Return DeepStack findings plus leftover retired capability names.
|
|
299
|
+
|
|
300
|
+
Args:
|
|
301
|
+
package_root: Package directory that holds the manifest and the active files.
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
Findings from the manifest rows and from leftover retired capability names.
|
|
305
|
+
"""
|
|
306
|
+
manifest_text = _read_text(package_root / MANIFEST_RELATIVE_PATH)
|
|
307
|
+
all_rows = replacement_rows(manifest_text)
|
|
308
|
+
skill_text = _read_text(package_root / DEEPSTACK_SKILL_RELATIVE_PATH)
|
|
309
|
+
all_findings = list(findings_for_rows(package_root, all_rows, skill_text))
|
|
310
|
+
for each_reference in unresolved_active_capabilities(package_root):
|
|
311
|
+
all_findings.append(
|
|
312
|
+
InventoryFinding(
|
|
313
|
+
retired_path=each_reference.file_path,
|
|
314
|
+
code="retired-capability",
|
|
315
|
+
detail=each_reference.capability_name,
|
|
316
|
+
)
|
|
317
|
+
)
|
|
318
|
+
return tuple(all_findings)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def _format_finding(finding: InventoryFinding) -> str:
|
|
322
|
+
return f"{finding.retired_path}: {finding.code}: {finding.detail}"
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def main(all_arguments: list[str]) -> int:
|
|
326
|
+
"""Print each finding and return 1 when the active tree fails the manifest.
|
|
327
|
+
|
|
328
|
+
Args:
|
|
329
|
+
all_arguments: Command-line arguments, without the program name.
|
|
330
|
+
|
|
331
|
+
Returns:
|
|
332
|
+
0 when the tree has no findings, and 1 when it has any.
|
|
333
|
+
"""
|
|
334
|
+
parser = argparse.ArgumentParser(description=__doc__, allow_abbrev=False)
|
|
335
|
+
parser.add_argument(
|
|
336
|
+
"--package-root",
|
|
337
|
+
type=Path,
|
|
338
|
+
default=Path(__file__).resolve().parent.parent,
|
|
339
|
+
)
|
|
340
|
+
arguments = parser.parse_args(all_arguments)
|
|
341
|
+
all_findings = inventory_findings(arguments.package_root)
|
|
342
|
+
for each_finding in all_findings:
|
|
343
|
+
sys.stdout.write(_format_finding(each_finding) + "\n")
|
|
344
|
+
return 1 if all_findings else 0
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
if __name__ == "__main__":
|
|
348
|
+
raise SystemExit(main(sys.argv[1:]))
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Constants for the DeepStack retirement inventory."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
UTF8_ENCODING: str = "utf-8"
|
|
6
|
+
SHORTEST_BACKTICKED_CELL: int = 2
|
|
7
|
+
TABLE_COLUMN_COUNT: int = 4
|
|
8
|
+
MANIFEST_RELATIVE_PATH: str = "rules-archived/ARCHIVE-MANIFEST.md"
|
|
9
|
+
DEEPSTACK_SECTION_HEADING: str = "## DeepStack replacements"
|
|
10
|
+
DEEPSTACK_SKILL_RELATIVE_PATH: str = "docs/decisions/deepstack-install.md"
|
|
11
|
+
EVAL_GUIDE_PATH_SUFFIX: str = "features-start-with-an-eval.md"
|
|
12
|
+
FIRST_ACTION_BEHAVIOR_PREFIX: str = "Your first action is the Skill tool"
|
|
13
|
+
RETIRED_PATH_HEADER: str = "retired path"
|
|
14
|
+
PATH_NONE: str = "none"
|
|
15
|
+
REQUIREMENT_NONE: str = "none"
|
|
16
|
+
REPRODUCIBLE_CHECK_SENTENCE: str = (
|
|
17
|
+
"A reproducible, re-runnable check is still required before any done claim."
|
|
18
|
+
)
|
|
19
|
+
FIRST_ACTION_RETIRED_SENTENCE: str = (
|
|
20
|
+
"Only the forced position as the very first action is retired."
|
|
21
|
+
)
|
|
22
|
+
ALL_TRUST_CARD_LINES: tuple[str, ...] = (
|
|
23
|
+
"Red before the fix",
|
|
24
|
+
"wrong twin fails",
|
|
25
|
+
"undo fails again",
|
|
26
|
+
)
|
|
27
|
+
ALL_EVAL_OPTIONAL_MARKERS: tuple[str, ...] = (
|
|
28
|
+
"evals are optional",
|
|
29
|
+
"eval is optional",
|
|
30
|
+
"evals optional",
|
|
31
|
+
"optional eval",
|
|
32
|
+
"reproducible check is removed",
|
|
33
|
+
"reproducible check is retired",
|
|
34
|
+
"no reproducible check",
|
|
35
|
+
"without a reproducible check",
|
|
36
|
+
)
|
|
37
|
+
FINDING_BEHAVIOR_STILL_ACTIVE: str = "behavior-still-active"
|
|
38
|
+
FINDING_TRIGGER_MISSING: str = "trigger-missing"
|
|
39
|
+
FINDING_MARKS_EVALS_OPTIONAL: str = "marks-evals-optional"
|
|
40
|
+
FINDING_DROPS_REPRODUCIBLE_CHECK: str = "drops-reproducible-check"
|
|
41
|
+
FINDING_DROPS_TRUST_LINE: str = "drops-trust-line"
|
|
42
|
+
FINDING_DROPS_FIRST_ACTION_NOTE: str = "drops-first-action-retired-note"
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""The inventory rejects an eval retirement that drops the reproducible check."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
import textwrap
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from deepstack_inventory import (
|
|
11
|
+
findings_for_rows,
|
|
12
|
+
inventory_findings,
|
|
13
|
+
replacement_rows,
|
|
14
|
+
eval_retirement_findings,
|
|
15
|
+
)
|
|
16
|
+
from dev_env_scripts_constants.deepstack_inventory_constants import (
|
|
17
|
+
FINDING_BEHAVIOR_STILL_ACTIVE,
|
|
18
|
+
FINDING_DROPS_REPRODUCIBLE_CHECK,
|
|
19
|
+
FINDING_MARKS_EVALS_OPTIONAL,
|
|
20
|
+
REPRODUCIBLE_CHECK_SENTENCE,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
_PACKAGE_ROOT = Path(__file__).resolve().parent.parent
|
|
24
|
+
_KEPT_REQUIREMENT = (
|
|
25
|
+
f"{REPRODUCIBLE_CHECK_SENTENCE} "
|
|
26
|
+
"Red before the fix, the wrong twin fails, and undo fails again. "
|
|
27
|
+
"Only the forced position as the very first action is retired."
|
|
28
|
+
)
|
|
29
|
+
_KEPT_INSTRUCTION = (
|
|
30
|
+
"The DeepStack reproducible-check leaf calls this guide after intake. "
|
|
31
|
+
f"{_KEPT_REQUIREMENT}"
|
|
32
|
+
)
|
|
33
|
+
_FIRST_ACTION = (
|
|
34
|
+
"Your first action is the Skill tool with skill `claude-api` and args `build-eval`"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _row_block(requirement: str, instruction_phrase: str) -> str:
|
|
39
|
+
return textwrap.dedent(
|
|
40
|
+
f"""\
|
|
41
|
+
## DeepStack replacements
|
|
42
|
+
|
|
43
|
+
| Retired path | Behavior it required | Trigger that replaces it | Requirement that stays |
|
|
44
|
+
|---|---|---|---|
|
|
45
|
+
| docs/rule-guides/features-start-with-an-eval.md | {instruction_phrase} | DeepStack reproducible-check leaf | {requirement} |
|
|
46
|
+
"""
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_should_reject_an_instruction_that_marks_evals_optional() -> None:
|
|
51
|
+
findings = eval_retirement_findings(
|
|
52
|
+
"Evals are optional before a done claim.",
|
|
53
|
+
"Evals are optional. The reproducible check is removed.",
|
|
54
|
+
"docs/rule-guides/features-start-with-an-eval.md",
|
|
55
|
+
)
|
|
56
|
+
assert any(each.code == FINDING_MARKS_EVALS_OPTIONAL for each in findings)
|
|
57
|
+
assert any(each.code == FINDING_DROPS_REPRODUCIBLE_CHECK for each in findings)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_should_reject_a_manifest_that_removes_the_reproducible_check() -> None:
|
|
61
|
+
findings = eval_retirement_findings(
|
|
62
|
+
_KEPT_INSTRUCTION,
|
|
63
|
+
"Only the forced position as the very first action is retired.",
|
|
64
|
+
"docs/rule-guides/features-start-with-an-eval.md",
|
|
65
|
+
)
|
|
66
|
+
manifest_drops = [
|
|
67
|
+
each
|
|
68
|
+
for each in findings
|
|
69
|
+
if each.code == FINDING_DROPS_REPRODUCIBLE_CHECK and each.detail == "manifest"
|
|
70
|
+
]
|
|
71
|
+
assert manifest_drops
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_should_accept_a_retirement_that_keeps_the_reproducible_check() -> None:
|
|
75
|
+
assert eval_retirement_findings(
|
|
76
|
+
_KEPT_INSTRUCTION,
|
|
77
|
+
_KEPT_REQUIREMENT,
|
|
78
|
+
"docs/rule-guides/features-start-with-an-eval.md",
|
|
79
|
+
) == ()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_should_reject_a_tree_whose_guide_still_orders_the_first_action(tmp_path: Path) -> None:
|
|
83
|
+
package_root = tmp_path
|
|
84
|
+
guide = package_root / "docs" / "rule-guides" / "features-start-with-an-eval.md"
|
|
85
|
+
guide.parent.mkdir(parents=True)
|
|
86
|
+
guide.write_text(f"{_FIRST_ACTION}. Build the feature.\n", encoding="utf-8")
|
|
87
|
+
skill = package_root / "docs" / "decisions" / "deepstack-install.md"
|
|
88
|
+
skill.parent.mkdir(parents=True)
|
|
89
|
+
skill.write_text("DeepStack reproducible-check leaf\n", encoding="utf-8")
|
|
90
|
+
manifest = package_root / "rules-archived" / "ARCHIVE-MANIFEST.md"
|
|
91
|
+
manifest.parent.mkdir(parents=True)
|
|
92
|
+
manifest.write_text(_row_block(_KEPT_REQUIREMENT, _FIRST_ACTION), encoding="utf-8")
|
|
93
|
+
all_rows = replacement_rows(manifest.read_text(encoding="utf-8"))
|
|
94
|
+
findings = findings_for_rows(package_root, all_rows, skill.read_text(encoding="utf-8"))
|
|
95
|
+
assert any(each.code == FINDING_BEHAVIOR_STILL_ACTIVE for each in findings)
|
|
96
|
+
assert any(each.code == FINDING_DROPS_REPRODUCIBLE_CHECK for each in findings)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def test_should_accept_a_tree_that_retires_only_the_first_action(tmp_path: Path) -> None:
|
|
100
|
+
package_root = tmp_path
|
|
101
|
+
guide = package_root / "docs" / "rule-guides" / "features-start-with-an-eval.md"
|
|
102
|
+
guide.parent.mkdir(parents=True)
|
|
103
|
+
guide.write_text(_KEPT_INSTRUCTION + "\n", encoding="utf-8")
|
|
104
|
+
skill = package_root / "docs" / "decisions" / "deepstack-install.md"
|
|
105
|
+
skill.parent.mkdir(parents=True)
|
|
106
|
+
skill.write_text("DeepStack reproducible-check leaf\n", encoding="utf-8")
|
|
107
|
+
manifest = package_root / "rules-archived" / "ARCHIVE-MANIFEST.md"
|
|
108
|
+
manifest.parent.mkdir(parents=True)
|
|
109
|
+
manifest.write_text(_row_block(_KEPT_REQUIREMENT, _FIRST_ACTION), encoding="utf-8")
|
|
110
|
+
(package_root / ".agents" / "skills" / "kept").mkdir(parents=True)
|
|
111
|
+
(package_root / ".agents" / "skills" / "kept" / "SKILL.md").write_text(
|
|
112
|
+
"---\nname: kept\n---\n", encoding="utf-8"
|
|
113
|
+
)
|
|
114
|
+
(package_root / "bin").mkdir()
|
|
115
|
+
(package_root / "bin" / "ever-shipped-skills.mjs").write_text("'kept'\n", encoding="utf-8")
|
|
116
|
+
assert inventory_findings(package_root) == ()
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_install_citation_names_the_plugin_repository_and_the_triggers() -> None:
|
|
120
|
+
text = (_PACKAGE_ROOT / "docs" / "decisions" / "deepstack-install.md").read_text(encoding="utf-8")
|
|
121
|
+
assert "jl-cmd-projects/DeepStack" in text
|
|
122
|
+
assert "deepstack@DeepStack" in text
|
|
123
|
+
assert "DeepStack intake" in text
|
|
124
|
+
assert "DeepStack search leaf" in text
|
|
125
|
+
assert "DeepStack reproducible-check leaf" in text
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def test_live_package_inventory_exits_clean() -> None:
|
|
129
|
+
completed = subprocess.run(
|
|
130
|
+
[sys.executable, str(_PACKAGE_ROOT / "scripts" / "deepstack_inventory.py")],
|
|
131
|
+
capture_output=True,
|
|
132
|
+
text=True,
|
|
133
|
+
check=False,
|
|
134
|
+
cwd=str(_PACKAGE_ROOT),
|
|
135
|
+
)
|
|
136
|
+
assert completed.returncode == 0
|
|
137
|
+
assert completed.stdout == ""
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""The wording rule cites the first-task gate."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
_PACKAGE_ROOT = Path(__file__).resolve().parent.parent
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_wording_rule_cites_the_gate() -> None:
|
|
11
|
+
rule_text = (_PACKAGE_ROOT / "rules" / "deepstack-wording.md").read_text(encoding="utf-8")
|
|
12
|
+
guide_text = (_PACKAGE_ROOT / "docs" / "rule-guides" / "deepstack-wording.md").read_text(
|
|
13
|
+
encoding="utf-8"
|
|
14
|
+
)
|
|
15
|
+
assert "hooks/session/deepen_first_prompt.py" in rule_text
|
|
16
|
+
assert "hooks/session/deepen_first_prompt.py" in guide_text
|
|
17
|
+
assert "SCOPE (role):" in guide_text
|
|
18
|
+
assert "EXAMPLES (illustration only):" in guide_text
|
|
19
|
+
assert "ZOOM-IN BLOCKER:" in guide_text
|
|
20
|
+
assert "DeepStack" in rule_text
|