Исследование системы составления расписания

«Расписание занятий и экзаменов»: техническое исследование§

Исследованы DB/1_sem_2026_2027, служебные файлы в DB и все 15 изображений в screen. Дата исследования: 9 сентября 2026 года. Это описание предоставленного снимка данных и наблюдаемых экранов. Основная программа не запускалась: в проекте есть только связанная утилита Reorder.EXE, а исполняемого файла самого планировщика и его исходного кода нет.

1. Основные выводы§

Перед нами настольная система ведения учебных справочников, планов и расписания занятий и экзаменов. Она хранит данные в файловых таблицах Paradox: отдельный .DB содержит одну таблицу, а индексы и служебные настройки находятся в соседних файлах. Название папки обозначает предполагаемый учебный период, но само по себе не доказывает, что все данные внутри актуальны именно для него.

Данные успешно прочитаны. Из 19 таблиц извлечено 75 909 записей, включая связи и вспомогательные данные. Это не число занятий: непосредственно в Classes.DB находится 15 111 записей занятий, в GROUPS.DB554 группы, в TEACHERS.DB866 преподавателей, в Rooms.DB184 аудитории, в Plan.DB4 748 записей плана. Названия в .DB читаются в кодировке CP866. Все значения сопоставлены с независимым чтением через pxlib; исключение касается только счетчика записей в заголовке ClassesInf.DB, а не разницы извлеченных значений.

Технологии связанной утилиты установлены по бинарным заголовкам и ресурсам: Windows x86, Delphi/VCL, Borland Database Engine (BDE). Для основной программы тот же стек весьма вероятен, однако без ее EXE нельзя доказать точную среду сборки, язык всего приложения и версию компилятора.

Для нового интерфейса уже достаточно данных, чтобы сделать поиск по справочникам, учебным планам и занятиям. Надежный первый этап — веб-просмотр отдельной выгрузки в SQLite/UTF-8. Для полноценного календаря и обратной записи сначала необходимо восстановить смысл кодов дня/недели и операций сохранения.

Что особенно важно учесть§

  1. Скриншоты календаря показывают 2–14 сентября 2024 года, хотя каталог называется 1_sem_2026_2027. В названиях потоков тоже сохранились прошлые учебные годы. Связь скриншотов с текущей копией нужно подтвердить.
  2. DayNo в занятиях принимает значения до 299. Это не простой внешний ключ на шесть строк DAYS.DB. У всех непустых значений остаток DayNo % 14 находится в диапазоне 0–5; полное правило перевода в дату пока не доказано.
  3. У занятия может не быть прямой группы: 3 458 строк имеют GroupNo=-1. Состав групп восстанавливается через PlanNo → GRPPLAN, с учетом подгрупп и вида занятия.
  4. ClassesInf.DB и CLASSINF.DBдве разные таблицы. Первая содержит вспомогательное представление позиций, вторая — пустую таблицу дополнительных связей занятия с аудиторией/преподавателем.
  5. В ClassesInf.DB заголовок объявляет 15 124 строки, а цепочка активных блоков содержит 15 111. pxlib подтверждает это расхождение. В одной позиции аудитория отличается от Classes.DB. Эту таблицу нельзя безусловно считать независимым актуальным расписанием.
  6. В текстовых .dat вместо русских букв уже записаны #. Это утрата символов, а не выбор неправильной кодировки при просмотре. Для переноса названий нужно читать .DB.
  7. У двух кафедр указаны отсутствующие факультеты (ID 46 и 48); 2 339 записей Assigned=True не имеют аудитории. Первое — несогласованная ссылка, второе требует проверки правил назначенности.
  8. В проекте подготовлены JSON и SQLite для исследования. Исходные файлы не изменялись; совпадение SHA-256 до и после экспорта проверено для всех 65 файлов каталога семестра.

2. Что подтверждено, а что еще предстоит проверить§

В отчете используются три уровня доказательности:

Уровень Что означает Примеры
Подтверждено файлами Прочитаны поля, байты, значения, связи, заголовки или ресурсы EXE Paradox, CP866, количество строк, ключи, поля PlanNo и TeacherNo
Видно в интерфейсе Есть подписанная команда, форма или поле на скриншоте «Сменить Аудиторию», «Стабильное», список неназначенных занятий
Интерпретация Обоснованная гипотеза, которую нельзя считать проверенным поведением Алгоритм автосоставления, точный смысл Stable, действие «Отдать на кафедру»

Изображение кнопки подтверждает наличие предусмотренной команды, но не ее успешное выполнение. Существование поля ограничения подтверждает хранение ограничений, но не доказывает, что программа проверяет их во всех сценариях. Таблицы позволяют восстановить структуру данных гораздо увереннее, чем алгоритмы редактирования.

В исходном наборе не обнаружены основной EXE, исходники .pas/.dpr/.dfm, установщик BDE, руководство пользователя, конфигурация начала семестра, API или журнал изменений. Отсутствие этих файлов именно в переданной папке не означает, что их нет в рабочей установке.

3. Архитектура системы§

Логически систему удобно разделить на пять частей:

Часть Основные данные Роль
Организация учебного процесса Факультеты, кафедры, курсы, группы, преподаватели Определяет участников и организационные связи
Ресурсы Аудитории, дни, начала занятий Задает помещения и временную сетку
Учебная потребность Дисциплины, записи плана, виды/объем нагрузки, группы плана Определяет, что требуется провести и для кого
Размещение Занятия, преподаватель, аудитория, код дня, время, признаки недель Представляет расписанные и неназначенные элементы
Ограничения и обслуживание Запреты преподавателей/аудиторий, индексы, вспомогательные таблицы Поддерживает проверку и работу файловой БД

Путь от дисциплины к расписанию выглядит так:

SUBJECTS (дисциплина)
  └─ Plan (позиция учебного плана + кафедра + Stable)
       ├─ PLANITEM (вид занятия + объем + деление на подгруппы)
       ├─ GRPPLAN → GROUPS (участвующие группы и подгруппы)
       ├─ PLANROOM → Rooms (набор аудиторий плана; здесь пуст)
       └─ Classes (экземпляры/элементы занятий)
            ├─ TEACHERS
            ├─ Rooms
            └─ DayNo + TimeNo + EachWeek + OddWeek + Assigned

Объект Plan нельзя отождествлять с дисциплиной: одна дисциплина может входить в несколько позиций плана. Объект Classes нельзя отождествлять с записью плана: одной учебной потребности соответствуют несколько элементов расписания. Названия не являются ключами — связи строятся по числовым идентификаторам.

Физический уровень§

База состоит из файлов в каталоге. В исследованном снимке нет признаков отдельного серверного хранилища вроде PostgreSQL или SQL Server. Связанная утилита использует компоненты TTable, TQuery, TDatabase и TSession; в ее ресурсах сохранены DriverName=STANDARD, DatabaseName=ScheduniDB и названия таблиц.

TTable — компонент доступа к таблицам через BDE; документация производителя прямо указывает поддержку Paradox и локальных файловых таблиц. Это согласуется с найденными ресурсами. Документация Embarcadero: TTable.

Файлы .LCK в каталоге DB относятся к блокировкам окружения Paradox/BDE. Их наличие в копии не позволяет определить, кто сейчас держит базу открытой, и не доказывает сетевой режим работы. Для воспроизведения рабочего окружения потребуется проверить параметры BDE, рабочий и сетевой каталоги в установленной программе.

Формат таблиц§

Заголовки показывают форматы Paradox уровня 4, 5 и 7: DAYS.DB и TIMES.DB имеют идентификатор формата 9, большинство таблиц — 11, Courses.DB — 12. Это версии формата файлов, а не версии приложения или Delphi. Во всех 19 таблицах в заголовке указана кодовая страница 866.

Используются поля фиксированной длины: Alpha, Short, Long, AutoIncrement, Logical. В найденных схемах нет дат, вещественных чисел и BLOB-полей; даты расписания, следовательно, нельзя просто прочитать из колонки типа Date. Заголовки и записи прочитаны с учетом цепочки активных блоков, а не поиском похожих байтов по всему файлу: свободные блоки могут хранить остатки старых записей. Структура сверена с исходниками pxlib.

4. Карта основных таблиц§

Файл Прочитано строк Для чего нужен
FACULTY.DB 6 Названия факультетов/организационных подразделений
CHAIRS.DB 47 Кафедры и принадлежность факультету
Courses.DB 12 Классификатор курсов/уровней обучения
GROUPS.DB 554 Группы, факультет, курс, численность и число подгрупп
TEACHERS.DB 866 Преподаватели, кафедра, степень, должность, звание, заметки
SUBJECTS.DB 5 068 Полные и краткие названия дисциплин
Rooms.DB 184 Аудитории, вместимость, тип, кафедра и заметки
DAYS.DB 6 Понедельник–суббота, коды 0–5
TIMES.DB 8 Номера слотов 1–8 и время начала
STREAMS.DB 140 Именованный справочник потоков/периодов
Plan.DB 4 748 Учебная потребность по дисциплине и кафедре
PLANITEM.DB 7 098 Виды и объем занятий для позиции плана
GRPPLAN.DB 21 419 Связи позиции плана с группами и подгруппами
PLANROOM.DB 0 Связи плана/вида занятия с аудиториями; механизм не заполнен в снимке
Classes.DB 15 111 Основные записи занятий и их размещение
CLASSINF.DB 0 Дополнительные сведения занятия: аудитория и преподаватель
ClassesInf.DB 15 111 Вспомогательные позиции и Stable; заголовок указывает 15 124
TCHRRSTR.DB 4 541 Ограничения преподавателей по дню, времени и варианту недели
ROOMRSTR.DB 990 Ограничения аудиторий по дню, времени и варианту недели

