). Previously any line beginning with `..` was\nrejected as a title, so the marker line became a paragraph and the\nfollowing block lost its title.\n\nCloses #957\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Recognize block title with a leading period (`..name`) (#958)", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-25T15:51:18Z", "body_truncated": false, "is_coding_agent": true }, { "oid": "320ce4bdfac06a8ba4b9a1e1c684c0587ee43276", "body": null, "is_bot": false, "headline": "chore(asciidoc-parser): release v0.27.0 (#941)", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-25T04:25:25Z", "body_truncated": false, "is_coding_agent": false }, { "oid": "aa767ff5cde506e86b4361ababa6c0266d9c44ac", "body": "* fix: capture block metadata on list items instead of dropping it\n\n`ListBlock::parse` built each list item with an empty `BlockMetadata`, so a\ntitle, anchor, or attribute list written directly before a list item's marker\nwas silently discarded. Worse, because the empty metadata could not parse past\n[…]\nt for them, restoring the original fast path for\nthe common paragraph case.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Capture block metadata on list items instead of dropping it (#954)", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-25T04:22:04Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "c4c7294195664e7d3005c7cc48796c9a2fdc9fcd", "body": "* chore: Pin GitHub Actions to specific commit SHAs\n\nReplace mutable version tags with pinned commit SHAs (each with a\ntrailing version comment) across ci.yml and pr_title.yml, following the\npattern already used in release.yml. Each SHA is the commit its tag or\nbranch currently resolves to. This har\n[…]\n currently resolves to) so all\nthree workflows share a single checkout SHA.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "chore: Pin GitHub Actions to specific commit SHAs (#955)", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-25T04:04:49Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "b34f99e95e10c41ff93d4c26edf3ae455560998c", "body": "Part of the #939 TEMPORARY-marker audit. The `#[allow(...)]` attributes\nguarding test scaffolding are no longer warranted:\n\n- `assert_dom/virtual_dom.rs`: the `VirtualNode` builder helpers are now\n used throughout the DOM assertions, so the blanket `#[allow(dead_code)]`\n on the impl block is remov\n[…]\nunconstructed, so per the audit guidance they (and their\n `Debug` / equality arms) are removed rather than left behind an allow.\n\nCloses #949.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "chore: Remove consumed 'while building' scaffolding allows (#949) (#952)", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-25T03:42:14Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "8944d9105400fdba9e9d7fa29d266ad1ecf38818", "body": "…o_name (#953)\n\n`Span::take_ident` borrowed Rust's identifier definition (leading\nalphabetic/underscore, then alphanumerics/underscores) because\n\"identifier\" is not crisply defined in the AsciiDoc documentation. Its\nuse was already discouraged in favor of more specific helpers.\n\nThere was a single c\n[…]\nng digit) is now parsed and then rejected as unrecognized\nrather than rejected at the name-capture stage, with identical results.\n\nCloses #948.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "refactor: Replace Span::take_ident with spec-grounded take_block_macr…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-25T03:40:42Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "78d9373b0f7d80bbd965d48ec60c5924b6592832", "body": "…947) (#951)\n\nThe `Block` enum's variants have converged in size as the parser\nevolved. The two largest, `Section` (568 bytes) and `Media` (536\nbytes), now differ by only 32 bytes – far under clippy's 200-byte\n`large_enum_variant` threshold – so the lint no longer fires. The\n`#[allow]` (carried forw\n[…]\nasoning already\ndocumented on `BlockParseOutcome`).\n\nVerified with the CI invocation\n`cargo clippy --all-features --all-targets -- -Dwarnings`.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "chore: Drop stale allow(clippy::large_enum_variant) on Block (close #…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-25T03:40:16Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "19faf3b5696dfb32a0f875f4d95ddb93db7a8706", "body": "Audit the code base for TEMPORARY / \"while building\" markers (excluding\n`ref` and tests quoting `ref` content) and convert the genuine ones to\nTODO comments that link to tracking issues, per #939.\n\n- List items discard block metadata (#946).\n- `Block` enum trips `clippy::large_enum_variant` (#947).\n- `Span::take_ident` uses a provisional identifier definition (#948).\n- Remove \"while building\" scaffolding allows once consumed (#949).\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "chore: replace TEMPORARY markers with issue-linked TODOs (#950)", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-25T03:19:25Z", "body_truncated": false, "is_coding_agent": true }, { "oid": "5fdf0f42b24c7d41e72c1df86811d1789cd3eaba", "body": "Code-coverage review for dead code found no removable dead code: line\ncoverage is 98.79% and the compiler's dead_code lint is clean. The\nuncovered product lines are all intentional guardrails (defensive\nbranches, assertions, Debug impls, and a refactor-blocked region).\n\nThe one actionable cleanup is this stale attribute: the re-export is now\nused via crate::document::DuplicateIdError in the parser, so the\nallow(unused) suppresses nothing.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "chore: Remove stale allow(unused) on DuplicateIdError re-export (#945)", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T23:05:40Z", "body_truncated": false, "is_coding_agent": true }, { "oid": "4bbb8fe9f0018185442bda7a16e44b199f8a8e60", "body": "…haustive (#940)\n\n* feat: Derive Hash on the public AST / output types\n\nSpan, Block, Content, WarningType and the types reachable from them now\nimplement Hash, so blocks and spans can key a HashMap/HashSet and warnings can\nbe bucketed by type. ResolvedAttributes hashes an order-independent summary o\n[…]\nleValue / ModificationContext fields, all of which hold only Hashable\ndata.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "feat: Derive Hash on the public AST/output types; mark Warning non_ex…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T21:39:56Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "a59f603280d80c729d8a0f80afdb3554901d187b", "body": "…pat 5.0.0 -> 5.0.1 (#938)\n\nPatch-level updates to the benchmark harness dev-dependencies. Raising the\ndeclared floors keeps the -Z direct-minimal-versions CI job on the current\npatch releases. Benchmarks compile and minimal-versions resolves cleanly.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "chore(deps): Bump criterion 0.8.0 -> 0.8.2 and codspeed-criterion-com…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T19:03:52Z", "body_truncated": false, "is_coding_agent": true }, { "oid": "ca8db26179c0fe77d71e8e55b3a358fde32945af", "body": "* chore(asciidoc-parser): release v0.26.0\n\n* docs: Add 0.26.0 breaking changes guide to the changelog\n\nDocument the source-level migration for the four breaking changes in\n0.26.0 (block traversal #930, PathResolver-as-trait #934, rendering API\npolish #929, and the SourceMap reshape #917), mirroring the prose\nguide added for 0.23.0.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "chore(asciidoc-parser): release v0.26.0 (#916)", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T15:52:19Z", "body_truncated": false, "is_coding_agent": true }, { "oid": "50f68b5578c980dbfe90d73256b5b3e3e8b27f97", "body": "…ers (close #896) (#933)\n\n* feat: Let a custom InlineSubstitutionRenderer override only what differs (close #896)\n\nTwo changes unblock a downstream (e.g. Zola) `InlineSubstitutionRenderer`:\n\n- Give every `InlineSubstitutionRenderer` method a default body that\n delegates to the built-in `HtmlSubstit\n[…]\n is not surprised that `render_icon` and a direct `icon_uri`\ncall disagree.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "feat: Let a custom InlineSubstitutionRenderer override only what diff…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T15:42:28Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "104ed44bd5ba50724bb852dbc58f9d423dcb9105", "body": "Warnings were deterministic but assembled by category (header, blocks,\npreprocessor, substitution, post-parse checks, then reference-resolution\nwarnings appended last), so an unresolved `include::` on an early line\ncould sort after a malformed inline macro further down, and unresolved-xref\nwarnings \n[…]\ne parse and after\na reference-resolution sweep folds its warnings in, so `warnings()` now\nyields line-ordered, still-deterministic diagnostics.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Emit document warnings in source order (close #901) (#932)", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T15:06:54Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "0202092e25f780df3441880c100fca1f2ed8082b", "body": "…(#936)\n\nPRs #930 (child_blocks API) and #934 (PathResolver trait) landed\nconcurrently without a rebase, leaving the with_path_resolver test\ncalling the removed Document::nested_blocks(). Point it at\nchild_blocks() to match the sibling call sites.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Repair stale nested_blocks() call left by concurrent PR landing …", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T14:36:01Z", "body_truncated": false, "is_coding_agent": true }, { "oid": "e454b6e3c8507d1dc916f572a55b0d13de7b22ad", "body": "…k=self (close #919) (#927)\n\n* fix: Reject a dangerous image/icon target promoted to an href via link=self (close #919)\n\nAn `image:`/`icon:` macro whose target carries a script-capable scheme\n(`javascript:`, `vbscript:`, or a non-image `data:` such as\n`data:text/html,…`) is harmless in the `\u003cimg src\n[…]\nage data URIs and trusted embedded SVGs (the Asciidoctor-parity case) live.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Reject a dangerous image/icon target promoted to an href via lin…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T14:27:49Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "08944ce4a76acacdb4515e1b549df4728080162e", "body": "…r (close #898) (#934)\n\nPath resolution was the one extensibility seam in the crate that could not\nbe swapped: `PathResolver` was a concrete struct exposed as a `pub` by-value\nfield on `Parser`, so an Antora/Zola-style host needing custom path or URL\nrewriting (virtual filesystems, content roots, UR\n[…]\n` field is now `pub(crate) Rc\u003cdyn PathResolver>`,\nconfigured through a new `with_path_resolver(...)` builder rather than direct\nfield mutation.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "refactor!: Make PathResolver a trait with a with_path_resolver builde…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T14:21:36Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "d01724d237725af16b2892d5572cc95e102b7443", "body": "…I (close #894) (#930)\n\n* feat!: replace IsBlock::nested_blocks with a complete child_blocks API (close #894)\n\nThe discoverable block accessor `IsBlock::nested_blocks()` silently omitted\nMarkdown-blockquote children (reachable only via `QuoteBlock::blocks()`) and\nAsciiDoc table-cell content, so tool\n[…]\nck`, and\n the `nth` override) generated by the `opaque_slice_iter!` macro.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "feat!: Replace IsBlock::nested_blocks with a complete child_blocks AP…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T14:18:52Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "6dbdb248bb87626baa8087ac7c6ef5cbc0f52de9", "body": "…#903) (#931)\n\n* fix: Enforce SourceMap append ordering with a debug assertion (close #903)\n\n`SourceMap::resolve` binary-searches `segments` by `output_line`, which\nsilently returns garbage on an unsorted slice. `append` documented that\nentries \"should\" arrive in increasing order but did not enforce\n[…]\nptile-apps[bot]@users.noreply.github.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>\nCo-authored-by: greptile-apps[bot] \u003c165735046+greptile-apps[bot]@users.noreply.github.com>", "is_bot": false, "headline": "fix: Enforce SourceMap append ordering with a debug assertion (close …", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T14:14:12Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "5cb17dc58929cd6e654764f8b50a06e222229607", "body": "…se #899) (#926)\n\n`Catalog::ids()` and `Catalog::entries()` iterated a randomly-seeded\n`HashMap`, so their order varied between process runs. A multi-document\npipeline that derives output from catalog iteration order (e.g. building a\nglobal cross-reference index, or resolving a collision as \"first s\n[…]\nookups. `DebugHashMapFrom` is generalized to render either map type and\nstill sorts its own output, so the `Debug` representation is unchanged.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Make catalog ID iteration deterministic across process runs (clo…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T14:02:54Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "7f1df812544eadf0f48551d0b98abfba3a438e77", "body": "…e #906) (#925)\n\nThe doc comment read only \"Alternative to\" with a TODO placeholder. Describe\nthat `LookaheadReplacer` is an alternative to `regex::Replacer` that can inspect\nthe text following a match and reject it via `SkipAheadAndRetry`, modeling the\nlook-ahead pattern that `regex::Replacer` cannot express.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "docs: Complete the truncated doc comment on `LookaheadReplacer` (clos…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T13:34:38Z", "body_truncated": false, "is_coding_agent": true }, { "oid": "8eef1e68450f576f513f568f1a1a33d8daf724ff", "body": "…K branch (close #908) (#928)\n\nThe invalid-macro-syntax `else` branch in `InlineLinkReplacer` carried a\nFIXME noting that a `link:` prefix should never reach it: the shared\nNON-ANGLE branch of `INLINE_LINK` let `link:` prefix a bare (bracket-less)\nURL, which then matched and was rejected as invalid \n[…]\nsyntax path.\n\n`NormalizedCaps` gains a third branch mapping and `bare` becomes optional\n(the LINK-MACRO branch always has a trailing attrlist).\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "refactor: Give the `link:` prefix its own bracket-required INLINE_LIN…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T13:32:34Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "024721f9252180c4962152effea6365cc966c97d", "body": "Settles several pre-1.0 public-API commitments flagged in the adversarial\nreview, each of which would become a breaking change to fix after the freeze:\n\n- Rename the misspelled trait method\n `InlineSubstitutionRenderer::render_quoted_substitition` to\n `render_quoted_substitution`.\n- Remove the pro\n[…]\n type and\n`LinkRenderParams::type_` field are removed; and `LinkRenderParams::window`\nchanges from `Option\u003c&'static str>` to `Option\u003c&'a str>`.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "refactor!: Polish public rendering API ahead of 1.0 (close #897) (#929)", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T13:30:31Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "91abb32cc09f6a331ac1c2898655248cb54037be", "body": "…ion (close #889) (#920)\n\nAdd a prominent \"Security: rendering untrusted input\" section to the\nREADME (which is also the crate-level doc via `include_str!`), stating\nthat the HTML renderer is not a sanitizer, that attribute-reference\nsubstitution and passthroughs emit raw HTML by design, and that\nco\n[…]\noc must run the output\nthrough an HTML sanitizer such as `ammonia`. Clarify that safe mode\ngoverns file/environment reach, not output escaping.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "docs: Document that untrusted AsciiDoc output requires HTML sanitizat…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T05:14:55Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "870609273fe4653c8dd8ecea622099c3543654ff", "body": "…05) (#924)\n\n* perf: Reduce allocations in the inline substitution pipeline (close #905)\n\nResidual allocation-reduction items from the adversarial review; each is\nsmall and mechanical, and the many-small-blocks-of-plain-prose throughput\ncase benefits from all of them.\n\n- `apply_special_characters` n\n[…]\nng both the\n no-op-filter borrow branch and the changed-text owned branch.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Reduce allocations in the inline substitution pipeline (close #9…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T05:14:23Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "e053106f32bb6358554dfd2f3fc584574ff3e393", "body": "…ounds slice (close #902) (#923)\n\n* fix: Fall back to an empty span instead of the whole span on out-of-bounds slice (close #902)\n\n`Span::slice` / `slice_from` / `slice_to` guarded their bounds only with a\n`debug_assert!`. In a release build, when `.get(range)` returned `None`, the\n`map_or(*self, …)\n[…]\nes;\nthe release fallback behavior is already covered by the `empty()` test.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Fall back to an empty span instead of the whole span on out-of-b…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T05:13:38Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "6ad42b74d3ae456eeccab4f1f7a6dc8504208804", "body": "…ciiDoc table cells (close #904) (#922)\n\nFor every AsciiDoc-style (`a`) table cell, `process_content` rebuilt the\nattribute-lock set from scratch, allocating an owned `String` for each of the\n~74 built-in attributes it locked and deep-cloning the whole `HashSet\u003cString>`\nper cell. This was the domina\n[…]\ncall out of the modifiable-attributes loop so the\nper-parser attribute map is made-mut once per cell rather than re-checked on\nevery iteration.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "perf: Avoid per-cell String allocations when locking attributes in As…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T05:07:35Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "24ec6d181229f6d09f8dccdcf646fbd5ef918cad", "body": "…or (close #907) (#921)\n\nThe `// TODO:` in `section_to_node` described how the section title heading is\nadded in the `Block::Section` match arm (using `section.level()` for the heading\nlevel and `section.section_title()` for the text). That behavior is already fully\nimplemented there, so the note tr\n[…]\nfold its one useful detail (the title heading, like the id,\nlands on the heading rather than the wrapper `\u003cdiv>`) into the surrounding\ncomment.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "chore: Remove stale TODO restating implemented section-heading behavi…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T05:07:00Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "80825d50579108831d9bc1f96f5a6e9e43d86cdd", "body": "…idelity (#917)\n\n* feat: Map preprocessed spans back to origin file, line, column, and fidelity (close #891)\n\nSpans carry coordinates relative to the single preprocessed buffer, and the\nonly way back to an origin was `SourceMap::original_file_and_line`, which is\nline-only and cannot say whether a li\n[…]\nhe included file's identity is\nnot carried forward into the parent's lines.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "feat: Map preprocessed spans back to origin file, line, column, and f…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T04:47:54Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "e64f4ade1fff3da5fba49aebf0aba8c2fb15d6dd", "body": "…k macro (close #888) (#911)\n\n* fix: Escape href/target/icon attributes and reject script URIs in link macro (close #888)\n\nSeveral `href`/`target` and icon attribute values were emitted into the\nrendered HTML without escaping the `\"` delimiter, allowing an author to\nbreak out of the attribute and in\n[…]\nnd `render_icon_or_image` (which drops the\nlive link) share one definition.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Escape href/target/icon attributes and reject script URIs in lin…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T01:59:19Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "0c93961c8288c853f6300d9487cb0139a3afe9b2", "body": "A UTF-8 byte-order mark (`EF BB BF` = U+FEFF) at the start of the input\nwas not stripped. `preprocess` short-circuits and returns the source\nunchanged when there are no directives, so the U+FEFF became the first\ncharacter of the first line. `Header::parse` requires the line to start\nwith `= `, so a \n[…]\n This matches Asciidoctor, which strips a UTF-8 BOM even\nfor UTF-8 input, and is independent of UTF-16 transcoding, which remains\nout of scope.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Strip a leading UTF-8 BOM before parsing (close #900) (#918)", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T01:45:04Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "436d8144f64c066572d62d4581da228bf52601ec", "body": "…nput (close #885) (#910)\n\n* fix: Cap block nesting depth to prevent stack overflow on untrusted input (close #885)\n\nBlock parsing descends recursively through `parse_blocks_until` (delimited\nblock bodies, section bodies, table cells, quote/blockquote content) and\nthrough `ListBlock::parse_inside_li\n[…]\ntores parity with\nthe pre-#885 baseline (measured within run-to-run noise).\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Cap block nesting depth to prevent stack overflow on untrusted i…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T01:30:04Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "9c91f6f9c6f3916cb55ae67e3fbfeccfb3bfa644", "body": "…r (close #893) (#909)\n\n* fix: Reset document attribute values between parses on a reused Parser (close #893)\n\n`Parser::parse_deferred` reset the catalog, callouts, substitution\nwarnings, section numbering, pending block title, and counters between\nparses but not `attribute_values`, so document-head\n[…]\nic's prose dash convention in the doc comment added by the\nprevious commit.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Reset document attribute values between parses on a reused Parse…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T01:08:35Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "c8aa0e203b0f9a0374a288eab5fcd69524e2134d", "body": "…ad (close #887) (#912)\n\n* fix: Honor char boundary when skipping constrained-monospace look-ahead (close #887)\n\nThe constrained-monospace quote regex's leading boundary group\n`[^\\w&;:\"'`}]` matches any non-word Unicode scalar, including multi-byte\ncharacters. When a failed look-ahead skipped the le\n[…]\nage gap left by\nthe multi-byte fix. The escaped text is preserved verbatim.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Honor char boundary when skipping constrained-monospace look-ahe…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T00:40:36Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "50f578e127fe1a0c76989d01cbf6a21aa8b9a28c", "body": "Apply the documented comment/doc style conventions to hand-written\ncomments and documentation text (excluding the vendored `ref/` tree and\nthe tests that quote it):\n\n- Convert prose em dashes to spaced en dashes (366 lines). The one\n literal em-dash character reference in `virtual_dom.rs` is preser\n[…]\nn test it marks.\n- File tracking issues for an incomplete doc comment and two unlinked\n TODO/FIXME comments, and link them (#906, #907, #908).\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "doc: Normalize comment and doc prose style across the codebase (#915)", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T00:37:00Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "a43b990ea8278c9b81394ffd2bff232a57b17a60", "body": "…#886) (#914)\n\n* fix: Avoid O(n²) parse time on many repeated block delimiters (close #886)\n\n`QuoteBlock::parse` runs before `CompoundDelimitedBlock` in block dispatch,\nso it is tried for every delimiter line. Its quoted-paragraph path called\n`read_paragraph` (a scan to the next blank line) before t\n[…]\nlines between\nthem) — the shape that previously triggered O(n²) parse time.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Avoid O(n²) parse time on many repeated block delimiters (close …", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T00:35:44Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "b5252cb2a4b00dd2dd93049da95c2c90d2178eb9", "body": "…ction (close #890) (#913)\n\nThe `Safe` and `Server` docstrings described protections the parser does\nnot actually enforce:\n\n- `Safe` claimed it prevents access to files outside the source file's\n parent directory. This crate performs no filesystem I/O and does not\n port Ruby Asciidoctor's `PathRes\n[…]\nent handler's responsibility —\nand that only `Secure`, not `Server`, disables include/asset embedding.\n\nDocumentation only; no behavior change.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "docs: Correct SafeMode Safe/Server docstrings to match enforced prote…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-24T00:28:44Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "006b8752176d0637c7f3c2535ecbb02f5ba47798", "body": null, "is_bot": false, "headline": "chore(asciidoc-parser): release v0.25.0 (#879)", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T15:21:24Z", "body_truncated": false, "is_coding_agent": false }, { "oid": "cfae1bd47ba42ecab7e0585b59f9f80fa7a40c81", "body": null, "is_bot": false, "headline": "chore: Update README to reflect fully feature-complete status (#884)", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T15:15:18Z", "body_truncated": false, "is_coding_agent": false }, { "oid": "b2106856ea6c1c62dcd52c1021720ca2d7b5d294", "body": "…(close #871) (#883)\n\n* test: Verify link attrlist enclosure rule for invalid attribute names (close #871)\n\nPromote the \"enclosure only required when the text preceding the equals\nsign matches a valid attribute name\" sentence in the link/URL macro\nattribute-parsing spec from a non-normative note to \n[…]\nor future spec-coverage work and silence the\nunused-macro/-import warnings.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Verify link attrlist enclosure rule for invalid attribute names …", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T15:04:32Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "48407cc93dcdb2524698690360334ec80e85f99e", "body": "… content (close #877) (#881)\n\n`reindent_included_lines` previously returned included content unchanged\nwhenever the `indent` attribute was absent, so `tabsize`-driven tab\nexpansion only fired when `indent` was also supplied.\n\nPer the spec, when `tabsize` is set, tabs are replaced with spaces\nregard\n[…]\nxpansion now runs\nwhenever `tabsize` is positive; indentation normalization is applied\nindependently when `indent` is present and non-negative.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Expand tabs from `tabsize` independently of `indent` on included…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T14:53:49Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "1c10c0badc6182a1de62af87f02a150e2f994d42", "body": "…ing blank lines (close #876) (#882)\n\nPromote the `to_do_verifies!` block in `document_test.rs` to two real\n`verifies!` tests, backed by an `InlineFileHandler` fixture reproducing\nAsciidoctor's canonical `include-with-leading-blank-line.adoc` (two blank\nlines before the level-0 title).\n\n- A whole-fi\n[…]\ne and sets `:toc:`.\n- `lines=6` selects by original line number, skipping the leading blank\n lines and the title so only the section survives.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "test: Verify document-title & lines= selection for includes with lead…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T14:53:02Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "de9a4cff700cb105ba39c66753cc902e78bfc5a7", "body": "…lose #801) (#880)\n\n`WarningType` became part of the public API in #799, so its variant names\nand `Display` strings now need to read as a deliberate, consistent set. This\nis the one-time review the long-standing TODO above `InvalidMacroName` asked\nfor.\n\nVariant renames (breaking for anyone matching \n[…]\ner\"). Wording is otherwise unchanged. This changes user-visible\nwarning text.\n\nThe `TODO (#801)` marker is removed now that the review is done.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "refactor(warnings)!: Review WarningType variant names and messages (c…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T14:44:50Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "0c6a48c7687d434f46b001a991b9aaae7ca4f778", "body": "…878)\n\nConvert the now-testable table structural-container row to verifies! and\nreclassify the permanently-unverifiable / out-of-scope blocks as\nnon_normative! with justifications:\n\n- delimited.rs: the four table delimiters (`|===`, `,===`, `:===`, `!===`)\n now assert the `table` context and conten\n[…]\ne two genuinely-deferred blocks now cite tracking issues #876 (include\ndoctitle recognition / lines= selection) and #877 (block-level tabsize).\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "test: Resolve remaining to_do_verifies! blocks from the #628 sweep (#…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T14:39:38Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "2f37e9dd217d6c7595c77300828d290df3b15aaa", "body": "…) (#874)\n\n* test: Cover description-list delimiter and anchor rules (close #864)\n\nThe opening `non_normative!` block in `lists/description.rs` reproduced\nseveral normative parsing rules for description lists but none were\nexercised by a test. Split the block so the normative prose is now backed\nby \n[…]\ntrast to\na leading `[[id]]` anchor which becomes part of the rendered term.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": " chore: Cover description-list delimiter and anchor rules (close #864…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T14:37:26Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "3e721feddf89a868c943c97bf3abb78d0b32387a", "body": "…horthand ID/role order, AsciiDoc-cell directive) (#873)\n\n* test: Cover `title`-attribute fallback for the document title\n\nSplit the `[#title-attr]` `non_normative!` block so the normative\nfallback rule is verified: with no level 0 section title and no\n`doctitle` attribute, a `title` attribute entry\n[…]\name\ndirective on the following line acts as a normal multiline conditional.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "chore: Close mislabeled-normative coverage gaps (doctitle fallback, s…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T14:27:21Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "18685312ef868d1f9906882096a40a25a8224b63", "body": "…se #865) (#875)\n\nSeveral inline-macro spec pages wrapped a normative parsing rule in\n`non_normative!` without covering tests. Add `verifies!` coverage for\neach rule the parser already implements correctly, and a justified\n`to_do_verifies!` marker for the one it does not:\n\n- Inline image alt-text: a\n[…]\next before `=` is a valid attribute name. The parser does not yet\n honor this; the marker documents current behavior and is tracked by\n #871.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "test: Cover inline-macro spec rules hidden behind non_normative! (clo…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T14:26:46Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "9aad9fafcabf48bfd30a115b4693f86279bde551", "body": "…combinators (close #866) (#868)\n\n* test: Cover mixed ifdef/ifndef combinator behavior (close #866)\n\nThe `non_normative!` block in `ifdef_ifndef.rs` stated the normative rule\nthat the `,` (or) and `+` (and) combinators cannot be combined in a single\nconditional-directive expression, but no test asse\n[…]\naffected. Extend `combinators_cannot_be_mixed` to cover the `+`-first case.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Match Asciidoctor's first-delimiter rule for mixed ifdef/ifndef …", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T14:14:25Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "5051db0ceb815d7961afb2c5fc2d53131d6ee2df", "body": "Port Asciidoctor's `doc.register :links, target` so the parser records\nevery link target it encounters, exposed as `Catalog::links()`. Like the\nimage registry, population is gated on the `catalog_assets` option and\nrecorded in substitution-pass order.\n\nAll four Asciidoctor registration sites are covered: bare-URL autolink,\n`link:` macro, `mailto:`/link macro, and email autolink (the last of\nwhich the original TO DO markers had missed).\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "feat: Populate the document catalog's link registry (close #335) (#872)", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T14:10:34Z", "body_truncated": false, "is_coding_agent": true }, { "oid": "e06f0caf0984685dcb64fa452c10e6ca152a60d2", "body": "Audit of commented-out code turned up two genuinely dead blocks in the\ncrate's own source (excluding quoted Asciidoctor / AsciiDoc reference\nmaterial):\n\n- `passthroughs.rs`: an abandoned trailing-backslash truncation approach,\n superseded by the retry logic that follows it.\n- `sdd/src/main.rs`: a developer debugging shortcut that scoped file\n processing to a single file.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "chore: Remove commented-out dead code (close #705) (#870)", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T14:09:52Z", "body_truncated": false, "is_coding_agent": true }, { "oid": "dbacb2413f412cdbee15fd2ebd8ff150b1c77b34", "body": null, "is_bot": false, "headline": "chore(asciidoc-parser): release v0.24.0 (#863)", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T04:33:53Z", "body_truncated": false, "is_coding_agent": false }, { "oid": "99cf75ffb9858f73cb164da754ce25058e314f13", "body": "…tle (#862)\n\nAdd a regression test asserting that a block attribute line above the\ndocument title whose value carries a `{counter:…}` reference does not fire\nthe counter at header time when the run is ultimately rejected (here by an\nembedded `[[anchor]]`).\n\n`document_title_follows_block_metadata` sc\n[…]\nparser and the counter advances exactly once. This\nlocks in that behavior, salvaging the one piece of unique coverage from the\nsuperseded #833.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "test: Cover counter deferral for a rejected metadata run above the ti…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T04:27:28Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "0944b66c0ba58ae3c2a2dc942f070698241756d1", "body": "…ub (#861)\n\nIssue #308 asked whether a block title can span multiple lines via a\ntrailing `+`. The answer is no: a title is a single line, and a trailing\n` +` is retained literally rather than joined to the following line\n(confirmed against the parser). Replace the stale `TO DO` comment linking\nto #\n[…]\n `to_do_verifies!` stub convention.\n\nThe `|Titles |{y}` spec-coverage marker stays; that gap is tracked by the\n`to_do_verifies!` sweep in #628.\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "test: Remove resolved #308 reference from post_replacements titles st…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T04:07:15Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "adf9ff733355bea5b2dba6b52c30deb736ecbc0d", "body": "…9) (#852)\n\n* fix: Fuse legacy `+`-continued multi-line attribute values (close #729)\n\nAn attribute entry value can be continued across lines with a trailing\n` +` (legacy) as well as ` \\` (modern). Previously only the backslash\ncontinuation was fused; a legacy `+`-continued value was not joined — th\n[…]\nn the document body).\n\nAdds span-, fold-, and parse-level regression tests.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Fuse legacy `+`-continued multi-line attribute values (close #72…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T04:06:45Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "3f2e0d78c748fff27314a181285a2863f43d4b05", "body": "…732) (#850)\n\n* fix: Formal `role=` replaces roles set via shorthand `.role` (close #732)\n\nWhen merging multiple block attribute lines, roles now follow\nAsciidoctor's running model: a formal `role=` entry replaces every role\naccumulated so far, while shorthand `.role` entries append. Previously\nall \n[…]\nat\n the formal value replaces the running roles and the shorthand appends.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "fix: Formal `role=` replaces roles set via shorthand `.role` (close #…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T03:59:34Z", "body_truncated": true, "is_coding_agent": true }, { "oid": "cab8554693ddb8d05d68eb5dd37bdf05384d37ff", "body": "…lose #745) (#848)\n\n* feat: Drop YAML/TOML front matter when `skip-front-matter` is set (close #745)\n\nA `---`-fenced block at the very top of the document is now removed – and\nits content captured in the `front-matter` document attribute – when the\n`skip-front-matter` attribute is set, mirroring Asc\n[…]\n, `+++` TOML is not, and the content is\nstored verbatim rather than parsed.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 \u003cnoreply@anthropic.com>", "is_bot": false, "headline": "feat: Drop YAML-style front matter when `skip-front-matter` is set (c…", "author_name": "Eric Scouten", "author_login": "scouten", "committed_at": "2026-07-23T03:54:47Z", "body_truncated": true, "is_coding_agent": true } ], "releases_count": 55, "commits_last_year": 546, "latest_release_at": "2026-08-01T16:14:24Z", "latest_release_tag": "v0.29.4", "releases_from_tags": false, "days_since_last_push": 0, "active_weeks_last_year": 37, "days_since_latest_release": 0, "mean_days_between_releases": 0.7 }, "community": { "has_readme": true, "has_license": true, "has_description": true, "has_contributing": false, "health_percentage": 37, "has_issue_template": false, "has_code_of_conduct": false, "has_pull_request_template": false }, "ecosystem": { "packages": [ { "name": "sdd", "exists": true, "license": "Apache-2.0", "keywords": [ "concurrent", "garbage", "memory", "epoch", "lock-free", "data-structures", "concurrency", "memory-management" ], "ecosystem": "crates", "matches_repo": false, "registry_url": "https://crates.io/crates/sdd", "is_deprecated": false, "latest_version": "4.8.8", "repository_url": "https://codeberg.org/wvwwvwwv/scalable-delayed-dealloc", "versions_count": 72, "total_downloads": 77608068, "dependents_count": null, "deprecation_note": null, "maintainers_count": null, "monthly_downloads": 5899173, "first_published_at": "2024-04-14T18:03:40.616625Z", "latest_published_at": "2026-07-02T14:12:15.625601Z", "latest_version_yanked": false, "days_since_latest_publish": 30 }, { "name": "asciidoc-parser", "exists": true, "license": "MIT OR Apache-2.0", "keywords": [ "parser", "asciidoc", "parser-implementations" ], "ecosystem": "crates", "matches_repo": true, "registry_url": "https://crates.io/crates/asciidoc-parser", "is_deprecated": false, "latest_version": "0.29.4", "repository_url": "https://github.com/asciidoc-rs/asciidoc-parser", "versions_count": 55, "total_downloads": 13542, "dependents_count": null, "deprecation_note": null, "maintainers_count": null, "monthly_downloads": 2012, "first_published_at": "2024-10-26T22:27:57.063155Z", "latest_published_at": "2026-08-01T16:14:20.394752Z", "latest_version_yanked": false, "days_since_latest_publish": 0 } ] }, "popularity": { "forks": 4, "stars": 34, "watchers": 2, "fork_history": { "days": [ { "date": "2026-01-23", "count": 1 }, { "date": "2026-02-17", "count": 1 }, { "date": "2026-04-01", "count": 1 }, { "date": "2026-07-18", "count": 1 } ], "complete": true, "collected": 4, "total_forks": 4 }, "star_history": null, "open_issues_and_prs": 5 }, "ai_readiness": { "has_nix": false, "example_dirs": [ "examples" ], "has_llms_txt": false, "has_dockerfile": false, "has_mcp_signal": false, "bootstrap_files": [], "api_schema_files": [], "has_devcontainer": true, "typecheck_configs": [], "toolchain_manifests": [ "Cargo.toml", "parser/Cargo.toml", "sdd/Cargo.toml" ], "largest_source_bytes": 434972, "source_files_sampled": 419, "oversized_source_files": 45, "agent_instruction_files": [], "agent_instruction_max_bytes": null }, "dependencies": { "manifests": [ "Cargo.toml", "parser/Cargo.toml", "sdd/Cargo.toml" ], "advisories": { "error": "No resolved dependencies carried a version and a supported ecosystem", "scope": "repository_graph", "source": null, "findings": [], "collected": false, "malicious": [], "truncated": false, "by_severity": {}, "advisory_count": 0, "affected_count": 0, "assessed_count": 0, "malicious_count": 0, "assessed_package": null, "unassessed_count": 10, "direct_affected_count": 0 }, "ecosystems": [ "crates" ], "dependencies": [ { "name": "bytecount", "manifest": "parser/Cargo.toml", "ecosystem": "crates", "version_constraint": "0.6.7" }, { "name": "memchr", "manifest": "parser/Cargo.toml", "ecosystem": "crates", "version_constraint": "2.6.4" }, { "name": "percent-encoding", "manifest": "parser/Cargo.toml", "ecosystem": "crates", "version_constraint": "2.3.2" }, { "name": "regex", "manifest": "parser/Cargo.toml", "ecosystem": "crates", "version_constraint": "1.11.1" }, { "name": "self_cell", "manifest": "parser/Cargo.toml", "ecosystem": "crates", "version_constraint": "1.2.0" }, { "name": "thiserror", "manifest": "parser/Cargo.toml", "ecosystem": "crates", "version_constraint": "2.0.1" }, { "name": "walkdir", "manifest": "sdd/Cargo.toml", "ecosystem": "crates", "version_constraint": "2.5" } ], "all_dependencies": { "error": null, "source": "github-sbom", "packages": [ { "name": "bytecount", "direct": true, "version": null, "ecosystem": "crates" }, { "name": "memchr", "direct": true, "version": null, "ecosystem": "crates" }, { "name": "percent-encoding", "direct": true, "version": null, "ecosystem": "crates" }, { "name": "regex", "direct": true, "version": null, "ecosystem": "crates" }, { "name": "self_cell", "direct": true, "version": null, "ecosystem": "crates" }, { "name": "thiserror", "direct": true, "version": null, "ecosystem": "crates" }, { "name": "walkdir", "direct": true, "version": null, "ecosystem": "crates" }, { "name": "codspeed-criterion-compat", "direct": false, "version": null, "ecosystem": "crates" }, { "name": "criterion", "direct": false, "version": null, "ecosystem": "crates" }, { "name": "pretty_assertions_sorted", "direct": false, "version": null, "ecosystem": "crates" } ], "collected": true, "truncated": false, "total_count": 10, "direct_count": 7, "indirect_count": 3 } }, "maintainership": { "issues": { "open_prs": 2, "merged_prs": 772, "open_issues": 3, "closed_ratio": 0.987, "closed_issues": 223, "closed_unmerged_prs": 40 }, "bus_factor": 2, "bot_contributors": 1, "top_contributors": [ { "type": "User", "login": "scouten", "commits": 759, "avatar_url": "https://avatars.githubusercontent.com/u/158391?v=4" }, { "type": "User", "login": "mojavelinux", "commits": 723, "avatar_url": "https://avatars.githubusercontent.com/u/79351?v=4" }, { "type": "User", "login": "graphitefriction", "commits": 37, "avatar_url": "https://avatars.githubusercontent.com/u/1124042?v=4" }, { "type": "User", "login": "ggrossetie", "commits": 3, "avatar_url": "https://avatars.githubusercontent.com/u/333276?v=4" }, { "type": "User", "login": "larryv", "commits": 2, "avatar_url": "https://avatars.githubusercontent.com/u/281175?v=4" }, { "type": "User", "login": "mmattel", "commits": 2, "avatar_url": "https://avatars.githubusercontent.com/u/3321281?v=4" }, { "type": "User", "login": "ahus1", "commits": 1, "avatar_url": "https://avatars.githubusercontent.com/u/3957921?v=4" }, { "type": "User", "login": "btat", "commits": 1, "avatar_url": "https://avatars.githubusercontent.com/u/1832069?v=4" }, { "type": "User", "login": "Vampire", "commits": 1, "avatar_url": "https://avatars.githubusercontent.com/u/325196?v=4" }, { "type": "User", "login": "danyill", "commits": 1, "avatar_url": "https://avatars.githubusercontent.com/u/674783?v=4" } ], "contributors_sampled": 22, "top_contributor_share": 0.492 }, "quality_signals": { "has_ci": true, "has_tests": true, "ci_workflows": [ "ci.yml", "pr_title.yml", "release.yml" ], "has_docs_dir": false, "linter_configs": [], "has_editorconfig": false, "has_linter_config": false, "has_precommit_config": false }, "security_signals": { "lockfiles": [], "scorecard": { "checks": [ { "name": "Binary-Artifacts", "score": 10, "reason": "no binaries found in the repo", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts" }, { "name": "Branch-Protection", "score": 3, "reason": "branch protection is not maximal on development and all release branches", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection" }, { "name": "CI-Tests", "score": 10, "reason": "30 out of 30 merged PRs checked by a CI test -- score normalized to 10", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests" }, { "name": "CII-Best-Practices", "score": 0, "reason": "no effort to earn an OpenSSF best practices badge detected", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices" }, { "name": "Code-Review", "score": 0, "reason": "Found 1/30 approved changesets -- score normalized to 0", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review" }, { "name": "Contributors", "score": 10, "reason": "project has 14 contributing companies or organizations", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors" }, { "name": "Dangerous-Workflow", "score": 10, "reason": "no dangerous workflow patterns detected", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow" }, { "name": "Dependency-Update-Tool", "score": 10, "reason": "update tool detected", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool" }, { "name": "Fuzzing", "score": 0, "reason": "project is not fuzzed", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing" }, { "name": "License", "score": 10, "reason": "license file detected", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license" }, { "name": "Maintained", "score": 10, "reason": "30 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained" }, { "name": "Packaging", "score": 10, "reason": "packaging workflow detected", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging" }, { "name": "Pinned-Dependencies", "score": 10, "reason": "all dependencies are pinned", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies" }, { "name": "SAST", "score": 0, "reason": "SAST tool is not run on all commits -- score normalized to 0", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast" }, { "name": "Security-Policy", "score": 0, "reason": "security policy file not detected", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy" }, { "name": "Signed-Releases", "score": null, "reason": "no releases found", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases" }, { "name": "Token-Permissions", "score": 0, "reason": "detected GitHub workflow tokens with excessive permissions", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions" }, { "name": "Vulnerabilities", "score": 10, "reason": "0 existing vulnerabilities detected", "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities" } ], "commit": "85320d8042ad10832b6e6cdc5cc7f7ef740c558f", "ran_at": "2026-08-01T18:21:44Z", "aggregate_score": 6.1, "scorecard_version": "v5.5.0" }, "has_codeql_workflow": false, "has_security_policy": false, "has_dependabot_config": true }, "contribution_flow": { "collected": true, "ci_last_run_at": "2026-08-01T17:56:39Z", "oldest_open_prs": [ { "number": 1039, "created_at": "2026-08-01T17:54:25Z", "last_comment_at": "2026-08-01T17:57:42Z", "last_comment_author": "codspeed-hq" }, { "number": 1040, "created_at": "2026-08-01T18:13:36Z", "last_comment_at": "2026-08-01T18:16:29Z", "last_comment_author": "codspeed-hq" } ], "last_merged_pr_at": "2026-08-01T17:53:45Z", "ci_last_conclusion": "SUCCESS", "oldest_open_issues": [ { "number": 943, "created_at": "2026-07-24T22:37:22Z", "last_comment_at": null, "last_comment_author": null }, { "number": 944, "created_at": "2026-07-24T22:37:43Z", "last_comment_at": null, "last_comment_author": null }, { "number": 1036, "created_at": "2026-08-01T17:29:43Z", "last_comment_at": null, "last_comment_author": null } ] } }, "config": { "disabled_metrics": [], "disabled_categories": [], "disabled_components": {} }, "source": { "url": "https://github.com/asciidoc-rs/asciidoc-parser", "host": "github.com", "name": "asciidoc-parser", "owner": "asciidoc-rs" }, "metrics": { "overall": { "key": "overall", "band": "good", "name": "Overall health", "note": "The weighted overall 66 is calibrated to 77 on the published index scale (record calibration 2026-08-02).", "notes": [ { "code": "overall_calibration", "params": { "raw": 66, "calibrated": 77, "calibration": "2026-08-02" } } ], "value": 77, "inputs": { "security": 61, "vitality": 94, "community": 43, "governance": 66, "calibration": "2026-08-02", "engineering": 61, "ai_readiness": 64, "weighted_overall_raw": 66 }, "components": [] }, "categories": [ { "key": "vitality", "band": "exceptional", "name": "Vitality", "value": 94, "weight": 0.21, "metrics": [ { "key": "development_activity", "band": "excellent", "name": "Development activity", "note": null, "notes": [], "value": 90, "inputs": { "commits_last_year": 546, "human_commit_share": 1, "days_since_last_push": 0, "active_weeks_last_year": 37 }, "components": [ { "key": "push_recency", "name": "Push recency", "detail": "last push 0 days ago", "points": 36, "status": "met", "details": [ { "code": "push_recency", "params": { "days": 0 } } ], "max_points": 36 }, { "key": "commit_cadence", "name": "Commit cadence", "detail": "37/52 weeks with commits", "points": 25.6, "status": "partial", "details": [ { "code": "commit_cadence_weeks", "params": { "weeks": 37 } } ], "max_points": 36 }, { "key": "commit_volume", "name": "Commit volume", "detail": "546 commits in the last year", "points": 18, "status": "met", "details": [ { "code": "commits_last_year", "params": { "count": 546 } } ], "max_points": 18 }, { "key": "openssf_scorecard_maintained", "name": "OpenSSF Scorecard: Maintained", "detail": "30 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10", "points": 10, "status": "met", "details": [], "max_points": 10 } ] }, { "key": "release_discipline", "band": "exceptional", "name": "Release discipline", "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.", "notes": [ { "code": "excluded_no_data", "params": { "components": [ "openssf_scorecard_signed_releases" ] } }, { "code": "weights_renormalized", "params": {} } ], "value": 100, "inputs": { "releases_count": 55, "latest_release_tag": "v0.29.4", "releases_from_tags": false, "days_since_latest_release": 0, "mean_days_between_releases": 0.7 }, "components": [ { "key": "ships_releases", "name": "Ships releases", "detail": "55 releases published", "points": 27, "status": "met", "details": [ { "code": "releases_published", "params": { "count": 55 } } ], "max_points": 27 }, { "key": "release_recency", "name": "Release recency", "detail": "latest release 0 days ago", "points": 36, "status": "met", "details": [ { "code": "release_recency", "params": { "days": 0 } } ], "max_points": 36 }, { "key": "release_cadence", "name": "Release cadence", "detail": "a release every ~0.7 days", "points": 27, "status": "met", "details": [ { "code": "release_cadence", "params": { "gap": 0.7 } } ], "max_points": 27 }, { "key": "openssf_scorecard_signed_releases", "name": "OpenSSF Scorecard: Signed-Releases", "detail": "no releases found", "points": 0, "status": "excluded", "details": [ { "code": "no_data", "params": {} } ], "max_points": 10 } ] }, { "key": "abandonment", "band": "exceptional", "name": "Abandonment", "note": null, "notes": [], "value": 100, "inputs": { "cap": null, "state": "maintained", "guards": [], "signals": [], "red_flag": false, "multiplier_pct": 100, "declared_reason": null, "unverified_reason": null, "unanswered_open_prs": null, "unanswered_open_issues": null, "days_since_last_merged_pr": null, "days_since_last_human_commit": 3, "days_since_last_human_commit_is_floor": false }, "components": [ { "key": "project_is_still_maintained", "name": "Project is still maintained", "detail": "last human commit 3 days ago", "points": 100, "status": "met", "details": [ { "code": "abandonment_maintained", "params": { "days": 3 } } ], "max_points": 100 } ] } ], "description": "Is the project alive — is code being written and are releases shipping?" }, { "key": "community", "band": "weak", "name": "Community & Adoption", "value": 43, "weight": 0.17, "metrics": [ { "key": "popularity", "band": "at_risk", "name": "Popularity & adoption", "note": null, "notes": [], "value": 29, "inputs": { "forks": 4, "stars": 34, "watchers": 2, "growth_state": "unverified", "growth_factor_pct": 100, "growth_unverified_reason": "no_history" }, "components": [ { "key": "stars", "name": "Stars", "detail": "34 stars", "points": 24.6, "status": "partial", "details": [ { "code": "stars", "params": { "count": 34 } } ], "max_points": 60 }, { "key": "forks", "name": "Forks", "detail": "4 forks", "points": 4, "status": "partial", "details": [ { "code": "forks", "params": { "count": 4 } } ], "max_points": 25 }, { "key": "watchers", "name": "Watchers", "detail": "2 watchers", "points": 0, "status": "missed", "details": [ { "code": "watchers", "params": { "count": 2 } } ], "max_points": 15 } ] }, { "key": "community_health", "band": "moderate", "name": "Community health", "note": null, "notes": [], "value": 50, "inputs": { "has_readme": true, "has_license": true, "readme_badges": null, "has_contributing": false, "has_issue_template": false, "has_code_of_conduct": false, "readme_badge_services": [], "has_pull_request_template": false }, "components": [ { "key": "readme", "name": "README", "detail": null, "points": 22.5, "status": "met", "details": [], "max_points": 22.5 }, { "key": "license", "name": "License", "detail": "recognized license (Apache-2.0)", "points": 22.5, "status": "met", "details": [ { "code": "license_standard", "params": {} }, { "code": "license_spdx", "params": { "spdx": "Apache-2.0" } } ], "max_points": 22.5 }, { "key": "contributing_guide", "name": "CONTRIBUTING guide", "detail": null, "points": 0, "status": "missed", "details": [], "max_points": 18 }, { "key": "code_of_conduct", "name": "Code of conduct", "detail": null, "points": 0, "status": "missed", "details": [], "max_points": 13.5 }, { "key": "issue_template", "name": "Issue template", "detail": null, "points": 0, "status": "missed", "details": [], "max_points": 7.2 }, { "key": "pr_template", "name": "PR template", "detail": null, "points": 0, "status": "missed", "details": [], "max_points": 6.3 } ] }, { "key": "ecosystem_adoption", "band": "moderate", "name": "Ecosystem adoption (downloads)", "note": "Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.", "notes": [ { "code": "excluded_no_data", "params": { "components": [ "registry_dependents" ] } }, { "code": "weights_renormalized", "params": {} } ], "value": 55, "inputs": { "packages": [ "asciidoc-parser" ], "dependents": null, "ecosystems": "crates", "total_downloads": 13542, "monthly_downloads": 2012 }, "components": [ { "key": "monthly_downloads", "name": "Monthly downloads", "detail": "2,012 downloads/month across crates", "points": 44.1, "status": "partial", "details": [ { "code": "downloads_monthly", "params": { "count": 2012, "ecosystems": "crates" } } ], "max_points": 80 }, { "key": "registry_dependents", "name": "Registry dependents", "detail": "not reported by this ecosystem", "points": 0, "status": "excluded", "details": [ { "code": "not_reported_by_this_ecosystem", "params": {} } ], "max_points": 20 } ] } ], "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?" }, { "key": "governance", "band": "good", "name": "Sustainability & Governance", "value": 66, "weight": 0.23, "metrics": [ { "key": "maintainer_resilience", "band": "moderate", "name": "Maintainer resilience (bus factor)", "note": null, "notes": [], "value": 60, "inputs": { "bus_factor": 2, "contributors_sampled": 22, "top_contributor_share": 0.492 }, "components": [ { "key": "bus_factor", "name": "Bus factor", "detail": "2 contributor(s) cover half of all commits", "points": 25.2, "status": "partial", "details": [ { "code": "bus_factor", "params": { "count": 2 } } ], "max_points": 54 }, { "key": "commit_distribution", "name": "Commit distribution", "detail": "top contributor authored 49% of commits", "points": 11.4, "status": "partial", "details": [ { "code": "top_contributor_share", "params": { "share": 49 } } ], "max_points": 22.5 }, { "key": "contributor_breadth", "name": "Contributor breadth", "detail": "22 contributors", "points": 13.5, "status": "met", "details": [ { "code": "contributors_sampled", "params": { "count": 22 } } ], "max_points": 13.5 }, { "key": "openssf_scorecard_contributors", "name": "OpenSSF Scorecard: Contributors", "detail": "project has 14 contributing companies or organizations", "points": 10, "status": "met", "details": [], "max_points": 10 } ] }, { "key": "responsiveness", "band": "excellent", "name": "Issue & PR responsiveness", "note": "Excluded from scoring (no data or not applicable): Newcomer PR acceptance. Remaining weights renormalized.", "notes": [ { "code": "excluded_no_data", "params": { "components": [ "newcomer_pr_acceptance" ] } }, { "code": "weights_renormalized", "params": {} } ], "value": 80, "inputs": { "merged_prs": 772, "open_issues": 3, "closed_issues": 223, "prs_merged_7d": null, "prs_decided_7d": null, "prs_merged_30d": null, "prs_decided_30d": null, "issue_closed_ratio": 0.987, "closed_unmerged_prs": 40, "first_time_authors_30d": null, "first_time_prs_merged_30d": null, "first_time_prs_decided_30d": null }, "components": [ { "key": "issue_resolution", "name": "Issue resolution", "detail": "99% of issues closed", "points": 41.5, "status": "partial", "details": [ { "code": "issues_closed_share", "params": { "share": 99 } } ], "max_points": 42 }, { "key": "pr_acceptance", "name": "PR acceptance", "detail": "772/812 decided PRs merged", "points": 28.5, "status": "partial", "details": [ { "code": "decided_prs_merged", "params": { "merged": 772, "decided": 812 } } ], "max_points": 30 }, { "key": "newcomer_pr_acceptance", "name": "Newcomer PR acceptance", "detail": "no first-time contributor's PR decided in 30d", "points": 0, "status": "excluded", "details": [ { "code": "no_newcomer_prs", "params": { "days": 30 } } ], "max_points": 13 }, { "key": "openssf_scorecard_code_review", "name": "OpenSSF Scorecard: Code-Review", "detail": "Found 1/30 approved changesets -- score normalized to 0", "points": 0, "status": "missed", "details": [], "max_points": 15 } ] }, { "key": "stewardship", "band": "at_risk", "name": "Ownership & stewardship", "note": null, "notes": [], "value": 34, "inputs": { "followers": 0, "owner_type": "Organization", "is_verified": null, "owner_login": "asciidoc-rs", "public_repos": 2, "account_age_days": 175 }, "components": [ { "key": "ownership_backing", "name": "Ownership backing", "detail": "organization-owned", "points": 30, "status": "met", "details": [ { "code": "owner_organization", "params": {} } ], "max_points": 30 }, { "key": "verified_domain", "name": "Verified domain", "detail": null, "points": 0, "status": "missed", "details": [], "max_points": 20 }, { "key": "owner_reach", "name": "Owner reach", "detail": "0 followers of asciidoc-rs", "points": 0, "status": "missed", "details": [ { "code": "owner_followers", "params": { "count": 0, "login": "asciidoc-rs" } } ], "max_points": 25 }, { "key": "track_record", "name": "Track record", "detail": "2 public repos, account ~0 yr old", "points": 4.4, "status": "partial", "details": [ { "code": "public_repos", "params": { "count": 2 } }, { "code": "account_age_years", "params": { "years": 0 } } ], "max_points": 25 } ] }, { "key": "package_maintenance", "band": "exceptional", "name": "Package maintenance", "note": null, "notes": [], "value": 100, "inputs": { "packages": [ "asciidoc-parser" ], "ecosystems": "crates", "any_deprecated": false, "min_days_since_publish": 0 }, "components": [ { "key": "published_resolvable", "name": "Published & resolvable", "detail": "1 package(s) on crates", "points": 25, "status": "met", "details": [ { "code": "packages_published", "params": { "count": 1, "ecosystems": "crates" } } ], "max_points": 25 }, { "key": "publish_recency", "name": "Publish recency", "detail": "latest publish 0 days ago", "points": 35, "status": "met", "details": [ { "code": "publish_recency", "params": { "days": 0 } } ], "max_points": 35 }, { "key": "version_history", "name": "Version history", "detail": "55 published versions", "points": 20, "status": "met", "details": [ { "code": "published_versions", "params": { "count": 55 } } ], "max_points": 20 }, { "key": "not_deprecated", "name": "Not deprecated", "detail": "active, not deprecated or yanked", "points": 20, "status": "met", "details": [ { "code": "package_not_deprecated", "params": {} } ], "max_points": 20 } ] } ], "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?" }, { "key": "engineering", "band": "moderate", "name": "Engineering Quality", "value": 61, "weight": 0.19, "metrics": [ { "key": "engineering_practices", "band": "good", "name": "Engineering practices", "note": null, "notes": [], "value": 68, "inputs": { "has_ci": true, "has_tests": true, "has_editorconfig": false, "has_linter_config": false, "has_precommit_config": false }, "components": [ { "key": "ci_workflows", "name": "CI workflows", "detail": "3 workflow(s)", "points": 24, "status": "met", "details": [ { "code": "ci_workflows", "params": { "count": 3 } } ], "max_points": 24 }, { "key": "tests_present", "name": "Tests present", "detail": null, "points": 24, "status": "met", "details": [], "max_points": 24 }, { "key": "linter_config", "name": "Linter config", "detail": null, "points": 0, "status": "missed", "details": [], "max_points": 16 }, { "key": "pre_commit_hooks", "name": "Pre-commit hooks", "detail": null, "points": 0, "status": "missed", "details": [], "max_points": 9.6 }, { "key": "editorconfig", "name": ".editorconfig", "detail": null, "points": 0, "status": "missed", "details": [], "max_points": 6.4 }, { "key": "openssf_scorecard_ci_tests", "name": "OpenSSF Scorecard: CI-Tests", "detail": "30 out of 30 merged PRs checked by a CI test -- score normalized to 10", "points": 20, "status": "met", "details": [], "max_points": 20 } ] }, { "key": "documentation", "band": "moderate", "name": "Documentation", "note": null, "notes": [], "value": 50, "inputs": { "topics": [ "asciidoc", "markup", "parser" ], "has_wiki": false, "homepage": null, "has_readme": true, "has_docs_dir": false, "has_description": true }, "components": [ { "key": "readme", "name": "README", "detail": null, "points": 30, "status": "met", "details": [], "max_points": 30 }, { "key": "documentation_directory", "name": "Documentation directory", "detail": null, "points": 0, "status": "missed", "details": [], "max_points": 25 }, { "key": "documentation_homepage_site", "name": "Documentation / homepage site", "detail": null, "points": 0, "status": "missed", "details": [], "max_points": 15 }, { "key": "repository_description", "name": "Repository description", "detail": null, "points": 10, "status": "met", "details": [], "max_points": 10 }, { "key": "topics", "name": "Topics", "detail": "3 topics", "points": 10, "status": "met", "details": [ { "code": "topics_count", "params": { "count": 3 } } ], "max_points": 10 }, { "key": "wiki", "name": "Wiki", "detail": null, "points": 0, "status": "missed", "details": [], "max_points": 10 } ] } ], "description": "Are baseline engineering and documentation practices in place?" }, { "key": "security", "band": "moderate", "name": "Security", "value": 61, "weight": 0.16, "metrics": [ { "key": "security_posture", "band": "moderate", "name": "Security posture", "note": "Excluded from scoring (no data or not applicable): Signed-Releases. Remaining weights renormalized.", "notes": [ { "code": "excluded_no_data", "params": { "components": [ "signed_releases" ] } }, { "code": "weights_renormalized", "params": {} } ], "value": 61, "inputs": { "source": "openssf_scorecard", "checks_evaluated": 17, "scorecard_version": "v5.5.0", "checks_inconclusive": 1, "scorecard_aggregate": 6.1 }, "components": [ { "key": "binary_artifacts", "name": "Binary-Artifacts", "detail": "no binaries found in the repo", "points": 7.5, "status": "met", "details": [], "max_points": 7.5 }, { "key": "branch_protection", "name": "Branch-Protection", "detail": "branch protection is not maximal on development and all release branches", "points": 2.2, "status": "partial", "details": [], "max_points": 7.5 }, { "key": "ci_tests", "name": "CI-Tests", "detail": "30 out of 30 merged PRs checked by a CI test -- score normalized to 10", "points": 2.5, "status": "met", "details": [], "max_points": 2.5 }, { "key": "cii_best_practices", "name": "CII-Best-Practices", "detail": "no effort to earn an OpenSSF best practices badge detected", "points": 0, "status": "missed", "details": [], "max_points": 2.5 }, { "key": "code_review", "name": "Code-Review", "detail": "Found 1/30 approved changesets -- score normalized to 0", "points": 0, "status": "missed", "details": [], "max_points": 7.5 }, { "key": "contributors", "name": "Contributors", "detail": "project has 14 contributing companies or organizations", "points": 2.5, "status": "met", "details": [], "max_points": 2.5 }, { "key": "dangerous_workflow", "name": "Dangerous-Workflow", "detail": "no dangerous workflow patterns detected", "points": 10, "status": "met", "details": [], "max_points": 10 }, { "key": "dependency_update_tool", "name": "Dependency-Update-Tool", "detail": "update tool detected", "points": 7.5, "status": "met", "details": [], "max_points": 7.5 }, { "key": "fuzzing", "name": "Fuzzing", "detail": "project is not fuzzed", "points": 0, "status": "missed", "details": [], "max_points": 5 }, { "key": "license", "name": "License", "detail": "license file detected", "points": 2.5, "status": "met", "details": [], "max_points": 2.5 }, { "key": "maintained", "name": "Maintained", "detail": "30 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10", "points": 7.5, "status": "met", "details": [], "max_points": 7.5 }, { "key": "packaging", "name": "Packaging", "detail": "packaging workflow detected", "points": 5, "status": "met", "details": [], "max_points": 5 }, { "key": "pinned_dependencies", "name": "Pinned-Dependencies", "detail": "all dependencies are pinned", "points": 5, "status": "met", "details": [], "max_points": 5 }, { "key": "sast", "name": "SAST", "detail": "SAST tool is not run on all commits -- score normalized to 0", "points": 0, "status": "missed", "details": [], "max_points": 5 }, { "key": "security_policy", "name": "Security-Policy", "detail": "security policy file not detected", "points": 0, "status": "missed", "details": [], "max_points": 5 }, { "key": "signed_releases", "name": "Signed-Releases", "detail": "no releases found", "points": 0, "status": "excluded", "details": [ { "code": "no_data", "params": {} } ], "max_points": 7.5 }, { "key": "token_permissions", "name": "Token-Permissions", "detail": "detected GitHub workflow tokens with excessive permissions", "points": 0, "status": "missed", "details": [], "max_points": 7.5 }, { "key": "vulnerabilities", "name": "Vulnerabilities", "detail": "0 existing vulnerabilities detected", "points": 7.5, "status": "met", "details": [], "max_points": 7.5 } ] }, { "key": "high_risk_jurisdiction_exposure", "band": "exceptional", "name": "High-Risk Jurisdiction Exposure", "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.", "notes": [ { "code": "jurisdiction_evidence_limits", "params": {} } ], "value": 100, "inputs": { "meaning": "self-published location evidence; not nationality or citizenship", "red_flag": false, "exposures": [], "policy_countries": [ "Russia", "Iran", "North Korea" ], "commit_weight_rule": { "min_commits": 50, "min_commit_share": 0.1 }, "review_only_matches": 0, "below_threshold_exposures": [], "assessed_self_published_locations": 21 }, "components": [ { "key": "policy_exposure_multiplier", "name": "Policy exposure multiplier", "detail": "no confirmed policy-scope location match", "points": 100, "status": "met", "details": [ { "code": "jurisdiction_no_match", "params": {} } ], "max_points": 100 } ] } ], "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?" }, { "key": "ai_readiness", "band": "moderate", "name": "AI Readiness", "value": 64, "weight": 0.04, "metrics": [ { "key": "ai_agent_context", "band": "weak", "name": "Agent context & guidance", "note": null, "notes": [], "value": 40, "inputs": { "has_llms_txt": false, "legible_history_share": 1, "agent_instruction_files": [], "agent_instruction_max_bytes": null }, "components": [ { "key": "agent_instructions", "name": "Agent instructions", "detail": "no CLAUDE.md / AGENTS.md / editor rules", "points": 0, "status": "missed", "details": [ { "code": "no_agent_instructions", "params": {} } ], "max_points": 45 }, { "key": "machine_readable_docs_llms_txt", "name": "Machine-readable docs (llms.txt)", "detail": null, "points": 0, "status": "missed", "details": [], "max_points": 15 }, { "key": "legible_commit_history", "name": "Legible commit history", "detail": "100 of 100 human commits state their intent (structured subject or explanatory body)", "points": 40, "status": "met", "details": [ { "code": "legible_history", "params": { "legible": 100, "sampled": 100 } } ], "max_points": 40 } ] }, { "key": "ai_verify_loop", "band": "excellent", "name": "Verify loop (build / test / typecheck)", "note": null, "notes": [], "value": 81, "inputs": { "has_nix": false, "has_tests": true, "lockfiles": [], "has_dockerfile": false, "typed_language": true, "bootstrap_files": [], "has_devcontainer": true, "has_linter_config": false, "typecheck_configs": [], "agent_commit_share": 0.86, "toolchain_manifests": [ "Cargo.toml", "parser/Cargo.toml", "sdd/Cargo.toml" ], "dependency_bot_commit_share": 0 }, "components": [ { "key": "one_command_bootstrap", "name": "One-command bootstrap", "detail": "Cargo.toml, parser/Cargo.toml, sdd/Cargo.toml (toolchain convention, no task runner)", "points": 12.6, "status": "partial", "details": [ { "code": "toolchain_convention", "params": { "files": "Cargo.toml, parser/Cargo.toml, sdd/Cargo.toml" } } ], "max_points": 18 }, { "key": "automated_tests", "name": "Automated tests", "detail": null, "points": 22, "status": "met", "details": [], "max_points": 22 }, { "key": "lint_format_config", "name": "Lint / format config", "detail": null, "points": 0, "status": "missed", "details": [], "max_points": 11 }, { "key": "static_type_checking", "name": "Static type checking", "detail": "Rust (statically typed)", "points": 11, "status": "met", "details": [ { "code": "statically_typed_language", "params": { "language": "Rust" } } ], "max_points": 11 }, { "key": "reproducible_environment", "name": "Reproducible environment", "detail": "devcontainer", "points": 10, "status": "met", "details": [ { "code": "file_list", "params": { "files": "devcontainer" } } ], "max_points": 10 }, { "key": "demonstrated_agent_practice", "name": "Demonstrated agent practice", "detail": "86 of the last 100 commits agent-authored or agent-credited", "points": 10, "status": "met", "details": [ { "code": "agent_authored_commits", "params": { "count": 86, "sampled": 100 } } ], "max_points": 10 }, { "key": "automated_maintenance", "name": "Automated maintenance", "detail": "dependency automation configured, none observed in the sampled commits", "points": 5, "status": "partial", "details": [ { "code": "dependency_bot_config_only", "params": {} } ], "max_points": 8 }, { "key": "openssf_scorecard_pinned_dependencies", "name": "OpenSSF Scorecard: Pinned-Dependencies", "detail": "all dependencies are pinned", "points": 10, "status": "met", "details": [], "max_points": 10 } ] }, { "key": "ai_code_legibility", "band": "exceptional", "name": "Code legibility for models", "note": null, "notes": [], "value": 94, "inputs": { "primary_language": "Rust", "largest_source_bytes": 434972, "source_files_sampled": 419, "oversized_source_files": 45 }, "components": [ { "key": "type_checkable_code", "name": "Type-checkable code", "detail": "Rust (statically typed)", "points": 45, "status": "met", "details": [ { "code": "statically_typed_language", "params": { "language": "Rust" } } ], "max_points": 45 }, { "key": "manageable_file_sizes", "name": "Manageable file sizes", "detail": "45/419 source files over 60KB", "points": 49.1, "status": "partial", "details": [ { "code": "oversized_source_files", "params": { "kb": 60, "sampled": 419, "oversized": 45 } } ], "max_points": 55 } ] }, { "key": "ai_interfaces", "band": "weak", "name": "Machine-readable interfaces", "note": null, "notes": [], "value": 40, "inputs": { "example_dirs": [ "examples" ], "has_mcp_signal": false, "api_schema_files": [] }, "components": [ { "key": "api_schema_openapi_graphql_proto", "name": "API schema (OpenAPI/GraphQL/proto)", "detail": null, "points": 0, "status": "missed", "details": [], "max_points": 40 }, { "key": "mcp_server", "name": "MCP server", "detail": null, "points": 0, "status": "missed", "details": [], "max_points": 20 }, { "key": "runnable_examples", "name": "Runnable examples", "detail": "examples", "points": 40, "status": "met", "details": [ { "code": "file_list", "params": { "files": "examples" } } ], "max_points": 40 } ] } ], "description": "How well is the repo equipped to be developed and maintained with AI coding agents? Carries a deliberately small weight: agent tooling is a real maintenance signal, but its absence must never gate the top of the scale (calibration saturates at raw 91, so 100/100 remains reachable with AI Readiness at zero)." } ], "classification": { "top": [ "library" ], "labels": [ "library" ], "scores": { "library": 6 }, "primary": "library", "evidence": [ { "tier": "distribution", "label": "library", "source": "registry:crates", "weight": 6 } ], "artifacts": [], "confidence": "medium", "host_extension": false, "runs_as_process": false, "consumed_by_code": true }, "metrics_version": "2.5.0" }, "warnings": [ "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token", "crates package 'sdd' points at a different repository (https://codeberg.org/wvwwvwwv/scalable-delayed-dealloc); excluded from ecosystem scoring", "deps.dev does not index crates:asciidoc-parser@0.29.4; advisories assessed against the repository dependency graph instead", "No resolved dependencies carried a version and a supported ecosystem" ], "report_type": "repository", "generated_at": "2026-08-01T18:22:10.907697Z", "schema_version": "0.27.0", "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/a/asciidoc-rs/asciidoc-parser.svg", "full_name": "asciidoc-rs/asciidoc-parser", "license_state": "standard", "license_spdx": "Apache-2.0" }, "repoMeta": null, "notFound": false, "related": [ { "id": 36269, "full_name": "markedjs/marked", "url": "https://github.com/markedjs/marked", "description": "A markdown parser and compiler. Built for speed.", "ecosystem": "npm", "ecosystems": [ "npm" ], "primary_language": "JavaScript", "languages": [ "JavaScript", "TypeScript", "HTML" ], "topics": [ "markdown", "compiler", "parser", "commonmark", "gfm", "hacktoberfest", "markup", "html" ], "license_spdx": null, "license_state": "custom", "stars": 37026, "forks": 3613, "watchers": 381, "monthly_downloads": 242534193, "latest_score": 98, "latest_band": "exceptional", "latest_scanned_at": "2026-08-04T19:43:46.054715Z", "has_high_risk_jurisdiction_exposure": false, "has_malicious_dependency": false, "growth_authenticity": "unverified", "abandonment_state": "maintained", "red_flags": [], "icon_url": "/icon/v1/markedjs/marked?v=6c02a7bf-1", "icon_source_type": "homepage", "badge_url": "" }, { "id": 9140, "full_name": "oxc-project/oxc", "url": "https://github.com/oxc-project/oxc", "description": "⚓ A collection of high-performance JavaScript tools.", "ecosystem": "crates", "ecosystems": [ "crates", "npm" ], "primary_language": "Rust", "languages": [ "Rust" ], "topics": [ "compiler", "javascript", "linter", "minifier", "parser", "typescript", "transpiler", "development-tools", "compilers", "web-programming" ], "license_spdx": "MIT", "license_state": "standard", "stars": 22220, "forks": 1171, "watchers": 85, "monthly_downloads": 1521396, "latest_score": 97, "latest_band": "exceptional", "latest_scanned_at": "2026-08-05T04:02:02.798361Z", "has_high_risk_jurisdiction_exposure": false, "has_malicious_dependency": false, "growth_authenticity": "unverified", "abandonment_state": "maintained", "red_flags": [], "icon_url": "/icon/v1/oxc-project/oxc?v=de80ce08-1", "icon_source_type": "homepage", "badge_url": "" }, { "id": 18476, "full_name": "biomejs/biome", "url": "https://github.com/biomejs/biome", "description": "A toolchain for web projects, aimed to provide functionalities to maintain them. Biome offers formatter and linter, usable via CLI and LSP.", "ecosystem": "crates", "ecosystems": [ "crates", "npm" ], "primary_language": "Rust", "languages": [ "Rust" ], "topics": [ "css", "formatter", "javascript", "jsx", "linter", "static-code-analysis", "typescript", "web", "json", "parser", "development-tools", "web-programming" ], "license_spdx": "Apache-2.0", "license_state": "standard", "stars": 25498, "forks": 1175, "watchers": 98, "monthly_downloads": 233173, "latest_score": 96, "latest_band": "exceptional", "latest_scanned_at": "2026-08-05T03:11:12.534840Z", "has_high_risk_jurisdiction_exposure": false, "has_malicious_dependency": false, "growth_authenticity": "unverified", "abandonment_state": "maintained", "red_flags": [], "icon_url": "/icon/v1/biomejs/biome?v=bf585c67-1", "icon_source_type": "homepage", "badge_url": "" }, { "id": 3036, "full_name": "swc-project/swc", "url": "https://github.com/swc-project/swc", "description": "Rust-based platform for the Web", "ecosystem": "crates", "ecosystems": [ "crates" ], "primary_language": "Rust", "languages": [ "Rust" ], "topics": [ "ecmascript", "compiler", "rust", "javascript", "parser", "babel", "swc", "ecmascript-parser", "typescript", "typescript-compiler", "typescript-parser" ], "license_spdx": "Apache-2.0", "license_state": "standard", "stars": 34163, "forks": 1533, "watchers": 182, "monthly_downloads": 1246493, "latest_score": 96, "latest_band": "exceptional", "latest_scanned_at": "2026-08-05T01:26:43.411729Z", "has_high_risk_jurisdiction_exposure": false, "has_malicious_dependency": false, "growth_authenticity": "unverified", "abandonment_state": "maintained", "red_flags": [], "icon_url": "/icon/v1/swc-project/swc?v=400c5222-1", "icon_source_type": "homepage", "badge_url": "" }, { "id": 44230, "full_name": "wasmerio/wasmer", "url": "https://github.com/wasmerio/wasmer", "description": "🚀 Fast, secure, lightweight containers based on WebAssembly", "ecosystem": "crates", "ecosystems": [ "crates" ], "primary_language": "Rust", "languages": [ "Rust" ], "topics": [ "webassembly", "wasm", "wasi", "emscripten", "rust", "windows", "macos", "linux", "wasmer", "wasix", "runtime", "vm", "cli", "command-line-interface", "api-bindings", "cache", "caching", "types", "data-structures", "no-std", "toml", "parser-implementations" ], "license_spdx": "MIT", "license_state": "standard", "stars": 20940, "forks": 989, "watchers": 194, "monthly_downloads": 727452, "latest_score": 96, "latest_band": "exceptional", "latest_scanned_at": "2026-08-05T04:21:24.420344Z", "has_high_risk_jurisdiction_exposure": false, "has_malicious_dependency": false, "growth_authenticity": "unverified", "abandonment_state": "maintained", "red_flags": [], "icon_url": "/icon/v1/wasmerio/wasmer?v=bf05dcc7-1", "icon_source_type": "homepage", "badge_url": "" }, { "id": 1517, "full_name": "tree-sitter/tree-sitter", "url": "https://github.com/tree-sitter/tree-sitter", "description": "An incremental parsing system for programming tools", "ecosystem": "crates", "ecosystems": [ "crates" ], "primary_language": "Rust", "languages": [ "Rust", "C" ], "topics": [ "incremental", "parsing", "tree-sitter", "rust", "parser", "wasm", "external-ffi-bindings", "api-bindings", "text-editors" ], "license_spdx": "MIT", "license_state": "standard", "stars": 26539, "forks": 2797, "watchers": 284, "monthly_downloads": 3981552, "latest_score": 95, "latest_band": "exceptional", "latest_scanned_at": "2026-08-05T02:50:54.012090Z", "has_high_risk_jurisdiction_exposure": false, "has_malicious_dependency": false, "growth_authenticity": "unverified", "abandonment_state": "maintained", "red_flags": [], "icon_url": "/icon/v1/tree-sitter/tree-sitter?v=a07c055f-1", "icon_source_type": "avatar", "badge_url": "" } ] } }
Public record
Software health reportschema 0.27.0 · metrics 2.5.0 · 2026-08-01 18:22 UTC

