///|
pub(all) enum AcceptanceGate {
CompletedWorkspace
ExternalDataReview
StageRetryPause
RoutineCancellation
AppToolContract
PromptSkillMigration
ImportTraceability
ParityReadiness
OperatorHandoffReadiness
DecommissionArchiveReadiness
SafetyAndRedaction
ModelDiscovery
ProviderFailureHandling
RecordIntegrity
MoondeskAppSmoke
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) enum AcceptanceStatus {
Pass
NeedsWork
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) struct AcceptanceFinding {
gate : AcceptanceGate
status : AcceptanceStatus
evidence_path : String
message : String
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) struct AcceptanceFixtureSet {
completed_workspace : @workspace.AnalysisWorkspace
awaiting_workspace : @workspace.AnalysisWorkspace
retry_result : @orchestration.TwoStageRoutineResult
cancelled_result : @orchestration.TwoStageRoutineResult
cancellation_report : @cancellation.CancellationReport
provider_failure_report : @resilience.ProviderFailureReport
record_integrity_report : @integrity.RecordIntegrityReport
app_smoke_report : @appsmoke.MoondeskAppSmokeReport
import_plan : @migration.LegacyImportPlan
import_projection : @migration.LegacyImportProjection
skill_migration_plan : @skills.SkillMigrationPlan
parity_report : @parity.ParityReport
comparison_report : @comparison.CutoverComparisonReport
readiness_report : @evaluation.CutoverReadinessReport
cutover_plan : @cutover.CutoverPlan
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) struct AcceptanceReport {
passed : Bool
pass_count : Int
needs_work_count : Int
findings : Array[AcceptanceFinding]
summary : String
} derive(Debug, Eq, ToJson, FromJson)
///|
fn base_suite_status() -> @model.SuiteStatusRef {
@model.suite_status_ref(
@model.moonsuite_suite_status_path(),
"fixture://model/v1",
"fixture-model",
catalog=[
@model.model_catalog_entry(
"fixture-model",
owner="moongate",
context_window=128000,
),
],
)
}
///|
fn fixture_diagnosis(confidence? : Int = 72) -> @domain.Stage1Diagnosis {
@domain.stage1_diagnosis(
TightChannel,
Bullish,
confidence,
Stable,
[AlwaysIn, H2],
key_signals=["three closed bull bars", "second-entry continuation"],
)
}
///|
fn fixture_decision(confidence? : Int = 64) -> @domain.Stage2Decision {
@domain.stage2_decision(
Wait,
confidence,
"fixture acceptance run; no executable order path exists",
)
}
///|
fn workspace_fixture(
run_id : @domain.RunId,
source : @domain.DataSource,
) -> @workspace.AnalysisWorkspace {
@workspace.prepare_analysis_workspace(
@workspace.analysis_workspace_input(
run_id,
"acceptance fixture",
source,
"BTCUSDT",
"15m",
base_suite_status(),
fixture_diagnosis(),
fixture_decision(),
limit=20,
captured_at_ms=0L,
),
)
}
///|
fn routine_fixture_request(run_id : @domain.RunId) -> @routine.RoutineRequest {
let workspace = workspace_fixture(run_id, Fixture)
match workspace.bundle.market_fetch.snapshot {
Some(snapshot) =>
@routine.routine_request(run_id, "acceptance fixture", snapshot)
None =>
@routine.routine_request(
run_id,
"acceptance fixture",
@domain.kline_snapshot(
"fixture:BTCUSDT:15m:1",
Fixture,
"BTCUSDT",
"15m",
0L,
[@domain.kline_bar(0, 100.0, 102.0, 99.0, 101.0)],
),
)
}
}
///|
fn live_snapshot_fixture() -> @domain.KlineSnapshot {
let bars : Array[@domain.KlineBar] = []
for index in 0..<20 {
let base = 100.0 + index.to_double()
bars.push(
@domain.kline_bar(
index,
base,
base + 2.0,
base - 1.0,
base + 1.0,
volume=1000.0 + index.to_double(),
closed=true,
),
)
}
@domain.kline_snapshot(
"tradingview:BTCUSDT:15m:20",
TradingView,
"BTCUSDT",
"15m",
0L,
bars,
)
}
///|
fn live_rehearsal_bundle() -> @workflow.AnalysisRunBundle {
@workflow.run_analysis_bundle_with_snapshot(
@workflow.analysis_run_request(
"acceptance-live",
"acceptance live snapshot rehearsal",
@data.market_source_request(TradingView, "BTCUSDT", "15m", limit=20),
base_suite_status().to_gateway(),
fixture_diagnosis(),
fixture_decision(),
),
live_snapshot_fixture(),
)
}
///|
fn import_plan_fixture() -> @migration.LegacyImportPlan {
@migration.prepare_legacy_import_plan(
@migration.legacy_import_batch_input("acceptance-import", "../paa", [
@migration.legacy_source_ref(
"records/pending/acceptance.json",
LegacyPendingRecord,
"acceptance-pending",
target_run_id="acceptance-legacy-run",
),
@migration.legacy_source_ref(
"experience/tight_channel/acceptance.json",
LegacyExperienceEntry,
"acceptance-experience",
),
@migration.legacy_source_ref(
"trade_records/acceptance.json",
LegacyTradeLog,
"acceptance-trade-log",
),
]),
)
}
///|
pub fn acceptance_fixture_set() -> AcceptanceFixtureSet {
let completed_workspace = workspace_fixture("acceptance-completed", Fixture)
let awaiting_workspace = workspace_fixture("acceptance-awaiting", TradingView)
let retry_result = @orchestration.run_two_stage_routine(
@orchestration.two_stage_routine_input(
routine_fixture_request("acceptance-retry"),
@model.fixture_gateway(),
fixture_diagnosis(confidence=120),
fixture_decision(),
),
)
let cancelled_result = @orchestration.run_two_stage_routine(
@orchestration.two_stage_routine_input(
routine_fixture_request("acceptance-cancel"),
@model.fixture_gateway(),
fixture_diagnosis(),
fixture_decision(),
cancel_after_phase=Stage1Validation,
),
)
let cancellation_report = @cancellation.prepare_cancellation_report(
cancelled_result,
)
let provider_failure_result = @orchestration.run_two_stage_routine(
@orchestration.two_stage_routine_input(
routine_fixture_request("acceptance-provider-failure"),
@model.moongate_gateway(
"http://127.0.0.1:15721/v1",
"offline-model",
health=Unavailable,
),
fixture_diagnosis(),
fixture_decision(),
),
)
let provider_failure_report = @resilience.prepare_provider_failure_report(
@resilience.provider_failure_input(
provider_failure_result,
@model.normalize_provider_error("gateway timeout", status_code=503),
),
)
let record_integrity_report = @integrity.prepare_record_integrity_report(
completed_workspace.bundle,
)
let app_smoke_report = @appsmoke.prepare_moondesk_app_smoke_report(
@appsmoke.moondesk_app_smoke_input(completed_workspace, awaiting_workspace),
)
let import_plan = import_plan_fixture()
let import_projection = @migration.materialize_legacy_import_projection(
import_plan,
)
let skill_migration_plan = @skills.prepare_skill_migration_plan()
let parity_report = @parity.prepare_parity_report(
@parity.parity_report_input(completed_workspace, import_plan),
)
let comparison_report = @comparison.prepare_cutover_comparison_report(
@comparison.cutover_comparison_input(
parity_report,
completed_workspace,
live_rehearsal_bundle(),
),
)
let readiness_report = @evaluation.prepare_cutover_readiness_report(
@evaluation.cutover_evaluation_input(
completed_workspace,
import_plan,
parity_report,
comparison_report,
skill_migration_plan~,
manifest=@pack.price_action_manifest(),
),
)
let cutover_plan = @cutover.prepare_cutover_plan(
@cutover.cutover_plan_input(readiness_report, import_plan),
)
{
completed_workspace,
awaiting_workspace,
retry_result,
cancelled_result,
cancellation_report,
provider_failure_report,
record_integrity_report,
app_smoke_report,
import_plan,
import_projection,
skill_migration_plan,
parity_report,
comparison_report,
readiness_report,
cutover_plan,
}
}
///|
fn finding(
gate : AcceptanceGate,
status : AcceptanceStatus,
evidence_path : String,
message : String,
) -> AcceptanceFinding {
{ gate, status, evidence_path, message }
}
///|
fn completed_workspace_finding(
fixtures : AcceptanceFixtureSet,
) -> AcceptanceFinding {
let workspace = fixtures.completed_workspace
let routine_completed = match workspace.routine_result {
Some(result) => result.outcome is Completed
None => false
}
if workspace.bundle.status is Completed &&
workspace.job_state.outcome is Completed &&
routine_completed &&
workspace.book_artifact_count > 0 &&
workspace.chart_candle_count > 0 {
finding(
CompletedWorkspace,
Pass,
"analysis-workspace",
"fixture workspace completes with routine result, chart candles, and MoonBook artifacts",
)
} else {
finding(
CompletedWorkspace,
NeedsWork,
"analysis-workspace",
"completed fixture does not prove the full analysis path",
)
}
}
///|
fn external_data_finding(fixtures : AcceptanceFixtureSet) -> AcceptanceFinding {
let workspace = fixtures.awaiting_workspace
if workspace.bundle.status is AwaitingMarketData &&
workspace.job_state.blocking_review_count > 0 &&
workspace.routine_result is None &&
workspace.app_tool_manifest.surfaces.any(fn(surface) {
surface.id == "configure-data-source"
}) &&
workspace.app_tool_manifest.surfaces.any(fn(surface) {
surface.id == "submit-market-snapshot"
}) &&
workspace.app_tool_manifest.bindings.any(fn(binding) {
binding.id == "market-ingest" &&
binding.schema_id == "market-ingest-input"
}) {
finding(
ExternalDataReview,
Pass,
"analysis-workspace.awaiting",
"external data runs block on review and expose data-source configuration plus snapshot ingest",
)
} else {
finding(
ExternalDataReview,
NeedsWork,
"analysis-workspace.awaiting",
"external data runs do not surface the expected blocking review path",
)
}
}
///|
fn retry_finding(fixtures : AcceptanceFixtureSet) -> AcceptanceFinding {
let result = fixtures.retry_result
if result.outcome is AwaitingStage1Retry &&
result.failure_kind is Some(Stage1Invalid) &&
result.partial_record_available &&
result.stage_gates.any(fn(gate) { gate.retry_decision.should_retry }) {
finding(
StageRetryPause,
Pass,
"orchestration.retry",
"invalid Stage 1 output pauses for bounded retry with partial evidence",
)
} else {
finding(
StageRetryPause,
NeedsWork,
"orchestration.retry",
"Stage 1 validation failure does not produce the expected retry pause",
)
}
}
///|
fn cancellation_finding(fixtures : AcceptanceFixtureSet) -> AcceptanceFinding {
let report = fixtures.cancellation_report
if report.ready &&
report.cancel_phase is Some(Stage1Validation) &&
report.findings.any(fn(finding) {
finding.check is PartialRecordPersisted && finding.status is Pass
}) &&
report.findings.any(fn(finding) {
finding.check is StageBoundaryPreserved && finding.status is Pass
}) {
finding(
RoutineCancellation,
Pass,
"cancellation-report",
"operator cancellation after Stage 1 has a reusable partial-record proof",
)
} else {
finding(
RoutineCancellation,
NeedsWork,
"cancellation-report",
"cancellation report does not prove the expected partial record boundary",
)
}
}
///|
fn app_tool_finding(fixtures : AcceptanceFixtureSet) -> AcceptanceFinding {
let manifest = fixtures.completed_workspace.app_tool_manifest
if manifest.controls.length() >= 6 &&
manifest.required_tools.contains("run_two_stage_routine") &&
manifest.required_tools.contains("prepare_market_refresh_plan") &&
manifest.required_tools.contains("ingest_market_snapshot") &&
manifest.required_tools.contains("select_experience_memories") &&
manifest.required_tools.contains("evaluate_decision_policy") &&
manifest.required_tools.contains("prepare_followup_session_plan") &&
manifest.required_tools.contains("prepare_followup_response") &&
manifest.bindings.any(fn(binding) {
binding.id == "market-refresh" &&
binding.schema_id == "market-refresh-plan"
}) &&
manifest.bindings.any(fn(binding) {
binding.id == "raw-model-exchange" && binding.redacted
}) &&
manifest.bindings.any(fn(binding) {
binding.id == "experience-memory" &&
binding.schema_id == "experience-memory-selection"
}) &&
manifest.bindings.any(fn(binding) {
binding.id == "decision-policy" &&
binding.schema_id == "decision-policy-report"
}) &&
manifest.surfaces.any(fn(surface) { surface.id == "prompt-debug-panel" }) {
finding(
AppToolContract,
Pass,
"moondesk-app-tool-manifest",
"Moondesk app-tool exposes controls, refresh readiness, data ingest, debug panes, memory selection, decision policy, follow-up session plans and responses, required tools, and redacted bindings",
)
} else {
finding(
AppToolContract,
NeedsWork,
"moondesk-app-tool-manifest",
"Moondesk app-tool manifest is missing a required operator contract",
)
}
}
///|
fn skill_migration_finding(
fixtures : AcceptanceFixtureSet,
) -> AcceptanceFinding {
let plan = fixtures.skill_migration_plan
if plan.source_count == 32 &&
plan.mapped_count == plan.source_count &&
plan.review_count == 0 &&
plan.catalog.assets.length() > 0 &&
plan.sources.any(fn(source) {
source.target_book_path == "skills/market-diagnosis/core.md"
}) &&
plan.sources.any(fn(source) {
source.target_book_path == "wiki/strategy-notes/major-trend-reversal.md"
}) {
finding(
PromptSkillMigration,
Pass,
"skill-migration-plan",
"PA prompt sources map into MoonBook skills, strategy notes, and concept references",
)
} else {
finding(
PromptSkillMigration,
NeedsWork,
"skill-migration-plan",
"PA prompt source migration is incomplete or under review",
)
}
}
///|
fn import_finding(fixtures : AcceptanceFixtureSet) -> AcceptanceFinding {
let plan = fixtures.import_plan
let projection = fixtures.import_projection
if plan.ready_count == 3 &&
plan.review_count == 0 &&
plan.skipped_count == 0 &&
plan.write_plan.artifacts.length() == 4 &&
projection.record_count == 3 &&
projection.review_count == 0 &&
projection.records.all(fn(record) {
record.source_path.contains("../paa/") &&
record.replay_anchor_path.contains(record.trace_id)
}) {
finding(
ImportTraceability,
Pass,
"legacy-import-plan",
"analysis, experience, and trade-log sources map to inspectable MoonBook records with replay anchors",
)
} else {
finding(
ImportTraceability,
NeedsWork,
"legacy-import-plan",
"legacy import fixture does not preserve expected inspectable traceability",
)
}
}
///|
fn parity_readiness_finding(
fixtures : AcceptanceFixtureSet,
) -> AcceptanceFinding {
if fixtures.parity_report.review_count == 0 &&
fixtures.parity_report.untraced_case_count == 0 &&
fixtures.parity_report.fixture_case_count ==
fixtures.parity_report.cases.length() &&
fixtures.comparison_report.ready &&
fixtures.readiness_report.ready {
finding(
ParityReadiness,
Pass,
"parity-report",
"parity report has traced PA Agent fixtures and cutover readiness passes",
)
} else {
finding(
ParityReadiness,
NeedsWork,
"parity-report",
"parity, fixture traceability, or readiness has a remaining review gate",
)
}
}
///|
fn operator_handoff_finding(
fixtures : AcceptanceFixtureSet,
) -> AcceptanceFinding {
let manifest = fixtures.completed_workspace.app_tool_manifest
let workflow_ready = manifest.id == "moondesk-price-action" &&
manifest.mount_path == "apps/moondesk-price-action" &&
manifest.surfaces.any(fn(surface) {
surface.id == "run-analysis" && surface.enabled
}) &&
manifest.surfaces.any(fn(surface) {
surface.id == "start-follow-up" && surface.enabled
}) &&
manifest.surfaces.any(fn(surface) {
surface.id == "replay-run" && surface.enabled
}) &&
manifest.surfaces.any(fn(surface) {
surface.id == "export-run" && surface.enabled
}) &&
manifest.required_tools.contains("run_two_stage_routine") &&
manifest.required_tools.contains("ingest_market_snapshot") &&
manifest.redacted_binding_count >= 3
if fixtures.readiness_report.ready &&
fixtures.comparison_report.ready &&
fixtures.cutover_plan.ready_to_cutover &&
workflow_ready {
finding(
OperatorHandoffReadiness,
Pass,
"operator-handoff-report",
"acceptance evidence proves the Moondesk launch path, workflow surfaces, comparison report, and cutover plan",
)
} else {
finding(
OperatorHandoffReadiness,
NeedsWork,
"operator-handoff-report",
"operator handoff evidence is incomplete",
)
}
}
///|
fn decommission_archive_finding(
fixtures : AcceptanceFixtureSet,
) -> AcceptanceFinding {
let cutover = fixtures.cutover_plan
let parity = fixtures.parity_report
let comparison = fixtures.comparison_report
let projection = fixtures.import_projection
let import_ready = projection.record_count > 0 &&
projection.review_count == 0 &&
projection.records.all(fn(record) {
record.source_path.contains("../paa/") &&
record.replay_anchor_path.contains(record.trace_id)
})
let known_difference_ready = parity.intentional_difference_count > 0 &&
parity.untraced_case_count == 0 &&
parity.cases.any(fn(item) {
item.expectation is IntentionalDifference &&
item.evidence_refs.any(fn(ref_item) {
ref_item.kind is KnownDifferenceNote
})
})
let rollback_ready = cutover.rollback_days >= 1 &&
cutover.rollback_plan.any(fn(step) {
step.kind is MonitorRollbackWindow && step.path == "../paa"
}) &&
comparison.cases.any(fn(item) {
item.kind is LegacyReadOnlyRollback && item.status is ComparisonPass
})
if cutover.ready_to_cutover &&
import_ready &&
known_difference_ready &&
rollback_ready {
finding(
DecommissionArchiveReadiness,
Pass,
"decommission-report",
"acceptance evidence proves imported records, known differences, read-only rollback, and archive readiness",
)
} else {
finding(
DecommissionArchiveReadiness,
NeedsWork,
"decommission-report",
"decommission archive evidence is incomplete",
)
}
}
///|
fn safety_finding(fixtures : AcceptanceFixtureSet) -> AcceptanceFinding {
let workspace = fixtures.completed_workspace
if workspace.safety_report.ok &&
workspace.app_tool_manifest.redacted_binding_count >= 3 &&
workspace.safety_report.findings.any(fn(finding) {
finding.kind is DecisionPolicyBoundary && finding.status is Pass
}) &&
!workspace.replay_plan.live_market_required {
finding(
SafetyAndRedaction,
Pass,
"safety-report",
"safety, decision policy, public export redaction, app debug redaction, and replay evidence checks pass",
)
} else {
finding(
SafetyAndRedaction,
NeedsWork,
"safety-report",
"safety or redaction acceptance evidence is incomplete",
)
}
}
///|
fn model_discovery_finding(
fixtures : AcceptanceFixtureSet,
) -> AcceptanceFinding {
let gateway = fixtures.completed_workspace.plan.gateway
if gateway.default_model != "" &&
gateway.openai_base_url != "" &&
!gateway.usage.quota_exhausted &&
gateway.contracts.all(fn(contract) { contract.ready }) {
finding(
ModelDiscovery,
Pass,
"suite-status-ref",
"MoonGate model gateway includes base URL, model, quota state, and ready integration contracts",
)
} else {
finding(
ModelDiscovery,
NeedsWork,
"suite-status-ref",
"MoonGate model discovery evidence is incomplete or unavailable",
)
}
}
///|
fn provider_failure_finding(
fixtures : AcceptanceFixtureSet,
) -> AcceptanceFinding {
let report = fixtures.provider_failure_report
if report.ready &&
report.error_kind is ProviderUnavailable &&
report.retryable &&
report.findings.any(fn(finding) {
finding.check is PartialRecordPreserved && finding.status is Pass
}) {
finding(
ProviderFailureHandling,
Pass,
"provider-failure-report",
"provider timeout normalizes to retryable unavailable and preserves partial run evidence",
)
} else {
finding(
ProviderFailureHandling,
NeedsWork,
"provider-failure-report",
"provider failure handling does not prove normalized retryable partial evidence",
)
}
}
///|
fn record_integrity_finding(
fixtures : AcceptanceFixtureSet,
) -> AcceptanceFinding {
let report = fixtures.record_integrity_report
if report.ready &&
report.artifact_count > 0 &&
report.findings.any(fn(finding) {
finding.check is AnalysisRecordSelfContained && finding.status is Pass
}) &&
report.findings.any(fn(finding) {
finding.check is ReplayAnchorsRecord && finding.status is Pass
}) {
finding(
RecordIntegrity,
Pass,
"record-integrity-report",
"MoonBook analysis record is self-contained, committed, replayable, and exportable",
)
} else {
finding(
RecordIntegrity,
NeedsWork,
"record-integrity-report",
"MoonBook record integrity evidence is incomplete",
)
}
}
///|
fn app_smoke_finding(fixtures : AcceptanceFixtureSet) -> AcceptanceFinding {
let report = fixtures.app_smoke_report
if report.ready &&
report.findings.any(fn(finding) {
finding.check is CompletedOperatorWorkflow && finding.status is Pass
}) &&
report.findings.any(fn(finding) {
finding.check is ExternalSnapshotIngest && finding.status is Pass
}) &&
report.findings.any(fn(finding) {
finding.check is MoonBookBackedState && finding.status is Pass
}) &&
report.findings.any(fn(finding) {
finding.check is RedactedDebugEvidence && finding.status is Pass
}) {
finding(
MoondeskAppSmoke,
Pass,
"moondesk-app-smoke-report",
"Moondesk app-tool smoke proves completed, external ingest, redacted debug, and MoonBook-backed operator paths",
)
} else {
finding(
MoondeskAppSmoke,
NeedsWork,
"moondesk-app-smoke-report",
"Moondesk app-tool smoke evidence is incomplete",
)
}
}
///|
fn count_status(
findings : Array[AcceptanceFinding],
status : AcceptanceStatus,
) -> Int {
findings.fold(init=0, fn(count, item) {
if item.status == status {
count + 1
} else {
count
}
})
}
///|
pub fn prepare_acceptance_report(
fixtures? : AcceptanceFixtureSet = acceptance_fixture_set(),
) -> AcceptanceReport {
let findings = [
completed_workspace_finding(fixtures),
external_data_finding(fixtures),
retry_finding(fixtures),
cancellation_finding(fixtures),
app_tool_finding(fixtures),
skill_migration_finding(fixtures),
import_finding(fixtures),
parity_readiness_finding(fixtures),
operator_handoff_finding(fixtures),
decommission_archive_finding(fixtures),
safety_finding(fixtures),
model_discovery_finding(fixtures),
provider_failure_finding(fixtures),
record_integrity_finding(fixtures),
app_smoke_finding(fixtures),
]
let needs_work_count = count_status(findings, NeedsWork)
let pass_count = count_status(findings, Pass)
let passed = needs_work_count == 0
{
passed,
pass_count,
needs_work_count,
findings,
summary: if passed {
"acceptance passed \{pass_count}/\{findings.length()} gates"
} else {
"acceptance has \{needs_work_count} gate(s) needing work"
},
}
}