Точные имена, типы, размеры и первичные ключи всех полей приведены в словаре данных ниже. Пустая таблица описывает предусмотренную структуру, но не доказывает применение соответствующего механизма в текущем расписании.

5. Как связаны группы, планы и занятия§

Прямая группа и группа через план§

У Classes есть GroupNo и Subgroup, но не все занятия привязаны к группе этим полем. В 3 458 строках GroupNo=-1; они относятся к типам л и э, имеют Subgroup=-1, а соответствующие позиции PLANITEM не разделены по подгруппам. Для них участники определяются через GRPPLAN по PlanNo. Часть таких планов содержит всего одну группу: значение -1 само по себе не означает обязательно несколько групп.

GRPPLAN имеет составной ключ (GroupNo, Subgroup, PlanNo). Одна группа может встречаться в одном плане несколько раз — для разных подгрупп. Поэтому список групп для общего занятия нужно получать с устранением повторов по GroupNo, сохраняя отдельно состав подгрупп. Суммирование NStudents по всем строкам GRPPLAN завысит численность.

Для занятий с конкретными GroupNo и Subgroup эти поля нужно учитывать вместе с PLANITEM.GrpSplit. Универсальный запрос, присоединяющий все группы плана ко всем занятиям без учета вида и деления, может приписать занятию лишние группы. В подготовленной SQLite есть отдельные представления прямых данных занятия и членства в плане; они намеренно не скрывают эту особенность.

Два значения слова «поток»§

Есть справочник STREAMS и поле GROUPS.StreamNo. Но у всех 554 групп в этой копии StreamNo=-1: действующей положительной привязки к 140 строкам справочника нет. Одновременно группы реально объединяются через GRPPLAN. Поэтому поле «Поток» в учебном плане и окно «Потоки» нельзя заранее считать одним и тем же механизмом. Разница видна и на экране плана, и в окне потоков.

Курс, идентификаторы и служебные значения§

CourseNo — ключ классификатора, а не обязательно номер года обучения. Например, 6 соответствует «1-й курс магистратуры», а 8 — «6-й курс». Для отображения нужен Courses.CourseName. Поле CourseCount у всех 12 записей равно CourseNo, поэтому его тоже нельзя считать фактическим годом обучения. Назначение этой числовой колонки требует проверки программы.

Значения NULL, 0, -1 нельзя автоматически объединять. Они встречаются в разных полях с разным назначением. В частности, GROUPS.StreamNo=-1 и Classes.GroupNo=-1 — разные контексты. Не следует создавать фиктивные справочные записи с такими ключами только ради формального внешнего ключа.

6. Временная модель и статусы§

Дни и недели§

DAYS.DB содержит коды 0–5. В TCHRRSTR и ROOMRSTR день действительно лежит в этом диапазоне, а Week принимает 0 или 1. В Classes.DayNo обнаружены 72 различных непустых кода от 0 до 299 и NULL; у всех непустых кодов DayNo % 14 лежит между 0 и 5. Значения согласуются с некоторым кодированием периода с шагом 14, но этого недостаточно для восстановления календаря.

Предположение для дальнейшего эксперимента: DayNo // 14 может обозначать номер двухнедельного периода, DayNo % 14 — день, а OddWeek — один из вариантов недели. Это не утвержденная формула. Не определены точка отсчета, нумерация первого периода, правило EachWeek, приоритет флагов и смысл неназначенных записей с оставшейся позицией. В интерфейсе рядом с днем действительно показаны две даты через дефис, но назначение такого отображения нужно подтвердить настройками.

В новом интерфейсе до проверки следует показывать исходный код DayNo и признаки недель. Производную дату стоит оставлять незаполненной. Нельзя выбирать 1 сентября 2026 года только по имени папки или подменять код дня остатком от деления на 7.

Назначенные и неназначенные§

Показатель Строк
Assigned=True 11 530
Assigned=False 3 581
Assigned=False и позиция DayNo/TimeNo/OddWeek заполнена 288
DayNo/TimeNo/OddWeek не заполнены 3 293
EachWeek=True 23
EachWeek=False 15 088

Таким образом, неназначенность не равна отсутствию всех координат. При построении списка следует фильтровать именно по Assigned, а оставшиеся поля показывать как исходные значения. Возможное объяснение — сохранение прежней позиции после отмены или промежуточное состояние; по снимку это не доказано.

Виды занятий и помещений§

В Classes.PlanType найдены шесть кириллических кодов: с — 10 573 строки, л — 3 258, п — 621, з — 358, э — 200, к — 101. По полям учебного плана наиболее вероятное соответствие: лекция л, практика/семинар с, лабораторная работа п, зачет з, экзамен э, консультация к. Особенно важно проверить различие с и п на одной сохраненной записи: буквенного кода самого по себе недостаточно. В прототипе просмотра разумно показывать код рядом с предположительным названием.

Rooms.RoomType использует с (77), л (63), п (40), к (4). Это отдельный классификатор: к для помещения, вероятно, компьютерный класс, а в занятиях — предположительно консультация. RoomSpec=False во всех 184 строках; смысл этого поля по данным не раскрывается. На экране поиска есть и вариант «Лингафонный кабинет», которого среди четырех наблюдаемых кодов нельзя автоматически идентифицировать.

Звонки и продолжительность§

Время хранится строками: 8:00, 9:40, 11:25, 13:20, 15:05, 16:50, 18:30, 20:05. В таблице нет времени окончания. Разность соседних начал включает перерывы и не определяет длительность занятия. PlanQty — числовой объем, а интерфейс называет поля часами; соотношение академического часа, пары, повторений и элементов Classes требует проверки.

Признак Stable§

Plan.Stable=True у 3 738 позиций, False у 1 010. В ClassesInf этот признак совпадает с Plan.Stable по PlanNo для всех 15 111 записей. Это подтверждает передачу признака от плана, но не раскрывает его действие. Нельзя автоматически трактовать его как запрет переноса или как проведенное занятие.

7. Навигатор по интерфейсу§

Начинать знакомство удобнее со справочников, затем перейти к учебному плану и только после этого к сетке расписания.

Задача Где искать Файлы Скриншот
Найти группу, численность и подгруппы Справочники → Группы GROUPS, FACULTY, Courses 3
Узнать кафедру и сведения преподавателя Справочники → Преподаватели TEACHERS, CHAIRS 4
Посмотреть дисциплины и сокращения Справочники → Дисциплины SUBJECTS 5
Найти аудиторию, тип и вместимость Справочники → Аудитории Rooms, CHAIRS 6
Разобраться в подразделениях Справочники → Кафедры / Факультеты CHAIRS, FACULTY 7, 8
Узнать нагрузку и состав групп по дисциплине Справочники → Учебный план Plan, PLANITEM, GRPPLAN, SUBJECTS 9
Проверить обозначения курсов Справочники → Курсы Courses 10
Посмотреть именованные потоки Справочники → Потоки STREAMS, предполагаемая связь с GROUPS 11
Узнать начала занятий Справочники → Звонки TIMES 12
Найти свободную аудиторию Расписание → Поиск свободной аудитории Rooms, Classes, ROOMRSTR, TIMES — ожидаемые источники 13
Посмотреть общую сетку и неназначенные занятия Расписание → Основной вид, вероятный переход Classes и справочники 14
Перенести занятие, сменить аудиторию/преподавателя Контекстное меню занятия Прежде всего Classes; полный набор изменяемых файлов не установлен 15

Меню «Расписание» также содержит «База данных» и «Параметры…», а главное меню — «Помощь». Их окна не представлены. Нельзя подтвердить выбор семестра, импорт, резервное копирование, печать, экспорт в Excel/HTML/XML, автоматическое составление или разграничение прав только по этим названиям.

Сетка позволяет наблюдать выбор недели, группы по колонкам, занятия по дням и временным позициям, всплывающие сведения и список «Не назначены». Контекстное меню предусматривает отмену, перестановку, смену аудитории, замену преподавателя, передачу «на кафедру», переходы к расписаниям и комментарий. Семантика «Отменить» и «Отдать на кафедру» требует отдельного опыта: это может быть изменение статуса, а не удаление записи.

Полный каталог из 59 видимых или предполагаемых интерфейсных возможностей приведен далее. Он не является перечнем 59 выполненных тестов.

8. Служебные и обменные файлы§

Индексы и семейства§

.PX — первичный индекс, пары .XG0/.YG0 и .XG1/.YG1 — вторичные индексы и их индексные структуры. Они нужны старому движку для порядка доступа и поиска. Их не нужно превращать в самостоятельные бизнес-таблицы современного интерфейса. Такое назначение расширений описано в руководстве Corel, раздел Paradox, печатная стр. 748.

В папке действительно 19 .PX, однако соответствие не один к одному: у ClassesInf.DB первичного ключа и одноименного .PX нет; присутствует LOAD.PX, хотя LOAD.DB отсутствует. LOAD.FAM и LOAD.TV содержат ссылки на CLASSES. Это исторические служебные следы, а не доказательство утраты необходимой таблицы нагрузки.

