@o-lang/resolver-tests 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/certify.yml +88 -0
- package/R-001-allowlist/README.md +21 -0
- package/R-001-allowlist/test.json +55 -0
- package/R-001-allowlist/workflow.ol +7 -0
- package/R-002-io-contract/README.md +26 -0
- package/R-002-io-contract/test.json +76 -0
- package/R-002-io-contract/workflow.ol +13 -0
- package/R-003-failure-modes/README +27 -0
- package/R-003-failure-modes/test.json +84 -0
- package/R-003-failure-modes/workflow.ol +13 -0
- package/R-004-invalid-syntax/README.md +5 -0
- package/R-004-invalid-syntax/test.json +57 -0
- package/R-004-invalid-syntax/workflow.ol +16 -0
- package/R-005-resolver-metadata-contract/README.md +5 -0
- package/R-005-resolver-metadata-contract/resolver.js +16 -0
- package/R-005-resolver-metadata-contract/test.json +60 -0
- package/README.md +46 -0
- package/badges/certified.svg +18 -0
- package/lib/O--Lang v1-Conformant-success.svg +1 -0
- package/lib/badge.js +27 -0
- package/lib/runner.js +337 -0
- package/package.json +29 -0
- package/reference-resolver/index.js +10 -0
- package/run-kernel.js +122 -0
- package/run.js +134 -0
- package/schema/conformance.schema.json +31 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
name: O-Lang Resolver Certification
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
certify:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write # 👈 Required to allow git push back to the repo
|
|
13
|
+
|
|
14
|
+
outputs:
|
|
15
|
+
status: ${{ steps.set-status.outputs.status }}
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
# 1️⃣ Checkout repository
|
|
19
|
+
- name: Checkout repository
|
|
20
|
+
uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
# 2️⃣ Setup Node.js
|
|
23
|
+
- name: Setup Node.js
|
|
24
|
+
uses: actions/setup-node@v4
|
|
25
|
+
with:
|
|
26
|
+
node-version: 18
|
|
27
|
+
|
|
28
|
+
# 3️⃣ Install dependencies
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: npm install
|
|
31
|
+
|
|
32
|
+
# 4️⃣ Run resolver tests
|
|
33
|
+
- name: Run resolver tests
|
|
34
|
+
id: run-tests
|
|
35
|
+
run: |
|
|
36
|
+
set -e
|
|
37
|
+
npm test || echo "failed" > result.txt
|
|
38
|
+
|
|
39
|
+
# 5️⃣ Set job status
|
|
40
|
+
- name: Set status output
|
|
41
|
+
id: set-status
|
|
42
|
+
run: |
|
|
43
|
+
if [ -f result.txt ]; then
|
|
44
|
+
echo "status=failed" >> $GITHUB_OUTPUT
|
|
45
|
+
else
|
|
46
|
+
echo "status=passed" >> $GITHUB_OUTPUT
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# 6️⃣ Generate SVG badge
|
|
50
|
+
- name: Generate badge
|
|
51
|
+
run: |
|
|
52
|
+
mkdir -p badges
|
|
53
|
+
STATUS="${{ steps.set-status.outputs.status }}"
|
|
54
|
+
if [ "$STATUS" = "passed" ]; then
|
|
55
|
+
COLOR="brightgreen"
|
|
56
|
+
MESSAGE="pass"
|
|
57
|
+
else
|
|
58
|
+
COLOR="red"
|
|
59
|
+
MESSAGE="fail"
|
|
60
|
+
fi
|
|
61
|
+
echo "<svg xmlns='http://www.w3.org/2000/svg' width='120' height='20'>
|
|
62
|
+
<linearGradient id='b' x2='0' y2='100%'>
|
|
63
|
+
<stop offset='0' stop-color='#bbb' stop-opacity='.1'/>
|
|
64
|
+
<stop offset='1' stop-opacity='.1'/>
|
|
65
|
+
</linearGradient>
|
|
66
|
+
<mask id='a'>
|
|
67
|
+
<rect width='120' height='20' rx='3' fill='#fff'/>
|
|
68
|
+
</mask>
|
|
69
|
+
<g mask='url(#a)'>
|
|
70
|
+
<rect width='70' height='20' fill='#555'/>
|
|
71
|
+
<rect x='70' width='50' height='20' fill='$COLOR'/>
|
|
72
|
+
<rect width='120' height='20' fill='url(#b)'/>
|
|
73
|
+
</g>
|
|
74
|
+
<g fill='#fff' text-anchor='middle' font-family='Verdana' font-size='11'>
|
|
75
|
+
<text x='35' y='14'>Certified</text>
|
|
76
|
+
<text x='95' y='14'>$MESSAGE</text>
|
|
77
|
+
</g>
|
|
78
|
+
</svg>" > badges/certified.svg
|
|
79
|
+
|
|
80
|
+
# 7️⃣ Commit and push badge back to repo
|
|
81
|
+
- name: Commit and push badge
|
|
82
|
+
if: always()
|
|
83
|
+
run: |
|
|
84
|
+
git config --global user.name "O-Lang CI"
|
|
85
|
+
git config --global user.email "ci@olang.org"
|
|
86
|
+
git add badges/certified.svg
|
|
87
|
+
git commit -m "Update resolver certification badge [skip ci]" || echo "No changes to commit"
|
|
88
|
+
git push
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# R-001 Allowlist Resolver Test
|
|
2
|
+
|
|
3
|
+
**Purpose:**
|
|
4
|
+
This test verifies that the O-Lang parser correctly captures and normalizes the list of allowed resolvers declared in a workflow.
|
|
5
|
+
|
|
6
|
+
**Workflow:**
|
|
7
|
+
- Workflow Name: `TestResolverAllowlist`
|
|
8
|
+
- Allowed Resolvers:
|
|
9
|
+
- `SimpleResolver`
|
|
10
|
+
- `AdvancedResolver`
|
|
11
|
+
|
|
12
|
+
**Assertions:**
|
|
13
|
+
1. All allowed resolvers are captured correctly.
|
|
14
|
+
2. Resolver names are normalized (no spaces, invalid characters).
|
|
15
|
+
3. Workflow name is correctly parsed.
|
|
16
|
+
4. No parser warnings are generated for valid syntax.
|
|
17
|
+
|
|
18
|
+
**Spec References:**
|
|
19
|
+
- §4.2 Allowed Resolvers
|
|
20
|
+
- §3.1 Workflow Parsing
|
|
21
|
+
- §2.3 Symbol Normalization
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"test_id": "R-001-allowlist",
|
|
3
|
+
"protocol_version": "1.1",
|
|
4
|
+
"category": "resolver",
|
|
5
|
+
"description": "Tests that the parser correctly captures and normalizes allowed resolvers.",
|
|
6
|
+
"spec_ref": [
|
|
7
|
+
"§4.2 Allowed Resolvers",
|
|
8
|
+
"§3.1 Workflow Parsing",
|
|
9
|
+
"§2.3 Symbol Normalization"
|
|
10
|
+
],
|
|
11
|
+
"fixtures": {
|
|
12
|
+
"inputs": [
|
|
13
|
+
{
|
|
14
|
+
"workflow": "R-001-allowlist/workflow.ol",
|
|
15
|
+
"values": {}
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"assertions": [
|
|
20
|
+
{
|
|
21
|
+
"id": "allowed_resolvers_listed",
|
|
22
|
+
"type": "allowed_resolvers_listed",
|
|
23
|
+
"expected": ["SimpleResolver", "AdvancedResolver"],
|
|
24
|
+
"severity": "fatal",
|
|
25
|
+
"description": "Parser must capture all allowed resolvers"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "resolver_names_normalized",
|
|
29
|
+
"type": "resolver_names_normalized",
|
|
30
|
+
"severity": "fatal",
|
|
31
|
+
"description": "All resolver names must conform to symbol normalization rules (start with letter, alphanumeric only)"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "workflow_name_present",
|
|
35
|
+
"type": "workflow_name_present",
|
|
36
|
+
"expected": "TestResolverAllowlist",
|
|
37
|
+
"severity": "fatal",
|
|
38
|
+
"description": "Workflow name must be parsed correctly"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": "workflow_return_values_empty",
|
|
42
|
+
"type": "workflow_return_values_empty",
|
|
43
|
+
"expected": [],
|
|
44
|
+
"severity": "fatal",
|
|
45
|
+
"description": "Return values must be empty as per workflow"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"id": "no_parse_warnings",
|
|
49
|
+
"type": "no_parse_warnings",
|
|
50
|
+
"expected": 0,
|
|
51
|
+
"severity": "warning",
|
|
52
|
+
"description": "No warnings should be issued for valid syntax"
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# R-002 IO Contract Resolver Test
|
|
2
|
+
|
|
3
|
+
**Purpose:**
|
|
4
|
+
This test validates that resolver input/output contracts are correctly recognized, including the proper handling of `Ask` and `Use` steps, and that `saveAs` values are normalized.
|
|
5
|
+
|
|
6
|
+
**Workflow:**
|
|
7
|
+
- Workflow Name: `TestResolverIOContract`
|
|
8
|
+
- Parameters: `userInput`
|
|
9
|
+
- Allowed Resolvers:
|
|
10
|
+
- `Calculator`
|
|
11
|
+
- `WeatherService`
|
|
12
|
+
- Steps:
|
|
13
|
+
1. `Ask Calculator` → `saveAs: calcResult`
|
|
14
|
+
2. `Use WeatherService` → `saveAs: weatherInfo`
|
|
15
|
+
- Return Values: `calcResult, weatherInfo`
|
|
16
|
+
|
|
17
|
+
**Assertions:**
|
|
18
|
+
1. Step 1 is parsed as an `ask` step with normalized `saveAs`.
|
|
19
|
+
2. Step 2 is parsed as a `use` step with normalized `saveAs`.
|
|
20
|
+
3. Return statement lists all resolver outputs.
|
|
21
|
+
4. No parser warnings are generated.
|
|
22
|
+
|
|
23
|
+
**Spec References:**
|
|
24
|
+
- §4.3 Resolver Input/Output Contracts
|
|
25
|
+
- §3.2 Step Parsing
|
|
26
|
+
- §2.3 Symbol Normalization
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"test_id": "R-002-io-contract",
|
|
3
|
+
"protocol_version": "1.1",
|
|
4
|
+
"category": "resolver",
|
|
5
|
+
"description": "Tests that resolver I/O contracts are correctly recognized and saveAs fields are applied.",
|
|
6
|
+
"spec_ref": [
|
|
7
|
+
"§4.3 Resolver Input/Output Contracts",
|
|
8
|
+
"§3.2 Step Parsing",
|
|
9
|
+
"§2.3 Symbol Normalization"
|
|
10
|
+
],
|
|
11
|
+
"fixtures": {
|
|
12
|
+
"inputs": [
|
|
13
|
+
{
|
|
14
|
+
"workflow": "R-002-io-contract/workflow.ol",
|
|
15
|
+
"values": {
|
|
16
|
+
"userInput": "42"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"assertions": [
|
|
22
|
+
{
|
|
23
|
+
"id": "allowed_resolvers_listed",
|
|
24
|
+
"type": "allowed_resolvers_listed",
|
|
25
|
+
"expected": ["Calculator", "WeatherService"],
|
|
26
|
+
"severity": "fatal",
|
|
27
|
+
"description": "Parser must capture all allowed resolvers"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "ask_step_type",
|
|
31
|
+
"type": "step_type",
|
|
32
|
+
"stepIndex": 0,
|
|
33
|
+
"expected": "ask",
|
|
34
|
+
"severity": "fatal",
|
|
35
|
+
"description": "Step 1 must be parsed as 'ask'"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "ask_step_saveas",
|
|
39
|
+
"type": "step_saveas",
|
|
40
|
+
"stepIndex": 0,
|
|
41
|
+
"expected": "calcResult",
|
|
42
|
+
"severity": "fatal",
|
|
43
|
+
"description": "Step 1 saveAs must be 'calcResult'"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": "use_step_type",
|
|
47
|
+
"type": "step_type",
|
|
48
|
+
"stepIndex": 1,
|
|
49
|
+
"expected": "use",
|
|
50
|
+
"severity": "fatal",
|
|
51
|
+
"description": "Step 2 must be parsed as 'use'"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": "use_step_saveas",
|
|
55
|
+
"type": "step_saveas",
|
|
56
|
+
"stepIndex": 1,
|
|
57
|
+
"expected": "weatherInfo",
|
|
58
|
+
"severity": "fatal",
|
|
59
|
+
"description": "Step 2 saveAs must be 'weatherInfo'"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"id": "workflow_return_values",
|
|
63
|
+
"type": "workflow_return_values",
|
|
64
|
+
"expected": ["calcResult", "weatherInfo"],
|
|
65
|
+
"severity": "fatal",
|
|
66
|
+
"description": "Return statement must list all saved outputs"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"id": "no_parse_warnings",
|
|
70
|
+
"type": "no_parse_warnings",
|
|
71
|
+
"expected": 0,
|
|
72
|
+
"severity": "warning",
|
|
73
|
+
"description": "No warnings for valid I/O contracts"
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# R-003 Failure Modes Resolver Test
|
|
2
|
+
|
|
3
|
+
**Purpose:**
|
|
4
|
+
This test validates that resolver failures, missing resolvers, and runtime errors are correctly handled and surfaced by the parser/runtime.
|
|
5
|
+
|
|
6
|
+
**Workflow:**
|
|
7
|
+
- Workflow Name: `TestResolverFailureModes`
|
|
8
|
+
- Parameters: `userInput`
|
|
9
|
+
- Allowed Resolvers:
|
|
10
|
+
- `ReliableResolver`
|
|
11
|
+
- `UnstableResolver`
|
|
12
|
+
- Steps:
|
|
13
|
+
1. `Ask ReliableResolver` → `saveAs: reliableResult`
|
|
14
|
+
2. `Ask UnstableResolver` → `saveAs: unstableResult`
|
|
15
|
+
- Return Values: `reliableResult, unstableResult`
|
|
16
|
+
|
|
17
|
+
**Assertions:**
|
|
18
|
+
1. Steps 1 & 2 are correctly parsed as `ask` resolver steps.
|
|
19
|
+
2. `saveAs` values are normalized.
|
|
20
|
+
3. Return statement lists all resolver outputs.
|
|
21
|
+
4. Errors from failing resolvers (e.g., `UnstableResolver`) are surfaced.
|
|
22
|
+
5. Missing resolvers (e.g., `MissingResolver`) trigger proper errors.
|
|
23
|
+
|
|
24
|
+
**Spec References:**
|
|
25
|
+
- §4.4 Resolver Failure Modes
|
|
26
|
+
- §3.2 Step Parsing
|
|
27
|
+
- §5.1 Error Handling
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"test_id": "R-003-failure-modes",
|
|
3
|
+
"protocol_version": "1.1",
|
|
4
|
+
"category": "resolver",
|
|
5
|
+
"description": "Tests that resolver failure modes and retry policies are parsed and exposed.",
|
|
6
|
+
"spec_ref": [
|
|
7
|
+
"§4.4 Resolver Failure Modes",
|
|
8
|
+
"§3.3 Step Parsing",
|
|
9
|
+
"§2.3 Symbol Normalization"
|
|
10
|
+
],
|
|
11
|
+
"fixtures": {
|
|
12
|
+
"inputs": [
|
|
13
|
+
{
|
|
14
|
+
"workflow": "R-003-failure-modes/workflow.ol",
|
|
15
|
+
"values": {
|
|
16
|
+
"userInput": "someInput"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"assertions": [
|
|
22
|
+
{
|
|
23
|
+
"id": "allowed_resolvers_listed",
|
|
24
|
+
"type": "allowed_resolvers_listed",
|
|
25
|
+
"expected": ["ReliableResolver", "UnstableResolver"],
|
|
26
|
+
"severity": "fatal",
|
|
27
|
+
"description": "Allowed resolvers must be captured"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "step_0_saveas",
|
|
31
|
+
"type": "step_saveas",
|
|
32
|
+
"stepIndex": 0,
|
|
33
|
+
"expected": "reliableResult",
|
|
34
|
+
"severity": "fatal",
|
|
35
|
+
"description": "Step 0 saveAs"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "step_1_saveas",
|
|
39
|
+
"type": "step_saveas",
|
|
40
|
+
"stepIndex": 1,
|
|
41
|
+
"expected": "unstableResult",
|
|
42
|
+
"severity": "fatal",
|
|
43
|
+
"description": "Step 1 saveAs"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": "workflow_name_present",
|
|
47
|
+
"type": "workflow_name_present",
|
|
48
|
+
"expected": "TestResolverFailureModes",
|
|
49
|
+
"severity": "fatal",
|
|
50
|
+
"description": "Workflow name parsed"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"id": "workflow_return_values",
|
|
54
|
+
"type": "workflow_return_values",
|
|
55
|
+
"expected": ["reliableResult", "unstableResult"],
|
|
56
|
+
"severity": "fatal",
|
|
57
|
+
"description": "Return values listed"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"id": "unstable_resolver_failure_policies",
|
|
61
|
+
"type": "step_failure_policies",
|
|
62
|
+
"stepIndex": 1,
|
|
63
|
+
"expected": {
|
|
64
|
+
"TIMEOUT": {
|
|
65
|
+
"action": "retry",
|
|
66
|
+
"count": 2
|
|
67
|
+
},
|
|
68
|
+
"NETWORK_ERROR": {
|
|
69
|
+
"action": "fail",
|
|
70
|
+
"count": 0
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"severity": "fatal",
|
|
74
|
+
"description": "Failure modes and retry counts must be parsed"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "no_parse_warnings",
|
|
78
|
+
"type": "no_parse_warnings",
|
|
79
|
+
"expected": 0,
|
|
80
|
+
"severity": "warning",
|
|
81
|
+
"description": "No warnings for valid failure mode syntax"
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Workflow "TestResolverFailureModes" with userInput
|
|
2
|
+
|
|
3
|
+
Allow resolvers:
|
|
4
|
+
- ReliableResolver
|
|
5
|
+
- UnstableResolver
|
|
6
|
+
|
|
7
|
+
Step 1: Ask ReliableResolver
|
|
8
|
+
Save as reliableResult
|
|
9
|
+
|
|
10
|
+
Step 2: Ask UnstableResolver
|
|
11
|
+
Save as unstableResult
|
|
12
|
+
|
|
13
|
+
Return reliableResult, unstableResult
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# R-005: Resolver Metadata Contract
|
|
2
|
+
|
|
3
|
+
Validates that resolver packages declare valid **inputs**, **outputs**, **resolverName**, and **failure modes**.
|
|
4
|
+
|
|
5
|
+
This test ensures that static resolver contracts (e.g., `resolver.js`) are well-formed and align with O-lang’s governance model—enabling tooling, linting, and safe composition.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"test_id": "R-004-invalid-syntax",
|
|
3
|
+
"protocol_version": "1.1",
|
|
4
|
+
"category": "resolver",
|
|
5
|
+
"description": "Tests that parser emits warnings or errors for invalid syntax.",
|
|
6
|
+
"spec_ref": [
|
|
7
|
+
"§2.3 Symbol Normalization",
|
|
8
|
+
"§3.1 Workflow Parsing",
|
|
9
|
+
"§4.2 Allowed Resolvers"
|
|
10
|
+
],
|
|
11
|
+
"fixtures": {
|
|
12
|
+
"inputs": [
|
|
13
|
+
{
|
|
14
|
+
"workflow": "R-004-invalid-syntax/workflow.ol",
|
|
15
|
+
"values": {}
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"assertions": [
|
|
20
|
+
{
|
|
21
|
+
"id": "warns_on_invalid_resolver_name",
|
|
22
|
+
"type": "contains_warning",
|
|
23
|
+
"expected_substring": "invalid resolver name",
|
|
24
|
+
"severity": "fatal",
|
|
25
|
+
"description": "Must warn about resolver name with space"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "warns_on_invalid_saveas",
|
|
29
|
+
"type": "contains_warning",
|
|
30
|
+
"expected_substring": "invalid identifier",
|
|
31
|
+
"severity": "fatal",
|
|
32
|
+
"description": "Must warn about malformed Save as"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"id": "warns_on_unrecognized_step",
|
|
36
|
+
"type": "contains_warning",
|
|
37
|
+
"expected_substring": "unrecognized step",
|
|
38
|
+
"severity": "fatal",
|
|
39
|
+
"description": "Must warn about unknown step type"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"id": "warns_on_duplicate_saveas",
|
|
43
|
+
"type": "contains_warning",
|
|
44
|
+
"expected_substring": "duplicate saveAs",
|
|
45
|
+
"severity": "fatal",
|
|
46
|
+
"description": "Must warn about duplicate Save as names"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"id": "parse_status_has_warnings",
|
|
50
|
+
"type": "status_greater_than",
|
|
51
|
+
"path": "__warnings.length",
|
|
52
|
+
"expected": 0,
|
|
53
|
+
"severity": "fatal",
|
|
54
|
+
"description": "Parser must emit at least one warning"
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// resolver.ol (treated as a JS module in test)
|
|
2
|
+
module.exports = {
|
|
3
|
+
resolverName: "RiskAssessment",
|
|
4
|
+
inputs: [
|
|
5
|
+
{ name: "transaction_id", type: "string", required: true },
|
|
6
|
+
{ name: "user_id", type: "string", required: true }
|
|
7
|
+
],
|
|
8
|
+
outputs: [
|
|
9
|
+
{ name: "risk_score", type: "number" },
|
|
10
|
+
{ name: "confidence", type: "number" }
|
|
11
|
+
],
|
|
12
|
+
failures: [
|
|
13
|
+
{ code: "DATA_UNAVAILABLE", retries: 1 },
|
|
14
|
+
{ code: "MODEL_ERROR", retries: 0 }
|
|
15
|
+
]
|
|
16
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# R-005: Resolver Metadata Contract
|
|
2
|
+
|
|
3
|
+
Validates that resolver packages declare valid **inputs**, **outputs**, **resolverName**, and **failure modes**.
|
|
4
|
+
|
|
5
|
+
This test ensures that static resolver contracts (e.g., `resolver.js`) are well-formed and align with O-lang’s governance model—enabling tooling, linting, and safe composition.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// R-005-resolver-metadata-contract/resolver.js
|
|
2
|
+
module.exports = {
|
|
3
|
+
resolverName: "RiskAssessment",
|
|
4
|
+
inputs: [
|
|
5
|
+
{ name: "transaction_id", type: "string", required: true },
|
|
6
|
+
{ name: "user_id", type: "string", required: true }
|
|
7
|
+
],
|
|
8
|
+
outputs: [
|
|
9
|
+
{ name: "risk_score", type: "number" },
|
|
10
|
+
{ name: "confidence", type: "number" }
|
|
11
|
+
],
|
|
12
|
+
failures: [
|
|
13
|
+
{ code: "DATA_UNAVAILABLE", retries: 1 },
|
|
14
|
+
{ code: "MODEL_ERROR", retries: 0 }
|
|
15
|
+
]
|
|
16
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"test_id": "R-005-resolver-metadata-contract",
|
|
3
|
+
"protocol_version": "1.1",
|
|
4
|
+
"category": "resolver",
|
|
5
|
+
"description": "Tests that resolver metadata (inputs, outputs, name) is valid and complete.",
|
|
6
|
+
"spec_ref": [
|
|
7
|
+
"§4.3 Resolver Input/Output Contracts",
|
|
8
|
+
"§4.4 Resolver Failure Modes",
|
|
9
|
+
"§2.3 Symbol Normalization"
|
|
10
|
+
],
|
|
11
|
+
"fixtures": {
|
|
12
|
+
"inputs": [
|
|
13
|
+
{
|
|
14
|
+
"resolver_contract": "R-005-resolver-metadata-contract/resolver.ol"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"assertions": [
|
|
19
|
+
{
|
|
20
|
+
"id": "resolver_has_name",
|
|
21
|
+
"type": "resolver_has_field",
|
|
22
|
+
"field": "resolverName",
|
|
23
|
+
"expected": "RiskAssessment",
|
|
24
|
+
"severity": "fatal",
|
|
25
|
+
"description": "Resolver must declare resolverName"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "resolver_inputs_valid",
|
|
29
|
+
"type": "resolver_inputs_valid",
|
|
30
|
+
"severity": "fatal",
|
|
31
|
+
"description": "Inputs must be array of {name, type, required}"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "resolver_outputs_valid",
|
|
35
|
+
"type": "resolver_outputs_valid",
|
|
36
|
+
"severity": "fatal",
|
|
37
|
+
"description": "Outputs must be array of {name, type}"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"id": "resolver_input_names_normalized",
|
|
41
|
+
"type": "field_names_normalized",
|
|
42
|
+
"field": "inputs",
|
|
43
|
+
"severity": "fatal",
|
|
44
|
+
"description": "Input names must follow symbol normalization"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "resolver_output_names_normalized",
|
|
48
|
+
"type": "field_names_normalized",
|
|
49
|
+
"field": "outputs",
|
|
50
|
+
"severity": "fatal",
|
|
51
|
+
"description": "Output names must follow symbol normalization"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": "resolver_failures_declared",
|
|
55
|
+
"type": "resolver_failures_valid",
|
|
56
|
+
"severity": "warning",
|
|
57
|
+
"description": "Failure modes should be declared for production resolvers"
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
package/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# O-Lang Resolver Test Suite
|
|
2
|
+
|
|
3
|
+
**Version:** 1.0.0
|
|
4
|
+
**Maintained by:** O-Lang Core Team
|
|
5
|
+
**Specification:** O-Lang Resolver Contract v1.x
|
|
6
|
+
**License:** MIT
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Certification Badge
|
|
11
|
+
|
|
12
|
+
[](https://medium.com/@o-lang/olang-resolver-certification-essay)
|
|
13
|
+
|
|
14
|
+
Click the badge to read the official essay on Medium explaining your resolver certification process, conformance philosophy, and project vision.
|
|
15
|
+
|
|
16
|
+
You can also link to the GitHub repo directly:
|
|
17
|
+
|
|
18
|
+
[](https://github.com/O-Lang-Central/resolver-test)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Overview
|
|
23
|
+
|
|
24
|
+
This repository provides the **official O-Lang Resolver Test Harness**, designed to validate any O-Lang resolver implementation against:
|
|
25
|
+
|
|
26
|
+
- Allowlist compliance
|
|
27
|
+
- Input/output contracts
|
|
28
|
+
- Failure modes
|
|
29
|
+
|
|
30
|
+
It mirrors the **kernel test philosophy**: deterministic, safe, and locked to a single entrypoint.
|
|
31
|
+
|
|
32
|
+
All tests are **self-contained** in folders `R-001`, `R-002`, `R-003`, etc., each containing:
|
|
33
|
+
|
|
34
|
+
- `workflow.ol` — the workflow for the test
|
|
35
|
+
- `test.json` — the assertions for this test suite
|
|
36
|
+
- `resolver.js` — for metadata (if applicable)
|
|
37
|
+
- `README.md` — notes for this suite
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Environment Setup
|
|
42
|
+
|
|
43
|
+
Set the resolver to test:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
export OLANG_RESOLVER=./path-to-your-resolver
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<svg xmlns='http://www.w3.org/2000/svg' width='120' height='20'>
|
|
2
|
+
<linearGradient id='b' x2='0' y2='100%'>
|
|
3
|
+
<stop offset='0' stop-color='#bbb' stop-opacity='.1'/>
|
|
4
|
+
<stop offset='1' stop-opacity='.1'/>
|
|
5
|
+
</linearGradient>
|
|
6
|
+
<mask id='a'>
|
|
7
|
+
<rect width='120' height='20' rx='3' fill='#fff'/>
|
|
8
|
+
</mask>
|
|
9
|
+
<g mask='url(#a)'>
|
|
10
|
+
<rect width='70' height='20' fill='#555'/>
|
|
11
|
+
<rect x='70' width='50' height='20' fill='red'/>
|
|
12
|
+
<rect width='120' height='20' fill='url(#b)'/>
|
|
13
|
+
</g>
|
|
14
|
+
<g fill='#fff' text-anchor='middle' font-family='Verdana' font-size='11'>
|
|
15
|
+
<text x='35' y='14'>Certified</text>
|
|
16
|
+
<text x='95' y='14'>fail</text>
|
|
17
|
+
</g>
|
|
18
|
+
</svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="159" height="20" role="img" aria-label="O-Lang v1: Conformant"><title>O-Lang v1: Conformant</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="159" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="84" height="20" fill="#555"/><rect x="84" width="75" height="20" fill="#4c1"/><rect width="159" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><image x="5" y="3" width="14" height="14" href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSJ3aGl0ZXNtb2tlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+R2l0SHViPC90aXRsZT48cGF0aCBkPSJNMTIgLjI5N2MtNi42MyAwLTEyIDUuMzczLTEyIDEyIDAgNS4zMDMgMy40MzggOS44IDguMjA1IDExLjM4NS42LjExMy44Mi0uMjU4LjgyLS41NzcgMC0uMjg1LS4wMS0xLjA0LS4wMTUtMi4wNC0zLjMzOC43MjQtNC4wNDItMS42MS00LjA0Mi0xLjYxQzQuNDIyIDE4LjA3IDMuNjMzIDE3LjcgMy42MzMgMTcuN2MtMS4wODctLjc0NC4wODQtLjcyOS4wODQtLjcyOSAxLjIwNS4wODQgMS44MzggMS4yMzYgMS44MzggMS4yMzYgMS4wNyAxLjgzNSAyLjgwOSAxLjMwNSAzLjQ5NS45OTguMTA4LS43NzYuNDE3LTEuMzA1Ljc2LTEuNjA1LTIuNjY1LS4zLTUuNDY2LTEuMzMyLTUuNDY2LTUuOTMgMC0xLjMxLjQ2NS0yLjM4IDEuMjM1LTMuMjItLjEzNS0uMzAzLS41NC0xLjUyMy4xMDUtMy4xNzYgMCAwIDEuMDA1LS4zMjIgMy4zIDEuMjMuOTYtLjI2NyAxLjk4LS4zOTkgMy0uNDA1IDEuMDIuMDA2IDIuMDQuMTM4IDMgLjQwNSAyLjI4LTEuNTUyIDMuMjg1LTEuMjMgMy4yODUtMS4yMy42NDUgMS42NTMuMjQgMi44NzMuMTIgMy4xNzYuNzY1Ljg0IDEuMjMgMS45MSAxLjIzIDMuMjIgMCA0LjYxLTIuODA1IDUuNjI1LTUuNDc1IDUuOTIuNDIuMzYuODEgMS4wOTYuODEgMi4yMiAwIDEuNjA2LS4wMTUgMi44OTYtLjAxNSAzLjI4NiAwIC4zMTUuMjEuNjkuODI1LjU3QzIwLjU2NSAyMi4wOTIgMjQgMTcuNTkyIDI0IDEyLjI5N2MwLTYuNjI3LTUuMzczLTEyLTEyLTEyIi8+PC9zdmc+"/><text aria-hidden="true" x="515" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="570">O-Lang v1</text><text x="515" y="140" transform="scale(.1)" fill="#fff" textLength="570">O-Lang v1</text><text aria-hidden="true" x="1205" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="650">Conformant</text><text x="1205" y="140" transform="scale(.1)" fill="#fff" textLength="650">Conformant</text></g></svg>
|