Skip to main content

lean_ctx/core/
tdd_schema.rs

1use serde_json::{json, Value};
2use std::path::{Path, PathBuf};
3
4pub fn default_tdd_schema_path() -> PathBuf {
5    let rust_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
6    let repo_root = rust_dir.parent().unwrap_or(&rust_dir);
7    repo_root.join("website/generated/tdd-schema.json")
8}
9
10pub fn tdd_schema_value() -> Value {
11    json!({
12        "schema_version": 1,
13        "format": "lean-ctx-tdd",
14        "crp": {
15            "modes": [
16                {
17                    "name": "off",
18                    "description": "No CRP transformation."
19                },
20                {
21                    "name": "compact",
22                    "description": "Compact prose; prefer bullet points and short lines."
23                },
24                {
25                    "name": "tdd",
26                    "description": "Token Dense Dialect: max information density, minimal narration."
27                }
28            ],
29            "output_rules": [
30                "Prefer structured bullets over paragraphs.",
31                "Avoid repeating previously shown context.",
32                "Show diffs instead of full files when possible.",
33                "For code reads, prefer map/signatures/task over full."
34            ]
35        },
36        "ctx_read": {
37            "read_modes": [
38                {"name":"auto","description":"Predict best mode (predictor + adaptive policy)."},
39                {"name":"full","description":"Full file content (cached)."},
40                {"name":"map","description":"Deps + exports + key API signatures (TOON)."},
41                {"name":"signatures","description":"API surface only."},
42                {"name":"diff","description":"Changed lines since last read."},
43                {"name":"aggressive","description":"Whitespace/comment stripping with safeguards."},
44                {"name":"entropy","description":"Entropy/Jaccard-based extraction."},
45                {"name":"task","description":"Task-aware compression (IB filter + graph context)."},
46                {"name":"reference","description":"Header-only reference (lines/tokens), no content."},
47                {"name":"lines:N-M","description":"Line-range extraction with line numbers."}
48            ],
49            "toon_header": {
50                "deps": "  deps: a, b, c",
51                "exports": "  exports: x, y",
52                "api": "  API:\\n    <signature>"
53            },
54            "file_ref_format": "F<idx>=<short-path> <line-count>L",
55            "compressed_hint": "[compressed — use mode=\"full\" for complete source]"
56        },
57        "stability": {
58            "determinism": [
59                "Sorted keys for manifests/exports.",
60                "Stable ordering for ledgers and reports."
61            ],
62            "local_first": [
63                "All files stored under LEAN_CTX_DATA_DIR by default.",
64                "No raw prompts stored."
65            ]
66        }
67    })
68}
69
70pub fn write_if_changed(path: &Path, content: &str) -> Result<(), String> {
71    let existing = std::fs::read_to_string(path).ok();
72    if existing.as_deref() == Some(content) {
73        return Ok(());
74    }
75    if let Some(parent) = path.parent() {
76        std::fs::create_dir_all(parent)
77            .map_err(|e| format!("create_dir_all {}: {e}", parent.display()))?;
78    }
79    std::fs::write(path, content).map_err(|e| format!("write {}: {e}", path.display()))
80}