Внутренние имена некоторых .DBresttemp.DB, у TIMES.DBTIME.DB. Идентифицировать актуальную таблицу следует по внешнему имени и схеме. Внутреннее старое имя не является основанием переименовывать файлы.

Текстовый обмен§

Пара Строк в DAT Строк в одноименной DB Содержимое
chairs.dat + chairs.sch 44 47 Кафедры и факультет
groups.dat + groups.sch 348 554 Группы, курс, численность, подгруппы
rooms.dat + rooms.sch 185 184 Аудитории, вместимость, тип
subjects.dat + subjects.sch 1 995 5 068 Названия дисциплин и сокращения
teachers.dat + teachers.sch 779 866 Преподаватели и квалификация

Каждая .sch задает Filetype=Fixed, длины и смещения текстовых полей. .dat состоят из фиксированных строк с разделителями |, концами CRLF и финальным байтом DOS EOF 0x1A. Проверены длины всех записей. .sch здесь означает схему обмена, а не готовое расписание.

Различия количества строк и утрата кириллицы показывают, что .dat нельзя использовать как полную актуальную копию .DB. Некоторые поля обмена даже имеют другие длины и имена. Точные смещения приведены в исследовании обменных файлов.

Прочие файлы§

DBDWORK.INI содержит только CRLF, настройки семестра в нем отсутствуют. Groups.VAL относится к правилам допустимости значений и содержит исторический путь к resttemp.DB; сами правила в этом исследовании не декодированы. LOAD.TV хранит параметры табличного представления, имена полей и шрифт. LOAD.FAM описывает семейство связанных файлов. Старые абсолютные пути внутри них не следует принимать за текущие пути установки.

9. Reorder.EXE и установленный технологический стек§

Reorder.EXE — PE32 GUI x86 размером 622 592 байта. Внутри найдены строки Delphi RTL, Borland, idapi32.DLL, TBDEDataSet, компоненты VCL и бинарные DFM-ресурсы. Основная форма имеет заголовок «Перестановка групп», кнопки «Группы», «Аудитории», перемещение вверх/вниз и «Сохранить»; список поддерживает множественное выделение.

Утилита обращается к CLASSES.DB, GRPPLAN.DB, GROUPS.DB, ROOMS.DB, ROOMRSTR.DB. Предположительно она меняет порядок групп/аудиторий с обновлением связанных ключей. Алгоритм сохранения не выполнялся. В бинарнике присутствует SQL delete from Rooms, поэтому запускать его как просмотрщик на рабочей базе было бы неправильно: это средство изменения данных.

Технология/свойство Степень подтверждения
Windows x86, PE32, графическая программа Прямо установлено по заголовку утилиты
Paradox, файловое хранение Прямо установлено по 19 таблицам и индексам
CP866 Указано в заголовках, корректно декодирует русские данные
Delphi RTL, VCL, BDE Прямые строки, компоненты и ресурсы утилиты
Object Pascal как язык исходников Высокая вероятность по совокупности признаков; исходников нет
Тот же стек у главной программы Вероятно; ее EXE не представлен
Конкретная версия Delphi/BDE Не установлена
Автоматический оптимизатор расписания, его алгоритм Не установлен
API, серверная часть, веб-технологии исходной системы В предоставленных файлах не обнаружены
Авторизация, роли, журнал действий Не подтверждены; библиотечные формы входа не доказывают их наличие

Timestamp EXE формально указывает 1992 год, но противоречит внутренним строкам copyright 1999 и признакам Delphi. Датировать программу по нему нельзя. Подробные байтовые смещения и восстановленные ресурсы сохранены в статическом исследовании и машинном протоколе (локальный материал).

BDE остается технологией совместимости; производитель не рекомендует начинать на ней новую разработку. Это аргумент в пользу отдельного современного слоя просмотра, сохраняя BDE только для возможного моста к старой программе. Embarcadero: Using Databases.

10. Как сделать небольшой веб-интерфейс§

Предлагаемая схема§

Закрытая/согласованная копия каталога Paradox
    ↓ чтение, CP866 → Unicode, проверка ключей и счетчиков
SQLite + сведения о происхождении + протокол аномалий
    ↓ сервер только чтения: выборка, поиск, пагинация
Браузер: справочники → планы → занятия → связанные объекты

Для первого варианта достаточно Python и SQLite на сервере, обычного HTML/CSS/JavaScript в браузере. React или отдельная серверная СУБД не обязательны для этого объема и одного снимка. Если появятся одновременное редактирование, несколько семестров и журнал операций, можно перейти к PostgreSQL и полноценному сервису изменений. Это предлагаемая архитектура нового инструмента, а не установленный стек старого приложения.

Веб-браузер не читает Paradox средствами обычного SQL-драйвера. Извлечение выполняется отдельным конвертером или сервером. В этой работе подготовлен небольшой читатель на стандартной библиотеке Python именно для обнаруженных типов полей; дополнительно использована независимая библиотека pxlib для проверки результата. Универсальной поддержки всех файлов Paradox у этого читателя нет.

Страницы первого этапа§

Раздел Содержание и действия просмотра Что требуется для готовности
Карта данных 19 таблиц, счетчики, поля, предупреждения, происхождение Уже извлечено
Группы Поиск по обозначению, факультету, курсу; численность; планы Уже извлечено
Преподаватели Поиск, кафедра, занятия и ограничения Уже извлечено
Аудитории Поиск, вместимость, тип, занятия и ограничения Уже извлечено
Учебный план Дисциплина, кафедра, виды нагрузки, группы/подгруппы Уже извлечено
Занятия Таблица, поиск по дисциплине/преподавателю/аудитории, исходные статусы Уже извлечено
Неназначенные Фильтр Assigned=False, отображение оставшихся координат Уже извлечено
Календарь Недели, даты, чередование, повторение Нужна проверенная временная модель
Свободные аудитории Тип, вместимость, занятость и ограничения Нужны временная модель и правила совместимости
Качество данных Несовпадения ссылок/счетчиков, устаревшие вспомогательные записи Протокол подготовлен

Карточки должны переходить друг в друга по идентификаторам. Для каждой записи полезно показывать исходную таблицу и ключ; это позволит сверять новый просмотрщик с оригиналом. В пользовательских списках основными подписями остаются понятные названия.

Предлагаемые API-операции§

Это контракт для будущей реализации, а не обнаруженные эндпоинты исходной системы:

Метод и путь Назначение
GET /api/meta Дата снимка, счетчики, предупреждения и версии формата
GET /api/groups?q=&faculty_id=&course_id=&offset=&limit= Поиск групп
GET /api/groups/{id} Карточка группы
GET /api/groups/{id}/plans Позиции плана группы с подгруппами
GET /api/teachers?q=&chair_id= Преподаватели
GET /api/rooms?q=&min_capacity=&type= Аудитории
GET /api/plans/{id} План, виды нагрузки, группы и занятия
GET /api/classes?teacher_id=&room_id=&assigned=&offset=&limit= Занятия с прямыми связями
GET /api/restrictions?resource_type=&resource_id= Исходные ограничения

На стороне сервера следует использовать параметры SQL и белый список полей сортировки. В браузере названия и заметки нужно выводить как текст (textContent), поскольку в данных уже встречается буквальная строка  . Автоматически интерпретировать содержимое как HTML или исправлять строки в исходной базе не нужно.

Для SQLite соединение открывается через URI с mode=ro. Пагинация ограничивает объем ответа. Обновление снимка производится отдельной командой экспорта с атомарной заменой готовой SQLite; браузер не должен запускать переписывание Paradox. В предоставленных свободных текстах встречаются служебные заметки и реквизиты дистанционных занятий, поэтому публичный режим следует строить на отдельном явно выбранном наборе полей.

Что нельзя корректно обещать на первом этапе§

Нельзя выдавать за готовую функцию календарь с точными датами, поиск конфликтов по фактическому времени, расчет свободных аудиторий и обратную запись, пока не проверены правила недель и сохранения. Простой фильтр по совпавшим DayNo и TimeNo способен дать кандидатов на пересечение, но не окончательный список конфликтов: нужны четность, повторение, подгруппы, потоки и разрешенные совмещенные занятия.

11. Что уже можно проверить на этой копии§

Подготовлены SQLite с данными (локальный материал), схема JSON (локальный материал) и отдельный JSON для каждой таблицы. Это производные артефакты; оригинальные .DB остались в своем каталоге. SQLite содержит 19 исходных таблиц, служебную _source_manifest и два представления: class_details и plan_group_membership.

Экспорт повторяется из корня проекта:

python3 tools/export_data.py --allow-count-mismatch

Параметр явно разрешает экспорт доступных строк при известном несовпадении счетчика ClassesInf.DB. Без него программа останавливается на этом расхождении. Она не исправляет заголовок и не создает записи по завышенному счетчику; фактическая утрата 13 записей не доказана.

Открыть SQLite для чтения можно стандартным клиентом SQLite или любым совместимым просмотрщиком. Примеры запросов:

-- Реальные счетчики.
SELECT COUNT(*) AS classes FROM Classes;
SELECT COUNT(*) AS groups_count FROM GROUPS;

-- Назначенность: 0 = False, 1 = True в SQLite.
SELECT Assigned, COUNT(*) AS qty
FROM Classes GROUP BY Assigned;

