Skip to content

Commit fff21c5

Browse files
committed
Merge ws/spec-m46-integration into feat/m40-plus
2 parents 4dd3acd + ccefca8 commit fff21c5

19 files changed

Lines changed: 831 additions & 409 deletions

CHANGELOG.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,9 @@
22

33
## Unreleased
44

5-
### Added
6-
7-
- **First-class bounded TypeScript execution in M45**`spec generate`, `spec build`, `spec test`, and `spec status` now accept `--target-language typescript` for exactly `kind:function` units classified as `function.arithmetic_leaf.monotone_up.v1` with `deps: []`. Bun is the only execution prerequisite, the generated helper surface is frozen at `__spec_ts/runtime.ts`, `__spec_ts/build_entry.ts`, and `__spec_ts/local_tests.ts`, and proof writes add `target_proofs.typescript` without replacing the Rust proof surface.
8-
95
### Changed
106

11-
- **The M45 TypeScript lane stays explicitly bounded**only atom tests execute in this lane, `local_tests.expect` remains limited to direct `Decimal::new(int, scale)` equality checks against the current unit, `.test.spec` stays unsupported for `--target-language typescript`, and `spec validate` plus `spec export` do not gain `--target-language`.
7+
- **The bounded TypeScript monotone-up lane is now helper-aware in M46**eligible `kind:function` units may still declare `deps: []`, or may declare exactly one direct local helper dep when that helper classifies to `function.helper.identity_passthrough.v1` and lives in the same loaded unit set and generated tree. The lane remains Bun-only, atom-only, and additive to Rust proof; it does not widen to wrapper execution, molecule execution, multi-dep execution, seam kinds, cross-library TypeScript resolution, `spec validate --target-language`, or `spec export --target-language`. Root-level TypeScript status over a mixed example remains truthfully non-green when non-eligible or unproven units are still untested in that target.
128

139
## 0.14.0 - 2026-05-07
1410

README.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,15 @@ spec validate examples/ecommerce/units
4747
spec generate examples/ecommerce/units
4848
```
4949

50-
## Bounded TypeScript lane (M45)
50+
## Bounded TypeScript lane (M46)
5151

5252
`spec` now exposes one bounded TypeScript execution lane. It is intentionally narrow:
5353

5454
- Bun is the only TypeScript prerequisite. The lane shells out to `bun`; no alternate Node, npm, or tsx contract is supported.
55-
- Eligible units are exactly `kind: function` specs that classify to `function.arithmetic_leaf.monotone_up.v1` and declare `deps: []`.
56-
- TypeScript execution is atom-only. Only `local_tests` run in this lane; `.test.spec` molecule tests remain Rust-only and are rejected for `--target-language typescript`.
55+
- Eligible units are exactly `kind: function` specs that classify to `function.arithmetic_leaf.monotone_up.v1` and declare either `deps: []` or exactly one direct local helper dep.
56+
- When one helper dep is present, it must classify to `function.helper.identity_passthrough.v1`, exist in the same loaded unit set and generated tree, and be the only direct dep of the current unit.
57+
- Rust remains the default target. TypeScript proof is additive only; it writes `target_proofs.typescript` without replacing the Rust proof surface.
58+
- TypeScript execution is atom-only. Only `local_tests` run in this lane; `.test.spec` molecule tests remain unsupported for `--target-language typescript` and fail before Bun runs.
5759
- The accepted `local_tests.expect` grammar is deliberately small: `<current_unit>(Decimal::new(int, scale), ...) == Decimal::new(int, scale)`. The left-hand side must be a direct call to the current unit, and both the arguments and expected value must use integer-literal `Decimal::new(...)` forms.
5860

5961
Commands available in this lane:
@@ -65,16 +67,19 @@ spec test <path> --target-language typescript
6567
spec status <unit-or-root> --target-language typescript
6668
```
6769

68-
The generated helper filenames are frozen in M45:
70+
`spec status <unit-or-root> --target-language typescript` reports target-specific proof only. In M46, a root-level status over a mixed example like `examples/ecommerce` may stay non-green even when the helper-aware `pricing/apply_tax` unit is freshly proven, because units outside the bounded monotone-up lane remain intentionally untested in TypeScript.
71+
72+
The generated helper filenames remain frozen in M46:
6973

