Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

### Fixed

- Validate selected instruction files and `.agentconfigscoreignore` as in-repository regular files before opening contents, and revalidate instruction sources at read time. Internal file aliases keep their discovered scopes/locations; child directory symlinks and Windows junctions are not traversed. Preserve ignore-glob meaning while pruning excluded trees before descent.
- Fail operationally on unsafe, dangling, cyclic or unreadable selected sources instead of skipping them, exposing raw errors, or scoring incomplete text. Doctor checks actual source readability. Keep legacy `read-error` for report/suppression compatibility, not as a bypass for operational failures; unrelated non-instruction link cycles no longer crash path indexing. This is not an atomic filesystem sandbox.
- Prevent explicit `./` and `../` prose references from passing through an unrelated package's suffix match while retaining existing repository-root/AGENTS-scope interpretations and accepting explicit document-relative paths in other formats. Preserve significant hidden-directory dots and skip references with no in-repository interpretation before index lookup.
- Stop scans on directory traversal errors rather than silently using a partial path index. Scan/compare/feedback report operational exit `2` without success output; `doctor` exposes a structured `repository-paths` error. Raw traversal messages are not echoed, and excluded dependency/admin trees remain pruned.
- Avoid `dead-path` false positives for narrowly typed repository/remote slugs and immediate closed `(if exists)` prose references, without exempting other local paths, actual Markdown links or dangerous commands.
Expand Down
8 changes: 8 additions & 0 deletions docs/doctor.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The command is read-only and offline. It checks:
- whether `.agentconfigscore.json` exists and parses successfully;
- whether the config uses the canonical AgentConfigScore JSON Schema;
- whether supported coding-agent instruction files are discoverable;
- whether selected instruction sources can be safely resolved and read inside the scan root;
- whether the repository path index can be traversed without a filesystem error;
- whether the directory is inside a Git repository for `diff` workflows;
- whether `agent-config-score diff` can automatically resolve a safe local baseline;
Expand All @@ -28,6 +29,13 @@ that a file is missing. Excluded dependency/admin trees are not traversed by thi
index check. It checks path metadata only, not instruction quality, tracked-file
membership, or an atomic snapshot; access can change after the check completes.

