TOUCHSTONE 0.2

Touchstone 0.2 explanatory errata#

Date: 2026-09-06.

This is a separately dated explanatory addendum, not a new rubric version. It identifies three prose errors inherited by the released 0.2 specification and explains the arithmetic already implemented and tested in that release. The original release remains available unchanged: v0.2, at commit 9b5de35ad69acd7d49cddbd92988f2c17ff6f9b8. The original specification, reference scorer, and conformance vectors are linked by immutable commit, so this addendum can be read beside the text it corrects. It does not replace that text or expand the conformance test set.

1. Centering: JavaScript rounding#

The Centering section incorrectly groups JavaScript's Math.round with half-to-even rounding.

Correct explanation: JavaScript's Math.round rounds exact ties toward positive infinity; Math.round(2.5) is 3, and Math.round(3.5) is 4. It does not use a ties-to-even rule. See the ECMAScript definition of Math.round.

Touchstone's existing centering penalty rule remains floor(sum(slope * span) + 0.5), applied once after accumulating the segments. For the rubric's nonnegative penalties, an exact half-point rounds upward. This correction does not replace the scorer's explicit rounding helper or alter input quantization. Binary floating-point representation can affect whether a computed value is exactly a tie; it does not make Math.round a ties-to-even function. The released front-centering example lr_pct: 60.3 produces a 105-point penalty, 895 points and grade 8.5.

2. Print defects and print attributes add together#

The Print defect paragraph incorrectly says a placed print defect and a gloss rung compete to cap the face.

Correct explanation: placed print defects and print attributes have additive penalties. Their penalties sum within that face's print region. The region starts at 1000 points and is reduced by their combined penalties, with a floor of zero. The resulting region score then participates in the existing minimum across regions and faces. Taking only the largest individual print penalty does not reproduce the released arithmetic.

For example, on the back, gloss: "most_retained" deducts 275 points and a print_defect of severity "blemish" deducts another 275. Together the print region scores 1000 - 275 - 275 = 450: grade 4.5 when all other regions are ideal. Each on its own gives 725 points / grade 7. Neither penalty receives the generic front-defect multiplier, so the same pair on the front also gives 450 points / grade 4.5. This summing behavior is already covered by the frozen vector named v04 print_defect + gloss pool in the same region.

3. The de-minimis-only statement is about corners and edges#

The Corner & edge defects section says that only de-minimis flaws can keep a 10 and extends that statement to visible defects generally. Those statements need the section's local scope.

Correct explanation: Within the corner and edge severity classes, only de_minimis defects can retain grade 10, subject to each face's accumulated region penalties. Even the least costly minor corner/edge defect, a back minor edge, deducts 51 points and yields 949 points / grade 9. De-minimis is therefore necessary within those classes, but does not guarantee grade 10: enough de-minimis defects in one region can also cross the grade boundary.

This is not a rule for every defect category or every visible physical finding. For example, a single back surface/deep/dot deducts 35 points, yielding 965 points / grade 10. A single print_defect/slight deducts 25 points on either face, yielding 975 points / grade 10. These are existing arithmetic examples, not new classification guidance. The 0.2 distinction between a surface-layer gouge and a stock crease still applies.

Reproduce the examples#

Run this JavaScript from a checkout of the linked 0.2 release using Node's ES-module mode (node --input-type=module). Omitted observations receive the scorer's existing ideal defaults; these synthetic inputs are arithmetic examples, not evidence that a physical card was completely inspected.

import assert from "node:assert/strict";
        import { readFileSync } from "node:fs";
        import { score } from "./scoring.mjs";
        const rubric = JSON.parse(readFileSync("./rubric.json", "utf8"));
        assert.equal(rubric.rubric_version, "0.2");
        assert.deepEqual([Math.round(2.5), Math.round(3.5)], [3, 4]);
        const check = (input, points, grade) => {
          const result = score(input, rubric);
          assert.deepEqual([result.points, result.grade], [points, grade]);
          return result;
        };
        const centering = check({ front: { centering: { lr_pct: 60.3 } } }, 895, 8.5);
        assert.equal(centering.line_items[0].penalty, 105);
        const blemish = { region: "print_defect", severity: "blemish", x: 0.5, y: 0.5 };
        check({ back: { print: { gloss: "most_retained" } } }, 725, 7);
        check({ back: { defects: [blemish] } }, 725, 7);
        for (const face of ["front", "back"]) {
          const combined = check({ [face]: {
            print: { gloss: "most_retained" }, defects: [blemish],
          } }, 450, 4.5);
          assert.equal(combined.faces[face].regions.print, 450);
          assert.deepEqual(combined.line_items.map(item => item.penalty), [275, 275]);
          check({ [face]: { defects: [{ ...blemish, severity: "slight" }] } }, 975, 10);
        }
        check({ back: { defects: [{ region: "edge", edge: "top", severity: "minor" }] } }, 949, 9);
        check({ back: { defects: [{
          region: "surface", depth: "deep", size: "dot", x: 0.5, y: 0.5,
        }] } }, 965, 10);
        check({ back: { defects: Array.from({ length: 4 }, (_, i) => ({
          region: "corner", corner: ["tl", "tr", "bl", "br"][i], severity: "de_minimis",
        })) } }, 940, 9);
        console.log("All errata examples match Touchstone 0.2");
        

Implementer and consumer impact#

No scoring behavior, rubric version, penalties, schemas, conformance vectors, classification definitions, governance or licensing terms change. The frozen 0.2 artifacts and release tag remain unchanged. No 0.3 release or consumer version migration is introduced by this addendum.

Implementations already reproducing the released arithmetic need no scoring change. Implementers whose code follows the erroneous explanatory sentences should compare their results with the linked scorer and frozen vectors, then correct any implementation discrepancy. Such a repair can change their newly computed results; that is not a change to Touchstone's published arithmetic. Existing recorded results remain unchanged. Preserve their original inputs, rubric and provenance; record any corrected computation separately and link it to the original instead of silently overwriting history.

This addendum establishes no new physical accuracy, inspection completeness, or empirical grading claim. It is dated documentation of existing behavior.

Source: dated public addendum at pinned revision 2a00964.