asciidoc-rs / asciidoc-parser

AsciiDoc parser

Rust · RubyApache-2.0★ 34 stars⑂ 4 forkssince Dec 2023View on GitHub ↗

asciidoc-rs/asciidoc-parser holds a health index of 77 out of 100, placing it in the Good band. It scores highest on Vitality (94/100) and lowest on Community & Adoption (43/100). It was last updated today. 2 contributors account for most of its recent work.

77
overall / 100
Good

Software health index

Metrics are grouped into weighted categories on one standardized 1–100 scale. Overall starts as their weighted mean, calibrated against the distribution of the public record so bands carry percentile meaning; when public evidence triggers the High-Risk Jurisdiction Policy, the rating is adjusted and receives an At Risk ceiling of 34.

77
Exceptional93-100The record's top tier (≈ top 5%); essentially all checked criteria met
Excellent80-92Strong across the board; minor gaps
Good65-79Healthy; gaps are limited and manageable
Moderate50-64Acceptable with notable gaps; review recommended
Weak35-49Material weaknesses across several areas
At Risk20-34Significant weaknesses; adoption warrants caution
Critical1-19Severe problems (abandoned, single-maintainer, no hygiene)
VitalityCommunity &AdoptionSustainability &GovernanceEngineeringQualitySecurityAI Readiness

