@heretek-ai/epistemic-swarm 0.7.11 → 0.7.13

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 (63) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/package.json +1 -1
  3. package/plugins/research-cache/skills/research_cache/hasher.py +56 -14
  4. package/prompts/agent_brainstormer.md +14 -0
  5. package/prompts/agent_darkharvest.md +20 -1
  6. package/runner/__pycache__/__init__.cpython-311.pyc +0 -0
  7. package/runner/__pycache__/auctioneer.cpython-311.pyc +0 -0
  8. package/runner/__pycache__/auditor_engine.cpython-311.pyc +0 -0
  9. package/runner/__pycache__/claim_store.cpython-311.pyc +0 -0
  10. package/runner/__pycache__/claim_witness.cpython-311.pyc +0 -0
  11. package/runner/__pycache__/darkharvest_claims.cpython-311.pyc +0 -0
  12. package/runner/__pycache__/living_dossiers.cpython-311.pyc +0 -0
  13. package/runner/__pycache__/mcp_protocol.cpython-311.pyc +0 -0
  14. package/runner/__pycache__/mcp_server.cpython-311.pyc +0 -0
  15. package/runner/__pycache__/path_safety.cpython-311.pyc +0 -0
  16. package/runner/__pycache__/pcrb.cpython-311.pyc +0 -0
  17. package/runner/__pycache__/pcrb_verify.cpython-311.pyc +0 -0
  18. package/runner/__pycache__/refinement.cpython-311.pyc +0 -0
  19. package/runner/__pycache__/research_swarm.cpython-311.pyc +0 -0
  20. package/runner/__pycache__/retrieval_log.cpython-311.pyc +0 -0
  21. package/runner/__pycache__/state_machine.cpython-311.pyc +0 -0
  22. package/runner/auditor_engine.py +267 -80
  23. package/runner/darkharvest_claims.py +326 -0
  24. package/runner/refinement.py +74 -0
  25. package/runner/research_swarm.py +119 -24
  26. package/runner/retrieval_log.py +90 -0
  27. package/runner/state_machine.py +35 -0
  28. package/runner/tests/__pycache__/test_auction_order.cpython-311.pyc +0 -0
  29. package/runner/tests/__pycache__/test_backends.cpython-311.pyc +0 -0
  30. package/runner/tests/__pycache__/test_bet1_spike.cpython-311.pyc +0 -0
  31. package/runner/tests/__pycache__/test_claim_store.cpython-311.pyc +0 -0
  32. package/runner/tests/__pycache__/test_claim_witness.cpython-311.pyc +0 -0
  33. package/runner/tests/__pycache__/test_claude_plugin.cpython-311.pyc +0 -0
  34. package/runner/tests/__pycache__/test_darkharvest_audit.cpython-311.pyc +0 -0
  35. package/runner/tests/__pycache__/test_domain_packs.cpython-311.pyc +0 -0
  36. package/runner/tests/__pycache__/test_dossier_contract.cpython-311.pyc +0 -0
  37. package/runner/tests/__pycache__/test_factory.cpython-311.pyc +0 -0
  38. package/runner/tests/__pycache__/test_fleet_seam.cpython-311.pyc +0 -0
  39. package/runner/tests/__pycache__/test_grounding.cpython-311.pyc +0 -0
  40. package/runner/tests/__pycache__/test_living_dossiers.cpython-311.pyc +0 -0
  41. package/runner/tests/__pycache__/test_manifest_concurrency.cpython-311.pyc +0 -0
  42. package/runner/tests/__pycache__/test_mcp_server.cpython-311.pyc +0 -0
  43. package/runner/tests/__pycache__/test_opencode_ux.cpython-311.pyc +0 -0
  44. package/runner/tests/__pycache__/test_opencode_v2_registrars.cpython-311.pyc +0 -0
  45. package/runner/tests/__pycache__/test_pcrb.cpython-311.pyc +0 -0
  46. package/runner/tests/__pycache__/test_refinement.cpython-311.pyc +0 -0
  47. package/runner/tests/__pycache__/test_swarm.cpython-311.pyc +0 -0
  48. package/runner/tests/__pycache__/test_swarm_config.cpython-311.pyc +0 -0
  49. package/runner/tests/__pycache__/test_sweep_regressions.cpython-311.pyc +0 -0
  50. package/runner/tests/__pycache__/test_webcache.cpython-311.pyc +0 -0
  51. package/runner/tests/test_darkharvest_audit.py +290 -0
  52. package/runner/tests/test_grounding.py +183 -0
  53. package/scripts/__pycache__/bet1_advisory_spike.cpython-311.pyc +0 -0
  54. package/scripts/__pycache__/build_adapters.cpython-311.pyc +0 -0
  55. package/scripts/__pycache__/divergence_experiment.cpython-311.pyc +0 -0
  56. package/skills/epistemic_search/scripts/__pycache__/search.cpython-311.pyc +0 -0
  57. package/skills/epistemic_search/scripts/search.py +16 -0
  58. package/skills/epistemic_search/scripts/webcache.py +11 -0
  59. package/skills/research_cache/__pycache__/__init__.cpython-311.pyc +0 -0
  60. package/skills/research_cache/__pycache__/hasher.cpython-311.pyc +0 -0
  61. package/skills/research_cache/hasher.py +56 -14
  62. package/skills/swarm_config/__pycache__/__init__.cpython-311.pyc +0 -0
  63. package/skills/swarm_config/__pycache__/configure.cpython-311.pyc +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "epistemic-swarm",
