Initial commit: Add project files
ci / backend (push) Failing after 12s
ci / frontend (push) Failing after 19s
ci / static (push) Failing after 45s

This commit is contained in:
2026-08-02 05:15:36 +09:00
commit dcd1322d41
636 changed files with 122352 additions and 0 deletions
@@ -0,0 +1,94 @@
namespace KArtSell.Modules.ModelOperations.FeedbackLoop;
public enum ModelFeedbackCycleState
{
Planned,
PredictionFrozen,
OutcomesMaturing,
Evaluated,
ImprovementProposed,
ChallengerPlanned,
IndependentlyValidated,
PromotionReviewPending,
BusinessHold,
Closed
}
public sealed record ModelFeedbackTransition(
ModelFeedbackCycleState From,
ModelFeedbackCycleState To,
string ReasonCode,
string EvidenceHash,
string ActorId,
DateTimeOffset OccurredAt);
public sealed class ModelFeedbackCycle
{
private static readonly IReadOnlyDictionary<ModelFeedbackCycleState, IReadOnlySet<ModelFeedbackCycleState>> Allowed =
new Dictionary<ModelFeedbackCycleState, IReadOnlySet<ModelFeedbackCycleState>>
{
[ModelFeedbackCycleState.Planned] = Set(ModelFeedbackCycleState.PredictionFrozen, ModelFeedbackCycleState.BusinessHold),
[ModelFeedbackCycleState.PredictionFrozen] = Set(ModelFeedbackCycleState.OutcomesMaturing, ModelFeedbackCycleState.BusinessHold),
[ModelFeedbackCycleState.OutcomesMaturing] = Set(ModelFeedbackCycleState.Evaluated, ModelFeedbackCycleState.BusinessHold),
[ModelFeedbackCycleState.Evaluated] = Set(ModelFeedbackCycleState.ImprovementProposed, ModelFeedbackCycleState.Closed, ModelFeedbackCycleState.BusinessHold),
[ModelFeedbackCycleState.ImprovementProposed] = Set(ModelFeedbackCycleState.ChallengerPlanned, ModelFeedbackCycleState.Closed, ModelFeedbackCycleState.BusinessHold),
[ModelFeedbackCycleState.ChallengerPlanned] = Set(ModelFeedbackCycleState.IndependentlyValidated, ModelFeedbackCycleState.BusinessHold),
[ModelFeedbackCycleState.IndependentlyValidated] = Set(ModelFeedbackCycleState.PromotionReviewPending, ModelFeedbackCycleState.Closed, ModelFeedbackCycleState.BusinessHold),
[ModelFeedbackCycleState.PromotionReviewPending] = Set(ModelFeedbackCycleState.Closed, ModelFeedbackCycleState.BusinessHold),
[ModelFeedbackCycleState.BusinessHold] = Set(ModelFeedbackCycleState.Planned, ModelFeedbackCycleState.Closed),
[ModelFeedbackCycleState.Closed] = new HashSet<ModelFeedbackCycleState>()
};
private readonly List<ModelFeedbackTransition> transitions = [];
public ModelFeedbackCycle(Guid cycleId, string scopeKey, string baseModelVersion, DateTimeOffset startedAt)
{
if (cycleId == Guid.Empty) throw new ArgumentException("Cycle ID is required.", nameof(cycleId));
if (string.IsNullOrWhiteSpace(scopeKey)) throw new ArgumentException("Scope key is required.", nameof(scopeKey));
if (string.IsNullOrWhiteSpace(baseModelVersion)) throw new ArgumentException("Base model version is required.", nameof(baseModelVersion));
CycleId = cycleId;
ScopeKey = scopeKey;
BaseModelVersion = baseModelVersion;
StartedAt = startedAt;
State = ModelFeedbackCycleState.Planned;
Revision = 1;
LastOccurredAt = startedAt;
}
public Guid CycleId { get; }
public string ScopeKey { get; }
public string BaseModelVersion { get; }
public DateTimeOffset StartedAt { get; }
public ModelFeedbackCycleState State { get; private set; }
public int Revision { get; private set; }
public DateTimeOffset LastOccurredAt { get; private set; }
public DateTimeOffset? ClosedAt { get; private set; }
public IReadOnlyList<ModelFeedbackTransition> Transitions => transitions;
public ModelFeedbackTransition MoveTo(
ModelFeedbackCycleState next,
string reasonCode,
string evidenceHash,
string actorId,
DateTimeOffset occurredAt)
{
if (!Allowed[State].Contains(next))
throw new InvalidOperationException($"Feedback cycle transition {State} -> {next} is not allowed.");
if (string.IsNullOrWhiteSpace(reasonCode)) throw new ArgumentException("Reason code is required.", nameof(reasonCode));
if (string.IsNullOrWhiteSpace(evidenceHash)) throw new ArgumentException("Evidence hash is required.", nameof(evidenceHash));
if (string.IsNullOrWhiteSpace(actorId)) throw new ArgumentException("Actor ID is required.", nameof(actorId));
if (occurredAt < LastOccurredAt) throw new InvalidOperationException("Feedback transition time cannot move backwards.");
var transition = new ModelFeedbackTransition(State, next, reasonCode, evidenceHash, actorId, occurredAt);
transitions.Add(transition);
State = next;
Revision++;
LastOccurredAt = occurredAt;
if (next == ModelFeedbackCycleState.Closed) ClosedAt = occurredAt;
return transition;
}
private static IReadOnlySet<ModelFeedbackCycleState> Set(params ModelFeedbackCycleState[] states)
=> new HashSet<ModelFeedbackCycleState>(states);
}