guido 0.8.0

A reactive Rust GUI library using wgpu for Wayland layer shell widgets
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
//! The workflow describes itself, and the description has to add up.
//!
//! `AGENTS.md`, `/implement` and the pull request template describe each other:
//! they count their own steps in prose, next to lists somebody edits, and they
//! point at files by name. Inserting a step is exactly when those stop
//! matching, and a count in prose is the part a person is worst at checking.
//!
//! Mostly this does not read the words. It counts headings and list markers,
//! compares them to the numbers the prose claims, checks that the files this
//! documentation names exist, and checks the two orderings the workflow depends
//! on: the review comes after the commits, because its criteria ask about them,
//! and the pass that edits the code comes before every pass that checks it.
//!
//! Where it does read them, it is for a sentence that has to appear in two
//! documents at once: the review's three levels, and the rule about researching
//! a design decision. Pinning a sentence is a poor test of whether a rule is
//! followed and the only test there is of whether both copies still say it.

use std::path::{Path, PathBuf};

fn repo() -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR")).to_path_buf()
}

/// Everything an agent is handed, found rather than listed: a command added
/// tomorrow is scanned tomorrow, which is the staleness this file exists to
/// catch happening to this file.
fn agent_facing_documents() -> Vec<PathBuf> {
    let mut found = vec![repo().join("AGENTS.md")];
    for dir in [".claude/commands", ".claude/agents", ".claude/skills"] {
        let mut here = Vec::new();
        collect_markdown(&repo().join(dir), &mut here);
        assert!(
            !here.is_empty(),
            "no markdown under {dir}: scanning nothing"
        );
        found.extend(here);
    }
    found
}

fn collect_markdown(dir: &Path, out: &mut Vec<PathBuf>) {
    let Ok(entries) = std::fs::read_dir(dir) else {
        return;
    };
    for entry in entries.flatten() {
        let path = entry.path();
        if path.is_dir() {
            collect_markdown(&path, out);
        } else if path.extension().is_some_and(|e| e == "md") {
            out.push(path);
        }
    }
}

fn read(relative: &str) -> String {
    std::fs::read_to_string(repo().join(relative))
        .unwrap_or_else(|e| panic!("cannot read {relative}: {e}"))
}

/// The backticked spans of a markdown file, with fenced blocks removed first.
///
/// Pairing backticks by parity over a whole file holds only as long as every
/// fence contributes an even number of them. One apostrophe-free shell string
/// with a stray backtick shifts the parity and every span after it is read as
/// the gap between spans — so the scan finds nothing and the test passes for
/// the worst possible reason. `skill_references.rs` already does this; this is
/// the same fix.
fn backticked(text: &str) -> Vec<String> {
    let mut prose = String::new();
    let mut rest = text;
    while let Some(start) = rest.find("```") {
        prose.push_str(&rest[..start]);
        let after = &rest[start + 3..];
        match after.find("```") {
            Some(end) => rest = &after[end + 3..],
            None => {
                rest = "";
                break;
            }
        }
    }
    prose.push_str(rest);
    prose
        .split('`')
        .skip(1)
        .step_by(2)
        .map(str::to_string)
        .collect()
}

/// A file's prose with its line wrapping removed, so that a sentence pinned by
/// this file can be re-wrapped by whoever edits the document. Pinning a literal
/// against wrapped markdown fails the moment a word is added ahead of it, which
/// is a build failure for a reason nobody meant.
fn unwrapped(text: &str) -> String {
    text.split_whitespace().collect::<Vec<_>>().join(" ")
}

/// From `needle` to the next `until`, or to the end. Two sections here are found
/// by where they start rather than by index: a `## ` heading runs to the next
/// heading, a numbered item runs to the blank line after it.
fn section_from<'a>(text: &'a str, needle: &str, until: &str) -> &'a str {
    let start = text
        .find(needle)
        .unwrap_or_else(|| panic!("this document has no `{needle}`"));
    let rest = &text[start..];
    // Searched past the needle, so a delimiter the needle itself begins with
    // cannot end the section on its own first character.
    match rest[needle.len()..].find(until) {
        Some(offset) => &rest[..needle.len() + offset],
        None => rest,
    }
}

/// The `## N. Title` section whose heading mentions `about`, to the next
/// heading. Found by the heading's words rather than its number, because
/// inserting a step renumbers it — which is what this file exists to survive.
fn step_about<'a>(text: &'a str, about: &str) -> &'a str {
    let heading = text
        .lines()
        .filter(|line| line.starts_with("## "))
        .find(|line| line.to_ascii_lowercase().contains(about))
        .unwrap_or_else(|| panic!("no step about `{about}`"));
    section_from(text, heading, "\n## ")
}

