PotencyTrendAndStabilityRegression_QualityChecker

Potency Trend And Stability Regression

Huvac human vaccines vaccination adjuvants mRNA vaccines sterility endotoxins cold chain
Открыть подборку

Описание утилиты: Potency Trend And Stability Regression

## 1. Краткое описание препарата (на русском)

**PotencyTrendAndStabilityRegression_QualityChecker** — Утилита для анализа трендов потенции и регрессионного моделирования стабильности фармацевтических препаратов.

ℹ️ Утилита обрабатывает данные долгосрочных исследований стабильности (Long-term Stability Studies), строя линейные или нелинейные регрессионные модели деградации активного вещества. Она рассчитывает срок годности (Shelf-life) на основе времени, необходимого для снижения потенции до нижнего предела спецификации (например, 90% или 95%), оценивает коэффициент детерминации (R²) модели и выявляет аномальные отклонения точек данных. Это критически важно для подтверждения сроков годности при регистрации препарата (ICH Q1E) и мониторинга качества в рамках ежегодных обзоров (PQR).

---

## 2. Полный исходный код файла `PotencyTrendAndStabilityRegression_QualityChecker.cs`

```csharp
using System;
using System.Globalization;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;

// --- МОДЕЛИ ДЛЯ LABWARE-СОВМЕСТИМОГО JSON ---

public class LabWareCompatibleOutput
{
    [JsonProperty("Header")]
    public OutputHeader Header { get; set; } = new OutputHeader();

    [JsonProperty("Samples")]
    public List<SampleResult> Samples { get; set; } = new List<SampleResult>();
}

public class OutputHeader
{
    [JsonProperty("UtilityName")]
    public string UtilityName { get; set; } = string.Empty;

    [JsonProperty("Version")]
    public string Version { get; set; } = "1.0.0";

    [JsonProperty("Timestamp")]
    public DateTime Timestamp { get; set; } = DateTime.UtcNow;

    [JsonProperty("InstrumentID")]
    public string InstrumentID { get; set; } = "STABILITY-LAB-01";

    [JsonProperty("OperatorID")]
    public string OperatorID { get; set; } = "Admin";
}

public class SampleResult
{
    [JsonProperty("SampleID")]
    public string SampleID { get; set; } = string.Empty;

    [JsonProperty("BatchNumber")]
    public string BatchNumber { get; set; } = string.Empty;

    [JsonProperty("ProductName")]
    public string ProductName { get; set; } = string.Empty;

    [JsonProperty("TestName")]
    public string TestName { get; set; } = "Potency_Stability_Regression_Analysis";

    [JsonProperty("AnalysisCode")]
    public string AnalysisCode { get; set; } = "ICH_Q1E_REGRESSION";

    [JsonProperty("Status")]
    public string Status { get; set; } = "UNKNOWN"; // STABLE, UNSTABLE, INSUFFICIENT_DATA, ERROR

    [JsonProperty("StatusCode")]
    public int StatusCode { get; set; } = 0; // 1=Stable, 0=Unstable, -1=Error

    [JsonProperty("ErrorMessage")]
    public string ErrorMessage { get; set; } = string.Empty;

    [JsonProperty("Description")]
    public string Description { get; set; } = string.Empty;

    [JsonProperty("DescriptionEN")]
    public string DescriptionEN { get; set; } = string.Empty;

    [JsonProperty("Results")]
    public List<TestParameter> Results { get; set; } = new List<TestParameter>();
}

public class TestParameter
{
    [JsonProperty("ParameterName")]
    public string ParameterName { get; set; } = string.Empty;

    [JsonProperty("ResultValue")]
    public double? ResultValue { get; set; }

    [JsonProperty("UnitOfMeasure")]
    public string UnitOfMeasure { get; set; } = string.Empty;

    [JsonProperty("SpecificationLimit")]
    public string SpecificationLimit { get; set; } = string.Empty;

    [JsonProperty("IsWithinSpec")]
    public bool IsWithinSpec { get; set; }
}

// --- ОСНОВНАЯ ЛОГИКА ---

public class Record
{
    public string BatchNumber { get; set; }
    public string ProductName { get; set; }
    public double TimePoint_Months { get; set; } // 0, 3, 6, 9, 12, 24...
    public double Potency_Percent { get; set; }   // % от номинала
    public double SpecLower_Limit { get; set; }   // Обычно 90% или 95%
}

class Program
{
    const string DEFAULT_INPUT = "input.csv";

    static void Main(string[] args)
    {
        if (args.Length == 0)
        {
            RunWithFiles(inputPath: null, outputPath: null);
            return;
        }

        if (args.Length == 2)
        {
            RunWithFiles(args[0], args[1]);
            return;
        }

        PrintHello();
    }

    static void RunWithFiles(string inputPath, string outputPath)
    {
        LabWareCompatibleOutput finalOutput = new LabWareCompatibleOutput();
        finalOutput.Header.UtilityName = "PotencyTrendAndStabilityRegression_QualityChecker";

        try
        {
            var records = LoadData(inputPath);
            if (records.Count == 0)
            {
                records = GetDemoData();
            }

            // Группируем по серии для построения индивидуальной регрессии
            var batches = records.GroupBy(r => new { r.BatchNumber, r.ProductName, r.SpecLower_Limit });

            foreach (var batchGroup in batches)
            {
                var sortedData = batchGroup.OrderBy(x => x.TimePoint_Months).ToList();
                var evalResult = EvaluateStability(sortedData);

                var sampleResult = new SampleResult
                {
                    SampleID = batchGroup.Key.BatchNumber,
                    BatchNumber = batchGroup.Key.BatchNumber,
                    ProductName = batchGroup.Key.ProductName,
                    TestName = "Shelf_Life_Prediction",
                    AnalysisCode = "REG_ANALYSIS_01",
                    Status = evalResult.Status,
                    StatusCode = evalResult.StatusCode,
                    ErrorMessage = evalResult.Status == "ERROR" ? evalResult.Reason : "",
                    Description = evalResult.Recommendation,
                    DescriptionEN = evalResult.RecommendationEN,
                    Results = new List<TestParameter>
                    {
                        new TestParameter { ParameterName = "Slope_Rate", ResultValue = evalResult.Slope, UnitOfMeasure = "%/month", SpecificationLimit = "N/A", IsWithinSpec = true },
                        new TestParameter { ParameterName = "R_Squared", ResultValue = evalResult.R2, UnitOfMeasure = "", SpecificationLimit = ">0.8", IsWithinSpec = evalResult.R2 > 0.8 },
                        new TestParameter { ParameterName = "Predicted_Shelf_Life", ResultValue = evalResult.PredictedShelfLifeMonths, UnitOfMeasure = "months", SpecificationLimit = $">={evalResult.TargetShelfLife}", IsWithinSpec = evalResult.IsStable },
                        new TestParameter { ParameterName = "Initial_Potency", ResultValue = evalResult.InitialPotency, UnitOfMeasure = "%", SpecificationLimit = "95-105%", IsWithinSpec = evalResult.InitialPotency >= 95 && evalResult.InitialPotency <= 105 }
                    }
                };

                finalOutput.Samples.Add(sampleResult);
            }
        }
        catch (Exception ex)
        {
            finalOutput.Samples.Add(new SampleResult
            {
                Status = "ERROR",
                StatusCode = -1,
                ErrorMessage = ex.Message,
                Description = "Ошибка выполнения утилиты",
                DescriptionEN = "Utility execution error"
            });
        }

        string json = JsonConvert.SerializeObject(finalOutput, Formatting.Indented);
        if (string.IsNullOrEmpty(outputPath))
        {
            Console.WriteLine(json);
        }
        else
        {
            File.WriteAllText(outputPath, json);
            Console.WriteLine($"Результат сохранён в: {outputPath}");
        }
    }

    static List<Record> LoadData(string csvPath = null)
    {
        var ni = CultureInfo.InvariantCulture;
        var records = new List<Record>();

        string path = csvPath ?? DEFAULT_INPUT;
        if (File.Exists(path))
        {
            var lines = File.ReadAllLines(path);
            for (int i = 1; i < lines.Length; i++)
            {
                var line = lines[i].Trim();
                if (string.IsNullOrEmpty(line)) continue;

                var parts = line.Split(',');
                if (parts.Length >= 5)
                {
                    records.Add(new Record
                    {
                        BatchNumber = parts[0].Trim(),
                        ProductName = parts[1].Trim(),
                        TimePoint_Months = double.Parse(parts[2].Trim(), ni),
                        Potency_Percent = double.Parse(parts[3].Trim(), ni),
                        SpecLower_Limit = double.Parse(parts[4].Trim(), ni)
                    });
                }
            }
        }

        return records;
    }

    static List<Record> GetDemoData()
    {
        return new List<Record>
        {
            // Стабильная серия
            new Record { BatchNumber = "STAB-2026-001", ProductName = "Drug A", TimePoint_Months = 0, Potency_Percent = 100.5, SpecLower_Limit = 90.0 },
            new Record { BatchNumber = "STAB-2026-001", ProductName = "Drug A", TimePoint_Months = 3, Potency_Percent = 99.8, SpecLower_Limit = 90.0 },
            new Record { BatchNumber = "STAB-2026-001", ProductName = "Drug A", TimePoint_Months = 6, Potency_Percent = 99.1, SpecLower_Limit = 90.0 },
            new Record { BatchNumber = "STAB-2026-001", ProductName = "Drug A", TimePoint_Months = 12, Potency_Percent = 98.0, SpecLower_Limit = 90.0 },
            new Record { BatchNumber = "STAB-2026-001", ProductName = "Drug A", TimePoint_Months = 24, Potency_Percent = 96.5, SpecLower_Limit = 90.0 },
            
            // Нестабильная серия (быстрая деградация)
            new Record { BatchNumber = "STAB-2026-002", ProductName = "Drug B", TimePoint_Months = 0, Potency_Percent = 101.0, SpecLower_Limit = 90.0 },
            new Record { BatchNumber = "STAB-2026-002", ProductName = "Drug B", TimePoint_Months = 3, Potency_Percent = 97.0, SpecLower_Limit = 90.0 },
            new Record { BatchNumber = "STAB-2026-002", ProductName = "Drug B", TimePoint_Months = 6, Potency_Percent = 93.5, SpecLower_Limit = 90.0 },
            new Record { BatchNumber = "STAB-2026-002", ProductName = "Drug B", TimePoint_Months = 9, Potency_Percent = 89.0, SpecLower_Limit = 90.0 }
        };
    }

    static (string Status, int StatusCode, string Reason, double Slope, double R2, double PredictedShelfLifeMonths, double InitialPotency, double TargetShelfLife, bool IsStable, string Recommendation, string RecommendationEN)
    EvaluateStability(List<Record> records)
    {
        if (records.Count < 3)
        {
            return ("INSUFFICIENT_DATA", 0, "Need at least 3 time points for regression.", 0, 0, 0, 0, 0, false, "Недостаточно данных", "Insufficient data");
        }

        double targetShelfLife = 24; // Целевой срок годности в месяцах (стандарт)
        double specLimit = records.First().SpecLower_Limit;

        // Линейная регрессия Y = a + bX
        double n = records.Count;
        double sumX = records.Sum(r => r.TimePoint_Months);
        double sumY = records.Sum(r => r.Potency_Percent);
        double sumXY = records.Sum(r => r.TimePoint_Months * r.Potency_Percent);
        double sumXX = records.Sum(r => Math.Pow(r.TimePoint_Months, 2));
        double sumYY = records.Sum(r => Math.Pow(r.Potency_Percent, 2));

        double denominator = (n * sumXX - sumX * sumX);
        if (denominator == 0) return ("ERROR", -1, "Math error in regression", 0, 0, 0, 0, targetShelfLife, false, "Ошибка расчета", "Calculation error");

        double slope = (n * sumXY - sumX * sumY) / denominator;
        double intercept = (sumY - slope * sumX) / n;

        // R-squared
        double ssTot = sumYY - (sumY * sumY) / n;
        double ssRes = sumYY - intercept * sumY - slope * sumXY;
        double r2 = (ssTot != 0) ? 1 - (ssRes / ssTot) : 0;

        double initialPotency = intercept;

        // Расчет срока годности: SpecLimit = Intercept + Slope * Time => Time = (SpecLimit - Intercept) / Slope
        // Важно: Slope обычно отрицательный (деградация)
        double predictedShelfLife = 0;
        if (slope < 0)
        {
            predictedShelfLife = (specLimit - intercept) / slope;
        }
        else
        {
            predictedShelfLife = 999; // Если растет или стагнирует, срок очень большой
        }

        bool isStable = predictedShelfLife >= targetShelfLife;
        string status = isStable ? "STABLE" : "UNSTABLE";
        int code = isStable ? 1 : 0;
        string reason = isStable ? "" : $"Predicted shelf life ({predictedShelfLife:F1} mo) < Target ({targetShelfLife} mo).";

        string recRu = isStable
            ? $"Серия стабильна. Прогнозируемый срок годности: {predictedShelfLife:F1} мес."
            : $"Серия нестабильна. Деградация превышает норму. Срок: {predictedShelfLife:F1} мес.";

        string recEn = isStable
            ? $"Batch is stable. Predicted shelf life: {predictedShelfLife:F1} months."
            : $"Batch is unstable. Degradation exceeds norms. Shelf life: {predictedShelfLife:F1} months.";

        return (status, code, reason, slope, r2, predictedShelfLife, initialPotency, targetShelfLife, isStable, recRu, recEn);
    }

    static void PrintHello()
    {
        string exeName = Path.GetFileName(System.Reflection.Assembly.GetExecutingAssembly().Location);
        Console.WriteLine("Potency Trend And Stability Regression Quality Checker — Регрессионный анализ стабильности");
        Console.WriteLine("");
        Console.WriteLine("ℹ️  Утилита строит модели деградации и прогнозирует срок годности (ICH Q1E):");
        Console.WriteLine("    • Линейная регрессия изменения потенции во времени");
        Console.WriteLine("    • Расчет коэффициента детерминации (R²)");
        Console.WriteLine("    • Прогноз времени достижения нижнего предела спецификации");
        Console.WriteLine("    • Оценка соответствия целевому сроку годности");
        Console.WriteLine("");
        Console.WriteLine("⚠️  ВАЖНО: Для точного прогноза требуется минимум 3-4 точки данных за длительный период.");
        Console.WriteLine("");
        Console.WriteLine("Использование:");
        Console.WriteLine($"  {exeName}                            → демо-режим (вывод в консоль)");
        Console.WriteLine($"  {exeName} input.csv output.json      → оценка ваших данных");
        Console.WriteLine("");
        Console.WriteLine("Формат input.csv:");
        Console.WriteLine("BatchNumber,ProductName,TimePoint_Months,Potency_Percent,SpecLower_Limit");
        Console.WriteLine("");
        Console.WriteLine(@"Пример:");
        Console.WriteLine(@"BATCH-001,Drug A,0,100.5,90.0");
    }
}
```

