The README makes claims. This file backs them up.
A Haskell library for parsing and rendering A2ML (Attested Markup Language) documents. A2ML is an attestation-native markup format designed for documents that carry trust metadata, cryptographic attestations, and provenance information.
Data.A2ML.Parser (src/Data/A2ML/Parser.hs) implements a line-oriented,
purely functional parser over Text. The top-level function parseA2ML ::
Text → Either ParseError Document returns a typed sum on failure rather than
crashing. Internally, parseLines → parseBlocks recurse over the line list,
pattern-matching on headings (# … #), directive blocks
(@name: … @end), bullet items (- ` or `* `), and plain paragraph lines.
Inline formatting (bold, `italic) is handled by parseInlines and
its helper parseInlinesItalic using Data.Text.breakOn — no regex, no
mutable state.
The Haskell variant models directives as multi-line blocks (@name: … @end),
which is a richer surface syntax than the single-line @name value used in
a2ml-rs. Both parsers share the same output semantics for Document and
Attestation, but diverge on directives: Data.A2ML.Types uses a
DirectiveName sum type with known constructors (DirAbstract, DirRefs,
DirAttestation, DirMeta, DirCustom Text) rather than a free-form string pair.
Caveat: The inline parser handles bold and italic via
left-to-right breakOn; nested or interleaved emphasis (e.g.
a b c) is not yet handled correctly. Link [text](url) and
@ref(id) patterns are declared in the module signature but the parser
implementation falls through to PlainText for those cases — the
infrastructure is present, the pattern matching is incomplete. The fuzz
corpus (tests/fuzz/) is a placeholder only.
-
Parser entry:
src/Data/A2ML/Parser.hs:49(parseA2ML :: Text → Either ParseError Document) -
Type definitions:
src/Data/A2ML/Types.hs(Document, Block, Inline, DirectiveName, Attestation, TrustLevel, Manifest, Reference) -
Renderer:
src/Data/A2ML/Renderer.hs -
Top-level re-export:
src/Data/A2ML.hs -
Learn more: https://hackage.haskell.org/package/a2ml (forthcoming), https://github.com/hyperpolymath/a2ml
A cryptographic attestation attached to content. attestationSigner :: Text attestationAlgorithm :: Text attestationSignature :: Text attestationTimestamp :: Maybe Text
The Haskell Attestation type goes further than the Rust binding: it records
attestationAlgorithm (e.g. "ed25519", "sha256") and
attestationSignature (hex or base64). The TrustLevel enum runs from
Unsigned through SelfAttested, ThirdPartyAttested, to MultiAttested,
encoding the number and independence of attestors rather than the Rust
variant’s subjective Reviewed/Verified distinction. Manifest aggregates
title, author, version, SPDX license, overall TrustLevel, and the full
attestation list — making it the canonical entry point for programmatic
provenance inspection.
Caveat: Signature verification (actual crypto) is not implemented in
this library. attestationSignature is stored as an opaque Text field.
An external verifier (e.g. the cookie-rebound Zig FFI layer or a GnuPG
wrapper) must perform the actual ed25519 or SHA-256 check. The
MultiAttested level is declared but no quorum logic is implemented yet.
-
Attestation type:
src/Data/A2ML/Types.hs:96–117 -
Trust level enum:
src/Data/A2ML/Types.hs:108–117(Unsigned → MultiAttested) -
Manifest type:
src/Data/A2ML/Types.hs:119–133
test-suite a2ml-tests other-modules: UnitSpec E2ESpec PropertySpec build-depends: hspec, QuickCheck, hspec-quickcheck
The test suite has three modules. UnitSpec tests individual parser functions
in isolation (heading level detection, directive name parsing, bullet list
accumulation). E2ESpec tests the full parseA2ML → renderA2ML round-trip
on representative .a2ml documents. PropertySpec uses QuickCheck to assert
parseA2ML (renderA2ML doc) == Right doc for arbitrary Document values —
that the renderer and parser are mutual inverses. The Spec.hs entry point
aggregates all three via hspec.
Caveat: QuickCheck generators for Document do not yet exercise the full
surface syntax — generated documents use only headings and paragraphs, not
directives or attestations. Property coverage will expand as the inline parser
matures.
-
Unit tests:
tests/UnitSpec.hs -
End-to-end tests:
tests/E2ESpec.hs -
Property tests:
tests/PropertySpec.hs -
Test runner:
tests/Spec.hs -
Benchmark:
bench/Main.hs(Criterion for parse and render hot paths) -
Run:
cabal testorjust test
license: MPL-2.0 — (PMPL-1.0-or-later preferred; MPL-2.0 required for Hackage OSI-approved policy)
Hackage requires an OSI-approved license; PMPL-1.0-or-later is not yet on the
OSI list. The fallback policy (identical to a2ml-rs) applies: every .hs
source file carries the dual SPDX comment. The LICENSE-MPL-2.0 file is
present alongside LICENSE (PMPL-1.0-or-later).
Caveat: Unlike crates.io, Hackage does not enforce the SPDX identifier at upload time by machine. The comment in each source file is the enforceable record of the dual-license intent.
-
License files:
LICENSE(PMPL-1.0-or-later),LICENSE-MPL-2.0 -
Learn more: https://github.com/hyperpolymath/palimpsest-license
Zig FFI scaffold for exposing Data.A2ML as a C-ABI library.
The src/interface/ffi/ directory follows the standard Idris2-ABI / Zig-FFI
architecture required by all RSR projects with cross-language interfaces. The
build.zig and main.zig scaffold is present; the Idris2 ABI definitions in
src/interface/abi/ are placeholders. This layer is intended to expose
parseA2ML as a C-callable function for embedding the Haskell parser in
non-Haskell hosts via GHC’s Foreign Function Interface.
Caveat: The Zig FFI is not yet wired to any real Haskell FFI export. No
.hs module currently declares foreign export ccall bindings. This is
scaffolding for a future integration milestone.
-
FFI scaffold:
src/interface/ffi/src/main.zig,src/interface/ffi/build.zig -
ABI placeholder:
src/interface/abi/(Idris2 definitions pending) -
Integration test scaffold:
src/interface/ffi/test/integration_test.zig
| Technology | Also Used In |
|---|---|
A2ML format |
a2ml-rs (Rust binding), pandoc-a2ml (Lua Pandoc reader), tree-sitter-a2ml (grammar) |
Haskell / GHC + cabal |
nextgen-languages (Scaffoldia CLI, AffineScript compiler), hypatia (rule modules) |
hspec + QuickCheck |
Other Haskell projects in the |
SPDX MPL-2.0 fallback |
a2ml-rs (crates.io policy) |
| Path | Proves |
|---|---|
|
Top-level re-export module — public API surface for library consumers |
|
AST: |
|
Line-oriented parser: |
|
Canonical serialiser: |
|
Isolated unit tests for parser primitives |
|
End-to-end parse→render→re-parse round-trip tests |
|
QuickCheck property: |
|
hspec aggregator entry point |
|
Criterion benchmarks for parse and render hot paths |
|
Package metadata: exposed modules, build deps (base, text, containers, bytestring), GHC warning flags, test suite and benchmark stanza definitions |
|
Idris2 ABI definitions (placeholder — formal proof artefacts pending) |
|
Zig FFI scaffold for C-ABI exposure of the Haskell parser |
|
FFI integration test scaffold |
|
AI session gatekeeper — read first before modifying any file |
|
A2ML state files: STATE.a2ml, ECOSYSTEM.a2ml, META.a2ml |