Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a181e73
Reject lua-prefixed fence labels with one general error
vinniefalco Oct 14, 2026
ad9303d
Remove the retired-symbol scan and retired-phrase check
vinniefalco Oct 14, 2026
88839e7
Sweep removed-feature traces from tests and comments
vinniefalco Oct 14, 2026
b45fe12
Remove live compatibility code for removed features
vinniefalco Oct 14, 2026
3cc16b9
Answer timers at once in the greeter example
vinniefalco Oct 14, 2026
6cb7990
Move positive-fixture test to Engine, fix catalog docs
vinniefalco Oct 14, 2026
48badf1
Add facade test harness and move greeter tests onto it
vinniefalco Oct 14, 2026
0186cae
Move effect, event, ids, cancel suites onto the harness
vinniefalco Oct 14, 2026
1a38c3b
Move remaining facade suites onto the test harness
vinniefalco Oct 14, 2026
30a66c7
Close plan: no-trace-fence
vinniefalco Oct 14, 2026
ab708c2
Remove thirteen tests from the facade integration suite
vinniefalco Oct 14, 2026
6042582
Move the shipped-prompt parse test into the engine suite
vinniefalco Oct 14, 2026
0de8d05
Replace the three TempDir test helpers with tempfile
vinniefalco Oct 14, 2026
b39f287
Share model, descriptor, note, and run-text test helpers
vinniefalco Oct 14, 2026
39c3c39
Trim restating comments from the facade test suite
vinniefalco Oct 14, 2026
ba9ee1f
Close plan: facade-suite-dedup
vinniefalco Oct 14, 2026
fdb20ba
Bump rustls to 0.23.46 for three security advisories
vinniefalco Oct 14, 2026
da35782
Write the cache sidecar before publishing the blob
vinniefalco Oct 14, 2026
8223eff
Make every non-exact Lua fence a parse error
vinniefalco Oct 14, 2026
5960a4d
Drop slot-era test probes and fix tool catalog docs
vinniefalco Oct 14, 2026
3b1ea0d
Close plan: sidecar-strict-fences
vinniefalco Oct 14, 2026
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
11 changes: 8 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 0 additions & 24 deletions crates/build-user-guide/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,30 +74,6 @@ fn main() {
}
}

/// Rejects guide text that names the `[workshop.stt]` section on a line that
/// does not describe it as rejected.
fn check_removed_workshop_stt_claims(src: &Path) -> Result<(), AssembleError> {
for (set, _) in BOOKS {
let set_dir = src.join(set);
for chapter in read_chapters(&set_dir)? {
let path = set_dir.join(chapter.file_name);
let content = fs::read_to_string(&path)
.map_err(|e| AssembleError(format!("cannot read {}: {e}", path.display())))?;
for (index, line) in content.lines().enumerate() {
if line.contains("[workshop.stt]") && !line.to_ascii_lowercase().contains("reject")
{
return Err(AssembleError(format!(
"removed [workshop.stt] section is not described as rejected in {}:{}",
path.display(),
index + 1
)));
}
}
}
}
Ok(())
}

