Generates the bug index table in docs/bugs/README.md from each bug file's own header block, and checks it in CI. The prose above the table is hand-written and untouched; only the rows between the markers are generated, so a record file and its index row cannot disagree.
| Tier | tools |
| Role | tooling |
| Path | crates/tools/bugs-index |
| Edition | 2021 |
| Targets | tools-bugs-index, tools_bugs_index, cli |
| Public items | 15 across 1 module |
| Tests | 70 |
What it is for
The bug index table, generated from the bug records themselves.
docs/bugs/README.md is two documents in one file. Above the table is prose a person wrote — the naming rule, the status lifecycle, the record format, the rule that every bug lives both here and on GitHub. None of it is derived from anything and none of it is touched here.
The table is the other document. Every column it carries already exists in each record's own header block, so a hand-maintained table can only ever drift from the records it summarizes — and did: three separate sessions left an "index gap noted" paragraph in that file rather than a mechanism, and the count reached 57 record files against 33 rows.
This is the mechanism. render builds the rows from the records; check decides whether the file on disk matches. A record missing a field it is required to carry is a hard error naming the file and the field — never a blank cell, because a blank cell is how a table starts lying quietly.
Capabilities
crate root
The bug index table, generated from the bug records themselves.
| Item |
|---|
pub const BEGIN_MARKER: & str |
pub const END_MARKER: & str |
pub const UNRECORDED: & str |
fn parse_record(file_name : & str, body : & str) -> Result <BugRecord, IndexError> |
BugId
The bug index table, generated from the bug records themselves.
| Item |
|---|
pub struct BugId |
BugId :: fn parse(raw : & str) -> Result <Self, IndexError> |
BugId :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result |
BugRecord
The bug index table, generated from the bug records themselves.
| Item |
|---|
pub struct BugRecord |
fn render_table(records : & mut BugRecord) -> String |
IndexError
The bug index table, generated from the bug records themselves.
| Item |
|---|
pub enum IndexError |
IndexError :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result |
fn splice(readme : & str, table : & str) -> Result <String, IndexError> |
Proposal
Priority proposals, derived from the records rather than read out of them
| Item |
|---|
pub struct Proposal |
fn propose(record : & BugRecord, body : & str) -> Option <Proposal> |
fn render_report(proposals : & Proposal, unrecorded_issues : usize) -> String |
How to use it
No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.
Module structure
tools_bugs_index
propose
Public surface
`crate root`
| Item | What it is |
|---|---|
pub const BEGIN_MARKER: & str | Opening marker; everything between it and END_MARKER is generated. |
pub const END_MARKER: & str | Closing marker |
pub const UNRECORDED: & str | Cell written when a record names no GitHub issue |
pub struct BugId | A record's identifier, kept as series plus number so ordering is numeric |
BugId :: fn parse(raw : & str) -> Result <Self, IndexError> | Parses B-050 or BUG-0006 |
BugId :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result | — |
pub struct BugRecord | One record, reduced to the columns the index shows. |
pub enum IndexError | Every way this can refuse |
IndexError :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result | — |
fn parse_record(file_name : & str, body : & str) -> Result <BugRecord, IndexError> | Builds a record from one file's name and contents |
fn render_table(records : & mut BugRecord) -> String | Renders the table body: header row, separator, then one row per record, ordered by series and number rather than by directory listing. |
fn splice(readme : & str, table : & str) -> Result <String, IndexError> | Replaces the marked region of readme, leaving every other byte alone |
`propose`
| Item | What it is |
|---|---|
pub struct Proposal | A band, and the words in the record that put it there. |
fn propose(record : & BugRecord, body : & str) -> Option <Proposal> | Bands one record from the words it uses about itself. |
fn render_report(proposals : & Proposal, unrecorded_issues : usize) -> String | Renders the dated operational report |
No pub use re-exports: every item above is declared in this crate.
Boundary
Depends on no other workspace tier.
Shares tier tools with 84 other crates: tools-advisory-reach, tools-archive-guard, tools-artifact-scaffold, tools-ask-ai-core, tools-ask-ais, tools-ask-gemini, tools-book, tools-book-report, … (84 total).
_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._
Where it sits
| Tier (ontology) | tools |
| Architectural role (taxonomy) | tooling |
| Location | crates/tools/bugs-index |
| Vocabulary in force (lexicon) | current |
Dependencies
Runtime, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
anyhow | ^1 | — | no | always |
Development, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
tempfile | ^3 | — | no | always |
Build. None.
Depended on by. Nothing in this workspace.
Feature flags
No Cargo features are defined: every capability is unconditional, so no consumer can receive a half-wired crate.
Targets
| Kind | Name | Source |
|---|---|---|
| bin | tools-bugs-index | `src/main.rs` |
| lib | tools_bugs_index | `src/lib.rs` |
| test | cli | `tests/cli.rs` |
Error model
| Error type | Named by |
|---|---|
IndexError | parse_record, splice |
Operational characteristics
| Property | Evidence |
|---|---|
| async public surface | none detected |
| async runtime | none detected |
| database access | none detected |
| network I/O | none detected |
| unsafe code | none detected |
| environment variables | none detected |
No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.
Configuration
No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.
Related capabilities
No workspace crate depends on this one.
Verification
| Kind | Count |
|---|---|
| Unit tests | 59 |
| Integration tests | 11 |
| Examples | 0 |
| Doctests | 0 |
Evidence by module. How often each public module is named by something executable.
| Module | Tests | Examples | Consumers |
|---|---|---|---|
crate root | 9 | 0 | 0 |
propose | 3 | 0 | 0 |
What the tests establish, by name:
a_directory_with_no_gaps_reports_none—tests/cli.rsa_missing_bugs_directory_is_an_error—tests/cli.rsa_second_write_is_a_no_op_and_says_so—tests/cli.rsan_unparseable_record_stops_the_run_and_names_it—tests/cli.rscheck_fails_when_the_readme_does_not_match_the_records—tests/cli.rscheck_passes_once_the_index_has_been_written—tests/cli.rspropose_priorities_prints_a_report_naming_the_records—tests/cli.rspropose_priorities_writes_the_report_where_it_is_told_to—tests/cli.rsrecords_stating_no_priority_or_no_issue_are_reported_as_gaps—tests/cli.rsthe_report_counts_the_records_that_cite_no_issue—tests/cli.rsthe_table_is_spliced_between_the_markers_and_the_prose_survives—tests/cli.rsa_bolded_word_without_a_colon_is_prose_and_the_scan_continues_past_it—src/lib.rsa_bullet_style_header_line_is_read_like_a_plain_one—src/lib.rsa_field_below_the_header_rule_is_not_read_into_the_table—src/lib.rsa_field_whose_value_is_empty_yields_an_empty_string—src/lib.rsa_generated_readme_is_a_fixed_point—src/lib.rsa_missing_field_names_the_file_and_the_field_rather_than_blanking_the_cell—src/lib.rsa_plain_header_line_outranks_a_table_row_naming_the_same_field—src/lib.rsa_priority_with_no_p_token_is_carried_through_verbatim—src/lib.rsa_record_naming_no_issue_is_marked_unrecorded_not_invented—src/lib.rsa_record_stating_no_priority_is_marked_unrecorded_not_triaged_by_a_program—src/lib.rsa_table_row_that_is_not_a_field_is_not_mistaken_for_one—src/lib.rsa_table_shaped_header_is_read_like_a_plain_one—src/lib.rsa_value_ends_where_the_next_bolded_field_begins—src/lib.rsa_value_stops_at_the_next_field_on_the_same_line—src/lib.rsa_value_with_no_following_field_is_kept_whole—src/lib.rsa_well_formed_record_parses_into_a_row—src/lib.rsan_empty_field_value_counts_as_missing—src/lib.rsan_end_marker_before_the_begin_marker_and_nowhere_after_is_refused—src/lib.rsan_unfamiliar_github_cell_is_passed_through_rather_than_guessed_at—src/lib.rs- _… 40 more_
Documentation coverage
| Measure | Documented | Total |
|---|---|---|
| Public items with rustdoc | 13 | 15 |
Public modules with a //! block | 1 | 1 |
pie showData
title Public items with rustdoc
"Documented" : 13
"No rustdoc detected" : 2
Metrics
| Metric | Value |
|---|---|
| Rust source files | 3 |
| Source lines | 1761 |
| Code lines | 1296 |
| Public API items | 15 |
| Public modules | 1 |
| Tests | 70 |
| Examples | 0 |
| Cargo features | 0 |
| Direct runtime dependencies | 1 |
| Workspace reverse dependencies | 0 |
pie showData
title Public API by kind
"constant" : 3
"enum" : 1
"function" : 5
"method" : 3
"struct" : 3
pie showData
title Rust source composition
"Code" : 1296
"Blank or comment" : 465
Generation
Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.