pi-ui-extend 1.0.40 → 1.0.42

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.
Files changed (186) hide show
  1. package/README.md +10 -2
  2. package/dist/app/app.d.ts +3 -0
  3. package/dist/app/app.js +26 -0
  4. package/dist/app/commands/command-host.d.ts +1 -0
  5. package/dist/app/commands/command-model-actions.js +6 -1
  6. package/dist/app/commands/command-registry.js +3 -3
  7. package/dist/app/commands/command-session-actions.d.ts +0 -1
  8. package/dist/app/commands/command-session-actions.js +30 -15
  9. package/dist/app/commands/reload-context-inventory.d.ts +11 -0
  10. package/dist/app/commands/reload-context-inventory.js +59 -0
  11. package/dist/app/extensions/extension-actions-controller.d.ts +1 -0
  12. package/dist/app/extensions/extension-actions-controller.js +6 -0
  13. package/dist/app/extensions/subagent-catalog-state.d.ts +9 -0
  14. package/dist/app/extensions/subagent-catalog-state.js +23 -0
  15. package/dist/app/icons.d.ts +14 -0
  16. package/dist/app/icons.js +33 -0
  17. package/dist/app/rendering/conversation-tool-renderer.js +2 -2
  18. package/dist/app/rendering/dcp-stats.d.ts +6 -1
  19. package/dist/app/rendering/dcp-stats.js +214 -46
  20. package/dist/app/rendering/editor-panels.js +17 -8
  21. package/dist/app/session/lazy-session-manager.js +12 -1
  22. package/dist/app/session/session-lifecycle-controller.d.ts +1 -0
  23. package/dist/app/session/session-lifecycle-controller.js +6 -0
  24. package/dist/app/session/tabs-controller.d.ts +3 -5
  25. package/dist/app/session/tabs-controller.js +31 -22
  26. package/dist/app/subagents/subagents-files.js +60 -1
  27. package/dist/app/subagents/subagents-model.d.ts +15 -1
  28. package/dist/app/subagents/subagents-model.js +52 -17
  29. package/dist/app/types.d.ts +7 -0
  30. package/dist/bundled-extensions/session-title/config.js +1 -1
  31. package/dist/default-pix-config.js +10 -0
  32. package/dist/markdown-format.js +27 -9
  33. package/dist/schemas/index.d.ts +1 -0
  34. package/dist/schemas/index.js +1 -0
  35. package/dist/schemas/pi-tools-suite-schema.d.ts +106 -71
  36. package/dist/schemas/pi-tools-suite-schema.js +68 -88
  37. package/dist/schemas/pix-schema.d.ts +7 -0
  38. package/dist/schemas/pix-schema.js +14 -0
  39. package/dist/schemas/tasks-schema.d.ts +18 -0
  40. package/dist/schemas/tasks-schema.js +41 -0
  41. package/docs/concurrency.md +6 -0
  42. package/docs/desktop-mvp.md +12 -1
  43. package/docs/desktop-task-manager.md +93 -82
  44. package/external/pi-tools-suite/README.md +192 -72
  45. package/external/pi-tools-suite/docs/browser-qa-subagent.md +50 -21
  46. package/external/pi-tools-suite/docs/context-gateway-p00-adr.md +216 -0
  47. package/external/pi-tools-suite/docs/context-gateway-p01n-gate-review.md +122 -0
  48. package/external/pi-tools-suite/docs/context-gateway-p01n-measurement.md +133 -0
  49. package/external/pi-tools-suite/docs/context-gateway-p01r-ra-evidence.md +111 -0
  50. package/external/pi-tools-suite/docs/context-gateway-p01r-rb-evidence.md +100 -0
  51. package/external/pi-tools-suite/docs/context-gateway-p01r-rc-evidence.md +69 -0
  52. package/external/pi-tools-suite/docs/context-gateway-p01r-rd-evidence.md +100 -0
  53. package/external/pi-tools-suite/docs/context-gateway-p01r-re-evidence.md +74 -0
  54. package/external/pi-tools-suite/docs/context-gateway-p01r-rf-evidence.md +153 -0
  55. package/external/pi-tools-suite/docs/context-gateway-p01r-rg-evidence.md +235 -0
  56. package/external/pi-tools-suite/docs/evals.md +1 -1
  57. package/external/pi-tools-suite/docs/session-recovery.md +40 -14
  58. package/external/pi-tools-suite/docs/subagent-model-pools.md +120 -0
  59. package/external/pi-tools-suite/package.json +3 -0
  60. package/external/pi-tools-suite/src/async-subagents/{private-skills → agents}/browser-qa/scripts/browser-qa-runner.mjs +82 -1
  61. package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/SKILL.md → agents/browser-qa.md} +261 -12
  62. package/external/pi-tools-suite/src/async-subagents/agents/frontier-review.md +23 -0
  63. package/external/pi-tools-suite/src/async-subagents/agents/implement.md +20 -0
  64. package/external/pi-tools-suite/src/async-subagents/agents/oracle.md +16 -0
  65. package/external/pi-tools-suite/src/async-subagents/agents/presets.jsonc +16 -0
  66. package/external/pi-tools-suite/src/async-subagents/agents/research.md +20 -0
  67. package/external/pi-tools-suite/src/async-subagents/agents/verify.md +18 -0
  68. package/external/pi-tools-suite/src/async-subagents/commands.ts +20 -72
  69. package/external/pi-tools-suite/src/async-subagents/core/activity.ts +33 -0
  70. package/external/pi-tools-suite/src/async-subagents/core/agent-catalog.ts +42 -0
  71. package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +13 -93
  72. package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +499 -0
  73. package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +9 -0
  74. package/external/pi-tools-suite/src/async-subagents/core/config.ts +284 -417
  75. package/external/pi-tools-suite/src/async-subagents/core/model-fallback.ts +1 -1
  76. package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +54 -0
  77. package/external/pi-tools-suite/src/async-subagents/core/prompt.ts +7 -6
  78. package/external/pi-tools-suite/src/async-subagents/core/routing.ts +65 -45
  79. package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +18 -6
  80. package/external/pi-tools-suite/src/async-subagents/core/state.ts +40 -0
  81. package/external/pi-tools-suite/src/async-subagents/core/types.ts +7 -0
  82. package/external/pi-tools-suite/src/async-subagents/index.ts +77 -3
  83. package/external/pi-tools-suite/src/async-subagents/lib.ts +12 -9
  84. package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +54 -22
  85. package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +6 -4
  86. package/external/pi-tools-suite/src/async-subagents/types.ts +3 -0
  87. package/external/pi-tools-suite/src/config.ts +42 -2
  88. package/external/pi-tools-suite/src/context-gateway/accounting.ts +151 -0
  89. package/external/pi-tools-suite/src/context-gateway/config.ts +120 -0
  90. package/external/pi-tools-suite/src/context-gateway/enforcement.ts +102 -0
  91. package/external/pi-tools-suite/src/context-gateway/index.ts +214 -0
  92. package/external/pi-tools-suite/src/context-gateway/metadata-normalization.ts +88 -0
  93. package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +89 -0
  94. package/external/pi-tools-suite/src/context-gateway/telemetry.ts +502 -0
  95. package/external/pi-tools-suite/src/context-gateway/test-output-parser.ts +326 -0
  96. package/external/pi-tools-suite/src/context-gateway/types.ts +158 -0
  97. package/external/pi-tools-suite/src/context-inventory.ts +99 -0
  98. package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +106 -0
  99. package/external/pi-tools-suite/src/dcp/auto-compress.ts +892 -136
  100. package/external/pi-tools-suite/src/dcp/commands.ts +82 -139
  101. package/external/pi-tools-suite/src/dcp/compress-tool.ts +533 -74
  102. package/external/pi-tools-suite/src/dcp/compression-blocks.ts +488 -94
  103. package/external/pi-tools-suite/src/dcp/compression-preview.ts +122 -0
  104. package/external/pi-tools-suite/src/dcp/compression-progress.ts +70 -0
  105. package/external/pi-tools-suite/src/dcp/config.ts +86 -68
  106. package/external/pi-tools-suite/src/dcp/conversation-index.ts +421 -0
  107. package/external/pi-tools-suite/src/dcp/debug-log.ts +7 -5
  108. package/external/pi-tools-suite/src/dcp/index.ts +617 -203
  109. package/external/pi-tools-suite/src/dcp/journal.ts +566 -0
  110. package/external/pi-tools-suite/src/dcp/progress-controller.ts +244 -0
  111. package/external/pi-tools-suite/src/dcp/prompts.ts +83 -189
  112. package/external/pi-tools-suite/src/dcp/protected-continuity.ts +175 -0
  113. package/external/pi-tools-suite/src/dcp/provider-tool-results.ts +189 -0
  114. package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +299 -79
  115. package/external/pi-tools-suite/src/dcp/pruner-compression-blocks.ts +173 -281
  116. package/external/pi-tools-suite/src/dcp/pruner-emergency.ts +2 -4
  117. package/external/pi-tools-suite/src/dcp/pruner-message-ids.ts +23 -15
  118. package/external/pi-tools-suite/src/dcp/pruner-metadata.ts +11 -1
  119. package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +30 -82
  120. package/external/pi-tools-suite/src/dcp/pruner-tools.ts +28 -136
  121. package/external/pi-tools-suite/src/dcp/pruner.ts +18 -33
  122. package/external/pi-tools-suite/src/dcp/recovery.ts +129 -0
  123. package/external/pi-tools-suite/src/dcp/shadow-plan.ts +127 -0
  124. package/external/pi-tools-suite/src/dcp/state-transaction.ts +102 -0
  125. package/external/pi-tools-suite/src/dcp/state.ts +158 -580
  126. package/external/pi-tools-suite/src/dcp/ui.ts +1 -0
  127. package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +36 -214
  128. package/external/pi-tools-suite/src/index.ts +16 -1
  129. package/external/pi-tools-suite/src/model-tools/index.ts +76 -42
  130. package/external/pi-tools-suite/src/repo-discovery/index.ts +84 -18
  131. package/external/pi-tools-suite/src/repo-discovery/native-compact.ts +458 -0
  132. package/external/pi-tools-suite/src/resource-registry/index.ts +2290 -0
  133. package/external/pi-tools-suite/src/session-recovery/index.ts +189 -43
  134. package/external/pi-tools-suite/src/shell-command-policy.ts +219 -0
  135. package/external/pi-tools-suite/src/tool-descriptions.ts +41 -38
  136. package/external/pi-tools-suite/src/truncation-metadata-normalizer/index.ts +17 -0
  137. package/package.json +6 -3
  138. package/schemas/pi-tools-suite.json +540 -312
  139. package/schemas/pix.json +24 -0
  140. package/schemas/tasks.json +132 -0
  141. package/skills/spec-wiki/SKILL.md +55 -0
  142. package/skills/spec-wiki/evals/evals.json +132 -0
  143. package/skills/spec-wiki/evals/files/bootstrap/architecture/rfc-007.md +14 -0
  144. package/skills/spec-wiki/evals/files/bootstrap/docs/how-to-pay.md +4 -0
  145. package/skills/spec-wiki/evals/files/bootstrap/docs/overview.md +9 -0
  146. package/skills/spec-wiki/evals/files/bootstrap/requirements/payment-behavior.md +17 -0
  147. package/skills/spec-wiki/evals/files/bootstrap/src/payments.ts +12 -0
  148. package/skills/spec-wiki/evals/files/bootstrap/tests/payments.test.ts +11 -0
  149. package/skills/spec-wiki/evals/files/focused/src/session.ts +5 -0
  150. package/skills/spec-wiki/evals/files/focused/tests/session.test.ts +17 -0
  151. package/skills/spec-wiki/evals/files/maintenance/low-signal/incoming/capture.txt +2 -0
  152. package/skills/spec-wiki/evals/files/maintenance/low-signal/src/capture.ts +3 -0
  153. package/skills/spec-wiki/evals/files/maintenance/move/docs/old-job-contract.md +18 -0
  154. package/skills/spec-wiki/evals/files/maintenance/move/src/job.ts +5 -0
  155. package/skills/spec-wiki/evals/files/maintenance/new-relation/docs/session-refresh.md +24 -0
  156. package/skills/spec-wiki/evals/files/maintenance/new-relation/incoming/refresh-worker.ts +7 -0
  157. package/skills/spec-wiki/evals/files/maintenance/new-relation/src/session.ts +7 -0
  158. package/skills/spec-wiki/evals/files/maintenance/no-impact/docs/auth-contract.md +17 -0
  159. package/skills/spec-wiki/evals/files/maintenance/no-impact/incoming/telemetry-format.ts +3 -0
  160. package/skills/spec-wiki/evals/files/maintenance/no-impact/src/auth.ts +3 -0
  161. package/skills/spec-wiki/evals/files/query/docs/how-to-run-jobs.md +4 -0
  162. package/skills/spec-wiki/evals/files/query/docs/spec-overview.md +9 -0
  163. package/skills/spec-wiki/evals/files/query/features/jobs/cancellation-contract.md +15 -0
  164. package/skills/spec-wiki/evals/files/query/features/jobs/retry-spec.md +6 -0
  165. package/skills/spec-wiki/evals/maintenance_regression.py +311 -0
  166. package/skills/spec-wiki/evals/retrieval-eval.md +37 -0
  167. package/skills/spec-wiki/evals/retrieval-evals.json +37 -0
  168. package/skills/spec-wiki/evals/trigger-evals.json +94 -0
  169. package/skills/spec-wiki/references/bootstrap.md +100 -0
  170. package/skills/spec-wiki/references/focused-spec.md +117 -0
  171. package/skills/spec-wiki/references/index-schema.md +330 -0
  172. package/skills/spec-wiki/references/maintenance.md +134 -0
  173. package/skills/spec-wiki/references/query.md +74 -0
  174. package/skills/spec-wiki/scripts/spec_wiki.py +2076 -0
  175. package/docs/desktop-markdown-media.md +0 -77
  176. package/external/pi-tools-suite/docs/dcp-emergency-current-turn.md +0 -102
  177. package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +0 -270
  178. package/external/pi-tools-suite/src/async-subagents/private-skills/browser-qa/references/auth-scaffold-spec.md +0 -78
  179. package/external/pi-tools-suite/src/async-subagents/private-skills/browser-qa/references/qa-design.md +0 -223
  180. package/external/pi-tools-suite/src/dcp/state-persistence.ts +0 -195
  181. package/external/pi-tools-suite/src/skill-installer/index.ts +0 -333
  182. package/skills/spec-lite/SKILL.md +0 -140
  183. /package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/references → agents/browser-qa/examples}/qa-auth.example.jsonc +0 -0
  184. /package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/references → agents/browser-qa/examples}/qa-flow.example.jsonc +0 -0
  185. /package/external/pi-tools-suite/src/async-subagents/{private-skills → agents}/browser-qa/vendor/fflate.LICENSE +0 -0
  186. /package/external/pi-tools-suite/src/async-subagents/{private-skills → agents}/browser-qa/vendor/fflate.mjs +0 -0