---

## 3. Полный содержимое файла `input.csv`

```csv
BatchNumber,ProductName,TimePoint_Months,Potency_Percent,SpecLower_Limit
STAB-2026-001,Drug A,0,100.5,90.0
STAB-2026-001,Drug A,3,99.8,90.0
STAB-2026-001,Drug A,6,99.1,90.0
STAB-2026-001,Drug A,12,98.0,90.0
STAB-2026-001,Drug A,24,96.5,90.0
STAB-2026-002,Drug B,0,101.0,90.0
STAB-2026-002,Drug B,3,97.0,90.0
STAB-2026-002,Drug B,6,93.5,90.0
STAB-2026-002,Drug B,9,89.0,90.0
```

---

## 4. Полный содержимое файла `PotencyTrendAndStabilityRegression_QualityChecker.description.txt`

```text
Potency Trend And Stability Regression Quality Checker — Регрессионный анализ стабильности

ℹ️  Утилита выполняет статистический анализ данных исследований стабильности для прогнозирования срока годности согласно ICH Q1E:
     • Построение модели: Линейная регрессия зависимости "Потенция-Время".
     • Оценка качества модели: Расчет R² для подтверждения линейности деградации.
     • Прогнозирование: Расчет времени, через которое потенция достигнет нижнего предела спецификации.
     • Принятие решений: Сравнение прогнозируемого срока с требуемым (Target Shelf Life).

⚠️  ВАЖНО: 
     • Метод предполагает линейную кинетику деградации первого порядка.
     • Для нелинейных процессов могут потребоваться более сложные модели.

Использование:
  PotencyTrendAndStabilityRegression_QualityChecker.exe                            → демо-режим (вывод в консоль)
  PotencyTrendAndStabilityRegression_QualityChecker.exe input.csv output.json      → оценка ваших данных

Формат input.csv:
BatchNumber,ProductName,TimePoint_Months,Potency_Percent,SpecLower_Limit

Пример:
  BATCH-001,Drug A,0,100.5,90.0

📍 Область применения (Usage Where):
     • Регистрация препаратов: Обоснование срока годности для досье.
     • Ежегодный обзор качества (PQR): Анализ трендов стабильности серий.
     • Разработка формуляций: Выбор оптимального состава для максимальной стабильности.
     • Управление запасами: Прогноз остаточного срока годности на складе.

— ЗАЧЕМ ЭТО НУЖНО?
Эмпирическое наблюдение за препаратом в течение всего срока годности занимает годы.
Регрессионный анализ позволяет экстраполировать данные ранних этапов (3, 6, 12 месяцев) для предварительной оценки стабильности.
Это ускоряет вывод продукта на рынок и снижает риски выпуска нестабильных партий.

⚠️  КРИТИЧЕСКИ ВАЖНО:
• R² Значение: Низкий R² (<0.8) указывает на то, что линейная модель неприменима или данные зашумлены.
• Outliers: Аномальные точки могут исказить наклон линии регрессии.
• Spec Limit: Точность прогноза сильно зависит от правильного установления нижнего предела.
• Temperature: Данные должны быть получены при одном температурном режиме (напр. 25°C/60%RH).

Ключевые особенности утилиты:
• Автоматический расчет параметров линейной регрессии
• Прогнозирование срока годности (Shelf-life prediction)
• Оценка статистической значимости тренда
• Генерация отчетов для регуляторных органов
• Поддержка множественных серий для сравнительного анализа

Критические параметры:
• Slope: Скорость деградации (%/месяц)
• R-Squared: Качество аппроксимации
• Predicted Shelf Life: Прогнозируемое время жизни
• Initial Potency: Начальная активность

💡 Советы по использованию:
1. Частота отбора: Включайте ключевые точки (0, 3, 6, 9, 12, 18, 24 месяца).
2. Очистка данных: Исключайте явные ошибки измерений перед анализом.
3. Комбинирование серий: Для регистрации часто используют объединенные данные нескольких серий.
4. Валидация: Регулярно сверяйте прогнозы с реальными данными долгосрочных исследований.
5. Документирование: Сохраняйте отчеты как часть протокола стабильности.

⚠️ Примечание: Данная утилита является инструментом статистического моделирования. Окончательное утверждение срока годности требует комплексной оценки всех параметров качества и условий хранения.

input.csv

BatchNumber,ProductName,TimePoint_Months,Potency_Percent,SpecLower_Limit
STAB-2026-001,Drug A,0,100.5,90.0
STAB-2026-001,Drug A,3,99.8,90.0
STAB-2026-001,Drug A,6,99.1,90.0
STAB-2026-001,Drug A,12,98.0,90.0
STAB-2026-001,Drug A,24,96.5,90.0
STAB-2026-002,Drug B,0,101.0,90.0
STAB-2026-002,Drug B,3,97.0,90.0
STAB-2026-002,Drug B,6,93.5,90.0
STAB-2026-002,Drug B,9,89.0,90.0

URS & FS — спецификация пользователя и функциональная спецификация

Документ описывает контролируемый интерфейс и поведение утилиты PotencyTrendAndStabilityRegression_QualityChecker для сценария ## 1. Краткое описание препарата (на русском).

Предметные ограничения и критические параметры

Ниже приведены ключевые фрагменты исходного описания. Перед продуктивным применением пределы должны быть сверены с утверждённой спецификацией, регистрационным досье и локальными SOP.
  • **PotencyTrendAndStabilityRegression_QualityChecker** — Утилита для анализа трендов потенции и регрессионного моделирования стабильности фармацевтических препаратов.
  • ℹ️ Утилита обрабатывает данные долгосрочных исследований стабильности (Long-term Stability Studies), строя линейные или нелинейные регрессионные модели деградации активного вещества. Она рассчитывает срок годности (Shelf-life) на основе времени, необходимого для снижения потенции до нижнего предела спецификации (например, 90% или 95%), оценивает коэффициент детерминации (R²) модели и выявляет аномальные отклонения точек данных. Это критически важно для подтверждения сроков годности при регистрац
  • ## 2. Полный исходный код файла `PotencyTrendAndStabilityRegression_QualityChecker.cs`
  • public List<SampleResult> Samples { get; set; } = new List<SampleResult>();
  • public string TestName { get; set; } = "Potency_Stability_Regression_Analysis";
  • public string AnalysisCode { get; set; } = "ICH_Q1E_REGRESSION";
  • public List<TestParameter> Results { get; set; } = new List<TestParameter>();
  • [JsonProperty("SpecificationLimit")]
  • public string SpecificationLimit { get; set; } = string.Empty;
  • public double Potency_Percent { get; set; } // % от номинала
  • public double SpecLower_Limit { get; set; } // Обычно 90% или 95%
  • finalOutput.Header.UtilityName = "PotencyTrendAndStabilityRegression_QualityChecker";
  • var batches = records.GroupBy(r => new { r.BatchNumber, r.ProductName, r.SpecLower_Limit });
  • var sortedData = batchGroup.OrderBy(x => x.TimePoint_Months).ToList();
  • Results = new List<TestParameter>
  • new TestParameter { ParameterName = "Slope_Rate", ResultValue = evalResult.Slope, UnitOfMeasure = "%/month", SpecificationLimit = "N/A", IsWithinSpec = true },
  • new TestParameter { ParameterName = "R_Squared", ResultValue = evalResult.R2, UnitOfMeasure = "", SpecificationLimit = ">0.8", IsWithinSpec = evalResult.R2 > 0.8 },
  • new TestParameter { ParameterName = "Predicted_Shelf_Life", ResultValue = evalResult.PredictedShelfLifeMonths, UnitOfMeasure = "months", SpecificationLimit = $">={evalResult.TargetShelfLife}", IsWithinSpec = evalResult.IsStable },

URS — пользовательские требования

IDТребованиеКритичностьКритерий приемки
URS-001Утилита должна принимать файл input.csv для ## 1. Краткое описание препарата (на русском) с заголовками, определёнными в контракте данных.HighФайл обрабатывается без ручного изменения заголовков.
URS-002Утилита должна выполнять детерминированную оценку QC/ОКК без машинного обучения и без вероятностного принятия решения о соответствии.HighПри одинаковых входных данных, версии правил и конфигурации результат полностью воспроизводим.
URS-003Утилита должна валидировать обязательные поля, типы данных, диапазоны, единицы измерения и предметную правдоподобность значений.HighОшибки схемы, преобразования и диапазона явно отражаются в результате.
URS-004Утилита должна применять предметные пределы и правила из описания, утверждённой спецификации, регистрационного досье и локальных SOP.HighКаждая проверка имеет результат PASS/WARNING/FAIL и понятное сообщение.
URS-005Утилита должна формировать output.json с машинно-читаемыми результатами, исходными значениями, предупреждениями, отказами и критическими находками.HighJSON пригоден для LIMS/ELN/MES-интеграции и QA/QC review.
URS-006Утилита должна сохранять трассируемость между серией/образцом, входным файлом, применёнными правилами и итоговым статусом.HighВыход содержит идентификаторы, список параметров и audit metadata.
URS-007Документация должна поддерживать подготовку IQ/OQ/PQ, CSV/CSA и обсуждение с инспекторами или внутренним QA.MediumURS, FS, контракт input/output и тестовые сценарии поставляются вместе с утилитой.
URS-008Утилита должна использоваться как decision-support инструмент QC, а не как замена утверждённым спецификациям и выпускному решению Qualified Person/QA.MediumВ документации указан контроль change control и необходимость сверки пределов.

Контракт input.csv

#ПолеТипПримерНазначение
1BatchNumberstring / controlled vocabularySTAB-2026-001Идентификатор серии/партии для трассируемости.
2ProductNamestring / controlled vocabularyDrug AНаименование продукта или проверяемой лекарственной формы.
3TimePoint_Monthsdecimal0Временной параметр процесса, инкубации, хранения или анализа.
4Potency_Percentdecimal100.5Потентность/активность; критический параметр эффективности.
5SpecLower_Limitdecimal90.0Утверждённый предел, применяемый при проверке результата.
BatchNumber,ProductName,TimePoint_Months,Potency_Percent,SpecLower_Limit
STAB-2026-001,Drug A,0,100.5,90.0
STAB-2026-001,Drug A,3,99.8,90.0
STAB-2026-001,Drug A,6,99.1,90.0

Правила валидации входных данных

IDПолеПравилоКритичность
VR-001BatchNumberПоле должно соответствовать утверждённому справочнику/словарю или допустимой строковой форме.High
VR-002ProductNameПоле должно соответствовать утверждённому справочнику/словарю или допустимой строковой форме.High
VR-003TimePoint_MonthsПоле должно соответствовать утверждённому справочнику/словарю или допустимой строковой форме.High
VR-004Potency_PercentПоле должно соответствовать утверждённому справочнику/словарю или допустимой строковой форме.Medium
VR-005SpecLower_LimitПоле должно соответствовать утверждённому справочнику/словарю или допустимой строковой форме.Medium

FS — функциональная спецификация

IDФункцияРеализация
FS-001CLI executionПоддержать режимы запуска: demo mode без аргументов и production mode input.csv output.json.
FS-002CSV importПрочитать input.csv в UTF-8/CSV-совместимом формате, проверить наличие заголовка и ожидаемых колонок.
FS-003Schema validationПроверить обязательные поля, количество колонок, неизвестные ключевые поля и пустые обязательные значения.
FS-004Type conversionПреобразовать числовые, флаговые и текстовые значения; некорректный формат фиксировать как ошибку строки.
FS-005Domain rule engineПрименить правила для ## 1. Краткое описание препарата (на русском), включая критические пределы из описания и утверждённой спецификации.
FS-006Status aggregationСформировать итоговый статус: FAIL при критическом отказе, WARNING при некритическом отклонении, PASS при соответствии.
FS-007JSON exportЗаписать output.json с детализацией проверок, исходными значениями, предупреждениями, отказами и critical findings.
FS-008Audit supportСохранять структуру результата пригодной для review, расследования отклонений и воспроизведения расчёта.
FS-009Integration contractПоддержать сценарий LIMS/ELN/MES → input.csv → utility → output.json → portal/admin review.
FS-010Error handlingВозвращать явные сообщения для отсутствующего файла, пустого CSV, неверной схемы, ошибки записи output.json и некорректного формата.

Пример output.json

{
  "utilityId": "potencytrendandstabilityregression-qualitychecker",
  "utilityFolder": "PotencyTrendAndStabilityRegression_QualityChecker",
  "package": "huvac",
  "overallStatus": "PASS|WARNING|FAIL",
  "sourceFile": "input.csv",
  "processedAtUtc": "2026-06-10T00:00:00Z",
  "checks": [
    {
      "parameter": "BatchNumber",
      "value": "STAB-2026-001",
      "status": "PASS|WARNING|FAIL",
      "message": "Deterministic rule-based check result",
      "ruleReference": "FS-RULE-001"
    },
    {
      "parameter": "ProductName",
      "value": "Drug A",
      "status": "PASS|WARNING|FAIL",
      "message": "Deterministic rule-based check result",
      "ruleReference": "FS-RULE-002"
    },
    {
      "parameter": "TimePoint_Months",
      "value": "0",
      "status": "PASS|WARNING|FAIL",
      "message": "Deterministic rule-based check result",
      "ruleReference": "FS-RULE-003"
    },
    {
      "parameter": "Potency_Percent",
      "value": "100.5",
      "status": "PASS|WARNING|FAIL",
      "message": "Deterministic rule-based check result",
      "ruleReference": "FS-RULE-004"
    },
    {
      "parameter": "SpecLower_Limit",
      "value": "90.0",
      "status": "PASS|WARNING|FAIL",
      "message": "Deterministic rule-based check result",
      "ruleReference": "FS-RULE-005"
    }
  ],
  "criticalFindings": [],
  "warnings": [],
  "audit": {
    "inputHash": "sha256:<calculated at runtime>",
    "rulesVersion": "<utility executable version>",
    "documentation": "PotencyTrendAndStabilityRegression_QualityChecker.documentation.html"
  }
}

Матрица трассируемости

URSFSТестПодтверждение
URS-001FS-001, FS-002OQ-001Проверить запуск и импорт валидного input.csv.
URS-002FS-005, FS-006OQ-004Повторить один и тот же набор данных и сравнить output.json.
URS-003FS-003, FS-004, FS-010OQ-002, OQ-003Проверить отсутствующие колонки и неверные типы.
URS-004FS-005, FS-006OQ-004, PQ-001Проверить критические отклонения по реальным/граничным данным.
URS-005FS-007, FS-009OQ-005Проверить JSON schema и пригодность для downstream-систем.
URS-006FS-008OQ-006Проверить наличие идентификаторов и audit metadata.
URS-007FS-008, FS-010IQ-001, OQ-007Проверить комплектность документации и control evidence.
URS-008FS-005, FS-008PQ-002Проверить review workflow и запрет автоматической замены QA-решения.

IQ/OQ/PQ тестовые сценарии

IDСценарийОжидаемый результат
IQ-001Проверить наличие executable, input.csv, документации и контрольной суммы.Комплект поставки полон; версия зафиксирована.
OQ-001Валидная строка из примера input.csv.PASS или допустимый WARNING согласно правилам.
OQ-002Удалить обязательную колонку из CSV.Ошибка схемы или FAIL с указанием отсутствующей колонки.
OQ-003Внести нечисловое значение в числовое поле.Ошибка преобразования типа с указанием строки/поля.
OQ-004Значение критического параметра вывести за предел.FAIL и critical finding.
OQ-005Проверить структуру output.json.Все обязательные секции присутствуют, JSON валиден.
OQ-006Проверить трассируемость серии/образца.Идентификаторы входа и результатов совпадают.
PQ-001Проверить 3–5 реальных партий/образцов пользователя.Результат подтверждён QC/QA review.
PQ-002Проверить workflow отклонения и ручного QA-решения.Утилита поддерживает review, но не заменяет утверждённое решение.

QA/QC и change control

  • Не менять имена колонок без обновления валидатора, документации и тестового набора.
  • Хранить input.csv, output.json, версию исполняемого файла и контрольную сумму.
  • Перед продуктивным использованием провести IQ/OQ/PQ или эквивалентную CSV/CSA-проверку.
  • Критические пределы должны быть сверены с утверждённой спецификацией, регистрационным досье и локальными SOP.
  • Утилита предоставляет формализованный QC decision support, но окончательное решение выпуска остаётся за QA/QP и утверждёнными процедурами.

Входит в пакеты

Биофармацевтика расширенная

Расширенный coverage-пакет QC-утилит для mAb, биоаналогов, белков, инсулинов, вакцин, mRNA/LNP, HCP, стерильного выпуска, микробиологии, воды, cleanroom и стабильности.

Открыть

Huvac — QC утилиты для вакцин человека

Пакет Huvac содержит утилиты для контроля качества вакцин человека: адъюванты, антигенная активность, стерильность, эндотоксины, cold chain, mRNA-контроль, контейнеры и стабильность.

Открыть