Карта проекта и границы изменения
В предыдущем уроке мы определили результат отбора рекомендуемых страниц и запретили менять входной манифест. Теперь нужно понять, какие файлы отвечают за этот результат. Карта проекта связывает пожелание с устройством программы: показывает, где хранятся сведения, где выполняется отбор и где описаны границы работы. После этого урока у нас будет явная область изменения и объяснение, почему соседние файлы остаются источниками данных.
Небольшой размер библиотеки помогает рассмотреть принцип без сложной инфраструктуры. В corpus находятся четыре Markdown-документа, manifest.json содержит идентификаторы и признаки, catalog.py читает записи. TASK.md описывает текущую задачу, RULES.md — устойчивые ограничения. Такой набор можно полностью прочитать. Мы не предполагаем, что название папки само по себе объясняет её содержимое или что агент заранее знаком с настоящим ProfessorWeb.
Ответственность вместо перечня
Обычный список файлов отвечает на вопрос «что находится рядом», но не объясняет, где требуется изменение. В OWNERSHIP.md добавим ответственность. Манифест является редакционным источником URL и признаков; корпус содержит авторский текст; Python-файл реализует чтение и отбор. Если результат содержит лишнюю служебную запись, сначала смотрим условие публичности в коде, а не ищем способ удалить неудобный документ из корпуса.
Это разделение помогает отличать причины от симптомов. Например, ссылка на страницу может выглядеть новой потому, что код вычисляет адрес из имени файла. Исправлять название Markdown в таком случае неправильно: оно не является источником публичного URL. Нужно найти преобразование в программе и заменить его чтением поля манифеста. Карта ответственности заранее объясняет, какой файл способен породить рассматриваемый дефект, и сокращает область поиска.
В учебном коде путь к данным вычисляется от __file__, а не от текущего каталога терминала. Поэтому запуск из другой папки не должен случайно переключать библиотеку на соседний манифест. Относительные пути удобны внутри проекта, но их основание следует назвать. В реальном репозитории оно может задаваться конфигурацией или параметром команды. В нашей библиотеке основание неизменно: папка выбранного состояния lesson-NN.
Чтение и запись имеют разные границы
Разрешённая область чтения шире области изменения. Чтобы понять отбор, нужно видеть поля public и featured, но это не даёт права менять их. Чтобы сохранить адрес, нужно прочитать старую запись, но нельзя произвольно переписать URL. Поэтому карта отмечает catalog.py как область записи, а манифест и корпус — как вход. В таком виде граница относится к именам файлов и может быть сопоставлена с фактическим кандидатом изменения.
Однако документ об ответственности не является файловой системой с ограниченными правами. Если инструмент агенту технически позволяет менять любой путь, одной фразы в Markdown недостаточно для жёсткой изоляции. Мы рассматриваем редакционный и инженерный контракт. Позднее отдельно обсудим реальные разрешения инструмента и окружения. Не нужно приписывать OWNERSHIP.md свойства системной защиты, которых у обычного текстового файла нет.
Полезно заранее выделить области, вообще не относящиеся к задаче: секреты, рабочая база, папка публикации, пользовательские документы. Агенту не требуется их содержание для изменения функции отбора. При сборе контекста мы также не будем рекурсивно читать всё дерево. Это снижает вероятность случайной передачи данных и помогает сосредоточиться на механизме. Ограничение чтения здесь одновременно является границей доступа и способом убрать шум из объяснения.
Как читать поток данных
Проследим путь одной записи urls. Загрузчик читает объект из JSON, проверяет повторение идентификатора и адреса, открывает соответствующий Markdown и добавляет текст. Затем public_pages оставляет запись, только если public буквально равно True. Наконец, основной блок формирует краткий объект вывода с id, title и url. Каждый шаг имеет отдельную ответственность, поэтому новое условие featured можно поставить после публичного отбора без изменения загрузки.
Проверка пути в загрузчике требует, чтобы раскрытый путь Markdown оставался непосредственно внутри корпуса и имел расширение .md. Это учебная граница плоского каталога. Если позднее понадобится вложенность, нельзя просто убрать проверку: следует изменить контракт пути и объяснить разрешённые подкаталоги. Для текущих четырёх документов расширять доступ незачем. Пример также не рассчитан на одновременную враждебную замену файлов другим процессом во время чтения.
Когда вы составляете карту более крупного проекта, начните с одного маршрута данных. Запишите вход запроса, обработчик, хранилище, преобразование и место отображения. Не пытайтесь сразу описать каждый вспомогательный модуль. Для маленькой задачи важнее знать, через какие функции проходит выбранная запись и где меняется её форма. Если один файл содержит несколько обязанностей, карта может описать их по функциям, не требуя немедленного архитектурного переписывания.
Ожидаемый результат статического чтения — понятное место для нового отбора: функция в catalog.py, принимающая уже загруженные записи. Манифест остаётся источником фактов, а текст документов не определяет доступ. Никакие команды учебного проекта при подготовке не выполнялись. Поэтому карта подтверждает наше понимание исходников, но не сообщает о наблюдаемой скорости, корректности окружения или поведении программы при реальном запуске.
Файл, который выглядит связанным
Представьте, что рядом появился deploy-notes.md с описанием хостинга. Название связано с сайтом, но для функции рекомендуемых материалов его содержание не требуется. Карта ответственности помогает не путать тематическую близость и причинную зависимость. Если документ содержит секреты или пользовательские сведения, включать его в пакет только ради «полного понимания» тем более незачем. Для текущего изменения достаточно структуры записей и существующего отбора.
Другой случай — cards.py, который действительно получает краткий объект и формирует карточки. Если задача ограничена функцией, его можно прочитать как потребителя, но область записи ещё не расширяется автоматически. Если в нём обнаружено ожидание другого формата, это существенная зависимость, которую нужно объяснить оператору. Такая находка может привести к уточнению контракта, однако не разрешает незаметно переписать шаблон и назвать это сопутствующим исправлением.
В нашей архивной библиотеке cards.py отсутствует. Поэтому этот разбор является вариантом расширения, а не ссылкой на уже существующий шаг. Старайтесь сохранять такое различие в документации: карта реальных файлов должна описывать то, что читатель действительно сможет открыть, а будущие компоненты обозначаются как возможное продолжение.
Проверьте мысленно два изменения: агент добавляет поле в TASK.md и агент меняет public у notes. Первое можно обсуждать как уточнение контракта, второе меняет исходные редакционные данные и выходит за задачу. В следующем уроке используем эту карту, чтобы выбрать компактный пакет контекста. Такой пакет будет содержать достаточно сведений для работы с функцией, сохраняя ясное происхождение каждого фрагмента.
Полный файл OWNERSHIP.md из состояния lesson-02. Полное самостоятельное состояние находится в архиве серии; фрагмент не заменяет остальные определения.
# Ответственность файлов
catalog.py: чтение, отбор и порядок; область изменения данной задачи.
manifest.json: редакционный источник id, URL, public, featured; только чтение.
corpus/*.md: авторские тексты; только чтение.
RULES.md: границы работы; TASK.md: результат текущего шага.
pack.py: явный allowlist контекста, не рекурсивный сбор всего каталога.
Статус примера: not_run. При подготовке не выполнялись учебные программы, тесты, вызовы AI или деплой. Описанные эффекты ожидаемые.
Оглавление серии · Полные исходники
Первичные документы: Источник 1.