Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cargo/audit.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ ignore = [
# rand 0.9.2 unsound only when a custom logger re-enters rand::rng();
# akroasis uses tracing-subscriber with no custom logger that calls
# into rand, so the condition is unreachable. Pulled in transitively
# via ulid 1.2.1 (semaino/koinon/syntonia/kryphos/kerykeion) and
# via ulid 1.2.1 (semaino/stoicheion/syntonia/kryphos/kerykeion) and
# proptest 1.11.0 (dev-only).
"RUSTSEC-2026-0097",
]
14 changes: 1 addition & 13 deletions .kanon-lint-baseline.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[baseline]
created = "2026-08-03"
remove_after = "2026-11-01"
reason = "akroasis#261 lint-debt burn-down — errors first (vault plain-string-secret, kerykeion crypto indexing), both resolved. Remaining entries are deliberate exceptions, not deferred mechanical work: RUST/no-arc-mutex-anti-pattern (kerykeion/collector.rs) already uses tokio::sync::Mutex — the rule's own recommended async-safe primitive; converting further to RwLock needs a per-callsite read/write classification across 5 files, an architecture change outside a lint-driven edit. VOCAB/crate-name-collision + NAMING/no-fleet-collision (koinon) are a cross-repo naming call deferred to a fleet naming decision (akroasis#264). NAMING/no-owner-prefix (akroasis-server) needs a GNOMON-reviewed rename, an identity decision outside a mechanical fix. ARCH/substrate-dead-dep (sphragis) is a deliberately staged dependency awaiting the pinax reference-store integration and a cryptographic review (akroasis#172). TOML/missing-trailing-comma (.gitleaks.toml), RUST/doc-promised-observability (delivery.rs), CI/release-yml-missing-attestation (release-please.yml builds no artifacts to attest — release.yml already attests), and RUST/plain-string-secret (ListEntryReport.credential_type, a JSON category label not a secret) are confirmed lint-rule false positives. YAML/missing-concurrency (gate-attestation.yml, added #262) is the same class: the file deliberately carries NO caller-level concurrency block because forkwright/.github/.github/workflows/hybrid-gate.yml already declares one and its own comment states a caller-level duplicate self-cancels the shared group — sphragis's gate-attestation.yml (the reusable workflow's other adopter) carries the identical no-block shape for the identical reason. Entries clear only when the rule is fixed upstream or the cited decision resolves."
reason = "akroasis#261 lint-debt burn-down — errors first (vault plain-string-secret, kerykeion crypto indexing), both resolved. Remaining entries are deliberate exceptions, not deferred mechanical work: RUST/no-arc-mutex-anti-pattern (kerykeion/collector.rs) already uses tokio::sync::Mutex — the rule's own recommended async-safe primitive; converting further to RwLock needs a per-callsite read/write classification across 5 files, an architecture change outside a lint-driven edit. NAMING/no-owner-prefix (akroasis-server) needs a GNOMON-reviewed rename, an identity decision outside a mechanical fix. ARCH/substrate-dead-dep (sphragis) is a deliberately staged dependency awaiting the pinax reference-store integration and a cryptographic review (akroasis#172). TOML/missing-trailing-comma (.gitleaks.toml), RUST/doc-promised-observability (delivery.rs), CI/release-yml-missing-attestation (release-please.yml builds no artifacts to attest — release.yml already attests), and RUST/plain-string-secret (ListEntryReport.credential_type, a JSON category label not a secret) are confirmed lint-rule false positives. YAML/missing-concurrency (gate-attestation.yml, added #262) is the same class: the file deliberately carries NO caller-level concurrency block because forkwright/.github/.github/workflows/hybrid-gate.yml already declares one and its own comment states a caller-level duplicate self-cancels the shared group — sphragis's gate-attestation.yml (the reusable workflow's other adopter) carries the identical no-block shape for the identical reason. Entries clear only when the rule is fixed upstream or the cited decision resolves."

