{
  "schemaVersion": 1,
  "id": "P48-C02",
  "title": "Диагностика писем: журнал из разрешенных полей",
  "author": {
    "id": "P48",
    "name": "Антон Лазарев"
  },
  "specialty": "ИИ в закрытом контуре",
  "projectStatus": "concept",
  "source": {
    "document": "catalogue_60_personas.md",
    "briefId": "P48-C02",
    "title": "Обработка рабочих писем",
    "kind": "editorial_concept",
    "data": "synthetic"
  },
  "context": "При ошибке парсинга удобно сериализовать весь объект письма. Вместе с причиной в журнал тогда уйдут адрес, содержание и заголовок авторизации.",
  "decision": "Я собираю диагностическое событие по разрешенному списку, а не удаляю известные секреты из произвольного объекта. Сохраняются проверенный ID, код ошибки и признак повторяемости. Свободный текст исключения не копируется.",
  "constraint": "Все письма и токены в наборе искусственные. Проверяется преобразование события, не доступ к почтовому серверу.",
  "steps": [
    "Подготовить четыре полных объекта ошибок с чувствительными тестовыми полями.",
    "Построить новый диагностический объект по трем разрешенным полям.",
    "Проверить неизвестный код, неправильный ID и дополнительное вложенное поле."
  ],
  "inspection": [
    "Весь выход не содержит адресов, тела или TEST-SECRET — проверено.",
    "Неизвестный код и непроверенный ID заменены безопасными значениями — проверено.",
    "Новое вложенное поле с секретом не расширяет журнал — проверено."
  ],
  "sample": {
    "headers": [
      "requestId",
      "code",
      "retryable"
    ],
    "rows": [
      [
        "REQ-01",
        "parse_error",
        "false"
      ],
      [
        "REQ-02",
        "timeout",
        "true"
      ],
      [
        "REQ-03",
        "schema_error",
        "false"
      ],
      [
        "invalid-id",
        "unclassified_error",
        "false"
      ]
    ]
  },
  "sampleNote": "Авторский контрольный набор; не клиентские документы и не результаты внешней модели.",
  "caseStudy": {
    "role": "Инженер локальной обработки данных",
    "contribution": "Я реализовал очистку почтовой диагностики по списку разрешённых полей и подготовил проверки приватных значений.",
    "objective": "Тело письма, адрес и тестовый токен остаются во входе и не попадают в диагностический результат.",
    "problem": "При ошибке парсинга удобно сериализовать весь объект письма. Вместе с причиной в журнал тогда уйдут адрес, содержание и заголовок авторизации.",
    "result": "Четыре события сведены к requestId, code, retryable. Ни адреса, ни тела, ни один TEST-SECRET не вошли в результат. Неизвестный код заменен unclassified_error, а повтор разрешен только для timeout.",
    "deliverables": [
      "index.html",
      "source.json",
      "source.csv",
      "result.json",
      "result.csv",
      "engine.js",
      "checks.json",
      "style.css"
    ],
    "blocks": [
      {
        "type": "text",
        "title": "REQ-02 сохраняет причину, но не письмо",
        "text": "У REQ-02 есть код timeout и возможность повтора, а также адрес, тема, тело и тестовый секрет. В результат переходят только requestId, code и retryable. Я выбрал разрешённый минимум вместо удаления нескольких известных лишних полей: новый атрибут входа не попадёт в диагностику автоматически."
      }
    ]
  },
  "deliverable": {
    "type": "app",
    "entry": "/catalogue/deliverables/p48-c02/index.html",
    "label": "Открыть работающий материал",
    "files": [
      {
        "path": "/catalogue/deliverables/p48-c02/index.html",
        "name": "index.html",
        "mimeType": "text/html"
      },
      {
        "path": "/catalogue/deliverables/p48-c02/source.json",
        "name": "source.json",
        "mimeType": "application/json"
      },
      {
        "path": "/catalogue/deliverables/p48-c02/source.csv",
        "name": "source.csv",
        "mimeType": "text/csv"
      },
      {
        "path": "/catalogue/deliverables/p48-c02/result.json",
        "name": "result.json",
        "mimeType": "application/json"
      },
      {
        "path": "/catalogue/deliverables/p48-c02/result.csv",
        "name": "result.csv",
        "mimeType": "text/csv"
      },
      {
        "path": "/catalogue/deliverables/p48-c02/engine.js",
        "name": "engine.js",
        "mimeType": "text/javascript"
      },
      {
        "path": "/catalogue/deliverables/p48-c02/verify.cjs",
        "name": "verify.cjs",
        "mimeType": "text/javascript"
      },
      {
        "path": "/catalogue/deliverables/p48-c02/checks.json",
        "name": "checks.json",
        "mimeType": "application/json"
      },
      {
        "path": "/catalogue/deliverables/p48-c02/style.css",
        "name": "style.css",
        "mimeType": "text/css"
      }
    ],
    "summary": "Четыре события сведены к requestId, code, retryable. Ни адреса, ни тела, ни один TEST-SECRET не вошли в результат. Неизвестный код заменен unclassified_error, а повтор разрешен только для timeout."
  },
  "takeaway": "Четыре события сведены к requestId, code, retryable. Ни адреса, ни тела, ни один TEST-SECRET не вошли в результат. Неизвестный код заменен unclassified_error, а повтор разрешен только для timeout.",
  "capabilities": [
    "completed_app"
  ],
  "externalConnections": []
}