3
- "version": "0.7.11",
3
+ "version": "0.7.13",
4
4
  "description": "High-Integrity Dialectic Research Agent Harness for Claude Code enforcing empirical evidence over parametric hallucination.",
5
5
  "author": {
6
6
  "name": "Heretek AI",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heretek-ai/epistemic-swarm",
3
- "version": "0.7.11",
3
+ "version": "0.7.13",
4
4
  "description": "IUMBTEMS (Epistemic Swarm) — High-Integrity Dialectic Research Agent Harness for Claude Code, OpenCode V2, Pi (pi.dev), OMP (oh-my-pi), Gemini CLI, Codex CLI, and AntiGravity",
5
5
  "main": "bin/cli.js",
6
6
  "bin": {
@@ -17,6 +17,20 @@ from typing import Dict, Any, Optional, Tuple
17
17
  DEFAULT_RESEARCH_DIR = ".research"
18
18
  BASE_DIR_HELP = "Base .research directory"
19
19
 
20
+
21
+ def _log_retrieval(base_dir, kind: str, **fields) -> None:
22
+ """Best-effort retrieval telemetry (see runner/retrieval_log.py)."""
23
+ try:
24
+ root = Path(__file__).resolve().parents[2]
25
+ if str(root) not in sys.path:
26
+ sys.path.insert(0, str(root))
27
+ from runner.retrieval_log import log_event
28
+
29
+ log_event(base_dir, kind, **fields)
30
+ except Exception:
31
+ pass
32
+
33
+
20
34
  class SourceHasher:
21
35
  def __init__(self, base_dir: Optional[Path] = None):
22
36
  target = base_dir or Path(DEFAULT_RESEARCH_DIR)
@@ -30,8 +44,14 @@ class SourceHasher:
30
44
  normalized = content.strip().encode("utf-8")
31
45
  return hashlib.sha256(normalized).hexdigest()
32
46
 
33
- def store_source(self, url: str, content: str, title: Optional[str] = None,
34
- tier: str = "WEB_DOCUMENT", metadata: Optional[Dict[str, Any]] = None) -> str:
47
+ def store_source(
48
+ self,
49
+ url: str,
50
+ content: str,
51
+ title: Optional[str] = None,
52
+ tier: str = "WEB_DOCUMENT",
53
+ metadata: Optional[Dict[str, Any]] = None,
54
+ ) -> str:
35
55
  """Store content and metadata content-addressed by SHA-256."""
36
56
  content_hash = self.compute_sha256(content)
37
57
  md_path = self.sources_dir / f"{content_hash}.md"
@@ -50,7 +70,7 @@ class SourceHasher:
50
70
  "cached_at": datetime.now(timezone.utc).isoformat(),
51
71
  "byte_size": len(content.encode("utf-8")),
52
72
  "char_count": len(content),
53
- "custom_metadata": metadata or {}
73
+ "custom_metadata": metadata or {},
54
74
  }
55
75
  with open(json_path, "w", encoding="utf-8") as f:
56
76
  json.dump(meta, f, indent=2)
@@ -84,7 +104,9 @@ class SourceHasher:
84
104
  """
85
105
  if not re.match(r"^[a-fA-F0-9]+$", hash_prefix):
86
106
  return None
87
- exact_path = Path(os.path.realpath(str(self.sources_dir / f"{hash_prefix}{extension}")))
107
+ exact_path = Path(
108
+ os.path.realpath(str(self.sources_dir / f"{hash_prefix}{extension}"))
109
+ )
88
110
  if exact_path.parent != self.sources_dir:
89
111
  return None
90
112
  if exact_path.exists():
@@ -102,12 +124,16 @@ class SourceHasher:
102
124
  def normalize_text_for_search(text: str) -> str:
103
125
  """Collapse whitespace and normalize typography for substring matching."""
104
126
  # Replace smart quotes and dashes
105
- text = text.replace("“", '"').replace("”", '"').replace("‘", "'").replace("’", "'")
127
+ text = (
128
+ text.replace("“", '"').replace("”", '"').replace("‘", "'").replace("’", "'")
129
+ )
106
130
  text = text.replace("—", "-").replace("–", "-")
107
131
  # Collapse all whitespace to single spaces
108
132
  return re.sub(r"\s+", " ", text).strip().lower()
109
133
 
110
- def verify_quote(self, content_hash: str, quote: str) -> Tuple[bool, float, Optional[str]]:
134
+ def verify_quote(
135
+ self, content_hash: str, quote: str
136
+ ) -> Tuple[bool, float, Optional[str]]:
111
137
  """
112
138
  Verifies whether quote exists in cached document.
113
139
  Returns: (is_verified, confidence_score, context_match)
@@ -136,7 +162,7 @@ class SourceHasher:
136
162
  best_score = 0.0
137
163
 
138
164
  for i in range(max(1, len(source_words) - window_size + 1)):
139
- window = source_words[i:i + window_size]
165
+ window = source_words[i : i + window_size]
140
166
  matches = sum(1 for w1, w2 in zip(quote_words, window) if w1 == w2)
141
167
  score = matches / window_size
142
168
  if score > best_score:
@@ -147,11 +173,17 @@ class SourceHasher:
147
173
  if best_score >= 0.88:
148
174
  return True, best_score, f"High-confidence fuzzy match ({best_score:.2f})."
149
175
 
150
- return False, best_score, f"Verification failed. Highest word overlap: {best_score:.2f}."
176
+ return (
177
+ False,
178
+ best_score,
179
+ f"Verification failed. Highest word overlap: {best_score:.2f}.",
180
+ )
151
181
 
152
182
 
153
183
  def main():
154
- parser = argparse.ArgumentParser(description="Epistemic Swarm Content Hasher & Quote Verifier")
184
+ parser = argparse.ArgumentParser(
185
+ description="Epistemic Swarm Content Hasher & Quote Verifier"
186
+ )
155
187
  subparsers = parser.add_subparsers(dest="command")
156
188
 
157
189
  # Cache command
@@ -166,7 +198,9 @@ def main():
166
198
  verify_parser = subparsers.add_parser("verify", help="Verify a verbatim quote")
167
199
  verify_parser.add_argument("--hash", required=True, help="Document SHA-256 hash")
168
200
  verify_parser.add_argument("--quote", required=True, help="Verbatim quote to check")
169
- verify_parser.add_argument("--dir", default=DEFAULT_RESEARCH_DIR, help=BASE_DIR_HELP)
201
+ verify_parser.add_argument(
202
+ "--dir", default=DEFAULT_RESEARCH_DIR, help=BASE_DIR_HELP
203
+ )
170
204
 
171
205
  # List command
172
206
  list_parser = subparsers.add_parser("list", help="List cached sources")
@@ -182,18 +216,26 @@ def main():
182
216
  if not sys.stdin.isatty():
183
217
  content = sys.stdin.read()
184
218
  else:
185
- print("Error: No content provided via --content or stdin.", file=sys.stderr)
219
+ print(
220
+ "Error: No content provided via --content or stdin.",
221
+ file=sys.stderr,
222
+ )
186
223
  sys.exit(1)
187
- h = hasher.store_source(url=args.url, content=content, title=args.title, tier=args.tier)
224
+ h = hasher.store_source(
225
+ url=args.url, content=content, title=args.title, tier=args.tier
226
+ )
188
227
  print(f"[CACHED] {h} -> {args.title} ({args.url})")
228
+ _log_retrieval(hasher.base_dir, "cache", url=args.url, hash=h, tool="hasher")
189
229
 
190
230
  elif args.command == "verify":
191
- verified, conf, msg = hasher.verify_quote(content_hash=args.hash, quote=args.quote)
231
+ verified, conf, msg = hasher.verify_quote(
232
+ content_hash=args.hash, quote=args.quote
233
+ )
192
234
  result = {
193
235
  "hash": args.hash,
194
236
  "verified": verified,
195
237
  "confidence": conf,
196
- "message": msg
238
+ "message": msg,
197
239
  }
198
240
  print(json.dumps(result, indent=2))
199
241
  sys.exit(0 if verified else 1)
@@ -26,6 +26,20 @@ context < 40%, use shallow mode (README + top-level tree only) and say so.
26
26
  - Open loops: TODOs, failing tests, stale branches.
27
27
  3. NEVER invent file contents. If a file was not ingested, mark the claim
28
28
  `[HYPOTHESIS: <how to check>]`, never `[VERIFIED]`.
29
+ 4. **External grounding** (mandatory when the objective implies external facts,
30
+ benchmarks, or prior art): discover with the zero-key search skill and cache
31
+ every source before citing it:
32
+
33
+ ```bash
34
+ python3 skills/epistemic_search/scripts/search.py "<query>"
35
+ python3 skills/research_cache/hasher.py cache --url "<URL>" --content "$(cat fetched.md)" --title "<TITLE>"
36
+ ```
37
+
38
+ Cite a cached source as `[VERIFIED: <sha256>]` **with an exact
39
+ `verbatim_quote`**; anything not retrieved stays `[HYPOTHESIS: <test>]`. A run
40
+ that never searches yields zero cached sources and will be flagged
41
+ `WARNING_LOW_GROUNDING` — that is only acceptable when the objective is purely
42
+ internal to the workspace.
29
43
 
30
44
  ## 2. DIALECTICAL DIVERGENCE (mandatory, in order)
31
45
 
@@ -33,6 +33,17 @@ partial per capability), benchmark/API quotes, and per-feature harvest
33
33
  proposals. Every cell needs `[VERIFIED: <hash>]` from