[[baseline.entry]]
rule = "ARCH/substrate-dead-dep"
Expand All @@ -15,12 +15,6 @@ file = ".github/workflows/release-please.yml"
line = 1
hash = "b525087c2878d94b7bcb773fc6795d4e90b36c64bb32ad2ec421a37935890fb1"

[[baseline.entry]]
rule = "NAMING/no-fleet-collision"
file = "crates/koinon/Cargo.toml"
line = 1
hash = "70acf00586aa7b90c3866278505be7b81fb7ee1f7e21c17c1a22ac239be3c72a"

[[baseline.entry]]
rule = "NAMING/no-owner-prefix"
file = "crates/akroasis-server/Cargo.toml"
Expand Down Expand Up @@ -147,12 +141,6 @@ file = ".gitleaks.toml"
line = 40
hash = "725011530d3abd84a570798b9d272d44d36de3c2a2fac6d6b2e0eda8aeba371b"

[[baseline.entry]]
rule = "VOCAB/crate-name-collision"
file = "crates/koinon/Cargo.toml"
line = 1
hash = "70acf00586aa7b90c3866278505be7b81fb7ee1f7e21c17c1a22ac239be3c72a"

[[baseline.entry]]
rule = "YAML/missing-concurrency"
file = ".github/workflows/gate-attestation.yml"
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ Communications sovereignty and RF intelligence platform. Rust workspace, single

## Architecture

- Foundation: `koinon` (shared types, signal model), `kryphos` (crypto, identity)
- Foundation: `stoicheion` (vocabulary: shared types, signal model), `tekmerion` (evidence: callers, receipts, tamper log), `kryphos` (crypto, identity)
- Collection crates produce typed `GeoSignal` into the shared pipeline - add a domain, add a crate, signals flow automatically
- Async: tokio, native async traits
- Mesh: clean-room Meshtastic stack via `prost` protobuf - not the official `meshtastic` crate (GPL-3, ~15% coverage)

## Where to add things

- New crate: `crates/<greek-name>/`, register in root `Cargo.toml` members, follow `~/dev/kanon/crates/basanos/standards/GNOMON.md` for naming, add entry to `docs/lexicon.md`
- New signal type: extend `GeoSignal` enum in `koinon`; downstream crates match exhaustively
- New signal type: extend `GeoSignal` enum in `stoicheion`; downstream crates match exhaustively
- New standard or convention: propose it in `~/dev/kanon/crates/basanos/standards/`; cross-link from this repo's `standards/README.md`

## Boundaries
Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!--
scope: akroasis repo conventions (SIGINT/comms crates: koinon, kryphos)
scope: akroasis repo conventions (SIGINT/comms crates: stoicheion, tekmerion, kryphos)
defers_to: ~/menos-ops/CLAUDE.md for machine topology; ~/.claude/CLAUDE.md for operator principles
tightens: per-crate CLAUDE.md files may narrow within their layer
-->
Expand All @@ -17,7 +17,7 @@ Writing: `~/dev/kanon/crates/basanos/standards/WRITING.md`

## Structure

Foundation layer: `koinon` (shared types, signal model), `kryphos` (encryption, identity). See README.md for the full domain map with status markers and `docs/ARCHITECTURE.md` for layer structure.
Foundation layer: `stoicheion` (the vocabulary: shared types, signal model), `tekmerion` (evidence: callers, effect receipts, tamper log), `kryphos` (encryption, identity). See README.md for the full domain map with status markers and `docs/ARCHITECTURE.md` for layer structure.

