Skip to content

Commit 7a3578e

Browse files
author
grysz
committed
test(cli): publish report schemas and goldens
1 parent 45dc2f8 commit 7a3578e

16 files changed

Lines changed: 959 additions & 30 deletions

.github/workflows/release.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ jobs:
6666
}
6767
6868
rm -rf "${package_dir}" dist
69-
mkdir -p "${package_dir}/bin" "${package_dir}/packages" "${package_dir}/docs" dist
69+
mkdir -p "${package_dir}/bin" "${package_dir}/packages" "${package_dir}/docs/schemas" "${package_dir}/goldens/cli" dist
7070
7171
cp "target/release/${{ matrix.binary }}" "${binary_path}"
7272
@@ -83,8 +83,11 @@ jobs:
8383
--tx-bytes 400
8484
8585
cp docs/KERNEL_PACKAGE_SCHEMA.md "${package_dir}/docs/KERNEL_PACKAGE_SCHEMA.md"
86+
cp docs/CLI_REPORT_SCHEMAS.md "${package_dir}/docs/CLI_REPORT_SCHEMAS.md"
87+
cp docs/schemas/*.schema.json "${package_dir}/docs/schemas/"
8688
cp docs/PROJECT_STATUS.md "${package_dir}/docs/PROJECT_STATUS.md"
8789
cp docs/RUSTY_KASPA_UPSTREAM_WATCH.md "${package_dir}/docs/RUSTY_KASPA_UPSTREAM_WATCH.md"
90+
cp tests/golden/cli/*.json "${package_dir}/goldens/cli/"
8891
8992
cat > "${package_dir}/RELEASE_NOTES.md" <<EOF
9093
# KaspaScript ${version}
@@ -98,6 +101,7 @@ jobs:
98101
- kaspascript CLI for ${{ matrix.label }}
99102
- verified TN12 kernel packages for escrow.ks and vault.ks
100103
- Kernel Package v0 schema reference
104+
- CLI report JSON Schemas and golden snapshots
101105
- project status and Rusty Kaspa upstream watch docs
102106
- smoke verification output
103107
- SHA-256 checksums
@@ -169,6 +173,7 @@ jobs:
169173
- \`kaspascript\` CLI binary
170174
- verified TN12 kernel packages for \`escrow.ks\` and \`vault.ks\`
171175
- Kernel Package v0 schema reference
176+
- CLI report JSON Schemas and golden snapshots
172177
- project status and Rusty Kaspa upstream watch docs
173178
- smoke verification output
174179
- internal \`SHA256SUMS.txt\`

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,11 @@ Every report-style command also supports `--json` for agents and CI:
266266
$ kaspascript doctor escrow.ks --target future-mainnet --json
267267
```
268268

269+
The report payloads are versioned contracts. JSON Schemas live in
270+
[`docs/schemas`](docs/schemas), and golden report snapshots live in
271+
[`tests/golden/cli`](tests/golden/cli). Start with
272+
[`docs/CLI_REPORT_SCHEMAS.md`](docs/CLI_REPORT_SCHEMAS.md).
273+
269274
```console
270275
$ kaspascript verify escrow.artifact.json
271276
backend: kaspa-txscript

cli/src/main.rs

Lines changed: 162 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -149,19 +149,7 @@ fn kernel_check_command(args: &[String]) -> Result<()> {
149149

150150
match options.format {
151151
OutputFormat::Json => {
152-
let report = json!({
153-
"schema_version": "kaspascript.cli.kernel.check.v0",
154-
"contract": package.kernel.readiness.contract,
155-
"target": package.package_target,
156-
"artifact": &package.artifact,
157-
"readiness": &package.kernel.readiness,
158-
"capabilities": &package.kernel.capabilities,
159-
"fee_estimate": &package.fee_estimate,
160-
"next_commands": [
161-
format!("kaspascript kernel preview {path} --target {}", package.package_target),
162-
format!("kaspascript kernel package {path} --target {} --compute-grams {} --tx-bytes {}", package.package_target, package.fee_estimate.compute_grams, package.fee_estimate.transaction_bytes)
163-
]
164-
});
152+
let report = kernel_check_report(path, &package);
165153
println!("{}", serde_json::to_string_pretty(&report)?);
166154
}
167155
OutputFormat::Human => print_kernel_check_human(path, &package),
@@ -195,12 +183,7 @@ fn kernel_preview_command(args: &[String]) -> Result<()> {
195183

196184
match options.format {
197185
OutputFormat::Json => {
198-
let report = json!({
199-
"schema_version": "kaspascript.cli.kernel.preview.v0",
200-
"contract": package.kernel.readiness.contract,
201-
"target": package.package_target,
202-
"previews": previews,
203-
});
186+
let report = kernel_preview_report(&package, &previews);
204187
println!("{}", serde_json::to_string_pretty(&report)?);
205188
}
206189
OutputFormat::Human => print_kernel_preview_human(&package, &previews),
@@ -276,10 +259,7 @@ fn toccata_targets_command(args: &[String]) -> Result<()> {
276259
let targets = target_matrix();
277260
match format {
278261
OutputFormat::Json => {
279-
let report = json!({
280-
"schema_version": "kaspascript.cli.toccata.targets.v0",
281-
"targets": targets,
282-
});
262+
let report = toccata_targets_report(targets);
283263
println!("{}", serde_json::to_string_pretty(&report)?);
284264
}
285265
OutputFormat::Human => print_target_matrix_human(&targets),
@@ -299,11 +279,7 @@ fn toccata_fee_command(args: &[String]) -> Result<()> {
299279

300280
match options.format {
301281
OutputFormat::Json => {
302-
let report = json!({
303-
"schema_version": "kaspascript.cli.toccata.fee.v0",
304-
"fee_estimate": estimate,
305-
"formula": "max(compute_grams, tx_bytes * 2) * 100 sompi",
306-
});
282+
let report = toccata_fee_report(&estimate);
307283
println!("{}", serde_json::to_string_pretty(&report)?);
308284
}
309285
OutputFormat::Human => {
@@ -593,6 +569,49 @@ fn parse_u64_option(option: &str, value: &str) -> Result<u64> {
593569
.with_context(|| format!("{option} must be a non-negative integer"))
594570
}
595571

572+
fn kernel_check_report(path: &str, package: &CompiledKernelPackage) -> Value {
573+
json!({
574+
"schema_version": "kaspascript.cli.kernel.check.v0",
575+
"contract": package.kernel.readiness.contract,
576+
"target": package.package_target,
577+
"artifact": &package.artifact,
578+
"readiness": &package.kernel.readiness,
579+
"capabilities": &package.kernel.capabilities,
580+
"fee_estimate": &package.fee_estimate,
581+
"next_commands": [
582+
format!("kaspascript kernel preview {path} --target {}", package.package_target),
583+
format!("kaspascript kernel package {path} --target {} --compute-grams {} --tx-bytes {}", package.package_target, package.fee_estimate.compute_grams, package.fee_estimate.transaction_bytes)
584+
]
585+
})
586+
}
587+
588+
fn kernel_preview_report(
589+
package: &CompiledKernelPackage,
590+
previews: &[&kaspascript_kernel::WalletPreview],
591+
) -> Value {
592+
json!({
593+
"schema_version": "kaspascript.cli.kernel.preview.v0",
594+
"contract": package.kernel.readiness.contract,
595+
"target": package.package_target,
596+
"previews": previews,
597+
})
598+
}
599+
600+
fn toccata_targets_report(targets: Vec<Value>) -> Value {
601+
json!({
602+
"schema_version": "kaspascript.cli.toccata.targets.v0",
603+
"targets": targets,
604+
})
605+
}
606+
607+
fn toccata_fee_report(estimate: &kaspascript_kernel::FeeEstimate) -> Value {
608+
json!({
609+
"schema_version": "kaspascript.cli.toccata.fee.v0",
610+
"fee_estimate": estimate,
611+
"formula": "max(compute_grams, tx_bytes * 2) * 100 sompi",
612+
})
613+
}
614+
596615
fn toccata_status_report() -> Value {
597616
json!({
598617
"schema_version": "kaspascript.cli.toccata.status.v0",
@@ -1256,6 +1275,34 @@ mod tests {
12561275
),
12571276
];
12581277

1278+
const CLI_REPORT_SCHEMAS: &[(&str, &str, &str)] = &[
1279+
(
1280+
"kaspascript.cli.toccata.status.v0",
1281+
include_str!("../../docs/schemas/kaspascript.cli.toccata.status.v0.schema.json"),
1282+
include_str!("../../tests/golden/cli/toccata.status.json"),
1283+
),
1284+
(
1285+
"kaspascript.cli.toccata.targets.v0",
1286+
include_str!("../../docs/schemas/kaspascript.cli.toccata.targets.v0.schema.json"),
1287+
include_str!("../../tests/golden/cli/toccata.targets.json"),
1288+
),
1289+
(
1290+
"kaspascript.cli.toccata.fee.v0",
1291+
include_str!("../../docs/schemas/kaspascript.cli.toccata.fee.v0.schema.json"),
1292+
include_str!("../../tests/golden/cli/toccata.fee.json"),
1293+
),
1294+
(
1295+
"kaspascript.cli.kernel.check.v0",
1296+
include_str!("../../docs/schemas/kaspascript.cli.kernel.check.v0.schema.json"),
1297+
include_str!("../../tests/golden/cli/kernel.check.escrow.verified-tn12.json"),
1298+
),
1299+
(
1300+
"kaspascript.cli.kernel.preview.v0",
1301+
include_str!("../../docs/schemas/kaspascript.cli.kernel.preview.v0.schema.json"),
1302+
include_str!("../../tests/golden/cli/kernel.preview.escrow.release.verified-tn12.json"),
1303+
),
1304+
];
1305+
12591306
#[test]
12601307
fn kernel_package_command_writes_combined_artifact() {
12611308
let dir =
@@ -1443,6 +1490,73 @@ mod tests {
14431490
assert!(ToccataFeeOptions::parse(&["--tx-bytes".to_owned(), "400".to_owned()]).is_err());
14441491
}
14451492

1493+
#[test]
1494+
fn cli_report_schema_files_are_valid_json() {
1495+
for (schema_version, schema, golden) in CLI_REPORT_SCHEMAS {
1496+
let schema_json: Value = serde_json::from_str(schema).expect("schema json");
1497+
let golden_json: Value = serde_json::from_str(golden).expect("golden json");
1498+
1499+
assert_eq!(
1500+
schema_json["properties"]["schema_version"]["const"],
1501+
Value::String((*schema_version).to_owned()),
1502+
"{schema_version}"
1503+
);
1504+
assert_eq!(
1505+
golden_json["schema_version"],
1506+
Value::String((*schema_version).to_owned()),
1507+
"{schema_version}"
1508+
);
1509+
assert_eq!(
1510+
schema_json["$schema"],
1511+
Value::String("https://json-schema.org/draft/2020-12/schema".to_owned()),
1512+
"{schema_version}"
1513+
);
1514+
}
1515+
}
1516+
1517+
#[test]
1518+
fn cli_report_golden_snapshots_match() {
1519+
assert_report_snapshot(
1520+
"toccata.status",
1521+
toccata_status_report(),
1522+
include_str!("../../tests/golden/cli/toccata.status.json"),
1523+
);
1524+
1525+
assert_report_snapshot(
1526+
"toccata.targets",
1527+
toccata_targets_report(target_matrix()),
1528+
include_str!("../../tests/golden/cli/toccata.targets.json"),
1529+
);
1530+
1531+
let fee = ToccataFeePolicy::default()
1532+
.estimate(1000, 400, "caller-provided Toccata fee estimate inputs")
1533+
.expect("fee estimate");
1534+
assert_report_snapshot(
1535+
"toccata.fee",
1536+
toccata_fee_report(&fee),
1537+
include_str!("../../tests/golden/cli/toccata.fee.json"),
1538+
);
1539+
1540+
let package = escrow_kernel_package();
1541+
assert_report_snapshot(
1542+
"kernel.check.escrow.verified-tn12",
1543+
kernel_check_report("tests/contracts/escrow.ks", &package),
1544+
include_str!("../../tests/golden/cli/kernel.check.escrow.verified-tn12.json"),
1545+
);
1546+
1547+
let previews = package
1548+
.kernel
1549+
.wallet_previews
1550+
.iter()
1551+
.filter(|preview| preview.transition == "release")
1552+
.collect::<Vec<_>>();
1553+
assert_report_snapshot(
1554+
"kernel.preview.escrow.release.verified-tn12",
1555+
kernel_preview_report(&package, &previews),
1556+
include_str!("../../tests/golden/cli/kernel.preview.escrow.release.verified-tn12.json"),
1557+
);
1558+
}
1559+
14461560
#[test]
14471561
fn kernel_package_golden_snapshots_match() {
14481562
for (source_path, source, golden) in KERNEL_GOLDENS {
@@ -1496,4 +1610,24 @@ mod tests {
14961610
);
14971611
assert!(!blocked_package.kernel.readiness.ready);
14981612
}
1613+
1614+
fn escrow_kernel_package() -> CompiledKernelPackage {
1615+
let options = KernelPackageOptions {
1616+
output: None,
1617+
compute_grams: 1000,
1618+
tx_bytes: Some(400),
1619+
target: Target::VerifiedTn12,
1620+
};
1621+
build_kernel_package(
1622+
"tests/contracts/escrow.ks",
1623+
include_str!("../../tests/contracts/escrow.ks"),
1624+
&options,
1625+
)
1626+
.expect("escrow package")
1627+
}
1628+
1629+
fn assert_report_snapshot(name: &str, actual: Value, golden: &str) {
1630+
let expected: Value = serde_json::from_str(golden).expect("golden json");
1631+
assert_eq!(actual, expected, "{name}");
1632+
}
14991633
}

docs/CLI_REPORT_SCHEMAS.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# CLI Report Schemas
2+
3+
KaspaScript publishes JSON Schema files and golden snapshots for the
4+
agent-facing CLI report payloads. These files are API contracts for agents, CI,
5+
wallets, SDKs, and indexers that consume `--json` output.
6+
7+
The CLI report schemas are versioned independently from the kernel package
8+
schema. A report schema version must not change shape without a new
9+
`schema_version` value.
10+
11+
## Schemas
12+
13+
| CLI command | Schema version | Schema file | Golden snapshot |
14+
| --- | --- | --- | --- |
15+
| `kaspascript toccata status --json` | `kaspascript.cli.toccata.status.v0` | [`docs/schemas/kaspascript.cli.toccata.status.v0.schema.json`](schemas/kaspascript.cli.toccata.status.v0.schema.json) | [`tests/golden/cli/toccata.status.json`](../tests/golden/cli/toccata.status.json) |
16+
| `kaspascript toccata targets --json` | `kaspascript.cli.toccata.targets.v0` | [`docs/schemas/kaspascript.cli.toccata.targets.v0.schema.json`](schemas/kaspascript.cli.toccata.targets.v0.schema.json) | [`tests/golden/cli/toccata.targets.json`](../tests/golden/cli/toccata.targets.json) |
17+
| `kaspascript toccata fee --compute-grams 1000 --tx-bytes 400 --json` | `kaspascript.cli.toccata.fee.v0` | [`docs/schemas/kaspascript.cli.toccata.fee.v0.schema.json`](schemas/kaspascript.cli.toccata.fee.v0.schema.json) | [`tests/golden/cli/toccata.fee.json`](../tests/golden/cli/toccata.fee.json) |
18+
| `kaspascript kernel check tests/contracts/escrow.ks --target verified-tn12 --compute-grams 1000 --tx-bytes 400 --json` | `kaspascript.cli.kernel.check.v0` | [`docs/schemas/kaspascript.cli.kernel.check.v0.schema.json`](schemas/kaspascript.cli.kernel.check.v0.schema.json) | [`tests/golden/cli/kernel.check.escrow.verified-tn12.json`](../tests/golden/cli/kernel.check.escrow.verified-tn12.json) |
19+
| `kaspascript kernel preview tests/contracts/escrow.ks --target verified-tn12 --transition release --json` | `kaspascript.cli.kernel.preview.v0` | [`docs/schemas/kaspascript.cli.kernel.preview.v0.schema.json`](schemas/kaspascript.cli.kernel.preview.v0.schema.json) | [`tests/golden/cli/kernel.preview.escrow.release.verified-tn12.json`](../tests/golden/cli/kernel.preview.escrow.release.verified-tn12.json) |
20+
21+
`kaspascript doctor <contract.ks> --json` is an alias for
22+
`kaspascript kernel check <contract.ks> --json` and uses
23+
`kaspascript.cli.kernel.check.v0`.
24+
25+
## Compatibility Rules
26+
27+
- `schema_version` is required in every report payload.
28+
- Existing required fields cannot be removed within the same schema version.
29+
- Existing field types cannot change within the same schema version.
30+
- New incompatible payload shapes must use a new schema version.
31+
- Golden snapshots are tested in CI against the report builders.
32+
- The report schemas are intentionally stricter at the top level than in nested
33+
kernel-owned metadata, where `kaspascript.kernel.package.v0` is the deeper
34+
contract.
35+
36+
## Local Checks
37+
38+
```bash
39+
cargo test -p kaspascript-cli cli_report_golden_snapshots_match
40+
cargo test -p kaspascript-cli cli_report_schema_files_are_valid_json
41+
```

docs/PROJECT_STATUS.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ CLI:
3232
[--transition <name>] [--json]`
3333
- `kaspascript toccata status|targets|fee [--json]`
3434
- `kaspascript doctor <contract.ks> --target <target> [--json]`
35+
- JSON Schemas in `docs/schemas` and golden report payloads in
36+
`tests/golden/cli` for the agent-facing report surfaces.
3537

3638
Kernel:
3739

@@ -74,7 +76,6 @@ Testnet readiness:
7476

7577
The current milestone is close to alpha complete. It needs:
7678

77-
- JSON-schema publication for the agent-facing CLI report payloads.
7879
- CI running `cargo fmt --check`, `cargo clippy`, and workspace tests.
7980

8081
### Testnet Complete
@@ -143,3 +144,10 @@ cargo run -p kaspascript-cli -- doctor tests/contracts/escrow.ks \
143144
--target future-mainnet \
144145
--json
145146
```
147+
148+
Check the CLI report contracts:
149+
150+
```bash
151+
cargo test -p kaspascript-cli cli_report_golden_snapshots_match
152+
cargo test -p kaspascript-cli cli_report_schema_files_are_valid_json
153+
```

docs/index.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,12 @@ <h2 id="quickstart-title">Compile, inspect, verify, package.</h2>
345345
--compute-grams 1000 \
346346
--tx-bytes 400</code></pre>
347347
</div>
348+
<p class="doc-link">
349+
CLI report schemas:
350+
<a href="https://github.com/gryszzz/Kaspa-Script/blob/main/docs/CLI_REPORT_SCHEMAS.md">
351+
docs/CLI_REPORT_SCHEMAS.md
352+
</a>
353+
</p>
348354
</section>
349355

350356
<section class="band" id="upstream" aria-labelledby="upstream-title">

0 commit comments

Comments
 (0)