@@ -0,0 +1,311 @@
1
+ #!/usr/bin/env python3
2
+ """Deterministic regression checks for Spec Wiki maintenance primitives."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import json
7
+ import subprocess
8
+ import tempfile
9
+ from pathlib import Path
10
+
11
+
12
+ CLI = Path(__file__).resolve().parents[1] / "scripts" / "spec_wiki.py"
13
+
14
+
15
+ def run(cwd: Path, *args: str) -> str:
16
+ proc = subprocess.run(
17
+ ["python3", str(CLI), "--root", str(cwd), *args],
18
+ cwd=cwd,
19
+ text=True,
20
+ stdout=subprocess.PIPE,
21
+ stderr=subprocess.PIPE,
22
+ check=False,
23
+ )
24
+ if proc.returncode != 0:
25
+ raise AssertionError(f"command failed {args}:\nstdout={proc.stdout}\nstderr={proc.stderr}")
26
+ return proc.stdout
27
+
28
+
29
+ def run_json(cwd: Path, *args: str) -> dict:
30
+ return json.loads(run(cwd, *args, "--json"))
31
+
32
+
33
+ def git(cwd: Path, *args: str) -> None:
34
+ subprocess.run(["git", *args], cwd=cwd, check=True, stdout=subprocess.DEVNULL)
35
+
36
+
37
+ def write(root: Path, rel: str, text: str) -> None:
38
+ path = root / rel
39
+ path.parent.mkdir(parents=True, exist_ok=True)
40
+ path.write_text(text, encoding="utf-8")
41
+
42
+
43
+ def init_repo(root: Path) -> None:
44
+ git(root, "init", "-q")
45
+ git(root, "config", "user.email", "spec-wiki-eval@example.com")
46
+ git(root, "config", "user.name", "Spec Wiki Eval")
47
+
48
+
49
+ def commit_all(root: Path, message: str = "baseline") -> None:
50
+ git(root, "add", ".")
51
+ git(root, "commit", "-qm", message)
52
+
53
+
54
+ def test_relation_map_invalidates_verification(tmp: Path) -> None:
55
+ root = tmp / "relations"
56
+ root.mkdir()
57
+ init_repo(root)
58
+ write(root, "src/a.ts", "export const a = 1\n")
59
+ write(root, "src/b.ts", "export const b = 2\n")
60
+ write(
61
+ root,
62
+ "docs/contract.md",
63
+ """# Contract
64
+
65
+ ## Type
66
+ As-is
67
+
68
+ ## Lifecycle
69
+ Active
70
+
71
+ ## Behavior
72
+ A is part of the current contract.
73
+
74
+ ## Related files
75
+ - `src/a.ts`
76
+ """,
77
+ )
78
+ commit_all(root)
79
+ run(
80
+ root,
81
+ "record",
82
+ "--path",
83
+ "docs/contract.md",
84
+ "--classification",
85
+ "spec",
86
+ "--type",
87
+ "as-is",
88
+ "--lifecycle",
89
+ "active",
90
+ "--confidence",
91
+ "high",
92
+ "--summary",
93
+ "Contract for A.",
94
+ )
95
+ run(root, "verify", "--path", "docs/contract.md")
96
+ audit = run_json(root, "audit")
97
+ assert audit["freshCount"] == 1
98
+
99
+ run(root, "relate", "--path", "docs/contract.md", "--add-code", "src/b.ts")
100
+ audit = run_json(root, "audit")
101
+ assert audit["freshCount"] == 0
102
+ status = next(item for item in audit["statuses"] if item["path"] == "docs/contract.md")
103
+ assert status["status"] == "inputs-changed"
104
+ assert "relations:changed" in status["reasons"]
105
+
106
+ run(root, "verify", "--path", "docs/contract.md")
107
+ assert run_json(root, "audit")["freshCount"] == 1
108
+ run(root, "relate", "--path", "docs/contract.md", "--remove-code", "src/b.ts")
109
+ status = next(item for item in run_json(root, "audit")["statuses"] if item["path"] == "docs/contract.md")
110
+ assert status["status"] == "inputs-changed"
111
+ assert status["reasons"] == ["relations:changed"]
112
+
113
+
114
+ def test_impact_detects_coverage_gaps_and_moves(tmp: Path) -> None:
115
+ root = tmp / "impact"
116
+ root.mkdir()
117
+ init_repo(root)
118
+ write(root, "src/session.ts", "export function session() { return 'ok' }\n")
119
+ write(
120
+ root,
121
+ "docs/session-contract.md",
122
+ """# Session contract
123
+
124
+ ## Type
125
+ As-is
126
+
127
+ ## Lifecycle
128
+ Active
129
+
130
+ ## Behavior
131
+ Session loading returns the current session.
132
+
133
+ ## Related files
134
+ - `src/session.ts`
135
+ """,
136
+ )
137
+ commit_all(root)
138
+ run(
139
+ root,
140
+ "record",
141
+ "--path",
142
+ "docs/session-contract.md",
143
+ "--classification",
144
+ "spec",
145
+ "--type",
146
+ "as-is",
147
+ "--lifecycle",
148
+ "active",
149
+ "--confidence",
150
+ "high",
151
+ "--summary",
152
+ "Session loading contract.",
153
+ )
154
+ run(root, "verify", "--path", "docs/session-contract.md")
155
+
156
+ git(root, "mv", "docs/session-contract.md", "docs/session-lifecycle.md")
157
+ with (root / "docs/session-lifecycle.md").open("a", encoding="utf-8") as handle:
158
+ handle.write("\nMoved without changing the behavioral contract.\n")
159
+ write(root, "src/refresh-worker.ts", "export const retryOnce = true\n")
160
+ write(root, "notes.txt", "deliberately low signal document\n")
161
+
162
+ impact = run_json(root, "impact")
163
+ assert ".spec-wiki/state.json" not in impact["changedPaths"]
164
+ assert any(
165
+ item.get("status") == "R"
166
+ and item.get("oldPath") == "docs/session-contract.md"
167
+ and item.get("path") == "docs/session-lifecycle.md"
168
+ for item in impact["changes"]
169
+ )
170
+ assert "src/refresh-worker.ts" in impact["uncoveredPaths"]
171
+ changed_docs = {item["path"]: item for item in impact["changedDocuments"]}
172
+ assert changed_docs["docs/session-lifecycle.md"]["requiresClassification"] is True
173
+ assert changed_docs["notes.txt"]["score"] == 0
174
+ assert "docs/session-contract.md" in impact["missingTrackedSpecs"]
175
+ assert impact["semanticSweepRequired"] is True
176
+
177
+
178
+ def test_deep_audit_finds_low_signal_committed_docs(tmp: Path) -> None:
179
+ root = tmp / "deep"
180
+ root.mkdir()
181
+ init_repo(root)
182
+ write(
183
+ root,
184
+ "notes/capture.txt",
185
+ "Duplicate capture requests with the same key return the original result.\n",
186
+ )
187
+ write(root, "skills/example/evals/fixture.md", "# Contract\n\n## Behavior\nFixture only.\n")
188
+ commit_all(root)
189
+
190
+ normal = run_json(root, "discover", "--limit", "100")
191
+ assert "notes/capture.txt" not in {item["path"] for item in normal["candidates"]}
192
+ deep = run_json(root, "discover", "--all-unclassified", "--limit", "100")
193
+ paths = {item["path"] for item in deep["candidates"]}
194
+ assert "notes/capture.txt" in paths
195
+ assert "skills/example/evals/fixture.md" not in paths
196
+
197
+
198
+ def test_relate_restores_source_explicit_relation(tmp: Path) -> None:
199
+ root = tmp / "supersession"
200
+ root.mkdir()
201
+ init_repo(root)
202
+ write(root, "docs/b.md", "# B\n")
203
+ write(
204
+ root,
205
+ "docs/a.md",
206
+ """# A contract
207
+
208
+ ## Type
209
+ As-is
210
+
211
+ ## Lifecycle
212
+ Active
213
+
214
+ ## Behavior
215
+ A references B.
216
+
217
+ [B](./b.md)
218
+ """,
219
+ )
220
+ commit_all(root)
221
+ run(
222
+ root,
223
+ "record",
224
+ "--path",
225
+ "docs/a.md",
226
+ "--classification",
227
+ "spec",
228
+ "--type",
229
+ "as-is",
230
+ "--lifecycle",
231
+ "active",
232
+ "--confidence",
233
+ "high",
234
+ "--summary",
235
+ "A contract.",
236
+ )
237
+ run(root, "verify", "--path", "docs/a.md")
238
+ run(root, "relate", "--path", "docs/a.md", "--add-supersedes", "docs/b.md")
239
+ state = json.loads((root / ".spec-wiki/state.json").read_text(encoding="utf-8"))
240
+ relations = state["entries"]["docs/a.md"]["relations"]["specs"]
241
+ assert any(
242
+ item.get("path") == "docs/b.md"
243
+ and item.get("source") == "explicit"
244
+ and item.get("kind") == "related"
245
+ for item in relations
246
+ )
247
+ assert any(item.get("path") == "docs/b.md" and item.get("kind") == "supersedes" for item in relations)
248
+ run(root, "relate", "--path", "docs/a.md", "--remove-supersedes", "docs/b.md")
249
+ state = json.loads((root / ".spec-wiki/state.json").read_text(encoding="utf-8"))
250
+ relations = state["entries"]["docs/a.md"]["relations"]["specs"]
251
+ assert any(
252
+ item.get("path") == "docs/b.md"
253
+ and item.get("source") == "explicit"
254
+ and item.get("kind") == "related"
255
+ for item in relations
256
+ )
257
+ assert not any(item.get("kind") == "supersedes" for item in relations)
258
+
259
+
260
+ def test_changed_non_primary_requires_reclassification(tmp: Path) -> None:
261
+ root = tmp / "reclassification"
262
+ root.mkdir()
263
+ init_repo(root)
264
+ write(root, "docs/info.md", "# Operator notes\n\nRun the service with --help.\n")
265
+ commit_all(root)
266
+ run(
267
+ root,
268
+ "record",
269
+ "--path",
270
+ "docs/info.md",
271
+ "--classification",
272
+ "guide",
273
+ "--summary",
274
+ "Operator notes.",
275
+ )
276
+ write(
277
+ root,
278
+ "docs/info.md",
279
+ """# Request contract
280
+
281
+ ## Type
282
+ As-is
283
+
284
+ ## Lifecycle
285
+ Active
286
+
287
+ ## Behavior
288
+ Duplicate requests return the original result.
289
+ """,
290
+ )
291
+ impact = run_json(root, "impact", "docs/info.md")
292
+ changed = next(item for item in impact["changedDocuments"] if item["path"] == "docs/info.md")
293
+ assert changed["knownClassification"] == "guide"
294
+ assert changed["requiresClassification"] is False
295
+ assert changed["requiresReclassification"] is True
296
+ assert impact["semanticSweepRequired"] is True
297
+
298
+
299
+ def main() -> None:
300
+ with tempfile.TemporaryDirectory(prefix="spec-wiki-maint-") as directory:
301
+ tmp = Path(directory)
302
+ test_relation_map_invalidates_verification(tmp)
303
+ test_impact_detects_coverage_gaps_and_moves(tmp)
304
+ test_deep_audit_finds_low_signal_committed_docs(tmp)
305
+ test_relate_restores_source_explicit_relation(tmp)
306
+ test_changed_non_primary_requires_reclassification(tmp)
307
+ print("maintenance regression: 5/5 passed")
308
+
309
+
310
+ if __name__ == "__main__":
311
+ main()
@@ -0,0 +1,37 @@
1
+ # Retrieval regression protocol
2
+
3
+ Use `retrieval-evals.json` to check the query router after search/index changes.
4
+ The cases are intentionally mixed: direct keywords, natural paraphrases,
5
+ Russian requests, synonyms, exact code paths, and symbols.
6
+
7
+ ## Guard against answer leakage
8
+
9
+ The retrieval agent must receive only each case `id` and `query`. Do not expose
10
+ `expectedAny` until after it returns candidate paths.
11
+
12
+ ## Stage 1: deterministic candidate generation
13
+
14
+ Run `spec_wiki.py search` against the current `.spec-wiki/state.json` and record
15
+ top-1/top-3/top-5 plus `confidence` / `catalogFallbackRecommended`. This stage is
16
+ expected to be imperfect for semantic paraphrases; its job is cheap candidate
17
+ generation and reliable low-confidence detection.
18
+
19
+ ## Stage 2: full skill workflow
20
+
21
+ Have a fresh agent read only `SKILL.md` and `references/query.md`, then for each
22
+ query:
23
+
24
+ 1. create the in-model retrieval bundle;
25
+ 2. call relation-aware `search` with `--also` aliases;
26
+ 3. semantically rerank compact result metadata;
27
+ 4. when fallback is recommended or intent coverage is visibly incomplete, use
28
+ only `.spec-wiki/index.md` as the semantic catalog fallback;
29
+ 5. return up to three primary spec paths without opening the primary specs.
30
+
31
+ Compare those paths with `expectedAny` only after the run. A case passes top-k
32
+ when any expected path appears in the first k selections.
33
+
34
+ Current target for this repository: at least 95% top-1 and 100% top-3/recall.
35
+ Do not tune expected paths after seeing a run merely to improve the score; change
36
+ an expectation only when independent review shows that more than one primary
37
+ spec is genuinely defensible.
@@ -0,0 +1,37 @@
1
+ {
2
+ "version": 1,
3
+ "description": "Live retrieval regression cases for the host repository. Expected paths are chosen before running the search; use expectedAny when more than one primary spec is defensible.",
4
+ "cases": [
5
+ {"id":"kw-dcp","category":"keyword","query":"dcp persistence recovery","expectedAny":["specs/dcp.md"]},
6
+ {"id":"kw-desktop-markdown","category":"keyword","query":"desktop markdown mermaid file preview","expectedAny":["specs/desktop-markdown-rendering.md"]},
7
+ {"id":"kw-project-agents","category":"keyword","query":"project local agents .pi/agents","expectedAny":["specs/project-agents-dir.md"]},
8
+ {"id":"kw-question-tab","category":"keyword","query":"question inactive tab","expectedAny":["specs/question-inactive-tab.md"]},
9
+ {"id":"kw-retry-toast","category":"keyword","query":"retry toast action","expectedAny":["specs/retry-toast-action.md"]},
10
+ {"id":"kw-openai-usage","category":"keyword","query":"openai codex token refresh usage","expectedAny":["specs/openai-codex-usage-refresh.md"]},
11
+
12
+ {"id":"para-recovery","category":"paraphrase","query":"recover old conversation after compaction","expectedAny":["external/pi-tools-suite/docs/session-recovery.md"]},
13
+ {"id":"para-browser-qa","category":"paraphrase","query":"browser qa credentials origin isolation redaction","expectedAny":["external/pi-tools-suite/docs/browser-qa-subagent.md"]},
14
+ {"id":"para-concurrency","category":"paraphrase","query":"async callback updates the wrong session tab","expectedAny":["docs/concurrency.md"]},
15
+ {"id":"para-cache","category":"paraphrase","query":"keep tool output stable for prompt caching","expectedAny":["specs/dcp-provider-cache-stability.md"]},
16
+ {"id":"para-window","category":"paraphrase","query":"window opens offscreen after monitor change","expectedAny":["specs/desktop-window-state.md"]},
17
+ {"id":"para-copy","category":"paraphrase","query":"copy last assistant response slash command","expectedAny":["specs/desktop-slash-commands.md"]},
18
+ {"id":"para-task-jsonc","category":"paraphrase","query":"task storage comments jsonc","expectedAny":["docs/desktop-task-manager.md"]},
19
+ {"id":"para-wrapped-link","category":"paraphrase","query":"click file uri in wrapped markdown","expectedAny":["specs/clickable-markdown-links.md"]},
20
+ {"id":"para-zed","category":"paraphrase","query":"open source file in zed at line","expectedAny":["specs/file-link-opening.md"]},
21
+
22
+ {"id":"ru-recovery","category":"russian","query":"как восстанавливается история после сжатия контекста","expectedAny":["external/pi-tools-suite/docs/session-recovery.md"]},
23
+ {"id":"ru-zed","category":"russian","query":"как открыть ссылку на файл в zed","expectedAny":["specs/file-link-opening.md"]},
24
+ {"id":"ru-question-tab","category":"russian","query":"что происходит с вопросом в неактивной вкладке","expectedAny":["specs/question-inactive-tab.md"]},
25
+ {"id":"ru-tasks","category":"russian","query":"где хранятся задачи проекта и поддерживаются ли комментарии","expectedAny":["docs/desktop-task-manager.md"]},
26
+ {"id":"ru-provider-seen","category":"russian","query":"почему старый tool result нельзя удалять до отправки провайдеру","expectedAny":["specs/dcp-provider-cache-stability.md"]},
27
+
28
+ {"id":"syn-auth","category":"synonym","query":"oauth account rotation when quota exhausted","expectedAny":["specs/antigravity-auth.md"]},
29
+ {"id":"syn-background-agent","category":"synonym","query":"cancel a running background agent","expectedAny":["specs/async-subagents.md"]},
30
+
31
+ {"id":"path-openai","category":"path","query":"src/app/model/model-usage-status.ts","expectedAny":["specs/openai-codex-usage-refresh.md"]},
32
+ {"id":"path-dcp-journal","category":"path","query":"external/pi-tools-suite/src/dcp/journal.ts","expectedAny":["specs/dcp.md","specs/dcp-reliability-mechanisms.md","specs/dcp-provider-cache-stability.md"]},
33
+
34
+ {"id":"symbol-sidebar","category":"symbol","query":"WorkspaceSidebar.svelte tasks","expectedAny":["docs/desktop-task-manager.md"]},
35
+ {"id":"symbol-question-bridge","category":"symbol","query":"ui-request-bridge question","expectedAny":["specs/desktop-question-tool.md"]}
36
+ ]
37
+ }
@@ -0,0 +1,94 @@
1
+ [
2
+ {
3
+ "query": "Before we touch src/auth/session.ts, write a compact spec for the new refresh-token rotation behavior. It changes persistence and the public login flow, and I want the expected behavior and verification path clear before implementation.",
4
+ "should_trigger": true
5
+ },
6
+ {
7
+ "query": "We have a pile of design docs under docs/, architecture/, and feature folders with no central specs directory. Find which ones are actual behavioral specs and build a small LLM-friendly project spec index without treating existing overview pages as source-of-truth.",
8
+ "should_trigger": true
9
+ },
10
+ {
11
+ "query": "src/jobs/runner.ts changed yesterday. Can you tell me which project specs may now be stale and check whether the documented cancellation/retry behavior still matches code and tests?",
12
+ "should_trigger": true
13
+ },
14
+ {
15
+ "query": "Which of our specs defines desktop session restore behavior? Please answer from the primary spec rather than scanning every markdown file, and warn me if the relevant spec looks stale.",
16
+ "should_trigger": true
17
+ },
18
+ {
19
+ "query": "The bug fix changes an externally visible CLI exit-code contract. Update the existing spec to describe the intended behavior, edge cases and compatibility, but don't implement the code yet.",
20
+ "should_trigger": true
21
+ },
22
+ {
23
+ "query": "Document the current as-is behavior of our webhook retry loop from code and tests. I'm especially worried the README is stale, so separate confirmed behavior from inference and unknowns.",
24
+ "should_trigger": true
25
+ },
26
+ {
27
+ "query": "We renamed several contract docs and moved implementation files. Refresh the project's spec knowledge base, repair missing paths, and show me which specs still need semantic review.",
28
+ "should_trigger": true
29
+ },
30
+ {
31
+ "query": "What do the project requirements say about idempotency for payment capture? There are multiple RFCs and an overview; find the primary spec and answer with its source path.",
32
+ "should_trigger": true
33
+ },
34
+ {
35
+ "query": "I'm about to change the on-disk cache schema. Check if we already have a spec for that behavior; if not, create a lightweight change spec before touching implementation.",
36
+ "should_trigger": true
37
+ },
38
+ {
39
+ "query": "Inventory the behavioral contracts in this unfamiliar repo and tell me which ones are affected by the changes in src/api and src/storage. Specs may be scattered and inconsistently named.",
40
+ "should_trigger": true
41
+ },
42
+ {
43
+ "query": "Implement background session refresh so a transient token-load failure is retried exactly once and a second failure still propagates. Add the code and tests and verify the change is complete.",
44
+ "should_trigger": true
45
+ },
46
+ {
47
+ "query": "I added a new src/auth/refresh-policy.ts implementation surface for an existing login behavior. Finish the change and make sure any project contracts or knowledge that should track the new file stay current.",
48
+ "should_trigger": true
49
+ },
50
+ {
51
+ "query": "Refactor src/utils/string.ts to use a helper function. This is a mechanical cleanup with no externally visible behavior change; just update the code and tests.",
52
+ "should_trigger": false
53
+ },
54
+ {
55
+ "query": "Write an ADR comparing Postgres and SQLite for a future analytics service. I want design tradeoffs and a decision record, not a behavior contract or spec audit.",
56
+ "should_trigger": false
57
+ },
58
+ {
59
+ "query": "Rewrite docs/getting-started.md so new users understand how to log in and run the CLI. Keep it friendly and add examples.",
60
+ "should_trigger": false
61
+ },
62
+ {
63
+ "query": "Search all markdown files for the exact string `refresh_token` and show me the matching lines. Don't interpret or update any documentation.",
64
+ "should_trigger": false
65
+ },
66
+ {
67
+ "query": "Trace callers of createSession and tell me what code modules would be affected by changing its return type. I only need code impact analysis, not documentation work.",
68
+ "should_trigger": false
69
+ },
70
+ {
71
+ "query": "Generate API reference pages from our OpenAPI JSON and publish them under docs/generated/. The schema is already authoritative; don't create or review project specs.",
72
+ "should_trigger": false
73
+ },
74
+ {
75
+ "query": "Summarize architecture/rfc-019.md for me in five bullets. I only want a summary of this one file, not a spec validation or project knowledge index.",
76
+ "should_trigger": false
77
+ },
78
+ {
79
+ "query": "Fix the typo in the error message in src/ui/toast.ts and adjust the snapshot. No contract or compatibility behavior changes.",
80
+ "should_trigger": false
81
+ },
82
+ {
83
+ "query": "Create a migration runbook for operators moving production from Redis 6 to Redis 7, including rollback commands and monitoring checks.",
84
+ "should_trigger": false
85
+ },
86
+ {
87
+ "query": "Compare these two external W3C specifications and explain the differences in browser behavior. This isn't about specs stored in our project.",
88
+ "should_trigger": false
89
+ },
90
+ {
91
+ "query": "Add a debug-only telemetry label to an internal helper and update its unit test. It must not change any user-visible behavior, persistence, API, retry, or compatibility contract.",
92
+ "should_trigger": false
93
+ }
94
+ ]
@@ -0,0 +1,100 @@
1
+ # Bootstrap the Spec Wiki
2
+
3
+ Use for repository-wide discovery when no useful `.spec-wiki/state.json` exists,
4
+ or when the user explicitly asks to inventory scattered specifications.
5
+
6
+ The repository may have no `specs/` directory, no frontmatter, inconsistent
7
+ formats, and multiple documentation roots.
8
+
9
+ ## Workflow
10
+
11
+ 1. Run `discover --limit 40`.
12
+ 2. Read only the high-signal shortlist.
13
+ 3. Semantically classify each candidate:
14
+ - `spec` — primary normative/descriptive specification;
15
+ - `spec-like` — useful spec knowledge with mixed/ambiguous purpose;
16
+ - `meta-index` — overview, inventory, catalog, TOC, generated index;
17
+ - `design-only` — design/decision material without enough behavioral contract;
18
+ - `guide` — tutorial/runbook/usage documentation;
19
+ - `other` — not useful spec knowledge.
20
+ Treat files under eval/fixture/example/testdata trees, skill resources, and
21
+ agent-role definition directories as examples/runtime configuration by
22
+ default, not project primary specs, unless repository evidence explicitly
23
+ says that document itself is normative project behavior.
24
+
25
+ Location is not a reason to downgrade a document. A document outside a
26
+ `specs/` directory that explicitly declares its behavioral Type/Lifecycle
27
+ and defines testable behavior/contracts/invariants should normally be
28
+ `spec`. Reserve `spec-like` for genuinely mixed-purpose or ambiguous
29
+ documents, not for clear subsystem contracts living under `docs/`.
30
+ 4. `record` every reviewed classification. For `spec`/`spec-like`, provide a
31
+ concise summary, type, lifecycle, confidence, and a few retrieval topics.
32
+ Classification/indexing is **not** semantic verification: bootstrap entries
33
+ normally remain `unverified` until a focused code/test review occurs.
34
+ 5. After recording a batch, rerun `discover --limit 40` from offset 0; unchanged
35
+ reviewed documents drop from the default shortlist.
36
+ 6. Continue until useful candidates are exhausted or coverage becomes too broad.
37
+ Report incomplete coverage rather than reading hundreds of weak candidates.
38
+ 7. Run `render` and `validate`.
39
+
40
+ Do not call `verify` merely because a document was read during discovery. Call
41
+ it only after checking the document's behavioral claims against the relevant
42
+ implementation/tests (or other authoritative evidence for a proposed contract).
43
+
44
+ ## What counts as a primary spec
45
+
46
+ A primary spec describes current or intended behavior, requirements, contracts,
47
+ invariants, externally observable semantics, acceptance criteria, compatibility
48
+ rules, or similarly testable expectations.
49
+
50
+ Classification is semantic. Filename, folder, headings, and links are signals,
51
+ not requirements.
52
+
53
+ ## Lifecycle
54
+
55
+ Classify primary documents separately from their as-is/change type:
56
+
57
+ - `active` — current authoritative contract;
58
+ - `proposed` — intended contract not yet established as current behavior;
59
+ - `historical` — useful milestone/history, not current precedence;
60
+ - `superseded` — replaced by a newer primary spec; add `--superseded-by`;
61
+ - `unknown` — lifecycle cannot be established safely.
62
+
63
+ Useful default reasoning:
64
+
65
+ - an as-is/current-behavior contract is normally `active` unless clearly
66
+ historical;
67
+ - a change document whose behavior is already implemented and still governs the
68
+ system is normally `active`;
69
+ - an intended/not-yet-implemented change is `proposed`;
70
+ - milestone documents whose former non-goals/features were later superseded are
71
+ `historical` unless a newer document explicitly replaces their whole contract;
72
+ - use `superseded` only when a specific replacement exists and record that edge.
73
+
74
+ The CLI requires explicit `--type` and `--lifecycle` on the first primary-spec
75
+ record so omission cannot silently become precedence metadata.
76
+
77
+ Use `--supersedes` / `--superseded-by` for known precedence instead of leaving
78
+ overlapping documents as coequal active specs.
79
+
80
+ ## Meta/index exclusion
81
+
82
+ Do not index derived inventories as primary specs. They are useful only to find
83
+ primary documents missed by heuristics. This avoids recursive knowledge such as:
84
+
85
+ `spec -> old index summary -> new wiki summary`.
86
+
87
+ ## Relationships
88
+
89
+ The CLI extracts resolvable source links/paths as `explicit` relationships. Add
90
+ `--code` or `--related-spec` only for relationships actually established from
91
+ repository evidence; these are recorded as `inferred`.
92
+
93
+ The resolver tries the source directory, nearest package/project roots, and the
94
+ repository root. Review `unresolvedReferences` after bootstrap: they are path-like
95
+ hints that could not be resolved deterministically and may need an inferred
96
+ relation or a source-doc fix.
97
+
98
+ Use project-relative path identity, never numeric prefixes as unique IDs.
99
+
100
+ For exact command/config/state details, read `index-schema.md`.