Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions conformance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,11 @@ version, and grow that record only by verify-then-add.
predicator or a misreading of `docs/isa.md`, and either way it gets sorted
out in review, not silently.

The `library/*` cases are the family's shared example world - a library's
loans, holds, renewals and patron standing - and its definition lives in the
statifier engine repository's `conformance/README.md`, so a new library row is
authored against that world rather than against a parallel one invented here.

## Known uncovered

### Opcodes excluded from the coverage rule
Expand Down
180 changes: 180 additions & 0 deletions conformance/cases/library.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
[
{
"id": "library/renew-allowed",
"source": "renewals < max_renewals and not holds_pending and patron.standing == \"good\"",
"context": {
"renewals": 1,
"max_renewals": 2,
"holds_pending": false,
"patron": { "id": "p-1", "standing": "good" }
},
"expected": { "result": true },
"tier": 3,
"notes": "the renewal guard of the library example world, in full: under the renewal limit, no hold waiting on the copy, and the patron in good standing. The three refusal rows below flip one conjunct each and change nothing else"
},
{
"id": "library/renew-refused-by-hold",
"source": "renewals < max_renewals and not holds_pending and patron.standing == \"good\"",
"context": {
"renewals": 1,
"max_renewals": 2,
"holds_pending": true,
"patron": { "id": "p-1", "standing": "good" }
},
"expected": { "result": false },
"tier": 3
},
{
"id": "library/renew-refused-at-max",
"source": "renewals < max_renewals and not holds_pending and patron.standing == \"good\"",
"context": {
"renewals": 2,
"max_renewals": 2,
"holds_pending": false,
"patron": { "id": "p-1", "standing": "good" }
},
"expected": { "result": false },
"tier": 3
},
{
"id": "library/renew-refused-blocked-standing",
"source": "renewals < max_renewals and not holds_pending and patron.standing == \"good\"",
"context": {
"renewals": 1,
"max_renewals": 2,
"holds_pending": false,
"patron": { "id": "p-2", "standing": "blocked" }
},
"expected": { "result": false },
"tier": 3
},
{
"id": "library/standing-good-no-fines",
"source": "patron.standing == \"good\" and fines_owed == 0",
"context": {
"patron": { "id": "p-1", "standing": "good" },
"fines_owed": 0
},
"expected": { "result": true },
"tier": 3
},
{
"id": "library/fine-owed",
"source": "patron.standing == \"good\" and fines_owed == 0",
"context": {
"patron": { "id": "p-1", "standing": "good" },
"fines_owed": 1
},
"expected": { "result": false },
"tier": 3,
"notes": "the same guard as the row above with one unpaid fine against the patron. fines_owed counts unpaid fines; the example world fixes no currency and no amount"
},
{
"id": "library/due-soon-window",
"source": "loan_period.days - 3 == 18",
"context": {
"loan_period": {
"$type": "duration",
"value": {
"years": 0,
"months": 0,
"weeks": 0,
"days": 21,
"hours": 0,
"minutes": 0,
"seconds": 0
}
}
},
"expected": { "result": true },
"tier": 3,
"notes": "hand-decode: the due-soon reminder sits three days before the end of the 21-day loan period, at 18 days from checkout. The subtraction is over the duration's days field, not over two durations: docs/isa.md section 5 gives subtract clauses for number-number, Date-Date, DateTime-DateTime and Date/DateTime-duration only, so a duration-duration subtraction is a TypeMismatchError and no window can be computed that way. A duration context value is tagged-value encoded; see conformance/README.md"
},
{
"id": "library/pickup-window",
"source": "7d",
"expected": {
"result": {
"$type": "duration",
"value": {
"years": 0,
"months": 0,
"weeks": 0,
"days": 7,
"hours": 0,
"minutes": 0,
"seconds": 0
}
}
},
"tier": 4,
"notes": "the pickup window of the example world: a hold that becomes available is held for seven days"
},
{
"id": "library/overdue-days",
"source": "overdue.days < lost_after.days",
"context": {
"overdue": {
"$type": "duration",
"value": {
"years": 0,
"months": 0,
"weeks": 0,
"days": 7,
"hours": 0,
"minutes": 0,
"seconds": 0
}
},
"lost_after": {
"$type": "duration",
"value": {
"years": 0,
"months": 0,
"weeks": 0,
"days": 28,
"hours": 0,
"minutes": 0,
"seconds": 0
}
}
},
"expected": { "result": true },
"tier": 3,
"notes": "hand-decode: a copy seven days overdue has not yet reached the 28-day point at which the example world declares it lost. The comparison reads the days field of each duration rather than comparing the two durations: docs/isa.md section 5 leaves ordering between two maps, which is what a duration is at the value level, unspecified for siblings"
},
{
"id": "library/max-renewals-boundary",
"source": "renewals < max_renewals",
"context": {
"renewals": 2,
"max_renewals": 2
},
"expected": { "result": false },
"tier": 1,
"notes": "the renewal limit is exclusive at the boundary: the second renewal is the last one allowed, and a third is refused"
},
{
"id": "library/nested-patron",
"source": "loan.patron.standing == \"good\"",
"context": {
"loan": {
"copy": "c-1",
"branch": "b-1",
"patron": { "id": "p-1", "standing": "good" }
}
},
"expected": { "result": true },
"tier": 3,
"notes": "hand-decode: two chained property reads over a nested context - the loan carries the patron, and the patron carries the standing. The keys a host supplies are strings; docs/isa.md section 5 makes a missing key undefined rather than an error"
},
{
"id": "library/holds-pending-negation",
"source": "not holds_pending",
"context": {
"holds_pending": true
},
"expected": { "result": false },
"tier": 1
}
]
2 changes: 2 additions & 0 deletions conformance/corpus/tier-1.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
{"context":{},"expected_result":true,"features":["legacy_logical","retired"],"id":"legacy/and-true-true","instructions":[["lit",true],["lit",true],["and"]],"notes":"the bare and/or opcodes (ADR-0001): retired at ISA v3 (4.0.0), so this build refuses them with a retired_opcode error, but never emitted by the compiler, which always compiles source-level and/or to jump_if_falsy_or_pop/jump_if_true_or_pop instead (see short_circuit.json). The case stays in the corpus with its expectation frozen, not recomputed, because a sibling claiming ISA v1 or v2 must still run it. Tier 1 by opcode; a v1 sibling must still run these.","source":null,"tier":1}
{"context":{},"expected_result":true,"features":["legacy_logical","retired"],"id":"legacy/or-false-true","instructions":[["lit",false],["lit",true],["or"]],"source":null,"tier":1}
{"context":{},"expected_error":{"reason":"logical_or","type":"TypeMismatchError"},"features":["errors","legacy_logical","retired"],"id":"legacy/or-rejects-non-boolean","instructions":[["lit",1],["lit",true],["or"]],"source":null,"tier":1}
{"context":{"holds_pending":true},"expected_result":false,"features":[],"id":"library/holds-pending-negation","instructions":[["load","holds_pending"],["not"]],"source":"not holds_pending","tier":1}
{"context":{"max_renewals":2,"renewals":2},"expected_result":false,"features":["comparison"],"id":"library/max-renewals-boundary","instructions":[["load","renewals"],["load","max_renewals"],["compare","LT"]],"notes":"the renewal limit is exclusive at the boundary: the second renewal is the last one allowed, and a third is refused","source":"renewals < max_renewals","tier":1}
{"context":{},"expected_result":false,"features":["short_circuit"],"id":"logical/and-short-circuit-false","instructions":[["lit",false],["jump_if_falsy_or_pop",2],["lit",true]],"source":"false and true","tier":1}
{"context":{},"expected_result":false,"features":[],"id":"logical/not-true","instructions":[["lit",true],["not"]],"source":"not true","tier":1}
{"context":{},"expected_result":true,"features":["short_circuit"],"id":"logical/or-short-circuit-true","instructions":[["lit",true],["jump_if_true_or_pop",2],["lit",false]],"source":"true or false","tier":1}
Expand Down
9 changes: 9 additions & 0 deletions conformance/corpus/tier-3.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@
{"context":{"user":{}},"expected_error":{"reason":"add","type":"TypeMismatchError"},"features":["access","arithmetic","errors"],"id":"arithmetic/add-type-mismatch","instructions":[["load","user"],["access","missing"],["lit",1],["add"]],"notes":":undefined is rejected by add, unlike compare/in/contains which propagate it","source":"user.missing + 1","tier":3}
{"context":{"user":{}},"expected_result":{"$type":"undefined"},"features":["access","comparison","undefined"],"id":"comparison/undefined-propagates-through-non-strict-compare","instructions":[["load","user"],["access","missing"],["lit",1],["compare","GT"]],"notes":"user.missing is a genuine :undefined produced by access on an absent key, not a load of an absent root (which errors under default options - see errors.json)","source":"user.missing > 1","tier":3}
{"context":{},"expected_error":{"reason":"insufficient_operands","type":"EvaluationError"},"features":["access","errors"],"id":"errors/insufficient-operands-bracket-access","instructions":[["lit",1],["bracket_access"]],"source":null,"tier":3}
{"context":{"loan_period":{"$type":"duration","value":{"days":21,"hours":0,"minutes":0,"months":0,"seconds":0,"weeks":0,"years":0}}},"expected_result":true,"features":["access","arithmetic","comparison","durations"],"id":"library/due-soon-window","instructions":[["load","loan_period"],["access","days"],["lit",3],["subtract"],["lit",18],["compare","EQ"]],"notes":"hand-decode: the due-soon reminder sits three days before the end of the 21-day loan period, at 18 days from checkout. The subtraction is over the duration's days field, not over two durations: docs/isa.md section 5 gives subtract clauses for number-number, Date-Date, DateTime-DateTime and Date/DateTime-duration only, so a duration-duration subtraction is a TypeMismatchError and no window can be computed that way. A duration context value is tagged-value encoded; see conformance/README.md","source":"loan_period.days - 3 == 18","tier":3}
{"context":{"fines_owed":1,"patron":{"id":"p-1","standing":"good"}},"expected_result":false,"features":["access","comparison","short_circuit"],"id":"library/fine-owed","instructions":[["load","patron"],["access","standing"],["lit","good"],["compare","EQ"],["jump_if_falsy_or_pop",4],["load","fines_owed"],["lit",0],["compare","EQ"]],"notes":"the same guard as the row above with one unpaid fine against the patron. fines_owed counts unpaid fines; the example world fixes no currency and no amount","source":"patron.standing == \"good\" and fines_owed == 0","tier":3}
{"context":{"loan":{"branch":"b-1","copy":"c-1","patron":{"id":"p-1","standing":"good"}}},"expected_result":true,"features":["access","comparison"],"id":"library/nested-patron","instructions":[["load","loan"],["access","patron"],["access","standing"],["lit","good"],["compare","EQ"]],"notes":"hand-decode: two chained property reads over a nested context - the loan carries the patron, and the patron carries the standing. The keys a host supplies are strings; docs/isa.md section 5 makes a missing key undefined rather than an error","source":"loan.patron.standing == \"good\"","tier":3}
{"context":{"lost_after":{"$type":"duration","value":{"days":28,"hours":0,"minutes":0,"months":0,"seconds":0,"weeks":0,"years":0}},"overdue":{"$type":"duration","value":{"days":7,"hours":0,"minutes":0,"months":0,"seconds":0,"weeks":0,"years":0}}},"expected_result":true,"features":["access","comparison","durations"],"id":"library/overdue-days","instructions":[["load","overdue"],["access","days"],["load","lost_after"],["access","days"],["compare","LT"]],"notes":"hand-decode: a copy seven days overdue has not yet reached the 28-day point at which the example world declares it lost. The comparison reads the days field of each duration rather than comparing the two durations: docs/isa.md section 5 leaves ordering between two maps, which is what a duration is at the value level, unspecified for siblings","source":"overdue.days < lost_after.days","tier":3}
{"context":{"holds_pending":false,"max_renewals":2,"patron":{"id":"p-1","standing":"good"},"renewals":1},"expected_result":true,"features":["access","comparison","short_circuit"],"id":"library/renew-allowed","instructions":[["load","renewals"],["load","max_renewals"],["compare","LT"],["jump_if_falsy_or_pop",3],["load","holds_pending"],["not"],["jump_if_falsy_or_pop",5],["load","patron"],["access","standing"],["lit","good"],["compare","EQ"]],"notes":"the renewal guard of the library example world, in full: under the renewal limit, no hold waiting on the copy, and the patron in good standing. The three refusal rows below flip one conjunct each and change nothing else","source":"renewals < max_renewals and not holds_pending and patron.standing == \"good\"","tier":3}
{"context":{"holds_pending":false,"max_renewals":2,"patron":{"id":"p-1","standing":"good"},"renewals":2},"expected_result":false,"features":["access","comparison","short_circuit"],"id":"library/renew-refused-at-max","instructions":[["load","renewals"],["load","max_renewals"],["compare","LT"],["jump_if_falsy_or_pop",3],["load","holds_pending"],["not"],["jump_if_falsy_or_pop",5],["load","patron"],["access","standing"],["lit","good"],["compare","EQ"]],"source":"renewals < max_renewals and not holds_pending and patron.standing == \"good\"","tier":3}
{"context":{"holds_pending":false,"max_renewals":2,"patron":{"id":"p-2","standing":"blocked"},"renewals":1},"expected_result":false,"features":["access","comparison","short_circuit"],"id":"library/renew-refused-blocked-standing","instructions":[["load","renewals"],["load","max_renewals"],["compare","LT"],["jump_if_falsy_or_pop",3],["load","holds_pending"],["not"],["jump_if_falsy_or_pop",5],["load","patron"],["access","standing"],["lit","good"],["compare","EQ"]],"source":"renewals < max_renewals and not holds_pending and patron.standing == \"good\"","tier":3}
{"context":{"holds_pending":true,"max_renewals":2,"patron":{"id":"p-1","standing":"good"},"renewals":1},"expected_result":false,"features":["access","comparison","short_circuit"],"id":"library/renew-refused-by-hold","instructions":[["load","renewals"],["load","max_renewals"],["compare","LT"],["jump_if_falsy_or_pop",3],["load","holds_pending"],["not"],["jump_if_falsy_or_pop",5],["load","patron"],["access","standing"],["lit","good"],["compare","EQ"]],"source":"renewals < max_renewals and not holds_pending and patron.standing == \"good\"","tier":3}
{"context":{"fines_owed":0,"patron":{"id":"p-1","standing":"good"}},"expected_result":true,"features":["access","comparison","short_circuit"],"id":"library/standing-good-no-fines","instructions":[["load","patron"],["access","standing"],["lit","good"],["compare","EQ"],["jump_if_falsy_or_pop",4],["load","fines_owed"],["lit",0],["compare","EQ"]],"source":"patron.standing == \"good\" and fines_owed == 0","tier":3}
{"context":{},"expected_result":false,"features":["membership"],"id":"membership/contains-false","instructions":[["lit",[1,2,3]],["lit",9],["contains"]],"source":"[1, 2, 3] contains 9","tier":3}
{"context":{},"expected_error":{"reason":"contains","type":"TypeMismatchError"},"features":["errors","membership"],"id":"membership/contains-left-must-be-list","instructions":[["lit","x"],["lit",1],["contains"]],"notes":"contains is the mirror of in - the left operand must be the list","source":"\"x\" contains 1","tier":3}
{"context":{},"expected_result":true,"features":["membership"],"id":"membership/contains-true","instructions":[["lit",[1,2,3]],["lit",2],["contains"]],"source":"[1, 2, 3] contains 2","tier":3}
Expand Down
1 change: 1 addition & 0 deletions conformance/corpus/tier-4.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
{"context":{},"expected_result":{"$type":"duration","value":{"days":3,"hours":0,"minutes":0,"months":0,"seconds":0,"weeks":2,"years":0}},"features":["durations"],"id":"durations/multi-unit","instructions":[["duration",[[2,"w"],[3,"d"]]]],"source":"2w3d","tier":4}
{"context":{},"expected_result":{"$type":"duration","value":{"days":3,"hours":0,"minutes":0,"months":0,"seconds":0,"weeks":0,"years":0}},"features":["durations"],"id":"durations/single-unit","instructions":[["duration",[[3,"d"]]]],"notes":"hand-decode: the duration value has eight keys, all present, defaulting to 0 - this is the normative shape from docs/isa.md section 3. The JSON omits a zero milliseconds as a compaction rule of the codec; see conformance/README.md","source":"3d","tier":4}
{"context":{},"expected_error":{"reason":"invalid_stack_value","type":"EvaluationError"},"features":["errors","objects"],"id":"errors/object-set-non-map-target","instructions":[["lit",5],["lit",1],["object_set","key"]],"notes":"docs/isa.md section 5: object_set's target must be a map. Reachable only from a hand-built instruction list - the compiler always emits object_new immediately before object_set - but specified, not undefined. Shares the invalid_stack_value reason with relative_date's non-duration case.","source":null,"tier":4}
{"context":{},"expected_result":{"$type":"duration","value":{"days":7,"hours":0,"minutes":0,"months":0,"seconds":0,"weeks":0,"years":0}},"features":["durations"],"id":"library/pickup-window","instructions":[["duration",[[7,"d"]]]],"notes":"the pickup window of the example world: a hold that becomes available is held for seven days","source":"7d","tier":4}
{"context":{},"expected_result":true,"features":["comparison","objects"],"id":"objects/equality-by-structure","instructions":[["object_new"],["lit",1],["object_set","a"],["lit",2],["object_set","b"],["object_new"],["lit",1],["object_set","a"],["lit",2],["object_set","b"],["compare","EQ"]],"notes":"docs/isa.md: EQ/NE/STRICT_EQ/STRICT_NE on two maps are well-defined and portable - only GT/LT/GTE/LTE between two maps are unspecified, and the conformance corpus does not exercise those","source":"{a: 1, b: 2} == {a: 1, b: 2}","tier":4}
{"context":{},"expected_result":{"age":30,"name":"John"},"features":["objects"],"id":"objects/literal-multi-key","instructions":[["object_new"],["lit","John"],["object_set","name"],["lit",30],["object_set","age"]],"source":"{name: \"John\", age: 30}","tier":4}
{"context":{},"expected_result":{"user":{"role":"admin"}},"features":["objects"],"id":"objects/literal-nested","instructions":[["object_new"],["object_new"],["lit","admin"],["object_set","role"],["object_set","user"]],"source":"{user: {role: \"admin\"}}","tier":4}
Expand Down
4 changes: 3 additions & 1 deletion conformance/examples/registry.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"claims": [
{"surface":"evaluator","tier":1}
],
"corpus_hash": "sha256:548f54cacdcb700df0c47d67f86a944b5dbe6b0c6f96ef0c4c6fbb95b0494892",
"corpus_hash": "sha256:bb60ec82faba2e82ef1e7abaac8d26257db2a77cd4ce0c083b683c5bc063fd43",
"entries": [
{"case_id":"comparison/eq-string-true","surface":"compiler","tier":1},
{"case_id":"comparison/gt-int-boundary","surface":"compiler","tier":1},
Expand Down Expand Up @@ -62,6 +62,8 @@
{"case_id":"legacy/and-true-true","surface":"evaluator","tier":1},
{"case_id":"legacy/or-false-true","surface":"evaluator","tier":1},
{"case_id":"legacy/or-rejects-non-boolean","surface":"evaluator","tier":1},
{"case_id":"library/holds-pending-negation","surface":"evaluator","tier":1},
{"case_id":"library/max-renewals-boundary","surface":"evaluator","tier":1},
{"case_id":"logical/and-short-circuit-false","surface":"evaluator","tier":1},
{"case_id":"logical/not-true","surface":"evaluator","tier":1},
{"case_id":"logical/or-short-circuit-true","surface":"evaluator","tier":1},
Expand Down
Loading
Loading