/// "six" -> 6, for the counts that are written as words.
fn number_word(word: &str) -> Option<usize> {
    const WORDS: &[&str] = &[
        "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten",
    ];
    let word = word.trim_matches(|c: char| !c.is_ascii_alphabetic());
    let word = word.to_ascii_lowercase();
    WORDS.iter().position(|w| *w == word)
}

/// The first number word anywhere in a sentence, so that rewording the sentence
/// does not fail the build for a reason nobody meant.
fn number_in(sentence: &str) -> Option<usize> {
    sentence.split_whitespace().find_map(number_word)
}

/// The numbers at the start of `## 3. Something` headings, in order.
fn numbered_headings(text: &str) -> Vec<usize> {
    text.lines()
        .filter_map(|line| line.strip_prefix("## "))
        .filter_map(|rest| rest.split('.').next()?.parse().ok())
        .collect()
}

/// The numbers at the start of `3. **Something**` list items, in order.
fn numbered_items(text: &str) -> Vec<usize> {
    text.lines()
        .filter_map(|line| {
            let (head, rest) = line.split_once(". ")?;
            if rest.starts_with("**") {
                head.parse().ok()
            } else {
                None
            }
        })
        .collect()
}

fn assert_contiguous(numbers: &[usize], what: &str) {
    assert!(
        !numbers.is_empty(),
        "{what}: found no numbered steps at all"
    );
    let expected: Vec<usize> = (1..=numbers.len()).collect();
    assert_eq!(
        numbers,
        expected,
        "{what}: the steps are numbered {numbers:?}, which is not 1..{}",
        numbers.len()
    );
}

#[test]
fn implement_numbers_its_steps_in_order() {
    let text = read(".claude/commands/implement.md");
    assert_contiguous(&numbered_headings(&text), "/implement");
}

#[test]
fn agents_md_counts_the_steps_it_lists() {
    let text = read("AGENTS.md");
    // To the next heading, not to the end of the file: a numbered list further
    // down the document is not this list.
    let section = section_from(&text, "## Working on a change", "\n## ");
    let steps = numbered_items(section);
    assert_contiguous(&steps, "AGENTS.md");

    // "`/implement <issue>` does all six."
    let claim = section
        .lines()
        .find(|line| line.contains("does all "))
        .expect("AGENTS.md never says how many steps /implement does");
    let word = claim
        .split("does all ")
        .nth(1)
        .and_then(|rest| rest.split(['.', ' ']).next())
        .expect("cannot read the number out of that sentence");
    let claimed =
        number_word(word).unwrap_or_else(|| panic!("`{word}` is not a number this test knows"));

    assert_eq!(
        claimed,
        steps.len(),
        "AGENTS.md lists {} steps and then says /implement does all {word}",
        steps.len()
    );
}

#[test]
fn the_pull_request_template_asks_as_many_questions_as_it_says() {
    let text = read(".github/pull_request_template.md");
    let sections = text.lines().filter(|l| l.starts_with("## ")).count();

    let claim = text
        .lines()
        .find(|line| line.contains(" questions"))
        .expect("the template never says how many questions it asks");
    let claimed =
        number_in(claim).unwrap_or_else(|| panic!("no number this test knows in: {claim}"));

    assert_eq!(
        claimed, sections,
        "the template has {sections} sections and says: {claim}"
    );
}

/// The review step keeps no copy of the reviewer's criteria — it points at the
/// file that holds them. A pointer nobody checks is how that file gets moved and the step
/// quietly stops saying anything.
///
/// This checks every repository path the agent-facing documentation names, not
/// only that one: a backticked span that looks like a path in this tree has to
/// resolve to something.
#[test]
fn the_documentation_points_at_files_that_exist() {
    let mut missing = Vec::new();

    for doc in agent_facing_documents() {
        let name = doc
            .strip_prefix(repo())
            .unwrap_or(&doc)
            .display()
            .to_string();
        let text =
            std::fs::read_to_string(&doc).unwrap_or_else(|e| panic!("cannot read {name}: {e}"));
        for span in backticked(&text) {
            let looks_like_a_path = span.contains('/')
                && !span.contains(' ')
                && (span.ends_with(".rs")
                    || span.ends_with(".md")
                    || span.ends_with(".toml")
                    || span.ends_with(".yml")
                    || span.ends_with('/'));
            // `target/` is build output: the documentation points at things
            // that appear there when a test fails, and they are supposed not
            // to exist the rest of the time.
            if !looks_like_a_path || span.starts_with("target/") {
                continue;
            }
            let path = repo().join(span.trim_end_matches('/'));
            if !path.exists() {
                missing.push(format!("  {name}: `{span}`"));
            }
        }
    }

    assert!(
        missing.is_empty(),
        "documentation names {} path(s) that do not exist:\n{}",
        missing.len(),
        missing.join("\n")
    );
}

