1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
//! The program capstone (spec §Eval gate): the reference export migrates into an
//! app that compiles, applies + seeds against a real database, and whose
//! `jerrycan check` reports the HONEST verdict — buildable, with the generated
//! isolation tests (cross-tenant negative controls for tenancy/REST, storage, and
//! realtime) compiled in, and RED only on the documented cron-task stub the
//! migrator leaves as agent work (#152). A dishonest "green right after migrate"
//! is what this capstone deliberately does NOT assert — a stub-handled migration
//! cannot honestly reach green. Requires Postgres (JERRYCAN_TEST_PG_URL) and the
//! jerrycan binary; never skipped in the eval/pre-publish pipelines, `#[ignore]`d
//! elsewhere.
use std::process::Command;
fn jerrycan() -> Command {
Command::new(env!("CARGO_BIN_EXE_jerrycan"))
}
#[test]
#[ignore = "capstone eval: needs postgres (JERRYCAN_TEST_PG_URL) — run with --ignored in the eval job"]
fn migrated_reference_app_checks_honest_red_only_on_the_cron_stub() {
let pg = std::env::var("JERRYCAN_TEST_PG_URL").expect("JERRYCAN_TEST_PG_URL");
let tmp = tempfile::tempdir().unwrap();
let app = tmp.path().join("acme-crm");
let fixture = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../../conformance/fixtures/supabase-export");
// 1. Migrate (offline, deterministic).
let out = jerrycan()
.args(["migrate", "--from", "supabase"])
.arg(&fixture)
.arg("--out")
.arg(&app)
.args(["--name", "acme-crm", "--bulk-threshold", "100"])
.output()
.unwrap();
assert!(
out.status.success(),
"migrate failed: {}",
String::from_utf8_lossy(&out.stderr)
);
// 2. Apply migrations + seed against a real database.
for step in [vec!["db", "migrate"], vec!["db", "seed"]] {
let out = jerrycan()
.args(&step)
.current_dir(&app)
.env("JERRYCAN_DATABASE_URL", &pg)
.output()
.unwrap();
assert!(
out.status.success(),
"{step:?} failed: {}",
String::from_utf8_lossy(&out.stderr)
);
}
// 3. The gate — assert the HONEST verdict, not a dishonest green (#152). A
// migrated app is a SCAFFOLD with documented gaps: the cron task bodies are
// agent work (a `pg_function` gap — `migrate::cronmap`), so `nightly_digest`'s
// generated jobs acceptance test fails until the agent implements the stub.
// So `jerrycan check` is honestly RED — but ONLY at the tests class, and its
// ONLY diagnostic is that one expected cron-stub test. Every EARLIER class
// (compile/clippy/audit/deny + `db migrate`/`db seed` above) is green, which
// proves the translation is buildable and correct: `check` reaches the tests
// class at all only because migration + compilation succeeded, and the
// generated cross-tenant negative controls (tenancy REST-404, storage,
// realtime scope filtering) compiled into the suite. A WRONG translation
// would fail an earlier class or add an UNEXPECTED diagnostic here, so this
// still catches it — without asserting a green that a stub-handled migration
// can never honestly reach.
// (`hourly-sync`'s `@hourly` is a non-5-field `cron_job` gap the migrator
// never emits as a job, so `nightly_digest` is the sole stub-task test.)
let out = jerrycan()
.args(["--json", "check"])
.current_dir(&app)
.env("JERRYCAN_DATABASE_URL", &pg)
.output()
.unwrap();
let payload: serde_json::Value =
serde_json::from_slice(&out.stdout).expect("`--json check` emits a JSON document");
assert_eq!(
payload["ok"], false,
"a freshly-migrated app has a stub cron task, so `check` is honestly RED — a green here would be the #152 dishonest capstone: {payload}"
);
let diags = payload["diagnostics"]
.as_array()
.expect("a red check reports a diagnostics array");
assert_eq!(
diags.len(),
1,
"the ONLY expected red is the single cron-stub jobs test; an extra diagnostic means a translation regression (an unexpected class went red): {payload}"
);
assert_eq!(
diags[0]["code"], "TEST0001",
"the expected red is a tests-class failure (TEST0001) — NOT a compile/clippy/audit/deny error, which would mean a broken translation: {payload}"
);
let msg = diags[0]["message"].as_str().unwrap_or("");
assert!(
msg.contains("nightly_digest"),
"the expected red is the `nightly_digest` cron-task stub (agent work), got: {msg}"
);
}