constraint-lens

A MoonBit rule engine for explainable project-text and release checklist audits.

moonbit
audit
readme
ci
release
compliance
moon add WB-ai-nb/constraint-lens@0.1.1
Download zip
Author
Version
0.1.1
License
MIT
Last updated
4 hours ago
Downloads
4
README

#Constraint Lens

Constraint Lens is a MoonBit package for explainable audits of project text: README files, release notes, issue briefs, acceptance checklists, and small engineering records.

It is useful when a maintainer wants an offline, deterministic check before a package is reviewed or published. Instead of returning only "pass" or "fail", Constraint Lens reports the rule id, severity, score, line-level evidence, and a repair hint for every finding.

#Overview

Project documentation often fails review for simple but costly reasons: missing usage commands, unclear scope, no test path, no release steps, forgotten placeholders, or hidden line-length problems. Constraint Lens gives these materials a reusable rule engine written in MoonBit, with built-in profiles for:

  • MoonBit package acceptance text
  • Changelog and release notes
  • Project application briefs

#Installation

After publishing, add the package from mooncakes.io:

moon add WB-ai-nb/constraint-lens

If your Mooncakes owner is different, replace WB-ai-nb in moon.mod, cmd/main/moon.pkg, and the README URLs before the first release.

#Usage

Minimal library usage:

import {
"WB-ai-nb/constraint-lens" @lens
}

test {
let audit = @lens.audit_text(
"release note",
@lens.example_text(),
@lens.moonbit_acceptance_profile(),
)
inspect(audit.is_success(), content="true")
}

Runnable example:

moon run cmd/main

#Local Development

moon update moon fmt --check moon check moon build moon test moon run cmd/main moon package --list moon publish --dry-run

moon publish --dry-run requires network access and a valid Mooncakes account session when the registry asks for authentication.

#Continuous Integration

The repository includes .github/workflows/ci.yml. On every push and pull request it installs the MoonBit toolchain, checks formatting, type-checks, builds, runs tests, executes the example, and inspects the publish package.

#API Surface

  • audit_text(title, text, rules) runs a weighted rule set.
  • moonbit_acceptance_profile() checks MoonBit package review material.
  • release_note_profile() checks changelog and release-note text.
  • application_profile() checks project application briefs.
  • tokenize_lines(text) converts Markdown-like text into line tokens.
  • analyze_shape(text) counts headings, bullets, paragraphs, blanks, and code fences.
  • Audit::to_markdown() exports a reviewer-friendly report.
  • Audit::to_jsonish() exports compact machine-readable report text.

#Supported Scope

  • Plain text and Markdown-like documents
  • Case-insensitive ASCII keyword matching
  • Weighted scoring and severity gates
  • Ordered-section checks
  • Forbidden placeholder checks
  • Line-length budget checks
  • Evidence extraction with source line numbers

#Not Supported

  • Full Markdown parsing
  • File system traversal
  • Network calls
  • Policy decisions that require private project context
  • Natural-language judgement beyond deterministic terms and sections

#Mooncakes

  • Package name: WB-ai-nb/constraint-lens
  • Module version: 0.1.1
  • Public repository: https://github.com/WB-ai-nb/constraint-lens
  • Expected docs URL after publish: https://mooncakes.io/docs/WB-ai-nb/constraint-lens
  • Expected manifest URL after publish: https://mooncakes.io/api/v0/manifest/WB-ai-nb/constraint-lens

#Testing

The test suite covers normal input, missing required text, forbidden terms, boundary line length, section ordering, paired terms, occurrence counting, document-shape conversion, report export, and empty rule sets.

Run:

moon test

#License

Constraint Lens is released under the MIT license. It contains original MoonBit source code and uses no third-party code, images, fonts, audio, or datasets. See THIRD_PARTY.md.

#
Audit

pub(all) struct Audit {
title : String
score : Int
max_score : Int
earned_score : Int
grade : String
findings : Array[Finding]
stats : AuditStats
} derive(
Debug
)

Complete audit result.

#
Audit::failed

fn Audit::failed(self : Audit) -> Array[Finding]

Return only failed findings.

#
Audit::is_success

fn Audit::is_success(self : Audit) -> Bool

True when the audit has no failing error-level findings.

#
Audit::passed

fn Audit::passed(self : Audit) -> Array[Finding]

Return only passed findings.

#
Audit::to_jsonish

fn Audit::to_jsonish(self : Audit) -> String

Render a compact JSON-like string without depending on a JSON package.

#
Audit::to_markdown

fn Audit::to_markdown(self : Audit) -> String

Render a human-readable Markdown audit report.

#
AuditStats

pub(all) struct AuditStats {
line_count : Int
char_count : Int
matched_rules : Int
failed_rules : Int
error_count : Int
warning_count : Int
heading_count : Int
bullet_count : Int
} derive(Eq,
Debug
)

Aggregated counters for an audit run.

#
DocumentShape

pub(all) struct DocumentShape {
lines : Int
headings : Int
bullets : Int
code_fences : Int
paragraphs : Int
blanks : Int
} derive(Eq,
Debug
)

Shape summary produced while tokenizing a document.

#
Evidence

pub(all) struct Evidence {
line : Int
snippet : String
matched : String
} derive(Eq,
Debug
)

Evidence points at a concrete line and matching term.

#
Finding

pub(all) struct Finding {
rule_id : String
title : String
category : String
severity : Severity
passed : Bool
weight : Int
earned : Int
message : String
hint : String
evidence : Array[Evidence]
} derive(
Debug
)

Result of evaluating a single rule.

#
Finding::is_blocking

fn Finding::is_blocking(self : Finding) -> Bool

True when a failed finding should block release.

#
LineKind

pub(all) enum LineKind {
Blank
Heading
Bullet
CodeFence
Paragraph
} derive(Eq,
Debug
)

Token category emitted by tokenize_lines.

#
LineToken

pub(all) struct LineToken {
line : Int
kind : LineKind
text : String
} derive(Eq,
Debug
)

A line-level token that keeps the source line number.

#
Rule

pub(all) struct Rule {
id : String
title : String
category : String
severity : Severity
weight : Int
kind : RuleKind
hint : String
} derive(
Debug
)

A weighted rule with an explanation-oriented hint.

#
Rule::max_line_length

fn Rule::max_line_length(id : StringView, title : StringView, category : StringView, severity : Severity, weight : Int, max : Int, hint : StringView) -> Rule

Construct a maximum line length rule.

#
Rule::min_occurrences

fn Rule::min_occurrences(id : StringView, title : StringView, category : StringView, severity : Severity, weight : Int, needle : StringView, min : Int, hint : StringView) -> Rule

Construct a minimum occurrence rule.

#
Rule::must_contain_any

fn Rule::must_contain_any(id : StringView, title : StringView, category : StringView, severity : Severity, weight : Int, terms : ArrayView[String], hint : StringView) -> Rule

Construct a presence rule that passes when any term is found.

#
Rule::must_not_contain_any

fn Rule::must_not_contain_any(id : StringView, title : StringView, category : StringView, severity : Severity, weight : Int, terms : ArrayView[String], hint : StringView) -> Rule

Construct a rule that fails when any forbidden term is found.

#
Rule::requires_pair

fn Rule::requires_pair(id : StringView, title : StringView, category : StringView, severity : Severity, weight : Int, left : StringView, right : StringView, hint : StringView) -> Rule

Construct a rule where the right term is required when the left term exists.

#
Rule::section_order

fn Rule::section_order(id : StringView, title : StringView, category : StringView, severity : Severity, weight : Int, sections : ArrayView[String], hint : StringView) -> Rule

Construct an ordered-section rule.

#
RuleKind

pub(all) enum RuleKind {
MustContainAny(Array[String])
MustNotContainAny(Array[String])
MinOccurrences(String, Int)
MaxLineLength(Int)
RequiresPair(String, String)
SectionOrder(Array[String])
} derive(
Debug
)

Rule strategies supported by the engine.

#
Severity

pub(all) enum Severity {
Info
Warning
Error
} derive(Eq,
Debug
)

Core data model for explainable text audits.

#
Severity::label

fn Severity::label(self : Severity) -> String

Stable lowercase label used by reports and external tools.

#
Severity::rank

fn Severity::rank(self : Severity) -> Int

A small ordinal used when callers need to sort or gate findings.

#
analyze_shape

fn analyze_shape(text : StringView) -> DocumentShape

Summarize a document shape from line tokens.

#
application_profile

fn application_profile() -> Array[Rule]

A profile for compact project briefs and application forms.

#
audit_text

fn audit_text(title : StringView, text : StringView, rules : ArrayView[Rule]) -> Audit

Run a weighted rule set against text.

#
example_text

fn example_text() -> String

Built-in sample used by moon run cmd/main.

#
moonbit_acceptance_profile

fn moonbit_acceptance_profile() -> Array[Rule]

A reusable profile for MoonBit package acceptance checklists.

#
release_note_profile

fn release_note_profile() -> Array[Rule]

A compact profile for changelog and release-note text.

#
tokenize_lines

fn tokenize_lines(text : StringView) -> Array[LineToken]

Parse source text into line-level tokens.

Powered by MoonBit

Site sourceReport issuePackagesBuild queueSkillsStatistics

© 2026 mooncakes.io