/// The review runs *after* the commits, because its criteria ask about them —
/// whether they are atomic, whether their subjects say what is now true. Swap
/// the two steps and the step still reads sensibly while asking questions
/// nothing can answer, which is the state this whole change started from.
#[test]
fn the_review_comes_after_the_commits() {
    let text = read(".claude/commands/implement.md");

    let step = |needle: &str| -> usize {
        text.lines()
            .filter_map(|line| line.strip_prefix("## "))
            .find(|heading| heading.to_ascii_lowercase().contains(needle))
            .and_then(|heading| heading.split('.').next()?.parse().ok())
            .unwrap_or_else(|| panic!("/implement has no step about `{needle}`"))
    };

    // Matched on the verb, not on the whole sentence: AGENTS.md spells this
    // step "read by something that did not write it" and /implement spells it
    // "somebody", and neither wording is the thing being asserted.
    let commit = step("commit");
    let review = step("read by");
    assert!(
        review > commit,
        "the review is step {review} and the commits are step {commit}: its \
         criteria ask about commits that would not exist yet"
    );

    // The cleanup applies what it finds instead of reporting it, so where it
    // sits decides whether anything checks its work. Before the harness, it is
    // re-tested; before the commits, its edits land inside them; before the
    // review, they are read like everything else. Below any of the three and
    // something ships that nothing looked at.
    let cleanup = step("clean it up");
    // "run the harness", not "harness": the cleanup's own heading says it runs
    // before the harness sees the change again, and a needle that matches both
    // finds the first one.
    let harness = step("run the harness");

    // A heading in the right position always survives a renumber, so the
    // ordering alone would let the step be emptied in one file and dropped
    // from the other. Both documents have to name the tool that does it.
    for (doc, name) in [(&text, "/implement"), (&read("AGENTS.md"), "AGENTS.md")] {
        assert!(
            doc.contains("`/simplify`"),
            "{name} never names `/simplify`, so the cleanup is a heading with \
             nothing behind it"
        );
    }

    assert!(
        cleanup < harness && cleanup < commit && cleanup < review,
        "the cleanup is step {cleanup}, the harness {harness}, the commits \
         {commit} and the review {review}: a pass that edits the code has to \
         run before every pass that checks it"
    );
}

/// `/implement` ends by saying how many lines to report back, and the template
/// says how many questions it asks. They are the same list, so they are the
/// same number — and a count in prose beside a list is the thing this file
/// exists to watch.
#[test]
fn the_report_back_matches_the_template() {
    let implement = read(".claude/commands/implement.md");
    let template = read(".github/pull_request_template.md");

    let claim = implement
        .lines()
        .find(|line| line.contains("report back, in "))
        .expect("/implement never says how many lines to report back");
    let claimed =
        number_in(claim).unwrap_or_else(|| panic!("no number this test knows in: {claim}"));
    let sections = template.lines().filter(|l| l.starts_with("## ")).count();

    assert_eq!(
        claimed, sections,
        "the template asks {sections} questions and /implement says: {claim}"
    );
}

