返回 Skill 列表
extension
分类: 效率与办公无需 API Key

软件目录解析工具

Use when the user wants Reasonix to perform a systematic file/directory structure analysis on a given software installation directory or project tree. Follows the AAK (Automated Asset Knowledge) methodology: three analysis phases (file system reconnaissance, config/text semantic parsing, cross-validated report generation) plus directory structure semantic interpretation. No binary execution — purely static file and text analysis. Every finding must carry a confidence tag — never fabricate evidence. Reports are forced to full Chinese output. Core directories with complex internal structure use semantic tree + role grouping instead of flat file lists.

person作者: MsidxshubModelScope

🦌 Deer-导航模式 — 技能级硬约束(最高优先级)

本技能启动时,若目标目录已存在 Deer/ 索引,Agent 必须进入 Deer-导航模式。 此约束优先级高于任何任务级指令,Agent 不得以"用户要求""快捷方式""效率考虑"为由绕过。

Hard Constraint (Pre-Execution Gatekeeper): 所有工具调用(lsgrep 等)在到达内核前必须先通过预执行校验器。 若请求路径/规则违反 Deer-导航规则,校验器在触及文件系统之前即中止工具调用——不会发生任何磁盘读取。 工具仅返回 { "error": "navigation_scope_violation", "data": null },当前步骤视为未执行的无操作步骤。

合规不是选择——它是工具返回非空数据的唯一前提。违规调用在系统层被丢弃,Agent 仅能收到空错误码,无法获取任何底层索引信息。

Deer-导航模式规则

| ✅ 唯一合法操作 | 🚫 严禁操作 | |---|---| | read_file 精确路径(来源: Deer/护栏.md → 向导.md → 索引.json (json.load) → entry["path"]) | ls / dir / glob / find / tree 目录遍历 | | 读取 Deer/ 下的索引/向导/变更日志/护栏 | grep -r / code_index outline 递归搜索 | | 写入 Deer/变更日志.md 记录修改;json.dump 更新 Deer/索引.json | bash 执行 os.walk / Get-ChildItem -Recurse / find 等遍历脚本 | | — | read_file 试探路径存在性(猜测路径后 read 验证) | | — | 🆕 使用 Pre-Deer 阶段 ls 记忆中的路径直接访问目标文件(见补丁2) |

🩹 补丁 1:护栏自检下沉到每次工具调用

每Phase入口自检保留,新增:Agent 在 read_file 任意 <target_path>/ 下文件之前, 必须在 reasoning/thinking 中打印以下三行(不输出给用户,仅内部自检):

[Deer Gate] 目标文件: <路径>
[Deer Gate] 索引来源: Deer/索引.json entry #<序号>, 编码=<encoding>
[Deer Gate] 护栏状态: [通过 — 路径来自 Deer 索引 / 🚨违规 — 路径来自 ls 记忆/猜测]

若第三行标记为 🚨违规,Agent 必须立即中止本次工具调用,改为先读取 Deer/索引.json 获取精确路径后重试。 不允许"反正也对"的心态绕过。

🩹 补丁 2:Pre-Deer 记忆清零(记忆污染阻断)

Pre-Deer 阶段(Deer 创建之前)通过 ls 获得的所有文件路径知识在 Deer 索引创建后 立即标记为"受污染记忆",Agent 不得以"我记得它在某目录下"为理由直接 read_file

唯一合法路径来源:Deer/索引.jsonentry["path"] 字段。

👉 实际执行规则: 即使 Agent "记得" !Setup.txtMir200\ 下, 也必须先从 Deer/索引.json 中 json.load 并检索 entry,取出其 pathencoding, 再执行 read_file。记忆不可代替索引。

🩹 补丁 3:伪造自检 = 会话级无效(后果升级)

| 违规类型 | 后果 | |---------|------| | 使用 ls/glob/find 等遍历工具 | 该工具调用结果立即废弃,不得作为后续推理依据 | | 使用 Pre-Deer 记忆路径直接 read_file(跳过 Deer 索引检索) | 该文件读取结果标记 [Deer绕行违规 — 索引未引用],读取内容不得用于任何分析结论 | | 在 [Deer Gate] 自检中伪造 [通过] 但实际绕过了索引 | 该阶段及后续所有阶段结论级联无效,Agent 必须承认违规并从护栏.md 重新初始化 | | 累计 3 次 Deer 绕行违规 | 本次 AAK 会话交付物全部无效,Agent 声明 [Deer契约破裂: 本会话输出不具备分析效力] |

护栏自检(每 Phase 入口强制执行 — 保留)

1. Test-Path <target_path>/Deer/ → 存在?
2. 若存在 → 进入 Deer-导航模式,所有文件定位走 护栏.md → 向导.md → 索引.json (json.load) → entry["path"]
3. 若不存在 → 正常分析模式,Deer 创建后立即切换
4. 自检结果写入报告: "Deer 护栏: [通过 / 未激活]"

🛡️ 上下文截断保护: 若 Deer/ 存在但 Agent 上下文已截断丢失此规则 — Deer/护栏.md 文件涵盖此块全部规则,并额外包含断链处理、快照被动声明、跨会话记忆。 Agent 在读取 Deer/ 任何内容前必须先 read_file Deer/护栏.md, 护栏文件自描述其约束规则。此文件在 Deer 创建时写入,永不删除。

📋 跨会话记忆: AAK Post-Analysis 阶段自动创建 Reasonix project memory (deer-index-available), 新会话启动时自动加载,Agent 从第一条消息起即感知 Deer 存在并进入导航模式。

🩹 补丁 4:Agent 启动时强制门控(Deer 存在的第一动作)

当 Agent 感知到目标目录存在 Deer/ 索引时,第一个工具调用必须是:

read_file <target_path>/Deer/护栏.md

在读取完护栏.md 之前,Agent 不得对目标目录发起任何其他工具调用(包括 read_file 任意目标文件、 grep 单文件搜索、current_status 等)。此门控确保补丁 1-3 全部进入上下文后操作才开始。

AAK — Automated Asset Knowledge

Static file/directory analysis methodology. Three phases: file system reconnaissance, config/text parsing, cross-validated reporting — plus directory structure semantic interpretation for architecture-level directories. No binary execution. No PE/ELF/Mach-O deep reverse engineering. Purely static analysis of files, text, and directory layout.

AAK is the lightweight sibling of ATK (Automated Target Knowledge). ATK adds binary static RE and dynamic runtime probing; use ATK when the target is an executable or you need runtime behavior. For pure directory analysis, AAK is sufficient and safer.


1. Overview

1.1 Core Objective

Perform a full-spectrum static analysis on a given directory tree. Extract file inventory, classification, dependency graph, configuration schema, data model, and architecture-level directory semantics. Every output must cite traceable evidence; never infer functionality without proof.

1.2 Input Requirements (Admission Check)

| Check | Pass Condition | Fail Action | |---|---|---| | Path exists | os.path.exists(input_path) == True | Reject, return error | | Path readable | os.access(path, os.R_OK) == True | Reject, return error | | Is a directory | os.path.isdir(input_path) == True | Accept single file, downgrade to flat analysis |

1.3 Output Deliverables

  • analysis_report.json (machine-readable): file inventory, classification stats, dependency graph, config schema, database structures, directory semantics. 最小结构如下(文件清单部分必须含 encoding,确保 Deer 缺失时 Agent 仍可获知文件编码):
    {
      "meta": {
        "target_path": "<绝对路径>",
        "analysis_utc": "<ISO 8601>",
        "deer_available": true
      },
      "file_inventory": [
        {
          "path": "相对路径",
          "type": ".ini|.json|.exe|...",
          "category": "conf|flow|gate|base",
          "encoding": "utf-8|gbk|binary|UNKNOWN",
          "size_bytes": 1234
        }
      ],
      "config_findings": [
        {
          "key_path": "database.host",
          "value": "db.myapp.com",
          "source_file": "config/db.ini",
          "source_encoding": "gbk",
          "sensitivity": "HIGH|MEDIUM",
          "confidence": "[已确认]|[建议]|[推测]"
        }
      ],
      "endpoints": [
        {
          "type": "NETWORK_ENDPOINT|FILE_PATH",
          "value": "https://...",
          "source_file": "...",
          "source_encoding": "utf-8",
          "confidence": "[已确认]|[建议]"
        }
      ],
      "dependencies": [
        {
          "from_file": "...",
          "to_file": "...",
          "status": "EXISTS|NOT_FOUND|EXTERNAL"
        }
      ],
      "database_schemas": [],
      "directory_semantics": {}
    }
    
  • analysis_summary.md (human-readable): key findings, high-risk items, architecture overview, recommendations. Every subjective judgment MUST carry a confidence level tag.

1.4 Confidence Level System (Mandatory for every finding)

| Level | Tag (English) | Tag (中文) | Definition | Example | |---|---|---|---|---| | C1 Confirmed | [CONFIRMED] | [已确认] | >=2 independent sources cross-validated | config key port: 8080 + firewall rule file both hit | | C2 Suggested | [SUGGESTED] | [建议] | 1 source hit, no contradictory evidence | only config file found LicenseServer= | | C3 Speculative | [SPECULATIVE] | [推测] | Heuristic/pattern match, no direct evidence | directory named plugins/ but empty | | CX Unknown | [UNKNOWN] | [未知] | No analyzable evidence found | encrypted file, unreadable format |

Hard constraint: If a finding cannot be assigned C1–C3, it MUST be tagged [UNKNOWN] with an explicit reason. Never skip it, never fabricate content.

1.5 输出语言策略 (Output Language Policy) — 强制性

规则: 默认输出语言为中文。所有面向用户的总结性输出(analysis_summary.md 及任何分析结论)必须 强制全中文,包括但不限于:

| 输出要素 | 中文要求 | 示例 | |----------|---------|------| | 章节标题 | 必须全中文 | "执行摘要" 而非 "Executive Summary" | | 置信度标签 | 必须用中文标签 | [已确认] 而非 [CONFIRMED] | | 表头 | 必须全中文 | "文件 | 原因 | 置信度" | | 描述文字 | 必须全中文 | 所有段落、说明、建议文字使用中文 | | 技术术语 | 中文为主,首次出现可附英文原名括号标注 | "交叉验证矩阵(Cross-Validation Matrix)" | | 图例/标注 | 必须全中文 | [阶段三跳过: 无配置文件] |