The `instructions` check also reads each selected instruction source through the
scanner's regular-file/containment guard, without executing or semantically
evaluating its text. Invalid source links, unreadable instruction contents and an
invalid `.agentconfigscoreignore` become error checks rather than a successful
preflight. Internal file aliases are supported; child directory symlinks/junctions
are not traversed. See the [filesystem boundary and concurrency limits](limitations.md#instruction-file-filesystem-boundary).

For scripts and CI:

```bash
Expand Down
31 changes: 31 additions & 0 deletions docs/limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,37 @@ a task, or whether an instruction file is generally “good.”
**An A 100 result means that no active deterministic rule matched. It is not a
semantic quality certification.**

## Instruction-file filesystem boundary

Selected instruction files and `.agentconfigscoreignore` must resolve to regular
files inside the resolved scan root. Internal file symlinks remain supported;
findings, Markdown links and instruction scopes use the discovered alias's
repository-relative location, not the shared target's directory. An explicitly
supplied root alias is allowed and defines the resolved boundary.

Discovery does not descend through child directory symlinks or Windows junctions,
even when their targets are internal. Excluded dependency/build trees and
subtrees covered by an ignore pattern ending in `/**` are pruned before descent.
Other ignore patterns retain their filename-matching meaning. A source explicitly
excluded from discovery is not inspected and has no coverage claim.

Selected external, dangling, cyclic or non-regular file sources fail before their
contents are opened. Sources are revalidated before reading, and the resolved
target is opened. Failed discovery, resolution or instruction-content reads are
operational errors: scan/compare/feedback return `2` without a successful score or
new success report. `doctor` checks source readability and reports an `instructions`
error with exit `1`. Raw target paths and filesystem error details are not echoed
in these source diagnostics. Legacy `read-error` remains in the catalog for old
report/suppression compatibility, but cannot suppress a current operational failure.

This is **not a filesystem sandbox or an atomic snapshot**. A concurrent process
can still replace parents or targets between validation and open. Hard-link
identity and mount boundaries are not certified. Other explicitly chosen inputs,
configuration/workflow readers and report destinations are separate interfaces;
this guard does not claim to constrain every filesystem operation in the tool.
Non-instruction link cycles are excluded from the path index, not judged safe or
semantically correct. Keep repositories stable while scanning.

## Command interpretation

The `rm-rf`, `git-clean-force`, and `docker-system-prune` rules tokenize bounded
Expand Down
10 changes: 10 additions & 0 deletions docs/simplified/limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@

AgentConfigScore 的分数衡量已经检测到的、由规则定义的风险,不衡量模型智力、任务成功率或指令总体质量。**A 100 表示没有命中生效的确定性规则,不是语义质量或安全认证。**

## 指令文件的文件系统边界

选中的指令文件和 `.agentconfigscoreignore` 必须解析为扫描根目录内的普通文件。仓库内的文件符号链接仍受支持;发现位置、Markdown 相对链接和指令作用域使用链接所在的位置,不是共享目标的目录。用户明确指定的根目录别名可用,并以其解析后的目录为边界。

发现过程不跟随子目录符号链接或 Windows junction,即使目标在仓库内;依赖、构建目录以及明确由 `/**` 忽略模式覆盖的整棵子树会在进入前排除,其他忽略模式保留文件名匹配含义。明确忽略的来源不检查,也没有覆盖声明。

选中的越界、失效、循环或非普通文件来源会在打开内容前失败;读取前再次验证,并打开解析后的目标。发现、解析或指令内容读取失败时,扫描、`compare`、`feedback` 返回 `2`,不生成成功分数或新的成功报告;`doctor` 检查实际可读性,给出 `instructions` 错误并返回 `1`。这些来源诊断不回显原始目标路径或系统错误详情。`read-error` 仅为旧报告和旧豁免保留,不能豁免当前操作错误。

这不是文件系统沙箱,也不是原子快照:并发进程仍可能在验证与打开之间替换父目录或目标;不认证硬链接身份或挂载边界。其他显式输入、配置或工作流读取器、报告输出是独立接口,这个守卫不约束工具的所有文件系统操作。非指令文件的循环链接从路径索引排除,不代表安全或语义正确。扫描期间应保持仓库稳定。[完整英文边界](../limitations.md#instruction-file-filesystem-boundary)。

## 高分不代表没有问题

只要避开已知规则,下列内容仍可能得到 100 分:
Expand Down
1 change: 1 addition & 0 deletions docs/simplified/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ agent-config-score feedback . --output .agent-config-score/case.md
| 找不到命令 | 确认装入当前 Python 环境,并检查 Scripts/bin 的 PATH。v0.23.0+ 可用 `python -m agent_config_score`。 |
| 配置或工作流编码错误 | 保存为 UTF-8,不要用 UTF-16 文件替代。 |
| `Unable to read repository path index` | 运行 `doctor`,核对 `repository-paths` 错误并修复目录访问或 I/O 问题。部分索引不会生成成功报告。 |
| 扫描源解析或读取错误 | 在本地核对已选择的指令文件和忽略文件链接,目标必须是仓库内的普通文件;修复失效、循环链接或权限问题。`doctor` 给出 `instructions` 错误,不要把不完整扫描当成通过。 |
| 报告不可写 | 选择可写的文件路径,不是已有目录;检查父目录权限。 |
| 无法检测基线 | 运行 `doctor`,然后指定本地已有的默认分支引用。 |
| 禁止示例被报为危险指令 | 对照[支持的禁止语法(英文)](../instruction-context.md)检查具体上下文;工具不理解任意语言和改写。 |
Expand Down
10 changes: 10 additions & 0 deletions docs/traditional/limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@

AgentConfigScore 的分數衡量已偵測到、由規則定義的風險,不衡量模型智力、任務成功率或指令整體品質。**A 100 表示沒有命中生效的確定性規則,不是語意品質或安全認證。**

## 指令檔的檔案系統邊界

選取的指令檔與 `.agentconfigscoreignore` 必須解析為掃描根目錄內的一般檔案。儲存庫內的檔案符號連結仍受支援;發現位置、Markdown 相對連結與指令作用域使用連結所在位置,不是共享目標的目錄。使用者明確指定的根目錄別名可用,並以其解析後的目錄為邊界。

探索過程不跟隨子目錄符號連結或 Windows junction,即使目標在儲存庫內;相依套件、建置目錄,以及明確由 `/**` 忽略模式涵蓋的整棵子樹會在進入前排除,其他忽略模式保留檔名匹配的意義。明確忽略的來源不檢查,也沒有涵蓋範圍的聲明。

選取的越界、失效、循環或非一般檔案來源會在開啟內容前失敗;讀取前再次驗證,並開啟解析後的目標。探索、解析或指令內容讀取失敗時,掃描、`compare`、`feedback` 返回 `2`,不產生成功分數或新的成功報告;`doctor` 檢查實際可讀性,提供 `instructions` 錯誤並返回 `1`。這些來源診斷不回顯原始目標路徑或系統錯誤細節。`read-error` 僅為舊報告及舊排除設定保留,不能豁免目前的操作錯誤。

這不是檔案系統沙箱,也不是原子快照:並行處理程序仍可能在驗證與開啟之間替換父目錄或目標;不認證硬連結身分或掛載邊界。其他明確輸入、設定或工作流程讀取器、報告輸出是獨立介面,這個守衛不約束工具的所有檔案系統操作。非指令檔的循環連結從路徑索引排除,不代表安全或語意正確。掃描期間應保持儲存庫穩定。[完整英文界線](../limitations.md#instruction-file-filesystem-boundary)。

## 高分不代表沒有問題

只要避開已知規則,下列內容仍可能得到 100 分:
Expand Down
1 change: 1 addition & 0 deletions docs/traditional/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ agent-config-score feedback . --output .agent-config-score/case.md
| 找不到命令 | 確認安裝在目前 Python 環境,並檢查 Scripts/bin 的 PATH。v0.23.0+ 可用 `python -m agent_config_score`。 |
| 設定或工作流程編碼錯誤 | 儲存為 UTF-8,不要以 UTF-16 檔案取代。 |
| `Unable to read repository path index` | 執行 `doctor`,檢查 `repository-paths` 錯誤並修正目錄存取或 I/O 問題。部分索引不會產生成功報告。 |
| 掃描來源解析或讀取錯誤 | 在本機檢查已選取的指令檔與忽略檔連結,目標必須是儲存庫內的一般檔案;修正失效、循環連結或權限問題。`doctor` 提供 `instructions` 錯誤,不要將不完整掃描當成通過。 |
| 報告無法寫入 | 選擇可寫入的檔案路徑,不是既有目錄;檢查父目錄權限。 |
| 無法偵測基準 | 執行 `doctor`,再指定本機已存在的預設分支參照。 |
| 禁止範例被判為危險指令 | 對照[支援的禁止語法(英文)](../instruction-context.md)檢查上下文;工具不理解任意語言和改寫。 |
Expand Down
6 changes: 6 additions & 0 deletions docs/translations.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ interpretations remain, arbitrary suffix substitution is disabled for explicit
relative references, and index read failures stay operational/doctor errors.
Commands and the published v0.23.0 artifacts remain unchanged.

On 2026-10-15, both guides and limitation summaries were reviewed with the English
instruction-source containment/readability changes built on source revision
`7ced98d3c4569bb21dcdbb83b48f948d8abe9a3c`: internal file aliases, pruned directory
aliases, operational failures, doctor readability checks, legacy `read-error`,
and explicit non-atomic/non-sandbox boundaries. Published artifacts are unchanged.

When an English source page changes, review both variants together and record
the new source revision here. Preserve executable examples, rule IDs and JSON
keys verbatim. Keep the score limitations and failure/exit semantics aligned;
Expand Down
1 change: 1 addition & 0 deletions docs/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ Nothing is uploaded. Review and sanitize the draft yourself before sharing.
| Configuration / workflow encoding error | Save the file as UTF-8; do not copy a UTF-16 file into the integration. |
| Cannot write HTML, SARIF or Markdown | Choose a writable file path, not an existing directory; inspect parent-directory permissions. |
| `Unable to read repository path index` | Run `doctor` and check its `repository-paths` error. Fix directory access or I/O failures; no success report is emitted from a partial index. |
| Scanner source resolution/read error | Inspect selected instruction and ignore-file links locally. They must point to in-repository regular files; fix dangling links, cycles or permissions. `doctor` reports an `instructions` error. Do not treat an incomplete scan as a passing score. |
| `diff` cannot detect a baseline | Check `doctor`, then pass an available default-branch ref explicitly. |
| A prohibited command was flagged | Compare its exact context with the [supported prohibition grammar](instruction-context.md); arbitrary languages and paraphrases are not understood. |
| Historic GitHub run is red | Open the run for the current commit. Fixing a later commit does not erase an earlier failed run. |
Expand Down
6 changes: 4 additions & 2 deletions src/agent_config_score/doctor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from .config import CONFIG_NAME, SCHEMA_URL, ConfigError, load_policy
from .gitdiff import GitError, detect_base_ref, repository_root
from .scanner import _repository_path_index, discover
from .scanner import _read_scanner_source, _repository_path_index, discover


@dataclass(frozen=True)
Expand Down Expand Up @@ -149,8 +149,10 @@ def diagnose(root: Path) -> DoctorReport:

try:
files = discover(root)
for path in files:
_read_scanner_source(root, path)
except OSError as exc:
checks.append(DoctorCheck("instructions", "error", f"Could not discover instruction files: {exc}"))
checks.append(DoctorCheck("instructions", "error", f"Could not safely read instruction files: {exc}"))
files = None
if files:
checks.append(DoctorCheck(
Expand Down
2 changes: 1 addition & 1 deletion src/agent_config_score/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class PatternRule:
Rule("github-token", "error", "secret", 25, "Possible GitHub token", "Flags strings shaped like common GitHub personal, OAuth, user, server, or refresh tokens."),
Rule("aws-access-key", "error", "secret", 25, "Possible AWS access key", "Flags strings shaped like AWS access key IDs."),
Rule("private-key", "error", "secret", 30, "Private key material detected", "Flags PEM/OpenSSH private-key headers in persistent agent instructions."),
Rule("read-error", "warning", "other", 2, "Instruction file could not be read", "Reports a supported instruction file that could not be read during analysis."),
Rule("read-error", "warning", "other", 2, "Instruction file could not be read", "Legacy finding retained for historical report and suppression compatibility. Current scans fail operationally when a selected instruction file cannot be safely read, rather than scoring an incomplete analysis."),
Rule("context-too-large", "warning", "size", 12, "Persistent instruction context is very large", "Reports an instruction file estimated above 8,000 tokens."),
Rule("context-large", "warning", "size", 6, "Persistent instruction context is large", "Reports an instruction file estimated above 5,000 tokens."),
Rule("dead-path", "warning", "dead", 4, "Referenced repository path does not exist", "Flags repository-like paths referenced by agent instructions when the target path is absent."),
Expand Down
Loading
Loading