/// The three mutations the counting does not see: strip the review step down to
/// its heading, take the review section out of the template, or drop the review
/// from AGENTS.md's list. Each leaves every count consistent and removes the
/// change entirely.
///
/// Found by its heading rather than its number, because inserting a step ahead
/// of it renumbers it — which is exactly what this file exists to survive.
#[test]
fn the_review_step_still_says_what_it_is_for() {
    let implement = read(".claude/commands/implement.md");
    let review_step = implement
        .split("\n## ")
        .find(|section| {
            // The heading, not the body: a neighbouring step that mentions the
            // review in its prose is not the review.
            section
                .lines()
                .next()
                .is_some_and(|heading| heading.to_ascii_lowercase().contains("read by"))
        })
        .expect("/implement has no step about having the change read");

    assert!(
        review_step.contains(".claude/agents/reviewer.md"),
        "the review step keeps no copy of the criteria, so naming the file that \
         holds them is the whole of it — and it does not"
    );
    assert!(
        review_step.contains("One pass"),
        "the review step does not say it is one pass, and a review with no \
         stopping rule is a review that runs until somebody gets tired"
    );
    assert!(
        review_step.contains("Blocks") && review_step.contains("Note"),
        "the review step does not say what to do with each level of finding"
    );
    assert!(
        review_step.contains("did not run"),
        "the review step does not say what to do when the review does not run, \
         and a review that did not run looks exactly like one that found nothing"
    );

    let template = read(".github/pull_request_template.md");
    assert!(
        template
            .lines()
            .any(|l| l.starts_with("## ") && l.contains("review")),
        "the pull request template has no section asking what the review found"
    );

    let agents = read("AGENTS.md");
    assert!(
        agents.contains("`reviewer` subagent"),
        "AGENTS.md's list of what a change goes through never mentions the \
         reviewer, so the step exists only in the command"
    );
}

/// The levels live in the reviewer's own file; the command only says what to do
/// with each. So the command is the copy, and a test that reads only the copy
/// defends the wrong document: delete the levels from `reviewer.md` and the
/// command goes on sorting findings into categories nothing produces.
///
/// This asserts they agree, which is the only thing that keeps two files
/// describing one mechanism honest.
#[test]
fn the_reviewer_and_the_command_use_the_same_levels() {
    const LEVELS: [&str; 3] = ["Blocks", "Worth answering", "Note"];

    let reviewer = read(".claude/agents/reviewer.md");
    let implement = read(".claude/commands/implement.md");

    for level in LEVELS {
        assert!(
            reviewer.contains(level),
            "the reviewer never defines `{level}`, so nothing it reports can \
             carry that level and the command sorts into an empty box"
        );
        assert!(
            implement.contains(level),
            "/implement never says what to do with `{level}`"
        );
    }

    assert!(
        reviewer.contains("how many block"),
        "the reviewer gives no verdict, so `zero blocking findings is the pass` \
         has nothing to read"
    );
}

/// The research rule lives in two places, and a rule that is only in the
/// contract is a rule nothing invokes.
///
/// `AGENTS.md` states it; `/spec` is where it is acted on, because that is the
/// command that writes alternatives down, and it names the section of the issue
/// the sources go in. Deleting the rule from either leaves the other describing
/// a step that does not happen; deleting the section leaves the rule asking for
/// something the issue has no room for.
///
/// What this cannot say is whether the research was *done* — only that the
/// contract asks for it and the issue has somewhere to put the answer.
#[test]
fn researching_a_design_decision_is_asked_for_where_the_alternatives_are_written() {
    let agents = unwrapped(&read("AGENTS.md"));
    let spec = unwrapped(&read(".claude/commands/spec.md"));

    const RULE: &str = "A design decision that is not obvious is researched before it is proposed.";
    assert!(
        agents.contains(RULE),
        "AGENTS.md does not carry the research rule, so nothing states it"
    );
    assert!(
        spec.contains(RULE),
        "/spec is the command that writes alternatives down and does not ask \
         for the research behind them — the rule would exist only in the \
         contract, where nothing invokes it"
    );

    // Where the answer goes. A rule asking for something the issue has no room
    // for degrades to "mention it somewhere", so `/spec` names the section, and
    // the body it enumerates has to contain it.
    const SLOT: &str = "**Prior art**";
    assert!(
        spec.contains(SLOT),
        "/spec asks for research and its issue body has no {SLOT} for the \
         answer, so the sources have nowhere to go"
    );
}

/// The inventory test checks that a reason is written; the reviewer asks
/// whether it holds, so both have to point at the same table.
#[test]
fn a_new_thread_local_is_questioned_where_it_is_listed() {
    let agents = unwrapped(&read("AGENTS.md"));
    let reviewer = unwrapped(&read(".claude/agents/reviewer.md"));

    const TEST: &str = "tests/ambient_state_inventory.rs";
    const TABLE: &str = "**Ambient state**";
    for (name, text) in [("AGENTS.md", &agents), ("the reviewer", &reviewer)] {
        assert!(
            text.contains(TEST) && text.contains(TABLE),
            "{name} does not name both {TEST} and the {TABLE} table, so one half \
             of the thread-local rule is missing from it"
        );
    }
    assert!(
        reviewer.contains("could carry the value"),
        "the reviewer names the table but no longer asks whether the reason holds"
    );
}

