A grade-1 (+node_execute) implementation of the programir
contract in Go — parse, validate, version-check,
link-check, profile-check, node-compile, diff, explain, plus the
scripted-trace execution engine (node_execute). A data library plus
the conformance shim; the engine runs only scripted leaves (no live
LMs) and nothing here ever touches the network.
The grade-1 hold layer (through node_set 0.3) is clean-room. It was
the first foreign implementation of the contract, written exclusively
from the public contract surface (spec/*.md, schema/*.json,
harness/PROTOCOL.md, harness/CASES-FORMAT.md, cases/**,
AUTHORITY.md, README.md, IMPLEMENTATIONS.md) — the Python
reference implementation was not consulted for that layer, and
underdetermined behaviors were resolved from fixtures alone.
The v0.4/v0.5 catch-up and the node_execute engine are NOT
clean-room. They were written with reference/interp.py,
reference/validate.py, and reference/shim.py open beside the spec:
the reference resolved semantic questions (pass ordering, refusal field
shapes, the record's runtime immutability path, float-repr mechanics)
faster than fixture archaeology would have. This port therefore no
longer serves as second-implementer evidence that the contract text
suffices on its own for those layers; programir-ts (still lagging)
remains available for that role.
| path | what |
|---|---|
internal/jsonval |
typed JSON values: json.Number decoding, int/float preserved end to end (1 != 1.0), key order kept, canonical re-emit, strict typed deep equality |
internal/schema |
a runtime interpreter for the two contract schema files, implementing exactly the restricted draft 2020-12 subset of schema/README.md (internal $ref + $defs, types, enum/const, oneOf, dependentRequired, …) — the schemas stay data |
internal/ops |
the grade-1 ops (capabilities, load_manifest, check_versions, link, profile_check, node_compile, diff, explain) plus the node_execute engine (nodeexecute.go: the SEM-1..8 interpreter over jsonval — exact int64 arithmetic, ordered dicts, reference-value aliasing, the v0.4 immutable record, While/recursion caps; nodebuiltins.go: the closed v0.3 builtin and value-method tables) |
cmd/shim |
the JSONL conformance shim (harness/PROTOCOL.md): one request per stdin line, one ordered reply per stdout line, exit 0 on EOF; PIR-E-SHIM-001/-002/-003 for panic / unknown op / malformed line |
Go 1.26, standard library only. go build ./... and go vet ./... are
clean.
The shim needs the contract checkout for the two schema files:
-contract <path>, else PROGRAMIR_CONTRACT, else ../programir-contract
(the sibling-checkout layout the shim registry assumes).
# by hand
echo '{"op":"capabilities","id":"1"}' | go run ./cmd/shim
# under the harness (registered as "go" in harness/shims.json)
cd ../programir-contract
python harness/check.py --shim goPer IMPLEMENTATIONS.md (grade + profile + pin):
programir-go: grade 1, checkable profile: declared-tier, pin
b24cd6f41796283c38f17e02b7ed6b9752fe41e1(CONTRACT_PIN).
Grade 1 is hold-only — the library executes nothing, so the profile part
names the profile its profile_check op implements, not a served one.
The claim holds when harness/check.py --shim go exits 0 at the pinned
SHA; it is never a claim of completeness (PIR-011).
The fixtures pin every refusal below; the following success shapes and corner behaviors have no fixture yet, so this port chose deterministically and records the choice for ratification:
check_versionssuccess result:{"versions": <the manifest's versions block>}— an identity echo, mirroringload_manifest's{"manifest": ...}.linksuccess result (spec/linking.mdopen item 1): the resolved-binding table keyed by predictor path,{"bindings": {<path>: {"adapter", "lm", "delta"}}}. Predictor paths follow the corpus convention: the root node's own name for a root Predict (self); nested leaves join child names with the root's name excluded (polish,drafter.classifier.classify).deltaresolution: no component is ratified as the delta pool (schema/README.mdambiguity 5), so any non-null delta refuses withPIR-E-LINK-002 {predictor, binding: "delta", entry}.diffshape (1.x-provisional byspec/SCOPE.md): input{"left", "right"}; result{"equal": bool, "diff": [{"path", "op", "left"?, "right"?}]}withop∈ added/removed/changed, JSON-pointer paths, objects recursed over the sorted key union, arrays element-wise by index, strict typed comparison (1 != 1.0is a change). Inputs are not schema-validated (the optimizer mid-edit use case).explainshape (View 1, 1.x-provisional):{"text": <string>}; the versions block prints first (spec/versions.md), then tree, predictors, pools, credentials — every map-ordered section sorted so the text is byte-stable.- Versions logic: the implementation declares a SET of supported
exact versions per entry (
spec/versions.md, D-034 amendment):node_setis{0.1, 0.2, 0.3, 0.4}(the ratified v0.2/v0.3/v0.4 batches, D-034/D-037/D-041); the other six entries are{0.1}(the corpus placeholders). Comparison follows the ratified rule: while an entry's major is0versions compare exact ("pre-1.0 is all-breaking") and set membership accepts; from1.0on, same-major accepts, with major = the substring before the first.(the grammar itself is open item 0).PIR-E-VERSION-001carriesentry,declared, andimplemented(the fixture pins the first two; "both versions" perspec/versions.md). Entries beyond the required seven are ignored (schema/README.mdambiguity 6). Checks run in the canonical entry order: presence/type for all seven, then the comparison rule. linkordering (spec/linking.md): versions → schema → depth-first tree walk in document order, adapter before lm before delta at each leaf, first failure refuses. Cross-map key-set agreement (2/3a/3b/3c ≡ tree paths) has no ratified refusal code, so grade-1linkdoes not enforce it yet.- Declared-tier clauses (provisional ids,
spec/placement.mdopen item 1, pinned bycases/profile/): DT-001 LM entries receiver-bound (an endpoint rung — notin_process— with a non-emptyendpoint_ref); DT-002 data-only adapter entries (builtin references or full canonical entries); DT-003 no authored-origin code (LMclass.origin, plus a deep scan of full adapter presets); DT-004 no bakedweights; DT-005 tools and interpreters receiver-bound or absent. Violations are{clause, subject}with subject<component>/<entry>, sorted by (clause, subject). An unknown profile name refusesPIR-E-PROFILE-001naming the profile — no code is ratified for that case. node_compilecodes:PIR-E-NODE-001 {node}for any un-whitelisted or malformed node (envelope violations use the kind"forward");PIR-E-NODE-002 {leaf}for every leaf-resolution failure (missing requiredref, dynamicnameoutside tool leaves, static/dynamic tool ambiguity, unknown leaf kind);PIR-E-NODE-002 {target}for an unknown builtin/method name (v0.3) or a splat that resolves to no declared record (v0.4);PIR-E-NODE-003 {key}andPIR-E-NODE-004 {record}per the v0.4 record rules (D-041). Locations are never reported — artifact form carries no source spans (SEM-8). The loadednode-set.schema.jsonruns as a backstop after the classification walk, so acceptance can never drift wider than the schema file. The v0.4 sweeps run after it: the standalone sweep (read-only record, splat resolution) in document order, then — only where the optionaldeclaredcontext suppliessignature/accepts— the per-splat-call collision and acceptance checks; a malformedsignature/acceptsshape refusesPIR-E-NODE-001(the op-input rule). Otherdeclaredkeys (the leaf pools) pass through untouched — no fixture pins a use for them at grade 1.- Missing op inputs refuse with the op's own family (
PIR-E- MANIFEST-001for an absent manifest/diff side,PIR-E-NODE-001for an absent forward,PIR-E-PROFILE-001for an absent profile name);PIR-E-SHIM-003stays purely protocol-level (unparseable line, non-object request, missingop). error.detailis present on every refusal but non-normative prose; the structured subject fields carry the comparison load (spec/errors.md).