-- Список занятий без выдуманных календарных дат.
SELECT ClassNo, SubjectName, DirectGroupName,
       TeacherName, RoomName, DayNo, TimeName,
       Assigned, EachWeek, OddWeek
FROM class_details ORDER BY ClassNo LIMIT 30;

-- Найти группы текстом. :needle передается параметром, например '%МИН%'.
SELECT g.GroupNo, g.GroupName, c.CourseName, f.FacultyName,
       g.NStudents, g.NSubgroups
FROM GROUPS g
LEFT JOIN Courses c ON c.CourseNo=g.CourseNo
LEFT JOIN FACULTY f ON f.FacultyNo=g.FacultyNo
WHERE g.GroupName LIKE :needle;

-- Участники конкретного плана без повторного подсчета групп.
SELECT DISTINCT GroupNo, GroupName
FROM plan_group_membership WHERE PlanNo=:plan_id;

-- Все занятия группы, включая общие занятия через план.
-- EXISTS не размножает строку из-за нескольких подгрупп в GRPPLAN.
SELECT c.* FROM class_details c
WHERE c.GroupNo=:group_id
   OR (c.GroupNo=-1 AND EXISTS (
       SELECT 1 FROM GRPPLAN gp
       WHERE gp.PlanNo=c.PlanNo AND gp.GroupNo=:group_id
   ))
ORDER BY c.ClassNo;

-- Исходные ограничения аудитории: Week оставлен как исходный код.
SELECT RoomNo, DayNo, TimeNo, Week
FROM ROOMRSTR WHERE RoomNo=:room_id
ORDER BY Week, DayNo, TimeNo;

-- Проверить состояние вспомогательной таблицы.
SELECT file, metadata_json FROM _source_manifest
WHERE file='ClassesInf.DB';

Важно: SQLite LIKE по умолчанию не дает полноценного нечувствительного к регистру поиска по кириллице. Для веб-поиска стоит заранее вычислять нормализованную поисковую строку через Unicode casefold() или использовать подходящий механизм индексирования. Точные Unicode-правила для SQLite описаны в документации выражений SQLite.

В class_details.DirectGroupName может быть NULL при GroupNo=-1; это ожидаемое следствие прямого соединения. Представление не заменяет правила вычисления состава групп. SQLite сохраняет исходные 0/-1/NULL, не добавляет неподтвержденные FK и не переписывает поврежденные значения.

Запрос фильтра группы проверен для всех 554 групп против независимого раскрытия JSON: получено 17 727 пар «занятие–группа», без потерь, лишних записей и дублей. Физических занятий при этом 15 111, а 32 группы не имеют занятий. Протокол: group-query-validation.json (локальный материал).

12. Возможности редактирования и путь к совместимости§

Изменения в самой программе§

По интерфейсу предусмотрены карточки справочников, поля плана и команды переноса/замены в расписании. Для точного перечня доступных операций нужно проверить состояние кнопок и сохранение на тестовой копии. Добавление и удаление по неподписанным пиктограммам пока относятся к интерпретациям. Факультеты, курсы и звонки показаны таблицами; возможность редактирования этих экранов отдельно не доказана.

Изменения через новый веб-слой§

Есть два разных варианта развития:

Вариант Как работает Что нужно восстановить
Совместимый редактор Новый интерфейс передает операции Windows-посреднику, который работает через старый движок и проверенные правила Сохранение исходной программы, индексы, вспомогательные таблицы, блокировки, валидация
Перенос системы SQLite/PostgreSQL становится новой основной БД, функции расписания реализуются заново Полная предметная модель, календарь, генерация, ограничения, пользовательские сценарии

Непосредственно менять байты .DB с веб-сервера не следует. Даже изменение одного ID или аудитории может требовать синхронизации индексов и производных данных. На текущей копии уже видна разница между Classes и ClassesInf, а Reorder.EXE содержит обращения к нескольким таблицам, включая SQL удаления. Фактическая последовательность его сохранения не выполнялась.

Минимальная единица будущего редактирования — понятная операция: «перенести занятие», «заменить преподавателя», «изменить участников плана», а не произвольный SQL UPDATE. Для нее нужны проверка ожидаемой версии записи, проверка ограничений, согласованное сохранение, журнал до/после и возможность отмены. Если базу продолжит менять оригинальная программа, новый слой должен учитывать параллельные изменения и не перетирать их устаревшим снимком.

Проверка поведения на тестовой копии§

Эксперимент Что наблюдать в интерфейсе Что сравнить в файлах
Открыть копию и закрыть без действий Ошибки, выбранный период Меняются ли счетчики/вспомогательные таблицы сами
Изменить одну подпись группы Видимое имя в списке и сетке GROUPS, индексы, неизменность ключа
Перенести одно занятие в пределах недели Старое/новое положение Classes, ClassesInf, DayNo, TimeNo
Перенести между четной/нечетной и следующей парой недель Выбор недели и даты Кодирование DayNo, OddWeek, EachWeek
Отменить назначение Переход в «Не назначены» Assigned, сохранение старых координат
Сменить аудиторию/преподавателя Новые сведения занятия Основные и дополнительные связи, ограничения
Изменить Stable у одной позиции Доступность переноса, отображение Plan, ClassesInf, другие связанные строки
Изменить объем/деление нагрузки Число элементов и список подгрупп PLANITEM, GRPPLAN, генерация Classes
Открыть «База данных» и «Параметры» Начало семестра, пути, периоды Конфигурация вне каталога данных
Создать заведомое пересечение на копии Запрет, предупреждение или разрешение Какие виды ограничений реально проверяются

Нужно сравнивать нормализованные записи, а не только бинарные размеры: индексы и служебные счетчики могут изменяться без изменения пользовательских данных. Для каждого опыта следует начинать с отдельной копии одного и того же состояния. Эти эксперименты пока не выполнялись.

13. Воспроизводимость и результаты проверки§

Проверка Результат
Чтение схем всех .DB 19 схем, известные типы, размеры полей согласованы с размером записи
Проверка цепочек блоков Пройдены ссылки вперед/назад, границы, количество записей
Счетчики в заголовках Совпадают у 18 таблиц; расхождение 13 у ClassesInf.DB
Независимое чтение pxlib Все 75 909 доступных записей совпали как мультимножества после нормализации пустых строк и NULL
Пустое числовое значение в pxlib В пяти CHAIRS.FacultyNo pxlib возвращает -2147483648; нормализовано в NULL согласно формату
Первичные ключи в SQLite Таблицы созданы с ключами из заголовков; загрузка не выявила нарушения этих ключей
PRAGMA integrity_check ok
Соединение class_details 15 111 строк, соединения не размножили записи занятий
Фильтр расписания группы Совпадение с независимым раскрытием JSON для всех 554 групп; 17 727 пар «занятие–группа»
Целостность исходных файлов SHA-256 всех 65 файлов каталога семестра совпали до и после экспорта
Проверка всех пяти DAT Длины записей и позиции разделителей соответствуют SCH
Просмотр скриншотов Все 15 просмотрены, функции привязаны к файлам
Запуск оригинальной программы и запись Paradox Не выполнялись

Проверка через pxlib проводилась на временных копиях. Установленный пакет pypxlib 2.5 содержит библиотеку macOS x86_64; на этом Mac он проверен через arch -x86_64 python3. Рабочий экспортер от pypxlib не зависит и выполняется обычным Python 3.11. Протокол сравнения: pxlib-validation.json (локальный материал); библиотека сравнения: pypxlib.

Читатель tools/paradox_read.py рассчитан на нешифрованные .DB с обнаруженными типами и уровнями формата. Он не разбирает .VAL, не проверяет согласованность записей всех .PX/.XG/.YG, не восстанавливает удаленные записи и не умеет сохранять Paradox. Флаг разрешения несовпадающего счетчика не отключает проверки границ и структуры блоков.

14. Какие дополнительные материалы дадут наибольший эффект§

Для текущего описания и просмотра извлеченных данных дополнительная информация не обязательна. Для проверки программы и редактора наиболее полезны:

  1. Основной EXE вместе с каталогом установки, версия из «О программе» и, если сохранились, исходники Delphi.
  2. Скриншоты окон «Параметры», «База данных», настроек периода и выбора недели.
  3. Подтверждение, к какому состоянию базы относятся изображения сентября 2024 года, и известная фактическая дата одного занятия из переданной копии.
  4. Две копии базы до и после одного контролируемого переноса занятия и смены четности недели.
  5. Пояснение, что оператор понимает под «Стабильное», «Отдать на кафедру», «Отменить», «час» и «поток».
  6. Приоритет следующего этапа: просмотр/поиск или запись изменений с сохранением работы старой программы.

Эти материалы позволят перейти от восстановленной структуры к проверенному описанию бизнес-алгоритмов. Уже сейчас карту файлов, справочники, планы и исходные позиции можно исследовать через подготовленную SQLite.

15. Конкретные вопросы качества данных§