Score profile

Each axis is a category. The shape matters more than the average — a healthy subject fills the whole shape, while a spike-and-crater profile means strength in one dimension is masking risk in another.

The weighted overall 66 is calibrated to 77 on the published index scale (record calibration 2026-08-02).

Ownership

Asciidoc in RustOrganization
0 followers2 public repossince Feb 2026

This repository is backed by an organization — shared, accountable stewardship that can outlive any single maintainer.

Package ecosystems

RegistryPackageVersionDownloads / moVersionsLast publishTags
crates.iosddpoints to another repo — not scored4.8.85,899,1737230 days agoconcurrentgarbagememoryepochlock-freedata-structuresconcurrencymemory-management
crates.ioasciidoc-parser0.29.42,012550 days agoparserasciidocparser-implementations

Metrics by category

Vitality

Is the project alive — is code being written and are releases shipping?

94Exceptional · 21% of overall
How it's scored
36/36Push recency — last push 0 days ago
25.6/36Commit cadence — 37/52 weeks with commits
18/18Commit volume — 546 commits in the last year
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10
Inputs used
commits_last_year546
human_commit_share1
days_since_last_push0
active_weeks_last_year37

Release discipline

100Exceptional
How it's scored
27/27Ships releases — 55 releases published
36/36Release recency — latest release 0 days ago
27/27Release cadence — a release every ~0.7 days
0/10OpenSSF Scorecard: Signed-Releases — no data
Inputs used
releases_count55
latest_release_tagv0.29.4
releases_from_tagsno
days_since_latest_release0
mean_days_between_releases0.7
Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.

