Files
khadhroony-bot3/scripts/audit_khadhroony_workspace_rules.py
2026-08-10 02:44:24 +02:00

1166 lines
45 KiB
Python

#!/usr/bin/env python3
# file: scripts/audit_khadhroony_workspace_rules.py
# version: 22
"""Audit mechanically verifiable rules specific to khadhroony-bot3."""
from __future__ import annotations
import argparse
import dataclasses
import json
import pathlib
import re
import sys
import tomllib
@dataclasses.dataclass(frozen=True)
class Violation:
"""One project-specific workspace rule violation."""
code: str
path: str
line: int
message: str
def package_name(crate_dir: pathlib.Path) -> str | None:
"""Return a crate package name."""
cargo = crate_dir / "Cargo.toml"
if not cargo.exists():
return None
value = tomllib.loads(cargo.read_text(encoding="utf-8")).get("package", {}).get("name")
return value if isinstance(value, str) else None
def relevant_tracing_crate(crate_dir: pathlib.Path) -> bool:
"""Return whether the crate owns a tracing target contract."""
cargo = crate_dir / "Cargo.toml"
data = tomllib.loads(cargo.read_text(encoding="utf-8"))
if "tracing" in data.get("dependencies", {}):
return True
return any("TRACING_TARGET" in path.read_text(encoding="utf-8") for path in crate_dir.glob("src/**/*.rs"))
def audit_tracing(root: pathlib.Path) -> list[Violation]:
"""Audit the project tracing target contract."""
violations: list[Violation] = []
for cargo in sorted(root.glob("*/Cargo.toml")):
crate = cargo.parent
if crate.name == "ks-lib":
continue
if not relevant_tracing_crate(crate):
continue
name = package_name(crate)
if name is None:
continue
constants = crate / "src/constants.rs"
expected = f'pub(crate) const TRACING_TARGET: &str = "{name}";'
relative_constants = constants.relative_to(root).as_posix()
if not constants.exists() or expected not in constants.read_text(encoding="utf-8"):
violations.append(Violation("KH_TRACE001", relative_constants, 1, f"expected `{expected}`"))
crate_root = crate / "src/lib.rs"
if not crate_root.exists():
crate_root = crate / "src/main.rs"
relative_root = crate_root.relative_to(root).as_posix()
if not crate_root.exists() or "pub(crate) use self::constants::TRACING_TARGET;" not in crate_root.read_text(encoding="utf-8"):
violations.append(Violation("KH_TRACE002", relative_root, 1, "missing crate-root TRACING_TARGET re-export"))
for path in crate.glob("src/**/*.rs"):
relative = path.relative_to(root).as_posix()
for index, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
if "khbot." in line:
violations.append(Violation("KH_TRACE003", relative, index, "legacy khbot tracing target is forbidden"))
if "crate::constants::TRACING_TARGET" in line:
violations.append(Violation("KH_TRACE004", relative, index, "use crate::TRACING_TARGET outside crate root"))
if re.search(r"(?:crate::[A-Za-z0-9_]+::|(?<!crate::))TRACING_TARGET", line) and "const TRACING_TARGET" not in line and "use self::constants::TRACING_TARGET" not in line:
if "crate::TRACING_TARGET" not in line:
violations.append(Violation("KH_TRACE005", relative, index, "non-canonical TRACING_TARGET path"))
return violations
def audit_ks_lib_tracing(root: pathlib.Path) -> list[Violation]:
"""Audit hierarchical tracing targets owned by operational ks-lib components."""
violations: list[Violation] = []
crate = root / "ks-lib"
crate_root = crate / "src/lib.rs"
if not crate_root.exists():
return violations
root_text = crate_root.read_text(encoding="utf-8")
re_exports = set()
re_export_pattern = re.compile(
r"^pub\(crate\) use self::[A-Za-z0-9_:]+::"
r"([A-Z][A-Z0-9_]+);$",
re.MULTILINE,
)
for match in re_export_pattern.finditer(root_text):
if match.group(1).startswith("TRACING_TARGET_"):
re_exports.add(match.group(1))
target_pattern = re.compile(
r'pub\(crate\) const (TRACING_TARGET_[A-Z0-9_]+): &str\s*=\s*"([^"]+)";',
re.MULTILINE,
)
declared_targets: dict[str, tuple[str, int]] = {}
for constants in sorted((crate / "src").rglob("constants.rs")):
text = constants.read_text(encoding="utf-8")
component = constants.parent.relative_to(crate / "src")
component_parts = component.parts
if component_parts and component_parts[0] in {"decoder", "executor", "materializer"}:
suffix = ".".join(component_parts[1:])
expected = f"ks-lib-{component_parts[0]}"
if suffix:
expected = f"{expected}.{suffix}"
else:
expected = "ks-lib." + ".".join(component_parts)
relative = constants.relative_to(root).as_posix()
for match in target_pattern.finditer(text):
line = text[: match.start()].count("\n") + 1
declared_targets[match.group(1)] = (relative, line)
if match.group(2) != expected:
violations.append(
Violation(
"KH_TRACE101",
relative,
line,
f"`{match.group(1)}` must use hierarchical target `{expected}`",
)
)
macro_pattern = re.compile(
r"tracing::(?:debug|error|info|trace|warn)!\(\s*target:\s*crate::(TRACING_TARGET_[A-Z0-9_]+)"
)
used_targets: set[str] = set()
for path in sorted((crate / "src").rglob("*.rs")):
relative = path.relative_to(root).as_posix()
text = path.read_text(encoding="utf-8")
for index, line in enumerate(text.splitlines(), 1):
if "let _target" in line:
violations.append(
Violation(
"KH_TRACE102",
relative,
index,
"fake tracing target consumption is forbidden",
)
)
for match in macro_pattern.finditer(text):
used_targets.add(match.group(1))
if match.group(1) not in re_exports:
violations.append(
Violation(
"KH_TRACE103",
relative,
text[: match.start()].count("\n") + 1,
f"missing crate-root re-export for `{match.group(1)}`",
)
)
for target, (relative, line) in sorted(declared_targets.items()):
if target not in used_targets:
violations.append(
Violation(
"KH_TRACE104",
relative,
line,
f"declared operational tracing target `{target}` is not used by a real tracing event",
)
)
return violations
def audit_solana_types(root: pathlib.Path) -> list[Violation]:
"""Reject non-canonical Solana address types in workspace Rust code."""
violations: list[Violation] = []
for path in sorted(root.rglob("*.rs")):
if "target" in path.parts or ".git" in path.parts:
continue
relative = path.relative_to(root).as_posix()
for index, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
if "solana_address::Address" in line:
violations.append(Violation("KH_SOL001", relative, index, "use solana_pubkey::Pubkey instead of solana_address::Address"))
return violations
def audit_ks_lib_symbol_prefixes(root: pathlib.Path) -> list[Violation]:
"""Require stable family prefixes on non-method ks-lib declarations."""
violations: list[Violation] = []
families = {
"decoder": ("DC_", "Dc", "decoder_"),
"executor": ("EX_", "Ex", "executor_"),
"materializer": ("MT_", "Mt", "materializer_"),
"model": ("MD_", "Md", "model_"),
}
declaration = re.compile(
r"^pub(?:\(crate\))?\s+"
r"(?:(?:async|const|unsafe)\s+)*"
r"(const|static|type|struct|enum|trait|union|fn)\s+"
r"([A-Za-z_][A-Za-z0-9_]*)"
)
for family, prefixes in families.items():
family_root = root / "ks-lib/src" / family
paths = [family_root.with_suffix(".rs")]
if family_root.is_dir():
paths.extend(sorted(family_root.rglob("*.rs")))
for path in paths:
if not path.is_file():
continue
relative = path.relative_to(root).as_posix()
for index, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
match = declaration.match(line)
if match is None:
continue
kind = match.group(1)
name = match.group(2)
expected = prefixes[0] if kind in {"const", "static"} else prefixes[2] if kind == "fn" else prefixes[1]
if kind in {"const", "static"} and name.startswith("TRACING_TARGET_"):
continue
if not name.startswith(expected):
violations.append(
Violation(
"KH_NAME001",
relative,
index,
f"`{name}` must start with `{expected}` for the {family} family",
)
)
return violations
def audit_reserved_decoder_scaffolds(root: pathlib.Path) -> list[Violation]:
"""Reject incomplete reserved decoder contracts."""
violations: list[Violation] = []
decoder_root = root / "ks-lib/src/decoder"
forbidden = (
"MIGRATION_BOUNDARIES",
"LEGACY_CRATE",
"MIGRATION_STATUS",
"source-preserved-pending-port",
)
struct_pattern = re.compile(r"^pub struct (Dc[A-Za-z0-9]+Decoder);$", re.MULTILINE)
for path in sorted(decoder_root.rglob("*.rs")):
relative = path.relative_to(root).as_posix()
text = path.read_text(encoding="utf-8")
for marker in forbidden:
offset = text.find(marker)
if offset >= 0:
violations.append(
Violation(
"KH_DC001",
relative,
text[:offset].count("\n") + 1,
f"temporary decoder migration marker `{marker}` is forbidden",
)
)
if "Reserved protocol decoder for `" not in text:
continue
struct_match = struct_pattern.search(text)
if struct_match is None:
violations.append(
Violation(
"KH_DC002",
relative,
1,
"reserved decoder must expose one `Dc*Decoder` unit struct",
)
)
continue
type_name = struct_match.group(1)
implementation = f"impl crate::DcApiProtocolDecoder for crate::{type_name} {{"
if implementation not in text:
violations.append(
Violation(
"KH_DC003",
relative,
text[: struct_match.start()].count("\n") + 1,
f"`{type_name}` must implement `DcApiProtocolDecoder`",
)
)
if "fn program_ids(&self) -> &'static [&'static str]" not in text:
violations.append(
Violation(
"KH_DC004",
relative,
1,
"reserved decoder must declare its exact Program ID boundary",
)
)
if "crate::DcApiDecoderSupport::Maybe" not in text:
violations.append(
Violation(
"KH_DC005",
relative,
1,
"reserved decoder must remain explicitly `Maybe` until implemented",
)
)
return violations
def audit_reserved_materializer_scaffolds(root: pathlib.Path) -> list[Violation]:
"""Reject incomplete reserved materializer contracts."""
violations: list[Violation] = []
materializer_root = root / "ks-lib/src/materializer"
forbidden = (
"MIGRATION_BOUNDARIES",
"LEGACY_CRATE",
"MIGRATION_STATUS",
"source-preserved-pending-port",
)
struct_pattern = re.compile(r"^pub struct (Mt[A-Za-z0-9]+Materializer);$", re.MULTILINE)
for path in sorted(materializer_root.rglob("*.rs")):
relative = path.relative_to(root).as_posix()
text = path.read_text(encoding="utf-8")
for marker in forbidden:
offset = text.find(marker)
if offset >= 0:
violations.append(
Violation(
"KH_MT001",
relative,
text[:offset].count("\n") + 1,
f"temporary materializer migration marker `{marker}` is forbidden",
)
)
if not text.startswith("// file:") or "\n//! Reserved " not in text:
continue
struct_match = struct_pattern.search(text)
if struct_match is None:
violations.append(
Violation(
"KH_MT002",
relative,
1,
"reserved materializer must expose one `Mt*Materializer` unit struct",
)
)
continue
type_name = struct_match.group(1)
legacy_implementation = f"impl crate::MtMaterializer for crate::{type_name} {{"
if legacy_implementation not in text:
violations.append(
Violation(
"KH_MT003",
relative,
text[: struct_match.start()].count("\n") + 1,
f"`{type_name}` must implement `MtMaterializer`",
)
)
api_implementation = f"impl crate::MtApiEventMaterializer for crate::{type_name} {{"
if api_implementation not in text:
violations.append(
Violation(
"KH_MT004",
relative,
text[: struct_match.start()].count("\n") + 1,
f"`{type_name}` must implement `MtApiEventMaterializer`",
)
)
if "fn accepted_families(&self) -> &'static [crate::MdEventFamily]" not in text:
violations.append(
Violation(
"KH_MT005",
relative,
1,
"reserved materializer must declare its inactive family boundary",
)
)
if "crate::MtApiMaterializerExecutionResult::ignored()" not in text:
violations.append(
Violation(
"KH_MT006",
relative,
1,
"reserved materializer must return an ignored API result",
)
)
if "std::result::Result::Ok(std::vec::Vec::new())" not in text:
violations.append(
Violation(
"KH_MT007",
relative,
1,
"reserved materializer legacy contract must return an empty event list",
)
)
if not re.search(r"return crate::MT_[A-Z0-9_]+_ACCEPTED_FAMILIES;", text):
violations.append(
Violation(
"KH_MT008",
relative,
1,
"reserved materializer must use its exported accepted-family constant",
)
)
return violations
def iter_rust_json_object_macros(text: str) -> list[tuple[int, str]]:
"""Return balanced `serde_json::json!({ ... })` object macro bodies."""
blocks: list[tuple[int, str]] = []
needle = "serde_json::json!({"
offset = 0
while True:
start = text.find(needle, offset)
if start < 0:
break
brace = text.find("{", start)
depth = 0
in_string = False
escaped = False
end = brace
while end < len(text):
character = text[end]
if in_string:
if escaped:
escaped = False
elif character == "\\":
escaped = True
elif character == '"':
in_string = False
elif character == '"':
in_string = True
elif character == "{":
depth += 1
elif character == "}":
depth -= 1
if depth == 0:
blocks.append((start, text[start: end + 1]))
offset = end + 1
break
end += 1
else:
offset = start + len(needle)
return blocks
def audit_materializer_conventions(root: pathlib.Path) -> list[Violation]:
"""Audit materializer names, constants and component facade structure."""
violations: list[Violation] = []
materializer_root = root / "ks-lib/src/materializer"
component_pattern = re.compile(
r'pub\(crate\) const (MT_[A-Z0-9_]+)_COMPONENT_NAME: &str\s*=\s*"([^"]+)";'
)
processor_pattern = re.compile(
r'pub\(crate\) const (MT_[A-Z0-9_]+)_PROCESSOR_NAME: &str\s*=\s*"([^"]+)";'
)
component_names: dict[str, tuple[str, str, int]] = {}
processor_names: dict[str, tuple[str, str, int]] = {}
for path in sorted(materializer_root.rglob("constants.rs")):
relative = path.relative_to(root).as_posix()
text = path.read_text(encoding="utf-8")
for match in component_pattern.finditer(text):
prefix = match.group(1)
line = text[: match.start()].count("\n") + 1
component_names[prefix] = (match.group(2), relative, line)
for match in processor_pattern.finditer(text):
prefix = match.group(1)
line = text[: match.start()].count("\n") + 1
processor_names[prefix] = (match.group(2), relative, line)
for prefix, (component_name, relative, line) in sorted(component_names.items()):
processor = processor_names.get(prefix)
if processor is None:
violations.append(
Violation(
"KH_MT009",
relative,
line,
f"`{prefix}` component name requires one matching processor name",
)
)
continue
processor_name = processor[0]
if not component_name.startswith("ks-lib-materializer."):
violations.append(
Violation(
"KH_MT010",
relative,
line,
f"materializer component name `{component_name}` must start with `ks-lib-materializer.`",
)
)
expected_processor = "materializer." + component_name.removeprefix("ks-lib-materializer.")
if processor_name != expected_processor:
violations.append(
Violation(
"KH_MT011",
processor[1],
processor[2],
f"processor name `{processor_name}` must equal `{expected_processor}`",
)
)
for prefix, (_, relative, line) in sorted(processor_names.items()):
if prefix not in component_names:
violations.append(
Violation(
"KH_MT012",
relative,
line,
f"`{prefix}` processor name requires one matching component name",
)
)
for path in sorted(materializer_root.rglob("constants.rs")):
relative = path.relative_to(root).as_posix()
text = path.read_text(encoding="utf-8")
for match in component_pattern.finditer(text):
symbol = f"{match.group(1)}_COMPONENT_NAME"
used_by_implementation = any(
symbol in candidate.read_text(encoding="utf-8")
for candidate in path.parent.rglob("*.rs")
if candidate.name != "constants.rs"
)
if not used_by_implementation:
violations.append(
Violation(
"KH_MT025",
relative,
text[: match.start()].count("\n") + 1,
f"materializer component constant `{symbol}` is not consumed by its implementation",
)
)
component_values = {value[0] for value in component_names.values()}
processor_values = {value[0] for value in processor_names.values()}
if len(component_values) != len(component_names):
violations.append(
Violation(
"KH_MT017",
"ks-lib/src/materializer",
1,
"materializer component names must be unique",
)
)
if len(processor_values) != len(processor_names):
violations.append(
Violation(
"KH_MT018",
"ks-lib/src/materializer",
1,
"materializer processor names must be unique",
)
)
tracing_pattern = re.compile(
r'pub\(crate\) const TRACING_TARGET_MATERIALIZER_[A-Z0-9_]+: &str\s*=\s*"([^"]+)";'
)
for path in sorted(materializer_root.rglob("constants.rs")):
relative = path.relative_to(root).as_posix()
text = path.read_text(encoding="utf-8")
for match in tracing_pattern.finditer(text):
if match.group(1) not in component_values:
line = text[: match.start()].count("\n") + 1
violations.append(
Violation(
"KH_MT019",
relative,
line,
f"materializer tracing target `{match.group(1)}` must equal one component name",
)
)
config_path = root / "config/logging.config.json"
if config_path.exists():
try:
config = json.loads(config_path.read_text(encoding="utf-8"))
except json.JSONDecodeError:
config = None
pending: list[object] = [config] if config is not None else []
while pending:
value = pending.pop()
if isinstance(value, dict):
targets = value.get("targets")
if isinstance(targets, list):
for target in targets:
if (
isinstance(target, str)
and target.startswith("ks-lib-materializer.")
and target not in component_values
):
violations.append(
Violation(
"KH_MT020",
"config/logging.config.json",
1,
f"logging target `{target}` is not a declared materializer component",
)
)
pending.extend(value.values())
elif isinstance(value, list):
pending.extend(value)
for path in sorted(materializer_root.rglob("*.rs")):
relative = path.relative_to(root).as_posix()
text = path.read_text(encoding="utf-8")
if path.name != "constants.rs" and re.search(r'"processorName"\s*:\s*"', text):
violations.append(
Violation(
"KH_MT021",
relative,
1,
"persisted processor names must come from exported component constants",
)
)
for offset, block in iter_rust_json_object_macros(text):
if '"projectionVersion"' not in block:
continue
line = text[:offset].count("\n") + 1
if '"processorName"' not in block:
violations.append(
Violation(
"KH_MT022",
relative,
line,
"versioned materializer output must persist its processor provenance",
)
)
if re.search(
r'"projectionVersion"\s*:\s*crate::MT_[A-Z0-9_]+_PROJECTION_VERSION',
block,
) is None:
violations.append(
Violation(
"KH_MT023",
relative,
line,
"materializer projection version must come from an exported component constant",
)
)
if re.search(
r'"processorName"\s*:\s*crate::MT_[A-Z0-9_]+_PROCESSOR_NAME',
block,
) is None:
violations.append(
Violation(
"KH_MT024",
relative,
line,
"materializer processor provenance must come from an exported component constant",
)
)
if path.name != "constants.rs" and re.search(
r"^\s*(?:pub(?:\(crate\))?\s+)?const\s+[A-Z][A-Z0-9_]*\b",
text,
re.MULTILINE,
):
violations.append(
Violation(
"KH_MT013",
relative,
1,
"materializer constants must be declared in the component `constants.rs`",
)
)
if path.name == "materializer.rs" and re.search(
r"^pub struct Mt[A-Za-z0-9]+Materializer;", text, re.MULTILINE
):
constants_path = path.parent / "constants.rs"
if not constants_path.exists():
violations.append(
Violation(
"KH_MT014",
relative,
1,
"materializer implementation requires a sibling `constants.rs`",
)
)
if re.search(r'"(?:ks-lib-)?materializer\.[^"]+"', text):
violations.append(
Violation(
"KH_MT015",
relative,
1,
"materializer identities must come from exported component constants",
)
)
module_lines = [
line
for line in text.splitlines()
if re.fullmatch(r"mod [A-Za-z_][A-Za-z0-9_]*;", line.strip()) is not None
]
if not module_lines:
continue
for index, line in enumerate(text.splitlines(), 1):
stripped = line.strip()
if not stripped or stripped.startswith("//") or stripped == "#[cfg(test)]":
continue
if re.fullmatch(r"mod [A-Za-z_][A-Za-z0-9_]*;", stripped) is not None:
continue
if stripped.startswith("pub use ") or stripped.startswith("pub(crate) use "):
continue
violations.append(
Violation(
"KH_MT016",
relative,
index,
"materializer facade may contain only submodule declarations and re-exports",
)
)
break
return violations
def audit_reserved_executor_scaffolds(root: pathlib.Path) -> list[Violation]:
"""Reject incomplete reserved executor contracts."""
violations: list[Violation] = []
executor_root = root / "ks-lib/src/executor"
forbidden = (
"MIGRATION_BOUNDARIES",
"LEGACY_CRATE",
"MIGRATION_STATUS",
"source-preserved-pending-port",
)
struct_pattern = re.compile(r"^pub struct (Ex[A-Za-z0-9]+Executor);$", re.MULTILINE)
reserved_count = 0
for path in sorted(executor_root.rglob("*.rs")):
relative = path.relative_to(root).as_posix()
text = path.read_text(encoding="utf-8")
for marker in forbidden:
offset = text.find(marker)
if offset >= 0:
violations.append(
Violation(
"KH_EX001",
relative,
text[:offset].count("\n") + 1,
f"temporary executor migration marker `{marker}` is forbidden",
)
)
if "\n//! Reserved executor for `" not in text:
continue
reserved_count += 1
struct_match = struct_pattern.search(text)
if struct_match is None:
violations.append(
Violation(
"KH_EX002",
relative,
1,
"reserved executor must expose one `Ex*Executor` unit struct",
)
)
continue
type_name = struct_match.group(1)
implementation = f"impl crate::ExApiInstructionExecutor for crate::{type_name} {{"
if implementation not in text:
violations.append(
Violation(
"KH_EX003",
relative,
text[: struct_match.start()].count("\n") + 1,
f"`{type_name}` must implement `ExApiInstructionExecutor`",
)
)
if "fn program_ids(&self) -> &'static [&'static str]" not in text:
violations.append(
Violation(
"KH_EX004",
relative,
1,
"reserved executor must declare its exact Program ID boundary",
)
)
if "crate::ExApiExecutionSupport::Maybe" not in text:
violations.append(
Violation(
"KH_EX005",
relative,
1,
"reserved executor must remain explicitly `Maybe` until implemented",
)
)
if '"status":"reserved_executor"' not in text or "instruction_count: 0" not in text:
violations.append(
Violation(
"KH_EX006",
relative,
1,
"reserved executor must build only an explicit zero-instruction plan",
)
)
if reserved_count != 103:
violations.append(
Violation(
"KH_EX007",
"ks-lib/src/executor",
1,
f"expected 103 reserved executor boundaries, found {reserved_count}",
)
)
return violations
def audit_token_2022_naming(root: pathlib.Path) -> list[Violation]:
"""Reject obsolete internal Token2022 spellings while preserving legacy evidence."""
violations: list[Violation] = []
obsolete = (
"kb-lib.decoder.spl.token_2022",
"`core_spl_token_2022",
)
candidates = [
root / "README.md",
root / "ROADMAP.md",
root / "RULES.md",
root / "docs/rules/RULES_GENERAL.md",
root / "docs/rules/RULES_RUST.md",
root / "docs/rules/RULES_SPECIFIC_KHADHROONY.md",
root / "ks-lib/README.md",
]
candidates.extend(sorted((root / "docs").glob("*.md")))
for path in candidates:
if not path.is_file() or path.name == "RUST_WORKSPACE_RULE_AUDIT.md":
continue
relative = path.relative_to(root).as_posix()
for index, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
for spelling in obsolete:
if spelling in line:
violations.append(
Violation(
"KH_NAME002",
relative,
index,
f"obsolete internal Token2022 spelling `{spelling}`",
)
)
return violations
def audit_private_ks_lib_paths_in_active_docs(root: pathlib.Path) -> list[Violation]:
"""Reject documentation that presents private ks-lib modules as public APIs."""
violations: list[Violation] = []
candidates = [
root / "README.md",
root / "ROADMAP.md",
root / "RULES.md",
root / "docs/rules/RULES_GENERAL.md",
root / "docs/rules/RULES_RUST.md",
root / "docs/rules/RULES_SPECIFIC_KHADHROONY.md",
root / "ks-lib/README.md",
root / "ks-program-ids/README.md",
]
candidates.extend(sorted((root / "docs").glob("*.md")))
candidates.extend(sorted((root / "docs").glob("*.json")))
pattern = re.compile(r"ks_lib::(?:decoder|executor|materializer|model)::")
for path in candidates:
if not path.is_file():
continue
relative = path.relative_to(root).as_posix()
for index, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
match = pattern.search(line)
if match is not None:
violations.append(
Violation(
"KH_API001",
relative,
index,
f"private ks-lib module path `{match.group(0)}` is forbidden in active documentation",
)
)
return violations
def audit_environment_namespaces(root: pathlib.Path) -> list[Violation]:
"""Require workspace-owned environment variables to use KS_* or KB_* namespaces."""
violations: list[Violation] = []
rust_pattern = re.compile(
r'std::env::(?:var|var_os|set_var|remove_var)\(\s*"([A-Z][A-Z0-9_]*)"'
)
rust_roots = [path.parent for path in sorted(root.glob("ks-*/Cargo.toml"))]
desktop = root / "kb-app-demo-desktop"
if desktop.is_dir():
rust_roots.append(desktop)
for rust_root in rust_roots:
for path in sorted((rust_root / "src").rglob("*.rs")):
relative = path.relative_to(root).as_posix()
text = path.read_text(encoding="utf-8")
for match in rust_pattern.finditer(text):
name = match.group(1)
if name.startswith(("KS_", "KB_")):
continue
violations.append(
Violation(
"KH_ENV001",
relative,
text[: match.start()].count("\n") + 1,
f"workspace-owned environment variable `{name}` must use a `KS_*` or `KB_*` namespace",
)
)
env_example = root / ".env.example"
if env_example.is_file():
assignment = re.compile(r"^\s*#?\s*([A-Z][A-Z0-9_]*)=")
for index, line in enumerate(env_example.read_text(encoding="utf-8").splitlines(), 1):
match = assignment.match(line)
if match is None or match.group(1).startswith(("KS_", "KB_")):
continue
violations.append(
Violation(
"KH_ENV002",
".env.example",
index,
f"workspace environment example `{match.group(1)}` must use a `KS_*` or `KB_*` namespace",
)
)
placeholder = re.compile(r"\$\{([A-Z][A-Z0-9_]*)")
for relative in [
"config/kb-app-demo-desktop.default.config.json",
"config/ks-pipeline-demo-scenarios.default.config.json",
"config/logging.config.json",
"config/transport.config.json",
"config/listeners.config.json",
"config/example.kb-app-demo-desktop.default.config.json",
"config/example.logging.config.json",
"config/example.transport.config.json",
"config/example.listeners.config.json",
]:
config = root / relative
if not config.is_file():
continue
text = config.read_text(encoding="utf-8")
for match in placeholder.finditer(text):
name = match.group(1)
if name.startswith(("KS_", "KB_")):
continue
violations.append(
Violation(
"KH_ENV003",
relative,
text[: match.start()].count("\n") + 1,
f"configuration placeholder `{name}` must use a `KS_*` or `KB_*` namespace",
)
)
guide = root / "docs/DEVNET_EXECUTION_GUIDE.md"
if guide.is_file():
text = guide.read_text(encoding="utf-8")
exported = re.compile(r"\bexport\s+([A-Z][A-Z0-9_]*)=")
for match in exported.finditer(text):
name = match.group(1)
if name.startswith(("KS_", "KB_")):
continue
violations.append(
Violation(
"KH_ENV004",
"docs/DEVNET_EXECUTION_GUIDE.md",
text[: match.start()].count("\n") + 1,
f"operator environment variable `{name}` must use a `KS_*` or `KB_*` namespace",
)
)
return violations
def audit_configuration_split(root: pathlib.Path) -> list[Violation]:
"""Require binary composition plus independent shared configuration documents."""
violations: list[Violation] = []
required_files = [
"config/kb-app-demo-desktop.default.config.json",
"config/ks-pipeline-demo-scenarios.default.config.json",
"config/logging.config.json",
"config/transport.config.json",
"config/listeners.config.json",
"config/example.kb-app-demo-desktop.default.config.json",
"config/example.logging.config.json",
"config/example.transport.config.json",
"config/example.listeners.config.json",
"config/schemas/composition.config.schema.json",
"config/schemas/logging.config.schema.json",
"config/schemas/transport.config.schema.json",
"config/schemas/listeners.config.schema.json",
"config/schemas/resolved.app.config.schema.json",
]
for relative in required_files:
if (root / relative).is_file():
continue
violations.append(
Violation(
"KH_CFG001",
relative,
1,
"required split configuration file is missing",
)
)
composition_paths = [
"config/kb-app-demo-desktop.default.config.json",
"config/ks-pipeline-demo-scenarios.default.config.json",
]
for relative in composition_paths:
path = root / relative
if not path.is_file():
continue
try:
composition = json.loads(path.read_text(encoding="utf-8"))
except json.JSONDecodeError:
composition = None
if not isinstance(composition, dict):
continue
sources = composition.get("sources")
if not isinstance(sources, dict) or set(sources) != {"logging", "transport", "listeners"}:
violations.append(
Violation(
"KH_CFG002",
relative,
1,
"binary composition must reference logging, transport and listeners sources",
)
)
for index, profile in enumerate(composition.get("profiles", []), 1):
if not isinstance(profile, dict):
continue
if "solana" in profile or "logging" in profile:
violations.append(
Violation(
"KH_CFG003",
relative,
index,
"composition profiles must reference transport/listener/logging profiles instead of embedding them",
)
)
for key in ["logging_profile", "transport_profile", "listeners_profile"]:
if not isinstance(profile.get(key), str) or not profile.get(key, "").strip():
violations.append(
Violation(
"KH_CFG004",
relative,
index,
f"composition profile must define non-empty `{key}`",
)
)
for relative in ["config/logging.config.json", "config/transport.config.json", "config/listeners.config.json"]:
path = root / relative
if not path.is_file():
continue
try:
document = json.loads(path.read_text(encoding="utf-8"))
except json.JSONDecodeError:
document = None
if not isinstance(document, dict):
continue
if not isinstance(document.get("active_profile"), str):
violations.append(Violation("KH_CFG005", relative, 1, "shared configuration document must define active_profile"))
if not isinstance(document.get("profiles"), list) or not document.get("profiles"):
violations.append(Violation("KH_CFG006", relative, 1, "shared configuration document must define named profiles"))
legacy = [
"config/app.config.json",
"config/example.app.config.json",
"config/schemas/app.config.schema.json",
"config/example.config.json",
"config/schema.config.json",
]
for relative in legacy:
if not (root / relative).exists():
continue
violations.append(
Violation(
"KH_CFG007",
relative,
1,
"legacy monolithic application configuration file must be removed",
)
)
return violations
def audit_wincode_resolution(root: pathlib.Path) -> list[Violation]:
"""Require the currently compatible Solana wincode dependency family."""
violations: list[Violation] = []
cargo_path = root / "Cargo.toml"
lock_path = root / "Cargo.lock"
if not cargo_path.exists():
return violations
cargo = tomllib.loads(cargo_path.read_text(encoding="utf-8"))
workspace_wincode = cargo.get("workspace", {}).get("dependencies", {}).get("wincode")
version = workspace_wincode.get("version") if isinstance(workspace_wincode, dict) else None
if version != "^0.5":
violations.append(
Violation(
"KH_DEP001",
"Cargo.toml",
1,
"workspace wincode must remain constrained to `^0.5`",
)
)
if not lock_path.exists():
violations.append(
Violation(
"KH_DEP002",
"Cargo.lock",
1,
"local workspace Cargo.lock is required to verify the pinned wincode resolution",
)
)
return violations
lock = tomllib.loads(lock_path.read_text(encoding="utf-8"))
packages = lock.get("package", [])
resolved_wincode = [
package.get("version")
for package in packages
if package.get("name") == "wincode"
]
resolved_varint = [
package.get("version")
for package in packages
if package.get("name") == "solana-wincode-varint"
]
if resolved_wincode != ["0.5.5"]:
violations.append(
Violation(
"KH_DEP003",
"Cargo.lock",
1,
f"expected only wincode 0.5.5, resolved {resolved_wincode}",
)
)
if resolved_varint != ["1.0.0"]:
violations.append(
Violation(
"KH_DEP004",
"Cargo.lock",
1,
f"expected only solana-wincode-varint 1.0.0, resolved {resolved_varint}",
)
)
return violations
def main() -> int:
"""Run the khadhroony-specific audit."""
parser = argparse.ArgumentParser()
parser.add_argument("--root", default=".")
parser.add_argument("--report-only", action="store_true")
arguments = parser.parse_args()
root = pathlib.Path(arguments.root).resolve()
violations = (
audit_tracing(root)
+audit_ks_lib_tracing(root)
+audit_ks_lib_symbol_prefixes(root)
+audit_reserved_decoder_scaffolds(root)
+audit_reserved_materializer_scaffolds(root)
+audit_materializer_conventions(root)
+audit_reserved_executor_scaffolds(root)
+audit_token_2022_naming(root)
+audit_private_ks_lib_paths_in_active_docs(root)
+audit_solana_types(root)
+audit_environment_namespaces(root)
+audit_configuration_split(root)
+audit_wincode_resolution(root)
)
violations.sort(key=lambda item: (item.code, item.path, item.line, item.message))
if not violations:
sys.stdout.write("Khadhroony workspace rule audit: clean\n")
return 0
sys.stdout.write(f"Khadhroony workspace rule audit: {len(violations)} violation(s)\n")
for item in violations:
sys.stdout.write(f"{item.code} {item.path}:{item.line}: {item.message}\n")
return 0 if arguments.report_only else 1
if __name__ == "__main__":
raise SystemExit(main())