use crate::catalog::CatalogEntry;
use kernel::{AdmissionRequirement, LandingPolicy, Mode, RunPolicy};
pub const DEV_ENTRY: &str = "dev";
#[must_use]
pub fn dev_entry() -> CatalogEntry {
CatalogEntry {
name: DEV_ENTRY.to_owned(),
disclosure: "when the work is to change this city's own code, SPECs or tools, open this \
entry before you touch anything"
.to_owned(),
expansion: "This city is built from small components, each with its SPEC beside it at \
`crates/<crate>/<crate>-SPEC.md`. Read that SPEC, then the code, then the \
tests next to the code - in that order, and before you change any of them. \
Where the implementation would differ from the SPEC, the SPEC changes first \
and says why.\n\nThe person chooses what a change must prove before it is \
merged:\n- tested: the asset's own tests ran and passed.\n- contract_kept: \
the asset's observable contract did not move.\n- double_validated: the change \
holds on held-in and on held-out evidence.\nAnd where it lands: \
ordinary work takes the building's own road, while an experiment works in a \
tree of its own and nothing in it is merged.\n\nYour next step: say which \
evidence this work needs and why, and wait for the person to dispatch it \
with that requirement. Choosing a requirement does not provide the evidence."
.to_owned(),
hash: None,
package: None,
}
}
#[must_use]
pub fn catalog_entry(mode: Mode) -> CatalogEntry {
let (disclosure, expansion) = match mode {
Mode::Chat => (
"chat mode: focus on conversing with the person; answer what they said, in their language",
"Reply in the conversation. Start work, plans or dispatches only when the person asks for them.",
),
Mode::Work => (
"work mode: carry out the task towards the stated goal; report when the goal is met",
"When the task asks for a plan first, write it into Roadmap.md with the `plan` tool \
before you change anything, then work through it. Report what you did and the \
evidence that the goal is met.",
),
};
CatalogEntry {
name: format!("mode:{}", mode.as_str()),
disclosure: disclosure.to_owned(),
expansion: expansion.to_owned(),
hash: None,
package: None,
}
}
#[must_use]
pub fn core_tools(mode: Mode) -> &'static [&'static str] {
match mode {
Mode::Chat => &[
crate::tools::CallTool::NAME,
crate::tools::DescribeTool::NAME,
crate::tools::ReadTool::NAME,
crate::tools::SearchTool::NAME,
crate::tools::StatusTool::NAME,
],
Mode::Work => &[
crate::tools::CallTool::NAME,
crate::tools::DescribeTool::NAME,
crate::tools::EditTool::NAME,
kernel::ToolName::EXEC,
crate::tools::ReadTool::NAME,
crate::tools::SearchTool::NAME,
crate::tools::StatusTool::NAME,
],
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Produced {
pub tests_passed: Option<bool>,
pub contract_moved: bool,
pub held_in: Option<bool>,
pub held_out: Option<bool>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Admission {
Lands,
Refused {
because: &'static str,
alternative: &'static str,
},
}
#[must_use]
pub fn admits(policy: &RunPolicy, produced: &Produced) -> Admission {
match policy.landing {
LandingPolicy::Experiment => Admission::Refused {
because: "nothing produced in an experiment lands",
alternative: "write what you learned into Memo.md, then ask for the work again \
with the ordinary landing",
},
LandingPolicy::Ordinary => admits_evidence(policy.admit, produced),
}
}
fn admits_evidence(required: AdmissionRequirement, produced: &Produced) -> Admission {
match required {
AdmissionRequirement::Standing => Admission::Lands,
AdmissionRequirement::Tested => match produced.tests_passed {
Some(true) => Admission::Lands,
Some(false) => Admission::Refused {
because: "the asset's own tests did not pass",
alternative: "fix the asset or the test, then offer it again",
},
None => Admission::Refused {
because: "the asset has no tests of its own",
alternative: "write the test that would fail if this asset broke",
},
},
AdmissionRequirement::ContractKept => {
if produced.contract_moved {
Admission::Refused {
because: "the asset's observable contract moved",
alternative: "keep the contract and renovate behind it, or ask for the work \
again under double_validated with held-out evidence",
}
} else {
Admission::Lands
}
}
AdmissionRequirement::DoubleValidated => match (produced.held_in, produced.held_out) {
(Some(true), Some(true)) => Admission::Lands,
(Some(false), _) => Admission::Refused {
because: "it got worse on the held-in set",
alternative: "a change that costs more than it buys is not adopted; revise it",
},
(_, Some(false)) => Admission::Refused {
because: "it did not stand up on the held-out set",
alternative: "a gain that only shows where it was built is a gain in fitting, \
not in ability",
},
_ => Admission::Refused {
because: "one half of the double validation is missing",
alternative: "run the suite on both sets; an unmeasured change is not adopted on \
confidence",
},
},
}
}
#[cfg(test)]
#[allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
reason = "test code"
)]
mod tests {
use super::*;
fn work(admit: AdmissionRequirement) -> RunPolicy {
RunPolicy {
admit,
..RunPolicy::of(Mode::Work)
}
}
#[test]
fn a_work_run_without_the_evidence_it_chose_does_not_land() {
let Admission::Refused { because, .. } =
admits(&work(AdmissionRequirement::Tested), &Produced::default())
else {
panic!("work that chose `tested` and ran no test landed");
};
assert!(because.contains("no tests"), "{because}");
}
#[test]
fn chat_is_one_line_about_the_conversation() {
let entry = catalog_entry(Mode::Chat);
assert_eq!(entry.name, "mode:chat");
assert!(entry.disclosure.contains("convers"), "{}", entry.disclosure);
assert!(!entry.disclosure.contains('\n'), "one line");
assert!(
!entry.expansion.is_empty(),
"a read of the entry says something"
);
assert_eq!(catalog_entry(Mode::Work).name, "mode:work");
}
#[test]
fn standing_adds_nothing_in_either_mode() {
for mode in Mode::ALL {
assert_eq!(
admits(&RunPolicy::of(mode), &Produced::default()),
Admission::Lands
);
}
}
#[test]
fn tested_wants_the_asset_proven_and_says_which_way_it_failed() {
let policy = work(AdmissionRequirement::Tested);
let failed = Produced {
tests_passed: Some(false),
..Produced::default()
};
let Admission::Refused { because, .. } = admits(&policy, &failed) else {
panic!("a failing asset does not land");
};
assert!(
because.contains("did not pass"),
"not the untested sentence"
);
let passed = Produced {
tests_passed: Some(true),
..Produced::default()
};
assert_eq!(admits(&policy, &passed), Admission::Lands);
}
#[test]
fn contract_kept_refuses_a_renovation_that_moved_the_contract() {
let policy = work(AdmissionRequirement::ContractKept);
assert_eq!(admits(&policy, &Produced::default()), Admission::Lands);
let moved = Produced {
contract_moved: true,
..Produced::default()
};
let Admission::Refused { alternative, .. } = admits(&policy, &moved) else {
panic!("a moved contract is not a renovation");
};
assert!(
alternative.contains("double_validated"),
"the refusal names the requirement that would take it"
);
}
#[test]
fn double_validated_takes_nothing_on_confidence() {
let policy = work(AdmissionRequirement::DoubleValidated);
let both = Produced {
held_in: Some(true),
held_out: Some(true),
..Produced::default()
};
assert_eq!(admits(&policy, &both), Admission::Lands);
for missing in [
Produced {
held_in: Some(true),
..Produced::default()
},
Produced {
held_out: Some(true),
..Produced::default()
},
Produced::default(),
] {
assert!(
matches!(admits(&policy, &missing), Admission::Refused { .. }),
"half of a double validation is not a double validation"
);
}
let regressed = Produced {
held_in: Some(true),
held_out: Some(false),
..Produced::default()
};
let Admission::Refused { because, .. } = admits(&policy, ®ressed) else {
panic!("a change that only holds where it was built does not land");
};
assert!(because.contains("held-out"));
}
#[test]
fn an_experiment_lands_nothing_however_well_it_went() {
let excellent = Produced {
tests_passed: Some(true),
contract_moved: false,
held_in: Some(true),
held_out: Some(true),
};
for admit in AdmissionRequirement::ALL {
let policy = RunPolicy {
landing: LandingPolicy::Experiment,
write: kernel::WriteLimit::Create,
..work(admit)
};
assert!(matches!(
admits(&policy, &excellent),
Admission::Refused { .. }
));
}
}
}