## Commands

Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ Capability domains span radio, mesh, SDR, proximity, network defense, OSINT, off
| Domain | Crate | Crate Shipped | Hardware Backend | What |
|--------|-------|:-------------:|:----------------:|------|
| **Application shell** | akroasis, akroasis-server | ✓ | △ | CLI binary + typed axum library routes. No server binary or desktop ships yet. Radio uses `StubHardware` by default; opt-in `hardware-serial` enables Baofeng detect/read/program/export sessions. Mesh CLI is static/no-live-connection until daemon mode is implemented. |
| **Foundation** | koinon | ✓ | - | Shared IDs, coordinates, frequency and power types, 7-domain `GeoSignal` model, hardware asset registry, temporal baselines, and tamper-evident logging. |
| **Foundation** | stoicheion | ✓ | - | The workspace vocabulary: shared IDs, coordinates, frequency and power types, 7-domain `GeoSignal` model, hardware asset registry, and temporal baselines. |
| **Foundation** | tekmerion | ✓ | - | Evidence about what was done: validated callers and authority, effect receipts, and the tamper-evident log that attests to them. |
| **Foundation** | kryphos | ✓ | - | Credential vault and installation identity: fjall-backed encrypted storage, Argon2id derivation, ChaCha20-Poly1305 encryption, Ed25519 signing keys, rotation/revocation metadata, and mutation audit logging at `tamper.log` beside the vault store. |
| **Radio Management** | syntonia | ✓ | △ | Frequency plans, CHIRP CSV/IMG import, CHIRP CSV export, validation, USB detection metadata, and Baofeng UV-5R-family codec. With `akroasis/hardware-serial`, live Baofeng serial detect/read/program/export sessions ship; real-device verification and Yaesu protocol sessions remain incomplete. |
| **Mesh Networking** | kerykeion | ✓ | △ | Meshtastic protocol stack implemented in this repository: protobuf framing, serial/TCP transports, handshake, encryption, node database, topology, discovery, routing, delivery tracking, store-and-forward, gateway bridge, and signal conversion. Real-device wire fixtures and live application wiring remain open. |
Expand Down Expand Up @@ -55,7 +56,7 @@ Capability domains span radio, mesh, SDR, proximity, network defense, OSINT, off
└────────┬─────────┘ │ (correlation, │ └──────┬──────┘
│ │ focal points, │ │
┌────────▼─────────┐ │ threat scoring) │ ┌──────▼──────┐
koinon │ └──────────────────┘ │ opsis │
stoicheion │ └──────────────────┘ │ opsis │
│ (signal model, │ │ (operator │
│ entity types, │ ┌──────────────────┐ │ surfaces) │
│ temporal engine)│ │ chorografia │ └─────────────┘
Expand All @@ -70,7 +71,7 @@ Capability domains span radio, mesh, SDR, proximity, network defense, OSINT, off
└──────────────────┘
```

Every collection crate is expected to produce typed `GeoSignal` objects defined by koinon. Kerykeion implements mesh-to-signal conversion, while semaino provides domain-agnostic aggregation and synthetic coverage for the seven-domain signal model; neither is wired into a live application pipeline yet. Ichneutes, Praxis, and Opsis remain architectural targets. Add a domain, add a crate, then explicitly wire and verify the collector-to-processing path.
Every collection crate is expected to produce typed `GeoSignal` objects defined by stoicheion. Kerykeion implements mesh-to-signal conversion, while semaino provides domain-agnostic aggregation and synthetic coverage for the seven-domain signal model; neither is wired into a live application pipeline yet. Ichneutes, Praxis, and Opsis remain architectural targets. Add a domain, add a crate, then explicitly wire and verify the collector-to-processing path.

---

Expand Down
11 changes: 8 additions & 3 deletions _llm/architecture.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,14 @@ path = "crates/akroasis"
role = "Single binary shell with CLI dispatch for shipped and future domain stubs."

[[architecture.crates]]
name = "koinon"
path = "crates/koinon"
role = "Shared IDs, coordinates, frequency/power types, GeoSignal model, hardware registry, baselines, and tamper log."
name = "stoicheion"
path = "crates/stoicheion"
role = "The workspace vocabulary: shared IDs, coordinates, frequency/power types, GeoSignal model, hardware registry, and baselines."

[[architecture.crates]]
name = "tekmerion"
path = "crates/tekmerion"
role = "Evidence: validated callers and authority, effect receipts, and the tamper-evident log."

[[architecture.crates]]
name = "kryphos"
Expand Down
4 changes: 2 additions & 2 deletions _llm/decisions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ id = "D-one-signal-model"
title = "Unify domains through typed signals"
status = "accepted"
context = "Radio, mesh, network, proximity, OSINT, and field operations otherwise fragment into separate tools."
decision = "Every domain emits typed GeoSignal objects into shared koinon/semaino models."
decision = "Every domain emits typed GeoSignal objects into shared stoicheion/semaino models."
consequences = "Correlation and convergence are domain-agnostic."

[[decision]]
Expand All @@ -40,7 +40,7 @@ id = "D-collector-trait"
title = "Hardware-facing crates implement Collector"
status = "accepted"
context = "Hardware domains vary but need a common integration shape."
decision = "Define hardware abstraction through the Collector trait in koinon."
decision = "Define hardware abstraction through the Collector trait in stoicheion."
consequences = "Hardware tests can use mocks and recorded replay."

[[decision]]
Expand Down
9 changes: 7 additions & 2 deletions _llm/glossary.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,13 @@ definition = "Typed signal object carrying domain, location, temporal, and sever
canonical = true

[[terms]]
term = "koinon"
definition = "Shared foundation crate for IDs, signal types, baselines, hardware registry, and tamper log."
term = "stoicheion"
definition = "στοιχεῖον — element. The workspace vocabulary: shared IDs, signal types, baselines, and the hardware registry."
canonical = true

[[terms]]
term = "tekmerion"
definition = "τεκμήριον — proof. Evidence about what was done: callers, effect receipts, and the tamper-evident log."
canonical = true

[[terms]]
Expand Down
2 changes: 1 addition & 1 deletion crates/akroasis/src/caller.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Application caller resolution and audit-before-effect execution.
//!
//! This module adapts authenticated transport evidence into the shared
//! `koinon` contract. It owns no credential store and does not implement any
//! `tekmerion` contract. It owns no credential store and does not implement any
//! domain-specific effect or policy.

use std::fmt;
Expand Down
4 changes: 2 additions & 2 deletions crates/akroasis/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ mod cli;
not(test),
expect(
dead_code,
reason = "mesh table/status helpers await daemon integration, tracked in #264"
reason = "mesh status/node tables need a live NodeDb and GatewayBridge, which #83 supplies"
)
)]
mod mesh;
Expand Down Expand Up @@ -60,7 +60,7 @@ enum Error {
#[serde(deny_unknown_fields)]
#[expect(
dead_code,
reason = "config fields reserved for future CLI options, tracked in #264"
reason = "config is loaded and discarded; the surface is resolved by #461"
)]
struct Config {
/// Path to the configuration file (default: `~/.config/akroasis/config.toml`).
Expand Down
11 changes: 6 additions & 5 deletions crates/kryphos/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,8 @@ impl Vault {
// `installation_public_key` while every signature verified against a
// different key entirely, which is the substitution this identity
// exists to make detectable.
if header.installation_public_key.as_deref() != Some(&identity.public_key_bytes()[..]) {
if header.installation_public_key.as_deref() != Some(identity.public_key_bytes().as_slice())
{
return Err(VaultError::InvalidHeader {
reason: String::from(
"installation_public_key does not match the sealed signing key",
Expand Down Expand Up @@ -1010,7 +1011,7 @@ impl Vault {
///
/// WHY the vault answers this rather than the caller reaching for
/// `tekmerion::verify_tip_provenance` directly: the vault is what knows
/// whether an identity is *expected*. koinon can report that a log is
/// whether an identity is *expected*. tekmerion can report that a log is
/// unsigned; only the header says whether that is a vault which never had
/// an identity or one whose signing has been stripped.
///
Expand All @@ -1029,7 +1030,7 @@ impl Vault {
/// header errors of [`Self::installation_identity`].
pub fn verify_tamper_log_provenance(&self) -> Result<tekmerion::TipStatus, VaultError> {
let Some(identity) = self.installation_identity()? else {
// No identity to check against; koinon reports the log's own state.
// No identity to check against; tekmerion reports the log's own state.
return tekmerion::verify_tip_provenance(
self.tamper_log_path(),
&self.chain_key(),
Expand Down Expand Up @@ -1182,10 +1183,10 @@ impl Vault {

// INVARIANT: `log` must drop before `_guard` — Rust drops function
// locals in reverse declaration order, so declaring `_guard` first
// guarantees `log`'s koinon-level OS advisory lock (`TamperLog`'s
// guarantees `log`'s tekmerion-level OS advisory lock (`TamperLog`'s
// `_lock` field) is released before this mutex is, so a thread that
// was waiting on `_guard` never sees a spurious `TamperLogError::
// Locked` from koinon's own (fail-fast, non-blocking) lock.
// Locked` from tekmerion's own (fail-fast, non-blocking) lock.
// WHY the identity is resolved per append rather than cached on the
// handle: the sealed signing key lives in the header, and reading it
// here keeps the plaintext key alive only for the append that uses it
Expand Down
4 changes: 2 additions & 2 deletions crates/kryphos/tests/tamper_log_signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ fn a_substituted_signature_does_not_verify() {
// The seal's MAC covers the signature field, so the edit is caught there
// and the signature check never runs. That is the correct outer defence and
// the honest thing for this test to assert — it does NOT cover
// `check_tip`'s signature arm, which koinon's own unit tests exercise
// `check_tip`'s signature arm, which tekmerion's own unit tests exercise
// directly with a valid MAC over a bad signature.
assert_eq!(
status.unwrap(),
Expand Down Expand Up @@ -121,7 +121,7 @@ fn a_substituted_key_id_does_not_verify() {
.verify_tamper_log_provenance();

// As above: the MAC covers the key id too, so this is refused before the
// signature is examined. koinon's unit tests cover the case where the MAC
// signature is examined. tekmerion's unit tests cover the case where the MAC
// is valid and the key id names a different installation.
assert_eq!(
status.unwrap(),
Expand Down
2 changes: 1 addition & 1 deletion crates/kryphos/tests/vault_tamper_audit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ fn concurrent_vault_mutations_produce_a_single_non_forked_chain() {
// sharing this `Arc<Vault>` could both recover the same tail and each
// append an entry chained from it, forking the chain (`verify_chain`
// reports `Broken`) or losing one writer's entry outright. The
// in-process mutex in `append_vault_audit` plus koinon's own
// in-process mutex in `append_vault_audit` plus tekmerion's own
// single-writer lock must make every mutation land, in some order, as
// one strictly-serial, verifiable chain.
const WRITERS: usize = 8;
Expand Down
4 changes: 2 additions & 2 deletions crates/semaino/src/aggregator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl KindKey {
SignalKind::Proximity(_) => Self::Proximity,
SignalKind::Gps(_) => Self::Gps,
SignalKind::Environmental(_) => Self::Environmental,
// WHY: SignalKind is #[non_exhaustive] in koinon; the wildcard arm
// WHY: SignalKind is #[non_exhaustive] in stoicheion; the wildcard arm
// handles Osint and any future variants without triggering
// unreachable_patterns. Grouping unknowns with Osint keeps the
// baseline discriminant stable.
Expand Down Expand Up @@ -241,7 +241,7 @@ pub(crate) fn day_hour_from_timestamp(ts: &stoicheion::Timestamp) -> (u8, u8) {
return (0, 0);
};
let dt = zoned.datetime();
// WHY: jiff Weekday is 1-indexed (Mon=1..Sun=7); subtract 1 to match koinon's 0-indexed layout.
// WHY: jiff Weekday is 1-indexed (Mon=1..Sun=7); subtract 1 to match stoicheion's 0-indexed layout.
let day = match dt.weekday() {
Weekday::Monday => 0u8,
Weekday::Tuesday => 1,
Expand Down
Loading