/// Four of the template's five questions are answered by the change and die
/// with it. **Left undone** is the one that points forward, and the place it is
/// written is a merged pull request's body — which nobody opens again. So the
/// answer needs a home outside the pull request, made in the same act as the
/// sentence, or the sentence is where the work goes to be forgotten.
///
/// `AGENTS.md` owns the rule and the reason for it; `/implement` and the
/// template carry the instruction and point back. So all three name it and only
/// one explains it — and all three are pinned here, the contract included,
/// because the document that would be reworded first is the one that reads
/// least like a checklist.
///
/// Pinning a sentence says nothing about whether an issue was ever filed. It
/// says the ask survives an edit to any one of the three, which is the failure
/// that actually happened.
#[test]
fn what_is_left_undone_is_given_a_home_outside_the_pull_request() {
    const RULE: &str = "gets an issue in the same act";

    // Where each document says it, not merely that it does somewhere. The
    // template's comment is read while the body is being filled in; a sentence
    // that drifts into another section is a sentence nobody sees at the moment
    // it applies, and a whole-file search cannot tell that from a rule that is
    // still in place.
    let agents = read("AGENTS.md");
    let implement = read(".claude/commands/implement.md");
    let template = read(".github/pull_request_template.md");
    let step_seven = section_from(&agents, "**Open the pull request**", "\n\n");

    for (name, section) in [
        ("AGENTS.md's step 7", step_seven),
        (
            "/implement's step about the pull request",
            step_about(&implement, "pull request"),
        ),
        (
            "the template's `Left undone`",
            section_from(&template, "## Left undone", "\n## "),
        ),
    ] {
        assert!(
            unwrapped(section).contains(RULE),
            "{name} does not say that what is left undone `{RULE}`, so it is \
             recorded only where a merged pull request keeps it"
        );
    }

    // And the contract's own enumeration of what the template asks. Stopping at
    // four of five is how the question that outlives the pull request ends up
    // absent from the document that introduces the step.
    assert!(
        unwrapped(step_seven)
            .to_ascii_lowercase()
            .contains("left undone"),
        "AGENTS.md's step 7 lists what the template asks and leaves out the one \
         question whose answer points past this change"
    );
}

/// And the rule that says *which* of them earns one.
///
/// "Whatever has to outlive this change gets an issue" has no threshold, so
/// every observation clears it. Measured on 2026-09-02: fifteen of the
/// thirty-six open issues were raised by our own reviews of our own pull
/// requests, one of them about the rule that raises them. A workflow whose
/// output is its own input does not converge.
///
/// The reason for the rule is unchanged — a follow-up written only in a merged
/// body is written down and lost in one motion. What it needed was a bar, and
/// the bar is a question with three answers rather than a size, because size is
/// what everybody argues about and nobody measures.
///
/// Pinned in the two places an agent reads while deciding: the contract, and
/// the reviewer's own description of what a note is for. The reviewer is the
/// one that leaked — it said a note goes in the pull request *or* an issue and
/// gave no way to choose, which for anything trying to be thorough reads as
/// "an issue".
#[test]
fn an_issue_is_what_clears_a_bar_rather_than_whatever_is_left_over() {
    const TRIAGE: &str = "worse off";

    let agents = read("AGENTS.md");
    let reviewer = read(".claude/agents/reviewer.md");
    let template = read(".github/pull_request_template.md");

    for (name, section) in [
        (
            "AGENTS.md's step 7",
            section_from(&agents, "**Open the pull request**", "\n\n## "),
        ),
        (
            "the template's `Left undone`",
            section_from(&template, "## Left undone", "\n## "),
        ),
        (
            "the reviewer's `Note` level",
            section_from(&reviewer, "- **Note.**", "\n\n"),
        ),
    ] {
        assert!(
            unwrapped(section).contains(TRIAGE),
            "{name} does not ask who is `{TRIAGE}` today, so nothing separates \
             the follow-up that earns an issue from the one that is a nit"
        );
    }

    // The reviewer used to offer the two homes and no way to pick between
    // them. That exact phrasing is what the bar replaces, so it must not come
    // back — a reworded rule elsewhere is survivable, this sentence is not.
    assert!(
        !unwrapped(&reviewer).contains("the pull request or an issue"),
        "the reviewer offers a note both homes and no criterion, which is the \
         sentence the bar exists to replace"
    );
}