AUR-363 — Fixar parsers e grammars
Documento histórico do board. Pode descrever componentes removidos; para uso atual, consulte o guia do produto.
Purpose
Pins, for every documentation-extraction adapter under
internal/documentation/extractors/, the language it handles, the SHA-256
digest of its extractor.go implementation, the identity and version (or
explicit unpinned/not-applicable disposition) of the external grammar/
tool that adapter shells out to, the SHA-256 digest of a small non-sensitive
fixture corpus file, and the 4 MiB (4194304 byte) maximum file size every
adapter is bound to. This card does not parse real source code and does not
judge grammar quality — see Non-goals in .board/cards/done/AUR-363.md; it
seals identity, digests, and bounds only.
tests/acceptance/AUR-363.sh verifies all of this two ways: (1) against the
real repository tree, cross-referencing the lock against every adapter
directory that actually contains an extractor.go, and (2) against ten
sealed fixtures under tests/bootstrap/locks/AUR-363/_fixtures/, driven by
tests/bootstrap/locks/AUR-363/cases.tsv. The fixtures tree is named
_fixtures/, not fixtures/: the _ prefix is a Go module-aware package
discovery convention (like the built-in testdata/ skip), so go build
./... and go vet ./... never descend into it, even though several
fixtures below deliberately contain synthetic .go files — including one,
implementationsymlink, where a real symlink and its target both declare
the same type name in the same directory, which would otherwise redeclare
across the whole-repository build.
Why the test was extended, not just read
The card's own Skeptical mutations (MUT-001 parser-unlocked, MUT-002
corpus-digest-mismatch) name disposition words that the originally sealed
four-line check could never produce: that check only confirmed the lock
file's own presence, its schema: line, the presence of some sha256:
pattern anywhere in the file, and the absence of a latest/branch-style
literal. It never associated a digest with the specific file it is supposed
to bind, and never compared the declared adapter set against what actually
exists in internal/documentation/extractors/. Two of the three named
mutations were therefore structurally undetectable — not a probabilistic
gap, an unconditional one — which the card's TDD proof requires ("aplicar
MUT-001, observar o erro comportamental"). tests/acceptance/AUR-363.sh is
listed in this card's own paths, so it was extended strictly additively:
every original check (parser_lock_incomplete, invalid_lock_or_manifest,
mutable_reference) is reproduced byte-for-byte, in the same order, before
any new check runs, so no previously-passing or previously-failing case
changes disposition. MUT-003's exact word, grammar-ref-mutable, is new
vocabulary added for the same reason: the pinned Go grammar's only real
version pin in the repository (Dockerfile:26) is a semver tag, not a
latest/branch literal, so swapping it for a bare, unversioned reference
would not have tripped the original mutable_reference check at all.
Artifacts and schema
.board/bootstrap/locks/parsers.yml
Flat key: value document, LC_ALL=C, one pair per line, 0 < size <=
16384 bytes (the real file is ~5 KiB; the bound leaves headroom for future
adapters without changing itself). A 4-line header:
| Key | Value |
|---|---|
schema |
bootstrap-lock-v1 |
card |
AUR-363 |
adapter_count |
8 |
max_file_bytes |
4194304 |
Then, for each adapter <lang> in {go, python, javascript, csharp, cpp,
rust, bash, powershell}, nine flat keys prefixed adapter_<lang>_:
| Suffix | Meaning |
|---|---|
language |
The Language value from internal/documentation/extractors/types.go; always equal to <lang>. |
implementation_path |
Repository-relative path to that adapter's extractor.go. |
implementation_sha256 |
sha256:<64 hex> — recomputed SHA-256 of implementation_path's content, never trusted from the file itself. |
grammar_identity |
The external tool/grammar the adapter's Extract/Validate shells out to (or native-go-comment-scanner when there is none — see below). |
grammar_version |
One of a pinned v<major>.<minor>.<patch>, the literal unpinned (an external tool exists but no version is asserted anywhere in the repository), or the literal not-applicable (no external grammar; the adapter's own Go source is the grammar). |
grammar_pin_source |
path:line of the exact repository evidence for grammar_version — a go install ...@vX.Y.Z pin or a bare --version probe with no assertion. |
fixture_corpus_path |
Repository-relative path to a small, non-sensitive, single-file corpus for that language. |
fixture_corpus_sha256 |
sha256:<64 hex> — recomputed SHA-256 of fixture_corpus_path's content. |
max_file_bytes |
Always 4194304 (4 MiB) — the per-adapter ceiling this card's Outcome commits to. |
Per-adapter grammar pins (real, repository-derived)
| Language | grammar_identity |
grammar_version |
Evidence |
|---|---|---|---|
| go | gomarkdoc |
v1.1.0 |
Dockerfile:26 — go install github.com/princjef/gomarkdoc/cmd/gomarkdoc@v1.1.0, chosen "rather than @latest so the image is reproducible" (Dockerfile:21). |
| python | pydoc-markdown |
unpinned |
internal/documentation/extractors/python/extractor.go:111 — p.runner.Run(ctx, "pydoc-markdown", []string{"--version"}, ...); no version is asserted. |
| javascript | typedoc |
unpinned |
internal/documentation/extractors/javascript/extractor.go:110 — same --version-probe-only pattern. |
| csharp | xmldocmd |
unpinned |
internal/documentation/extractors/csharp/extractor.go:179 — same pattern; dotnet itself is also probed at line 170 but xmldocmd is the doc-generating grammar per the type doc comment at line 41. |
| cpp | doxygen |
unpinned |
internal/documentation/extractors/cpp/extractor.go:114. |
| rust | cargo-doc |
unpinned |
internal/documentation/extractors/rust/extractor.go:125 — cargo --version probed, no assertion; cargo doc itself invoked at line 79. |
| bash | native-go-comment-scanner |
not-applicable |
internal/documentation/extractors/bash/extractor.go:82 — the only external call is bash --version (an availability check, not a parser); extraction is native Go comment scanning. |
| powershell | native-go-comment-scanner |
not-applicable |
internal/documentation/extractors/powershell/extractor.go:82 — identical pattern, pwsh -Version only. |
No network lookup was performed or needed: every value above is read
directly from a file already in the repository at the cited line, per this
card's read_paths (go.mod, go.sum, internal/documentation/extractors)
plus Dockerfile, which documents its own pin rationale inline.
tests/bootstrap/locks/AUR-363/cases.tsv
Same shape as the sibling card's fixture table: #name, fixture,
input_sha256 (- for deliberate absence), expected. Ten rows,
<= 256, <= 4 MiB. Each row's fixture names a subdirectory under
tests/bootstrap/locks/AUR-363/_fixtures/, a self-contained two-adapter
(alpha, beta) micro-repository — never the real 8-language lock — that
exercises verify_parsers_lock in isolation:
| Row | Fixture shape | Expected |
|---|---|---|
nominal |
Complete, consistent 2-adapter lock, corpus, and implementations. | pass |
absence |
No .board/bootstrap/locks/parsers.yml. |
parser_lock_incomplete |
tamper |
parsers.yml is a symlink to real.yml (also digest-wrong). |
parser_lock_incomplete (this card's file-existence check treats a symlink the same as absence — see "Codes" below) |
invalid |
adapter_alpha_max_file_bytes is 4194303, not 4194304. |
invalid_lock_or_manifest |
overlimit |
Lock padded past 16384 bytes. |
input_limit_exceeded |
unlocked |
internal/documentation/extractors/gamma/extractor.go exists with no adapter_gamma_language line. |
parser-unlocked |
corpusmismatch |
adapter_alpha_fixture_corpus_sha256 does not match the recomputed digest of corpus/alpha.txt. |
corpus-digest-mismatch |
grammarmutable |
adapter_alpha_grammar_version is current (name-based, not a pin). |
grammar-ref-mutable |
implementationtamper |
adapter_alpha_implementation_sha256 does not match the recomputed digest of extractor.go's actual content. |
source_integrity_error |
implementationsymlink |
internal/documentation/extractors/alpha/extractor.go is a symlink to a sibling real_impl.go, not a regular file. |
source_integrity_error |
Bounds
| Bound | Value |
|---|---|
.board/bootstrap/locks/parsers.yml size |
16384 bytes |
Any implementation_path or fixture_corpus_path file read |
4194304 bytes (4 MiB) — checked by size before any read; a file over this bound is never opened for hashing |
tests/bootstrap/locks/AUR-363/cases.tsv size |
4 MiB |
cases.tsv rows |
256 |
| Acceptance container wall-clock (informational) | 15 s |
Codes
Typed dispositions on stderr as AUR-363/AC-001/<code> (exit 1,
behavioral) or AUR-363/AC-001/inconclusive/<reason> (exit 79,
environment):
| Code | Trigger |
|---|---|
parser_lock_incomplete |
.board/bootstrap/locks/parsers.yml is absent, or exists but is a symlink or not a regular file (this card's file-level check does not distinguish absence from symlink/non-regular — both are "the lock this card owns does not exist as declared"). |
invalid_lock_or_manifest |
The lock is empty, missing schema: bootstrap-lock-v1, missing any sha256:[0-9a-f]{64} pattern, missing a required per-adapter key, or a per-adapter max_file_bytes value is not exactly 4194304. |
input_limit_exceeded |
The lock exceeds 16384 bytes, or an implementation_path/fixture_corpus_path file exceeds 4194304 bytes. |
mutable_reference |
The lock contains a latest or @main/@master/@head literal anywhere. |
parser-unlocked |
An adapter directory containing extractor.go exists under internal/documentation/extractors/ with no matching adapter_<name>_language: <name> line in the lock (MUT-001). |
corpus-digest-mismatch |
A declared fixture_corpus_sha256 diverges from the recomputed SHA-256 of the file at fixture_corpus_path (MUT-002). |
grammar-ref-mutable |
A declared grammar_version is not unpinned, not not-applicable, and not v<major>.<minor>.<patch> — i.e. it is a name-based or otherwise unverifiable reference (MUT-003). |
source_integrity_error |
A declared implementation_path is absent, a symlink, or its recomputed SHA-256 diverges from implementation_sha256. |
fixture_sensitivity_error |
This program's own fixture self-test observed a disposition other than what cases.tsv seals — the verifier failed to discriminate a known fixture. |
Diagnostic example (synthetic)
$ bash tests/acceptance/AUR-363.sh
{"card":"AUR-363","scenario":"AC-001","selector":"AC-001","fixture_cases":10,"result":"pass"}
An absent lock instead produces, on stderr, exit 1:
AUR-363/AC-001/parser_lock_incomplete
Offline OCI command
This is exactly the card's accept: line, run through the pinned bootstrap
profile (bash@sha256:ae4668c2560999e65e89532cd2ad1b6688bb23298189f0bd229ef80fa4bd0831,
network=none, non-root, read-only rootfs — see
.board/bootstrap/locks/trust-root.yml and .board/oci/profiles/
bootstrap-readonly-v1.json), reproducible offline once that image is present
in the local image cache:
./.board/bin/oci-run --profile bootstrap-readonly-v1 --card AUR-363