CI: the first full run on the branch, three fixes

- The oracle harness masks the climb to the root a /-prefixed target
  produces (<UP_TO_ROOT>/): the number of `../` is the staged tmpdir's depth
  (7 on macOS, 2 on Linux), not the verb's behavior. surface-brief-path-slash
  re-recorded.
- Two context test helpers canonicalized their temp dir, which on Windows
  yields a \\?\ verbatim path that takes `/` literally; they strip the prefix
  like Node's realpathSync. The critique-storage identity test compares
  against the platform's own resolved path.
- Every job that drives the binary end to end (live-e2e smoke and full,
  accept-cleanup, the DeepSeek sweep, the remote CLI smoke) builds it from
  the checkout first; before, they looked for a release that does not exist.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vau2X53xGTjjTCXWMVBoNY
This commit is contained in:
Paul Bakaus
2026-09-03 13:37:26 -07:00
co-authored by Claude Fable 5.1
parent 88ccc9c42b
commit c5adf55bc8
5 changed files with 77 additions and 5 deletions
+56
View File
@@ -280,6 +280,16 @@ jobs:
- name: Install dependencies
run: bun install
# The live verbs are the engine binary; build it from this checkout so the
# suite tests the branch, not the last published release.
- name: Install the pinned toolchain
run: rustup show
- uses: Swatinem/rust-cache@v2
- name: Build the engine
run: cargo build --release -p impeccable
- name: Run remote CLI E2E smoke
run: bun run test:cli-remote-e2e
@@ -335,6 +345,16 @@ jobs:
- name: Install Playwright Chromium
run: npx playwright install chromium
# The live verbs are the engine binary; build it from this checkout so the
# suite tests the branch, not the last published release.
- name: Install the pinned toolchain
run: rustup show
- uses: Swatinem/rust-cache@v2
- name: Build the engine
run: cargo build --release -p impeccable
- name: Run live E2E tests
run: bun run test:live-e2e
env:
@@ -411,6 +431,16 @@ jobs:
- name: Install Playwright Chromium
run: npx playwright install chromium
# The live verbs are the engine binary; build it from this checkout so the
# suite tests the branch, not the last published release.
- name: Install the pinned toolchain
run: rustup show
- uses: Swatinem/rust-cache@v2
- name: Build the engine
run: cargo build --release -p impeccable
- name: Run live E2E tests
run: bun run test:live-e2e
env:
@@ -483,6 +513,19 @@ jobs:
if: ${{ env.ANTHROPIC_API_KEY != '' || env.DEEPSEEK_API_KEY != '' }}
run: npx playwright install chromium
# The live verbs are the engine binary; build it from this checkout so the
# suite tests the branch, not the last published release.
- name: Install the pinned toolchain
if: ${{ env.ANTHROPIC_API_KEY != '' || env.DEEPSEEK_API_KEY != '' }}
run: rustup show
- uses: Swatinem/rust-cache@v2
if: ${{ env.ANTHROPIC_API_KEY != '' || env.DEEPSEEK_API_KEY != '' }}
- name: Build the engine
if: ${{ env.ANTHROPIC_API_KEY != '' || env.DEEPSEEK_API_KEY != '' }}
run: cargo build --release -p impeccable
- name: Run accept cleanup regression
if: ${{ env.ANTHROPIC_API_KEY != '' || env.DEEPSEEK_API_KEY != '' }}
run: |
@@ -547,6 +590,19 @@ jobs:
if: ${{ env.DEEPSEEK_API_KEY != '' }}
run: npx playwright install chromium
# The live verbs are the engine binary; build it from this checkout so the
# suite tests the branch, not the last published release.
- name: Install the pinned toolchain
if: ${{ env.DEEPSEEK_API_KEY != '' }}
run: rustup show
- uses: Swatinem/rust-cache@v2
if: ${{ env.DEEPSEEK_API_KEY != '' }}
- name: Build the engine
if: ${{ env.DEEPSEEK_API_KEY != '' }}
run: cargo build --release -p impeccable
- name: Run Svelte adapter DeepSeek sweep
if: ${{ env.DEEPSEEK_API_KEY != '' }}
run: bun run test:live-svelte-adapter-deepseek
+10 -3
View File
@@ -694,7 +694,10 @@ mod tests_660 {
std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_nanos()
));
std::fs::create_dir_all(&base).unwrap();
std::fs::canonicalize(&base).unwrap().to_string_lossy().into_owned()
// Like Node's `realpathSync`: no `\\\\?\\` verbatim prefix on Windows,
// so paths the verb joins with `/` resolve under this root.
let real = std::fs::canonicalize(&base).unwrap().to_string_lossy().into_owned();
real.strip_prefix(r"\\\\?\\").map(str::to_string).unwrap_or(real)
}
fn run_capture(cwd: &str, args: &[&str]) -> (i32, String, String) {
@@ -719,7 +722,10 @@ mod tests_660 {
#[test]
fn target_identity_file_url_and_trailing_slash() {
let cwd = "/work";
assert_eq!(resolve_target_identity("src/App.tsx", cwd), Some("file:/work/src/App.tsx".to_string()));
// The file identity is the platform's resolved path (Node `path.resolve`
// semantics through `jsp`), so it carries the host's separators.
let expected_file = format!("file:{}", jsp::resolve(cwd, &["src/App.tsx"]));
assert_eq!(resolve_target_identity("src/App.tsx", cwd), Some(expected_file));
assert_eq!(resolve_target_identity("http://example.com/pricing/", cwd), Some("url:http://example.com/pricing".to_string()));
assert_eq!(resolve_target_identity("http://example.com", cwd), Some("url:http://example.com/".to_string()));
assert_eq!(resolve_target_identity("", cwd), None);
@@ -746,7 +752,8 @@ mod tests_660 {
let dir = jsp::join(&[&cwd, ".impeccable", "critique"]);
std::fs::create_dir_all(&dir).unwrap();
let name = "2026-05-12T18-30-00Z__app-tsx.md";
let identity = format!("file:{}/App.tsx", cwd);
// Joined the way the verb resolves it, so the separators match on Windows.
let identity = format!("file:{}", jsp::join(&[&cwd, "App.tsx"]));
let body = format!("---\ntarget_identity: \"{}\"\nslug: app-tsx\n---\n# Critique\n", identity);
std::fs::write(jsp::join(&[&dir, name]), &body).unwrap();
+5 -1
View File
@@ -444,7 +444,11 @@ mod tests {
std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_nanos()
));
std::fs::create_dir_all(&base).unwrap();
std::fs::canonicalize(&base).unwrap().to_string_lossy().into_owned()
// Like Node's `realpathSync`: on Windows, `canonicalize` yields a
// `\\?\` verbatim path, which the kernel takes literally, so the `/`
// separators a hook command appends would not resolve under it.
let real = std::fs::canonicalize(&base).unwrap().to_string_lossy().into_owned();
real.strip_prefix(r"\\?\").map(str::to_string).unwrap_or(real)
}
fn write(root: &str, rel: &str, body: &str) {
@@ -1,5 +1,5 @@
{
"stdout": "../../../../../../../.impeccable/surfaces/route.md\n",
"stdout": "<UP_TO_ROOT>/.impeccable/surfaces/route.md\n",
"stderr": "",
"exit": 0,
"signal": null,
+5
View File
@@ -151,6 +151,11 @@ export function normalize(text, { ws, home = os.homedir() }) {
// (2026-05-12T18-30-00Z), both in the file name (<stamp>__<slug>.md) and in
// the `timestamp:` frontmatter it writes.
out = out.replace(/\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}Z/g, '<STAMP>');
// A target given as an absolute path outside the workspace makes the verb
// print the surface path relative to the root, which climbs as many levels
// as the staged tmpdir is deep (7 on macOS, 2 on Linux). The climb is a
// property of the machine, not of the verb.
out = out.replace(/(?:\.\.\/){2,}(?=\.impeccable\/)/g, '<UP_TO_ROOT>/');
// Hook audit entries carry wall-clock durations.
out = out.replace(/"durationMs":\s*\d+(?:\.\d+)?/g, '"durationMs": <MS>');
// ISO timestamps and epoch millis are run-dependent.