@antprofuse/saddle-skill 0.2.0 → 0.3.0-alpha.2
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/SKILL.md +45 -61
- package/agents/openai.yaml +3 -3
- package/package.json +5 -15
- package/references/consumer-start.md +64 -0
- package/references/external-function-contracts.md +84 -0
- package/references/programming-model.md +86 -0
- package/references/validation.md +38 -0
- package/scripts/saddle-03-gate.js +96 -0
- package/assets/registry-consumer/Cargo.lock +0 -1814
- package/assets/registry-consumer/Cargo.toml +0 -20
- package/assets/registry-consumer/src/generated_artifact.rs +0 -858
- package/assets/registry-consumer/src/lib.rs +0 -12
- package/assets/registry-consumer/tests/provider_consumer.rs +0 -20
- package/package-files.txt +0 -25
- package/package-manifest.json +0 -112
- package/references/api-boundary.md +0 -71
- package/references/declaration-schema.md +0 -115
- package/references/identity-closure.json +0 -49
- package/references/machine-schema.md +0 -47
- package/references/migration.md +0 -24
- package/references/public-api.snapshot +0 -16
- package/scripts/parameterized-capacity-facts.py +0 -254
- package/scripts/sync-identity-closure.py +0 -124
- package/scripts/validate-contract.sh +0 -62
- package/scripts/validate-generated-preflight.sh +0 -120
- package/scripts/validate-generated-project.sh +0 -123
- package/scripts/validate-identity-closure.py +0 -138
- package/scripts/validate-machine-input.sh +0 -48
- package/scripts/validate-managed-objects-peak.py +0 -147
- package/scripts/validation-cache-key.py +0 -88
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Generate or validate Saddle's final parameterized generated-capacity facts."""
|
|
3
|
-
|
|
4
|
-
from __future__ import annotations
|
|
5
|
-
|
|
6
|
-
import hashlib
|
|
7
|
-
import json
|
|
8
|
-
import re
|
|
9
|
-
import sys
|
|
10
|
-
from pathlib import Path
|
|
11
|
-
|
|
12
|
-
U64_MAX = (1 << 64) - 1
|
|
13
|
-
APPROVED_PROFILE_COUNT = 6_505_728
|
|
14
|
-
APPROVED_DOMAIN_FINGERPRINT = (
|
|
15
|
-
"b83afcae5ee83ae410b207fe93b4609bf1c12549e2eb52a139cb5728c2f121f9"
|
|
16
|
-
)
|
|
17
|
-
DOMAIN = {
|
|
18
|
-
"worker_threads_min": 1,
|
|
19
|
-
"worker_threads_max": 8,
|
|
20
|
-
"active_requests_min": 1,
|
|
21
|
-
"active_requests_max": 128,
|
|
22
|
-
"wait_slots_min": 0,
|
|
23
|
-
"wait_slots_max": 128,
|
|
24
|
-
"db_max": 64,
|
|
25
|
-
}
|
|
26
|
-
COST = {
|
|
27
|
-
"route_count": 6,
|
|
28
|
-
"managed_commitment_per_active": 232,
|
|
29
|
-
"managed_objects_per_active": 2,
|
|
30
|
-
"task_storage_per_active": 2072,
|
|
31
|
-
"framework_per_active": 7200,
|
|
32
|
-
"response_carrier_per_active": 64,
|
|
33
|
-
"entry_reserve_per_active": 64,
|
|
34
|
-
}
|
|
35
|
-
IDENTITY_KEYS = (
|
|
36
|
-
"source_commit",
|
|
37
|
-
"contract_sha256",
|
|
38
|
-
"calibration_sha256",
|
|
39
|
-
"physical_measurement_sha256",
|
|
40
|
-
"physical_binary_sha256",
|
|
41
|
-
"physical_cargo_lock_sha256",
|
|
42
|
-
"query_artifact_sha256",
|
|
43
|
-
"c1_artifact_sha256",
|
|
44
|
-
"managed_objects_peak_fingerprint",
|
|
45
|
-
)
|
|
46
|
-
BASE_KEYS = {
|
|
47
|
-
"schema",
|
|
48
|
-
"source_commit",
|
|
49
|
-
"contract_sha256",
|
|
50
|
-
"calibration_sha256",
|
|
51
|
-
"physical_measurement_sha256",
|
|
52
|
-
"physical_binary_sha256",
|
|
53
|
-
"physical_cargo_lock_sha256",
|
|
54
|
-
"query_artifact_sha256",
|
|
55
|
-
"c1_artifact_sha256",
|
|
56
|
-
"managed_objects_peak_fingerprint",
|
|
57
|
-
"source_build_identity",
|
|
58
|
-
"worker_threads_domain",
|
|
59
|
-
"active_requests_domain",
|
|
60
|
-
"wait_slots_domain",
|
|
61
|
-
"db_domain",
|
|
62
|
-
"transport_registration_relation",
|
|
63
|
-
"io_events_relation",
|
|
64
|
-
"task_slot_capacity_relation",
|
|
65
|
-
"route_count",
|
|
66
|
-
"managed_commitment_per_active",
|
|
67
|
-
"managed_objects_per_active",
|
|
68
|
-
"task_storage_per_active",
|
|
69
|
-
"framework_per_active",
|
|
70
|
-
"response_carrier_per_active",
|
|
71
|
-
"entry_reserve_per_active",
|
|
72
|
-
"profile_count",
|
|
73
|
-
"domain_fingerprint",
|
|
74
|
-
"arithmetic",
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def fail(message: str) -> None:
|
|
79
|
-
raise ValueError(message)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def checked(value: int, label: str) -> int:
|
|
83
|
-
if value < 0 or value > U64_MAX:
|
|
84
|
-
fail(f"{label} exceeds approved 64-bit usize")
|
|
85
|
-
return value
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def sha256_text(text: str) -> str:
|
|
89
|
-
return hashlib.sha256(text.encode("utf-8")).hexdigest()
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def validate_sha(value: object, key: str) -> str:
|
|
93
|
-
length = 40 if key == "source_commit" else 64
|
|
94
|
-
label = "full Git commit" if key == "source_commit" else "SHA-256"
|
|
95
|
-
if not isinstance(value, str) or not re.fullmatch(rf"[0-9a-f]{{{length}}}", value):
|
|
96
|
-
fail(f"{key} is not {label}")
|
|
97
|
-
return value
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
def canonical_identity(identity: dict[str, object]) -> tuple[dict[str, str], str]:
|
|
101
|
-
if set(identity) != set(IDENTITY_KEYS):
|
|
102
|
-
fail("source/build identity has unknown, duplicate, or missing fields")
|
|
103
|
-
values = {key: validate_sha(identity[key], key) for key in IDENTITY_KEYS}
|
|
104
|
-
text = "".join(f"{key}={values[key]}\n" for key in IDENTITY_KEYS)
|
|
105
|
-
return values, sha256_text(text)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def profile_record(
|
|
109
|
-
workers: int,
|
|
110
|
-
active: int,
|
|
111
|
-
waiters: int,
|
|
112
|
-
db: int,
|
|
113
|
-
*,
|
|
114
|
-
task_storage_per_active: int = COST["task_storage_per_active"],
|
|
115
|
-
) -> str:
|
|
116
|
-
if not 1 <= workers <= 8:
|
|
117
|
-
fail("T is outside 1..8")
|
|
118
|
-
if not 1 <= active <= 128:
|
|
119
|
-
fail("N is outside 1..128")
|
|
120
|
-
if not 0 <= waiters <= 128:
|
|
121
|
-
fail("W is outside 0..128")
|
|
122
|
-
if not 0 <= db <= min(active, 64):
|
|
123
|
-
fail("DB is outside 0..min(N,64)")
|
|
124
|
-
registration = checked(active + waiters, "R=N+W")
|
|
125
|
-
events = checked(registration + 3, "E=R+3")
|
|
126
|
-
task_slots = active
|
|
127
|
-
managed = checked(active * COST["managed_commitment_per_active"], "managed")
|
|
128
|
-
objects = checked(active * COST["managed_objects_per_active"], "objects")
|
|
129
|
-
task = checked(active * task_storage_per_active, "task")
|
|
130
|
-
framework = checked(active * COST["framework_per_active"], "framework")
|
|
131
|
-
response = checked(active * COST["response_carrier_per_active"], "response")
|
|
132
|
-
entry = checked(active * COST["entry_reserve_per_active"], "entry")
|
|
133
|
-
return (
|
|
134
|
-
f"T={workers};N={active};W={waiters};DB={db};"
|
|
135
|
-
f"R={registration};E={events};task_slots={task_slots};"
|
|
136
|
-
f"managed={managed};objects={objects};task={task};"
|
|
137
|
-
f"framework={framework};response={response};entry={entry}\n"
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
def enumerate_domain() -> tuple[int, str]:
|
|
142
|
-
digest = hashlib.sha256()
|
|
143
|
-
count = 0
|
|
144
|
-
for workers in range(1, 9):
|
|
145
|
-
for active in range(1, 129):
|
|
146
|
-
for waiters in range(0, 129):
|
|
147
|
-
for db in range(0, min(active, 64) + 1):
|
|
148
|
-
record = profile_record(workers, active, waiters, db)
|
|
149
|
-
digest.update(record.encode("ascii"))
|
|
150
|
-
count += 1
|
|
151
|
-
return count, digest.hexdigest()
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
def expected(identity: dict[str, object], *, derive_domain: bool) -> dict[str, str]:
|
|
155
|
-
identity_values, source_build_identity = canonical_identity(identity)
|
|
156
|
-
if derive_domain:
|
|
157
|
-
count, domain_fingerprint = enumerate_domain()
|
|
158
|
-
if (
|
|
159
|
-
count != APPROVED_PROFILE_COUNT
|
|
160
|
-
or domain_fingerprint != APPROVED_DOMAIN_FINGERPRINT
|
|
161
|
-
):
|
|
162
|
-
fail("enumerated support domain drifted from schema 1")
|
|
163
|
-
else:
|
|
164
|
-
count = APPROVED_PROFILE_COUNT
|
|
165
|
-
domain_fingerprint = APPROVED_DOMAIN_FINGERPRINT
|
|
166
|
-
return {
|
|
167
|
-
"schema": "saddle-generated-parameterized-capacity/1",
|
|
168
|
-
**identity_values,
|
|
169
|
-
"source_build_identity": source_build_identity,
|
|
170
|
-
"worker_threads_domain": "1..8",
|
|
171
|
-
"active_requests_domain": "1..128",
|
|
172
|
-
"wait_slots_domain": "0..128",
|
|
173
|
-
"db_domain": "0..min(N,64)",
|
|
174
|
-
"transport_registration_relation": "R=N+W",
|
|
175
|
-
"io_events_relation": "E=R+3",
|
|
176
|
-
"task_slot_capacity_relation": "task_slot_capacity=N",
|
|
177
|
-
**{key: str(value) for key, value in COST.items()},
|
|
178
|
-
"profile_count": str(count),
|
|
179
|
-
"domain_fingerprint": domain_fingerprint,
|
|
180
|
-
"arithmetic": "checked-u64",
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
def read_facts(path: Path) -> dict[str, str]:
|
|
185
|
-
values: dict[str, str] = {}
|
|
186
|
-
for line_number, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
|
|
187
|
-
if not line or "=" not in line:
|
|
188
|
-
fail(f"line {line_number} is not canonical key=value")
|
|
189
|
-
key, value = line.split("=", 1)
|
|
190
|
-
if key in values:
|
|
191
|
-
fail(f"duplicate field: {key}")
|
|
192
|
-
if key not in BASE_KEYS:
|
|
193
|
-
fail(f"unknown field: {key}")
|
|
194
|
-
values[key] = value
|
|
195
|
-
if set(values) != BASE_KEYS:
|
|
196
|
-
fail("machine facts have missing fields")
|
|
197
|
-
return values
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
def generate(identity_path: Path, output_path: Path) -> None:
|
|
201
|
-
identity = json.loads(identity_path.read_text(encoding="utf-8"))
|
|
202
|
-
values = expected(identity, derive_domain=True)
|
|
203
|
-
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
204
|
-
output_path.write_text(
|
|
205
|
-
"".join(f"{key}={values[key]}\n" for key in values),
|
|
206
|
-
encoding="utf-8",
|
|
207
|
-
)
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
def validate(facts_path: Path) -> None:
|
|
211
|
-
values = read_facts(facts_path)
|
|
212
|
-
identity = {key: values[key] for key in IDENTITY_KEYS}
|
|
213
|
-
wanted = expected(identity, derive_domain=False)
|
|
214
|
-
if values != wanted:
|
|
215
|
-
drift = sorted(key for key in BASE_KEYS if values.get(key) != wanted.get(key))
|
|
216
|
-
fail(f"generated capacity facts drifted: {','.join(drift)}")
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
def main() -> int:
|
|
220
|
-
try:
|
|
221
|
-
if len(sys.argv) == 4 and sys.argv[1] == "generate":
|
|
222
|
-
generate(Path(sys.argv[2]), Path(sys.argv[3]))
|
|
223
|
-
return 0
|
|
224
|
-
if len(sys.argv) == 3 and sys.argv[1] == "validate":
|
|
225
|
-
validate(Path(sys.argv[2]))
|
|
226
|
-
print("saddle-generated-parameterized-capacity/1: valid")
|
|
227
|
-
return 0
|
|
228
|
-
if len(sys.argv) == 7 and sys.argv[1] == "probe":
|
|
229
|
-
workers, active, waiters, db, task_cost = map(int, sys.argv[2:])
|
|
230
|
-
print(
|
|
231
|
-
profile_record(
|
|
232
|
-
workers,
|
|
233
|
-
active,
|
|
234
|
-
waiters,
|
|
235
|
-
db,
|
|
236
|
-
task_storage_per_active=task_cost,
|
|
237
|
-
),
|
|
238
|
-
end="",
|
|
239
|
-
)
|
|
240
|
-
return 0
|
|
241
|
-
print(
|
|
242
|
-
"usage: parameterized-capacity-facts.py "
|
|
243
|
-
"generate <identity.json> <facts> | validate <facts> | "
|
|
244
|
-
"probe <T> <N> <W> <DB> <task-cost>",
|
|
245
|
-
file=sys.stderr,
|
|
246
|
-
)
|
|
247
|
-
return 64
|
|
248
|
-
except (OSError, ValueError, json.JSONDecodeError) as error:
|
|
249
|
-
print(f"parameterized capacity facts invalid: {error}", file=sys.stderr)
|
|
250
|
-
return 1
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
if __name__ == "__main__":
|
|
254
|
-
raise SystemExit(main())
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Synchronize the packaged Skill closure from one approved Rust candidate."""
|
|
3
|
-
|
|
4
|
-
from __future__ import annotations
|
|
5
|
-
|
|
6
|
-
import argparse
|
|
7
|
-
import hashlib
|
|
8
|
-
import json
|
|
9
|
-
import re
|
|
10
|
-
from pathlib import Path
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def digest(path: Path) -> str:
|
|
14
|
-
return hashlib.sha256(path.read_bytes()).hexdigest()
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def main() -> None:
|
|
18
|
-
parser = argparse.ArgumentParser()
|
|
19
|
-
parser.add_argument("--root", type=Path, required=True)
|
|
20
|
-
parser.add_argument("--rust-candidate-manifest", type=Path, required=True)
|
|
21
|
-
parser.add_argument("--skill-release", default="0.2.0")
|
|
22
|
-
args = parser.parse_args()
|
|
23
|
-
|
|
24
|
-
root = args.root.resolve()
|
|
25
|
-
candidate_path = args.rust_candidate_manifest.resolve()
|
|
26
|
-
candidate = json.loads(candidate_path.read_text(encoding="utf-8"))
|
|
27
|
-
if candidate.get("schema") != "saddle-rs-01-r12-rust-recovery-candidate/1":
|
|
28
|
-
raise SystemExit("unsupported Rust candidate manifest")
|
|
29
|
-
if candidate.get("release") != "0.2.0" or candidate.get("status") != "candidate-ready-for-transport-review":
|
|
30
|
-
raise SystemExit("unexpected or incomplete Rust candidate")
|
|
31
|
-
if candidate.get("publish_performed") is not False or candidate.get("tag_performed") is not False:
|
|
32
|
-
raise SystemExit("Rust candidate crossed the release boundary")
|
|
33
|
-
source = candidate.get("artifact_source_commit", "")
|
|
34
|
-
if not re.fullmatch(r"[0-9a-f]{40}", source):
|
|
35
|
-
raise SystemExit("Rust artifact source is not a full commit")
|
|
36
|
-
expected_packages = {
|
|
37
|
-
"saddle-core", "saddle-macros", "saddle-admission", "saddle-observability",
|
|
38
|
-
"saddle-runtime", "saddle-db", "saddle-service", "saddle-framework",
|
|
39
|
-
}
|
|
40
|
-
packages = {item["name"]: item for item in candidate.get("crates", [])}
|
|
41
|
-
if set(packages) != expected_packages:
|
|
42
|
-
raise SystemExit("Rust candidate does not contain exactly eight Saddle crates")
|
|
43
|
-
if any(not re.fullmatch(r"[0-9a-f]{64}", item.get("sha256", "")) for item in packages.values()):
|
|
44
|
-
raise SystemExit("Rust candidate crate digest is invalid")
|
|
45
|
-
|
|
46
|
-
skill = root / "skills/saddle-service-0-2"
|
|
47
|
-
manifest_path = skill / "package-manifest.json"
|
|
48
|
-
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
|
49
|
-
snapshot = skill / "references/public-api.snapshot"
|
|
50
|
-
machine_doc = skill / "references/machine-schema.md"
|
|
51
|
-
template_root = skill / "assets/registry-consumer"
|
|
52
|
-
template_inputs = {
|
|
53
|
-
"cargo_lock": template_root / "Cargo.lock",
|
|
54
|
-
"cargo_manifest": template_root / "Cargo.toml",
|
|
55
|
-
"library": template_root / "src/lib.rs",
|
|
56
|
-
"generated_owner": template_root / "src/generated_artifact.rs",
|
|
57
|
-
"external_consumer_test": template_root / "tests/provider_consumer.rs",
|
|
58
|
-
"output_validator": skill / "scripts/validate-generated-project.sh",
|
|
59
|
-
"preflight_validator": skill / "scripts/validate-generated-preflight.sh",
|
|
60
|
-
"cache_key_builder": skill / "scripts/validation-cache-key.py",
|
|
61
|
-
}
|
|
62
|
-
observed_template = {name: digest(path) for name, path in template_inputs.items()}
|
|
63
|
-
template_identity = hashlib.sha256(
|
|
64
|
-
json.dumps(observed_template, separators=(",", ":")).encode()
|
|
65
|
-
).hexdigest()
|
|
66
|
-
gate_identity = manifest.get("gate_identity", {})
|
|
67
|
-
if not re.fullmatch(r"[0-9a-f]{40}", gate_identity.get("d1_source_candidate", "")):
|
|
68
|
-
raise SystemExit("approved Gate identity is missing")
|
|
69
|
-
|
|
70
|
-
closure = {
|
|
71
|
-
"schema": "saddle-skill-identity-closure/2",
|
|
72
|
-
"skill_release": args.skill_release,
|
|
73
|
-
"rust_release": candidate["release"],
|
|
74
|
-
"artifact_source_commit": source,
|
|
75
|
-
"registry_artifact_source_commit": source,
|
|
76
|
-
"rust_candidate_manifest_sha256": digest(candidate_path),
|
|
77
|
-
"registry_packages_sha256": {name: packages[name]["sha256"] for name in sorted(packages)},
|
|
78
|
-
"framework_crate_sha256": packages["saddle-framework"]["sha256"],
|
|
79
|
-
"fresh_registry_cargo_lock_sha256": candidate["consumer_lock_sha256"],
|
|
80
|
-
"registry_consumer_cargo_lock_sha256": observed_template["cargo_lock"],
|
|
81
|
-
"declaration_schema": "saddle-application/1",
|
|
82
|
-
"machine_schema": "saddle-approved-build/2",
|
|
83
|
-
"generated_static_schema": "saddle-generated-static-facts/2",
|
|
84
|
-
"gate_identity": gate_identity,
|
|
85
|
-
"public_api_snapshot_sha256": digest(snapshot),
|
|
86
|
-
"machine_schema_document_sha256": digest(machine_doc),
|
|
87
|
-
"approved_locks": {"registry_consumer": observed_template["cargo_lock"]},
|
|
88
|
-
"unified_application_sha256": observed_template["library"],
|
|
89
|
-
"unified_owner_sha256": observed_template["generated_owner"],
|
|
90
|
-
"template_identity_sha256": template_identity,
|
|
91
|
-
"registry_consumer_template": observed_template,
|
|
92
|
-
}
|
|
93
|
-
closure_path = skill / "references/identity-closure.json"
|
|
94
|
-
closure_path.write_text(json.dumps(closure, indent=2) + "\n", encoding="utf-8")
|
|
95
|
-
|
|
96
|
-
manifest["npm"]["version"] = args.skill_release
|
|
97
|
-
manifest["rust"]["requirement"] = f'={candidate["release"]}'
|
|
98
|
-
manifest["rust"]["source_commit"] = source
|
|
99
|
-
manifest["rust"]["public_api_snapshot_sha256"] = closure["public_api_snapshot_sha256"]
|
|
100
|
-
manifest["consumer_evidence"]["approved_locks"] = closure["approved_locks"]
|
|
101
|
-
manifest["consumer_evidence"]["unified_application_sha256"] = closure["unified_application_sha256"]
|
|
102
|
-
manifest["consumer_evidence"]["unified_owner_sha256"] = closure["unified_owner_sha256"]
|
|
103
|
-
manifest["consumer_evidence"]["registry_consumer_template"] = observed_template
|
|
104
|
-
manifest["generated_static_facts"]["application_machine_fingerprint"] = "NOT_GENERATED_SK_02"
|
|
105
|
-
manifest["generated_static_facts"]["template_identity_sha256"] = template_identity
|
|
106
|
-
manifest["identity_closure"] = {
|
|
107
|
-
"path": "references/identity-closure.json",
|
|
108
|
-
"sha256": digest(closure_path),
|
|
109
|
-
"registry_artifact_source_commit": source,
|
|
110
|
-
"rust_candidate_manifest_sha256": closure["rust_candidate_manifest_sha256"],
|
|
111
|
-
"registry_packages_sha256": closure["registry_packages_sha256"],
|
|
112
|
-
"framework_crate_sha256": closure["framework_crate_sha256"],
|
|
113
|
-
"fresh_registry_cargo_lock_sha256": closure["fresh_registry_cargo_lock_sha256"],
|
|
114
|
-
"registry_consumer_cargo_lock_sha256": closure["registry_consumer_cargo_lock_sha256"],
|
|
115
|
-
}
|
|
116
|
-
manifest_path.write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8")
|
|
117
|
-
package_path = skill / "package.json"
|
|
118
|
-
package = json.loads(package_path.read_text(encoding="utf-8"))
|
|
119
|
-
package["version"] = args.skill_release
|
|
120
|
-
package_path.write_text(json.dumps(package, indent=2) + "\n", encoding="utf-8")
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if __name__ == "__main__":
|
|
124
|
-
main()
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
if [[ $# -ne 1 ]]; then
|
|
5
|
-
echo "usage: validate-contract.sh <application.rs>" >&2
|
|
6
|
-
exit 64
|
|
7
|
-
fi
|
|
8
|
-
|
|
9
|
-
source_file=$1
|
|
10
|
-
if [[ ! -f "$source_file" ]]; then
|
|
11
|
-
echo "contract source not found: $source_file" >&2
|
|
12
|
-
exit 66
|
|
13
|
-
fi
|
|
14
|
-
|
|
15
|
-
source_text="$(<"$source_file")"
|
|
16
|
-
|
|
17
|
-
required=(
|
|
18
|
-
'saddle::application!'
|
|
19
|
-
'schema "saddle-application/1";'
|
|
20
|
-
'application '
|
|
21
|
-
'service '
|
|
22
|
-
)
|
|
23
|
-
for token in "${required[@]}"; do
|
|
24
|
-
if ! grep -Fq "$token" <<<"$source_text"; then
|
|
25
|
-
echo "missing required declaration token: $token" >&2
|
|
26
|
-
exit 1
|
|
27
|
-
fi
|
|
28
|
-
done
|
|
29
|
-
|
|
30
|
-
if [[ "$(grep -Fc 'saddle::application!' <<<"$source_text")" -ne 1 ]]; then
|
|
31
|
-
echo "exactly one saddle::application! declaration is required" >&2
|
|
32
|
-
exit 1
|
|
33
|
-
fi
|
|
34
|
-
|
|
35
|
-
if grep -Eq \
|
|
36
|
-
'ServiceHandler|ServiceFuture|ServiceRegistry|Statement|DbValue|TransactionFuture|serde|sqlx|String|Vec<|Box<|dyn Future|tokio::|std::thread|spawn\(|channel\(|capacity[[:space:]]|deadline[[:space:]]|timeout[[:space:]]' \
|
|
37
|
-
<<<"$source_text"
|
|
38
|
-
then
|
|
39
|
-
echo "declaration contains a V1, unmanaged, execution, or numeric-profile bypass" >&2
|
|
40
|
-
exit 1
|
|
41
|
-
fi
|
|
42
|
-
|
|
43
|
-
if grep -Eq 'transaction[[:space:]].*\{([^}]|$)*steps[[:space:]]+([02-9]|[1-9][0-9]+);' \
|
|
44
|
-
<<<"$(tr '\n' ' ' <"$source_file")"
|
|
45
|
-
then
|
|
46
|
-
echo "schema 1 transaction must contain exactly one step" >&2
|
|
47
|
-
exit 1
|
|
48
|
-
fi
|
|
49
|
-
|
|
50
|
-
if grep -Eq 'decision[[:space:]]+([^;]+);' <<<"$source_text"; then
|
|
51
|
-
while IFS= read -r decision; do
|
|
52
|
-
case "$decision" in
|
|
53
|
-
"decision commit;"|"decision business_rollback;") ;;
|
|
54
|
-
*)
|
|
55
|
-
echo "unsupported transaction decision: $decision" >&2
|
|
56
|
-
exit 1
|
|
57
|
-
;;
|
|
58
|
-
esac
|
|
59
|
-
done < <(grep -Eo 'decision[[:space:]]+[^;]+;' <<<"$source_text")
|
|
60
|
-
fi
|
|
61
|
-
|
|
62
|
-
echo "saddle-application/1 declaration: candidate-valid"
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
if [[ $# -ne 1 ]]; then
|
|
5
|
-
echo "usage: validate-generated-preflight.sh <project-root>" >&2
|
|
6
|
-
exit 64
|
|
7
|
-
fi
|
|
8
|
-
|
|
9
|
-
project=$(cd "$1" && pwd)
|
|
10
|
-
python3 - "$project" <<'PY'
|
|
11
|
-
from pathlib import Path
|
|
12
|
-
import re, sys
|
|
13
|
-
|
|
14
|
-
root = Path(sys.argv[1])
|
|
15
|
-
sources = sorted((root / "src").glob("**/*.rs"))
|
|
16
|
-
if not sources:
|
|
17
|
-
raise SystemExit("generated source is missing")
|
|
18
|
-
source = "\n".join(path.read_text() for path in sources)
|
|
19
|
-
without_blocks = re.sub(r"/\*.*?\*/", "", source, flags=re.S)
|
|
20
|
-
active = "\n".join(line.split("//", 1)[0] for line in without_blocks.splitlines())
|
|
21
|
-
required = [
|
|
22
|
-
r"let\s+bundle\s*=\s*builder\s*\.\s*freeze_with_capacity_leaf\s*\(",
|
|
23
|
-
r"generated_bootstrap\s*\(\s*seal\.preflight_token\(\)\s*,\s*bundle\s*,",
|
|
24
|
-
r"seal\s*\.\s*bind\s*\(\s*bootstrap\s*\)",
|
|
25
|
-
]
|
|
26
|
-
for pattern in required:
|
|
27
|
-
if not re.search(pattern, active, flags=re.S):
|
|
28
|
-
raise SystemExit(f"missing active generated runtime preflight shape: {pattern}")
|
|
29
|
-
|
|
30
|
-
marker = re.search(r"seal\s*\.\s*bind\s*\(", active)
|
|
31
|
-
if marker is None:
|
|
32
|
-
raise SystemExit("missing active Facade opaque bind call")
|
|
33
|
-
start = marker.end()
|
|
34
|
-
round_depth, curly_depth, square_depth = 1, 0, 0
|
|
35
|
-
commas = []
|
|
36
|
-
end = None
|
|
37
|
-
for index in range(start, len(active)):
|
|
38
|
-
char = active[index]
|
|
39
|
-
if char == "(":
|
|
40
|
-
round_depth += 1
|
|
41
|
-
elif char == ")":
|
|
42
|
-
round_depth -= 1
|
|
43
|
-
if round_depth == 0:
|
|
44
|
-
end = index
|
|
45
|
-
break
|
|
46
|
-
elif char == "{":
|
|
47
|
-
curly_depth += 1
|
|
48
|
-
elif char == "}":
|
|
49
|
-
curly_depth -= 1
|
|
50
|
-
elif char == "[":
|
|
51
|
-
square_depth += 1
|
|
52
|
-
elif char == "]":
|
|
53
|
-
square_depth -= 1
|
|
54
|
-
elif char == "," and round_depth == 1 and curly_depth == 0 and square_depth == 0:
|
|
55
|
-
commas.append(index)
|
|
56
|
-
if end is None:
|
|
57
|
-
raise SystemExit("unterminated Facade opaque bind call")
|
|
58
|
-
arguments = active[start:end]
|
|
59
|
-
parts = []
|
|
60
|
-
previous = 0
|
|
61
|
-
for comma in commas:
|
|
62
|
-
parts.append(arguments[previous:comma - start].strip())
|
|
63
|
-
previous = comma - start + 1
|
|
64
|
-
parts.append(arguments[previous:].strip())
|
|
65
|
-
parts = [part for part in parts if part]
|
|
66
|
-
if parts != ["bootstrap"]:
|
|
67
|
-
raise SystemExit("Facade bind must receive only the Service whole-bundle bootstrap")
|
|
68
|
-
for forbidden in [
|
|
69
|
-
r"type\s+ServiceCapacity\s*=", r"type\s+Termination\s*=", r"type\s+Continuation\s*=",
|
|
70
|
-
r"\.into_parts\s*\(\s*\)", r"GeneratedBootstrapBinder", r"GeneratedTerminationTopologyWorkOwner",
|
|
71
|
-
r"PreflightGeneratedStaticContinuationOwner", r"runtime_layout_preflight\s*\(",
|
|
72
|
-
r"impl\s+(?:GeneratedBootstrapBinder|PreflightGeneratedStaticContinuationOwner|GeneratedTerminationTopologyWorkOwner)\s+for\s+",
|
|
73
|
-
]:
|
|
74
|
-
if re.search(forbidden, active):
|
|
75
|
-
raise SystemExit(f"generated production proof injection remains: {forbidden}")
|
|
76
|
-
|
|
77
|
-
def function_body(name: str) -> str:
|
|
78
|
-
marker = re.search(rf"fn\s+{name}\s*\([^)]*\)\s*->\s*ExecutionError\s*\{{", active)
|
|
79
|
-
if marker is None:
|
|
80
|
-
raise SystemExit(f"missing generated error mapper: {name}")
|
|
81
|
-
start = marker.end() - 1
|
|
82
|
-
depth = 0
|
|
83
|
-
for index in range(start, len(active)):
|
|
84
|
-
if active[index] == "{":
|
|
85
|
-
depth += 1
|
|
86
|
-
elif active[index] == "}":
|
|
87
|
-
depth -= 1
|
|
88
|
-
if depth == 0:
|
|
89
|
-
return active[start + 1:index]
|
|
90
|
-
raise SystemExit(f"unterminated generated error mapper: {name}")
|
|
91
|
-
|
|
92
|
-
expected = {
|
|
93
|
-
"map_query_error": {
|
|
94
|
-
"ConnectionUnavailable", "QueryFailed", "InvalidRow", "FinalizerFailed",
|
|
95
|
-
"Cancelled", "Shutdown", "DependencyExecutionFailed", "DependencyUnavailable",
|
|
96
|
-
},
|
|
97
|
-
"map_write_error": {
|
|
98
|
-
"ConnectionUnavailable", "WriteFailed", "FinalizerFailed", "Cancelled", "Shutdown",
|
|
99
|
-
"DependencyExecutionFailed", "DependencyUnavailable",
|
|
100
|
-
},
|
|
101
|
-
"map_transaction_error": {
|
|
102
|
-
"BusinessRollback", "ConnectionUnavailable", "BeginFailed", "WriteFailed",
|
|
103
|
-
"CommitFailed", "RollbackFailed", "FinalizerFailed", "Cancelled", "Shutdown",
|
|
104
|
-
"Business", "DependencyExecutionFailed", "DependencyUnavailable",
|
|
105
|
-
},
|
|
106
|
-
}
|
|
107
|
-
for name, tokens in expected.items():
|
|
108
|
-
body = function_body(name)
|
|
109
|
-
if re.search(r"(?:^|[,{|])\s*_\s*=>", body):
|
|
110
|
-
raise SystemExit(f"generated error mapper contains a catch-all: {name}")
|
|
111
|
-
for token in tokens:
|
|
112
|
-
if len(re.findall(rf"\b{re.escape(token)}\b", body)) != 1:
|
|
113
|
-
raise SystemExit(f"generated error mapper token drift: {name}/{token}")
|
|
114
|
-
if name != "map_transaction_error" and re.search(r"\bExecutionError::Business\b", body):
|
|
115
|
-
raise SystemExit(f"dependency failure was downgraded to Business: {name}")
|
|
116
|
-
if len(re.findall(r"\bExecutionError::Business\b", function_body("map_transaction_error"))) != 1:
|
|
117
|
-
raise SystemExit("only BusinessRollback may map to ExecutionError::Business")
|
|
118
|
-
PY
|
|
119
|
-
|
|
120
|
-
echo 'generated whole-bundle opaque proof authority: PASS'
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
if [[ $# -ne 1 ]]; then
|
|
5
|
-
echo "usage: validate-generated-project.sh <project-root>" >&2
|
|
6
|
-
exit 64
|
|
7
|
-
fi
|
|
8
|
-
|
|
9
|
-
project=$(cd "$1" && pwd)
|
|
10
|
-
test -f "$project/Cargo.toml"
|
|
11
|
-
test -f "$project/Cargo.lock"
|
|
12
|
-
script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)
|
|
13
|
-
cache_key_builder="$script_dir/validation-cache-key.py"
|
|
14
|
-
test -x "$cache_key_builder"
|
|
15
|
-
|
|
16
|
-
if [[ ${CARGO_NET_OFFLINE:-} != true ]]; then
|
|
17
|
-
echo "Skill validation requires CARGO_NET_OFFLINE=true" >&2
|
|
18
|
-
exit 1
|
|
19
|
-
fi
|
|
20
|
-
if [[ ${SADDLE_SKILL_FEATURE_SET:-default} != default ]]; then
|
|
21
|
-
echo "Skill validation supports only the declared default feature set" >&2
|
|
22
|
-
exit 1
|
|
23
|
-
fi
|
|
24
|
-
if [[ -z ${SADDLE_ENTRY_LOCAL_ROOT:-} || -z ${CARGO_HOME:-} || -z ${CARGO_TARGET_DIR:-} ]]; then
|
|
25
|
-
echo "Skill validation requires the approved entry-local cache runner" >&2
|
|
26
|
-
exit 1
|
|
27
|
-
fi
|
|
28
|
-
entry_root=$(cd "$SADDLE_ENTRY_LOCAL_ROOT" && pwd -P)
|
|
29
|
-
trusted_tmp=$(cd /tmp && pwd -P)
|
|
30
|
-
if [[ $(dirname "$entry_root") != "$trusted_tmp" || -L $SADDLE_ENTRY_LOCAL_ROOT ]]; then
|
|
31
|
-
echo "Skill validation entry root must be a canonical direct child of /tmp" >&2
|
|
32
|
-
exit 1
|
|
33
|
-
fi
|
|
34
|
-
if [[ $(cd "$CARGO_HOME" && pwd -P) != "$entry_root/cargo-home" || \
|
|
35
|
-
$(cd "$CARGO_TARGET_DIR" && pwd -P) != "$entry_root/target" || \
|
|
36
|
-
$(pwd -P) != "$entry_root/work" ]]; then
|
|
37
|
-
echo "Skill validation requires entry-local cargo-home, target, and workdir" >&2
|
|
38
|
-
exit 1
|
|
39
|
-
fi
|
|
40
|
-
"$script_dir/validate-generated-preflight.sh" "$project"
|
|
41
|
-
if find "$project" -type d -name target -print -quit | grep -q .; then
|
|
42
|
-
echo "tracked or unignored build target is forbidden" >&2
|
|
43
|
-
exit 1
|
|
44
|
-
fi
|
|
45
|
-
|
|
46
|
-
python3 - "$project" <<'PY'
|
|
47
|
-
from pathlib import Path
|
|
48
|
-
import re, sys, tomllib
|
|
49
|
-
|
|
50
|
-
root = Path(sys.argv[1])
|
|
51
|
-
cargo_text = (root / "Cargo.toml").read_text()
|
|
52
|
-
cargo = tomllib.loads(cargo_text)
|
|
53
|
-
package = cargo.get("package", {})
|
|
54
|
-
if package.get("rust-version") != "1.85":
|
|
55
|
-
raise SystemExit("generated project must declare rust-version 1.85")
|
|
56
|
-
if re.search(r"(?:path|git|workspace)\s*=|\[patch", cargo_text):
|
|
57
|
-
raise SystemExit("path/git/workspace/patch dependency is forbidden")
|
|
58
|
-
|
|
59
|
-
deps = cargo.get("dependencies", {})
|
|
60
|
-
framework = deps.get("saddle")
|
|
61
|
-
if not isinstance(framework, dict) or framework.get("package") != "saddle-framework" or framework.get("version") != "=0.2.0":
|
|
62
|
-
raise SystemExit("exact registry saddle-framework =0.2.0 is required")
|
|
63
|
-
for name, value in deps.items():
|
|
64
|
-
if name.startswith("saddle-"):
|
|
65
|
-
version = value if isinstance(value, str) else value.get("version")
|
|
66
|
-
if version != "=0.2.0":
|
|
67
|
-
raise SystemExit(f"{name} must use exact registry 0.2.0")
|
|
68
|
-
|
|
69
|
-
sources = sorted((root / "src").glob("**/*.rs"))
|
|
70
|
-
tests = sorted((root / "tests").glob("**/*.rs"))
|
|
71
|
-
if not sources or not tests:
|
|
72
|
-
raise SystemExit("generated source and at least one executable integration test are required")
|
|
73
|
-
source = "\n".join(p.read_text() for p in sources)
|
|
74
|
-
without_blocks = re.sub(r"/\*.*?\*/", "", source, flags=re.S)
|
|
75
|
-
active = "\n".join(line.split("//", 1)[0] for line in without_blocks.splitlines())
|
|
76
|
-
required = [
|
|
77
|
-
r"pub\s+fn\s+run\s*<\s*B\s*>",
|
|
78
|
-
r"B\s*:\s*ApprovedExternalBundle",
|
|
79
|
-
r"ProductionLauncher::verify\s*\(\s*bundle\s*\)\?\s*\.run\s*\(\s*config\s*,\s*GeneratedOwner\s*\)",
|
|
80
|
-
r"mod\s+__saddle_generated\s*;",
|
|
81
|
-
]
|
|
82
|
-
for pattern in required:
|
|
83
|
-
if not re.search(pattern, active, re.S):
|
|
84
|
-
raise SystemExit(f"missing active generated consumer shape: {pattern}")
|
|
85
|
-
if re.search(r"pub\s+struct\s+GeneratedOwner", active):
|
|
86
|
-
raise SystemExit("GeneratedOwner must remain private")
|
|
87
|
-
if "TODO" in source or re.search(r"fn\s+main[^{}]*\{\s*(?:return\s+)?Ok\s*\(\s*\(\s*\)\s*\)\s*;?\s*\}", active, re.S):
|
|
88
|
-
raise SystemExit("placeholder or no-op main is forbidden")
|
|
89
|
-
test_text = "\n".join(p.read_text() for p in tests)
|
|
90
|
-
if "#[test]" not in test_text:
|
|
91
|
-
raise SystemExit("zero executable tests are forbidden")
|
|
92
|
-
PY
|
|
93
|
-
|
|
94
|
-
case "$(cd "$CARGO_TARGET_DIR" && pwd -P)" in
|
|
95
|
-
"$project"|"$project"/*)
|
|
96
|
-
echo "Cargo target must be outside the generated project" >&2
|
|
97
|
-
exit 1
|
|
98
|
-
;;
|
|
99
|
-
esac
|
|
100
|
-
cargo +1.85.0 test --manifest-path "$project/Cargo.toml" --locked --offline
|
|
101
|
-
if find "$project" -type d -name target -print -quit | grep -q .; then
|
|
102
|
-
echo "validation left a build target in the generated project" >&2
|
|
103
|
-
exit 1
|
|
104
|
-
fi
|
|
105
|
-
rustc_verbose=$(rustc +1.85.0 -vV)
|
|
106
|
-
rustc_version=$(sed -n '1s/^rustc //p' <<<"$rustc_verbose")
|
|
107
|
-
toolchain_identity=$(sed -n 's/^commit-hash: //p' <<<"$rustc_verbose")
|
|
108
|
-
target_triple=$(sed -n 's/^host: //p' <<<"$rustc_verbose")
|
|
109
|
-
if [[ -z $rustc_version || -z $toolchain_identity || -z $target_triple ]]; then
|
|
110
|
-
echo "Rust toolchain identity is incomplete" >&2
|
|
111
|
-
exit 1
|
|
112
|
-
fi
|
|
113
|
-
cache_identity=$(python3 "$cache_key_builder" cache-key \
|
|
114
|
-
--project "$project" \
|
|
115
|
-
--rustc-version "$rustc_version" \
|
|
116
|
-
--toolchain-identity "$toolchain_identity" \
|
|
117
|
-
--target-triple "$target_triple" \
|
|
118
|
-
--feature-set default \
|
|
119
|
-
--build-contract "validate-generated-project=$script_dir/validate-generated-project.sh" \
|
|
120
|
-
--build-contract "validate-generated-preflight=$script_dir/validate-generated-preflight.sh" \
|
|
121
|
-
--build-contract "validation-cache-key=$cache_key_builder")
|
|
122
|
-
printf 'saddle-skill-validation-cache=%s\n' "$cache_identity"
|
|
123
|
-
echo "generated provider-generic consumer: PASS"
|