Feat/strictdoc sdoc support#191
Merged
Merged
Conversation
Two related fixes: * Probe pnpm presence with `pnpm --version` instead of `pnpm version`. The subcommand form expects a version argument and fails with ERR_PNPM_INVALID_VERSION_BUMP outside a node project, so `output.status.success()` is false and the build script panics. The flag form matches every other "is X installed?" probe in the file. * allowBuilds for @parcel/watcher and esbuild in dashboard/pnpm-workspace.yaml. pnpm 11 refuses to run third-party postinstall scripts by default and exits non-zero with ERR_PNPM_IGNORED_BUILDS; these two are required for vite/esbuild's native binaries.
Two related changes to the comment scanner: 1. Relax the rule-ID body character class from is_ascii_lowercase to is_ascii_alphabetic, in both the text-based extractor (lexer.rs) and the tree-sitter-driven one (code_units.rs). The prefix lowercase rule still stands — tracey's normative spec (markdown.syntax.marker+2) only constrains the prefix, and the rule-ID body restriction was an undocumented implementation invariant. parse_rule_id already preserves case, so existing case-sensitive equality and Hash/Ord behaviour are unchanged: r[foo] and r[FOO] remain distinct. 2. Add a sibling scan for StrictDoc-style @relation(UID[, UID...][, scope=...][, role=...]) source-comment annotations. Implementation parser comes from the strictdoc-parser crate. Role mapping: no role / role=Implements -> RefVerb::Impl role=Verifies -> RefVerb::Verify role=Refines -> warning + skipped (v1) role=<anything else> -> warning + skipped (v1) Multi-UID annotations expand to one ReqReference per UID, sharing the call's span. References use a synthetic prefix "r" so they pair with r[...]-style markdown specs without per-spec configuration. Adds 7 lexer unit tests covering uppercase/mixed-case rule IDs and every @relation shape (single UID, role=Verifies, multi-UID, Refines-warns). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8f8c70e to
eb323f1
Compare
fasterthanlime
requested changes
May 15, 2026
Contributor
fasterthanlime
left a comment
There was a problem hiding this comment.
Just need a crate publish, then we're good to go. I think!
| } | ||
|
|
||
| // Check if pnpm is available | ||
| let pnpm_check = shell_command("pnpm").arg("version").output(); |
Contributor
Author
There was a problem hiding this comment.
<insert generic javascript bashing comment here, adding nothing to the PR but making myself feel smug>
| pulldown-cmark = "0.13" | ||
|
|
||
| # StrictDoc parser for .sdoc spec files | ||
| strictdoc-parser = { git = "https://github.com/kraln/strictdoc-parser", tag = "v0.1.0" } |
Contributor
There was a problem hiding this comment.
Okay, so I can't actually merge until this is published. Because that would prevent publishing tracey.
Well, I guess I can, but I won't.
Adds StrictDoc (.sdoc) ingest as a first-class peer of markdown specs.
File extension drives the choice of parser: .md keeps going through marq,
.sdoc routes to a new sdoc module that bridges strictdoc-parser onto
tracey's existing ReqDefinition / ExtractedRule types.
Spec rule fields are mapped from a RequirementView as follows:
id parse_rule_id(view.uid()) (preserves UID case)
anchor_id "r--<UID>"
line RequirementView.span.line
span covering the whole [REQUIREMENT] block
raw source slice of the same range
metadata ReqMetadata::default() (STATUS/MARKUP wiring is v2)
html see below
Requirements without a UID are silently skipped, matching strictdoc's own
behaviour for unidentified requirements (in the upstream 0.21.0 corpus
that's 424 of 1893 reqs across docs that aren't traceability sources).
HTML rendering for v1:
OPTIONS.MARKUP = "Markdown" -> route STATEMENT through marq
everything else (Text / RST / absent) -> HTML-escape and wrap in <p>
This makes the dashboard and `query` paths show readable prose without
pulling in an RST renderer in v1; the structured fields still surface in
`query rule <UID>` via the raw source slice.
The bridge plugs in at four call sites: the CLI spec loader
(load_rules_from_glob), the daemon's cached spec extractor
(extract_sdoc_rules_cached, mirroring the markdown one), bump.rs
(parse_spec_rules now dispatches on .sdoc), and the LSP diagnostic
clear-on-close path. A new tracey_core::is_spec_extension helper
centralises the "is this a .md or .sdoc?" predicate.
Source-side, .sdoc projects can use either the existing r[impl <UID>]
syntax or the StrictDoc-native @relation(<UID>, scope=function) form
added in the prior commit — both produce ReqReferences with prefix "r"
that match the synthetic prefix used by the bridge.
Tests:
- crates/tracey/tests/sdoc_integration.rs (2 tests): end-to-end via
Engine::new on a fixture with a 3-req .sdoc (BR-001 MARKUP:Markdown,
BR-002/BR-003 default) and a Rust source file exercising every
annotation shape plus a legacy r[impl ...] marker.
- crates/tracey/tests/sdoc_corpus_smoke.rs (#[ignore]d): walks an
out-of-tree StrictDoc corpus pointed at by $STRICTDOC_CORPUS and
asserts the bridge handles >1000 docs without panicking. Tested
against strictdoc-project/strictdoc 0.21.0 locally: 1434/1436 docs
bridge cleanly (same two failures as strictdoc-parser's own parser
CI — a deliberately-malformed fixture and a deep heredoc-in-heredoc
case).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three small doc adds matching the feature: - README.md: broaden the "(in markdown)" framing to include StrictDoc. - guide/writing-specs.md: append a "StrictDoc format (.sdoc)" section covering UID conventions, the synthetic source-side prefix, MARKUP rendering rules, and the supported subset of the grammar. - guide/annotating-code.md: add a "StrictDoc-style markers (@relation)" section with the role-to-verb mapping, multi-UID syntax, and a note on co-existing with r[...] markers. tracey's normative spec (docs/content/spec/tracey.md) is untouched — its requirement-ID design feels like a maintainer call. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eb323f1 to
4b4fd57
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds StrictDoc support to tracey: load
.sdocfiles as specs alongside.md, and recognize@relation(UID, scope=..., role=...)source annotations alongsider[impl <id>].The parser is a standalone
strictdoc-parsercrate (github.com/kraln/strictdoc-parser) which essentially exists to support the PR (happy to push to crates.io if that's important)I tried to keep the change surface as small as possible, so there were some compromises along the way:
.sdocOPTIONS.MARKUP: Markdownroutes throughmarq; everything else (RST/Text/absent) is HTML-escapedrole=Refinesemits a warning and produces no reference. There's not a good match for it in Tracey.and maybe the most controversial one:
r[foo]andr[FOO]are now distinct rule IDsThis could also be structured as a feature flag if that makes more sense.