Community & Adoption

Does the project have users, downloads, attention, and a welcoming setup for contributors?

43Weak · 17% of overall
How it's scored
24.6/60Stars — 34 stars
4/25Forks — 4 forks
0/15Watchers — 2 watchers
Inputs used
forks4
stars34
watchers2
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
How it's scored
22.5/22.5README
22.5/22.5License — recognized license (Apache-2.0)
0/18CONTRIBUTING guide
0/13.5Code of conduct
0/7.2Issue template
0/6.3PR template
Inputs used
has_readmeyes
has_licenseyes
readme_badges
has_contributingno
has_issue_templateno
has_code_of_conductno
readme_badge_services
has_pull_request_templateno
How it's scored
44.1/80Monthly downloads — 2,012 downloads/month across crates
0/20Registry dependents — not reported by this ecosystem
Inputs used
packagesasciidoc-parser
dependents
ecosystemscrates
total_downloads13,542
monthly_downloads2,012
Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.

Sustainability & Governance

Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?

66Good · 23% of overall
How it's scored
25.2/54Bus factor — 2 contributor(s) cover half of all commits
11.4/22.5Commit distribution — top contributor authored 49% of commits
13.5/13.5Contributor breadth — 22 contributors
10/10OpenSSF Scorecard: Contributors — project has 14 contributing companies or organizations
Inputs used
bus_factor2
contributors_sampled22
top_contributor_share0.492
How it's scored
41.5/42Issue resolution — 99% of issues closed
28.5/30PR acceptance — 772/812 decided PRs merged
0/13Newcomer PR acceptance — no first-time contributor's PR decided in 30d
0/15OpenSSF Scorecard: Code-Review — Found 1/30 approved changesets -- score normalized to 0
Inputs used
merged_prs772
open_issues3
closed_issues223
prs_merged_7d
prs_decided_7d
prs_merged_30d
prs_decided_30d
issue_closed_ratio0.987
closed_unmerged_prs40
first_time_authors_30d
first_time_prs_merged_30d
first_time_prs_decided_30d
Excluded from scoring (no data or not applicable): newcomer_pr_acceptance. Remaining weights renormalized.
How it's scored
30/30Ownership backing — organization-owned
0/20Verified domain
0/25Owner reach — 0 followers of asciidoc-rs
4.4/25Track record — 2 public repos, account ~0 yr old
Inputs used
followers0
owner_typeOrganization
is_verified
owner_loginasciidoc-rs
public_repos2
account_age_days175

Package maintenance

100Exceptional
How it's scored
25/25Published & resolvable — 1 package(s) on crates
35/35Publish recency — latest publish 0 days ago
20/20Version history — 55 published versions
20/20Not deprecated — active, not deprecated or yanked
Inputs used
packagesasciidoc-parser
ecosystemscrates
any_deprecatedno
min_days_since_publish0

Engineering Quality

Are baseline engineering and documentation practices in place?

61Moderate · 19% of overall
How it's scored
24/24CI workflows — 3 workflow(s)
24/24Tests present
0/16Linter config
0/9.6Pre-commit hooks
0/6.4.editorconfig
20/20OpenSSF Scorecard: CI-Tests — 30 out of 30 merged PRs checked by a CI test -- score normalized to 10
Inputs used
has_ciyes
has_testsyes
has_editorconfigno
has_linter_configno
has_precommit_configno

Documentation

50Moderate
How it's scored
30/30README
0/25Documentation directory
0/15Documentation / homepage site
10/10Repository description
10/10Topics — 3 topics
0/10Wiki
Inputs used
topicsasciidoc, markup, parser
has_wikino
homepage
has_readmeyes
has_docs_dirno
has_descriptionyes

Security

Are visible security and supply-chain practices strong, without unresolved high-risk jurisdiction exposure?

61Moderate · 16% of overall
How it's scored
7.5/7.5Binary-Artifacts — no binaries found in the repo
2.2/7.5Branch-Protection — branch protection is not maximal on development and all release branches
2.5/2.5CI-Tests — 30 out of 30 merged PRs checked by a CI test -- score normalized to 10
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 1/30 approved changesets -- score normalized to 0
2.5/2.5Contributors — project has 14 contributing companies or organizations
10/10Dangerous-Workflow — no dangerous workflow patterns detected
7.5/7.5Dependency-Update-Tool — update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5License — license file detected
7.5/7.5Maintained — 30 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10
5/5Packaging — packaging workflow detected
5/5Pinned-Dependencies — all dependencies are pinned
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — no data
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
7.5/7.5Vulnerabilities — 0 existing vulnerabilities detected
Inputs used
sourceopenssf_scorecard
checks_evaluated17
scorecard_versionv5.5.0
checks_inconclusive1
scorecard_aggregate6.1
Excluded from scoring (no data or not applicable): signed_releases. Remaining weights renormalized.