Наблюдение Значение для интерпретации Следующий шаг
ClassesInf: 15 124 в заголовке, 15 111 в активных блоках Счетчик не согласован с доступными записями; это подтвердили два читателя Проверить открытие/закрытие на копии; не придумывать недостающие строки
Одна аудитория расходится между Classes и ClassesInf PlanNo=226555, DayNo=16, TimeNo=3, OddWeek=True: 10141 против 10151 Сверить с оригинальным приложением, какой источник оно показывает
Две CHAIRS.FacultyNo ссылаются на отсутствующие ID 46 и 48 Нарушена предполагаемая связь с факультетами Уточнить правильные подразделения; до этого LEFT JOIN и явное предупреждение
Пять CHAIRS.FacultyNo равны NULL Подразделение не задано Сохранять отсутствие значения, не приписывать факультет
2 339 Assigned=True без аудитории; 23 из них без преподавателя Назначенность не равна полной укомплектованности ресурсов Отдельно показывать оба признака; не называть все случаи ошибками
Все 554 GROUPS.StreamNo=-1 Именованный справочник потоков фактически не связан с группами Состав занятий брать через GRPPLAN
5 068 дисциплин, 5 028 различных названий Совпадение названий не означает одинаковый объект Соединять по SubjectNo
47 кафедр, 33 различных названия Есть совпадения/служебные обозначения Соединять по ChairNo
Буквальное   в названиях Служебная HTML-последовательность стала текстом Отображать безопасно; исправлять только после предметной сверки
DAT существенно отличаются от DB и потеряли кириллицу Обменные файлы не являются актуальной полной копией Основной источник — DB

Все положительные ссылки основного плана, групп, элементов нагрузки и занятий, кроме двух указанных связей кафедр, найдены в ожидаемых справочниках. Все 15 111 пар (PlanNo, PlanType) занятий существуют в PLANITEM. Все явные группы/подгруппы занятий входят в соответствующие GRPPLAN; номера подгрупп укладываются в число подгрупп группы.

1 674 позиции плана связаны с несколькими группами, максимум — с 21. Всего 4 748 позиций имеют хотя бы одну группу. Без ссылок из других выгруженных таблиц остаются 4 066 дисциплин, 82 преподавателя, 19 аудиторий, 32 группы и 140 потоков. Это может быть исторический запас справочников; эти строки не удалялись и не объявляются лишними.

Подробные агрегаты и методика: анализ связей, машинные метрики (локальный материал).

Приложение A. Полный словарь 88 полей§

Типы, размеры и порядок ключей прочитаны из заголовков файлов. Описания назначения восстановлены по именам, значениям и интерфейсу; неоднозначные поля отмечены. Столбец PK отражает первичный ключ формата, а не обязательность всех прочих полей. Правила .VAL отдельно не восстановлены.

Alpha — строка фиксированной длины в байтах CP866; Short — знаковое 16-битное число; Long и AutoIncrement — 32-битные числа; Logical — логическое значение с возможным NULL. Пустой Alpha в экспорте представлен пустой строкой, логические значения в JSON — true/false/null, в SQLite — 1/0/NULL. Размер в UTF-8 может быть больше исходного байтового лимита.

A. CHAIRS.DB — Кафедры и принадлежность факультету§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 47; счетчик заголовка: 47; ключ: ChairNo. Формат Paradox 5, кодировка cp866, размер записи 58 байт. Внутреннее имя: CHAIRS.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
ChairNo AutoIncrement / 4 Да Идентификатор кафедры; ссылка на CHAIRS вне самой CHAIRS. Служебные 0/-1 зависят от таблицы. NULL: 0; диапазон: 464…521
ChairName Alpha / 50 Название кафедры; не уникальный ключ. Пустых: 0; различных: 33; макс. длина: 27
FacultyNo Long / 4 Идентификатор факультета; ссылка на FACULTY. В CHAIRS есть NULL и две отсутствующие положительные ссылки. NULL: 5; диапазон: 46…57

A. CLASSINF.DB — Дополнительные ресурсы занятия; таблица пуста§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 0; счетчик заголовка: 0; ключ: ClassNo, RoomNo. Формат Paradox 5, кодировка cp866, размер записи 12 байт. Внутреннее имя: CLASSINF.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
ClassNo Long / 4 Да Идентификатор занятия; ключ Classes, ссылка из CLASSINF. Таблица пуста
RoomNo Long / 4 Да Идентификатор аудитории; ссылка на Rooms. В Classes значение -1 означает отсутствие указанной аудитории. Таблица пуста
TeacherNo Long / 4 Идентификатор преподавателя; ссылка на TEACHERS. В Classes значение -1 означает отсутствие указанного преподавателя. Таблица пуста

A. Classes.DB — Основные записи занятий§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 15111; счетчик заголовка: 15111; ключ: ClassNo. Формат Paradox 5, кодировка cp866, размер записи 94 байт. Внутреннее имя: Classes.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
ClassNo AutoIncrement / 4 Да Идентификатор занятия; ключ Classes, ссылка из CLASSINF. NULL: 0; диапазон: 710248…732032
GroupNo Long / 4 Идентификатор группы; ссылка на GROUPS. В Classes при -1 состав определяется через GRPPLAN. NULL: 0; диапазон: -1…434159
Subgroup Short / 2 Номер подгруппы. В GRPPLAN 1–5; в Classes также -1 без конкретной подгруппы. NULL: 0; диапазон: -1…5
PlanNo Long / 4 Идентификатор позиции плана; ссылка на Plan вне самой Plan. NULL: 0; диапазон: 222250…229104
PlanType Alpha / 1 Однобайтовый кириллический код вида занятия. Шесть кодов; точная расшифровка сверяется с программой. Пустых: 0; различных: 6; макс. длина: 1
EachWeek Logical / 1 Флаг, по имени — еженедельность. Приоритет над OddWeek и алгоритм повторения требуют проверки. True: 23; False: 15088; NULL: 0
Assigned Logical / 1 Флаг назначенности по имени и сопоставлению интерфейса. Не гарантирует наличие аудитории/преподавателя. True: 11530; False: 3581; NULL: 0
OddWeek Logical / 1 Флаг варианта недели, по имени — нечетная. NULL возможен без позиции; календарная привязка не установлена. True: 6035; False: 5783; NULL: 3293
DayNo Short / 2 В DAYS и ограничениях код дня 0–5; в Classes/ClassesInf составной код 0–299 или NULL, не прямой FK на DAYS. NULL: 3293; диапазон: 0…299
TimeNo Short / 2 Номер временной позиции TIMES (1–8); в занятиях возможен NULL. NULL: 3293; диапазон: 1…8
TeacherNo Long / 4 Идентификатор преподавателя; ссылка на TEACHERS. В Classes значение -1 означает отсутствие указанного преподавателя. NULL: 0; диапазон: -1…47553
RoomNo Long / 4 Идентификатор аудитории; ссылка на Rooms. В Classes значение -1 означает отсутствие указанной аудитории. NULL: 0; диапазон: -1…10179
Comment Alpha / 64 Текстовый комментарий занятия. Не использовать для восстановления ключей и состава групп. Пустых: 12196; различных: 247; макс. длина: 64

A. ClassesInf.DB — Предположительно производные позиции расписания; есть рассогласование§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 15111; счетчик заголовка: 15124; ключ: не задан. Формат Paradox 5, кодировка cp866, размер записи 16 байт. Внутреннее имя: resttemp.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
PlanNo Long / 4 Идентификатор позиции плана; ссылка на Plan вне самой Plan. NULL: 0; диапазон: 222250…229104
RoomNo Long / 4 Идентификатор аудитории; ссылка на Rooms. В Classes значение -1 означает отсутствие указанной аудитории. NULL: 0; диапазон: -1…10179
EachWeek Logical / 1 Флаг, по имени — еженедельность. Приоритет над OddWeek и алгоритм повторения требуют проверки. True: 23; False: 15088; NULL: 0
OddWeek Logical / 1 Флаг варианта недели, по имени — нечетная. NULL возможен без позиции; календарная привязка не установлена. True: 6035; False: 5783; NULL: 3293
Assigned Logical / 1 Флаг назначенности по имени и сопоставлению интерфейса. Не гарантирует наличие аудитории/преподавателя. True: 11530; False: 3581; NULL: 0
DayNo Short / 2 В DAYS и ограничениях код дня 0–5; в Classes/ClassesInf составной код 0–299 или NULL, не прямой FK на DAYS. NULL: 3293; диапазон: 0…299
TimeNo Short / 2 Номер временной позиции TIMES (1–8); в занятиях возможен NULL. NULL: 3293; диапазон: 1…8
Stable Logical / 1 Флаг «Стабильное» из плана; действие на редактирование/размещение не доказано. True: 11491; False: 3620; NULL: 0

Предупреждение: Header declares 15124 rows; active block chain contains 15111.

A. Courses.DB — Классификатор курсов и уровней обучения§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 12; счетчик заголовка: 12; ключ: CourseNo. Формат Paradox 7, кодировка cp866, размер записи 261 байт. Внутреннее имя: Courses.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
CourseNo AutoIncrement / 4 Да Идентификатор записи Courses; не обязательно номер года обучения. NULL: 0; диапазон: 1…12
CourseCount Short / 2 Числовой атрибут классификатора. Во всех 12 строках равен CourseNo; не является надежным номером года обучения. Роль не установлена. NULL: 0; диапазон: 1…12
CourseName Alpha / 255 Отображаемое название курса, включая магистратуру/аспирантуру. Пустых: 0; различных: 12; макс. длина: 21

A. DAYS.DB — Дни шестидневной недели§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 6; счетчик заголовка: 6; ключ: DayNo. Формат Paradox 4, кодировка cp866, размер записи 15 байт. Внутреннее имя: resttemp.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
DayNo Short / 2 Да В DAYS и ограничениях код дня 0–5; в Classes/ClassesInf составной код 0–299 или NULL, не прямой FK на DAYS. NULL: 0; диапазон: 0…5
DayName Alpha / 11 Полное название дня. Пустых: 0; различных: 6; макс. длина: 11
ShortDayName Alpha / 2 Краткое название дня для отображения. Пустых: 0; различных: 6; макс. длина: 2

A. FACULTY.DB — Факультеты / организационные подразделения§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 6; счетчик заголовка: 6; ключ: FacultyNo. Формат Paradox 5, кодировка cp866, размер записи 36 байт. Внутреннее имя: FACULTY.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
FacultyNo AutoIncrement / 4 Да Идентификатор факультета; ссылка на FACULTY. В CHAIRS есть NULL и две отсутствующие положительные ссылки. NULL: 0; диапазон: 52…57
FacultyName Alpha / 32 Отображаемое название факультета/подразделения. Пустых: 0; различных: 6; макс. длина: 4

A. GROUPS.DB — Учебные группы§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 554; счетчик заголовка: 554; ключ: GroupNo. Формат Paradox 5, кодировка cp866, размер записи 28 байт. Внутреннее имя: GROUPS.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
GroupNo AutoIncrement / 4 Да Идентификатор группы; ссылка на GROUPS. В Classes при -1 состав определяется через GRPPLAN. NULL: 0; диапазон: 433604…434159
GroupName Alpha / 8 Обозначение группы; для связи использовать GroupNo. Пустых: 0; различных: 554; макс. длина: 8
FacultyNo Long / 4 Идентификатор факультета; ссылка на FACULTY. В CHAIRS есть NULL и две отсутствующие положительные ссылки. NULL: 0; диапазон: 52…57
NSubgroups Short / 2 Количество подгрупп группы (в этой копии 1–5). NULL: 0; диапазон: 1…5
NStudents Short / 2 Количество студентов группы; распределение студентов по отдельным подгруппам отдельно не хранится здесь. NULL: 0; диапазон: 1…93
StreamNo Long / 4 Идентификатор STREAMS или служебное -1. В GROUPS все значения -1. NULL: 0; диапазон: -1…-1
CourseNo Long / 4 Идентификатор записи Courses; не обязательно номер года обучения. NULL: 0; диапазон: 1…11

A. GRPPLAN.DB — Участие групп и подгрупп в позиции плана§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 21419; счетчик заголовка: 21419; ключ: GroupNo, Subgroup, PlanNo. Формат Paradox 5, кодировка cp866, размер записи 10 байт. Внутреннее имя: GRPPLAN.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
GroupNo Long / 4 Да Идентификатор группы; ссылка на GROUPS. В Classes при -1 состав определяется через GRPPLAN. NULL: 0; диапазон: 433604…434159
Subgroup Short / 2 Да Номер подгруппы. В GRPPLAN 1–5; в Classes также -1 без конкретной подгруппы. NULL: 0; диапазон: 1…5
PlanNo Long / 4 Да Идентификатор позиции плана; ссылка на Plan вне самой Plan. NULL: 0; диапазон: 222250…229104

A. PLANITEM.DB — Вид, объем нагрузки и деление на подгруппы§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 7098; счетчик заголовка: 7098; ключ: PlanNo, PlanType. Формат Paradox 5, кодировка cp866, размер записи 8 байт. Внутреннее имя: resttemp.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
PlanNo Long / 4 Да Идентификатор позиции плана; ссылка на Plan вне самой Plan. NULL: 0; диапазон: 222250…229104
PlanType Alpha / 1 Да Однобайтовый кириллический код вида занятия. Шесть кодов; точная расшифровка сверяется с программой. Пустых: 0; различных: 6; макс. длина: 1
PlanQty Short / 2 Объем по виду занятия. Интерфейс называет часами; единица и преобразование в Classes требуют проверки. NULL: 0; диапазон: 1…18
GrpSplit Logical / 1 Разделять вид занятия по подгруппам; соответствует флажкам плана и фактическим подгруппам. True: 772; False: 6326; NULL: 0

A. PLANROOM.DB — Связь плана/вида с аудиториями; таблица пуста§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 0; счетчик заголовка: 0; ключ: PlanNo, PlanType, RoomNo. Формат Paradox 5, кодировка cp866, размер записи 9 байт. Внутреннее имя: PLANROOM.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
PlanNo Long / 4 Да Идентификатор позиции плана; ссылка на Plan вне самой Plan. Таблица пуста
PlanType Alpha / 1 Да Однобайтовый кириллический код вида занятия. Шесть кодов; точная расшифровка сверяется с программой. Таблица пуста
RoomNo Long / 4 Да Идентификатор аудитории; ссылка на Rooms. В Classes значение -1 означает отсутствие указанной аудитории. Таблица пуста

A. Plan.DB — Позиции учебного плана§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 4748; счетчик заголовка: 4748; ключ: PlanNo. Формат Paradox 5, кодировка cp866, размер записи 13 байт. Внутреннее имя: resttemp.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
PlanNo AutoIncrement / 4 Да Идентификатор позиции плана; ссылка на Plan вне самой Plan. NULL: 0; диапазон: 222250…229104
SubjectNo Long / 4 Идентификатор дисциплины; ссылка на SUBJECTS. NULL: 0; диапазон: 2295…7641
ChairNo Long / 4 Идентификатор кафедры; ссылка на CHAIRS вне самой CHAIRS. Служебные 0/-1 зависят от таблицы. NULL: 0; диапазон: 465…521
Stable Logical / 1 Флаг «Стабильное» из плана; действие на редактирование/размещение не доказано. True: 3738; False: 1010; NULL: 0

A. ROOMRSTR.DB — Ограничения аудиторий§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 990; счетчик заголовка: 990; ключ: RoomNo, DayNo, TimeNo, Week. Формат Paradox 5, кодировка cp866, размер записи 74 байт. Внутреннее имя: resttemp.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
RoomNo Long / 4 Да Идентификатор аудитории; ссылка на Rooms. В Classes значение -1 означает отсутствие указанной аудитории. NULL: 0; диапазон: 10041…10179
DayNo Short / 2 Да В DAYS и ограничениях код дня 0–5; в Classes/ClassesInf составной код 0–299 или NULL, не прямой FK на DAYS. NULL: 0; диапазон: 0…5
TimeNo Short / 2 Да Номер временной позиции TIMES (1–8); в занятиях возможен NULL. NULL: 0; диапазон: 1…8
Week Short / 2 Да Код варианта недели ограничения: 0 или 1; соответствие четной/нечетной неделе требует проверки. NULL: 0; диапазон: 0…1
Reason Alpha / 64 Причина/заметка ограничения; свободный текст может включать служебные сведения. Пустых: 0; различных: 75; макс. длина: 64

A. Rooms.DB — Аудитории§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 184; счетчик заголовка: 184; ключ: RoomNo. Формат Paradox 5, кодировка cp866, размер записи 84 байт. Внутреннее имя: resttemp.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
RoomNo AutoIncrement / 4 Да Идентификатор аудитории; ссылка на Rooms. В Classes значение -1 означает отсутствие указанной аудитории. NULL: 0; диапазон: 9994…10179
RoomName Alpha / 8 Обозначение аудитории; отдельного справочника корпусов в копии не найдено. Пустых: 0; различных: 184; макс. длина: 8
RoomCap Short / 2 Вместимость аудитории; наличие поля не доказывает обязательную проверку при размещении. NULL: 0; диапазон: 1…210
RoomSpec Logical / 1 Логический признак помещения; все False, точный смысл не установлен. True: 0; False: 184; NULL: 0
RoomType Alpha / 1 Код назначения помещения; отдельный классификатор от PlanType. В копии с/л/п/к. Пустых: 0; различных: 4; макс. длина: 1
RoomMemo Alpha / 64 Замечания об аудитории. Пустых: 182; различных: 3; макс. длина: 34
ChairNo Long / 4 Идентификатор кафедры; ссылка на CHAIRS вне самой CHAIRS. Служебные 0/-1 зависят от таблицы. NULL: 0; диапазон: -1…516

A. STREAMS.DB — Именованный справочник потоков/периодов§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 140; счетчик заголовка: 140; ключ: StreamNo. Формат Paradox 5, кодировка cp866, размер записи 259 байт. Внутреннее имя: STREAMS.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
StreamNo AutoIncrement / 4 Да Идентификатор STREAMS или служебное -1. В GROUPS все значения -1. NULL: 0; диапазон: 374…568
StreamName Alpha / 255 Название потока/периода. Может содержать исторические учебные годы. Пустых: 0; различных: 140; макс. длина: 51

A. SUBJECTS.DB — Дисциплины и краткие названия§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 5068; счетчик заголовка: 5068; ключ: SubjectNo. Формат Paradox 5, кодировка cp866, размер записи 50 байт. Внутреннее имя: SUBJECTS.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
SubjectNo AutoIncrement / 4 Да Идентификатор дисциплины; ссылка на SUBJECTS. NULL: 0; диапазон: 2293…7641
SubjectName Alpha / 35 Полное/основное название дисциплины с историческим ограничением длины. Пустых: 0; различных: 5028; макс. длина: 35
SubjectChar Alpha / 1 Однобайтовый условный символ дисциплины; точная роль в интерфейсе не подтверждена. Пустых: 5068; различных: 1; макс. длина: 0
SubjectShortName Alpha / 10 Краткое название дисциплины для компактного отображения. Пустых: 0; различных: 4667; макс. длина: 10

A. TCHRRSTR.DB — Ограничения преподавателей§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 4541; счетчик заголовка: 4541; ключ: TeacherNo, DayNo, TimeNo, Week. Формат Paradox 5, кодировка cp866, размер записи 74 байт. Внутреннее имя: TCHRRSTR.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
TeacherNo Long / 4 Да Идентификатор преподавателя; ссылка на TEACHERS. В Classes значение -1 означает отсутствие указанного преподавателя. NULL: 0; диапазон: 43451…47547
DayNo Short / 2 Да В DAYS и ограничениях код дня 0–5; в Classes/ClassesInf составной код 0–299 или NULL, не прямой FK на DAYS. NULL: 0; диапазон: 0…5
TimeNo Short / 2 Да Номер временной позиции TIMES (1–8); в занятиях возможен NULL. NULL: 0; диапазон: 1…8
Week Short / 2 Да Код варианта недели ограничения: 0 или 1; соответствие четной/нечетной неделе требует проверки. NULL: 0; диапазон: 0…1
Reason Alpha / 64 Причина/заметка ограничения; свободный текст может включать служебные сведения. Пустых: 0; различных: 1019; макс. длина: 64

A. TEACHERS.DB — Преподаватели§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 866; счетчик заголовка: 866; ключ: TeacherNo. Формат Paradox 5, кодировка cp866, размер записи 126 байт. Внутреннее имя: TEACHERS.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
TeacherNo AutoIncrement / 4 Да Идентификатор преподавателя; ссылка на TEACHERS. В Classes значение -1 означает отсутствие указанного преподавателя. NULL: 0; диапазон: 43451…47553
TeacherName Alpha / 30 Фамилия и инициалы/отображаемое имя преподавателя; не использовать как ключ. Пустых: 0; различных: 866; макс. длина: 19
ChairNo Long / 4 Идентификатор кафедры; ссылка на CHAIRS вне самой CHAIRS. Служебные 0/-1 зависят от таблицы. NULL: 0; диапазон: -1…521
TeacherDegree Alpha / 16 Ученая степень. Пустых: 552; различных: 40; макс. длина: 16
TeacherPosition Alpha / 16 Должность. Пустых: 55; различных: 10; макс. длина: 13
TeacherTitle Alpha / 16 Ученое звание. Пустых: 865; различных: 2; макс. длина: 13
TeacherMemo Alpha / 40 Замечания о преподавателе. Пустых: 852; различных: 15; макс. длина: 39

A. TIMES.DB — Временные позиции и начала занятий§

Источник: файл (локальный материал); JSON (локальный материал). Активных строк: 8; счетчик заголовка: 8; ключ: TimeNo. Формат Paradox 4, кодировка cp866, размер записи 12 байт. Внутреннее имя: TIME.DB.

Поле Тип / байт PK Назначение Наблюдения по данным
TimeNo Short / 2 Да Номер временной позиции TIMES (1–8); в занятиях возможен NULL. NULL: 0; диапазон: 1…8
TimeName Alpha / 10 Строка начала занятия, например 8:00. Конец и длительность здесь отсутствуют. Пустых: 0; различных: 8; макс. длина: 5

Приложение B. Все 65 файлов каталога семестра§

Размеры приведены для предоставленного снимка. SHA-256 каждого файла находятся в source-manifest.json (локальный материал). Ссылки ведут на оригинальные файлы; для чтения данных удобнее SQLite/JSON.

Файл Байт Содержимое / назначение
chairs.dat (локальный материал) 3 389 Обменные строки фиксированной ширины: Кафедры и принадлежность факультету; кириллица заменена #
CHAIRS.DB (локальный материал) 6 144 Кафедры и принадлежность факультету
CHAIRS.PX (локальный материал) 4 096 Первичный индекс CHAIRS.DB
chairs.sch (локальный материал) 213 Схема полей/длин/смещений chairs.dat; Filetype=Fixed
Classes.DB (локальный материал) 3 801 088 Основные записи занятий
Classes.PX (локальный материал) 34 816 Первичный индекс Classes.DB
Classes.XG0 (локальный материал) 456 704 Вторичный индекс PlanNoIdx: PlanNo + ClassNo
Classes.XG1 (локальный материал) 512 000 Вторичный индекс TeacherNoIdx: TeacherNo + ClassNo
Classes.YG0 (локальный материал) 8 192 Индексная структура для classes.xg0; полное дерево не проверено
Classes.YG1 (локальный материал) 10 240 Индексная структура для classes.xg1; полное дерево не проверено
ClassesInf.DB (локальный материал) 544 768 Предположительно производные позиции расписания; есть рассогласование
CLASSINF.DB (локальный материал) 2 048 Дополнительные ресурсы занятия; таблица пуста
CLASSINF.PX (локальный материал) 2 048 Первичный индекс CLASSINF.DB
Courses.DB (локальный материал) 6 144 Классификатор курсов и уровней обучения
Courses.PX (локальный материал) 4 096 Первичный индекс Courses.DB
DAYS.DB (локальный материал) 4 096 Дни шестидневной недели
DAYS.PX (локальный материал) 4 096 Первичный индекс DAYS.DB
DBDWORK.INI (локальный материал) 2 Только CRLF; полезных настроек нет
FACULTY.DB (локальный материал) 4 096 Факультеты / организационные подразделения
FACULTY.PX (локальный материал) 4 096 Первичный индекс FACULTY.DB
groups.dat (локальный материал) 9 049 Обменные строки фиксированной ширины: Учебные группы; кириллица заменена #
GROUPS.DB (локальный материал) 18 432 Учебные группы
GROUPS.PX (локальный материал) 4 096 Первичный индекс GROUPS.DB
groups.sch (локальный материал) 341 Схема полей/длин/смещений groups.dat; Filetype=Fixed
Groups.VAL (локальный материал) 349 Правила допустимости/метаданные GROUPS; содержательные правила не декодированы
GROUPS.XG0 (локальный материал) 8 192 Вторичный индекс GroupStreamIdx: StreamNo + GroupNo
GROUPS.YG0 (локальный материал) 4 096 Индексная структура для groups.xg0; полное дерево не проверено
GRPPLAN.DB (локальный материал) 235 520 Участие групп и подгрупп в позиции плана
GRPPLAN.PX (локальный материал) 4 096 Первичный индекс GRPPLAN.DB
GRPPLAN.XG0 (локальный материал) 718 848 Вторичный индекс PlanGroupIdx: PlanNo GroupNo Subgroup + первичный ключ
GRPPLAN.YG0 (локальный материал) 16 384 Индексная структура для grpplan.xg0; полное дерево не проверено
LOAD.FAM (локальный материал) 240 Метаданные семейства; ссылки на CLASSES.TV
LOAD.PX (локальный материал) 4 096 Индекс исторического LOAD; одноименного LOAD.DB в снимке нет
LOAD.TV (локальный материал) 2 096 Настройки табличного представления :WORK:CLASSES.DB
Plan.DB (локальный материал) 229 376 Позиции учебного плана
Plan.PX (локальный материал) 4 096 Первичный индекс Plan.DB
PLANITEM.DB (локальный материал) 212 992 Вид объем нагрузки и деление на подгруппы
PLANITEM.PX (локальный материал) 4 096 Первичный индекс PLANITEM.DB
PLANROOM.DB (локальный материал) 2 048 Связь плана/вида с аудиториями; таблица пуста
PLANROOM.PX (локальный материал) 2 048 Первичный индекс PLANROOM.DB
Reorder.EXE (локальный материал) 622 592 Утилита перестановки групп/аудиторий Windows x86 Delphi/VCL/BDE; не запускалась
ROOMRSTR.DB (локальный материал) 354 304 Ограничения аудиторий
ROOMRSTR.PX (локальный материал) 8 192 Первичный индекс ROOMRSTR.DB
rooms.dat (локальный материал) 4 811 Обменные строки фиксированной ширины: Аудитории; кириллица заменена #
Rooms.DB (локальный материал) 22 528 Аудитории
Rooms.PX (локальный материал) 4 096 Первичный индекс Rooms.DB
rooms.sch (локальный материал) 210 Схема полей/длин/смещений rooms.dat; Filetype=Fixed
STREAMS.DB (локальный материал) 51 200 Именованный справочник потоков/периодов
STREAMS.PX (локальный материал) 4 096 Первичный индекс STREAMS.DB
STREAMS.XG0 (локальный материал) 61 440 Вторичный индекс StreamNameIdx: StreamName + StreamNo; имена в верхнем регистре
STREAMS.YG0 (локальный материал) 18 432 Индексная структура для streams.xg0; полное дерево не проверено
subjects.dat (локальный материал) 123 691 Обменные строки фиксированной ширины: Дисциплины и краткие названия; кириллица заменена #
SUBJECTS.DB (локальный материал) 296 960 Дисциплины и краткие названия
SUBJECTS.PX (локальный материал) 4 096 Первичный индекс SUBJECTS.DB
subjects.sch (локальный материал) 223 Схема полей/длин/смещений subjects.dat; Filetype=Fixed
TCHRRSTR.DB (локальный материал) 1 038 336 Ограничения преподавателей
TCHRRSTR.PX (локальный материал) 18 432 Первичный индекс TCHRRSTR.DB
teachers.dat (локальный материал) 69 332 Обменные строки фиксированной ширины: Преподаватели; кириллица заменена #
TEACHERS.DB (локальный материал) 215 040 Преподаватели
TEACHERS.PX (локальный материал) 4 096 Первичный индекс TEACHERS.DB
teachers.sch (локальный материал) 357 Схема полей/длин/смещений teachers.dat; Filetype=Fixed
TEACHERS.XG0 (локальный материал) 18 432 Вторичный индекс TeacherFacultyIdx: фактически ChairNo + TeacherNo
TEACHERS.YG0 (локальный материал) 4 096 Индексная структура для teachers.xg0; полное дерево не проверено
TIMES.DB (локальный материал) 4 096 Временные позиции и начала занятий
TIMES.PX (локальный материал) 4 096 Первичный индекс TIMES.DB

