Coverage Summary for Class: InboxGenerationResult (core.pipeline)
| Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| InboxGenerationResult |
100%
(1/1)
|
33.3%
(1/3)
|
0%
(0/10)
|
30.8%
(4/13)
|
25%
(17/68)
|
// FILE: core/src/main/kotlin/core/pipeline/InboxLifecycle.kt
package core.pipeline
import core.BalanceSettings
import core.calculateThreatLevel
import core.calculateBaseDifficulty
import core.flavour.ContractPricing
import core.primitives.ContractId
import core.primitives.Rank
import core.primitives.SalvagePolicy
import core.rng.Rng
import core.state.ContractDraft
/**
* Inbox lifecycle model.
*
* ## Semantic Ownership
* Answers: **What contracts should be generated?**
*
* ## Stability Gradient
* STABLE: Pure generation logic with explicit rules.
*
* ## Determinism
* - RNG usage is explicit and ordered.
*
* ## Boundary Rules
* - Must NOT emit events.
* - Must NOT mutate state directly.
*/
object InboxLifecycle {
/**
* Generates new inbox drafts for the day.
*
* ## Money units
* - `feeOffered` is stored in **copper** (Int).
* - `clientDeposit` is stored in **copper** (Int).
* - Values are produced via [ContractPricing.samplePayoutMoney] /
* [ContractPricing.sampleClientDepositMoney].
*
* @param count Number of drafts to generate.
* @param currentDay Current day index.
* @param stability Current region stability.
* @param startingContractId Starting ID for new contracts.
* @param rng Deterministic RNG.
* @return [InboxGenerationResult] with generated drafts and next ID.
*/
fun generateDrafts(
count: Int,
currentDay: Int,
stability: Int,
startingContractId: Int,
rng: Rng
): InboxGenerationResult {
val drafts = ArrayList<ContractDraft>(count)
val contractIds = IntArray(count)
var nextId = startingContractId
for (i in 0 until count) {
val draftId = nextId++
contractIds[i] = draftId
val threatLevel = calculateThreatLevel(stability)
val baseDifficulty = calculateBaseDifficulty(threatLevel, rng)
// Sample payout and client deposit using rank-based pricing (FP-ECON-02)
val payout = ContractPricing.samplePayoutMoney(Rank.F, rng)
val clientDeposit = ContractPricing.sampleClientDepositMoney(payout, rng)
drafts.add(
ContractDraft(
id = ContractId(draftId),
createdDay = currentDay,
nextAutoResolveDay = currentDay + BalanceSettings.AUTO_RESOLVE_INTERVAL_DAYS,
title = "Request #$draftId",
rankSuggested = Rank.F,
feeOffered = payout.copper, // Now using sampled payout in copper!
salvage = SalvagePolicy.GUILD,
baseDifficulty = baseDifficulty,
proofHint = "proof",
clientDeposit = clientDeposit.copper
)
)
}
return InboxGenerationResult(
drafts = drafts,
contractIds = contractIds,
nextContractId = nextId
)
}
}
/**
* Result of inbox generation.
*
* @property drafts Generated drafts.
* @property contractIds Raw integer IDs generated for the drafts (same order as [drafts]).
* @property nextContractId Next available contract ID after generation.
*/
data class InboxGenerationResult(
val drafts: List<ContractDraft>,
val contractIds: IntArray,
val nextContractId: Int
) {
/**
* Value equality that compares [contractIds] by content.
*
* @param other Object to compare.
*/
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is InboxGenerationResult) return false
return drafts == other.drafts &&
contractIds.contentEquals(other.contractIds) &&
nextContractId == other.nextContractId
}
/** Hash code that uses [IntArray.contentHashCode]. */
override fun hashCode(): Int {
var result = drafts.hashCode()
result = 31 * result + contractIds.contentHashCode()
result = 31 * result + nextContractId
return result
}
}