AI Readiness

How well is the repo equipped to be developed and maintained with AI coding agents? Carries a deliberately small weight (4%): agent tooling is a real maintenance signal, but a repository with none can still reach 100/100.

64Moderate · 4% of overall
How it's scored
0/45Agent instructions — no CLAUDE.md / AGENTS.md / editor rules
0/15Machine-readable docs (llms.txt)
40/40Legible commit history — 100 of 100 human commits state their intent (structured subject or explanatory body)
Inputs used
has_llms_txtno
legible_history_share1
agent_instruction_files
agent_instruction_max_bytes
How it's scored
12.6/18One-command bootstrap — Cargo.toml, parser/Cargo.toml, sdd/Cargo.toml (toolchain convention, no task runner)
22/22Automated tests
0/11Lint / format config
11/11Static type checking — Rust (statically typed)
10/10Reproducible environment — devcontainer
10/10Demonstrated agent practice — 86 of the last 100 commits agent-authored or agent-credited
5/8Automated maintenance — dependency automation configured, none observed in the sampled commits
10/10OpenSSF Scorecard: Pinned-Dependencies — all dependencies are pinned
Inputs used
has_nixno
has_testsyes
lockfiles
has_dockerfileno
typed_languageyes
bootstrap_files
has_devcontaineryes
has_linter_configno
typecheck_configs
agent_commit_share0.86
toolchain_manifestsCargo.toml, parser/Cargo.toml, sdd/Cargo.toml
dependency_bot_commit_share0
How it's scored
45/45Type-checkable code — Rust (statically typed)
49.1/55Manageable file sizes — 45/419 source files over 60KB
Inputs used
primary_languageRust
largest_source_bytes434,972
source_files_sampled419
oversized_source_files45
How it's scored
0/40API schema (OpenAPI/GraphQL/proto)
0/20MCP server
40/40Runnable examples — examples
Inputs used
example_dirsexamples
has_mcp_signalno
api_schema_files

Key facts

34GitHub stars
22contributors
546commits, last 12 months
0days since last push
55releases
2bus factor
3open issues
crates.iopackage ecosystems

