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
6 changes: 6 additions & 0 deletions USER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -1872,6 +1872,9 @@ For scripts and AI agents that need to classify failures without substring-match
| `E012_INTERRUPTED` | The user interrupted the command with Ctrl-C / signal cancellation |
| `E013_INDEX_EXTRACTION_STALLED` | Index extraction made no forward progress within the bounded stall timeout |
| `E014_REGEX_MATCH_TIMEOUT` | A user-supplied regular expression exceeded the bounded match timeout while executing |
| `E015_FS_CASE_PROBE_FAILED` | Filesystem case-sensitivity probing failed before cdidx could select a safe path-casing policy |
| `E016_CHECKPOINT_NOT_FOUND` | The requested database checkpoint name does not exist |
| `E017_WORKSPACE_MANIFEST_INVALID` | A workspace manifest was found but failed JSON schema or safety validation |
| `E018_QUERY_NOT_FOUND` | A lookup that requires a result did not match an indexed entity |
| `E019_FILE_NOT_FOUND` | An exact indexed file path requested by a query command does not exist |
| `E020_LINE_OUT_OF_RANGE` | A requested source line falls outside the indexed file's 1-based line range |
Expand Down Expand Up @@ -4920,6 +4923,9 @@ raw match density を正確に測る、といった理由で全 raw chunk hit
| `E012_INTERRUPTED` | Ctrl-C / signal cancellation でユーザーがコマンドを中断した |
| `E013_INDEX_EXTRACTION_STALLED` | 制限付きの停止判定時間内に index 抽出が前進しなかった |
| `E014_REGEX_MATCH_TIMEOUT` | ユーザー指定の正規表現が実行中に制限付き match timeout を超えた |
| `E015_FS_CASE_PROBE_FAILED` | ファイルシステムの大文字小文字区別 probe に失敗し、安全な path casing policy を選択できなかった |
| `E016_CHECKPOINT_NOT_FOUND` | 指定されたデータベース checkpoint 名が存在しない |
| `E017_WORKSPACE_MANIFEST_INVALID` | workspace manifest JSON が見つかったが、schema または安全性の検証に失敗した |
| `E018_QUERY_NOT_FOUND` | 結果必須の lookup が indexed entity に一致しなかった |
| `E019_FILE_NOT_FOUND` | query command が要求した indexed file の完全一致 path が存在しない |
| `E020_LINE_OUT_OF_RANGE` | 要求した source line が indexed file の 1-based 行範囲外だった |
Expand Down
16 changes: 16 additions & 0 deletions changelog.d/unreleased/4644.docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: docs
issues:
- 4644
affected:
- USER_GUIDE.md
- tests/CodeIndex.Tests/DocumentationDriftTests.cs
---

## English

- **Documented the complete stable command error-code taxonomy (#4644)** — the USER_GUIDE now includes E015–E017 in its English error-code table, with a contract test keeping both language tables synchronized with `CommandErrorCodes`.

## 日本語

- **安定したコマンドエラーコード分類を完全に文書化しました (#4644)** — USER_GUIDE の日本語エラーコード表に E015–E017 を追加し、両言語の表と `CommandErrorCodes` の同期を契約テストで維持します。
40 changes: 40 additions & 0 deletions tests/CodeIndex.Tests/DocumentationDriftTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Reflection;
using System.Text.RegularExpressions;
using CodeIndex.Cli;
using CodeIndex.Database;

namespace CodeIndex.Tests;
Expand All @@ -21,6 +23,10 @@ public sealed class DocumentationDriftTests
@"`(?:[A-Z_][A-Z0-9_]*=\S+\s+)*(?<prefix>cdidx|dotnet\s+\./src/CodeIndex/bin/Debug/net8\.0/cdidx\.dll|dotnet\s+run\s+--project\s+src/CodeIndex\s+--)\s+(?<token>[^\s`|;&]+)[^`]*`",
RegexOptions.Compiled);

private static readonly Regex ErrorCodeTableRowRegex = new(
@"^\| `(?<code>E[0-9]{3}_[A-Z0-9_]+)` \|",
RegexOptions.Compiled | RegexOptions.Multiline);

private static readonly HashSet<string> KnownCdidxEntrypointTokens = new(StringComparer.Ordinal)
{
"--completions",
Expand Down Expand Up @@ -153,6 +159,24 @@ public void PreparedCommandCacheDefault_DocumentationMatchesRuntime()
Assert.Equal(2, content.Split(documentedRow, StringSplitOptions.None).Length - 1);
}

[Fact]
public void UserGuide_ErrorCodeTablesMatchCommandErrorCodes_Issue4644()
{
var content = RepositoryTestPaths.ReadNormalizedText("USER_GUIDE.md");
var expectedCodes = typeof(CommandErrorCodes)
.GetFields(BindingFlags.Public | BindingFlags.Static)
.Where(field => field.IsLiteral && field.FieldType == typeof(string))
.Select(field => (string)field.GetRawConstantValue()!)
.Order(StringComparer.Ordinal)
.ToArray();

var englishCodes = ExtractErrorCodesFromSection(content, "### Error codes", "### Debugging reader errors");
var japaneseCodes = ExtractErrorCodesFromSection(content, "### エラーコード", "### reader エラーのデバッグ");

Assert.Equal(expectedCodes, englishCodes);
Assert.Equal(expectedCodes, japaneseCodes);
}

[Theory]
[InlineData("README.md", "## Quick Start", "## すぐに試す")]
[InlineData("USER_GUIDE.md", "## Why cdidx", "## なぜ cdidx なのか")]
Expand Down Expand Up @@ -204,6 +228,22 @@ private static HashSet<string> ExtractWorkflowPathReferences(string relativePath
.ToHashSet(StringComparer.Ordinal);
}

private static string[] ExtractErrorCodesFromSection(string content, string heading, string nextHeading)
{
var sectionStart = content.IndexOf(heading, StringComparison.Ordinal);
if (sectionStart < 0)
throw new InvalidOperationException($"Missing documentation heading '{heading}'.");

var sectionEnd = content.IndexOf(nextHeading, sectionStart + heading.Length, StringComparison.Ordinal);
if (sectionEnd < 0)
throw new InvalidOperationException($"Missing documentation heading '{nextHeading}'.");

return ErrorCodeTableRowRegex
.Matches(content[sectionStart..sectionEnd])
.Select(match => match.Groups["code"].Value)
.ToArray();
}

private static HashSet<string> ExtractWorkflowReadmeReferences(HashSet<string> workflowFileNames)
{
var content = RepositoryTestPaths.ReadText(".codex", "workflows", "README.md");
Expand Down
Loading