///|
/// High-level acceptance state for release and contest submission reviews.
pub(all) enum TapReadinessLevel {
ReadinessReady
ReadinessNeedsWork
ReadinessBlocked
} derive(Debug, Eq)
///|
/// Risk level attached to one readiness check.
pub(all) enum TapReadinessRisk {
RiskPass
RiskNotice
RiskWarning
RiskBlock
} derive(Debug, Eq)
///|
/// Evidence supplied by a project, script, or human review.
pub(all) struct TapProjectEvidence {
package_name : String
version : String
repository : String
license : String
readme_present : Bool
readme_has_usage : Bool
readme_has_features : Bool
ci_configured : Bool
examples : Int
test_cases : Int
build_ok : Bool
mooncakes_published : Bool
mooncakes_version : String
mooncakes_build_ok : Bool
commit_count : Int
total_moonbit_lines : Int
effective_moonbit_lines : Int
has_changelog : Bool
has_design_doc : Bool
has_provenance_doc : Bool
has_acceptance_checklist : Bool
clean_tree : Bool
} derive(Debug, Eq)
///|
/// One scored acceptance or release readiness check.
pub(all) struct TapReadinessCheck {
id : String
category : String
title : String
required : Bool
passed : Bool
score : Int
max_score : Int
risk : TapReadinessRisk
evidence : String
remediation : String
} derive(Debug, Eq)
///|
/// Complete readiness report composed from TAP data and repository evidence.
pub(all) struct TapReadinessReport {
project : String
suite : TapSuiteReport
policy : TapPolicyResult
evidence : TapProjectEvidence
checks : Array[TapReadinessCheck]
score : Int
level : TapReadinessLevel
ok : Bool
} derive(Debug, Eq)
///|
/// Construct an empty evidence object for tests or incremental tools.
pub fn empty_project_evidence(package_name : String) -> TapProjectEvidence {
TapProjectEvidence::{
package_name,
version: "",
repository: "",
license: "",
readme_present: false,
readme_has_usage: false,
readme_has_features: false,
ci_configured: false,
examples: 0,
test_cases: 0,
build_ok: false,
mooncakes_published: false,
mooncakes_version: "",
mooncakes_build_ok: false,
commit_count: 0,
total_moonbit_lines: 0,
effective_moonbit_lines: 0,
has_changelog: false,
has_design_doc: false,
has_provenance_doc: false,
has_acceptance_checklist: false,
clean_tree: false,
}
}
///|
/// Construct evidence for a repository that already passed local verification.
pub fn verified_project_evidence(
package_name : String,
version : String,
repository : String,
license : String,
examples : Int,
test_cases : Int,
total_moonbit_lines : Int,
effective_moonbit_lines : Int,
commit_count : Int,
) -> TapProjectEvidence {
TapProjectEvidence::{
package_name,
version,
repository,
license,
readme_present: true,
readme_has_usage: true,
readme_has_features: true,
ci_configured: true,
examples,
test_cases,
build_ok: true,
mooncakes_published: true,
mooncakes_version: version,
mooncakes_build_ok: true,
commit_count,
total_moonbit_lines,
effective_moonbit_lines,
has_changelog: true,
has_design_doc: true,
has_provenance_doc: true,
has_acceptance_checklist: true,
clean_tree: true,
}
}
///|
/// Evaluate one TAP report by wrapping it as a single-member suite.
pub fn readiness_from_report(
project : String,
report_name : String,
report : TapReport,
evidence : TapProjectEvidence,
) -> TapReadinessReport {
readiness_from_suite(
project,
build_suite_report(report_name, [named_report(report_name, report)]),
evidence,
)
}
///|
/// Evaluate a full suite and repository evidence for release readiness.
pub fn readiness_from_suite(
project : String,
suite : TapSuiteReport,
evidence : TapProjectEvidence,
) -> TapReadinessReport {
let policy = evaluate_suite_policy(suite, release_policy())
let checks = build_readiness_checks(suite, policy, evidence)
let score = readiness_score(checks)
let level = classify_readiness(checks, score)
TapReadinessReport::{
project,
suite,
policy,
evidence,
checks,
score,
level,
ok: level == ReadinessReady,
}
}
///|
/// Return true when the readiness report is suitable for submission.
pub fn readiness_passes(report : TapReadinessReport) -> Bool {
report.ok
}
///|
/// Return a stable label for the readiness level.
pub fn readiness_level_label(level : TapReadinessLevel) -> String {
match level {
ReadinessReady => "ready"
ReadinessNeedsWork => "needs-work"
ReadinessBlocked => "blocked"
}
}
///|
/// Return a stable label for one readiness risk.
pub fn readiness_risk_label(risk : TapReadinessRisk) -> String {
match risk {
RiskPass => "pass"
RiskNotice => "notice"
RiskWarning => "warning"
RiskBlock => "block"
}
}
///|
/// Numeric risk order for dashboards and automation.
pub fn readiness_risk_rank(risk : TapReadinessRisk) -> Int {
match risk {
RiskPass => 0
RiskNotice => 1
RiskWarning => 2
RiskBlock => 3
}
}
///|
/// Return a compact grade for a readiness score.
pub fn readiness_grade(score : Int) -> String {
if score >= 95 {
"excellent"
} else if score >= 90 {
"ready"
} else if score >= 75 {
"solid"
} else if score >= 60 {
"needs-work"
} else {
"high-risk"
}
}
///|
/// Sum earned points across checks.
pub fn readiness_earned_score(checks : Array[TapReadinessCheck]) -> Int {
let mut total = 0
for item in checks {
total += item.score
}
total
}
///|
/// Sum maximum points across checks.
pub fn readiness_max_score(checks : Array[TapReadinessCheck]) -> Int {
let mut total = 0
for item in checks {
total += item.max_score
}
total
}
///|
/// Calculate normalized 0-100 readiness score.
pub fn readiness_score(checks : Array[TapReadinessCheck]) -> Int {
let max_score = readiness_max_score(checks)
if max_score == 0 {
0
} else {
readiness_earned_score(checks) * 100 / max_score
}
}
///|
/// Return checks that passed.
pub fn passed_readiness_checks(
report : TapReadinessReport,
) -> Array[TapReadinessCheck] {
let items : Array[TapReadinessCheck] = []
for item in report.checks {
if item.passed {
items.push(item)
}
}
items
}
///|
/// Return failed checks, including optional recommendations.
pub fn failed_readiness_checks(
report : TapReadinessReport,
) -> Array[TapReadinessCheck] {
let items : Array[TapReadinessCheck] = []
for item in report.checks {
if !item.passed {
items.push(item)
}
}
items
}
///|
/// Return failed required checks.
pub fn blocking_readiness_checks(
report : TapReadinessReport,
) -> Array[TapReadinessCheck] {
let items : Array[TapReadinessCheck] = []
for item in report.checks {
if !item.passed && item.required {
items.push(item)
}
}
items
}
///|
/// Return failed optional checks.
pub fn optional_readiness_gaps(
report : TapReadinessReport,
) -> Array[TapReadinessCheck] {
let items : Array[TapReadinessCheck] = []
for item in report.checks {
if !item.passed && !item.required {
items.push(item)
}
}
items
}
///|
/// Count checks with a given risk level.
pub fn readiness_risk_count(
report : TapReadinessReport,
risk : TapReadinessRisk,
) -> Int {
let mut count = 0
for item in report.checks {
if item.risk == risk {
count += 1
}
}
count
}
///|
/// Return the highest risk present in a report.
pub fn highest_readiness_risk(report : TapReadinessReport) -> TapReadinessRisk {
let mut risk = RiskPass
for item in report.checks {
if readiness_risk_rank(item.risk) > readiness_risk_rank(risk) {
risk = item.risk
}
}
risk
}
///|
/// Return a one-line summary for terminals and release notes.
pub fn readiness_summary_line(report : TapReadinessReport) -> String {
"\{report.project}: \{readiness_level_label(report.level)} score=\{report.score} grade=\{readiness_grade(report.score)} blockers=\{blocking_readiness_checks(report).length()} warnings=\{readiness_risk_count(report, RiskWarning)}"
}
///|
/// Render a Markdown report suitable for GitHub job summaries.
pub fn readiness_to_markdown(report : TapReadinessReport) -> String {
let sb = StringBuilder()
sb.write_string("# TAPTrail Release Readiness\n\n")
sb.write_string("- project: ")
sb.write_string(report.project)
sb.write_string("\n")
sb.write_string("- level: ")
sb.write_string(readiness_level_label(report.level))
sb.write_string("\n")
sb.write_string("- score: \{report.score}\n")
sb.write_string("- grade: ")
sb.write_string(readiness_grade(report.score))
sb.write_string("\n")
sb.write_string("- suite_status: ")
sb.write_string(suite_status_label(report.suite))
sb.write_string("\n")
sb.write_string("- policy_status: ")
sb.write_string(if report.policy.ok { "ok" } else { "failed" })
sb.write_string("\n")
sb.write_string("- highest_risk: ")
sb.write_string(readiness_risk_label(highest_readiness_risk(report)))
sb.write_string("\n")
sb.write_string("\n## Evidence\n\n")
sb.write_string(readiness_evidence_markdown(report.evidence))
sb.write_string("\n## Checks\n\n")
sb.write_string(readiness_checks_to_markdown(report.checks))
let blockers = blocking_readiness_checks(report)
if blockers.length() > 0 {
sb.write_string("\n## Blocking Fixes\n\n")
sb.write_string(readiness_actions_markdown(blockers))
}
let gaps = optional_readiness_gaps(report)
if gaps.length() > 0 {
sb.write_string("\n## Optional Improvements\n\n")
sb.write_string(readiness_actions_markdown(gaps))
}
sb.to_string()
}
///|
/// Render only the evidence section as Markdown.
pub fn readiness_evidence_markdown(evidence : TapProjectEvidence) -> String {
let sb = StringBuilder()
sb.write_string("| Field | Value |\n")
sb.write_string("| --- | --- |\n")
sb.write_string("| package | ")
sb.write_string(readiness_cell(evidence.package_name))
sb.write_string(" |\n")
sb.write_string("| version | ")
sb.write_string(readiness_cell(evidence.version))
sb.write_string(" |\n")
sb.write_string("| repository | ")
sb.write_string(readiness_cell(evidence.repository))
sb.write_string(" |\n")
sb.write_string("| license | ")
sb.write_string(readiness_cell(evidence.license))
sb.write_string(" |\n")
sb.write_string("| examples | \{evidence.examples} |\n")
sb.write_string("| test_cases | \{evidence.test_cases} |\n")
sb.write_string("| total_moonbit_lines | \{evidence.total_moonbit_lines} |\n")
sb.write_string(
"| effective_moonbit_lines | \{evidence.effective_moonbit_lines} |\n",
)
sb.write_string("| commits | \{evidence.commit_count} |\n")
sb.write_string("| mooncakes | ")
sb.write_string(
if evidence.mooncakes_published {
"published"
} else {
"missing"
},
)
sb.write_string(" |\n")
sb.to_string()
}
///|
/// Render checks as a Markdown table.
pub fn readiness_checks_to_markdown(
checks : Array[TapReadinessCheck],
) -> String {
let sb = StringBuilder()
sb.write_string("| Check | Required | Status | Risk | Score | Evidence |\n")
sb.write_string("| --- | --- | --- | --- | ---: | --- |\n")
for item in checks {
sb.write_string("| `")
sb.write_string(item.id)
sb.write_string("` ")
sb.write_string(readiness_cell(item.title))
sb.write_string(" | ")
sb.write_string(if item.required { "yes" } else { "no" })
sb.write_string(" | ")
sb.write_string(if item.passed { "pass" } else { "fail" })
sb.write_string(" | ")
sb.write_string(readiness_risk_label(item.risk))
sb.write_string(" | \{item.score}/\{item.max_score} | ")
sb.write_string(readiness_cell(item.evidence))
sb.write_string(" |\n")
}
sb.to_string()
}
///|
/// Render remediation actions as Markdown bullets.
pub fn readiness_actions_markdown(checks : Array[TapReadinessCheck]) -> String {
let sb = StringBuilder()
for item in checks {
sb.write_string("- `")
sb.write_string(item.id)
sb.write_string("`: ")
sb.write_string(item.remediation)
sb.write_string("\n")
}
sb.to_string()
}
///|
/// Render a compact JSON object for dashboards.
pub fn readiness_to_json(report : TapReadinessReport) -> String {
let sb = StringBuilder()
sb.write_string("{")
sb.write_string("\"project\":\"")
sb.write_string(json_escape(report.project))
sb.write_string("\",\"level\":\"")
sb.write_string(readiness_level_label(report.level))
sb.write_string("\",\"ok\":")
sb.write_string(if report.ok { "true" } else { "false" })
sb.write_string(",\"score\":\{report.score}")
sb.write_string(",\"grade\":\"")
sb.write_string(readiness_grade(report.score))
sb.write_string("\",\"highest_risk\":\"")
sb.write_string(readiness_risk_label(highest_readiness_risk(report)))
sb.write_string(
"\",\"blockers\":\{blocking_readiness_checks(report).length()}",
)
sb.write_string(",\"warnings\":\{readiness_risk_count(report, RiskWarning)}")
sb.write_string(",\"suite_ok\":")
sb.write_string(if report.suite.ok { "true" } else { "false" })
sb.write_string(",\"policy_ok\":")
sb.write_string(if report.policy.ok { "true" } else { "false" })
sb.write_string(",\"effective_moonbit_lines\":")
sb.write_string("\{report.evidence.effective_moonbit_lines}")
sb.write_string(",\"checks\":[")
for item in report.checks; first = true {
if first {
()
} else {
sb.write_string(",")
}
sb.write_string("{\"id\":\"")
sb.write_string(json_escape(item.id))
sb.write_string("\",\"category\":\"")
sb.write_string(json_escape(item.category))
sb.write_string("\",\"required\":")
sb.write_string(if item.required { "true" } else { "false" })
sb.write_string(",\"passed\":")
sb.write_string(if item.passed { "true" } else { "false" })
sb.write_string(",\"risk\":\"")
sb.write_string(readiness_risk_label(item.risk))
sb.write_string(
"\",\"score\":\{item.score},\"max_score\":\{item.max_score}",
)
sb.write_string(",\"title\":\"")
sb.write_string(json_escape(item.title))
sb.write_string("\"}")
continue false
}
sb.write_string("]}")
sb.to_string()
}
///|
/// Render readiness fields as .properties content.
pub fn readiness_to_properties(
report : TapReadinessReport,
prefix : String,
) -> String {
let key = if prefix.length() == 0 { "taptrail" } else { prefix }
let sb = StringBuilder()
sb.write_string("\{key}.ready=\{report.ok}\n")
sb.write_string("\{key}.level=\{readiness_level_label(report.level)}\n")
sb.write_string("\{key}.score=\{report.score}\n")
sb.write_string("\{key}.grade=\{readiness_grade(report.score)}\n")
sb.write_string(
"\{key}.blockers=\{blocking_readiness_checks(report).length()}\n",
)
sb.write_string(
"\{key}.warnings=\{readiness_risk_count(report, RiskWarning)}\n",
)
sb.write_string("\{key}.checks=\{report.checks.length()}\n")
sb.write_string(
"\{key}.effective_moonbit_lines=\{report.evidence.effective_moonbit_lines}\n",
)
sb.write_string(
"\{key}.mooncakes_published=\{report.evidence.mooncakes_published}\n",
)
sb.write_string("\{key}.ci_configured=\{report.evidence.ci_configured}\n")
sb.to_string()
}
///|
/// Render readiness values as GitHub environment lines.
pub fn readiness_to_env_lines(
report : TapReadinessReport,
prefix : String,
) -> String {
let key = readiness_env_prefix(prefix)
let sb = StringBuilder()
sb.write_string("\{key}_READY=\{report.ok}\n")
sb.write_string("\{key}_LEVEL=\{readiness_level_label(report.level)}\n")
sb.write_string("\{key}_SCORE=\{report.score}\n")
sb.write_string("\{key}_GRADE=\{readiness_grade(report.score)}\n")
sb.write_string(
"\{key}_BLOCKERS=\{blocking_readiness_checks(report).length()}\n",
)
sb.write_string(
"\{key}_WARNINGS=\{readiness_risk_count(report, RiskWarning)}\n",
)
sb.write_string(
"\{key}_EFFECTIVE_MOONBIT_LINES=\{report.evidence.effective_moonbit_lines}\n",
)
sb.to_string()
}
///|
/// Render one CSV row for spreadsheet-style tracking.
pub fn readiness_to_csv(report : TapReadinessReport) -> String {
let sb = StringBuilder()
sb.write_string(
"project,level,ok,score,grade,blockers,warnings,checks,effective_moonbit_lines\n",
)
sb.write_string(csv_escape(report.project))
sb.write_string(",")
sb.write_string(readiness_level_label(report.level))
sb.write_string(",\{report.ok}")
sb.write_string(",\{report.score}")
sb.write_string(",")
sb.write_string(readiness_grade(report.score))
sb.write_string(",\{blocking_readiness_checks(report).length()}")
sb.write_string(",\{readiness_risk_count(report, RiskWarning)}")
sb.write_string(",\{report.checks.length()}")
sb.write_string(",\{report.evidence.effective_moonbit_lines}\n")
sb.to_string()
}
///|
/// Render a checkbox list for manual release review.
pub fn readiness_to_checklist(report : TapReadinessReport) -> String {
let sb = StringBuilder()
sb.write_string("# Acceptance Checklist\n\n")
for item in report.checks {
sb.write_string("- [")
sb.write_string(if item.passed { "x" } else { " " })
sb.write_string("] ")
sb.write_string(item.title)
sb.write_string(" (`")
sb.write_string(item.id)
sb.write_string("`, ")
sb.write_string(readiness_risk_label(item.risk))
sb.write_string(")\n")
}
sb.to_string()
}
///|
/// Render a short release note sentence.
pub fn readiness_release_note(report : TapReadinessReport) -> String {
let blockers = blocking_readiness_checks(report).length()
let warnings = readiness_risk_count(report, RiskWarning)
let sb = StringBuilder()
sb.write_string("TapTrail readiness is ")
sb.write_string(readiness_level_label(report.level))
sb.write_string(" with score \{report.score}/100")
sb.write_string(
" and \{report.evidence.effective_moonbit_lines} effective MoonBit lines.",
)
if blockers > 0 {
sb.write_string(" Blocking checks: \{blockers}.")
}
if warnings > 0 {
sb.write_string(" Optional warnings: \{warnings}.")
}
sb.to_string()
}
///|
/// Render a Markdown badge for README or release dashboards.
pub fn readiness_badge_markdown(
report : TapReadinessReport,
target_url : String,
) -> String {
let message = readiness_level_label(report.level)
let color = if report.level == ReadinessReady {
"brightgreen"
} else if report.level == ReadinessNeedsWork {
"yellow"
} else {
"red"
}
let url = "https://img.shields.io/badge/taptrail%20readiness-\{url_component(message)}-\{color}"
if target_url.length() == 0 {
""
} else {
"[](\{target_url})"
}
}
///|
/// Return concise human-readable recommendations.
pub fn readiness_recommendations(report : TapReadinessReport) -> Array[String] {
let items : Array[String] = []
if report.ok {
items.push(
"Keep CI, mooncakes.io publication, examples, and test evidence synchronized with the submitted commit.",
)
} else {
for check in failed_readiness_checks(report) {
items.push("\{check.title}: \{check.remediation}")
}
}
items
}
///|
/// Return true when a package name looks publishable to mooncakes.io.
pub fn package_name_has_namespace(package_name : String) -> Bool {
match package_name.find("/") {
Some(index) => index > 0 && index + 1 < package_name.length()
None => false
}
}
///|
/// Return true when a repository URL is present and public-looking.
pub fn repository_link_present(repository : String) -> Bool {
repository.has_prefix("https://github.com/") ||
repository.has_prefix("http://github.com/") ||
repository.has_prefix("https://gitlink.org.cn/") ||
repository.has_prefix("http://gitlink.org.cn/")
}
///|
/// Return true when supplied evidence has a recognized open-source license.
pub fn license_is_recognized(license : String) -> Bool {
license == "MIT" ||
license == "Apache-2.0" ||
license == "BSD-2-Clause" ||
license == "BSD-3-Clause" ||
license == "MPL-2.0" ||
license == "ISC" ||
license == "LGPL-2.1-or-later" ||
license == "LGPL-3.0-or-later"
}
///|
/// Return true when the code scale is close to the contest reference range.
pub fn code_scale_matches_reference(evidence : TapProjectEvidence) -> Bool {
evidence.effective_moonbit_lines >= 4000 &&
evidence.effective_moonbit_lines <= 10000
}
///|
/// Return true when source scale is meaningful even if still below reference.
pub fn code_scale_is_meaningful(evidence : TapProjectEvidence) -> Bool {
evidence.effective_moonbit_lines >= 2000 &&
evidence.total_moonbit_lines >= evidence.effective_moonbit_lines
}
///|
fn build_readiness_checks(
suite : TapSuiteReport,
policy : TapPolicyResult,
evidence : TapProjectEvidence,
) -> Array[TapReadinessCheck] {
let checks : Array[TapReadinessCheck] = []
checks.push(
readiness_check(
"moonbit-project",
"project",
"MoonBit package metadata",
true,
package_name_has_namespace(evidence.package_name) &&
evidence.version.length() > 0,
8,
"package=\{evidence.package_name}, version=\{evidence.version}",
"Set `moon.mod` name to `owner/package` and keep a non-empty version.",
),
)
checks.push(
readiness_check(
"public-repository",
"submission",
"Public repository link",
true,
repository_link_present(evidence.repository),
7,
evidence.repository,
"Use a public GitHub or Gitlink URL in repository metadata and submission form.",
),
)
checks.push(
readiness_check(
"readme-complete",
"documentation",
"README explains purpose, features, and usage",
true,
evidence.readme_present &&
evidence.readme_has_usage &&
evidence.readme_has_features,
9,
"present=\{evidence.readme_present}, usage=\{evidence.readme_has_usage}, features=\{evidence.readme_has_features}",
"Keep README purpose, feature list, install/run commands, examples, and status links complete.",
),
)
checks.push(
readiness_check(
"ci-configured",
"automation",
"Continuous integration configured",
true,
evidence.ci_configured,
8,
"ci_configured=\{evidence.ci_configured}",
"Add a CI workflow that runs format, check, build, info, tests, and examples.",
),
)
checks.push(
readiness_check(
"local-build",
"verification",
"Local build and standard checks pass",
true,
evidence.build_ok,
8,
"build_ok=\{evidence.build_ok}",
"Run `moon check`, `moon build`, and `moon test` before submitting.",
),
)
checks.push(
readiness_check(
"tap-suite-release-policy",
"verification",
"TAP suite passes release policy",
true,
suite.ok && policy.ok,
11,
"suite_ok=\{suite.ok}, policy_ok=\{policy.ok}, reports=\{suite.summary.suites}",
"Fix failing TAP reports or release-policy errors before tagging the release.",
),
)
checks.push(
readiness_check(
"runnable-examples",
"usability",
"Runnable examples are present",
true,
evidence.examples >= 1,
7,
"examples=\{evidence.examples}",
"Provide at least one `moon run` example and document the command.",
),
)
checks.push(
readiness_check(
"tests-present",
"verification",
"Tests are present and runnable",
true,
evidence.test_cases >= 1,
7,
"test_cases=\{evidence.test_cases}",
"Add unit or white-box tests for parser, policy, renderers, and edge cases.",
),
)
checks.push(
readiness_check(
"mooncakes-published",
"release",
"Package published to mooncakes.io",
true,
evidence.mooncakes_published &&
evidence.mooncakes_build_ok &&
evidence.mooncakes_version == evidence.version,
10,
"published=\{evidence.mooncakes_published}, version=\{evidence.mooncakes_version}, build=\{evidence.mooncakes_build_ok}",
"Publish the current version to mooncakes.io and wait for successful package build.",
),
)
checks.push(
readiness_check(
"license-clear",
"license",
"Open-source license is clear",
true,
license_is_recognized(evidence.license),
6,
"license=\{evidence.license}",
"Keep a root LICENSE file and matching SPDX-like license value in `moon.mod`.",
),
)
checks.push(
readiness_check(
"meaningful-code-scale",
"implementation",
"MoonBit implementation is substantial",
true,
code_scale_is_meaningful(evidence),
7,
"effective=\{evidence.effective_moonbit_lines}, total=\{evidence.total_moonbit_lines}",
"Keep the main implementation in MoonBit and avoid template-only or demo-only scope.",
),
)
checks.push(
readiness_check(
"contest-scale-reference",
"implementation",
"Effective MoonBit lines meet contest scale reference",
false,
code_scale_matches_reference(evidence),
5,
"effective=\{evidence.effective_moonbit_lines}",
"Aim for 4k-10k effective MoonBit lines through real features, tests, and examples.",
),
)
checks.push(
readiness_check(
"history-trackable",
"process",
"Development history is trackable",
true,
evidence.commit_count >= 5,
5,
"commits=\{evidence.commit_count}",
"Keep meaningful commits that show development progress during the contest period.",
),
)
checks.push(
readiness_check(
"maintenance-docs",
"maintenance",
"Maintenance documents are present",
false,
evidence.has_changelog &&
evidence.has_design_doc &&
evidence.has_acceptance_checklist,
4,
"changelog=\{evidence.has_changelog}, design=\{evidence.has_design_doc}, checklist=\{evidence.has_acceptance_checklist}",
"Maintain CHANGELOG, design notes, and acceptance checklist for future maintainers.",
),
)
checks.push(
readiness_check(
"provenance-documented",
"license",
"Third-party provenance is documented",
false,
evidence.has_provenance_doc,
4,
"provenance_doc=\{evidence.has_provenance_doc}",
"Document dependencies, generated material, fixtures, and license provenance.",
),
)
checks.push(
readiness_check(
"clean-working-tree",
"release",
"Repository is clean before push",
false,
evidence.clean_tree,
4,
"clean_tree=\{evidence.clean_tree}",
"Remove generated artifacts and commit intended files before publishing.",
),
)
checks
}
///|
fn readiness_check(
id : String,
category : String,
title : String,
required : Bool,
passed : Bool,
max_score : Int,
evidence : String,
remediation : String,
) -> TapReadinessCheck {
let risk = if passed {
RiskPass
} else if required {
RiskBlock
} else if max_score >= 5 {
RiskWarning
} else {
RiskNotice
}
TapReadinessCheck::{
id,
category,
title,
required,
passed,
score: if passed {
max_score
} else {
0
},
max_score,
risk,
evidence,
remediation,
}
}
///|
fn classify_readiness(
checks : Array[TapReadinessCheck],
score : Int,
) -> TapReadinessLevel {
for item in checks {
if item.required && !item.passed {
return ReadinessBlocked
}
}
if score >= 90 {
ReadinessReady
} else {
ReadinessNeedsWork
}
}
///|
fn readiness_env_prefix(prefix : String) -> String {
let raw = if prefix.length() == 0 { "TAPTRAIL" } else { prefix }
let sb = StringBuilder()
for ch in raw {
let code = ch.to_int()
if code >= 97 && code <= 122 {
sb.write_char(Int::unsafe_to_char(code - 32))
} else if code >= 65 && code <= 90 {
sb.write_char(ch)
} else if code >= 48 && code <= 57 {
sb.write_char(ch)
} else {
sb.write_string("_")
}
}
sb.to_string()
}
///|
fn readiness_cell(text : String) -> String {
let sb = StringBuilder()
for ch in text {
match ch {
'|' => sb.write_string("\\|")
'\n' => sb.write_string("
")
'\r' => ()
_ => sb.write_char(ch)
}
}
sb.to_string()
}