Data collection warnings

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • crates package 'sdd' points at a different repository (https://codeberg.org/wvwwvwwv/scalable-delayed-dealloc); excluded from ecosystem scoring
  • deps.dev does not index crates:asciidoc-parser@0.29.4; advisories assessed against the repository dependency graph instead
  • No resolved dependencies carried a version and a supported ecosystem

More detail

Star and fork history 0 ★ / 4 ⇿
0Stars
4Forks
20Releases

When each star and fork was added, collected from GitHub and bucketed by day. Cumulative growth sits directly above the daily additions it is made of, so the two read against each other: steady organic accretion looks nothing like an abrupt, short-lived burst. Where that difference is measurable, it is reported as growth authenticity.

1223344412026-012026-042026-07
Major 0Minor 9Patch 11
OpenSSF Scorecard 6.1 / 10
6.1aggregate

Independent, tool-agnostic security assessment from the open-source OpenSSF Scorecard. Each check rewards a security practice, not a specific vendor's tool. Checks Scorecard could not determine are marked n/a and excluded from the security score (never counted as zero).Scorecard v5.5.0 · 2026-08-01 18:21 UTC

10Binary-Artifactsno binaries found in the repo
3Branch-Protectionbranch protection is not maximal on development and all release branches
10CI-Tests30 out of 30 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 1/30 approved changesets -- score normalized to 0
10Contributorsproject has 14 contributing companies or organizations
10Dangerous-Workflowno dangerous workflow patterns detected
10Dependency-Update-Toolupdate tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10
10Packagingpackaging workflow detected
10Pinned-Dependenciesall dependencies are pinned
0SASTSAST tool is not run on all commits -- score normalized to 0
0Security-Policysecurity policy file not detected
n/aSigned-Releasesno releases found
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
10Vulnerabilities0 existing vulnerabilities detected
Direct dependencies 7
RegistryPackageVersion constraintManifest
crates.iobytecount0.6.7parser/Cargo.toml
crates.iomemchr2.6.4parser/Cargo.toml
crates.iopercent-encoding2.3.2parser/Cargo.toml
crates.ioregex1.11.1parser/Cargo.toml
crates.ioself_cell1.2.0parser/Cargo.toml
crates.iothiserror2.0.1parser/Cargo.toml
crates.iowalkdir2.5sdd/Cargo.toml
All dependencies 10

Full resolved dependency set from the GitHub dependency graph: 7 direct and 3 indirect (transitive) packages. The transitive closure is complete when the repository commits a lockfile.

RegistryPackageVersionRelation
crates.iobytecountdirect
crates.iomemchrdirect
crates.iopercent-encodingdirect
crates.ioregexdirect
crates.ioself_celldirect
crates.iothiserrordirect
crates.iowalkdirdirect
crates.iocodspeed-criterion-compatindirect
crates.iocriterionindirect
crates.iopretty_assertions_sortedindirect
Dependency advisories not assessed

Advisory matching could not run for this report: No resolved dependencies carried a version and a supported ecosystem

Raw JSON report machine-readable
{
  "data": {
    "repo": {
      "topics": [
        "asciidoc",
        "markup",
        "parser"
      ],
      "is_fork": false,
      "size_kb": 10362,
      "has_wiki": false,
      "homepage": null,
      "languages": {
        "Ruby": 1365426,
        "Rust": 9173981
      },
      "pushed_at": "2026-08-01T18:18:34Z",
      "created_at": "2023-12-08T22:28:07Z",
      "owner_type": "Organization",
      "updated_at": "2026-08-01T17:53:52Z",
      "description": "AsciiDoc parser",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "Apache-2.0",
      "default_branch": "main",
      "license_spdx_raw": "Apache-2.0",
      "primary_language": "Rust",
      "significant_languages": [
        "Rust",
        "Ruby"
      ]
    },
    "owner": {
      "blog": null,
      "name": "Asciidoc in Rust",
      "type": "Organization",
      "login": "asciidoc-rs",
      "company": null,
      "location": null,
      "followers": 0,
      "avatar_url": "https://avatars.githubusercontent.com/u/259974080?v=4",
      "created_at": "2026-02-06T23:44:44Z",
      "is_verified": null,
      "public_repos": 2,
      "account_age_days": 175
    },
    "license": {
      "state": "standard",
      "spdx_id": "Apache-2.0",
      "raw_spdx": "Apache-2.0",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.29.4",
          "kind": "patch",
          "published_at": "2026-08-01T16:14:24Z"
        },
        {
          "tag": "v0.29.3",
          "kind": "patch",
          "published_at": "2026-08-01T15:12:16Z"
        },
        {
          "tag": "v0.29.2",
          "kind": "patch",
          "published_at": "2026-08-01T03:07:56Z"
        },
        {
          "tag": "v0.29.1",
          "kind": "patch",
          "published_at": "2026-07-31T16:04:51Z"
        },
        {
          "tag": "v0.29.0",
          "kind": "minor",
          "published_at": "2026-07-30T11:59:36Z"
        },
        {
          "tag": "v0.28.1",
          "kind": "patch",
          "published_at": "2026-07-29T04:41:03Z"
        },
        {
          "tag": "v0.28.0",
          "kind": "minor",
          "published_at": "2026-07-29T01:56:13Z"
        },
        {
          "tag": "v0.27.4",
          "kind": "patch",
          "published_at": "2026-07-27T19:11:27Z"
        },
        {
          "tag": "v0.27.3",
          "kind": "patch",
          "published_at": "2026-07-27T14:34:35Z"
        },
        {
          "tag": "v0.27.2",
          "kind": "patch",
          "published_at": "2026-07-26T18:15:58Z"
        },
        {
          "tag": "v0.27.1",
          "kind": "patch",
          "published_at": "2026-07-25T20:45:30Z"
        },
        {
          "tag": "v0.27.0",
          "kind": "minor",
          "published_at": "2026-07-25T04:26:16Z"
        },
        {
          "tag": "v0.26.0",
          "kind": "minor",
          "published_at": "2026-07-24T15:53:14Z"
        },
        {
          "tag": "v0.25.0",
          "kind": "minor",
          "published_at": "2026-07-23T15:22:02Z"
        },
        {
          "tag": "v0.24.0",
          "kind": "minor",
          "published_at": "2026-07-23T04:34:34Z"
        },
        {
          "tag": "v0.23.4",
          "kind": "patch",
          "published_at": "2026-07-18T16:01:38Z"
        },
        {
          "tag": "v0.23.3",
          "kind": "patch",
          "published_at": "2026-07-16T03:42:30Z"
        },
        {
          "tag": "v0.23.2",
          "kind": "patch",
          "published_at": "2026-07-16T00:51:13Z"
        },
        {
          "tag": "v0.23.1",
          "kind": "patch",
          "published_at": "2026-07-15T04:54:15Z"
        },
        {
          "tag": "v0.23.0",
          "kind": "minor",
          "published_at": "2026-07-14T15:11:44Z"
        },
        {
          "tag": "v0.22.1",
          "kind": "patch",
          "published_at": "2026-07-13T04:20:21Z"
        },
        {
          "tag": "v0.22.0",
          "kind": "minor",
          "published_at": "2026-07-13T02:50:59Z"
        },
        {
          "tag": "v0.21.0",
          "kind": "minor",
          "published_at": "2026-07-12T16:06:19Z"
        },
        {
          "tag": "v0.20.0",
          "kind": "minor",
          "published_at": "2026-07-12T02:15:00Z"
        },
        {
          "tag": "v0.19.2",
          "kind": "patch",
          "published_at": "2026-07-11T16:10:24Z"
        },
        {
          "tag": "v0.19.1",
          "kind": "patch",
          "published_at": "2026-07-10T15:21:10Z"
        },
        {
          "tag": "v0.19.0",
          "kind": "minor",
          "published_at": "2026-07-05T04:01:37Z"
        },
        {
          "tag": "v0.18.0",
          "kind": "minor",
          "published_at": "2026-07-04T21:17:01Z"
        },
        {
          "tag": "v0.17.0",
          "kind": "minor",
          "published_at": "2026-06-30T13:52:23Z"
        },
        {
          "tag": "v0.16.0",
          "kind": "minor",
          "published_at": "2026-06-29T20:57:15Z"
        },
        {
          "tag": "v0.15.2",
          "kind": "patch",
          "published_at": "2026-06-29T14:39:19Z"
        },
        {
          "tag": "v0.15.1",
          "kind": "patch",
          "published_at": "2026-06-20T00:28:43Z"
        },
        {
          "tag": "v0.15.0",
          "kind": "minor",
          "published_at": "2026-06-19T01:21:07Z"
        },
        {
          "tag": "v0.14.5",
          "kind": "patch",
          "published_at": "2026-06-18T04:38:17Z"
        },
        {
          "tag": "v0.14.4",
          "kind": "patch",
          "published_at": "2026-03-07T16:38:47Z"
        },
        {
          "tag": "v0.14.3",
          "kind": "patch",
          "published_at": "2026-01-25T01:19:57Z"
        },
        {
          "tag": "v0.14.2",
          "kind": "patch",
          "published_at": "2026-01-17T20:00:18Z"
        },
        {
          "tag": "v0.14.1",
          "kind": "patch",
          "published_at": "2026-01-02T02:48:33Z"
        },
        {
          "tag": "v0.14.0",
          "kind": "minor",
          "published_at": "2025-12-08T04:33:46Z"
        },
        {
          "tag": "v0.13.1",
          "kind": "patch",
          "published_at": "2025-11-17T00:30:53Z"
        },
        {
          "tag": "v0.13.0",
          "kind": "minor",
          "published_at": "2025-11-16T02:12:01Z"
        },
        {
          "tag": "v0.12.0",
          "kind": "minor",
          "published_at": "2025-11-15T01:04:20Z"
        },
        {
          "tag": "v0.11.0",
          "kind": "minor",
          "published_at": "2025-11-02T21:47:12Z"
        },
        {
          "tag": "v0.10.0",
          "kind": "minor",
          "published_at": "2025-10-15T02:27:11Z"
        },
        {
          "tag": "v0.9.0",
          "kind": "minor",
          "published_at": "2025-10-12T23:17:56Z"
        },
        {
          "tag": "v0.8.0",
          "kind": "minor",
          "published_at": "2025-10-10T05:04:40Z"
        },
        {
          "tag": "v0.7.0",
          "kind": "minor",
          "published_at": "2025-09-18T04:35:20Z"
        },
        {
          "tag": "v0.6.0",
          "kind": "minor",
          "published_at": "2025-09-08T05:10:31Z"
        },
        {
          "tag": "v0.5.0",
          "kind": "minor",
          "published_at": "2025-08-16T20:42:11Z"
        },
        {
          "tag": "v0.4.0",
          "kind": "minor",
          "published_at": "2025-04-27T19:26:02Z"
        },
        {
          "tag": "v0.3.1",
          "kind": "patch",
          "published_at": "2025-04-14T03:55:19Z"
        },
        {
          "tag": "v0.3.0",
          "kind": "minor",
          "published_at": "2025-04-11T20:31:10Z"
        },
        {
          "tag": "v0.2.0",
          "kind": "minor",
          "published_at": "2024-11-30T19:23:59Z"
        },
        {
          "tag": "v0.1.1",
          "kind": "patch",
          "published_at": "2024-10-26T22:33:15Z"
        },
        {
          "tag": "v0.1.0",
          "kind": "minor",
          "published_at": "2024-10-26T22:28:00Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "85320d8042ad10832b6e6cdc5cc7f7ef740c558f",
          "body": "A block title (`.Title`) directly above the `= …` document-title line\nmeans the line is not the document title. Asciidoctor demotes it to a\nlevel-0 section heading in the body, leaves the header empty, and logs\n\"level 0 sections can only be used when doctype is book\".\n\nv0.29.3 delivered only the car\n[…]\nning still hold. This also\nmakes a block title above `= …` at the document start behave exactly like\nthe same construct mid-body.\n\nCloses #1037\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Demote the document title when block metadata precedes it (#1038)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-08-01T17:53:45Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b658c8d3f19b02767dd0c0e447cb1eb9d99cfaca",
          "body": null,
          "is_bot": false,
          "headline": "chore(asciidoc-parser): release v0.29.4 (#1035)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-08-01T16:13:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ffb81e9641a3d6e2fa640752a81f796915ac46ca",
          "body": "…ue (#1034)\n\n* fix: Strip a trailing `@` soft-set modifier from an API attribute value\n\nA single trailing `@` on an attribute value supplied via the API (the\nAsciidoctor CLI/API soft-set modifier) is now stripped from the stored\nvalue, and the attribute is made overridable by a document `:name:` ent\n[…]\nhe crate's `#![deny(warnings)]`,\nfailing the internal-documentation CI job.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Strip a trailing `@` soft-set modifier from an API attribute val…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-08-01T16:06:18Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "78f8a5f0e76c29812d4ebef7263e363faf21bcc0",
          "body": null,
          "is_bot": false,
          "headline": "chore(asciidoc-parser): release v0.29.3 (#1031)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-08-01T15:11:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "42a8a285fe280f75443d82564a7a5de3fd064610",
          "body": "…try (#1032)\n\nA single `:author:` attribute entry populated `author` (and the derived\n`firstname`, `lastname`, `authorinitials`, …) inline but never set the\ncombined `authors` attribute, so `{authors}` rendered empty. The implicit\nauthor line and the `:authors:` / indexed `:author_N:` forms all set \n[…]\n is done inline rather\nthan through `set_author_metadata` so an explicit `:authorinitials:`\noverride on this path still survives.\n\nCloses #1027\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Set the combined `authors` attribute from a single `:author:` en…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-08-01T15:05:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e9d97bc5912e51fe49857cff17e1ab4c3cfaebf1",
          "body": "…ent (#1030)\n\n* fix: Treat a section heading inside a delimited block as literal content\n\nA `== …` line inside a delimited block (an example `====`, sidebar\n`****`, or open `--` block, a quote `____` block, or a Markdown-style\nblockquote) was parsed as a real section. Asciidoctor only recognizes\nsec\n[…]\nary, so cell sections are recognized\nregardless of where the table appears.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Treat a section heading inside a delimited block as literal cont…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-08-01T05:04:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0c5621ec0f21620d893fe4192b4959fdc30b04fc",
          "body": "…le (#1028)\n\n* fix: Coerce a leveloffset-shifted level-0 heading to the document title\n\nWhen a `:leveloffset:` shift drives a heading to effective level 0, that\nheading is now coerced to the document title (doctitle), mirroring\nAsciidoctor's `is_next_line_doctitle?`. Previously the offset was applie\n[…]\nvel-1 section by the body parser. Add a test for\nthe tab-delimited variant.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Coerce a leveloffset-shifted level-0 heading to the document tit…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-08-01T04:07:44Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "761ebf78f9ee3f31e795c4b28f076f1d69b03e04",
          "body": "…rally (#1026)\n\n* fix: Ignore an empty block anchor `[[]]` instead of rendering it literally\n\nAn empty bracketed block anchor (`[[]]`) on its own line above a block\nnames nothing. Asciidoctor drops it; this crate was instead leaving the\nline in place, so it rendered as a literal `[[]]` paragraph bef\n[…]\n\nblock\". Adds regression tests for both the open-block and lone-body forms.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Ignore an empty block anchor `[[]]` instead of rendering it lite…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-08-01T04:00:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e271a290c583a186e10746842cf1da59511c2a3e",
          "body": "…adata (#1029)\n\nA block title line (`.Title`) directly above the document title (`= …`)\nwas not recognized in the document header. It fell through to the block\nparser, which attached the block title to a paragraph whose text was the\nescaped `= …` line, so the title was rendered as literal paragraph \n[…]\ncument title as a level-0 section, so it keeps `= …` as the\ndocument title. The block-title recognition and carryover are shared.\n\nCloses #1022\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Recognize a block title above the document title as document met…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-08-01T03:44:48Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0f9585ba016d1ff540d1d9c9574596be7dd5f66a",
          "body": null,
          "is_bot": false,
          "headline": "chore(asciidoc-parser): release v0.29.2 (#1019)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-08-01T03:07:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c50dc8ee7b4013ff083fa029389485ec1cc93497",
          "body": "… include (#1021)\n\nAn `IncludeFileHandler` that finds and reads a file which is not valid UTF-8\nand cannot be transcoded (no `encoding` attribute, or one it does not support)\npreviously had to return `IncludeResolution::NotFound`, misreporting the cause\nas \"include file not found\".\n\nAdd an `IncludeR\n[…]\ntor's fatal\n`invalid byte sequence in UTF-8` does.\n\nBoth types are `#[non_exhaustive]`, so the additions are backward compatible.\n\nCloses #1020\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: Add IncludeResolution::NotDecodable for a found-but-undecodable…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-08-01T03:03:08Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1d7839bdd1d89446284ec87256f5b36ca56bcbee",
          "body": "…tains a nested section (#1017)\n\n* fix: Emit a warning when a special section that doesn't support subsections contains a nested section\n\nSpecial sections such as `glossary`, `bibliography`, `colophon`,\n`dedication`, and `index` do not support nested sections. Asciidoctor\nlogs an error (e.g. `glossa\n[…]\ntion. Adds a regression\ntest covering metadata above the offending heading.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Warn when a special section that doesn't support subsections con…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-08-01T02:52:40Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bca694ba89c7379d20d85c637ff74cfcc8b9e1d6",
          "body": "…te heading (#1018)\n\n* fix: Treat a `[float]`/`[discrete]` level-0 (`=`) heading as a discrete heading\n\nA `[float]`/`[discrete]` style on a level-0 (`=`) heading was promoted to\nthe document title and dropped from the block stream, instead of yielding a\ndiscrete floating-title block. Discrete headin\n[…]\nstyles_gate_doctitle_by_effective_style` covering both\noverride directions.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Treat a `[float]`/`[discrete]` level-0 (`=`) heading as a discre…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-08-01T02:47:16Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c603302bcfad4510b3a679cf89ff8da3ff091b8a",
          "body": "…tring (#1016)\n\nWhen an indexed `:author_N:` attribute entry overrode one author of a\nmulti-author implicit author line, the individual `author_N` attribute was\nupdated but the combined `authors` string (and `Document::authors()`) still\nreflected the original, un-overridden author.\n\n`resolve_authors\n[…]\nluding `authors` and `authorcount` –\nso `{authors}`, `Document::authors()`, and the resolved author list all\nreflect the override.\n\nclose #1013\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Reflect an indexed :author_N: override in the combined authors s…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-08-01T02:28:03Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e89e7584b1fcb5e57c26f93cfb2c19db6795908c",
          "body": null,
          "is_bot": false,
          "headline": "chore(asciidoc-parser): release v0.29.1 (#1010)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-31T16:04:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e4a74f7f3a1577667e4799d3375967953dcbd9c3",
          "body": "…artitioning (#1009)\n\n* fix: Run :author: attribute value through substitutions before name partitioning\n\nAsciidoctor substitutes an attribute-entry value (via\napply_attribute_value_subs) before process_authors partitions it into name\nparts. Two gaps caused asciidoc-parser to partition the raw, unsu\n[…]\n test documenting\nthis so the behavior is not mistaken for a dropped email.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Run :author: attribute value through substitutions before name p…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-31T16:00:03Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "02f4349b53e3db823a69cd0f17901d36cb49ac8a",
          "body": "…-line (#1012)\n\n* fix: Emit a diagnostic for each line dropped under attribute-missing=drop-line\n\nWhen `attribute-missing` is set to `drop-line`, the parser correctly drops\nthe offending line (or blanks a header attribute value), but until now it\nrecorded no diagnostic, so a caller had no way to obs\n[…]\nion. Adds a\nregression test parsing `['{missing}']++x++` under `drop-line`.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Emit a diagnostic for lines dropped under attribute-missing=drop…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-31T15:55:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b90ac8ae62f5ecb447c4ec19f32cb14d1a4a969e",
          "body": "…mplicit author line (#1007)\n\n* fix: Populate combined `authors` and `author_1` attributes from the implicit author line\n\nFor an implicit author line, Asciidoctor exposes a combined, comma-joined\n`authors` attribute and, when more than one author is present, the first\nauthor's attributes under both \n[…]\nts\nthe header-metadata hash cardinality, which this crate does not surface.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Populate combined `authors` and `author_1` attributes from the i…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-31T15:26:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "58f6b79043c04bec341acf4a0b75cd60f370fa19",
          "body": "…hor line (#1006)\n\n* fix: Reconcile an explicit `:authors:` entry against the implicit author line\n\nWhen an explicit `:authors:` attribute entry follows an implicit author\nline, Asciidoctor reconciles the two: if the entry's value does not match\nthe computed (comma-joined) value of the implicit list\n[…]\nfail loudly rather than silently\ndiverge from the reference implementation.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Reconcile an explicit `:authors:` entry against the implicit aut…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-31T14:23:09Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4fec22bf196eb4301d38061c9b461c2b267e45a2",
          "body": "…#1008)\n\nSurface the inline passthroughs (`+++…+++`, `++…++`, `$$…$$`, `pass:[…]`,\ninline STEM macros) that the substitution pipeline extracts from a block's\ncontent, so downstream consumers can assert – for each extracted\npassthrough – its stored (unescaped) text and its resolved substitution\nlist,\n[…]\nbs()`. `SubstitutionGroup::steps()` is now public too, so\nthe resolved, ordered substitution steps for an entry are inspectable.\n\nCloses #1002.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: Expose the inline passthrough collection on a block's content (…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-31T04:34:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6996bed96d60c872081c8efd442906613462d0ce",
          "body": "* chore(asciidoc-parser): release v0.29.0\n\n* docs(changelog): describe the #999 breaking change and migration for v0.29.0\n\nAdd a \"Breaking changes\" section to the 0.29.0 entry explaining the\nIncludeFileHandler::resolve_target reshape (Option<IncludeContent> ->\nIncludeResolution) and how to migrate a handler, matching the prose\nstyle used for earlier breaking releases.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(asciidoc-parser): release v0.29.0 (#1001)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-30T11:58:56Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1059e9b9204bfa72649ee9ca7fc463c8fa2f2763",
          "body": "…(#1000)\n\nThe release_commits regex required the commit type to be immediately\nfollowed by `(` or `:`, so a scopeless breaking-change commit such as\n`feat!:` did not match. This meant release-plz reported \"no commit\nmatches the release commit regex\" and skipped opening a release PR\nafter #999.\n\nAdd an optional `!` before the `(`/`:` so all Conventional Commit\nforms – including `feat!:` and `fix!:` – trigger a release.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Match breaking-change commits (feat!:) in release_commits regex …",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-30T11:51:23Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8a274b3472c985f8d83a9659eb0c843307e16d09",
          "body": "* feat!: Distinguish an unreadable include file from a missing one\n\nWhen an `include::` directive names a file that exists but cannot be\nread (e.g. a permission error), the parser previously reported it\nidentically to a missing file (`WarningType::IncludeFileNotFound`).\nAsciidoctor distinguishes the\n[…]\nes a compile error here rather than silently collapsing into\n  \"not found\".\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat!: Distinguish an unreadable include file from a missing one (#999)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-30T05:09:23Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bf90b2983c3c11bdd3438cae3c2395697d075e98",
          "body": null,
          "is_bot": false,
          "headline": "chore(asciidoc-parser): release v0.28.1 (#997)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-29T04:40:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2fa904e123ffb8ceb69df3c74021f8eeed663d87",
          "body": "…it (#996)\n\n* fix: Keep block metadata attached when a comment sits directly above it\n\nA single-line comment (`//`) placed directly above a block-metadata line\n(an attribute list `[...]`, an anchor `[[...]]`, etc.) with no blank line\nbetween them detached that metadata from the block it decorated: t\n[…]\nary text directly above it already\nis, producing identical rendered output.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Keep block metadata attached when a comment sits directly above …",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-29T04:35:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2d066e138e2a784193f5962855272b8ea675dd3b",
          "body": null,
          "is_bot": false,
          "headline": "chore(asciidoc-parser): release v0.28.0 (#994)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-29T01:55:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2fd07c7e30a42627a85fad890feab0c4a7df08fe",
          "body": "* fix: Mirror Asciidoctor TOC position normalization\n\nResolve the `toc` family of attributes the way Asciidoctor's header\nnormalization does (`document.rb`), so the derived `toc-position` /\n`toc-placement` / `toc-class` attributes match for three inputs that\npreviously diverged:\n\n- direction shortha\n[…]\nnd\nadd a regression test covering `^`/`v`/`top`/`bottom`/`<`/`>` in a cell.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Mirror Asciidoctor TOC position normalization (#993)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-29T01:50:12Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9635c779449ff6a114f046eb05f8a65c30919282",
          "body": null,
          "is_bot": false,
          "headline": "chore(asciidoc-parser): release v0.27.4 (#991)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-27T19:10:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "64f2b3cbe2dc2509fc0836be9053cc96311cd84b",
          "body": "…(#990)\n\nAn API/intrinsic `numbered` attribute (`ModificationContext::ApiOnly`, as the\nhtml5 converter applies `attributes: { 'numbered' => '' }`) remapped to a\n*locked* `sectnums`, and a locked `sectnums` could not be unset by a body\n`:numbered!:` — so every section rendered numbered and the mid-do\n[…]\nPI`) from `non_normative!` to verified tests, and add\nfocused parser unit tests for both directions of the flexible-attribute lock.\n\nclose #989\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Unlock an API-enabled `numbered` so a body toggle still applies …",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-27T19:06:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c058b485333393e38211ed677dda13eb6b043e00",
          "body": null,
          "is_bot": false,
          "headline": "chore(asciidoc-parser): release v0.27.3 (#982)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-27T14:33:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8a59d4c7ae7753854ab89cc8b2f7e487c16c631f",
          "body": "Asciidoctor's `InlinePassRx` consumes one character before each inline\npassthrough it matches (its leading group absorbs the preceding\ncharacter and re-emits it). Because Ruby's `gsub` resumes scanning after\neach match, this shifts where the opening `+` lands inside a long run of\n`+` characters, par\n[…]\ntheir zero-width\nboundary. The retry path now splits on a char boundary since the\nconsumed preceding character may be multi-byte.\n\nCloses #979.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Tokenize a run of `+` around a passthrough like Asciidoctor (#988)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-27T14:30:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6e8550843e97f66d3060ed39e4c0306a5541b659",
          "body": "* fix: Preserve a quoted role on an inline passthrough span (#973)\n\nAn inline passthrough (or inline quoted text) whose role is enclosed in\nquotes – e.g. `['role']++text++` – dropped the role and rendered no\n`<span>`, diverging from Asciidoctor which keeps the quoted role verbatim.\n\nThe general attr\n[…]\nAsciidoctor slices at the\nfirst comma) with a unit assertion.\n\nCloses #987.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Preserve a quoted role on an inline passthrough span (#973) (#978)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-27T03:47:26Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "25fcab7ddb6a76043e5d9cd4661b32b006772692",
          "body": "…s caption (#984)\n\n* fix: Honor an empty document `caption` attribute to suppress a block's caption\n\nA document-wide `caption` attribute that is set but empty (bare `:caption:`,\nor `:caption:` with an empty value) now suppresses a captionable block's\ncaption and consumes no counter, matching Asciido\n[…]\n to\nsuch a block falls back to the block title, never a numbered signifier.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Honor an empty document `caption` attribute to suppress a block'…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-27T03:18:09Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5c4f74095a5e626626b6bf5d3b145963c49b432c",
          "body": "… mode (#985)\n\n* fix: Fall back to link macro for remote include under non-secure safe mode\n\nUnder a non-secure safe mode (`unsafe`/`safe`/`server`), a remote (URI)\n`include::` target whose `allow-uri-read` attribute is unset is a no-fetch\ncase: no network read is required, only that the target be *\n[…]\nes and\nall) as its `href`, rather than leaving `pass:c` as the destination.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Fall back to link macro for remote include under non-secure safe…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-27T03:17:36Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "95d31782df361c5ba32de2cbb5a78dba6885a0cf",
          "body": "* fix: Parse the `toc::[]` block macro as a `toc`-context block\n\nThe `toc::[]` block macro previously parsed as an ordinary paragraph\nwhose content was the literal text `toc::[]`, so a backend had no way to\ndetect the macro and render a table of contents at that position.\n\nAdd a `TocBlock` type (and\n[…]\nrget requirement into the `[` prefix check, removing an\nunreachable branch.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Parse the `toc::[]` block macro as a `toc`-context block (#986)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-27T03:10:18Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ef44687753e612ed06b8b8defcdfc836beb543c2",
          "body": "* feat: Expose an AsciiDoc table cell's own footnotes\n\nAn AsciiDoc (`a`) table cell is a nested document with its own footnote\nregistry, isolated from the main document (#544). That per-cell footnote\nlist was discarded after the cell parsed, so a renderer had no data to\nbuild the cell-local `#footno\n[…]\nop the issue reference, so no closed-issue link is\nleft behind in the code.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: Expose an AsciiDoc table cell's own footnotes (#977)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-27T02:58:39Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e378c1bbdeda984ad62380ae8cb81500e0633fc8",
          "body": "…ks (#976)\n\nAn externally-supplied `hardbreaks` attribute (Asciidoctor's `-a hardbreaks`\n/ `attributes: { 'hardbreaks' => '' }`) did not insert a `<br>` at each\nunwrapped paragraph line, even though the same attribute set as a header\nentry (`:hardbreaks:`) or a `[%hardbreaks]` block option did.\n\nAsc\n[…]\ntutions_test` hardbreaks cases now faithfully\nuse the API attribute (as upstream does) instead of sidestepping via\n`[%hardbreaks]`.\n\nclose #974\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Honor API-supplied `hardbreaks` document attribute for line brea…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-27T02:30:16Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "30d60ceedd4cda1f7e52986892dfaeb656bbf7fb",
          "body": null,
          "is_bot": false,
          "headline": "chore(asciidoc-parser): release v0.27.2 (#971)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-26T18:15:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "151472d4b863cd82f7c1f6ccc5df57cbfc7739f7",
          "body": "…8) (#970)\n\n* fix: Resolve cross-reference to the document title to its title text\n\nA cross-reference to a document title carrying an explicit shorthand ID\n(`[#id]` above `= Title`) rendered the bracketed `[id]` fallback instead\nof the title's reference text, because the document title was never\nreg\n[…]\n ends the header, and\nthe empty `[[]]` form remains rejected.\n\nCloses #968.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Resolve cross-references to the document title (issues #965, #96…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-26T18:03:14Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a036061fdaa93e10bb07f518ba70b8d722366dae",
          "body": "A discrete (floating) heading — a `[float]` or `[discrete]` styled title —\nwas exposed with the block context `section`, indistinguishable from an\nordinary section by context alone. Asciidoctor models it as a block whose\ncontext is `floating_title`, which consumers rely on to (for example)\nexclude d\n[…]\n\ntype is `Discrete`, and `section` otherwise. `resolved_context` follows,\nsince neither the `float` nor `discrete` style is a built-in context.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Report `floating_title` context for discrete headings (#967)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-26T17:49:04Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0cfe8b98bf6136c297dd888477298b2b8decc0c3",
          "body": "…(#969)\n\nThe newest `dtolnay/rust-toolchain` (master) makes the `toolchain` input\nrequired and no longer falls back to a default. Dependabot (#964) bumped\nevery pinned SHA – including the ones tagged `# stable` and `# nightly` –\nto the single master SHA, so the jobs that relied on a tag's built-in\nd\n[…]\nss an explicit `toolchain:`\ninput so the setup is correct and stays clean under future Dependabot\nbumps (a single SHA to update).\n\nCloses #964.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "ci: Add required `toolchain` input for dtolnay/rust-toolchain (#964) …",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-26T17:42:18Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a288f6551831c319537370b60e507f2f1e3b235f",
          "body": null,
          "is_bot": false,
          "headline": "chore(asciidoc-parser): release v0.27.1 (#959)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-25T20:44:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "32dd76cdbcc6365ac4bf60ddb23cf87a3d388951",
          "body": "* fix: Unescape `\\{` and `\\}` in attribute reference substitution\n\nAn escaped attribute-reference brace should render as a literal brace with\nthe escaping backslash removed and the reference left unexpanded. The\nattribute-reference regex only recognized a backslash before the opening\nbrace (`\\{name}\n[…]\nan `{name}` form unexpanded, consistent with the\ncontent-substitution path.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Unescape `\\{` and `\\}` in attribute reference substitution (#963)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-25T20:41:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d48de8394a07d38a2f01965dee28babc4599fd6b",
          "body": "Remove the author_association (OWNER/COLLABORATOR/MEMBER) and explicit\ndependabot login checks from every job gate, relying purely on write\naccess to the primary repo via head.repo.full_name == github.repository.\nPushing a branch here already requires write access, so this covers\nmaintainers, dependabot, and agent-authored PRs alike. Fork PRs still\nawait the \"safe to test\" label.\n\nMirrors asciidoc-rs/asciidoc-html5#107.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: Rely on write access instead of author_association gates (#960)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-25T16:01:28Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2afd0b3a2b98bf8ad7630a4f9ca45d7849b5e48d",
          "body": "A block title whose first character is a period and is not followed by a\nspace (e.g. `..gitignore`) is now parsed as a block title with text\n`.gitignore`, matching Asciidoctor's `BlockTitleRx`\n(`^\\.(\\.?[^ \\t.]…)$`). Previously any line beginning with `..` was\nrejected as a title, so the marker line became a paragraph and the\nfollowing block lost its title.\n\nCloses #957\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Recognize block title with a leading period (`..name`) (#958)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-25T15:51:18Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "320ce4bdfac06a8ba4b9a1e1c684c0587ee43276",
          "body": null,
          "is_bot": false,
          "headline": "chore(asciidoc-parser): release v0.27.0 (#941)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-25T04:25:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "aa767ff5cde506e86b4361ababa6c0266d9c44ac",
          "body": "* fix: capture block metadata on list items instead of dropping it\n\n`ListBlock::parse` built each list item with an empty `BlockMetadata`, so a\ntitle, anchor, or attribute list written directly before a list item's marker\nwas silently discarded. Worse, because the empty metadata could not parse past\n[…]\nt for them, restoring the original fast path for\nthe common paragraph case.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Capture block metadata on list items instead of dropping it (#954)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-25T04:22:04Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c4c7294195664e7d3005c7cc48796c9a2fdc9fcd",
          "body": "* chore: Pin GitHub Actions to specific commit SHAs\n\nReplace mutable version tags with pinned commit SHAs (each with a\ntrailing version comment) across ci.yml and pr_title.yml, following the\npattern already used in release.yml. Each SHA is the commit its tag or\nbranch currently resolves to. This har\n[…]\n currently resolves to) so all\nthree workflows share a single checkout SHA.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: Pin GitHub Actions to specific commit SHAs (#955)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-25T04:04:49Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b34f99e95e10c41ff93d4c26edf3ae455560998c",
          "body": "Part of the #939 TEMPORARY-marker audit. The `#[allow(...)]` attributes\nguarding test scaffolding are no longer warranted:\n\n- `assert_dom/virtual_dom.rs`: the `VirtualNode` builder helpers are now\n  used throughout the DOM assertions, so the blanket `#[allow(dead_code)]`\n  on the impl block is remov\n[…]\nunconstructed, so per the audit guidance they (and their\n  `Debug` / equality arms) are removed rather than left behind an allow.\n\nCloses #949.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: Remove consumed 'while building' scaffolding allows (#949) (#952)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-25T03:42:14Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8944d9105400fdba9e9d7fa29d266ad1ecf38818",
          "body": "…o_name (#953)\n\n`Span::take_ident` borrowed Rust's identifier definition (leading\nalphabetic/underscore, then alphanumerics/underscores) because\n\"identifier\" is not crisply defined in the AsciiDoc documentation. Its\nuse was already discouraged in favor of more specific helpers.\n\nThere was a single c\n[…]\nng digit) is now parsed and then rejected as unrecognized\nrather than rejected at the name-capture stage, with identical results.\n\nCloses #948.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: Replace Span::take_ident with spec-grounded take_block_macr…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-25T03:40:42Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "78d9373b0f7d80bbd965d48ec60c5924b6592832",
          "body": "…947) (#951)\n\nThe `Block` enum's variants have converged in size as the parser\nevolved. The two largest, `Section` (568 bytes) and `Media` (536\nbytes), now differ by only 32 bytes – far under clippy's 200-byte\n`large_enum_variant` threshold – so the lint no longer fires. The\n`#[allow]` (carried forw\n[…]\nasoning already\ndocumented on `BlockParseOutcome`).\n\nVerified with the CI invocation\n`cargo clippy --all-features --all-targets -- -Dwarnings`.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: Drop stale allow(clippy::large_enum_variant) on Block (close #…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-25T03:40:16Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "19faf3b5696dfb32a0f875f4d95ddb93db7a8706",
          "body": "Audit the code base for TEMPORARY / \"while building\" markers (excluding\n`ref` and tests quoting `ref` content) and convert the genuine ones to\nTODO comments that link to tracking issues, per #939.\n\n- List items discard block metadata (#946).\n- `Block` enum trips `clippy::large_enum_variant` (#947).\n- `Span::take_ident` uses a provisional identifier definition (#948).\n- Remove \"while building\" scaffolding allows once consumed (#949).\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: replace TEMPORARY markers with issue-linked TODOs (#950)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-25T03:19:25Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5fdf0f42b24c7d41e72c1df86811d1789cd3eaba",
          "body": "Code-coverage review for dead code found no removable dead code: line\ncoverage is 98.79% and the compiler's dead_code lint is clean. The\nuncovered product lines are all intentional guardrails (defensive\nbranches, assertions, Debug impls, and a refactor-blocked region).\n\nThe one actionable cleanup is this stale attribute: the re-export is now\nused via crate::document::DuplicateIdError in the parser, so the\nallow(unused) suppresses nothing.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: Remove stale allow(unused) on DuplicateIdError re-export (#945)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T23:05:40Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4bbb8fe9f0018185442bda7a16e44b199f8a8e60",
          "body": "…haustive (#940)\n\n* feat: Derive Hash on the public AST / output types\n\nSpan, Block, Content, WarningType and the types reachable from them now\nimplement Hash, so blocks and spans can key a HashMap/HashSet and warnings can\nbe bucketed by type. ResolvedAttributes hashes an order-independent summary o\n[…]\nleValue / ModificationContext fields, all of which hold only Hashable\ndata.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: Derive Hash on the public AST/output types; mark Warning non_ex…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T21:39:56Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a59f603280d80c729d8a0f80afdb3554901d187b",
          "body": "…pat 5.0.0 -> 5.0.1 (#938)\n\nPatch-level updates to the benchmark harness dev-dependencies. Raising the\ndeclared floors keeps the -Z direct-minimal-versions CI job on the current\npatch releases. Benchmarks compile and minimal-versions resolves cleanly.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(deps): Bump criterion 0.8.0 -> 0.8.2 and codspeed-criterion-com…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T19:03:52Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ca8db26179c0fe77d71e8e55b3a358fde32945af",
          "body": "* chore(asciidoc-parser): release v0.26.0\n\n* docs: Add 0.26.0 breaking changes guide to the changelog\n\nDocument the source-level migration for the four breaking changes in\n0.26.0 (block traversal #930, PathResolver-as-trait #934, rendering API\npolish #929, and the SourceMap reshape #917), mirroring the prose\nguide added for 0.23.0.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(asciidoc-parser): release v0.26.0 (#916)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T15:52:19Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "50f68b5578c980dbfe90d73256b5b3e3e8b27f97",
          "body": "…ers (close #896) (#933)\n\n* feat: Let a custom InlineSubstitutionRenderer override only what differs (close #896)\n\nTwo changes unblock a downstream (e.g. Zola) `InlineSubstitutionRenderer`:\n\n- Give every `InlineSubstitutionRenderer` method a default body that\n  delegates to the built-in `HtmlSubstit\n[…]\n is not surprised that `render_icon` and a direct `icon_uri`\ncall disagree.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: Let a custom InlineSubstitutionRenderer override only what diff…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T15:42:28Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "104ed44bd5ba50724bb852dbc58f9d423dcb9105",
          "body": "Warnings were deterministic but assembled by category (header, blocks,\npreprocessor, substitution, post-parse checks, then reference-resolution\nwarnings appended last), so an unresolved `include::` on an early line\ncould sort after a malformed inline macro further down, and unresolved-xref\nwarnings \n[…]\ne parse and after\na reference-resolution sweep folds its warnings in, so `warnings()` now\nyields line-ordered, still-deterministic diagnostics.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Emit document warnings in source order (close #901) (#932)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T15:06:54Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0202092e25f780df3441880c100fca1f2ed8082b",
          "body": "…(#936)\n\nPRs #930 (child_blocks API) and #934 (PathResolver trait) landed\nconcurrently without a rebase, leaving the with_path_resolver test\ncalling the removed Document::nested_blocks(). Point it at\nchild_blocks() to match the sibling call sites.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Repair stale nested_blocks() call left by concurrent PR landing …",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T14:36:01Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e454b6e3c8507d1dc916f572a55b0d13de7b22ad",
          "body": "…k=self (close #919) (#927)\n\n* fix: Reject a dangerous image/icon target promoted to an href via link=self (close #919)\n\nAn `image:`/`icon:` macro whose target carries a script-capable scheme\n(`javascript:`, `vbscript:`, or a non-image `data:` such as\n`data:text/html,…`) is harmless in the `<img src\n[…]\nage data URIs and trusted embedded SVGs (the Asciidoctor-parity case) live.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Reject a dangerous image/icon target promoted to an href via lin…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T14:27:49Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "08944ce4a76acacdb4515e1b549df4728080162e",
          "body": "…r (close #898) (#934)\n\nPath resolution was the one extensibility seam in the crate that could not\nbe swapped: `PathResolver` was a concrete struct exposed as a `pub` by-value\nfield on `Parser`, so an Antora/Zola-style host needing custom path or URL\nrewriting (virtual filesystems, content roots, UR\n[…]\n` field is now `pub(crate) Rc<dyn PathResolver>`,\nconfigured through a new `with_path_resolver(...)` builder rather than direct\nfield mutation.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor!: Make PathResolver a trait with a with_path_resolver builde…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T14:21:36Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d01724d237725af16b2892d5572cc95e102b7443",
          "body": "…I (close #894) (#930)\n\n* feat!: replace IsBlock::nested_blocks with a complete child_blocks API (close #894)\n\nThe discoverable block accessor `IsBlock::nested_blocks()` silently omitted\nMarkdown-blockquote children (reachable only via `QuoteBlock::blocks()`) and\nAsciiDoc table-cell content, so tool\n[…]\nck`, and\n  the `nth` override) generated by the `opaque_slice_iter!` macro.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat!: Replace IsBlock::nested_blocks with a complete child_blocks AP…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T14:18:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6dbdb248bb87626baa8087ac7c6ef5cbc0f52de9",
          "body": "…#903) (#931)\n\n* fix: Enforce SourceMap append ordering with a debug assertion (close #903)\n\n`SourceMap::resolve` binary-searches `segments` by `output_line`, which\nsilently returns garbage on an unsorted slice. `append` documented that\nentries \"should\" arrive in increasing order but did not enforce\n[…]\nptile-apps[bot]@users.noreply.github.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>\nCo-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix: Enforce SourceMap append ordering with a debug assertion (close …",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T14:14:12Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5cb17dc58929cd6e654764f8b50a06e222229607",
          "body": "…se #899) (#926)\n\n`Catalog::ids()` and `Catalog::entries()` iterated a randomly-seeded\n`HashMap`, so their order varied between process runs. A multi-document\npipeline that derives output from catalog iteration order (e.g. building a\nglobal cross-reference index, or resolving a collision as \"first s\n[…]\nookups. `DebugHashMapFrom` is generalized to render either map type and\nstill sorts its own output, so the `Debug` representation is unchanged.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Make catalog ID iteration deterministic across process runs (clo…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T14:02:54Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7f1df812544eadf0f48551d0b98abfba3a438e77",
          "body": "…e #906) (#925)\n\nThe doc comment read only \"Alternative to\" with a TODO placeholder. Describe\nthat `LookaheadReplacer` is an alternative to `regex::Replacer` that can inspect\nthe text following a match and reject it via `SkipAheadAndRetry`, modeling the\nlook-ahead pattern that `regex::Replacer` cannot express.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: Complete the truncated doc comment on `LookaheadReplacer` (clos…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T13:34:38Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8eef1e68450f576f513f568f1a1a33d8daf724ff",
          "body": "…K branch (close #908) (#928)\n\nThe invalid-macro-syntax `else` branch in `InlineLinkReplacer` carried a\nFIXME noting that a `link:` prefix should never reach it: the shared\nNON-ANGLE branch of `INLINE_LINK` let `link:` prefix a bare (bracket-less)\nURL, which then matched and was rejected as invalid \n[…]\nsyntax path.\n\n`NormalizedCaps` gains a third branch mapping and `bare` becomes optional\n(the LINK-MACRO branch always has a trailing attrlist).\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: Give the `link:` prefix its own bracket-required INLINE_LIN…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T13:32:34Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "024721f9252180c4962152effea6365cc966c97d",
          "body": "Settles several pre-1.0 public-API commitments flagged in the adversarial\nreview, each of which would become a breaking change to fix after the freeze:\n\n- Rename the misspelled trait method\n  `InlineSubstitutionRenderer::render_quoted_substitition` to\n  `render_quoted_substitution`.\n- Remove the pro\n[…]\n type and\n`LinkRenderParams::type_` field are removed; and `LinkRenderParams::window`\nchanges from `Option<&'static str>` to `Option<&'a str>`.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor!: Polish public rendering API ahead of 1.0 (close #897) (#929)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T13:30:31Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "91abb32cc09f6a331ac1c2898655248cb54037be",
          "body": "…ion (close #889) (#920)\n\nAdd a prominent \"Security: rendering untrusted input\" section to the\nREADME (which is also the crate-level doc via `include_str!`), stating\nthat the HTML renderer is not a sanitizer, that attribute-reference\nsubstitution and passthroughs emit raw HTML by design, and that\nco\n[…]\noc must run the output\nthrough an HTML sanitizer such as `ammonia`. Clarify that safe mode\ngoverns file/environment reach, not output escaping.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: Document that untrusted AsciiDoc output requires HTML sanitizat…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T05:14:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "870609273fe4653c8dd8ecea622099c3543654ff",
          "body": "…05) (#924)\n\n* perf: Reduce allocations in the inline substitution pipeline (close #905)\n\nResidual allocation-reduction items from the adversarial review; each is\nsmall and mechanical, and the many-small-blocks-of-plain-prose throughput\ncase benefits from all of them.\n\n- `apply_special_characters` n\n[…]\nng both the\n  no-op-filter borrow branch and the changed-text owned branch.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Reduce allocations in the inline substitution pipeline (close #9…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T05:14:23Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e053106f32bb6358554dfd2f3fc584574ff3e393",
          "body": "…ounds slice (close #902) (#923)\n\n* fix: Fall back to an empty span instead of the whole span on out-of-bounds slice (close #902)\n\n`Span::slice` / `slice_from` / `slice_to` guarded their bounds only with a\n`debug_assert!`. In a release build, when `.get(range)` returned `None`, the\n`map_or(*self, …)\n[…]\nes;\nthe release fallback behavior is already covered by the `empty()` test.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Fall back to an empty span instead of the whole span on out-of-b…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T05:13:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6ad42b74d3ae456eeccab4f1f7a6dc8504208804",
          "body": "…ciiDoc table cells (close #904) (#922)\n\nFor every AsciiDoc-style (`a`) table cell, `process_content` rebuilt the\nattribute-lock set from scratch, allocating an owned `String` for each of the\n~74 built-in attributes it locked and deep-cloning the whole `HashSet<String>`\nper cell. This was the domina\n[…]\ncall out of the modifiable-attributes loop so the\nper-parser attribute map is made-mut once per cell rather than re-checked on\nevery iteration.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "perf: Avoid per-cell String allocations when locking attributes in As…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T05:07:35Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "24ec6d181229f6d09f8dccdcf646fbd5ef918cad",
          "body": "…or (close #907) (#921)\n\nThe `// TODO:` in `section_to_node` described how the section title heading is\nadded in the `Block::Section` match arm (using `section.level()` for the heading\nlevel and `section.section_title()` for the text). That behavior is already fully\nimplemented there, so the note tr\n[…]\nfold its one useful detail (the title heading, like the id,\nlands on the heading rather than the wrapper `<div>`) into the surrounding\ncomment.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: Remove stale TODO restating implemented section-heading behavi…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T05:07:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "80825d50579108831d9bc1f96f5a6e9e43d86cdd",
          "body": "…idelity (#917)\n\n* feat: Map preprocessed spans back to origin file, line, column, and fidelity (close #891)\n\nSpans carry coordinates relative to the single preprocessed buffer, and the\nonly way back to an origin was `SourceMap::original_file_and_line`, which is\nline-only and cannot say whether a li\n[…]\nhe included file's identity is\nnot carried forward into the parent's lines.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: Map preprocessed spans back to origin file, line, column, and f…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T04:47:54Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e64f4ade1fff3da5fba49aebf0aba8c2fb15d6dd",
          "body": "…k macro (close #888) (#911)\n\n* fix: Escape href/target/icon attributes and reject script URIs in link macro (close #888)\n\nSeveral `href`/`target` and icon attribute values were emitted into the\nrendered HTML without escaping the `\"` delimiter, allowing an author to\nbreak out of the attribute and in\n[…]\nnd `render_icon_or_image` (which drops the\nlive link) share one definition.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Escape href/target/icon attributes and reject script URIs in lin…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T01:59:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0c93961c8288c853f6300d9487cb0139a3afe9b2",
          "body": "A UTF-8 byte-order mark (`EF BB BF` = U+FEFF) at the start of the input\nwas not stripped. `preprocess` short-circuits and returns the source\nunchanged when there are no directives, so the U+FEFF became the first\ncharacter of the first line. `Header::parse` requires the line to start\nwith `= `, so a \n[…]\n This matches Asciidoctor, which strips a UTF-8 BOM even\nfor UTF-8 input, and is independent of UTF-16 transcoding, which remains\nout of scope.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Strip a leading UTF-8 BOM before parsing (close #900) (#918)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T01:45:04Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "436d8144f64c066572d62d4581da228bf52601ec",
          "body": "…nput (close #885) (#910)\n\n* fix: Cap block nesting depth to prevent stack overflow on untrusted input (close #885)\n\nBlock parsing descends recursively through `parse_blocks_until` (delimited\nblock bodies, section bodies, table cells, quote/blockquote content) and\nthrough `ListBlock::parse_inside_li\n[…]\ntores parity with\nthe pre-#885 baseline (measured within run-to-run noise).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Cap block nesting depth to prevent stack overflow on untrusted i…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T01:30:04Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9c91f6f9c6f3916cb55ae67e3fbfeccfb3bfa644",
          "body": "…r (close #893) (#909)\n\n* fix: Reset document attribute values between parses on a reused Parser (close #893)\n\n`Parser::parse_deferred` reset the catalog, callouts, substitution\nwarnings, section numbering, pending block title, and counters between\nparses but not `attribute_values`, so document-head\n[…]\nic's prose dash convention in the doc comment added by the\nprevious commit.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Reset document attribute values between parses on a reused Parse…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T01:08:35Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c8aa0e203b0f9a0374a288eab5fcd69524e2134d",
          "body": "…ad (close #887) (#912)\n\n* fix: Honor char boundary when skipping constrained-monospace look-ahead (close #887)\n\nThe constrained-monospace quote regex's leading boundary group\n`[^\\w&;:\"'`}]` matches any non-word Unicode scalar, including multi-byte\ncharacters. When a failed look-ahead skipped the le\n[…]\nage gap left by\nthe multi-byte fix. The escaped text is preserved verbatim.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Honor char boundary when skipping constrained-monospace look-ahe…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T00:40:36Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "50f578e127fe1a0c76989d01cbf6a21aa8b9a28c",
          "body": "Apply the documented comment/doc style conventions to hand-written\ncomments and documentation text (excluding the vendored `ref/` tree and\nthe tests that quote it):\n\n- Convert prose em dashes to spaced en dashes (366 lines). The one\n  literal em-dash character reference in `virtual_dom.rs` is preser\n[…]\nn test it marks.\n- File tracking issues for an incomplete doc comment and two unlinked\n  TODO/FIXME comments, and link them (#906, #907, #908).\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "doc: Normalize comment and doc prose style across the codebase (#915)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T00:37:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a43b990ea8278c9b81394ffd2bff232a57b17a60",
          "body": "…#886) (#914)\n\n* fix: Avoid O(n²) parse time on many repeated block delimiters (close #886)\n\n`QuoteBlock::parse` runs before `CompoundDelimitedBlock` in block dispatch,\nso it is tried for every delimiter line. Its quoted-paragraph path called\n`read_paragraph` (a scan to the next blank line) before t\n[…]\nlines between\nthem) — the shape that previously triggered O(n²) parse time.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Avoid O(n²) parse time on many repeated block delimiters (close …",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T00:35:44Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b5252cb2a4b00dd2dd93049da95c2c90d2178eb9",
          "body": "…ction (close #890) (#913)\n\nThe `Safe` and `Server` docstrings described protections the parser does\nnot actually enforce:\n\n- `Safe` claimed it prevents access to files outside the source file's\n  parent directory. This crate performs no filesystem I/O and does not\n  port Ruby Asciidoctor's `PathRes\n[…]\nent handler's responsibility —\nand that only `Secure`, not `Server`, disables include/asset embedding.\n\nDocumentation only; no behavior change.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: Correct SafeMode Safe/Server docstrings to match enforced prote…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-24T00:28:44Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "006b8752176d0637c7f3c2535ecbb02f5ba47798",
          "body": null,
          "is_bot": false,
          "headline": "chore(asciidoc-parser): release v0.25.0 (#879)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T15:21:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cfae1bd47ba42ecab7e0585b59f9f80fa7a40c81",
          "body": null,
          "is_bot": false,
          "headline": "chore: Update README to reflect fully feature-complete status (#884)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T15:15:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b2106856ea6c1c62dcd52c1021720ca2d7b5d294",
          "body": "…(close #871) (#883)\n\n* test: Verify link attrlist enclosure rule for invalid attribute names (close #871)\n\nPromote the \"enclosure only required when the text preceding the equals\nsign matches a valid attribute name\" sentence in the link/URL macro\nattribute-parsing spec from a non-normative note to \n[…]\nor future spec-coverage work and silence the\nunused-macro/-import warnings.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Verify link attrlist enclosure rule for invalid attribute names …",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T15:04:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "48407cc93dcdb2524698690360334ec80e85f99e",
          "body": "… content (close #877) (#881)\n\n`reindent_included_lines` previously returned included content unchanged\nwhenever the `indent` attribute was absent, so `tabsize`-driven tab\nexpansion only fired when `indent` was also supplied.\n\nPer the spec, when `tabsize` is set, tabs are replaced with spaces\nregard\n[…]\nxpansion now runs\nwhenever `tabsize` is positive; indentation normalization is applied\nindependently when `indent` is present and non-negative.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Expand tabs from `tabsize` independently of `indent` on included…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T14:53:49Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1c10c0badc6182a1de62af87f02a150e2f994d42",
          "body": "…ing blank lines (close #876) (#882)\n\nPromote the `to_do_verifies!` block in `document_test.rs` to two real\n`verifies!` tests, backed by an `InlineFileHandler` fixture reproducing\nAsciidoctor's canonical `include-with-leading-blank-line.adoc` (two blank\nlines before the level-0 title).\n\n- A whole-fi\n[…]\ne and sets `:toc:`.\n- `lines=6` selects by original line number, skipping the leading blank\n  lines and the title so only the section survives.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test: Verify document-title & lines= selection for includes with lead…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T14:53:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "de9a4cff700cb105ba39c66753cc902e78bfc5a7",
          "body": "…lose #801) (#880)\n\n`WarningType` became part of the public API in #799, so its variant names\nand `Display` strings now need to read as a deliberate, consistent set. This\nis the one-time review the long-standing TODO above `InvalidMacroName` asked\nfor.\n\nVariant renames (breaking for anyone matching \n[…]\ner\"). Wording is otherwise unchanged. This changes user-visible\nwarning text.\n\nThe `TODO (#801)` marker is removed now that the review is done.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor(warnings)!: Review WarningType variant names and messages (c…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T14:44:50Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0c6a48c7687d434f46b001a991b9aaae7ca4f778",
          "body": "…878)\n\nConvert the now-testable table structural-container row to verifies! and\nreclassify the permanently-unverifiable / out-of-scope blocks as\nnon_normative! with justifications:\n\n- delimited.rs: the four table delimiters (`|===`, `,===`, `:===`, `!===`)\n  now assert the `table` context and conten\n[…]\ne two genuinely-deferred blocks now cite tracking issues #876 (include\ndoctitle recognition / lines= selection) and #877 (block-level tabsize).\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test: Resolve remaining to_do_verifies! blocks from the #628 sweep (#…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T14:39:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2f37e9dd217d6c7595c77300828d290df3b15aaa",
          "body": "…) (#874)\n\n* test: Cover description-list delimiter and anchor rules (close #864)\n\nThe opening `non_normative!` block in `lists/description.rs` reproduced\nseveral normative parsing rules for description lists but none were\nexercised by a test. Split the block so the normative prose is now backed\nby \n[…]\ntrast to\na leading `[[id]]` anchor which becomes part of the rendered term.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": " chore: Cover description-list delimiter and anchor rules (close #864…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T14:37:26Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3e721feddf89a868c943c97bf3abb78d0b32387a",
          "body": "…horthand ID/role order, AsciiDoc-cell directive) (#873)\n\n* test: Cover `title`-attribute fallback for the document title\n\nSplit the `[#title-attr]` `non_normative!` block so the normative\nfallback rule is verified: with no level 0 section title and no\n`doctitle` attribute, a `title` attribute entry\n[…]\name\ndirective on the following line acts as a normal multiline conditional.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: Close mislabeled-normative coverage gaps (doctitle fallback, s…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T14:27:21Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "18685312ef868d1f9906882096a40a25a8224b63",
          "body": "…se #865) (#875)\n\nSeveral inline-macro spec pages wrapped a normative parsing rule in\n`non_normative!` without covering tests. Add `verifies!` coverage for\neach rule the parser already implements correctly, and a justified\n`to_do_verifies!` marker for the one it does not:\n\n- Inline image alt-text: a\n[…]\next before `=` is a valid attribute name. The parser does not yet\n  honor this; the marker documents current behavior and is tracked by\n  #871.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test: Cover inline-macro spec rules hidden behind non_normative! (clo…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T14:26:46Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9aad9fafcabf48bfd30a115b4693f86279bde551",
          "body": "…combinators (close #866) (#868)\n\n* test: Cover mixed ifdef/ifndef combinator behavior (close #866)\n\nThe `non_normative!` block in `ifdef_ifndef.rs` stated the normative rule\nthat the `,` (or) and `+` (and) combinators cannot be combined in a single\nconditional-directive expression, but no test asse\n[…]\naffected. Extend `combinators_cannot_be_mixed` to cover the `+`-first case.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Match Asciidoctor's first-delimiter rule for mixed ifdef/ifndef …",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T14:14:25Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5051db0ceb815d7961afb2c5fc2d53131d6ee2df",
          "body": "Port Asciidoctor's `doc.register :links, target` so the parser records\nevery link target it encounters, exposed as `Catalog::links()`. Like the\nimage registry, population is gated on the `catalog_assets` option and\nrecorded in substitution-pass order.\n\nAll four Asciidoctor registration sites are covered: bare-URL autolink,\n`link:` macro, `mailto:`/link macro, and email autolink (the last of\nwhich the original TO DO markers had missed).\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: Populate the document catalog's link registry (close #335) (#872)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T14:10:34Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e06f0caf0984685dcb64fa452c10e6ca152a60d2",
          "body": "Audit of commented-out code turned up two genuinely dead blocks in the\ncrate's own source (excluding quoted Asciidoctor / AsciiDoc reference\nmaterial):\n\n- `passthroughs.rs`: an abandoned trailing-backslash truncation approach,\n  superseded by the retry logic that follows it.\n- `sdd/src/main.rs`: a developer debugging shortcut that scoped file\n  processing to a single file.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: Remove commented-out dead code (close #705) (#870)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T14:09:52Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "dbacb2413f412cdbee15fd2ebd8ff150b1c77b34",
          "body": null,
          "is_bot": false,
          "headline": "chore(asciidoc-parser): release v0.24.0 (#863)",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T04:33:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "99cf75ffb9858f73cb164da754ce25058e314f13",
          "body": "…tle (#862)\n\nAdd a regression test asserting that a block attribute line above the\ndocument title whose value carries a `{counter:…}` reference does not fire\nthe counter at header time when the run is ultimately rejected (here by an\nembedded `[[anchor]]`).\n\n`document_title_follows_block_metadata` sc\n[…]\nparser and the counter advances exactly once. This\nlocks in that behavior, salvaging the one piece of unique coverage from the\nsuperseded #833.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test: Cover counter deferral for a rejected metadata run above the ti…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T04:27:28Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0944b66c0ba58ae3c2a2dc942f070698241756d1",
          "body": "…ub (#861)\n\nIssue #308 asked whether a block title can span multiple lines via a\ntrailing `+`. The answer is no: a title is a single line, and a trailing\n` +` is retained literally rather than joined to the following line\n(confirmed against the parser). Replace the stale `TO DO` comment linking\nto #\n[…]\n `to_do_verifies!` stub convention.\n\nThe `|Titles |{y}` spec-coverage marker stays; that gap is tracked by the\n`to_do_verifies!` sweep in #628.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test: Remove resolved #308 reference from post_replacements titles st…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T04:07:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "adf9ff733355bea5b2dba6b52c30deb736ecbc0d",
          "body": "…9) (#852)\n\n* fix: Fuse legacy `+`-continued multi-line attribute values (close #729)\n\nAn attribute entry value can be continued across lines with a trailing\n` +` (legacy) as well as ` \\` (modern). Previously only the backslash\ncontinuation was fused; a legacy `+`-continued value was not joined — th\n[…]\nn the document body).\n\nAdds span-, fold-, and parse-level regression tests.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Fuse legacy `+`-continued multi-line attribute values (close #72…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T04:06:45Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3f2e0d78c748fff27314a181285a2863f43d4b05",
          "body": "…732) (#850)\n\n* fix: Formal `role=` replaces roles set via shorthand `.role` (close #732)\n\nWhen merging multiple block attribute lines, roles now follow\nAsciidoctor's running model: a formal `role=` entry replaces every role\naccumulated so far, while shorthand `.role` entries append. Previously\nall \n[…]\nat\n  the formal value replaces the running roles and the shorthand appends.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: Formal `role=` replaces roles set via shorthand `.role` (close #…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T03:59:34Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "cab8554693ddb8d05d68eb5dd37bdf05384d37ff",
          "body": "…lose #745) (#848)\n\n* feat: Drop YAML/TOML front matter when `skip-front-matter` is set (close #745)\n\nA `---`-fenced block at the very top of the document is now removed – and\nits content captured in the `front-matter` document attribute – when the\n`skip-front-matter` attribute is set, mirroring Asc\n[…]\n, `+++` TOML is not, and the content is\nstored verbatim rather than parsed.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: Drop YAML-style front matter when `skip-front-matter` is set (c…",
          "author_name": "Eric Scouten",
          "author_login": "scouten",
          "committed_at": "2026-07-23T03:54:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        }
      ],
      "releases_count": 55,
      "commits_last_year": 546,
      "latest_release_at": "2026-08-01T16:14:24Z",
      "latest_release_tag": "v0.29.4",
      "releases_from_tags": false,
      "days_since_last_push": 0,
      "active_weeks_last_year": 37,
      "days_since_latest_release": 0,
      "mean_days_between_releases": 0.7
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 37,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "sdd",
          "exists": true,
          "license": "Apache-2.0",
          "keywords": [
            "concurrent",
            "garbage",
            "memory",
            "epoch",
            "lock-free",
            "data-structures",
            "concurrency",
            "memory-management"
          ],
          "ecosystem": "crates",
          "matches_repo": false,
          "registry_url": "https://crates.io/crates/sdd",
          "is_deprecated": false,
          "latest_version": "4.8.8",
          "repository_url": "https://codeberg.org/wvwwvwwv/scalable-delayed-dealloc",
          "versions_count": 72,
          "total_downloads": 77608068,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": 5899173,
          "first_published_at": "2024-04-14T18:03:40.616625Z",
          "latest_published_at": "2026-07-02T14:12:15.625601Z",
          "latest_version_yanked": false,
          "days_since_latest_publish": 30
        },
        {
          "name": "asciidoc-parser",
          "exists": true,
          "license": "MIT OR Apache-2.0",
          "keywords": [
            "parser",
            "asciidoc",
            "parser-implementations"
          ],
          "ecosystem": "crates",
          "matches_repo": true,
          "registry_url": "https://crates.io/crates/asciidoc-parser",
          "is_deprecated": false,
          "latest_version": "0.29.4",
          "repository_url": "https://github.com/asciidoc-rs/asciidoc-parser",
          "versions_count": 55,
          "total_downloads": 13542,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": 2012,
          "first_published_at": "2024-10-26T22:27:57.063155Z",
          "latest_published_at": "2026-08-01T16:14:20.394752Z",
          "latest_version_yanked": false,
          "days_since_latest_publish": 0
        }
      ]
    },
    "popularity": {
      "forks": 4,
      "stars": 34,
      "watchers": 2,
      "fork_history": {
        "days": [
          {
            "date": "2026-01-23",
            "count": 1
          },
          {
            "date": "2026-02-17",
            "count": 1
          },
          {
            "date": "2026-04-01",
            "count": 1
          },
          {
            "date": "2026-07-18",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 4,
        "total_forks": 4
      },
      "star_history": null,
      "open_issues_and_prs": 5
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [
        "examples"
      ],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": true,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "Cargo.toml",
        "parser/Cargo.toml",
        "sdd/Cargo.toml"
      ],
      "largest_source_bytes": 434972,
      "source_files_sampled": 419,
      "oversized_source_files": 45,
      "agent_instruction_files": [],
      "agent_instruction_max_bytes": null
    },
    "dependencies": {
      "manifests": [
        "Cargo.toml",
        "parser/Cargo.toml",
        "sdd/Cargo.toml"
      ],
      "advisories": {
        "error": "No resolved dependencies carried a version and a supported ecosystem",
        "scope": "repository_graph",
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 10,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "crates"
      ],
      "dependencies": [
        {
          "name": "bytecount",
          "manifest": "parser/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "0.6.7"
        },
        {
          "name": "memchr",
          "manifest": "parser/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "2.6.4"
        },
        {
          "name": "percent-encoding",
          "manifest": "parser/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "2.3.2"
        },
        {
          "name": "regex",
          "manifest": "parser/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "1.11.1"
        },
        {
          "name": "self_cell",
          "manifest": "parser/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "1.2.0"
        },
        {
          "name": "thiserror",
          "manifest": "parser/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "2.0.1"
        },
        {
          "name": "walkdir",
          "manifest": "sdd/Cargo.toml",
          "ecosystem": "crates",
          "version_constraint": "2.5"
        }
      ],
      "all_dependencies": {
        "error": null,
        "source": "github-sbom",
        "packages": [
          {
            "name": "bytecount",
            "direct": true,
            "version": null,
            "ecosystem": "crates"
          },
          {
            "name": "memchr",
            "direct": true,
            "version": null,
            "ecosystem": "crates"
          },
          {
            "name": "percent-encoding",
            "direct": true,
            "version": null,
            "ecosystem": "crates"
          },
          {
            "name": "regex",
            "direct": true,
            "version": null,
            "ecosystem": "crates"
          },
          {
            "name": "self_cell",
            "direct": true,
            "version": null,
            "ecosystem": "crates"
          },
          {
            "name": "thiserror",
            "direct": true,
            "version": null,
            "ecosystem": "crates"
          },
          {
            "name": "walkdir",
            "direct": true,
            "version": null,
            "ecosystem": "crates"
          },
          {
            "name": "codspeed-criterion-compat",
            "direct": false,
            "version": null,
            "ecosystem": "crates"
          },
          {
            "name": "criterion",
            "direct": false,
            "version": null,
            "ecosystem": "crates"
          },
          {
            "name": "pretty_assertions_sorted",
            "direct": false,
            "version": null,
            "ecosystem": "crates"
          }
        ],
        "collected": true,
        "truncated": false,
        "total_count": 10,
        "direct_count": 7,
        "indirect_count": 3
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 2,
        "merged_prs": 772,
        "open_issues": 3,
        "closed_ratio": 0.987,
        "closed_issues": 223,
        "closed_unmerged_prs": 40
      },
      "bus_factor": 2,
      "bot_contributors": 1,
      "top_contributors": [
        {
          "type": "User",
          "login": "scouten",
          "commits": 759,
          "avatar_url": "https://avatars.githubusercontent.com/u/158391?v=4"
        },
        {
          "type": "User",
          "login": "mojavelinux",
          "commits": 723,
          "avatar_url": "https://avatars.githubusercontent.com/u/79351?v=4"
        },
        {
          "type": "User",
          "login": "graphitefriction",
          "commits": 37,
          "avatar_url": "https://avatars.githubusercontent.com/u/1124042?v=4"
        },
        {
          "type": "User",
          "login": "ggrossetie",
          "commits": 3,
          "avatar_url": "https://avatars.githubusercontent.com/u/333276?v=4"
        },
        {
          "type": "User",
          "login": "larryv",
          "commits": 2,
          "avatar_url": "https://avatars.githubusercontent.com/u/281175?v=4"
        },
        {
          "type": "User",
          "login": "mmattel",
          "commits": 2,
          "avatar_url": "https://avatars.githubusercontent.com/u/3321281?v=4"
        },
        {
          "type": "User",
          "login": "ahus1",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/3957921?v=4"
        },
        {
          "type": "User",
          "login": "btat",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/1832069?v=4"
        },
        {
          "type": "User",
          "login": "Vampire",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/325196?v=4"
        },
        {
          "type": "User",
          "login": "danyill",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/674783?v=4"
        }
      ],
      "contributors_sampled": 22,
      "top_contributor_share": 0.492
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "ci.yml",
        "pr_title.yml",
        "release.yml"
      ],
      "has_docs_dir": false,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 3,
            "reason": "branch protection is not maximal on development and all release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "30 out of 30 merged PRs checked by a CI test -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 1/30 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 10,
            "reason": "project has 14 contributing companies or organizations",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 10,
            "reason": "update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": 10,
            "reason": "packaging workflow detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 10,
            "reason": "all dependencies are pinned",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 0,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 10,
            "reason": "0 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "85320d8042ad10832b6e6cdc5cc7f7ef740c558f",
        "ran_at": "2026-08-01T18:21:44Z",
        "aggregate_score": 6.1,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": true
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-08-01T17:56:39Z",
      "oldest_open_prs": [
        {
          "number": 1039,
          "created_at": "2026-08-01T17:54:25Z",
          "last_comment_at": "2026-08-01T17:57:42Z",
          "last_comment_author": "codspeed-hq"
        },
        {
          "number": 1040,
          "created_at": "2026-08-01T18:13:36Z",
          "last_comment_at": "2026-08-01T18:16:29Z",
          "last_comment_author": "codspeed-hq"
        }
      ],
      "last_merged_pr_at": "2026-08-01T17:53:45Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 943,
          "created_at": "2026-07-24T22:37:22Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 944,
          "created_at": "2026-07-24T22:37:43Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 1036,
          "created_at": "2026-08-01T17:29:43Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/asciidoc-rs/asciidoc-parser",
    "host": "github.com",
    "name": "asciidoc-parser",
    "owner": "asciidoc-rs"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "good",
      "name": "Overall health",
      "note": "The weighted overall 66 is calibrated to 77 on the published index scale (record calibration 2026-08-02).",
      "notes": [
        {
          "code": "overall_calibration",
          "params": {
            "raw": 66,
            "calibrated": 77,
            "calibration": "2026-08-02"
          }
        }
      ],
      "value": 77,
      "inputs": {
        "security": 61,
        "vitality": 94,
        "community": 43,
        "governance": 66,
        "calibration": "2026-08-02",
        "engineering": 61,
        "ai_readiness": 64,
        "weighted_overall_raw": 66
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "exceptional",
        "name": "Vitality",
        "value": 94,
        "weight": 0.21,
        "metrics": [
          {
            "key": "development_activity",
            "band": "excellent",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "commits_last_year": 546,
              "human_commit_share": 1,
              "days_since_last_push": 0,
              "active_weeks_last_year": 37
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "37/52 weeks with commits",
                "points": 25.6,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 37
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "546 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 546
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "exceptional",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "releases_count": 55,
              "latest_release_tag": "v0.29.4",
              "releases_from_tags": false,
              "days_since_latest_release": 0,
              "mean_days_between_releases": 0.7
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "55 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 55
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~0.7 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 0.7
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "exceptional",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "maintained",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": null,
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": 3,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 3 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 3
                    }
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "weak",
        "name": "Community & Adoption",
        "value": 43,
        "weight": 0.17,
        "metrics": [
          {
            "key": "popularity",
            "band": "at_risk",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 29,
            "inputs": {
              "forks": 4,
              "stars": 34,
              "watchers": 2,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "34 stars",
                "points": 24.6,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 34
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "4 forks",
                "points": 4,
                "status": "partial",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 4
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "2 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "readme_badges": null,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "readme_badge_services": [],
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (Apache-2.0)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "Apache-2.0"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          },
          {
            "key": "ecosystem_adoption",
            "band": "moderate",
            "name": "Ecosystem adoption (downloads)",
            "note": "Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "registry_dependents"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 55,
            "inputs": {
              "packages": [
                "asciidoc-parser"
              ],
              "dependents": null,
              "ecosystems": "crates",
              "total_downloads": 13542,
              "monthly_downloads": 2012
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "2,012 downloads/month across crates",
                "points": 44.1,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 2012,
                      "ecosystems": "crates"
                    }
                  }
                ],
                "max_points": 80
              },
              {
                "key": "registry_dependents",
                "name": "Registry dependents",
                "detail": "not reported by this ecosystem",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_reported_by_this_ecosystem",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "good",
        "name": "Sustainability & Governance",
        "value": 66,
        "weight": 0.23,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "moderate",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 60,
            "inputs": {
              "bus_factor": 2,
              "contributors_sampled": 22,
              "top_contributor_share": 0.492
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "2 contributor(s) cover half of all commits",
                "points": 25.2,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 49% of commits",
                "points": 11.4,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 49
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "22 contributors",
                "points": 13.5,
                "status": "met",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 22
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 14 contributing companies or organizations",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "excellent",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): Newcomer PR acceptance. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "newcomer_pr_acceptance"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 80,
            "inputs": {
              "merged_prs": 772,
              "open_issues": 3,
              "closed_issues": 223,
              "prs_merged_7d": null,
              "prs_decided_7d": null,
              "prs_merged_30d": null,
              "prs_decided_30d": null,
              "issue_closed_ratio": 0.987,
              "closed_unmerged_prs": 40,
              "first_time_authors_30d": null,
              "first_time_prs_merged_30d": null,
              "first_time_prs_decided_30d": null
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "99% of issues closed",
                "points": 41.5,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 99
                    }
                  }
                ],
                "max_points": 42
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "772/812 decided PRs merged",
                "points": 28.5,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 772,
                      "decided": 812
                    }
                  }
                ],
                "max_points": 30
              },
              {
                "key": "newcomer_pr_acceptance",
                "name": "Newcomer PR acceptance",
                "detail": "no first-time contributor's PR decided in 30d",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_newcomer_prs",
                    "params": {
                      "days": 30
                    }
                  }
                ],
                "max_points": 13
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 1/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "at_risk",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 34,
            "inputs": {
              "followers": 0,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "asciidoc-rs",
              "public_repos": 2,
              "account_age_days": 175
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "organization-owned",
                "points": 30,
                "status": "met",
                "details": [
                  {
                    "code": "owner_organization",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "0 followers of asciidoc-rs",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 0,
                      "login": "asciidoc-rs"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "2 public repos, account ~0 yr old",
                "points": 4.4,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 2
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 0
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "exceptional",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "asciidoc-parser"
              ],
              "ecosystems": "crates",
              "any_deprecated": false,
              "min_days_since_publish": 0
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on crates",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "crates"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 0 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "55 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 55
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 61,
        "weight": 0.19,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "good",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 68,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "3 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "30 out of 30 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "moderate",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "topics": [
                "asciidoc",
                "markup",
                "parser"
              ],
              "has_wiki": false,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": false,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": "3 topics",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "topics_count",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "moderate",
        "name": "Security",
        "value": 61,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "moderate",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 61,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 17,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 1,
              "scorecard_aggregate": 6.1
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection is not maximal on development and all release branches",
                "points": 2.2,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "30 out of 30 merged PRs checked by a CI test -- score normalized to 10",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 1/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 14 contributing companies or organizations",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "update tool detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow detected",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "all dependencies are pinned",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is not run on all commits -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "0 existing vulnerabilities detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "exceptional",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "commit_weight_rule": {
                "min_commits": 50,
                "min_commit_share": 0.1
              },
              "review_only_matches": 0,
              "below_threshold_exposures": [],
              "assessed_self_published_locations": 21
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "moderate",
        "name": "AI Readiness",
        "value": 64,
        "weight": 0.04,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "weak",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 1,
              "agent_instruction_files": [],
              "agent_instruction_max_bytes": null
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "no CLAUDE.md / AGENTS.md / editor rules",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_instructions",
                    "params": {}
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "100 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 100,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "excellent",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 81,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": true,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0.86,
              "toolchain_manifests": [
                "Cargo.toml",
                "parser/Cargo.toml",
                "sdd/Cargo.toml"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "Cargo.toml, parser/Cargo.toml, sdd/Cargo.toml (toolchain convention, no task runner)",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "toolchain_convention",
                    "params": {
                      "files": "Cargo.toml, parser/Cargo.toml, sdd/Cargo.toml"
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "Rust (statically typed)",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Rust"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "devcontainer",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "devcontainer"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "86 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 86,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "dependency automation configured, none observed in the sampled commits",
                "points": 5,
                "status": "partial",
                "details": [
                  {
                    "code": "dependency_bot_config_only",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "all dependencies are pinned",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "exceptional",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 94,
            "inputs": {
              "primary_language": "Rust",
              "largest_source_bytes": 434972,
              "source_files_sampled": 419,
              "oversized_source_files": 45
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Rust (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Rust"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "45/419 source files over 60KB",
                "points": 49.1,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 419,
                      "oversized": 45
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "weak",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "example_dirs": [
                "examples"
              ],
              "has_mcp_signal": false,
              "api_schema_files": []
            },
            "components": [
              {
                "key": "api_schema_openapi_graphql_proto",
                "name": "API schema (OpenAPI/GraphQL/proto)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              },
              {
                "key": "mcp_server",
                "name": "MCP server",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "runnable_examples",
                "name": "Runnable examples",
                "detail": "examples",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "examples"
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? Carries a deliberately small weight: agent tooling is a real maintenance signal, but its absence must never gate the top of the scale (calibration saturates at raw 91, so 100/100 remains reachable with AI Readiness at zero)."
      }
    ],
    "classification": {
      "top": [
        "library"
      ],
      "labels": [
        "library"
      ],
      "scores": {
        "library": 6
      },
      "primary": "library",
      "evidence": [
        {
          "tier": "distribution",
          "label": "library",
          "source": "registry:crates",
          "weight": 6
        }
      ],
      "artifacts": [],
      "confidence": "medium",
      "host_extension": false,
      "runs_as_process": false,
      "consumed_by_code": true
    },
    "metrics_version": "2.5.0"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "crates package 'sdd' points at a different repository (https://codeberg.org/wvwwvwwv/scalable-delayed-dealloc); excluded from ecosystem scoring",
    "deps.dev does not index crates:asciidoc-parser@0.29.4; advisories assessed against the repository dependency graph instead",
    "No resolved dependencies carried a version and a supported ecosystem"
  ],
  "report_type": "repository",
  "generated_at": "2026-08-01T18:22:10.907697Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/a/asciidoc-rs/asciidoc-parser.svg",
  "full_name": "asciidoc-rs/asciidoc-parser",
  "license_state": "standard",
  "license_spdx": "Apache-2.0"
}

Scores are signals, not warranties. They reflect publicly visible practices on GitHub — not a code audit, and not a security guarantee.

Missing data is excluded and weights renormalized, never scored as zero. Methodology is versioned and open: metrics v2.5.0, schema v0.27.0 — full methodology · metrics wiki.

How one result sits in the wider record: aggregate statisticscrates.io.