/// Lists a set directory's chapter files in reading order, reading each
/// chapter's title from its first H1 heading.
fn read_chapters(set_dir: &Path) -> Result<Vec<Chapter>, AssembleError> {
Expand Down
27 changes: 3 additions & 24 deletions crates/build-user-guide/src/stage-tests.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! Tests for stage mode: chapters come from the docs root it is given,
//! which must be set and name a directory; one flat tree per book with its
//! config, back-link script, chapters, rendered overview, and SUMMARY, and
//! each book's single-file export beside the trees; a relative output path,
//! a broken SUMMARY link, and a `[workshop.stt]` claim are rejected;
//! output is deterministic and the guide and docs trees are only read.
//! each book's single-file export beside the trees; a relative output path
//! and a broken SUMMARY link are rejected; output is deterministic and the
//! guide and docs trees are only read.

use std::collections::BTreeMap;
use std::fs;
Expand Down Expand Up @@ -240,27 +240,6 @@ fn stage_rejects_a_summary_link_that_does_not_resolve() {
assert!(message.contains("gateway book"), "{message}");
}

#[test]
fn stage_rejects_a_stale_workshop_stt_claim_in_any_set_before_writing() {
for (set, _) in BOOKS {
let fake = fake_guide();
fs::write(
fake.docs.join("src").join(set).join("09-stale.md"),
"# Stale\n\nLegacy `[workshop.stt]` input is accepted.\n",
)
.expect("stale chapter");
let out = tempfile::tempdir().expect("tempdir");
let error = stage_fake(&fake, out.path()).expect_err(set);
let message = error.to_string();
assert!(message.contains("09-stale.md"), "{set}: {message}");
assert!(
message.contains("removed [workshop.stt] section is not described as rejected"),
"{set}: {message}"
);
assert!(snapshot(out.path()).is_empty(), "{set}");
}
}

#[test]
fn staging_is_deterministic() {
let fake = fake_guide();
Expand Down
10 changes: 4 additions & 6 deletions crates/build-user-guide/src/stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@ use std::fs;
use std::path::{Path, PathBuf};

use crate::{
AssembleError, BOOKS, DOCS_VAR, check_links, check_removed_workshop_stt_claims, read_chapters,
render_export, render_index, render_summary, write_file,
AssembleError, BOOKS, DOCS_VAR, check_links, read_chapters, render_export, render_index,
render_summary, write_file,
};

/// Stages every book in `BOOKS` into `out`, which must be absolute, from
/// the chapters under `src/` in `docs`, the `promptforge-docs` root, and
/// the book configs and chrome in `guide`. The `[workshop.stt]` check runs
/// before anything is written; the SUMMARY link check runs on each staged
/// book. Files already in `out` are overwritten, never removed.
/// the book configs and chrome in `guide`. The SUMMARY link check runs on
/// each staged book. Files already in `out` are overwritten, never removed.
pub(crate) fn stage(guide: &Path, docs: Option<&Path>, out: &Path) -> Result<(), AssembleError> {
if !out.is_absolute() {
return Err(AssembleError(format!(
Expand All @@ -28,7 +27,6 @@ pub(crate) fn stage(guide: &Path, docs: Option<&Path>, out: &Path) -> Result<(),
)));
}
let src = docs_src(docs)?;
check_removed_workshop_stt_claims(&src)?;

for (book, part_title) in BOOKS {
let book_out = out.join(book);
Expand Down
72 changes: 1 addition & 71 deletions crates/build-xtask/src/engine_guards-tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! The live Engine guards over this workspace, plus fixture tests that a
//! reintroduced retired symbol or a forbidden dependency in an Engine
//! crate fails the guard.
//! forbidden dependency in an Engine crate fails the guard.

use std::path::{Path, PathBuf};

Expand Down Expand Up @@ -54,16 +53,6 @@ fn engine_crates_declare_no_forbidden_dependencies() {
);
}

#[test]
fn engine_sources_name_no_retired_symbols() {
let violations = retired_symbol_violations(&workspace_root());
assert!(
violations.is_empty(),
"retired symbols in live engine source:\n{}",
violations.join("\n")
);
}

#[test]
fn the_engine_crate_set_is_the_root_crates_plus_every_container_member() {
let root = clean_engine_root();
Expand Down Expand Up @@ -151,65 +140,6 @@ fn the_facade_forwarding_the_engine_test_support_feature_passes_every_engine_gua
);
}

#[test]
fn a_retired_symbol_reintroduced_in_an_engine_crate_fails_the_guard() {
let root = clean_engine_root();
write_crate(
root.path(),
"promptforge-internal/lua",
"",
"pub struct Vm;\n\npub fn install_agent_chat_shim() {}\n",
);
let violations = engine_guard_violations(root.path());
assert_eq!(violations.len(), 1, "{violations:?}");
assert!(
violations[0].contains("install_agent_chat_shim")
&& violations[0].contains("lib.rs")
&& violations[0].contains(":3"),
"the reintroduced seed is reported with its file and line: {violations:?}"
);
}

#[test]
fn every_seed_is_caught_and_a_seed_confined_to_test_code_passes() {
let root = clean_engine_root();
let live = RETIRED_SEEDS
.iter()
.map(|seed| format!("pub struct {seed};\n"))
.collect::<Vec<_>>()
.concat();
write_crate(root.path(), "promptforge-internal/live", "", &live);
let test_items = RETIRED_SEEDS
.iter()
.map(|seed| format!(" struct {seed};\n"))
.collect::<Vec<_>>()
.concat();
let test_only = format!(
"pub struct Live;\n// {}\n#[cfg(test)]\nmod tests {{\n{test_items}}}\n",
RETIRED_SEEDS.join(" "),
);
write_crate(root.path(), "promptforge-internal/quiet", "", &test_only);
let violations = retired_symbol_violations(root.path());
let mut symbols: Vec<&str> = violations
.iter()
.map(|v| {
RETIRED_SEEDS
.iter()
.copied()
.find(|seed| v.contains(&format!("retired symbol {seed} ")))
.expect("a violation names a seed")
})
.collect();
symbols.sort_unstable();
let mut expected = RETIRED_SEEDS.to_vec();
expected.sort_unstable();
assert_eq!(symbols, expected, "{violations:?}");
assert!(
violations.iter().all(|v| !v.contains("quiet")),
"the crate whose seeds sit in a comment and a cfg(test) module is clean: {violations:?}"
);
}

#[test]
fn a_forbidden_dependency_in_a_container_crate_fails_the_guard() {
let root = clean_engine_root();
Expand Down
62 changes: 5 additions & 57 deletions crates/build-xtask/src/engine_guards.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! Engine guards, live: the manifest guard and the retired-symbol scan run
//! over the Engine crates, and the `test-support` leak guard runs over the
//! whole workspace, as part of `cargo test -p build-xtask` and
//! `cargo xtask tidy`.
//! Engine guards, live: the manifest guard runs over the Engine crates,
//! and the `test-support` leak guard runs over the whole workspace, as
//! part of `cargo test -p build-xtask` and `cargo xtask tidy`.
//!
//! The Engine is the `promptforge` facade, the `promptforge-plugin`
//! contract, and every crate under the `crates/promptforge-internal/`
Expand All @@ -18,44 +17,6 @@ const ENGINE_ROOT_CRATES: [&str; 2] = ["promptforge", "promptforge-plugin"];
/// The private container whose every member is an Engine crate.
pub(crate) const ENGINE_CONTAINER: &str = "promptforge-internal";

/// The seed list for the retired-symbol scan. Live Engine source (outside
/// `#[cfg(test)]`, `tests/`, and test-support modules) may not name any
/// identifier on it.
const RETIRED_SEEDS: [&str; 32] = [
"install_agent_chat_shim",
"EventsSnapshot",
"install_runtime_events",
"GatewaySource",
"run_models_loop",
"LuaFanoutResult",
"Observer",
"DebugCapture",
"HostBackend",
"HostAccess",
"HostRoot",
"identity_to_host",
"inject_host",
"inject_host_with_var",
"install_host_apis",
"host_injected",
"HostGlobal",
"replay_shared",
"section_vm_with_shared",
"LuaSharedLoadStarted",
"LuaSharedLoadSucceeded",
"LuaSharedLoadFailed",
"LUA_SHARED_LOAD_STARTED",
"LUA_SHARED_LOAD_SUCCEEDED",
"LUA_SHARED_LOAD_FAILED",
"install_always_offer",
"description_overrides",
"model_description",
"ToolView",
"lock_tool_set",
"tool_set_snapshot",
"Environment",
];

/// Every Engine crate directory: the named root crates first, whether or
/// not they exist, then every crate under the container in directory
/// order.
Expand Down Expand Up @@ -100,24 +61,11 @@ fn engine_manifest_violations(root: &Path) -> Vec<String> {
.collect()
}

/// Runs the retired-symbol scan over every Engine crate's live source. The
/// scan takes the whole crate directory, so `build.rs`, `benches/`, and
/// `examples/` are covered too; it skips `tests/` and test support itself.
#[must_use]
fn retired_symbol_violations(root: &Path) -> Vec<String> {
engine_crates(root)
.iter()
.flat_map(|dir| crate::retired_symbols::retired_symbols(dir, &RETIRED_SEEDS))
.map(|hit| hit.to_string())
.collect()
}

/// Every Engine guard, in one list: the manifest guard, the retired-symbol
/// scan, and the workspace-wide `test-support` leak guard.
/// Every Engine guard, in one list: the manifest guard and the
/// workspace-wide `test-support` leak guard.
#[must_use]
pub(crate) fn engine_guard_violations(root: &Path) -> Vec<String> {
let mut violations = engine_manifest_violations(root);
violations.extend(retired_symbol_violations(root));
violations.extend(crate::test_support_leak::test_support_leak_violations(root));
violations
}
Expand Down
1 change: 0 additions & 1 deletion crates/build-xtask/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ mod manifest;
mod new_crate;
mod no_doctests;
mod product;
mod retired_symbols;
mod site;
mod test_support_leak;
mod tidy;
Expand Down
23 changes: 1 addition & 22 deletions crates/build-xtask/src/product/plugin_tests.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
//! Plugin-family fixtures: a `plugin-*` crate depends only on
//! `promptforge-plugin`, `shared-*` crates, and outside libraries; Engine,
//! Gateway, and Harness crates may not depend on a Plugin crate, except
//! `harness-gateway-client`; and the web Plugin is no longer a public
//! Harness crate.
//! `harness-gateway-client`.

use super::product_boundary_violations;
use super::test_support::write_crate;
Expand Down Expand Up @@ -101,23 +100,3 @@ fn the_harness_gateway_client_and_workshop_crates_may_name_a_plugin_crate() {
assert!(violations.is_empty(), "{package}: {violations:?}");
}
}

#[test]
fn harness_web_is_no_longer_a_public_harness_crate() {
let root = tempfile::TempDir::new().expect("tempdir");
write_crate(
root.path(),
"workshop/server",
"workshop-server",
"[dependencies]\nharness-web = { path = \"../../harness-web\" }\n",
);
write_crate(root.path(), "harness-web", "harness-web", "");
let violations = product_boundary_violations(root.path());
assert_eq!(violations.len(), 1, "{violations:?}");
assert!(
violations[0].ends_with(
"outside crates may depend on the harness family only through harness or harness-gateway-client"
),
"{violations:?}"
);
}
Loading
Loading