Внешние служебные файлы в DB§

Файл Байт Назначение
PARADOX.LCK (локальный материал) 110 Файл блокировок Paradox
PDOXUSRS.LCK (локальный материал) 21 504 Файл блокировок BDE; содержит исторический путь E:\LOCK\ и имена таблиц
.DS_Store Метаданные просмотра папки macOS, не часть логики расписания

В каталоге семестра 65 файлов, еще два файла приложения — блокировки в родительском DB. .DS_Store не включен в эти 67 файлов приложения. По содержимому копии блокировок нельзя определить активных пользователей. В отчете форматов указаны байтовые доказательства.

Что проверено у индексов§

Все шесть мультимножеств вторичных ключей вместе с первичными ключами совпали с соответствующими DB; для STREAMS применено приведение регистра. Поля индексов перечислены в инвентаре выше. При этом индексное дерево YG и полное поведение поиска BDE не проверялись. В служебном Blk Num есть расхождения с текущими физическими блоками: их смысл требует проверки движком и не трактуется здесь как доказанное повреждение. Подробности: исследование индексов.

Приложение C. Полный каталог функций по скриншотам§

Здесь «видна» означает видимый экран/подписанную команду; «предполагается» — вывод по форме или неподписанной пиктограмме.

Функция Статус и источник
1 Открыть список групп Видна — 1, 3
2 Найти/отфильтровать группы Видно поле — 3; логика поиска не показана
3 Вести факультет, численность, подгруппы и курс группы Видны поля — 3; сохранение не показано
4 Добавить/изменить/удалить группу Предполагается по пиктограммам — 3
5 Открыть список преподавателей Видна — 1, 4
6 Найти/отфильтровать преподавателя Видно поле — 4
7 Вести кафедру, должность, звание, степень, замечания преподавателя Видны поля — 4
8 Добавить/изменить/удалить преподавателя Предполагается по пиктограммам — 4
9 Открыть список дисциплин Видна — 1, 5
10 Найти/отфильтровать дисциплину Видно поле — 5
11 Вести полное и краткое название дисциплины Видны поля — 5
12 Добавить/изменить/удалить дисциплину Предполагается по пиктограммам — 5
13 Открыть список аудиторий Видна — 1, 6
14 Найти/отфильтровать аудиторию Видно поле — 6
15 Вести вместимость, назначение, кафедру, замечания аудитории Видны поля — 6
16 Добавить/изменить/удалить аудиторию Предполагается по пиктограммам — 6
17 Открыть список кафедр Видна — 1, 7
18 Найти/отфильтровать кафедру Видно поле — 7
19 Связать кафедру с факультетом Видно поле — 7
20 Добавить/изменить кафедру Предполагается по пиктограммам — 7
21 Просмотреть факультеты Видна — 1, 8
22 Просмотреть учебный план выбранной группы Видна — 1, 9
23 Указать дисциплину и кафедру в плане Видны поля — 9
24 Указать недельную нагрузку по лекциям, практикам, лабораторным Видны поля — 9
25 Учитывать проведение практик/лабораторных по подгруппам Видны флажки — 9
26 Учитывать экзамены, консультации, зачеты Видны блоки — 9; поведение ввода не показано
27 Задать признак «Стабильное» Видны флажок и значения — 9; смысл неизвестен
28 Просмотреть группы, объединенные для записи плана Видно поле «Поток» — 9
29 Добавить/изменить/удалить запись учебного плана Предполагается по пиктограммам — 9
30 Просмотреть классификатор курсов и уровней обучения Видна — 1, 10
31 Просмотреть потоки и состав групп Видна — 1, 11
32 Создать поток Видна кнопка «Новый» — 11
33 Удалить поток Видна кнопка «Удалить» — 11
34 Включить/исключить группу из потока Предполагается по стрелкам и спискам — 11
35 Выбрать режим потока «Полное»/«Нечетная»/«Четная»/«Экзамены» Кнопки видны, неактивны — 11; результат неизвестен
36 Просмотреть начала занятий Видна таблица «Звонки» — 1, 12
37 Открыть общее расписание Видна сетка — 14, 15; вероятный переход «Основной вид» — 2
38 Выбрать неделю Видно поле — 14, 15
39 Просмотреть занятия по дням, позициям и группам Видна сетка — 14, 15
40 Просмотреть детали занятия при наведении Видна всплывающая карточка — 14
41 Просмотреть неназначенные занятия Видна панель — 14, 15
42 Обновить представление расписания Видна кнопка «Обновить» — 14, 15
43 Отменить выбранный элемент Видна команда — 15; точная семантика неизвестна
44 Переставить занятие Видна команда — 15
45 Сменить аудиторию занятия Видна команда — 15
46 Заменить преподавателя Видна команда — 15
47 Отдать на кафедру Видна команда — 15; точная семантика неизвестна
48 Открыть расписание группы Видна команда — 15
49 Открыть расписание преподавателя Видна команда — 15
50 Открыть расписание аудитории Команда видна, неактивна — 15
51 Работать с комментарием занятия Видна команда — 15
52 Открыть поиск свободных аудиторий Видны меню и окно — 2, 13
53 Выбрать день поиска аудитории Видны кнопки — 13
54 Отобрать аудитории по назначению Видны варианты — 13
55 Просмотреть свободные аудитории по времени Видны колонки — 13; выдача пуста
56 Выполнить действие «База данных» Видна команда — 2; содержание неизвестно
57 Открыть параметры Видны меню/кнопка — 2, 14, 15
58 Открыть помощь Видно меню — 1, 2
59 Выйти из приложения Видна команда «Выход», Alt+X — 1

Номера источников в последней колонке соответствуют Screenshot_N.jpg. Это каталог предусмотренных интерфейсом возможностей, а не перечень 59 проверенных рабочих операций.

Указатель всех 15 скриншотов§

Файл Что показывает
Screenshot_1.jpg Главное окно и раскрытые «Справочники»
Screenshot_2.jpg Раскрытое меню «Расписание»
Screenshot_3.jpg Группы и карточка группы
Screenshot_4.jpg Преподаватели и карточка преподавателя
Screenshot_5.jpg Дисциплины
Screenshot_6.jpg Аудитории
Screenshot_7.jpg Кафедры
Screenshot_8.jpg Факультеты
Screenshot_9.jpg Учебный план
Screenshot_10.jpg Курсы
Screenshot_11.jpg Потоки
Screenshot_12.jpg Звонки
Screenshot_13.jpg Поиск свободных аудиторий
Screenshot_14.jpg Общее расписание и всплывающие сведения
Screenshot_15.jpg Контекстные команды занятия

Полное описание каждой формы с разграничением наблюдения и интерпретации: screens-analysis.md.

Приложение D. Файлы результата и их назначение§

Артефакт Назначение
system-report.html Этот отчет в автономном HTML с оглавлением, фильтром разделов и печатью
system-report.md (локальный материал) Полный исходный текст отчета
schedule.sqlite (локальный материал) 19 исходных таблиц, два представления и происхождение данных
schema.json (локальный материал) Все поля, ключи, параметры формата, блоки и предупреждения
source-manifest.json (локальный материал) SHA-256 всех 65 файлов каталога семестра
metrics.json (локальный материал) Агрегаты, проверки связей и качества
pxlib-validation.json (локальный материал) Независимое сравнение всех доступных записей
indexes-evidence.json (локальный материал) Заголовки и проверка вторичных ключей
auxiliary-evidence.json (локальный материал) Статически извлеченные формы EXE и схемы текстовых файлов
paradox_read.py (локальный материал) Читатель найденных форматов Paradox без операций записи
export_data.py (локальный материал) Воспроизводимый экспорт JSON и SQLite
validate_pxlib.py (локальный материал) Необязательное сравнение с pypxlib на временных копиях
analyze_relations.py (локальный материал) Повторный расчет связей и агрегатов из JSON
inspect_auxiliary.py (локальный материал) Статическое исследование DAT/SCH и конкретного Reorder.EXE
inspect_indexes.py (локальный материал) Проверка вторичных индексов
build_report.py (локальный материал) Сборка этого Markdown из текста, схемы и каталогов
render_report.py (локальный материал) Преобразование итогового Markdown в HTML

Это техническое исследование и подготовка данных для просмотра. Полноценное веб-приложение, развертывание, автосоставление и редактор с обратной записью в Paradox в рамках этой работы не реализованы. Архитектура и проверяемые шаги их создания описаны выше.