英文保留范围: 仅以下内容可用英文原文:

  • 文件路径(如 app/config/settings/
  • 技术标识符(如 DLL 名、函数名、配置键名)
  • JSON 键名、数据库表名、配置节名
  • analysis_report.json 机器可读报告(内部使用,可用英文 key)

违反后果: 报告包含非必要英文 → 标记 [中文化不合格],必须修正后方可交付。


1.6 Deer 索引预检(开工前强制检查)

在进入 Phase 1 分析流程之前,必须执行以下预检:

步骤1.6.1 — 检查源目录顶层是否存在 Deer/ 目录
         read_file <target_path>/Deer/护栏.md
         (注: 使用 read_file 精确路径读取而非 ls 目录遍历——后者与 Deer-导航模式
          「🚫 ls/dir/glob/find/tree」硬约束冲突,见文件头 Deer-导航模式规则。)
         结果:
           - 存在 Deer/    → 执行步骤 1.6.2
           - 不存在 Deer/  → 跳过预检,进入正常 Phase 1 分析流程

步骤1.6.2 — 读取现有 Deer 索引
         判断 Deer/ 内容是否完整(包含 Deer/索引.json 及至少一个分类子目录,
         且该子目录内含其自身的 索引.json):
           - 完整可用 → 执行步骤 1.6.2a(时效性校验)
           - 不完整/损坏 → 标记 "[DEER_INDEX_CORRUPT: 索引不完整,需要重新分析]"

步骤1.6.2a — 时效性校验(防止 Deer 过期)
         ⚠ 原方案使用 find/Get-ChildItem -Recurse 递归遍历目标目录获取最新 mtime,
         这与 Deer-导航模式「🚫 find / Get-ChildItem -Recurse」硬约束冲突。
         现替换为零遍历方案:读取 Deer 索引自身的时间戳元数据判定。

         方法:
         1. read_file Deer/索引.json → json.load()
         2. 提取 meta["last_verified_utc"](若无则取 meta["created_utc"])
         3. 与当前 UTC 时间比较:
            - 距今 > 7 天 → 标记 "[DEER_STALE: 索引超过7天未验证]",强制重新分析
            - 距今 ≤ 7 天 → 索引视为有效,跳过 Phase 1–3,复用已有报告
         4. 备选: 若平台支持,可对 Deer/索引.json 自身执行 stat 获取磁盘 mtime
            交叉比对,但不遍历目标目录。

         此方案为启发式——无法精确检测目标文件是否被外部修改。
         如需精确检测,用户应主动请求重新分析(见下方例外规则表)。
         全量重建触发条件详见 B.5.3。

步骤1.6.3 — 输出说明
         最终报告中注明:
           "分析依据: Deer 现有索引(非重新解析)"
           "分析依据: 全新解析(无现有 Deer 索引)"

例外规则:

| 条件 | 行为 | |------|------| | Deer/ 存在且完整,但用户明确要求重新分析 | → 忽略现有 Deer,重新分析,完成后覆盖 Deer | | Deer/ 存在但为空目录 | → 视为不存在,进入正常分析 | | Deer/ 存在且完整,直接使用已有报告 | → 跳过分析,也跳过 Post-Analysis 的 Deer 创建提示。Agent 进入 Deer-导航模式:禁止任何形式的文件发现/枚举行为,所有文件定位强制通过 Deer/护栏.md → 向导.md → 索引.json (json.load 查询) → path 字段 → read_file |


2. Core Principles (Non-Negotiable)

| Principle | Operational Definition | Violation Consequence | |---|---|---| | Real files are sole ground truth | All analysis based on actual file content; never invent functionality or interfaces | Entire report marked INVALID | | Output must be verifiable | Every finding cites evidence source (file path, line number, config key) | Section marked UNVERIFIED | | Minimal intrusion | Do NOT modify target files or change system config. Deer/ 索引目录为例外——经用户确认后可在目标目录内创建,不修改任何原始文件 | Step skipped with declaration in report | | Layered progression | Must follow Phase 1→2→3 order. Previous phase output feeds next phase input | Skipped phase marked SKIPPED with reason | | Fully reproducible | Every operation recorded as reproducible CLI/script invocation | Step marked NOT_REPRODUCIBLE | | Deer-first navigation | 一旦 Deer 索引就绪,Agent 禁止以任何方式发现或枚举目标目录中的文件(含 ls/glob/find/dir/tree/grep -r/code_index outline/bash 执行任何遍历脚本/read_file 试探路径存在性)。唯一合法操作:从 Deer/护栏.md → Deer/向导.md → Deer/索引.json (json.load) → entry["path"] 提取精确路径后 read_file(注意 entry["encoding"])。此规则由技能第 1 层硬约束块 + 每 Phase 护栏自检 + Deer/护栏.md 磁盘文件 + project memory 四层联合保障,上下文截断后可从 Deer/护栏.md 恢复。 | 违规 → 标记 [Deer绕行违规],该阶段结论无效 |


3. Analysis Workflow (Three Phases + Mandatory Gate Controls)

⛔ 安全围栏(全部 Phase 强制执行)

Agent 在进入 Phase 1 前必须自述以下约束,并在全部分析完成后验证:

安全围栏 — 对目标目录的不可变操作承诺:

  ❌ 禁止 修改目标目录内任何文件的内容
  ❌ 禁止 删除目标目录内任何文件或目录
  ❌ 禁止 移动/重命名目标目录内任何文件或目录
  ❌ 禁止 在目标目录内创建新文件(Deer/ 索引目录除外,需用户确认)
  ❌ 禁止 修改目标文件的权限、属性、时间戳

  ✅ 允许 读取文件内容
  ✅ 允许 列出目录结构
  ✅ 允许 检测文件元数据(大小、编码、类型)
  ✅ 允许 在目标目录外创建 atk_output/ 输出分析报告
  ✅ 允许 经用户确认后在目标目录内创建 Deer/ 索引目录
  ✅ 允许 修改目标文件前自动复制原文件到 Deer/快照/(被动操作,不修改原文件)

  验证: Phase 3 结束后对 Deer/ 之外的所有文件进行前后 mtime/size 比对。
  任何变动 → 标记 [围栏违规: <具体文件>],报告置为不可信。

Phase 1: File System Reconnaissance

🛡️ Deer 护栏自检(Phase 1 入口强制执行)

1. Test-Path <target_path>/Deer/ → 存在?
2. 若存在 → 检查 Deer/护栏.md:
   - 护栏有效 + mtime 校验通过 (1.6.2a) → 跳过 Phase 1–3,直接复用已有报告
   - 护栏有效 + mtime 校验失败 → 触发 B.5.3 全量重建(重建过程是重新执行 Phase 1–3,此时 Phase 1 作为重建的一部分有权 ls/glob)
3. 若不存在 → 正常分析模式,Phase 1 允许 ls/glob 遍历(首次建索引)
4. 自检结果: "Deer 护栏: [跳过分析 (复用索引) / 全量重建 (索引过期) / 未激活 (首次分析)]"

Phase 1 例外: 仅在 Deer/ 不存在(首次分析)时允许 ls/glob 遍历目标目录。 Deer/ 存在但 mtime 校验失败 → 走 B.5.3 全量重建,不在本例外条款内。

Admission Gate

  • [ ] Input path passed Section 1.2 admission check
  • [ ] Output directory is writable (default: atk_output/; override via OUTPUT_DIR)
  • [ ] At least one tool available: file, python-magic, or fallback to suffix-based classification

Step 1.1 — Directory Tree Traversal

Method:
  Recursively scan input path. For each file:
    1. Read magic bytes with python-magic (or `file` command) to determine real type
    2. Classify by suffix + magic dual-verification into:
       EXECUTABLE / LIBRARY / SCRIPT / CONFIG / DOCUMENT / DATA / UNKNOWN
    3. Skip condition: file size > 500MB → 执行子类型探测而非完全跳过:
       - 用 `file` 命令识别子类型(SQLite/JSON/XML/归档/其他)
       - 若为 SQLite → sqlite3 连接,PRAGMA table_info 提取 schema,不读数据行
       - 若为 JSON  → json-stream 流式解析前 1MB,提取所有 key 和 value 类型
       - 若为 XML/归档 → 记录类型和大小,标记 "LARGE_FILE_SCHEMA_ONLY"
       - 无法识别 → 仅记录元数据,标记 "LARGE_FILE_UNPARSED"
    4. For directories: record depth, child count, total size

Example:
  >>> file -i "app/config/settings.json"
  text/plain; charset=utf-8  → Classification: CONFIG

Error Handling:
  - `file` command unavailable → fallback to python-magic → if both fail → suffix-only classification
  - Permission denied → skip file, record "ACCESS_DENIED" in report

Step 1.2 — File Metadata Extraction

Method:
  For each file extract:
    - Size (bytes)
    - Modification time (ISO 8601)
    - Permissions (Linux/Mac: octal; Windows: readonly/hidden only)
    - Version info (Windows: parse VERSIONINFO resource if available)
    - Entropy flag (entropy > 7.5 → mark HIGH_ENTROPY — possible encrypted/packed)

Example output (JSON fragment):
  {
    "path": "database.sqlite",
    "size_bytes": 5242880,
    "modified_utc": "2025-06-18T08:00:00Z",
    "classification": "DATA",
    "entropy_flag": null
  }

Step 1.3 — Structural Dependency Identification

Method:
  For CONFIG and SCRIPT files, identify cross-file references:
    - Config files referencing other configs: include / import / extends / $ref
    - Scripts importing other files: import / require / include / source
    - Database files referenced by config: connection strings, file paths
    - Template references: template_dir, layout, partial paths

  Tag each dependency:
    - EXISTS: referenced file found on disk
    - NOT_FOUND: referenced file does not exist (broken reference)
    - EXTERNAL: reference to path outside target directory

Example:
  config/main.json → references database.ini → EXISTS
  config/main.json → references /etc/ssl/certs/ca.pem → EXTERNAL

Phase 1 Exit Decision

| Condition | Action | |---|---| | File classification == empty | → Terminate, report ERROR: no analyzable content | | No CONFIG or SCRIPT files found | → Skip Phase 2, proceed to Phase 3 | | Normal completion | → Write phase1 section. 将 Phase 1 文件分类清单按以下映射规则转换为 Deer 分类(flow/conf/gate/base)。转换后的 Deer 映射表即为 Phase 2/3 的文件导航入口。Proceed to Phase 2 |

Phase 1 → Deer 分类映射规则(强制):

| Phase 1 标签 | Deer 分类 | 说明 | |-------------|----------|------| | EXECUTABLE | gate | 可执行入口 | | LIBRARY | gate | 动态库/驱动 | | SCRIPT | gate | 可执行脚本(.py/.lua/.js/.bat/.ps1) | | CONFIG | conf | 配置文件(.json/.xml/.ini/.yaml/.cfg) | | DOCUMENT | base | 文档/license/readme | | DATA | base | 数据文件(.pak/.dat/.bin/资源/字典) | | UNKNOWN | 待分类 | 暂不归入四类,写入 uncategorized 数组 |

注意: Deer JSON 索引中 category 字段仅有 flow/conf/gate/base 四值,不出现 SCRIPT/CONFIG 等 Phase 1 标签。Phase 2 导航时 用 category 字段筛选: conf 类 = 所有配置文件, gate 类 = 可执行+库+脚本。 | Phase 2 发现需修正分类 | → 允许 Phase 2 回写 Deer 索引。若文本解析失败(JSON/YAML/XML 损坏)、文件实际为二进制(misleading suffix),则降级: category 改为 base(原为 conf),写入 reclassify_note: "RECLASSIFIED: CONFIG→DATA (parse failed)"。禁止 Phase 2 升级分类(gate 不允许改为更高级别) |


Phase 2: Configuration & Text Semantic Parsing

⚠️ 导航规则: Phase 2/3 中所有文件定位操作必须先查 Phase 1 产出的 Deer 分类 JSON(内存中 idx["entries"] 数组), 按 category 字段(conf/gate/flow)筛选后直接 Read 目标文件,禁止重新 ls / glob / find 遍历目标目录。 Deer 索引 JSON 是当前分析的唯一文件导航入口。 注意: 此时 Deer/ 目录尚未写入磁盘(Post-Analysis 阶段才创建),导航使用的是 Phase 1 内存中的 JSON 数据结构。

🛡️ Deer 护栏自检(Phase 2 入口强制执行)

1. 检查 Phase 1 产出的 Deer 分类映射表(内存)是否就绪
2. 若 Deer/ 磁盘目录已存在 → 进入 Deer-导航模式:
   - 文件定位: 查 Deer 映射表(内存)→ 提取路径 → read_file
   - 禁止 ls/glob/find 遍历目标目录
3. 若 Deer/ 不存在 → 使用 Phase 1 内存映射表导航(同上)
4. 自检结果: "Deer 护栏: [通过 (内存映射表) / 通过 (Deer 磁盘索引)]"

Admission Gate

  • [ ] Phase 1 file classification contains CONFIG or SCRIPT type files
  • [ ] At least one text-class file in Phase 1 output
  • [ ] Phase 1 Deer 分类映射表(内存)已就绪
  • [ ] If both false → skip Phase 2, tag "PHASE2_SKIPPED: no text files found"

文件大小限制: 单个文本文件 > 100KB 且非 JSON/YAML/INI/TOML → 仅读首 512 字节检测内容类型,不完整读取。超大 JSON 仍完整读取。 编码检测不受此限制——编码检测对所有 "PENDING" 条目使用分级采样(见 Step 2.1)。

Step 2.1 — Text File Identification & Routing

Method:
  1. 从 Phase 1 Deer 分类 JSON(内存)中筛选 encoding 为 "PENDING" 的所有 entry
     (不再限制 category=conf/gate——base 类文本文件同样需要编码检测。)
  2. 对每个 entry["path"] 对应的磁盘路径执行 Read,进行编码检测:
     采样规则:
       - 文件 ≤ 1MB       → 全量读取
       - 文件 1MB–100MB   → 读取首 8KB
       - 文件 > 100MB     → 读取首 4KB
     判定逻辑:
       a. chardet.detect(sample),若置信度 ≥ 0.8 → 采用检测结果
       b. 置信度 < 0.8 → 检查 BOM (UTF-8/UTF-16 LE/BE/UTF-32 LE/BE)
          → BOM 命中则按 BOM 判定
       c. 无 BOM + sample 中无 null 字节 + 全为 ASCII 可打印字符
          → 标记 "utf-8"(保守推定: ASCII 是 UTF-8 子集)
       d. sample 含 null 字节(\x00)且无可打印文本 → 标记 "binary"
       e. 其它情况 → 标记 "UNKNOWN"
  3. Route by suffix — entry["type"] 字段直接提供后缀,无需二次推断:
  4. 编码检测完成后回写: entry["encoding"] = 检测到的编码值
     此字段为后续文件修改操作提供保存格式依据。
     ⚠ 修改文件前必须读取 entry["encoding"];若为 "UNKNOWN" 则重新 chardet 全量检测。
       ├── .json     → json.load() → STRUCTURED_JSON
       ├── .xml      → defusedxml.ElementTree.parse() → STRUCTURED_XML
       ├── .yaml/.yml → yaml.safe_load() → STRUCTURED_YAML
       ├── .ini/.cfg  → configparser.ConfigParser() → INI
       ├── .properties → line-by-line key=value → PROPERTIES
       ├── .toml     → tomllib/tomli load → STRUCTURED_TOML
       ├── .env      → dotenv key=value parse → ENV_FILE
       ├── .reg       → regex parse [Section] and key=value → REG_SCRIPT
       ├── .bat/.ps1/.sh → SCRIPT (regex scan for high-risk calls only)
       ├── .py/.lua/.js  → SCRIPT (AST if available, else regex)
       └── other text    → PLAINTEXT (full output, no structured parse)

Error Handling:
  - JSON/XML/YAML parse failure → downgrade to PLAINTEXT, record "PARSING_FAILED: <msg>"
  - File is gzip/bzip2/zlib → decompress to temp first, tag "DECOMPRESSED"

Step 2.2 — Structured Config Parsing

Method:
  After type-specific parse, extract only nodes matching these keywords
  (others preserved verbatim, no semantic inference):
  REQUIRED_KEYWORDS = {'url','host','port','timeout','enable_','disable_',
                       'debug','mode','path','server','database','password',
                       'token','secret','key','cert','proxy','endpoint'}

  For each matched key-value pair, output:
  {
    "key_path": "database.host",
    "value": "db.myapp.com",
    "source_file": "settings.json",
    "source_encoding": "utf-8",
    "sensitivity": "HIGH" if key in ('password','token','secret','key') else "MEDIUM",
    "confidence": "[建议]" if value is concrete (non-empty, non-placeholder)
                      — 单源标记为 [建议],待 Phase 3 交叉验证后升级为 [已确认]
  }

  source_encoding 从 Deer 索引对应 entry 的 encoding 字段提取。
  用途: 后续修改该配置文件时,Agent 可直接获知编码而无须重新 chardet。
  值为 "UNKNOWN" 时 → 修改前必须全量 chardet 检测。

  Placeholder values (e.g. your_token_here, <PASSWORD>, ****) → tag [建议]
  with "value_is_placeholder": true.

Forbidden:
  - Do NOT semantically infer from values. Examples of forbidden inference:
    * "test" → "测试环境"
    * "prod" → "生产环境"
    * "localhost" → "本地开发"
    * "port": 443 → "使用 HTTPS"
  - Do NOT combine adjacent key-value pairs to deduce business logic

Step 2.3 — Script File Scanning (Fact Extraction Only)

Method:
  For Python/Lua/JS/BAT/PS1 files:
    1. Extract all import/require/include statements → module dependency list
    2. Regex-scan high-risk function calls (extract only, no context analysis):
       - os.execute / subprocess.run / Process.Start → process creation
       - socket.connect / http.request / urlopen → network request
       - open / File.WriteAllText → file write
       - exec / eval / compile → dynamic code execution
    3. Extract all hardcoded strings (length >=10 printable chars), deduplicate
    4. Extract --flag / -f value CLI parameter patterns

Example output:
  {
    "script_type": "python",
    "imports": ["os", "sys", "requests"],
    "high_risk_calls": [
      {"function": "os.execute", "line": 42,
       "argument_fragment": "ping -n 1 8.8.8.8", "confidence": "[已确认]"}
    ]
  }

Error Handling:
  - AST parse failure → fallback to regex
  - Import references non-standard library → record module name only, do not install

Step 2.4 — Local Database Probing

Method:
  For .db / .sqlite / .dat files:
    1. Read first 16 bytes, check SQLite header: "SQLite format 3\x00"
    2. If match:
       - sqlite3.connect(dbfile) → .tables for table names
       - PRAGMA table_info(table) for column: name, type, nullable, default
       - SELECT COUNT(*) FROM table for row count
    3. If no SQLite match:
       - Check Berkeley DB magic (0x00061561 / 0x00061562)
       - If match → "DB_TYPE: Berkeley DB"
       - No match → "DB_TYPE: UNKNOWN, content_entropy: <value>"

Example output:
  {
    "file": "data.db", "type": "SQLITE", "confidence": "[已确认]",
    "tables": [{"name": "users", "confidence": "[已确认]", "columns": [
      {"name": "id", "type": "INTEGER", "notnull": true}
    ], "row_count": 142}]
  }

Hard constraints:
  - NEVER execute INSERT/UPDATE/DELETE
  - NEVER output actual row data content (only schema + row count)
  - If database is encrypted → tag ENCRYPTED_DB, skip

Step 2.5 — Endpoint & Interface Aggregation

Method:
  从 Phase 2 已解析的所有配置/脚本中聚合网络端点和接口入口:

  1. 扫描 Step 2.2 产出的所有 matched key-value pairs,提取:
     - key 含 url / host / endpoint / server / proxy 的值 → 网络端点候选
     - key 含 port 的值 → 端口候选
     - key 含 path / dir / folder 的值 → 文件路径候选

  2. 输出格式:
     {
       "type": "NETWORK_ENDPOINT",
       "value": "https://lic.myapp.com/v1/validate",
       "source_file": "config/server/xxx.ini",
       "source_encoding": "utf-8",
       "source_key": "LicenseServer",
       "confidence": "[已确认]"   ← 值非空且非占位符
     }

     source_encoding 从 Step 2.2 的 matched key-value pair 继承
     (原始来源: Deer 索引对应 entry 的 encoding 字段)。

  3. 去重: 相同 value + 相同 type → 合并,source_files 追加

  4. 不做连通性验证 — AAK 无网络探测能力。所有端点为静态提取。

Example output:
  NETWORK_ENDPOINTS:
    - https://api.gameviewer.netease.com  [已确认] from client.json
    - wss://ws.gameviewer.netease.com     [已确认] from server.json
  FILE_PATHS:
    - /data/cache/                         [已确认] from streamer-config.json

Phase 2 Exit Decision

| Condition | Action | |---|---| | No parsable text files | → PHASE2_SKIPPED, proceed to Phase 3 | | All configs are placeholders/templates | → Tag CONFIG_TEMPLATE_ONLY | | Normal completion | → Merge to phase2 section, proceed to Phase 3 |


Phase 3: Cross-Validation & Report Generation

🛡️ Deer 护栏自检(Phase 3 入口强制执行)

1. Test-Path <target_path>/Deer/ → 存在?
2. 若存在 → 进入 Deer-导航模式。
   - 交叉验证时 Source B 来自 Deer 映射表(内存),不重新遍历目录
   - 需要核实路径存在性 → 查 Deer 映射表,禁止 ls/glob
3. 若不存在 → 正常模式(首次分析,Deer 尚未创建)
4. 自检结果: "Deer 护栏: [通过 / 未激活]"

Admission Gate

  • [ ] At least one prior phase produced non-empty output
  • [ ] If ALL phases SKIPPED or empty → output "EMPTY_ANALYSIS: target yields no analyzable data", terminate

Cross-Validation Rules (Matrix)

Cross-validation uses Deer 索引 JSON (Appendix B) as the evidence baseline —
every entry is a verified disk entity that can be cross-referenced against
config values, script imports, and structural findings.

For every C2 [建议] finding, execute cross-validation:

+----------------------+-----------------------------------+---------------------+
| Source A             | Source B (Deer baseline)          | Merge Result        |
+----------------------+-----------------------------------+---------------------+
| Config "db.host"     | Deer entry: .db 文件存在           | [已确认] data flow  |
| Config "port: 8080"  | Deer entry: 脚本引用该端口         | [已确认] parameter  |
| Script import "xyz"  | Deer entry: xyz.py on disk        | [已确认] dependency |
| String "password="   | 源行是注释 (#)                    | Downgrade to [推测] |
| Config key value     | Deer entry: 引用文件缺失           | Tag "断链" + [建议] |
| Two sources disagree | e.g. config:8080, env:9090        | Both output, tag "矛盾" |
+----------------------+-----------------------------------+---------------------+

Deer 的角色: Deer 索引 JSON = Phase 1 全量扫描的物化输出。
每个 entry 都是一条可 Test-Path 验证的证据。交叉验证时:
  - Source A = Phase 2 提取的配置/脚本发现
  - Source B = Deer 索引 JSON 中对应 entry(按 path 匹配)
  - 两者交叉 → C1 [已确认] / C2 [建议] / 矛盾 / 断链

Key constraints:

  • No forced merging: unrelated evidence must not be combined
  • Preserve contradictions: when sources disagree, list both
  • Missing marker: if a phase was skipped, cross-validation field writes null
  • Deer is the single source of truth for "what files exist on disk"

#### 中文报告章节模板

`analysis_summary.md` 必须以下列格式输出。注意:模板中的 **AI 强制导航规则** 是面向后续 AI 读取者的机器可执行指令,必须逐字包含在输出的 summary 中,不得省略。

⛔ AI 强制导航规则 — 逐字执行,不得跳过

本摘要仅提供概览数字、告警项和配置/数据模型提炼。获取完整文件清单、 逐条配置参数、所有端点定义、依赖关系图表的唯一合法路径:

第0步: 检查 <target_path>/Deer/ 是否存在 → 不存在: 本摘要 + analysis_report.json 为唯一可用信息源 Agent 需声明 "[Deer缺失: 仅摘要+report可用]" 两者关系: 摘要为人类可读概览,report.json 为完整机器数据; 同一事实以 report.json 为准,摘要仅做归纳 ⚠ 编码获取: report.json 的 file_inventory[].encoding 提供文件编码; 若该项为 "UNKNOWN" 或 report.json 不含 encoding → 修改文件前必须 对目标文件执行 chardet 全量检测(≥0.8 置信度),绝不假设 UTF-8。 → 存在但损坏: 声明 "[Deer损坏: 索引不可信,建议重新分析]" 第1步: 读取 <target_path>/Deer/护栏.md(硬约束自述文件) 第2步: 读取 <target_path>/Deer/向导.md(任务 → 子索引映射) 第3步: 按向导指引,读取对应 Deer/<分类>/索引.json python3 -c "import json; idx=json.load(open('Deer/<分类>/索引.json'))" 第4步: 从 entry["path"] 字段提取文件路径,精确 read_file 注意 entry["encoding"] —— 用检测到的编码打开文件,不假设 UTF-8

🚫 严禁以下任何文件发现/枚举行为:

  • 目录遍历: ls / glob / find / dir / tree
  • 递归搜索: grep -r、code_index outline、bash 执行 os.walk / Get-ChildItem
  • 路径试探: 通过 read_file 猜测性地探测路径是否存在
  • 绕过向导直接构造或从本摘要推断文件路径

⚠ 违规 → Deer 索引立即失效,分析结论视为不可信。 例外: AAK 技能 Phase 1 首次建索引时允许 ls/glob(技能内部控制,非 Agent 自主决定)

🛡️ 断链处理:

  • Deer/ 不存在 → 不得强行构造导航链。本摘要 + analysis_report.json 为唯一依据
  • Deer/索引.json 不可解析 → 标记 [Deer损坏],建议用户重新运行 AAK 分析
  • entry["path"] 指向的文件缺失 → 标记 [路径失效],跳过该条目,继续下一项 连续 ≥5 条路径失效 → 🔴 [DEER_INDEX_SUSPECT],停止检索,建议全量重建
  • 向导.md 引用不存在的子索引 → 跳过该分类,使用主索引 entries 筛选代替

📸 快照系统: 若 Deer/快照/ 存在: Agent 不得主动提及、不得主动建议回滚。 仅当用户明确要求"回滚文件 X"或"查看修改历史"时才查阅 快照/快照日志.md。

  1. 执行摘要

    • 核心发现(仅 C1 [已确认] + C2 [建议])
    • 文件分类概览
    • 风险项数统计
  2. 文件系统解剖

    • 分类统计:可执行文件、库、配置、脚本、数据
    • 关注文件(高熵/加密/超大文件)
    • 关键目录结构树与子系统角色(参见 Section 4 目录结构语义解读方法)
  3. 依赖关系清单

    • 跨文件引用(配置引用、脚本导入、模板依赖)
    • 断链标记(NOT_FOUND / EXTERNAL)
    • 每条引用标注 source_file 的编码(如 "config/main.json (utf-8) → database.ini (gbk)") 编码来源: analysis_report.json → file_inventory[].encoding 或 Deer/索引.json → entry["encoding"]。 用途: 修改被引用文件前获知编码,避免用错误编码写入导致损坏。
  4. 配置与数据模型

    • 配置 Schema(JSON Schema 格式,仅包含匹配关键词的节点)
    • 本地数据库表结构
    • 敏感项清单(HIGH sensitivity key)
    • 每项必须附带 source_encoding(来自 Phase 2 Step 2.2)。 示例: password: **** → config/db.ini (源文件, 编码: gbk)
  5. 接口与入口清单

    • 网络端点(Phase 2 Step 2.5 聚合的 URL/host/port/server)
    • 脚本入口点(Phase 2 Step 2.3 提取的 main / start / run 标识)
    • CLI 参数模式(Phase 2 Step 2.3 从脚本中 regex 提取的 --flag / -f 模式)
    • 文件路径引用(Phase 2 Step 2.5 聚合的 path/dir/folder 值)
    • 每项标注源文件编码(来自 Step 2.5 source_encoding),如: https://api.example.com → config/client.json (utf-8)
  6. 待验证清单

    • 所有 C3 [推测] 级发现
    • 所有 "[矛盾]" 标记项
    • 建议的后续分析方向

#### Final Output Audit Checklist

| # | 检查项 | 方法 | 不合格处理 |
|---|--------|------|-----------|
| 1 | 所有发现均有置信度标签 | 扫描每条发现 | 强制补填,无则标记 [未知] |
| 2 | 无空体 [未知] | 每个 [未知] 必须有明确的"原因"说明 | 补写原因 |
| 3 | 无无声跳过的阶段 | 每个阶段显式标记 | 补标跳过原因 |
| 4 | 所有 [已确认] 有 ≥2 个交叉来源 | 检查证据数组 ≥2 个独立来源 | 降级为 [建议] 或 [推测] |
| 5 | 无主观词汇 | 搜索"可能"、"也许"、"大概"、"应该" | 替换为置信度标签或删除 |
| 6 | 证据链完整 | 每条非平凡发现标注来源(工具、文件、命令) | 补全 |
| 7 | 章节标题/标签 全中文 | 标题、表头、置信度标签无英文 | 修正 |
| 8 | 核心目录有结构树 | 重要目录不以扁平文件列表呈现(参见 Section 4) | 补充结构树 |
| 9 | 核心原则违规已标记 | 如有违规,对应节标记 [跳过] 或 [不可复现] | 补标 |

---

#### Step 3.1 — 执行合规自查(Agent 自我审查)

Phase 3 报告生成后,Agent 必须逐项核对以下清单。任何一项失败 → 报告标注 [合规未通过: #N], 修正后重新验证。全部通过方可交付。

执行合规自查表(9 项):

| # | 检查项 | 验证方法 | 失败标记 | |---|--------|---------|---------| | 1 | Phase 1 → Deer 索引完整 | 检查 meta["total_files"] + meta["total_dirs"] = len(entries) + len(uncategorized) | [合规未通过: 映射不完整] | | 2 | 分类体系一致 | 遍历 entries,category 字段仅有 flow/conf/gate/base 四值,无 Phase 1 标签残留 | [合规未通过: 分类标签不一致] | | 3 | 编码列已回填 | [e for e in entries if e["encoding"] == "PENDING"] → 输出为空 | [合规未通过: 编码未回填] | | 4 | 置信度合规 | 每条 C1 [已确认] 发现至少 2 个 evidence 来源 | [合规未通过: 伪C1发现] | | 5 | 路径语法合规 | entry["path"] 无 +/* /(n) 符号,每 entry 单一路径,非文件实体已在 notes 标注 | [合规未通过: 路径语法] | | 6 | 所有文件有痕迹 | Phase 1 ls 清单中的每个文件都在 entries 或 uncategorized 中有对应 entry | [合规未通过: 文件遗漏] | | 7 | 安全围栏验证 | Deer/ 之外的所有目标文件 mtime/size 无变化 | [围栏违规: <文件>] | | 8 | Deer 索引完整性 | Deer/ 目录含 护栏.md + 向导.md + 索引.json + 变更日志.md + 快照/快照日志.md + ≥1 子目录含 索引.json | [合规未通过: Deer不完整] | | 9 | 无跳过步骤 | 每个 Phase/Step 显式标记 已完成/[跳过: 原因]/[不可复现] | [合规未通过: 无声跳过] |

判定: 9/9 通过 → 标记 [合规通过],交付报告 ≤8/9 → 标记 [合规未通过],逐项修正后重新执行自查


---

## 4. 目录结构语义解读 (Directory Structure Semantic Interpretation)

### 4.1 核心规则

对分析目标中**任何具有架构意义的关键目录**,**禁止输出扁平文件列表**。必须传达目录的**结构性意义**和**业务角色**。

### 4.2 如何识别"需要结构树的关键目录"(启发式判定)

一个目录满足以下 **任意 2 条** 即判定为"架构级关键目录":

| # | 启发式信号 | 说明 |
|---|-----------|------|
| 1 | **含可执行文件** | `.exe`/`.dll`/`.so`/`.jar` 等与子目录混在同一层 |
| 2 | **一级子目录数 ≥ 5** | 内部结构复杂的目录,非简单文件集合 |
| 3 | **文件类型跨 ≥ 3 个分类** | 同时含 二进制+配置+脚本+数据 |
| 4 | **路径深度 ≥ 2 且含配置/脚本** | 如 `app/core/config/`,深度嵌入架构 |
| 5 | **存在同名或功能相关的子系统目录** | 如 `plugins/`、`modules/`、`engines/`、`services/` |
| 6 | **目录名暗示架构角色** | 如 `core/`、`server/`、`data/`、`config/`、`scripts/` |

**反例 — 不需要结构树的目录**: 纯数据目录(全是 `.jpg`)、临时文件目录(`temp/`、`cache/`)、单层日志目录、第三方库扁平堆放的 `libs/` — 这些用扁平列表即可。

### 4.3 三层分析法

针对判定为架构级的关键目录,执行以下三层分析:

第一层 — 一级子目录结构树: 列出目标目录的直属子目录和根级关键文件,以树状图形式呈现。 只列一级子目录,不深入到叶子文件(根级配置文件例外)。

第二层 — 子系统功能分组: 将子目录/文件按业务功能分组,每组赋予一个中文"角色标签"。 标签说明该系统是干什么的、为什么重要。

第三层 — 关键文件标注: 对分组中的代表性文件标注业务含义和置信度。


### 4.4 输出格式

<目录名>/ — <一句话概括该目录在整体架构中的角色> │ ├── 🔧 <角色标签1> [最低: [推测]] │ ├── <关键文件或子目录> — <业务含义> [必填: [已确认]/[建议]/[推测]] │ └── ... │ ├── 📜 <角色标签2> │ └── ... │ └── 🗄️ <角色标签N> └── ...


角色标签从实际文件内容推导:
- 含 `.exe`/`.dll` → "核心引擎"、"运行时"
- 含配置类文件 → "资源配置"、"启动配置"
- 含脚本/源码 → "脚本/自动化"、"业务逻辑"
- 含数据库文件 → "数据持久化"、"本地存储"
- 含插件/模块子目录 → "扩展/插件系统"
- 含日志子目录 → "日志/审计"

**不得凭空赋予业务含义**。无直接证据时标注 `[推测]`。

### 4.5 约束

| 约束 | 说明 |
|------|------|
| 禁止扁平列表 | 不得仅列出文件名和大小,必须附功能分组 |
| 不得编造功能 | 每个子系统角色必须基于实际文件内容推断 |
| 置信度标注 | 子系统角色如无直接证据,标注 [推测] |
| 比例适度 | 一级子目录 ≤ 20 个时全列;> 20 个时按重要性排序只列 TOP 15 |
| 中文输出 | 子系统角色标签必须用中文 |

### 4.6 示例:某后端服务的 `ServerCore/`

ServerCore/ — 后端 API 服务的核心逻辑层 │ ├── 🧠 核心引擎 │ ├── api_server.exe [4.2MB, PE64 CUI] — 主服务进程 [已确认] │ └── worker_pool.dll [1.8MB] — 异步任务工作池 [推测] │ ├── 📜 业务脚本 (scripts/) │ ├── handlers/ — 42个请求处理器脚本 [已确认] │ ├── migrations/ — 数据库迁移脚本 [已确认] │ └── tasks/ — 定时任务定义 [已确认] │ ├── 🗺️ 路由系统 (routes/) │ ├── api.yaml [12KB] — REST API 路由定义 [已确认] │ └── middleware/ — 中间件链配置 [已确认] │ ├── ⚙️ 资源配置 │ ├── server.ini [8KB] — 主配置文件 [已确认] │ ├── database.ini — 数据库连接参数 [已确认] │ └── cache.ini — 缓存策略配置 [已确认] │ ├── 🏰 持久化数据 │ ├── storage/ — 本地文件存储 [已确认] │ └── sessions/ — 会话状态持久化 [已确认] │ ├── 📊 日志体系 │ ├── access_log/ — 访问日志 [已确认] │ └── error_log/ — 错误日志 [已确认] │ ├── 🔌 插件/扩展 │ ├── plugins/ — 可插拔功能模块 [推测] │ └── lua/ — Lua 扩展脚本(当前未启用: enable_lua=0)[已确认] │ └── 🗄️ 数据库支撑 ├── sqlite3.dll — SQLite 引擎 [已确认] └── ip_location.db [5MB] — IP 归属地数据库 [已确认]


### 4.7 解读对比:错误 vs 正确

| 错误做法(扁平列表) | 正确做法(结构树+功能分组) |
|----------|---------|
| `scripts/handlers/auth-0.lua (88B)` | `scripts/handlers/ — 请求处理器脚本,用户认证模块入口 [已确认]` |
| `tiles/000001.dat (48KB)` | `tiles/ — 997个数据块文件 [已确认]` |
| `config/scheduler.txt (1.4KB)` | `config/scheduler.txt — 定时任务配置 [已确认]` |

---

## 5. Quick Reference — Tool Table (零外部依赖)

本技能所有分析操作使用 **Reasonix 内建工具 + Python 标准库**,不依赖任何外部 CLI 程序。

| Analysis Type | Method (Python / bash built-in) | 说明 |
|---|---|---|
| **File type ID** | `python3 -c "import mimetypes; print(mimetypes.guess_type(p)[0])"` 或后缀判定 | 不依赖 `file` 命令 (WSL/Git Bash) |
| **Directory traversal** | `ls` / `glob` (Reasonix built-in) | 不依赖 `find` / `dir /s` |
| **JSON parsing** | `json.load()` (Python stdlib) | 不依赖 `jq` |
| **YAML parsing** | `yaml.safe_load()` (Python PyYAML) | 不依赖 `yq` |
| **XML parsing** | `xml.etree.ElementTree` (Python stdlib) 或 `defusedxml` | 不依赖 `xmlstarlet` |
| **INI/CFG parsing** | `configparser` (Python stdlib) | — |
| **TOML parsing** | `tomllib` (Python 3.11+ stdlib) 或 `tomli` | — |
| **SQLite probing** | `sqlite3` (Python stdlib) | 不依赖 `sqlite3.exe` |
| **Entropy check** | Python `math.log2` | 不依赖 `ent` |
| **Encoding detect** | `chardet` (Python) — 建议采样 ≥ 8KB,置信度 < 0.8 时检查 BOM/二进制回退 | — |
| **Regex matching** | Python `re` module | 不依赖 `grep -E` / `findstr /R` |
| **mtime query** | `bash` 内建 `stat` (Linux/macOS) 或 PowerShell `Get-ChildItem` (Windows) | 仅 1.6 时效性校验使用 |
| **文本解码** | Python `open(f, encoding=detected_encoding)` | 编码来源: Deer/索引.json 的 entry["encoding"] 字段 |

> ⚠ **依赖清零原则**: 上表左侧列出的所有 Method 均可在 Reasonix subagent 环境中直接执行。
> 禁止使用任何未在上表列出的外部 CLI 工具。若某项 Method 在当前环境不可用,
> 必须标记 `[SKIP: tool unavailable]` 并继续,不得尝试安装或寻找替代外部工具。

---

## Appendix A: Defensive Rule Cards

| Scenario | Rule (English) | Rule (中文) |
|---|---|---|
| String `admin` found in config | Tag `[建议]` username; NEVER claim "admin account exists" | 标记 [建议] 用户名;绝不声称"存在 admin 账户" |
| File `config.json` exists but is empty `{}` | Output `"exists but empty"`, tag `[未知]` | 输出"配置文件存在但为空",标记 [未知] |
| Function name contains `Test` or `Debug` | Tag `[推测]` "possible debug interface"; NEVER use for production assertion | 标记 [推测] 可能的调试接口 |
| High entropy, no other encryption evidence | Tag `[推测]` "suspected encrypted", recommend manual review | 标记 [推测] 疑似加密 |
| IP address found in config/strings | Record only; NEVER claim "this address is connected to" | 仅记录;绝不声称"连接了该地址" |
| Placeholder values (`your_token_here`, `<PASSWORD>`, `****`) | Tag `[建议]` with `value_is_placeholder: true` | 标记 [建议] 附带"值为占位符" |
| Two evidence sources of different types found together | Do NOT infer: `port` string + `password` config != "database credentials" | 不要组合推断:端口 + 密码 ≠ 数据库凭据 |
| No config files on disk + no path patterns in text files | Tag `[未知]` "config storage location cannot be determined". NEVER guess registry or AppData without evidence. | 标记 [未知] 配置存储位置无法确定 |
| File/directory name is opaque (random string, hash-like, no semantic meaning) | Record as-is; use file content summary in "说明" column. NEVER guess the purpose from the name alone. Tag `[建议]` with reason "文件名不透明,含义来自内容分析" | 文件名无语义时记录为文件内容摘要,不加猜测 |
| File name is semantic but misleading (e.g. `cleanup_utils.exe` actually performs HTTP logout, not file cleanup) | Trust behavior evidence over filename. If content/behavior contradicts the name, record the actual behavior and tag filename as "MISLEADING_NAME". NEVER use filename alone as functional evidence. | 文件名有语义但与行为矛盾时,以行为证据为准,标记文件名"误导性命名" |
| Text file > 100KB that is not JSON/YAML/INI/TOML | Read first 512 bytes only; record size and encoding, skip full content. Mark "LARGE_TEXT_SKIPPED" | 超大文本仅读前 512 字节 |
| File encoding not recorded before modification | Modifying a text file without knowing its original encoding will corrupt it. Always read entry["encoding"] from Deer/索引.json before any write. If encoding is "UNKNOWN", detect it first (chardet, full file, see Phase 2 Step 2.1) before touching the file. NEVER assume UTF-8. After rollback (B.6.5), restore encoding from snapshot log instead of re-detecting. | 修改文件前必须从 Deer/索引.json 的 entry["encoding"] 字段获取原编码。编码为 "UNKNOWN" 时先用 chardet 全量检测(见 Phase 2 Step 2.1),绝不假设 UTF-8。回滚操作后从快照日志恢复编码,不重新检测。 |

---

## Appendix B: Deer 索引系统 — 验证与创建

AAK 内建 Deer 索引系统承担三重角色:

| 角色 | 说明 |
|------|------|
| **全量覆盖验证** | 核心方程 `N_total = M_mapped + K_uncategorized` 保证零遗漏 |
| **交叉验证物证** | 每个 Deer entry = 一条可 `Test-Path` 验证的磁盘实体,Phase 3 交叉验证以 Deer 索引 JSON 为 Source B 基线 |
| **重分析加速器** | Deer/ 存在于目标目录后,再次分析时 1.6 预检命中 → 直接复用已有报告,跳过 Phase 1–3 |

Deer/ 创建位置: `<target_path>/Deer/`。索引 JSON 中所有 path 字段值均为相对于目标根目录的真实相对路径,
与 `ls` / `Test-Path` 可直接对账。

> 完整 Deer 规范参见 ATK 技能(Appendix D/E/F)。以下为 AAK 专用的精简版,
> 保留验证引擎和创建流程,省略回收机制和高级关联关系表。

### B.1 规则一:建立映射 — 全量扫描 + 原子写入

#### 第零步:全量扫描(强制前置)

步骤0.1 — 获取全量清单 ls <目标目录> (Depth 0) 输出: 完整文件清单(文件名 + 大小 + 类型)

步骤0.2 — 计数 N_file = 文件总数 N_dir = 目录总数 N_total = N_file + N_dir

步骤0.3 — 分类 对清单中每一项按默认分类规则判定 flow / conf / gate / base:

     | 包含内容 | 默认分类 |
     |---------|---------|
     | .exe / .dll / .so / .elf / 导出符号 / CLI 入口 | gate |
     | .ini / .json / .yaml / .xml / .conf / .cfg / .env / 注册表 | conf |
     | 网络请求 / API 调用 / socket / HTTP / TCP / 域名 / IP | flow |
     | 版本信息 / 打包标记 / 熵值 / 整体架构说明 / README | base |
     | 无法匹配以上 → 标记"未分类" | 待分类 |

步骤0.4 — 验证方程 N_total = 已分类数 + 未分类数 等式不成立: - 若差异 ≤ 5 且为日志/临时文件类 → 标记 [VOLATILE_ENV: 扫描期间目标目录发生文件变动] 并列出差异文件清单,允许继续分析。方程写为: N_total ≈ M_mapped + K_uncategorized (含 Δ=N_diff) - 若差异 > 5 或涉及 CONFIG/EXECUTABLE 类 → 报告"扫描计数不一致,重新扫描" [失败]


#### 第一步:写入映射(原子提交)

步骤1.0 — 构建 JSON 索引结构 Deer/索引.json 采用以下结构:

{ "meta": { "target_path": "<目标目录绝对路径>", "created_utc": "<ISO 8601>", "last_verified_utc": "<ISO 8601>", "version": 2, "total_files": <N_file>, "total_dirs": <N_dir>, "mapped": <已分类数>, "uncategorized": <未分类数> }, "entries": [ { "category": "conf|flow|gate|base", "path": "相对目标根目录的真实相对路径", "type": ".ini|.exe|.dll|.json|.dat|...", "size_bytes": <整数>, "encoding": "utf-8|gbk|binary|PENDING|UNKNOWN", "related_files": ["相对路径", ...], "verified_utc": "<ISO 8601 或 null>", "status": "verified|path_broken|reclassified|deleted", "reclassify_note": "RECLASSIFIED: CONFIG→DATA (parse failed) 或 null", "is_aggregate": false, "file_count": null, "pattern": null, "notes": "业务说明中文" } ], "uncategorized": [ { "path": "相对路径", "type": ".blob|.dat|...", "reason": "无法分类的原因", "checked_utc": "<ISO 8601>" } ] }

步骤1.1 — 逐条构建 entries 数组 每个文件对应一个 entry 对象。字段填充规则:

     category: 按 B.1 步骤0.3 默认分类规则判定 (flow/conf/gate/base)
     path: 文件在磁盘上的真实相对路径。禁止别名、符号名、虚拟路径
     type: 文件后缀,如 .exe / .dll / .ini / .json / .dat
     size_bytes: 整数,字节数
     encoding: 两阶段填充。
       Phase 1 出口: 所有文件统一填 "PENDING"(不做 binary/文本 预判)。
         理由: 后缀不可靠(.dat 可能是 UTF-8 文本),
         提前标 "binary" 会导致编码检测永久跳过该文件(单向门 bug)。
       Phase 2 Step 2.1: 编码检测完成后,将 "PENDING" 替换为实际编码值
       (utf-8 / gbk / shift_jis / binary / UNKNOWN)。
       binary 判定在 Phase 2 完成——含 null 字节且无可打印文本时标记。
     related_files: 字符串数组。填入本文件直接依赖/驱动/生成的其他文件路径,无则 []
     verified_utc: Phase 1 出口填 null,B.1 第二步 Test-Path 验证时写入
     status: Phase 1 出口填 null,验证后填 "verified";失败填 "path_broken"
     reclassify_note: Phase 2 发现需修正分类时回写,否则 null
     is_aggregate: 聚合条目为 true,普通条目为 false
     file_count: 聚合条目填写文件数,普通条目为 null
     pattern: 聚合条目填写文件名模式(如 "tiles/NNNNNN.dat"),普通条目为 null
     notes: 必须填写,不可留空。该文件在系统中的角色、用途、关联说明
            禁止 "这是个文件" / "未知" / 空字符串
            无法确定业务含义 → "待确认: <原因>"

     命名与路径约束(强制):
       - path 必须为相对于目标根目录的真实相对路径,与 ls 输出可直接对账
         禁止: 别名、符号名、虚拟路径、手工构造的假名
       - path 仅供 Test-Path 可验证的磁盘实体。网络端点(URL/IP/域名)不得填入
         path 字段,应在 notes 中以完整 URL 形式记录
       - path 不得含括号注释(如 "GameViewer.exe (根级)")
         每个磁盘实体独占一个 entry
       - 文件名/目录名 必须为磁盘上 ls/dir 列出的原始名称,不得重命名或美化

     同质数据目录聚合规则(严格限制):
       仅 base 分类允许聚合。flow/conf/gate 禁止聚合——必须逐文件映射
       满足以下全部条件的目录,可在 base 分类下聚合为一个 entry:
         1. 目录内文件数 ≥ 20
         2. 目录内文件类型 ≤ 3 种且高度同质
         3. 文件名存在明显模式(如 log_YYYYMMDD.txt)
         4. 非 CONFIG / SCRIPT / EXECUTABLE / LIBRARY 类
       聚合 entry 格式:
         "category": "base",
         "path": "tiles/",
         "type": ".dat",
         "is_aggregate": true,
         "file_count": 997,
         "pattern": "tiles/NNNNNN.dat",
         "size_bytes": null,
         "encoding": "binary"
       聚合 entry 计入 M_mapped

步骤1.2 — 写入未分类数组 无法归入 flow/conf/gate/base 的项写入 uncategorized 数组 每个元素: path / type / reason / checked_utc 禁止静默跳过未分类项

步骤1.3 — 写入后计数验证 读取 Deer/索引.json: M_mapped = len(entries) K_uncategorized = len(uncategorized) total = json["meta"]["total_files"] + json["meta"]["total_dirs"] 验证: total ≈ M_mapped + K_uncategorized(允许 Δ≤5 的 VOLATILE_ENV 软失败) 不成立 → [写入失败: 映射不完整],回滚 成立 → 更新 json["meta"]["mapped"] = M_mapped 更新 json["meta"]["uncategorized"] = K_uncategorized json.dump 写回磁盘


#### 第二步:逐一验证去重

步骤2.1 — 逐条 Test-Path 验证 对 entries 数组每个 entry 的 path 字段执行 Test-Path 通过 → entry["status"] = "verified", entry["verified_utc"] = 当前时间 失败 → entry["status"] = "path_broken", entry["verified_utc"] = 当前时间 不删除 entry,保留历史记录 更新 meta["last_verified_utc"]

步骤2.2 — 去重检查 遍历 entries,相同 path 出现在多个 entry → 合并(保留最完整字段),删除重复 entries ∩ uncategorized 交叉 → 从 uncategorized 移除(已分类优先)

步骤2.3 — 最终校验 total = meta["total_files"] + meta["total_dirs"] mapped = len(entries)(去重后) uncat = len(uncategorized)(去重后) 与 total 比对 → 必须一致(允许 Δ≤5) json.dump 写回磁盘


**禁止**: 凭记忆写入文件名、模糊词、一个 entry 含多个文件、抽样验证代替全量验证

### B.2 规则二:强制检索(JSON 字段查询 + 失败即止)

**检索顺序(禁止跳过):**

  1. read_file Deer/索引.json → json.load() → 存入内存 文件不存在 → [失败: Deer索引缺失]

  2. 按 category 字段筛选: Python: entries = [e for e in idx["entries"] if e["category"] == "flow"] 未找到匹配项 → [失败: 分类 flow 无条目] 支持多分类: [e for e in idx["entries"] if e["category"] in ("conf","gate")]

  3. 提取 path 字段 → Test-Path 验证当前存在

    • 存在 → 重置连续失效计数器 consecutive_failures = 0,正常使用
    • 不存在 → entry["status"] = "path_broken",记录 [路径失效: 日期] consecutive_failures += 1 if consecutive_failures >= 5: → 🔴 断路器触发: 声明 [DEER_INDEX_SUSPECT: 连续5条路径失效,索引可能大面积过期] → 停止当前检索,不再处理剩余条目 → 建议执行 B.5.3 全量重建 → 返回已有结果 + 断路器触发声明
    • 计数器仅连续计数(找到一条有效即归零),非累计
  4. 需要更详细信息 → 检查 entry["notes"] 字段(业务说明) 需要关联关系 → 检查 entry["related_files"] 数组

  5. 需要子索引 → read_file Deer/<category>_<...>/索引.json 子索引格式与主索引相同(含 meta + entries + uncategorized)


**Agent 操作示例**:

```python
import json
idx = json.loads(read_file("Deer/索引.json"))

# 查所有配置文件
confs = [e for e in idx["entries"] if e["category"] == "conf"]

# 查所有 > 1MB 的文件
large = [e for e in idx["entries"] if e.get("size_bytes") and e["size_bytes"] > 1_000_000]

# 查所有路径失效的
dead = [e for e in idx["entries"] if e["status"] == "path_broken"]

# 查编码待定的文本文件
pending = [e for e in idx["entries"] if e["encoding"] == "PENDING"]

# 读取某个 entry 对应的磁盘文件
e = next(e for e in idx["entries"] if e["path"] == "config/server/settings.ini")
content = read_file(e["path"])  # 注意编码: e["encoding"]

禁止: path 不存在时自行遍历替代路径、推测缺失字段、用 grep / 正则解析 JSON(JSON 用 json.load,不是文本匹配)、断路器触发后强行继续检索剩余条目

B.3 规则三:审查验证(全量 + 时效性)

每次交付分析前执行 9 项检查:

| # | 检查项 | 方法 | 失败处理 | |---|--------|------|---------| | 1 | 索引与磁盘一致性 | 逐条 Test-Path 每个 entry["path"],连续 ≥5 条失效触发断路器 → B.5.3 全量重建 | 标 status="path_broken";断路器触发 → 全量重建 | | 2 | 子索引一致性 | 每条记录 Test-Path 源文件 | 标 status="path_broken" | | 3 | 无孤儿文件 | 检查所有 Deer/ 下引用的磁盘路径 | 标 status="path_broken" | | 4 | 索引时效性 | 检查 meta["last_verified_utc"] | >7天标 [需重验] | | 5 | 无模糊词 | Python re.search(r'大概|可能|也许|应该', entry["notes"]) | 替换或删除 | | 6 | 大小一致性 | 主索引 vs 子索引 meta 比对 | 重新 ls 覆盖 | | 7 | 验证工具可复现 | 每步记录验证工具名 | 补工具名 | | 8 | 0文件目录标注 | 目录 entry 标注 file_count | 补 ls 计数 | | 9 | 全量覆盖方程 | total = meta["mapped"] + meta["uncategorized"] | 不成立则补全 |

B.4 Deer 索引目录创建规范

触发时机

分析完成并交付 analysis_report.jsonanalysis_summary.md 后, 必须提示用户是否创建 Deer 索引目录。

禁止未经用户确认自动创建。

目录命名规则(绝对值,不可变更)

Deer 目录创建位置: <target_path>/Deer/ — 即被分析目标目录的顶层。 这样 Deer 索引与目标文件同目录共存,路径均为相对目标根目录的真实相对路径, 后续重分析时可直接通过 ls <target_path>/Deer/ 检测并复用。

<target_path>/              ← 被分析目标根目录
├── Deer/                   ← Deer 索引根(固定名称,不可变更)
│   ├── 护栏.md              ← Agent 导航约束(磁盘副本)
│   ├── 向导.md              ← 人工可读导航入口
│   ├── 索引.json            ← 主索引(机器优先,JSON 结构化)
│   ├── 变更日志.md           ← 审计轨迹(append-only)
│   ├── 快照/                ← 被动回滚保障(静默,不问不提)
│   │   ├── 快照日志.md       ← 进出记录(append-only)
│   │   └── <timestamp>_<path>/  ← 各快照目录
│   ├── flow_<内容说明>/     ← 数据流/通信/网络行为类
│   │   └── 索引.json
│   ├── conf_<内容说明>/     ← 配置/设置/参数类
│   │   └── 索引.json
│   ├── gate_<内容说明>/     ← 接口/入口/边界类
│   │   └── 索引.json
│   └── base_<内容说明>/     ← 基础信息/通用参考类
│       └── 索引.json
├── app/                    ← 原始目标文件(不受 Deer 影响)
├── config/
└── ...

内容说明必须基于证据(分析阶段的发现),不得凭空编造。 base_ 为基础元信息目录,不受"基于证据"规则约束。

创建流程

步骤1: 在目标目录顶层创建 Deer/ 根目录
       mkdir <target_path>/Deer/
       所有后续写入均在此目录下进行,不修改 Deer/ 外的任何目标文件

步骤1b: 创建快照系统
       mkdir <target_path>/Deer/快照/
       写入 Deer/快照/快照日志.md 初始内容:

       # 快照日志
       
       > 本文档记录所有进出 Deer/快照/ 的文件操作。
       > append-only,禁止删除、禁止修改已有记录。
       > Agent 不得主动提及快照系统,除非用户明确询问。
       
       | 时间 | 目标文件 | 快照路径 | 操作 | encoding | 触发原因 |
       |------|---------|---------|------|----------|---------|
       | <创建时间> | — | — | init | — | Deer 快照系统初始化 |

步骤2: 根据分析发现创建子目录
       - 网络/通信类  → flow_<内容说明>/
       - 配置设置类   → conf_<内容说明>/
       - 接口入口类   → gate_<内容说明>/
       - 基础信息     → base_<内容说明>/(始终创建)

步骤3: 写入 Deer/索引.json
       3a. 构建 meta 对象(分类定义表 = B.1 步骤0.3 的默认分类规则)
       3b. 构建 entries 数组(B.1 步骤1.1 的逐条映射格式)
       3c. 构建 uncategorized 数组(未分类项)
       3d. json.dump 写入磁盘,indent=2 保证人类可读

步骤4: 创建各分类子索引
       在每个子目录下创建 索引.json
       格式与主索引相同: { meta, entries, uncategorized }
       entries 仅包含该分类的文件
       对架构级关键目录(判定标准见 Section 4.2),在子索引的 meta 中
       嵌入 Section 4.4 的结构树(作为 meta.architecture 字段)

步骤5: 创建入口向导 Deer/向导.md
       按任务组织(非按分类组织)。模板:

       # <软件名> — 目录地图

       ## 快速入口
       | 我想... | 看这里 | 说明 |
       |---------|--------|------|
       | 改参数/开关 | → [conf_<...>/](#) | 端口、开关、环境变量 |
       | 看文件结构 | → [base_<...>/](#) | 整体目录树和依赖关系 |
       | 查数据流向 | → [flow_<...>/](#) | 配置引用的外部端点 |
       | 了解整体架构 | → [base_<...>/](#) | 子系统分组和角色说明 |

       ## 按任务导航
       ### 改配置
       - **[conf_<...>/]** — 主配置文件及参数说明
       ### 看结构
       - **[base_<...>/]** — 目录结构树和子系统角色
       ### 查依赖
       - **[关联关系.md]** — 跨文件引用和断链清单

步骤5b: 创建变更日志 Deer/变更日志.md
        Deer 索引的修改溯源文件。初始内容:

       # 变更日志
       
       > 本文档记录目标目录内所有文件的修改历史。
       > 每次 Deer 索引更新、文件增删改、重新分析均在此追加记录。
       
       | 时间 | 文件 | 操作 | 原因 | 操作者 |
       |------|------|------|------|--------|
       | <创建时间> | Deer/ | 创建 | 首次 AAK 分析,建立 Deer 索引 | AAK Agent |

步骤5c: 创建护栏文件 Deer/护栏.md
        此文件是 Agent 上下文截断后的唯一恢复锚点。
        内容必须与技能开头的"Deer-导航模式激活"硬约束块等价(非简化版)。
        模板(按此逐字写入,禁止省略任何段落):

> 🦌 **Deer-导航模式 — 硬约束(护栏文件)**
>
> **你在读这个文件,说明你的上下文已截断,Deer 规则丢失了。
>  本文件是恢复锚点——它包含与 AAK 技能第 1 层完全相同的约束规则。**
>
> 本文件由 AAK 分析创建,与 Deer 索引共存,永不删除。
>
> ## Deer-导航模式规则
>
> | ✅ 唯一合法操作 | 🚫 严禁操作 |
> |---|---|
> | `read_file` 精确路径(来源: Deer/向导.md → 索引.json (json.load) → entry["path"]) | `ls` / `dir` / `glob` / `find` / `tree` 目录遍历 |
> | 读取 `Deer/` 下的索引/向导/变更日志/护栏 | `grep -r` / `code_index outline` 递归搜索 |
> | 写入 `Deer/变更日志.md` 记录修改;`json.dump` 更新 `Deer/索引.json` | `bash` 执行 os.walk / Get-ChildItem -Recurse / find 等遍历脚本 |
> | — | `read_file` 试探路径存在性(猜测路径后 read 验证) |
>
> ## 护栏自检
>
> 每次操作目标目录前:
> 1. 检查 Deer/ 是否存在 → 若存在,必须走导航链
> 2. 不确定文件路径 → 查 Deer/向导.md,禁止 ls 探索
> 3. 修改文件后 → 记录到 Deer/变更日志.md
>
> ⚠ 违规 → [Deer绕行违规],分析结论无效。
> 例外: AAK 技能 Phase 1 首次建索引时允许 ls/glob(技能内部控制)。
>
> ## 🛡️ 断链处理
>
> - Deer/索引.json 不可解析 → 标记 [Deer损坏],建议重新运行 AAK
> - entry["path"] 文件缺失 → 标记 [路径失效],跳过,继续
> - 连续 ≥5 条路径失效 → 🔴 [DEER_INDEX_SUSPECT],停止检索,建议全量重建
> - 向导引用不存在的子索引 → 跳过该分类,用主索引 entries 按 category 筛选代替
>
> ## 📸 快照系统(被动——不问不提)
>
> Deer/快照/ 目录存放修改前文件的自动副本。Agent 修改任何目标文件前,
> 系统已自动复制原文件到 Deer/快照/<timestamp>_<path>/ 下。
> Deer/快照/快照日志.md 记录所有进出(append-only)。
>
> ⚠ Agent 不得主动提及快照、不得主动建议回滚、不得展示快照内容。
> 仅当用户明确要求"回滚"或"查看修改历史"时才查阅快照日志。
>
> ## 📋 跨会话记忆
>
> Reasonix project memory (`deer-index-available`) 在 Deer 创建时自动写入。
> 若你已看到本文件但未感知该 memory,说明 memory 可能丢失——本护栏文件
> 即为降级恢复路径。正常情况 memory + 护栏双重保障。

步骤6: 最终验证
       ls Deer/ 确认目录结构完整:
         ├── 护栏.md           (必须)
         ├── 向导.md           (必须)
         ├── 索引.json         (必须,JSON 有效可解析)
         ├── 变更日志.md        (必须)
         ├── 快照/             (必须,含 快照日志.md)
         │   └── 快照日志.md
         ├── flow_<...>/        (含 索引.json)
         ├── conf_<...>/        (含 索引.json)
         ├── gate_<...>/        (含 索引.json)
         └── base_<...>/        (含 索引.json)
       验证索引中的路径与实际磁盘一致
       验证 python3 -c "import json; json.load(open('Deer/索引.json'))" 无异常

步骤7: 报告创建结果
       "Deer 索引目录已创建:
         ├── 护栏.md
         ├── 向导.md
         ├── 索引.json
         ├── 变更日志.md
         ├── 快照/
         ├── flow_<...>/
         ├── conf_<...>/
         ├── gate_<...>/
         └── base_<...>/"

步骤8: 创建 Reasonix project memory(记忆持久化)
       调用 `remember` 工具写入以下记忆,确保后续会话自动感知 Deer 存在:

       name: "deer-index-available"
       type: "project"
       title: "Deer 索引可用"
       body: |
         ## Deer 索引可用
         - 目标路径: <target_path>
         - Deer 索引路径: <target_path>/Deer/
         - 创建时间: <ISO 8601 timestamp>
         - 导航入口: Deer/向导.md
         
         ## Deer-导航模式已激活
         当 Agent 操作此目标目录时,进入 Deer-导航模式:
         禁止 ls / glob / find / dir / tree / grep -r / code_index outline /
         bash 遍历脚本 / read_file 试探路径。
         所有文件定位必须通过 Deer/护栏.md → 向导.md → 索引.json (json.load) → entry["path"] → read_file。
         修改文件后必须记录到 Deer/变更日志.md。
       
       此 memory 在每次新会话启动时自动加载,Agent 读取后即进入 Deer-导航模式,
       无需用户每次手动提醒。Deer 索引过期或删除时,调用 `forget` 移除此 memory。

禁止行为

| 禁止行为 | 原因 | |----------|------| | 未经用户确认自动创建 Deer 目录 | 违反"最小侵入"核心原则 | | 修改 Deer 根目录名称或子目录命名规则 | 绝对值和分类规则不可变更 | | 在无证据的情况下创建 flow/conf/gate 子目录 | 违反"真实文件为唯一依据"核心原则 | | 将 Deer 目录纳入 analysis_report.json | Deer 是辅助索引系统,非分析产出 |


B.5 Deer 索引维护与更新

Deer 索引不是一次性产物。目标目录文件变更后,索引必须同步更新, 防止退化为记录过期数据的无用文档。

B.5.1 变更检测(自动触发)

每次 AAK 技能启动时,1.6 预检自动判定 Deer 索引时效性(详见 1.6.2a):

  • 索引距今 ≤ 7 天 → 索引视为有效,进入 Deer-导航模式复用
  • 索引距今 > 7 天 → 标记 [DEER_STALE],强制重新分析(全量),完成后覆盖 Deer

B.5.2 增量更新(用户主动触发)

当用户明确告知"我修改了文件 X"或"新增了文件 Y",执行增量更新:

步骤0: (静默)创建快照
       若步骤2将对目标文件执行修改操作(edit_file/write_file/delete_file/move_file),
       先按 B.6.3 流程创建快照: 复制原文件 → 追加快照日志 → 静默继续
       不向用户报告。新增文件无需快照。

步骤1: 记录变更到 Deer/变更日志.md
       | <ISO时间> | <文件路径> | <修改/新增/删除> | <用户说明的原因> | user |

步骤2: 对变更文件重新分类
       - 修改 → 按 Phase 2 Step 2.1 编码检测流程重新判定类型/编码
         (不再使用 512B 简化检测——采用分级采样 + chardet + BOM 回退的完整流程),
         更新 entries 中对应 entry 的 type / encoding / size_bytes 字段。
         例外: 若此修改来自 B.6.5 回滚操作,encoding 以快照日志记录的值为准(见 B.6.5 步骤4)。
       - 新增 → ls 确认存在,全量流程(分类→编码检测→entries append 新 entry)
       - 删除 → entry["status"] = "deleted",不移除(保留历史)

步骤3: 更新 Deer/索引.json 中受影响的 entry
       - 更新 size_bytes(如文件大小变化)
       - 更新 verified_utc(刷新为当前时间)
       - 更新 encoding(如文件内容编码变化)
       - 更新 notes(如用户说明了修改原因)
       json.dump 写回磁盘

步骤4: 更新关联文件
       若变更文件被其他 entry 的 related_files 引用,检查关联是否仍有效
       失效 → 更新引用方的 related_files 或 notes

步骤5: 重新验证
       对受影响 entry 逐条 Test-Path,更新 status + verified_utc
       meta["last_verified_utc"] = 当前时间
       json.dump 写回磁盘

B.5.3 全量重建

以下情况必须全量重建 Deer 索引(重新执行 Phase 1→2→3):

| 触发条件 | 原因 | |----------|------| | 用户明确要求重新分析 | 覆盖旧 Deer | | 增量更新涉及 >10 个文件 | 变更过于分散,增量不可靠 | | N_total 方程验证失败 | 索引与磁盘不一致,存在遗漏 | | Deer/ 自身损坏 | 护栏/向导/索引任一文件缺失或不可读 | | 编码大面积 "UNKNOWN" | Phase 2 编码检测未完成,entries 中 encoding 字段大量为 UNKNOWN | | 断路器触发 (连续 ≥5 条路径失效) | 索引与磁盘大面积脱节,B.2 或 B.3 触发 [DEER_INDEX_SUSPECT] |

B.5.4 变更日志格式(Deer/变更日志.md)

# 变更日志

> 本文档记录目标目录内所有文件的修改历史。
> 每次 Deer 索引更新、文件增删改、重新分析均在此追加记录。

| 时间 | 文件 | 操作 | 原因 | 操作者 |
|------|------|------|------|--------|
| 2025-01-15T10:30:00Z | Deer/ | 创建 | 首次 AAK 分析建立索引 | AAK Agent |
| 2025-01-16T14:00:00Z | config/settings.json | 修改 | 用户更新端口号 | user |
| 2025-01-16T14:05:00Z | Deer/索引.json | 更新 | 同步 config/settings.json 变更 | AAK Agent |
| 2025-01-17T09:00:00Z | plugins/new.dll | 新增 | 用户部署新插件 | user |
| 2025-01-17T09:10:00Z | Deer/ | 全量重建 | 新增文件>10个,触发全量重分析 | AAK Agent |

规则:

  • 每行一条记录,时间精确到分钟
  • "操作者"列: user(用户手工修改)/ AAK Agent(Agent 自动同步)/ AAK Agent (re-analysis)(全量重建)
  • 禁止删除旧记录——变更日志是只追加(append-only)的审计轨迹
  • 变更日志自身不受 Deer 护栏约束(Agent 有权追加写入)

B.5.5 过期索引清理

若 Deer/ 索引对应的目标目录已不存在(用户删除或移动了目标),调用:

forget deer-index-available   # 移除 project memory

并提示用户: "目标目录已不存在,Deer 索引及关联 memory 已失效。是否需要删除 Deer/ 目录?"

禁止 Agent 自行删除 Deer/ 目录——必须经用户确认。


B.6 快照系统(被动回滚保障)

被动模式: 快照系统是静默安全网。Agent 不得主动提及快照、不得主动建议回滚、 不得在无用户询问时展示快照内容。用户不问,就当它不存在。

B.6.1 目录结构

Deer/快照/
├── 快照日志.md              ← append-only 进出记录
├── 2025-01-16T140500Z_config_server_settings.ini/
│   └── settings.ini         ← 修改前的原始副本
├── 2025-01-17T090000Z_plugins_new.dll/
│   └── new.dll              ← 删除前的原始副本
└── ...

命名规则: <ISO timestamp>_<安全路径>(路径中的 //\ 替换为 _

B.6.2 触发时机(自动、静默)

Agent 在执行以下目标文件修改操作前,必须自动创建快照:

| 操作 | 触发条件 | 快照内容 | |------|---------|---------| | edit_file / write_file | 目标路径在 <target_path>/ 下且不在 Deer/ 内 | 修改前原文件完整副本 | | delete_file / delete_range / delete_symbol | 同上 | 删除前原文件完整副本 | | move_file(目标在 target 内) | 同上 | 移动前原文件副本 |

不触发快照的操作:

  • 读取文件(read_filegrep
  • 写入 Deer/ 目录内的文件(索引/护栏/向导/变更日志/快照日志自身)
  • atk_output/ 输出目录写入报告
  • 创建新文件(目标路径原本不存在)→ 无需快照,但需记录到快照日志

B.6.3 快照执行流程

步骤1: 生成快照目录名
       snapshot_dir = "Deer/快照/" + now_utc.strftime("%Y-%m-%dT%H%M%SZ") + "_" + safe_path
       其中 safe_path = 目标相对路径.replace("/", "_").replace("\\", "_")

步骤2: 创建快照目录并复制原文件
       mkdir -p <snapshot_dir>
       cp <target_path>/<relative_path> <snapshot_dir>/<filename>
       注意: 保留原文件的编码、权限、时间戳(如平台支持)

步骤3: 追加快照日志
       写入 Deer/快照/快照日志.md(append-only):
       | <ISO时间> | <目标相对路径> | <快照目录名> | <即将执行的操作> | encoding:<原编码> | <触发原因> |
       
       示例:
       | 2025-01-16T14:00:00Z | config/settings.json | 2025-01-16T140000Z_... | edit_file | encoding:gbk | 用户要求修改端口号 |

       快照日志新增 encoding 列(B.6.4 表头同步更新),记录修改前 Deer/索引.json 中
       该文件的 entry["encoding"] 值。回滚时此值作为编码恢复锚点(见 B.6.5 步骤4)。

步骤4: 静默继续
       不向用户报告快照创建。继续执行用户请求的修改操作。

B.6.4 快照日志格式(Deer/快照/快照日志.md)

# 快照日志

> 本文档记录所有进出 Deer/快照/ 的文件操作。
> append-only,禁止删除、禁止修改已有记录。

| 时间 | 目标文件 | 快照路径 | 操作 | encoding | 触发原因 |
|------|---------|---------|------|----------|---------|
| 2025-01-16T14:00:00Z | config/settings.json | 2025-01-16T140000Z_config_settings.json | edit_file | gbk | 用户要求修改端口号 |
| 2025-01-17T09:00:00Z | plugins/old.dll | 2025-01-17T090000Z_plugins_old.dll | delete_file | binary | 用户要求删除旧插件 |
| 2025-01-17T09:30:00Z | config/settings.json | RESTORE: 2025-01-16T140000Z_config_settings.json | 回滚恢复 | gbk | 用户要求回滚端口修改 |

规则:

  • 每行一条记录,时间精确到秒
  • 新增 "encoding" 列(自本修订起),记录修改前 entry["encoding"] 值,供回滚时编码恢复锚定
  • "操作"列: edit_file / write_file / delete_file / delete_range / delete_symbol / move_file / RESTORE: <快照目录名>(回滚时记录)
  • 回滚操作也记录在案(视为一次"进入"快照目录的读操作)
  • 禁止删除旧记录——append-only
  • 快照日志自身不受 Deer 护栏约束(Agent 有权追加写入)

B.6.5 回滚操作(用户主动触发)

仅当用户明确要求"回滚文件 X"或"恢复到修改前的版本"时执行:

步骤1: 查询快照日志
       grep "<目标文件路径>" Deer/快照/快照日志.md
       列出该文件的所有快照版本,供用户选择

步骤2: 用户确认版本后执行恢复
       cp <snapshot_dir>/<filename> <target_path>/<relative_path>

步骤3: 追加恢复记录
       | <ISO时间> | <目标相对路径> | RESTORE: <快照目录名> | 回滚恢复 | <快照中的 encoding 值> | 用户要求回滚 |

步骤4: 更新 Deer 索引
       恢复后的文件可能与索引记录不一致 → 触发增量更新(B.5.2)。
       此外,编码恢复规则:
       a. 从快照日志中读取该快照行的 encoding 列(修改前记录的 entry["encoding"])
       b. 若该值非 "PENDING" / "UNKNOWN" / "binary" → 直接写入 entry["encoding"],
          跳过 B.5.2 的重新检测(避免 chardet 两次检测结果不一致导致编码漂移)
       c. 若该值为 "PENDING" / "UNKNOWN" → B.5.2 正常重新检测
       d. 若该值为 "binary" → 保留 "binary",不重新检测

禁止: Agent 在用户未明确要求时自行回滚。

B.6.6 快照清理

快照不自动清理。若用户明确要求清理快照:

  • 列出所有快照及其占用空间
  • 用户确认后删除指定快照目录
  • 在快照日志追加清理记录: | <时间> | — | DELETE: <快照目录名> | 清理 | 用户要求释放空间 |

Appendix C: AAK vs ATK — When to Use Which

| 场景 | 用 AAK | 用 ATK | |------|--------|--------| | 分析安装目录/项目树结构 | ✅ | ✅ (过重) | | 提取配置文件内容 | ✅ | ✅ | | 解读目录架构语义 | ✅ | ✅ (Appendix B) | | 解析 PE/ELF 头、导入导出表 | ❌ | ✅ Phase 2 | | 提取二进制字符串 | ❌ | ✅ Phase 2.3 | | 运行时行为探测 | ❌ | ✅ Phase 4 | | 网络抓包分析 | ❌ | ✅ Phase 4.3 | | Deer 索引目录创建 | ✅ Appendix B | ✅ Appendix E |

经验法则: 如果你的目标里有 .exe/.dll/.so 且你需要知道它们内部的行为 → 用 ATK。如果只是看目录结构、配置文件、脚本内容 → AAK 足够且更安全(零执行风险)。