fix(audit-r2): HIGH+MEDIUM closures from second round audit
HIGH-1: submodule URL ssh → https + shallow (DNS spoofing surface, both repos)
HIGH-3: docs/DNA-MIGRATION.md — two-format coexistence policy (4-seg legacy
task-class vs 5-seg agent-shell marketplace)
HIGH-5: agent_shell_dna doc — explicit consumer = marketplace, planned ledger
integration; module-doc clarification
MEDIUM: Haiku model id pinned to claude-haiku-4-5-20251001 across
pricing.rs::from_slug + ::name + escalate.rs tests + select_posterior
fixture + kei-registries submodule (pushed c39e528→7aaa6a7)
This commit is contained in:
parent
08654a40b4
commit
f7218e06b6
8 changed files with 94 additions and 9 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -1,3 +1,4 @@
|
|||
[submodule "_blocks/registries"]
|
||||
path = _blocks/registries
|
||||
url = git@github.com:KeiSeiLab/kei-registries.git
|
||||
url = https://github.com/KeiSeiLab/kei-registries.git
|
||||
shallow = true
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 14a1e62db6bff685e9b707fd368e6bbe42e9a819
|
||||
Subproject commit 7aaa6a79b00271d9c08ac4f5c1f0e2d523a49da0
|
||||
|
|
@ -1,5 +1,10 @@
|
|||
//! Agent-shell DNA — 5-segment per-invocation identifier.
|
||||
//!
|
||||
//! **Consumer:** `keisei-marketplace` (not yet wired into kei-model-router's
|
||||
//! routing/posterior; planned for v0.18 when the marketplace pushes invocation
|
||||
//! records into the shared ledger). See `docs/DNA-MIGRATION.md` for the
|
||||
//! two-format coexistence policy.
|
||||
//!
|
||||
//! Format emitted by `keisei-marketplace/src/lib/cryptoid.ts::agentDna`:
|
||||
//!
|
||||
//! `agent-shell::<provider>:<model>:<caps>::<scope_sha>::<body_sha>-<nonce>`
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ mod tests {
|
|||
#[test]
|
||||
fn haiku_escalates_to_sonnet_within_anthropic() {
|
||||
let r = reg();
|
||||
assert_eq!(next_model("claude-haiku-4-5", "anthropic", &r), EscalationResult::Next("claude-sonnet-4-6"));
|
||||
assert_eq!(next_model("claude-haiku-4-5-20251001", "anthropic", &r), EscalationResult::Next("claude-sonnet-4-6"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -136,7 +136,7 @@ mod tests {
|
|||
#[test]
|
||||
fn next_variant_carries_model_id() {
|
||||
let r = reg();
|
||||
assert!(matches!(next_model("claude-haiku-4-5", "anthropic", &r), EscalationResult::Next("claude-sonnet-4-6")));
|
||||
assert!(matches!(next_model("claude-haiku-4-5-20251001", "anthropic", &r), EscalationResult::Next("claude-sonnet-4-6")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ pub enum Model {
|
|||
impl Model {
|
||||
pub fn slug(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Haiku45 => "claude-haiku-4-5",
|
||||
Self::Haiku45 => "claude-haiku-4-5-20251001",
|
||||
Self::Sonnet46 => "claude-sonnet-4-6",
|
||||
Self::Opus47 => "claude-opus-4-7",
|
||||
}
|
||||
|
|
@ -72,7 +72,7 @@ impl Model {
|
|||
|
||||
pub fn from_slug(s: &str) -> Option<Model> {
|
||||
match s {
|
||||
"haiku" | "haiku-4.5" | "claude-haiku-4-5" => Some(Self::Haiku45),
|
||||
"haiku" | "haiku-4.5" | "claude-haiku-4-5" | "claude-haiku-4-5-20251001" => Some(Self::Haiku45),
|
||||
"sonnet" | "sonnet-4.6" | "claude-sonnet-4-6" => Some(Self::Sonnet46),
|
||||
"opus" | "opus-4.7" | "claude-opus-4-7" => Some(Self::Opus47),
|
||||
_ => None,
|
||||
|
|
@ -131,7 +131,7 @@ mod tests {
|
|||
#[test]
|
||||
fn haiku_output_1m_is_500m_microcents() {
|
||||
let r = reg();
|
||||
let c = cost_micro_cents("claude-haiku-4-5", 0, 1_000_000, &r).unwrap();
|
||||
let c = cost_micro_cents("claude-haiku-4-5-20251001", 0, 1_000_000, &r).unwrap();
|
||||
assert_eq!(c, 500_000_000);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ mod tests {
|
|||
let c = fresh_db();
|
||||
for i in 0..30 {
|
||||
c.execute(
|
||||
"INSERT INTO agents VALUES (?1,'tc1','claude-haiku-4-5','functional',0)",
|
||||
"INSERT INTO agents VALUES (?1,'tc1','claude-haiku-4-5-20251001','functional',0)",
|
||||
rusqlite::params![format!("a{i}")],
|
||||
)
|
||||
.unwrap();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# KeiSeiKit DNA Encyclopedia
|
||||
|
||||
> Auto-generated from kei-registry. Last regenerated: 2026-05-13T16:01:55Z.
|
||||
> Auto-generated from kei-registry. Last regenerated: 2026-05-14T04:37:36Z.
|
||||
> Total blocks: 679. Per-type breakdown:
|
||||
|
||||
| Type | Count |
|
||||
|
|
|
|||
79
docs/DNA-MIGRATION.md
Normal file
79
docs/DNA-MIGRATION.md
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# DNA Migration — two formats coexist
|
||||
|
||||
> Status lock 2026-05-14. Authoritative on which format to use when.
|
||||
|
||||
## Two formats, two granularities
|
||||
|
||||
| Format | Layout | Used by | Purpose |
|
||||
|---|---|---|---|
|
||||
| **task-class** (4-segment, legacy) | `<role>::<caps>::<scope8>::<body8>-<nonce8>` | `kei-ledger` agent forks (RULE 0.12), internal agent invocations | Internal-agent identity; same prompt re-runs cluster on same task-class |
|
||||
| **agent-shell** (5-segment, new) | `agent-shell::<provider>:<model>:<caps>::<scope16>::<body16>-<nonce16>` | `keisei-marketplace` user-level invocations | User-shell identity; carries provider+model in the wire format so the marketplace UI / billing pipeline can join on it without parsing JSON |
|
||||
|
||||
Hex lengths differ on purpose — 8-char nonce was sufficient for single-machine
|
||||
ledger; 16-char (64-bit) is required for marketplace where N concurrent
|
||||
sessions across the public install base push birthday collision into reach.
|
||||
|
||||
## Which format does my code emit?
|
||||
|
||||
- Writing a substrate-internal agent spawn (sub-agent of an orchestrator,
|
||||
background ML run, ledger row for `kei-fork`) → **task-class** via
|
||||
`kei-shared::dna::compose(...)` (or equivalent helper in your crate).
|
||||
- Writing a marketplace user-facing invocation (chat message hitting
|
||||
`/v1/chat/completions`, agent the user picked from the public catalog) →
|
||||
**agent-shell** via `cryptoid.ts::agentDna(...)` in the marketplace.
|
||||
|
||||
When in doubt, ask: "does this row in the ledger correspond to a particular
|
||||
human user clicking a button?" If yes → agent-shell. If no → task-class.
|
||||
|
||||
## Parser table
|
||||
|
||||
| You have a string | Parse it with |
|
||||
|---|---|
|
||||
| `kei-shared::dna::*` or `kei-model-router::dna_class::*` | `dna_class::role` / `dna_class::caps` / `dna_class::task_class_dna` / `dna_class::agent_class_dna` |
|
||||
| `agent-shell::*` | `kei-model-router::agent_shell_dna::parse` (Rust) or `cryptoid.ts::parseAgentDna` (TS) |
|
||||
|
||||
Both parsers tolerate `None` / `null` on malformed input — never panic.
|
||||
|
||||
## Ledger join
|
||||
|
||||
When `agent_runs` (marketplace, agent-shell) needs to join `kei-ledger.agents`
|
||||
(KSK, task-class), use the explicit translation:
|
||||
|
||||
```
|
||||
agent-shell DNA → drop prefix → use (provider, model, caps) as filter,
|
||||
use scope_sha+body_sha as join keys
|
||||
```
|
||||
|
||||
There is intentionally **no** lossless round-trip between the two formats —
|
||||
they carry different information. agent-shell carries provider+model that
|
||||
task-class does not.
|
||||
|
||||
## Cross-language contract
|
||||
|
||||
Field names on the parsed struct are aligned per 2026-05-14:
|
||||
|
||||
| Rust (`agent_shell_dna::AgentShellDna`) | TypeScript (`ParsedAgentDna`) |
|
||||
|---|---|
|
||||
| `provider` | `provider` |
|
||||
| `model` | `model` |
|
||||
| `caps` | `caps` |
|
||||
| `scope_sha` | `scope_sha` |
|
||||
| `body_sha` | `body_sha` |
|
||||
| `nonce` | `nonce` |
|
||||
|
||||
snake_case on both sides (TS field names exempted from camelCase convention
|
||||
for cross-language consistency). JSON round-trip is byte-equal.
|
||||
|
||||
## Migration history
|
||||
|
||||
- 2026-05-13 — `agent_shell_dna` cube added to `kei-model-router` (issue: marketplace needs provider-aware DNA).
|
||||
- 2026-05-13 — `cryptoid.ts::agentDna` added in marketplace.
|
||||
- 2026-05-14 — fields aligned snake_case; legacy 8-hex DNAs explicitly REJECTED by TS `parseAgentDna` (return `null`).
|
||||
|
||||
## Not migrated yet
|
||||
|
||||
- `kei-shared/src/dna.rs` does not exist as a separate crate in this tree
|
||||
yet; the canonical 4-segment implementation lives in
|
||||
`_primitives/_rust/kei-model-router/src/dna_class.rs`. When kei-shared
|
||||
is extracted, `dna_class` moves there and `agent_shell_dna` follows.
|
||||
Update `docs/DNA-FORMAT.md::SSoT` pointer at that time.
|
||||
Loading…
Reference in a new issue