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.
- package/README.md +10 -2
- package/dist/app/app.d.ts +3 -0
- package/dist/app/app.js +26 -0
- package/dist/app/commands/command-host.d.ts +1 -0
- package/dist/app/commands/command-model-actions.js +6 -1
- package/dist/app/commands/command-registry.js +3 -3
- package/dist/app/commands/command-session-actions.d.ts +0 -1
- package/dist/app/commands/command-session-actions.js +30 -15
- package/dist/app/commands/reload-context-inventory.d.ts +11 -0
- package/dist/app/commands/reload-context-inventory.js +59 -0
- package/dist/app/extensions/extension-actions-controller.d.ts +1 -0
- package/dist/app/extensions/extension-actions-controller.js +6 -0
- package/dist/app/extensions/subagent-catalog-state.d.ts +9 -0
- package/dist/app/extensions/subagent-catalog-state.js +23 -0
- package/dist/app/icons.d.ts +14 -0
- package/dist/app/icons.js +33 -0
- package/dist/app/rendering/conversation-tool-renderer.js +2 -2
- package/dist/app/rendering/dcp-stats.d.ts +6 -1
- package/dist/app/rendering/dcp-stats.js +214 -46
- package/dist/app/rendering/editor-panels.js +17 -8
- package/dist/app/session/lazy-session-manager.js +12 -1
- package/dist/app/session/session-lifecycle-controller.d.ts +1 -0
- package/dist/app/session/session-lifecycle-controller.js +6 -0
- package/dist/app/session/tabs-controller.d.ts +3 -5
- package/dist/app/session/tabs-controller.js +31 -22
- package/dist/app/subagents/subagents-files.js +60 -1
- package/dist/app/subagents/subagents-model.d.ts +15 -1
- package/dist/app/subagents/subagents-model.js +52 -17
- package/dist/app/types.d.ts +7 -0
- package/dist/bundled-extensions/session-title/config.js +1 -1
- package/dist/default-pix-config.js +10 -0
- package/dist/markdown-format.js +27 -9
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/index.js +1 -0
- package/dist/schemas/pi-tools-suite-schema.d.ts +106 -71
- package/dist/schemas/pi-tools-suite-schema.js +68 -88
- package/dist/schemas/pix-schema.d.ts +7 -0
- package/dist/schemas/pix-schema.js +14 -0
- package/dist/schemas/tasks-schema.d.ts +18 -0
- package/dist/schemas/tasks-schema.js +41 -0
- package/docs/concurrency.md +6 -0
- package/docs/desktop-mvp.md +12 -1
- package/docs/desktop-task-manager.md +93 -82
- package/external/pi-tools-suite/README.md +192 -72
- package/external/pi-tools-suite/docs/browser-qa-subagent.md +50 -21
- package/external/pi-tools-suite/docs/context-gateway-p00-adr.md +216 -0
- package/external/pi-tools-suite/docs/context-gateway-p01n-gate-review.md +122 -0
- package/external/pi-tools-suite/docs/context-gateway-p01n-measurement.md +133 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-ra-evidence.md +111 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-rb-evidence.md +100 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-rc-evidence.md +69 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-rd-evidence.md +100 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-re-evidence.md +74 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-rf-evidence.md +153 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-rg-evidence.md +235 -0
- package/external/pi-tools-suite/docs/evals.md +1 -1
- package/external/pi-tools-suite/docs/session-recovery.md +40 -14
- package/external/pi-tools-suite/docs/subagent-model-pools.md +120 -0
- package/external/pi-tools-suite/package.json +3 -0
- package/external/pi-tools-suite/src/async-subagents/{private-skills → agents}/browser-qa/scripts/browser-qa-runner.mjs +82 -1
- package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/SKILL.md → agents/browser-qa.md} +261 -12
- package/external/pi-tools-suite/src/async-subagents/agents/frontier-review.md +23 -0
- package/external/pi-tools-suite/src/async-subagents/agents/implement.md +20 -0
- package/external/pi-tools-suite/src/async-subagents/agents/oracle.md +16 -0
- package/external/pi-tools-suite/src/async-subagents/agents/presets.jsonc +16 -0
- package/external/pi-tools-suite/src/async-subagents/agents/research.md +20 -0
- package/external/pi-tools-suite/src/async-subagents/agents/verify.md +18 -0
- package/external/pi-tools-suite/src/async-subagents/commands.ts +20 -72
- package/external/pi-tools-suite/src/async-subagents/core/activity.ts +33 -0
- package/external/pi-tools-suite/src/async-subagents/core/agent-catalog.ts +42 -0
- package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +13 -93
- package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +499 -0
- package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +9 -0
- package/external/pi-tools-suite/src/async-subagents/core/config.ts +284 -417
- package/external/pi-tools-suite/src/async-subagents/core/model-fallback.ts +1 -1
- package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +54 -0
- package/external/pi-tools-suite/src/async-subagents/core/prompt.ts +7 -6
- package/external/pi-tools-suite/src/async-subagents/core/routing.ts +65 -45
- package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +18 -6
- package/external/pi-tools-suite/src/async-subagents/core/state.ts +40 -0
- package/external/pi-tools-suite/src/async-subagents/core/types.ts +7 -0
- package/external/pi-tools-suite/src/async-subagents/index.ts +77 -3
- package/external/pi-tools-suite/src/async-subagents/lib.ts +12 -9
- package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +54 -22
- package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +6 -4
- package/external/pi-tools-suite/src/async-subagents/types.ts +3 -0
- package/external/pi-tools-suite/src/config.ts +42 -2
- package/external/pi-tools-suite/src/context-gateway/accounting.ts +151 -0
- package/external/pi-tools-suite/src/context-gateway/config.ts +120 -0
- package/external/pi-tools-suite/src/context-gateway/enforcement.ts +102 -0
- package/external/pi-tools-suite/src/context-gateway/index.ts +214 -0
- package/external/pi-tools-suite/src/context-gateway/metadata-normalization.ts +88 -0
- package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +89 -0
- package/external/pi-tools-suite/src/context-gateway/telemetry.ts +502 -0
- package/external/pi-tools-suite/src/context-gateway/test-output-parser.ts +326 -0
- package/external/pi-tools-suite/src/context-gateway/types.ts +158 -0
- package/external/pi-tools-suite/src/context-inventory.ts +99 -0
- package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +106 -0
- package/external/pi-tools-suite/src/dcp/auto-compress.ts +892 -136
- package/external/pi-tools-suite/src/dcp/commands.ts +82 -139
- package/external/pi-tools-suite/src/dcp/compress-tool.ts +533 -74
- package/external/pi-tools-suite/src/dcp/compression-blocks.ts +488 -94
- package/external/pi-tools-suite/src/dcp/compression-preview.ts +122 -0
- package/external/pi-tools-suite/src/dcp/compression-progress.ts +70 -0
- package/external/pi-tools-suite/src/dcp/config.ts +86 -68
- package/external/pi-tools-suite/src/dcp/conversation-index.ts +421 -0
- package/external/pi-tools-suite/src/dcp/debug-log.ts +7 -5
- package/external/pi-tools-suite/src/dcp/index.ts +617 -203
- package/external/pi-tools-suite/src/dcp/journal.ts +566 -0
- package/external/pi-tools-suite/src/dcp/progress-controller.ts +244 -0
- package/external/pi-tools-suite/src/dcp/prompts.ts +83 -189
- package/external/pi-tools-suite/src/dcp/protected-continuity.ts +175 -0
- package/external/pi-tools-suite/src/dcp/provider-tool-results.ts +189 -0
- package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +299 -79
- package/external/pi-tools-suite/src/dcp/pruner-compression-blocks.ts +173 -281
- package/external/pi-tools-suite/src/dcp/pruner-emergency.ts +2 -4
- package/external/pi-tools-suite/src/dcp/pruner-message-ids.ts +23 -15
- package/external/pi-tools-suite/src/dcp/pruner-metadata.ts +11 -1
- package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +30 -82
- package/external/pi-tools-suite/src/dcp/pruner-tools.ts +28 -136
- package/external/pi-tools-suite/src/dcp/pruner.ts +18 -33
- package/external/pi-tools-suite/src/dcp/recovery.ts +129 -0
- package/external/pi-tools-suite/src/dcp/shadow-plan.ts +127 -0
- package/external/pi-tools-suite/src/dcp/state-transaction.ts +102 -0
- package/external/pi-tools-suite/src/dcp/state.ts +158 -580
- package/external/pi-tools-suite/src/dcp/ui.ts +1 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +36 -214
- package/external/pi-tools-suite/src/index.ts +16 -1
- package/external/pi-tools-suite/src/model-tools/index.ts +76 -42
- package/external/pi-tools-suite/src/repo-discovery/index.ts +84 -18
- package/external/pi-tools-suite/src/repo-discovery/native-compact.ts +458 -0
- package/external/pi-tools-suite/src/resource-registry/index.ts +2290 -0
- package/external/pi-tools-suite/src/session-recovery/index.ts +189 -43
- package/external/pi-tools-suite/src/shell-command-policy.ts +219 -0
- package/external/pi-tools-suite/src/tool-descriptions.ts +41 -38
- package/external/pi-tools-suite/src/truncation-metadata-normalizer/index.ts +17 -0
- package/package.json +6 -3
- package/schemas/pi-tools-suite.json +540 -312
- package/schemas/pix.json +24 -0
- package/schemas/tasks.json +132 -0
- package/skills/spec-wiki/SKILL.md +55 -0
- package/skills/spec-wiki/evals/evals.json +132 -0
- package/skills/spec-wiki/evals/files/bootstrap/architecture/rfc-007.md +14 -0
- package/skills/spec-wiki/evals/files/bootstrap/docs/how-to-pay.md +4 -0
- package/skills/spec-wiki/evals/files/bootstrap/docs/overview.md +9 -0
- package/skills/spec-wiki/evals/files/bootstrap/requirements/payment-behavior.md +17 -0
- package/skills/spec-wiki/evals/files/bootstrap/src/payments.ts +12 -0
- package/skills/spec-wiki/evals/files/bootstrap/tests/payments.test.ts +11 -0
- package/skills/spec-wiki/evals/files/focused/src/session.ts +5 -0
- package/skills/spec-wiki/evals/files/focused/tests/session.test.ts +17 -0
- package/skills/spec-wiki/evals/files/maintenance/low-signal/incoming/capture.txt +2 -0
- package/skills/spec-wiki/evals/files/maintenance/low-signal/src/capture.ts +3 -0
- package/skills/spec-wiki/evals/files/maintenance/move/docs/old-job-contract.md +18 -0
- package/skills/spec-wiki/evals/files/maintenance/move/src/job.ts +5 -0
- package/skills/spec-wiki/evals/files/maintenance/new-relation/docs/session-refresh.md +24 -0
- package/skills/spec-wiki/evals/files/maintenance/new-relation/incoming/refresh-worker.ts +7 -0
- package/skills/spec-wiki/evals/files/maintenance/new-relation/src/session.ts +7 -0
- package/skills/spec-wiki/evals/files/maintenance/no-impact/docs/auth-contract.md +17 -0
- package/skills/spec-wiki/evals/files/maintenance/no-impact/incoming/telemetry-format.ts +3 -0
- package/skills/spec-wiki/evals/files/maintenance/no-impact/src/auth.ts +3 -0
- package/skills/spec-wiki/evals/files/query/docs/how-to-run-jobs.md +4 -0
- package/skills/spec-wiki/evals/files/query/docs/spec-overview.md +9 -0
- package/skills/spec-wiki/evals/files/query/features/jobs/cancellation-contract.md +15 -0
- package/skills/spec-wiki/evals/files/query/features/jobs/retry-spec.md +6 -0
- package/skills/spec-wiki/evals/maintenance_regression.py +311 -0
- package/skills/spec-wiki/evals/retrieval-eval.md +37 -0
- package/skills/spec-wiki/evals/retrieval-evals.json +37 -0
- package/skills/spec-wiki/evals/trigger-evals.json +94 -0
- package/skills/spec-wiki/references/bootstrap.md +100 -0
- package/skills/spec-wiki/references/focused-spec.md +117 -0
- package/skills/spec-wiki/references/index-schema.md +330 -0
- package/skills/spec-wiki/references/maintenance.md +134 -0
- package/skills/spec-wiki/references/query.md +74 -0
- package/skills/spec-wiki/scripts/spec_wiki.py +2076 -0
- package/docs/desktop-markdown-media.md +0 -77
- package/external/pi-tools-suite/docs/dcp-emergency-current-turn.md +0 -102
- package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +0 -270
- package/external/pi-tools-suite/src/async-subagents/private-skills/browser-qa/references/auth-scaffold-spec.md +0 -78
- package/external/pi-tools-suite/src/async-subagents/private-skills/browser-qa/references/qa-design.md +0 -223
- package/external/pi-tools-suite/src/dcp/state-persistence.ts +0 -195
- package/external/pi-tools-suite/src/skill-installer/index.ts +0 -333
- package/skills/spec-lite/SKILL.md +0 -140
- /package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/references → agents/browser-qa/examples}/qa-auth.example.jsonc +0 -0
- /package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/references → agents/browser-qa/examples}/qa-flow.example.jsonc +0 -0
- /package/external/pi-tools-suite/src/async-subagents/{private-skills → agents}/browser-qa/vendor/fflate.LICENSE +0 -0
- /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`.
|