34
34
  `.research/sources/<sha256>.md` or `file://<path>#L<start>-L<end>`.
35
35
 
36
+ Discover and cache every cited source before you cite it (zero-key, no API keys):
37
+
38
+ ```bash
39
+ python3 skills/epistemic_search/scripts/search.py "<query>"
40
+ python3 skills/research_cache/hasher.py cache --url "<URL>" --content "$(cat fetched.md)" --title "<TITLE>"
41
+ ```
42
+
43
+ Confirm a repository actually exists (`owner/repo`) before citing it. A run that
44
+ never searches caches zero sources and is flagged `WARNING_LOW_GROUNDING` — the
45
+ runner prints `retrieval: N queries, M results, K cached` as evidence either way.
46
+
36
47
  ### Beta — Red Team
37
48
  License gate (LICENSE file + package metadata → SPDX), transitive weight,
38
49
  CVE/takeover notes, staleness (`⚠️ STALE` when >12mo or solo-maintainer),
@@ -51,7 +62,9 @@ AND what we lack). Gates are warn-only: badge inline, never auto-skip.
51
62
  ## 4. OUTPUT SPECIFICATION
52
63
 
53
64
  Per scope write `alpha_dossier.json` / `beta_dossier.json` with
54
- `candidate_repositories[]` entries:
65
+ `candidate_repositories[]` entries. Every entry MUST carry `source_hash` **and**
66
+ `verbatim_quote` (an exact substring of the cached `.research/sources/<hash>.md`);
67
+ entries without both are rejected as unverified by the audit.
55
68
 
