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
16 changes: 8 additions & 8 deletions .trinity/seals/claw_ClawTokenShape.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@
}
],
"config": "gen=c,rust,verilog,zig;tests=zig",
"gen_hash_c": "sha256:793e236c843d71659823ebee20444c902a3abf1b3f1dbda763ca42b54dc59c51",
"gen_hash_rust": "sha256:28c9289a2ea5104684dc941b3e02fa0004d5257adcd00c4593bae415f10c7df2",
"gen_hash_verilog": "sha256:7973bacc8961200f38e14563f04b61e6e9dc8b43e442fcdda85fa62dc7faed7a",
"gen_hash_zig": "sha256:30ab84bff278fbba91a98f007ba0493da30b0ef89a280c4aaffd909c0b64dd7d",
"gen_hash_c": "sha256:6ffa5bc072e7016706cd0d8525170b09682f4146920e26f52dd7b3d72cfefcff",
"gen_hash_rust": "sha256:f052387f815f371e380d604bcdb90bb46486588e288fdde3ca1efa798093030e",
"gen_hash_verilog": "sha256:aab1d5e59d3e371756e79e33076be1b50ddf8a7feb0a6aa767e9582c85ddb8ca",
"gen_hash_zig": "sha256:e1d6217b8196e2ea7d721ff7dbf85b8143f34309aae5a86d5f6c10c630e8e372",
"module": "ClawTokenShape",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-18T17:57:50Z",
"sealed_at": "2026-10-18T21:47:51Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:b326da148e0d837cb05228f27efdcdf0faf22d85b0a0693a791052caf44f8b04",
"spec_hash": "sha256:fa1c7d25a6a9374f2dd1ffe1ad47a6bfb0437a0580655ab40cc30c20e58760c7",
"spec_path": "specs/claw/token_shape.t27",
"tests": {
"failed": 0,
"failing": [],
"forced": false,
"passed": 10,
"total": 10,
"passed": 16,
"total": 16,
"vacuous": 0
},
"toolchain": {
Expand Down
104 changes: 104 additions & 0 deletions specs/claw/token_shape.t27
Original file line number Diff line number Diff line change
Expand Up @@ -351,3 +351,107 @@ test a_job_that_says_red_on_purpose_is_not_judged {
assert n == 127;
assert token_shape_count(&t, n) == 0;
}

// Tests below were added by the mutation sweep of #10673 (tick 18); each names the mutants it kills.

// span_has `<=` -> `<`: a needle that ends exactly at the end of its line.
test a_note_at_the_end_of_its_line_counts {
var t : [512]u8 = undefined;
var n : usize = put_str(&t, 512, 0, "jobs:\n", 6);
n = put_str(&t, 512, n, " claw-a:\n", 10);
n = put_str(&t, 512, n, " steps:\n", 11);
n = put_str(&t, 512, n, " - {id: tok, continue-on-error: true, uses: actions/create-github-app-token@v2}\n", 85);
n = put_str(&t, 512, n, " - if: steps.tok.outcome == 'failure'\n", 43);
n = put_str(&t, 512, n, " run: echo note\n", 23);
assert n == 178;
assert token_shape_count(&t, n) == 0;
}

// top `e > s` -> `e >= s` and is_job_header's empty-name `return false` -> `return true`:
// an empty line and a line of two spaces inside a job end neither the job nor `jobs:`.
test blank_and_two_space_lines_do_not_end_a_job {
var t : [512]u8 = undefined;
var n : usize = put_str(&t, 512, 0, "jobs:\n", 6);
n = put_str(&t, 512, n, " claw-a:\n", 10);
n = put_str(&t, 512, n, " steps:\n", 11);
n = put_str(&t, 512, n, " - {id: tok, continue-on-error: true, uses: actions/create-github-app-token@v2}\n", 85);
n = put_str(&t, 512, n, "\n", 1);
n = put_str(&t, 512, n, " \n", 3);
n = put_str(&t, 512, n, " - {if: steps.tok.outcome == 'failure', run: echo note}\n", 61);
assert n == 177;
assert token_shape_count(&t, n) == 0;
}

// is_job_header `or` -> `and` and its `return false` -> `return true` on '#' or '-':
// a commented-out job is not a job, so the note after it still belongs to claw-a.
test a_commented_out_job_header_is_not_a_job {
var t : [512]u8 = undefined;
var n : usize = put_str(&t, 512, 0, "jobs:\n", 6);
n = put_str(&t, 512, n, " claw-a:\n", 10);
n = put_str(&t, 512, n, " steps:\n", 11);
n = put_str(&t, 512, n, " - {id: tok, continue-on-error: true, uses: actions/create-github-app-token@v2}\n", 85);
n = put_str(&t, 512, n, " #build:\n", 10);
n = put_str(&t, 512, n, " - {if: steps.tok.outcome == 'failure', run: echo note}\n", 61);
assert n == 183;
assert token_shape_count(&t, n) == 0;
}

// item `ind > 2` -> `ind >= 2`: a step is deeper than its job; a list item at the job's own indent is not one.
// The `or` -> `and` on the in-step key check: a key-shaped line deep inside a `run: |` block is not a key of the step.
test only_a_step_or_its_own_key_can_mint {
var t : [256]u8 = undefined;
var n : usize = put_str(&t, 256, 0, "jobs:\n", 6);
n = put_str(&t, 256, n, " claw-a:\n", 10);
n = put_str(&t, 256, n, " - {id: tok, uses: actions/create-github-app-token@v2}\n", 56);
assert n == 72;
assert token_shape_count(&t, n) == 0;
var b : [256]u8 = undefined;
var m : usize = put_str(&b, 256, 0, "jobs:\n", 6);
m = put_str(&b, 256, m, " plain:\n", 9);
m = put_str(&b, 256, m, " steps:\n", 11);
m = put_str(&b, 256, m, " - run: |\n", 15);
m = put_str(&b, 256, m, " uses: actions/create-github-app-token@v2\n", 53);
assert m == 94;
assert token_shape_count(&b, m) == 0;
}

// is_job_header, line by line: trailing spaces and a CR are allowed after the colon (kills `!=` -> `==`
// and `and` -> `or` on the tail check); anything else after it, an empty name, a space in the name or no
// colon at all is not a header (kills `i + 1` -> `i + 2`, `>` -> `>=` on the name length, both
// `return false` -> `return true`, and the scan running past the line on `<` -> `<=`).
test only_a_bare_name_and_a_colon_is_a_job_header {
var t : [32]u8 = undefined;
var n : usize = put_str(&t, 32, 0, " claw-a: x\n", 13);
t[11] = 13;
assert n == 13;
assert is_job_header(&t, 0, 12) == true;
n = put_str(&t, 32, 0, " a:b\n", 6);
assert is_job_header(&t, 0, 5) == false;
n = put_str(&t, 32, 0, " #build:\n", 10);
assert is_job_header(&t, 0, 9) == false;
n = put_str(&t, 32, 0, " :\n", 4);
assert is_job_header(&t, 0, 3) == false;
n = put_str(&t, 32, 0, " a b:\n", 7);
assert is_job_header(&t, 0, 6) == false;
n = put_str(&t, 32, 0, " \n", 3);
assert is_job_header(&t, 0, 2) == false;
// a last line with no newline in a reused buffer: the stale byte at e is a colon, and the scan must stop before it
n = put_str(&t, 32, 0, " oops:\n", 8);
assert n == 8;
assert is_job_header(&t, 0, 6) == false;
}

// put_span `x < cap` -> `x <= cap`: a clipped copy writes nothing at index cap.
test a_clipped_span_writes_nothing_at_cap {
var t : [16]u8 = undefined;
const n : usize = put_str(&t, 16, 0, "abcdef", 6);
var d : [8]u8 = undefined;
var k : usize = 0;
while (k < 8) {
d[k] = 0;
k += 1;
}
assert put_span(&d, 4, 0, &t, 0, n) == 6;
assert d[3] == 'd';
assert d[4] == 0;
}
Loading