7074
- `__spec_ts/runtime.ts`
7175
- `__spec_ts/build_entry.ts`
7276
- `__spec_ts/local_tests.ts`
7377

74-
Commands that do not widen for M45:
78+
Commands and surfaces that do not widen for M46:
7579

7680
- `spec validate` does not accept `--target-language`
7781
- `spec export` does not accept `--target-language`
82+
- This lane does not widen to wrapper execution, molecule execution, multi-dep execution, seam kinds, cross-library TypeScript resolution, `spec validate --target-language`, or `spec export --target-language`.
7883

7984
## Spec format
8085

examples/ecommerce/units/money/round.spec.passport.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
},
1414
"deps": [],
1515
"local_tests": [],
16-
"generated_at": "2026-05-10T18:06:38Z",
17-
"source_file": "/Users/spensermcconnell/__Active_Code/atomize-hq/.worktrees/spec-m45/integration/examples/ecommerce/units/money/round.unit.spec",
16+
"generated_at": "2026-05-10T23:07:21Z",
17+
"source_file": "/Users/spensermcconnell/__Active_Code/atomize-hq/.worktrees/spec-m46/integration/examples/ecommerce/units/money/round.unit.spec",
1818
"evidence": {
1919
"build_status": "pass",
2020
"test_results": [],
@@ -68,6 +68,10 @@
6868
{
6969
"path": "contract.returns",
7070
"summary": "returns Decimal"
71+
},
72+
{
73+
"path": "body.typescript",
74+
"summary": "authored TypeScript body present"
7175
}
7276
],
7377
"executable_surfaces": [

examples/ecommerce/units/money/round.unit.spec

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,7 @@ body:
1414
{
1515
value
1616
}
17-
17+
typescript: |
18+
{
19+
return value;
20+
}

examples/ecommerce/units/pricing/apply_discount.spec.passport.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
"expect": "apply_discount(Decimal::new(10000, 2), Decimal::new(10, 2)) == Decimal::new(9000, 2)"
2929
}
3030
],
31-
"generated_at": "2026-05-10T18:06:38Z",
32-
"source_file": "/Users/spensermcconnell/__Active_Code/atomize-hq/.worktrees/spec-m45/integration/examples/ecommerce/units/pricing/apply_discount.unit.spec",
31+
"generated_at": "2026-05-10T23:07:21Z",
32+
"source_file": "/Users/spensermcconnell/__Active_Code/atomize-hq/.worktrees/spec-m46/integration/examples/ecommerce/units/pricing/apply_discount.unit.spec",
3333
"evidence": {
3434
"build_status": "pass",
3535
"test_results": [

examples/ecommerce/units/pricing/apply_tax.spec.passport.json

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"spec_version": "0.3.0",
33
"id": "pricing/apply_tax",
4-
"intent": "Add sales tax to a subtotal using a rate expressed as a decimal fraction.",
4+
"intent": "Add sales tax to a subtotal using a rate expressed as a decimal fraction and round the total.",
55
"contract": {
66
"inputs": [
77
{
@@ -18,14 +18,16 @@
1818
"output >= subtotal"
1919
]
2020
},
21-
"deps": [],
21+
"deps": [
22+
"money/round"
23+
],
2224
"local_tests": [
2325
{
2426
"id": "basic_tax",
2527
"expect": "apply_tax(Decimal::new(10000, 2), Decimal::new(725, 4)) == Decimal::new(10725, 2)"
2628
}
2729
],
28-
"generated_at": "2026-05-10T18:20:36Z",
30+
"generated_at": "2026-05-10T23:08:46Z",
2931
"source_file": "examples/ecommerce/units/pricing/apply_tax.unit.spec",
3032
"evidence": {
3133
"build_status": "pass",
@@ -35,16 +37,16 @@
3537
"status": "pass"
3638
}
3739
],
38-
"observed_at": "2026-05-10T18:04:50Z",
40+
"observed_at": "2026-05-10T23:07:06Z",
3941
"provenance": {
40-
"git_commit_sha": "50d8a9f43c1085b5c5a2f2bc86028f812a0413cb"
42+
"git_commit_sha": "467ebd3bd1c2de1d932cddc47cca2ff08c93a1a5"
4143
}
4244
},
4345
"freshness_anchor": {
44-
"authored_truth_digest": "sha256:da0c3d9983aff0c88a432a263f93d0a7f912dd92d50dc6a74d168669a5ebdf28"
46+
"authored_truth_digest": "sha256:2c618f123ec6666dae4be1c4cc9da04022c9985cf6bfdb7b1b2071d1c0af83fe"
4547
},
4648
"freshness": {
47-
"authored_truth_digest": "sha256:da0c3d9983aff0c88a432a263f93d0a7f912dd92d50dc6a74d168669a5ebdf28",
49+
"authored_truth_digest": "sha256:2c618f123ec6666dae4be1c4cc9da04022c9985cf6bfdb7b1b2071d1c0af83fe",
4850
"authored_truth_status": "fresh",
4951
"backend_execution_status": "unknown"
5052
},
@@ -58,16 +60,16 @@
5860
"status": "pass"
5961
}
6062
],
61-
"observed_at": "2026-05-10T18:04:50Z",
63+
"observed_at": "2026-05-10T23:07:06Z",
6264
"provenance": {
63-
"git_commit_sha": "50d8a9f43c1085b5c5a2f2bc86028f812a0413cb"
65+
"git_commit_sha": "467ebd3bd1c2de1d932cddc47cca2ff08c93a1a5"
6466
}
6567
},
6668
"freshness_anchor": {
67-
"authored_truth_digest": "sha256:da0c3d9983aff0c88a432a263f93d0a7f912dd92d50dc6a74d168669a5ebdf28"
69+
"authored_truth_digest": "sha256:2c618f123ec6666dae4be1c4cc9da04022c9985cf6bfdb7b1b2071d1c0af83fe"
6870
},
6971
"freshness": {
70-
"authored_truth_digest": "sha256:da0c3d9983aff0c88a432a263f93d0a7f912dd92d50dc6a74d168669a5ebdf28",
72+
"authored_truth_digest": "sha256:2c618f123ec6666dae4be1c4cc9da04022c9985cf6bfdb7b1b2071d1c0af83fe",
7173
"authored_truth_status": "fresh",
7274
"backend_execution_status": "unknown"
7375
}
@@ -81,16 +83,16 @@
8183
"status": "pass"
8284
}
8385
],
84-
"observed_at": "2026-05-10T18:20:36Z",
86+
"observed_at": "2026-05-10T23:08:46Z",
8587
"provenance": {
86-
"git_commit_sha": "50d8a9f43c1085b5c5a2f2bc86028f812a0413cb"
88+
"git_commit_sha": "467ebd3bd1c2de1d932cddc47cca2ff08c93a1a5"
8789
}
8890
},
8991
"freshness_anchor": {
90-
"authored_truth_digest": "sha256:2895a88bccd94874e9d7e28666fbe9194862c5a71e43b1a1bdc9e2bcb855b1f8"
92+
"authored_truth_digest": "sha256:b6f56171141034c8a8455d90fca10ee1d2ca923c4a7210f1bdc939e538d8e1ac"
9193
},
9294
"freshness": {
93-
"authored_truth_digest": "sha256:2895a88bccd94874e9d7e28666fbe9194862c5a71e43b1a1bdc9e2bcb855b1f8",
95+
"authored_truth_digest": "sha256:b6f56171141034c8a8455d90fca10ee1d2ca923c4a7210f1bdc939e538d8e1ac",
9496
"authored_truth_status": "fresh",
9597
"backend_execution_status": "unknown"
9698
}
@@ -104,7 +106,7 @@
104106
"authored_surfaces": [
105107
{
106108
"path": "intent.why",
107-
"summary": "Add sales tax to a subtotal using a rate expressed as a decimal fraction."
109+
"summary": "Add sales tax to a subtotal using a rate expressed as a decimal fraction and round the total."
108110
},
109111
{
110112
"path": "contract.inputs",
@@ -118,6 +120,10 @@
118120
"path": "contract.invariants",
119121
"summary": "1 authored invariant(s)"
120122
},
123+
{
124+
"path": "deps",
125+
"summary": "1 declared dep(s)"
126+
},
121127
{
122128
"path": "body.typescript",
123129
"summary": "authored TypeScript body present"

examples/ecommerce/units/pricing/apply_tax.unit.spec

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,28 @@ id: pricing/apply_tax
22
kind: function
33
spec_version: "0.3.0"
44
intent:
5-
why: Add sales tax to a subtotal using a rate expressed as a decimal fraction.
5+
why: Add sales tax to a subtotal using a rate expressed as a decimal fraction and round the total.
66
contract:
77
inputs:
88
subtotal: Decimal
99
rate: Decimal
1010
returns: Decimal
1111
invariants:
1212
- output >= subtotal
13+
deps:
14+
- money/round
1315
imports:
1416
- rust_decimal::Decimal
1517
body:
1618
rust: |
1719
{
18-
subtotal + subtotal * rate
20+
let taxed = subtotal + subtotal * rate;
21+
round(taxed)
1922
}
2023
typescript: |
2124
{
22-
return subtotal.add(subtotal.mul(rate));
25+
const taxed = subtotal.add(subtotal.mul(rate));
26+
return round(taxed);
2327
}
2428
local_tests:
2529
- id: basic_tax

examples/ecommerce/units/pricing/checkout_quote.spec.passport.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@
100100
"expect": "CheckoutQuote::new(rust_decimal::Decimal::new(10000, 2), rust_decimal::Decimal::new(10, 2), rust_decimal::Decimal::new(725, 4)).total() == rust_decimal::Decimal::new(96525, 3)"
101101
}
102102
],
103-
"generated_at": "2026-05-10T18:06:38Z",
104-
"source_file": "/Users/spensermcconnell/__Active_Code/atomize-hq/.worktrees/spec-m45/integration/examples/ecommerce/units/pricing/checkout_quote.unit.spec",
103+
"generated_at": "2026-05-10T23:07:21Z",
104+
"source_file": "/Users/spensermcconnell/__Active_Code/atomize-hq/.worktrees/spec-m46/integration/examples/ecommerce/units/pricing/checkout_quote.unit.spec",
105105
"evidence": {
106106
"build_status": "pass",
107107
"test_results": [

examples/ecommerce/units/pricing/discount_plus_tax.test.evidence.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"money/round"
99
],
1010
"status": "pass",
11-
"observed_at": "2026-05-10T18:06:41Z",
11+
"observed_at": "2026-05-10T23:07:24Z",
1212
"test_body_hash": "sha256:ab1eb353dc1aba61a125fe7311500535bd643a7926f80d4285b458e02a369ace",
1313
"covered_unit_contract_hashes": {
1414
"money/round": "sha256:5b5fe2cf748b211051a4b6a1d213a70308302ab84c6687d5f23e54cc8003ebb8",
@@ -23,10 +23,10 @@
2323
"authored_truth_digest": "sha256:bbc4ed3407164fcb25f710e577c914f0adeff75689da95850dbe7eaab5cd422b"
2424
},
2525
"pricing/apply_tax": {
26-
"authored_truth_digest": "sha256:da0c3d9983aff0c88a432a263f93d0a7f912dd92d50dc6a74d168669a5ebdf28"
26+
"authored_truth_digest": "sha256:2c618f123ec6666dae4be1c4cc9da04022c9985cf6bfdb7b1b2071d1c0af83fe"
2727
}
2828
},
2929
"provenance": {
30-
"git_commit_sha": "50d8a9f43c1085b5c5a2f2bc86028f812a0413cb"
30+
"git_commit_sha": "467ebd3bd1c2de1d932cddc47cca2ff08c93a1a5"
3131
}
3232
}

examples/ecommerce/units/pricing/discount_policy.spec.passport.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@
143143
"expect": "DiscountPolicy::None.fixed_amount_capped_behavior_holds()"
144144
}
145145
],
146-
"generated_at": "2026-05-10T18:06:38Z",
147-
"source_file": "/Users/spensermcconnell/__Active_Code/atomize-hq/.worktrees/spec-m45/integration/examples/ecommerce/units/pricing/discount_policy.unit.spec",
146+
"generated_at": "2026-05-10T23:07:21Z",
147+
"source_file": "/Users/spensermcconnell/__Active_Code/atomize-hq/.worktrees/spec-m46/integration/examples/ecommerce/units/pricing/discount_policy.unit.spec",
148148
"evidence": {
149149
"build_status": "pass",
150150
"test_results": [

0 commit comments

Comments
 (0)