56
69
  ```json
57
70
  {
@@ -59,6 +72,7 @@ Per scope write `alpha_dossier.json` / `beta_dossier.json` with
59
72
  "name": "owner/repo",
60
73
  "url": "https://github.com/owner/repo",
61
74
  "source_hash": "<sha256>",
75
+ "verbatim_quote": "<exact substring of the cached source>",
62
76
  "license": "Apache-2.0",
63
77
  "license_risk": "SAFE | COPYLEFT_WARNING | PROHIBITIVE",
64
78
  "harvest_policy": "depend-or-vendor | clean-room-rebuild-only",
@@ -89,3 +103,8 @@ candidates.
89
103
  3. No unverified harvest verdicts. Metadata ranks; only VERIFIED harvests.
90
104
  4. No unbounded expansion past `--max-repos` or per-repo caps without user
91
105
  confirmation. Firecrawl missing → gap note, never abort.
106
+ 5. **Do NOT self-report audit results.** Never emit `epistemic_audit`,
107
+ `confidence`, `verified_*`, `unverified_*`, `mean_epistemic_score`, or any
108
+ `*.verified` / `*.total_sources` field. The runner computes verification from
109
+ cached witnesses; agent-declared counts are ignored (renamed to
110
+ `self_reported_*`) and only mislead a human reader.