mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
Add verified Ollama DeepSeek review emitter
This commit is contained in:
parent
32ed48ee4e
commit
d56ef67ec9
5 changed files with 494 additions and 13 deletions
|
|
@ -0,0 +1,363 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Emit Ollama-compatible DeepSeek review answers and receipts.
|
||||
|
||||
This is the canonical emitter for receipts with schema
|
||||
`ollama_deepseek_review_receipt_v1` and
|
||||
`ollama_deepseek_review_continuation_receipt_v1`.
|
||||
|
||||
The integrity rule is deliberately strict: write the answer first, compute
|
||||
`answer_sha256` from the bytes read back from disk, write the receipt, then
|
||||
verify the receipt against the answer path before returning success.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import datetime as dt
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
REPO = Path(__file__).resolve().parents[3]
|
||||
DEFAULT_OUTPUT_DIR = REPO / "shared-data" / "artifacts" / "deepseek_review"
|
||||
DEFAULT_ENDPOINT = "https://ollama.com/v1/chat/completions"
|
||||
PROVIDER_TAG = "deepseek"
|
||||
PRIMARY_SCHEMA = "ollama_deepseek_review_receipt_v1"
|
||||
CONTINUATION_SCHEMA = "ollama_deepseek_review_continuation_receipt_v1"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class EmittedReview:
|
||||
answer_path: Path
|
||||
receipt_path: Path
|
||||
answer_sha256: str
|
||||
prompt_sha256: str
|
||||
|
||||
|
||||
def sha256_bytes(data: bytes) -> str:
|
||||
return "sha256:" + hashlib.sha256(data).hexdigest()
|
||||
|
||||
|
||||
def canonical_json_bytes(value: Any) -> bytes:
|
||||
return json.dumps(
|
||||
value,
|
||||
ensure_ascii=False,
|
||||
sort_keys=True,
|
||||
separators=(",", ":"),
|
||||
).encode("utf-8")
|
||||
|
||||
|
||||
def repo_relative(path: Path, repo_root: Path = REPO) -> str:
|
||||
path = path.resolve()
|
||||
repo_root = repo_root.resolve()
|
||||
try:
|
||||
return str(path.relative_to(repo_root))
|
||||
except ValueError:
|
||||
return str(path)
|
||||
|
||||
|
||||
def safe_slug(value: str) -> str:
|
||||
slug = re.sub(r"[^A-Za-z0-9._-]+", "_", value).strip("_")
|
||||
return slug or "review"
|
||||
|
||||
|
||||
def utc_timestamp() -> str:
|
||||
return dt.datetime.now(dt.timezone.utc).strftime("%Y%m%dT%H%M%SZ")
|
||||
|
||||
|
||||
def iso_from_stamp(stamp: str) -> str:
|
||||
parsed = dt.datetime.strptime(stamp, "%Y%m%dT%H%M%SZ").replace(tzinfo=dt.timezone.utc)
|
||||
return parsed.isoformat()
|
||||
|
||||
|
||||
def read_text(path: Path) -> str:
|
||||
return path.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def read_context_bundle(paths: list[Path], repo_root: Path = REPO) -> tuple[str, list[str]]:
|
||||
chunks: list[str] = []
|
||||
context_files: list[str] = []
|
||||
for path in paths:
|
||||
body = read_text(path)
|
||||
rel = repo_relative(path, repo_root)
|
||||
chunks.append(f"\n\n===== FILE: {rel} =====\n{body}")
|
||||
context_files.append(rel)
|
||||
return "".join(chunks), context_files
|
||||
|
||||
|
||||
def build_messages(
|
||||
prompt: str,
|
||||
context_text: str,
|
||||
previous_answer_path: Path | None,
|
||||
) -> list[dict[str, str]]:
|
||||
if previous_answer_path is not None:
|
||||
previous_answer = read_text(previous_answer_path)
|
||||
user_content = (
|
||||
f"{previous_answer}\n\n"
|
||||
"===== CONTINUATION REQUEST =====\n"
|
||||
f"{prompt}"
|
||||
)
|
||||
else:
|
||||
user_content = (
|
||||
f"{context_text}\n\n"
|
||||
"===== REVIEW REQUEST =====\n"
|
||||
f"{prompt}"
|
||||
)
|
||||
|
||||
return [
|
||||
{
|
||||
"role": "system",
|
||||
"content": (
|
||||
"You are an external mathematical reviewer. Answer only from "
|
||||
"the provided context and make arithmetic checks explicit."
|
||||
),
|
||||
},
|
||||
{"role": "user", "content": user_content},
|
||||
]
|
||||
|
||||
|
||||
def build_request_body(
|
||||
model: str,
|
||||
messages: list[dict[str, str]],
|
||||
max_tokens: int,
|
||||
temperature: float,
|
||||
) -> dict[str, Any]:
|
||||
return {
|
||||
"model": model,
|
||||
"messages": messages,
|
||||
"temperature": temperature,
|
||||
"max_tokens": max_tokens,
|
||||
"stream": False,
|
||||
}
|
||||
|
||||
|
||||
def call_ollama_chat(endpoint: str, api_key: str | None, request_bytes: bytes) -> dict[str, Any]:
|
||||
headers = {"Content-Type": "application/json"}
|
||||
if api_key:
|
||||
headers["Authorization"] = f"Bearer {api_key}"
|
||||
elif not endpoint.startswith(("http://127.0.0.1", "http://localhost")):
|
||||
raise RuntimeError("OLLAMA_API_KEY is required for non-local Ollama endpoints")
|
||||
|
||||
request = urllib.request.Request(
|
||||
endpoint,
|
||||
data=request_bytes,
|
||||
headers=headers,
|
||||
method="POST",
|
||||
)
|
||||
try:
|
||||
with urllib.request.urlopen(request, timeout=600) as response:
|
||||
return json.loads(response.read().decode("utf-8"))
|
||||
except urllib.error.HTTPError as exc:
|
||||
detail = exc.read().decode("utf-8", errors="replace")
|
||||
raise RuntimeError(f"Ollama endpoint returned HTTP {exc.code}: {detail}") from exc
|
||||
|
||||
|
||||
def extract_answer(response: dict[str, Any]) -> tuple[str, dict[str, int], list[str]]:
|
||||
choices = response.get("choices")
|
||||
if not isinstance(choices, list) or not choices:
|
||||
raise ValueError("response has no choices")
|
||||
|
||||
message = choices[0].get("message", {})
|
||||
if not isinstance(message, dict):
|
||||
raise ValueError("response choice has no message object")
|
||||
|
||||
content = message.get("content", "")
|
||||
if isinstance(content, str):
|
||||
answer_text = content
|
||||
else:
|
||||
answer_text = json.dumps(content, ensure_ascii=False)
|
||||
|
||||
usage_obj = response.get("usage", {})
|
||||
usage = {
|
||||
"prompt_tokens": int(usage_obj.get("prompt_tokens", 0) or 0),
|
||||
"completion_tokens": int(usage_obj.get("completion_tokens", 0) or 0),
|
||||
"total_tokens": int(usage_obj.get("total_tokens", 0) or 0),
|
||||
}
|
||||
if usage["total_tokens"] == 0:
|
||||
usage["total_tokens"] = usage["prompt_tokens"] + usage["completion_tokens"]
|
||||
|
||||
return answer_text, usage, list(message.keys())
|
||||
|
||||
|
||||
def write_text_and_hash(path: Path, text: str) -> str:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(text, encoding="utf-8")
|
||||
return sha256_bytes(path.read_bytes())
|
||||
|
||||
|
||||
def write_receipt(path: Path, receipt: dict[str, Any]) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(receipt, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def verify_receipt(receipt_path: Path, repo_root: Path = REPO) -> bool:
|
||||
receipt = json.loads(receipt_path.read_text(encoding="utf-8"))
|
||||
schema = receipt.get("schema")
|
||||
if schema not in {PRIMARY_SCHEMA, CONTINUATION_SCHEMA}:
|
||||
raise ValueError(f"{receipt_path}: unknown schema {schema!r}")
|
||||
|
||||
answer_path = repo_root / receipt["answer_path"]
|
||||
actual = sha256_bytes(answer_path.read_bytes())
|
||||
expected = receipt.get("answer_sha256")
|
||||
if actual != expected:
|
||||
raise ValueError(f"{receipt_path}: answer_sha256 mismatch: {actual} != {expected}")
|
||||
|
||||
if schema == PRIMARY_SCHEMA:
|
||||
if not isinstance(receipt.get("context_files"), list):
|
||||
raise ValueError(f"{receipt_path}: primary receipt missing context_files")
|
||||
if "previous_answer_path" in receipt:
|
||||
raise ValueError(f"{receipt_path}: primary receipt must not carry previous_answer_path")
|
||||
else:
|
||||
if not receipt.get("previous_answer_path"):
|
||||
raise ValueError(f"{receipt_path}: continuation receipt missing previous_answer_path")
|
||||
if "context_files" in receipt:
|
||||
raise ValueError(f"{receipt_path}: continuation receipt must omit context_files")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def emit_review(
|
||||
*,
|
||||
topic: str,
|
||||
model: str,
|
||||
prompt: str,
|
||||
context_paths: list[Path],
|
||||
previous_answer_path: Path | None,
|
||||
output_dir: Path = DEFAULT_OUTPUT_DIR,
|
||||
endpoint: str = DEFAULT_ENDPOINT,
|
||||
max_tokens: int = 5000,
|
||||
temperature: float = 0.0,
|
||||
timestamp: str | None = None,
|
||||
api_key: str | None = None,
|
||||
response: dict[str, Any] | None = None,
|
||||
repo_root: Path = REPO,
|
||||
) -> EmittedReview:
|
||||
stamp = timestamp or utc_timestamp()
|
||||
created_at = iso_from_stamp(stamp)
|
||||
context_text, context_files = read_context_bundle(context_paths, repo_root)
|
||||
messages = build_messages(prompt, context_text, previous_answer_path)
|
||||
request_body = build_request_body(model, messages, max_tokens, temperature)
|
||||
request_bytes = canonical_json_bytes(request_body)
|
||||
prompt_sha256 = sha256_bytes(request_bytes)
|
||||
|
||||
if response is None:
|
||||
response = call_ollama_chat(endpoint, api_key or os.getenv("OLLAMA_API_KEY"), request_bytes)
|
||||
|
||||
answer_text, usage, message_keys = extract_answer(response)
|
||||
stem = f"{safe_slug(topic)}_{PROVIDER_TAG}_{safe_slug(model)}"
|
||||
if previous_answer_path is not None:
|
||||
stem += "_continuation"
|
||||
stem += f"_{stamp}"
|
||||
|
||||
answer_path = output_dir / f"{stem}.md"
|
||||
receipt_path = output_dir / f"{stem}.receipt.json"
|
||||
answer_sha256 = write_text_and_hash(answer_path, answer_text)
|
||||
|
||||
receipt: dict[str, Any] = {
|
||||
"schema": CONTINUATION_SCHEMA if previous_answer_path else PRIMARY_SCHEMA,
|
||||
"created_at": created_at,
|
||||
"model": model,
|
||||
"endpoint": endpoint,
|
||||
"prompt_sha256": prompt_sha256,
|
||||
"answer_sha256": answer_sha256,
|
||||
"usage": usage,
|
||||
"answer_path": repo_relative(answer_path, repo_root),
|
||||
}
|
||||
|
||||
if previous_answer_path is None:
|
||||
receipt["context_files"] = context_files
|
||||
else:
|
||||
receipt["previous_answer_path"] = repo_relative(previous_answer_path, repo_root)
|
||||
if message_keys:
|
||||
receipt["message_keys"] = message_keys
|
||||
|
||||
write_receipt(receipt_path, receipt)
|
||||
verify_receipt(receipt_path, repo_root)
|
||||
return EmittedReview(answer_path, receipt_path, answer_sha256, prompt_sha256)
|
||||
|
||||
|
||||
def verify_receipt_dir(path: Path, repo_root: Path = REPO) -> int:
|
||||
count = 0
|
||||
for receipt_path in sorted(path.glob("*.receipt.json")):
|
||||
verify_receipt(receipt_path, repo_root)
|
||||
count += 1
|
||||
return count
|
||||
|
||||
|
||||
def read_prompt(args: argparse.Namespace) -> str:
|
||||
if args.prompt_file:
|
||||
return read_text(Path(args.prompt_file))
|
||||
if args.prompt:
|
||||
return args.prompt
|
||||
return sys.stdin.read()
|
||||
|
||||
|
||||
def _cli() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("prompt", nargs="?", help="review prompt; stdin is used if omitted")
|
||||
parser.add_argument("--prompt-file", help="read review prompt from a file")
|
||||
parser.add_argument("--topic", default="review", help="artifact topic slug")
|
||||
parser.add_argument("--model", default="deepseek-v3.2")
|
||||
parser.add_argument("--endpoint", default=os.getenv("OLLAMA_ENDPOINT", DEFAULT_ENDPOINT))
|
||||
parser.add_argument("--context-file", action="append", default=[], help="primary review context file")
|
||||
parser.add_argument("--continue-from", help="previous answer markdown for continuation receipts")
|
||||
parser.add_argument("--output-dir", default=str(DEFAULT_OUTPUT_DIR))
|
||||
parser.add_argument("--max-tokens", type=int, default=5000)
|
||||
parser.add_argument("--temperature", type=float, default=0.0)
|
||||
parser.add_argument("--timestamp", help="UTC stamp YYYYMMDDTHHMMSSZ; mainly for tests/replay")
|
||||
parser.add_argument("--answer-text-file", help="offline mode: write this answer text instead of calling Ollama")
|
||||
parser.add_argument("--verify-only", nargs="*", help="verify receipt paths; with no paths, verify --output-dir")
|
||||
args = parser.parse_args()
|
||||
|
||||
output_dir = Path(args.output_dir)
|
||||
if args.verify_only is not None:
|
||||
if args.verify_only:
|
||||
for receipt in args.verify_only:
|
||||
verify_receipt(Path(receipt))
|
||||
print(f"verified {receipt}")
|
||||
else:
|
||||
count = verify_receipt_dir(output_dir)
|
||||
print(f"verified {count} receipts in {output_dir}")
|
||||
return
|
||||
|
||||
prompt = read_prompt(args)
|
||||
response = None
|
||||
if args.answer_text_file:
|
||||
answer_text = read_text(Path(args.answer_text_file))
|
||||
response = {
|
||||
"choices": [{"message": {"role": "assistant", "content": answer_text}}],
|
||||
"usage": {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0},
|
||||
}
|
||||
|
||||
emitted = emit_review(
|
||||
topic=args.topic,
|
||||
model=args.model,
|
||||
prompt=prompt,
|
||||
context_paths=[Path(p) for p in args.context_file],
|
||||
previous_answer_path=Path(args.continue_from) if args.continue_from else None,
|
||||
output_dir=output_dir,
|
||||
endpoint=args.endpoint,
|
||||
max_tokens=args.max_tokens,
|
||||
temperature=args.temperature,
|
||||
timestamp=args.timestamp,
|
||||
response=response,
|
||||
)
|
||||
print(json.dumps({
|
||||
"answer_path": repo_relative(emitted.answer_path),
|
||||
"receipt_path": repo_relative(emitted.receipt_path),
|
||||
"answer_sha256": emitted.answer_sha256,
|
||||
"prompt_sha256": emitted.prompt_sha256,
|
||||
}, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
_cli()
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import json
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
MODULE_PATH = Path(__file__).with_name("ollama_deepseek_review_emitter.py")
|
||||
SPEC = importlib.util.spec_from_file_location("ollama_deepseek_review_emitter", MODULE_PATH)
|
||||
assert SPEC is not None and SPEC.loader is not None
|
||||
emitter = importlib.util.module_from_spec(SPEC)
|
||||
sys.modules[SPEC.name] = emitter
|
||||
SPEC.loader.exec_module(emitter)
|
||||
|
||||
|
||||
class OllamaDeepSeekReviewEmitterTest(unittest.TestCase):
|
||||
def test_primary_receipt_hashes_answer_after_write(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
context = root / "context.md"
|
||||
context.write_text("canonical arithmetic context", encoding="utf-8")
|
||||
output = root / "deepseek_review"
|
||||
|
||||
emitted = emitter.emit_review(
|
||||
topic="prime_gap_entropy_collapse",
|
||||
model="deepseek-v3.2",
|
||||
prompt="Review this.",
|
||||
context_paths=[context],
|
||||
previous_answer_path=None,
|
||||
output_dir=output,
|
||||
endpoint="http://localhost:11434/v1/chat/completions",
|
||||
timestamp="20260512T000000Z",
|
||||
response={
|
||||
"choices": [{"message": {"role": "assistant", "content": "answer body"}}],
|
||||
"usage": {"prompt_tokens": 2, "completion_tokens": 3, "total_tokens": 5},
|
||||
},
|
||||
repo_root=root,
|
||||
)
|
||||
|
||||
receipt = json.loads(emitted.receipt_path.read_text(encoding="utf-8"))
|
||||
self.assertEqual(receipt["schema"], emitter.PRIMARY_SCHEMA)
|
||||
self.assertEqual(receipt["context_files"], ["context.md"])
|
||||
self.assertEqual(receipt["answer_sha256"], emitter.sha256_bytes(emitted.answer_path.read_bytes()))
|
||||
self.assertTrue(emitter.verify_receipt(emitted.receipt_path, root))
|
||||
|
||||
def test_continuation_omits_context_and_points_to_previous_answer(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
previous = root / "previous.md"
|
||||
previous.write_text("first answer", encoding="utf-8")
|
||||
output = root / "deepseek_review"
|
||||
|
||||
emitted = emitter.emit_review(
|
||||
topic="prime_gap_entropy_collapse",
|
||||
model="deepseek-v4-flash",
|
||||
prompt="Continue.",
|
||||
context_paths=[],
|
||||
previous_answer_path=previous,
|
||||
output_dir=output,
|
||||
endpoint="http://localhost:11434/v1/chat/completions",
|
||||
timestamp="20260512T000100Z",
|
||||
response={
|
||||
"choices": [{"message": {"role": "assistant", "content": "continued", "reasoning": "brief"}}],
|
||||
"usage": {"prompt_tokens": 1, "completion_tokens": 1, "total_tokens": 2},
|
||||
},
|
||||
repo_root=root,
|
||||
)
|
||||
|
||||
receipt = json.loads(emitted.receipt_path.read_text(encoding="utf-8"))
|
||||
self.assertEqual(receipt["schema"], emitter.CONTINUATION_SCHEMA)
|
||||
self.assertNotIn("context_files", receipt)
|
||||
self.assertEqual(receipt["previous_answer_path"], "previous.md")
|
||||
self.assertEqual(receipt["message_keys"], ["role", "content", "reasoning"])
|
||||
self.assertTrue(emitter.verify_receipt(emitted.receipt_path, root))
|
||||
|
||||
def test_verify_receipt_rejects_stale_answer_hash(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
context = root / "context.md"
|
||||
context.write_text("context", encoding="utf-8")
|
||||
output = root / "deepseek_review"
|
||||
emitted = emitter.emit_review(
|
||||
topic="review",
|
||||
model="deepseek-v3.2",
|
||||
prompt="Review.",
|
||||
context_paths=[context],
|
||||
previous_answer_path=None,
|
||||
output_dir=output,
|
||||
endpoint="http://localhost:11434/v1/chat/completions",
|
||||
timestamp="20260512T000200Z",
|
||||
response={"choices": [{"message": {"role": "assistant", "content": "stable"}}]},
|
||||
repo_root=root,
|
||||
)
|
||||
|
||||
emitted.answer_path.write_text("mutated", encoding="utf-8")
|
||||
with self.assertRaises(ValueError):
|
||||
emitter.verify_receipt(emitted.receipt_path, root)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
@ -10,12 +10,11 @@ of the review pipeline, the receipt schema, and the canonical example
|
|||
`shared-data/artifacts/deepseek_review/`.
|
||||
|
||||
Important boundary: the canonical artifacts documented on this page are
|
||||
Ollama-compatible review receipts. The tracked
|
||||
`5-Applications/tools-scripts/llm/deepseek_review_adapter.py` is a separate
|
||||
Anthropic-compatible DeepSeek adapter with its own `schema_version: "1.0"`
|
||||
receipt format. Do not use that adapter as the emitter for the
|
||||
`ollama_deepseek_review_receipt_v1` schema unless it has first been reconciled
|
||||
to this schema.
|
||||
Ollama-compatible review receipts. Use
|
||||
`5-Applications/tools-scripts/llm/ollama_deepseek_review_emitter.py` for this
|
||||
schema. The tracked `5-Applications/tools-scripts/llm/deepseek_review_adapter.py`
|
||||
is a separate Anthropic-compatible DeepSeek adapter with its own
|
||||
`schema_version: "1.0"` receipt format.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -52,10 +51,12 @@ Anthropic-compatible DeepSeek reviews.
|
|||
The artifacts in `shared-data/artifacts/deepseek_review/` instead record the
|
||||
Ollama-compatible schema documented below: `schema`, `created_at`, `endpoint`,
|
||||
`usage.{prompt_tokens,completion_tokens,total_tokens}`, plain string
|
||||
`context_files`, and `answer_sha256`. As of this page, no tracked canonical
|
||||
Ollama emitter script has been identified in the repository. Treat the checked
|
||||
receipts themselves as the schema authority until such an emitter is added or
|
||||
the adapter is reconciled.
|
||||
`context_files`, and `answer_sha256`. The canonical emitter is
|
||||
`5-Applications/tools-scripts/llm/ollama_deepseek_review_emitter.py`; it writes
|
||||
the answer file first, computes `answer_sha256` from bytes read back from disk,
|
||||
writes the receipt, and immediately verifies the receipt against the answer
|
||||
path before returning success. This write-time verification gate exists because
|
||||
the first manually landed Ollama receipts had stale `answer_sha256` values.
|
||||
|
||||
### Receipt Schema
|
||||
|
||||
|
|
@ -188,9 +189,11 @@ When emitting new review artifacts:
|
|||
2. Write the matching receipt alongside it with the same stem and
|
||||
`.receipt.json` suffix, using `ollama_deepseek_review_receipt_v1` for the
|
||||
primary review and `ollama_deepseek_review_continuation_receipt_v1` for any
|
||||
continuation. Do not generate these receipts with
|
||||
`5-Applications/tools-scripts/llm/deepseek_review_adapter.py`; it emits a
|
||||
different Anthropic-compatible schema unless explicitly updated.
|
||||
continuation. Use
|
||||
`5-Applications/tools-scripts/llm/ollama_deepseek_review_emitter.py`; do not
|
||||
generate these receipts with
|
||||
`5-Applications/tools-scripts/llm/deepseek_review_adapter.py`, which emits a
|
||||
different Anthropic-compatible schema.
|
||||
3. Populate `context_files` with repo-relative paths to every file consumed
|
||||
by the prompt so future agents can reproduce the prompt body. Continuation
|
||||
receipts omit `context_files` and `message_keys` records the alternate
|
||||
|
|
@ -208,6 +211,9 @@ When emitting new review artifacts:
|
|||
|
||||
- [[Build-System]] — pinned Python interpreter for review tooling and
|
||||
prompt-hash reproducibility across runs.
|
||||
- `5-Applications/tools-scripts/llm/ollama_deepseek_review_emitter.py` —
|
||||
canonical Ollama-compatible emitter for this schema; verifies
|
||||
`answer_sha256` after writing.
|
||||
- `5-Applications/tools-scripts/llm/deepseek_review_adapter.py` —
|
||||
Anthropic-compatible DeepSeek adapter with a different receipt schema; useful
|
||||
as related infrastructure, but not the emitter for the current Ollama-style
|
||||
|
|
|
|||
|
|
@ -81,4 +81,5 @@
|
|||
|---|---|
|
||||
| `wiki/DeepSeek-Review-Process.md` | Receipt schema (`ollama_deepseek_review_receipt_v1`), two-stage pipeline (`deepseek-v3.2` + `deepseek-v4-flash` continuation), prime-gap entropy-collapse example |
|
||||
| `shared-data/artifacts/deepseek_review/` | Paired answer + receipt artifacts for each review run |
|
||||
| `5-Applications/tools-scripts/llm/ollama_deepseek_review_emitter.py` | Canonical Ollama-compatible DeepSeek review emitter with write-time answer-hash verification |
|
||||
| `5-Applications/tools-scripts/llm/deepseek_review_adapter.py` | Related Anthropic-compatible DeepSeek adapter; it does not emit the current Ollama-style receipt schema |
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ This file is the first stop for coding agents working in this repository.
|
|||
- Documentation and wiki surfaces: `6-Documentation/`
|
||||
- Stack receipts: `shared-data/data/stack_solidification/`
|
||||
- Promoted review receipts: `shared-data/artifacts/deepseek_review/`
|
||||
- Canonical Ollama/DeepSeek review emitter:
|
||||
`5-Applications/tools-scripts/llm/ollama_deepseek_review_emitter.py`
|
||||
- CAD harness: `5-Applications/text-to-cad/`
|
||||
- Historical scoped staging maps:
|
||||
`6-Documentation/docs/stack_solidification_staging_manifest_2026-05-09.md`
|
||||
|
|
@ -34,6 +36,9 @@ This file is the first stop for coding agents working in this repository.
|
|||
- For Lean changes, run the narrow target first, then the broader `lake build` when feasible.
|
||||
- For Python shims, run `python3 -m py_compile` on touched files.
|
||||
- For JSON receipts, run `python3 -m json.tool` or a repo-native receipt parser.
|
||||
- For promoted Ollama/DeepSeek review receipts, run
|
||||
`python3 5-Applications/tools-scripts/llm/ollama_deepseek_review_emitter.py --verify-only`
|
||||
so `answer_sha256` is checked against the answer file after write.
|
||||
- For hardware claims, distinguish software witness, bitstream presence, SRAM load, flash persistence, UART beacon, and live hardware receipt.
|
||||
- Before committing, run `git diff --cached --check` and a staged secret scan
|
||||
for touched source/receipt files. The repository credential hook is a final
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue