polydeukes 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/README.ko.md +30 -70
  2. package/README.md +31 -84
  3. package/dist/baseline.d.ts +37 -1
  4. package/dist/baseline.js +68 -1
  5. package/dist/bin.d.ts +3 -4
  6. package/dist/bin.js +79 -93
  7. package/dist/covenant/bash-line.d.ts +130 -0
  8. package/dist/covenant/bash-line.js +566 -0
  9. package/dist/covenant/declaration-engine.d.ts +108 -0
  10. package/dist/covenant/declaration-engine.js +415 -0
  11. package/dist/covenant/discipline.d.ts +103 -0
  12. package/dist/covenant/discipline.js +667 -0
  13. package/dist/covenant/dispatch.d.ts +153 -0
  14. package/dist/covenant/dispatch.js +237 -0
  15. package/dist/covenant/extract-steps.d.ts +122 -0
  16. package/dist/covenant/extract-steps.js +0 -0
  17. package/dist/covenant/mention.d.ts +117 -0
  18. package/dist/covenant/mention.js +209 -0
  19. package/dist/covenant/module.d.ts +25 -0
  20. package/dist/covenant/module.js +23 -0
  21. package/dist/covenant/mutation-rules.d.ts +40 -0
  22. package/dist/covenant/mutation-rules.js +146 -0
  23. package/dist/covenant/relations.d.ts +46 -0
  24. package/dist/covenant/relations.js +68 -0
  25. package/dist/covenant/run-covenant.d.ts +95 -0
  26. package/dist/covenant/run-covenant.js +164 -0
  27. package/dist/covenant/self-mod.d.ts +55 -0
  28. package/dist/covenant/self-mod.js +84 -0
  29. package/dist/covenant/shell-evidence.d.ts +38 -0
  30. package/dist/covenant/shell-evidence.js +247 -0
  31. package/dist/covenant/shell-mod.d.ts +84 -0
  32. package/dist/covenant/shell-mod.js +213 -0
  33. package/dist/covenant/supply.d.ts +54 -0
  34. package/dist/covenant/supply.js +50 -0
  35. package/dist/covenant/transcript-mod.d.ts +60 -0
  36. package/dist/covenant/transcript-mod.js +254 -0
  37. package/dist/covenant/ttl-witness.d.ts +47 -0
  38. package/dist/covenant/ttl-witness.js +80 -0
  39. package/dist/covenant-check.d.ts +72 -39
  40. package/dist/covenant-check.js +260 -121
  41. package/dist/diff-ir.d.ts +28 -0
  42. package/dist/diff-ir.js +310 -0
  43. package/dist/docs/README.ko.md +60 -0
  44. package/dist/docs/README.md +64 -0
  45. package/dist/docs/catalog.json +480 -0
  46. package/dist/docs/concepts/judgment.ko.md +113 -0
  47. package/dist/docs/concepts/judgment.md +113 -0
  48. package/dist/docs/how-to/configure-project.ko.md +99 -0
  49. package/dist/docs/how-to/configure-project.md +98 -0
  50. package/dist/docs/how-to/connect-surfaces.ko.md +120 -0
  51. package/dist/docs/how-to/connect-surfaces.md +121 -0
  52. package/dist/docs/how-to/write-disciplines.ko.md +179 -0
  53. package/dist/docs/how-to/write-disciplines.md +181 -0
  54. package/dist/docs/index.json +2280 -0
  55. package/dist/docs/reference/cli/covenant-check.ko.md +148 -0
  56. package/dist/docs/reference/cli/covenant-check.md +153 -0
  57. package/dist/docs/reference/cli/docs.ko.md +97 -0
  58. package/dist/docs/reference/cli/docs.md +95 -0
  59. package/dist/docs/reference/cli/explain.ko.md +84 -0
  60. package/dist/docs/reference/cli/explain.md +89 -0
  61. package/dist/docs/reference/cli/init.ko.md +119 -0
  62. package/dist/docs/reference/cli/init.md +119 -0
  63. package/dist/docs/reference/configuration/index.ko.md +553 -0
  64. package/dist/docs/reference/{configuration.md → configuration/index.md} +215 -90
  65. package/dist/docs/reference/packages/adapter-claude-code.ko.md +110 -0
  66. package/dist/docs/reference/{adapter-claude-code.md → packages/adapter-claude-code.md} +47 -19
  67. package/dist/docs/reference/packages/adapter-grok.ko.md +77 -0
  68. package/dist/docs/reference/packages/adapter-grok.md +79 -0
  69. package/dist/docs/reference/packages/core.ko.md +174 -0
  70. package/dist/docs/reference/{core.md → packages/core.md} +74 -12
  71. package/dist/docs/reference/packages/polydeukes.ko.md +195 -0
  72. package/dist/docs/reference/packages/polydeukes.md +204 -0
  73. package/dist/docs/reference/packages/sdk-ts.ko.md +161 -0
  74. package/dist/docs/reference/packages/sdk-ts.md +164 -0
  75. package/dist/docs/troubleshooting.ko.md +144 -0
  76. package/dist/docs/troubleshooting.md +103 -151
  77. package/dist/docs/tutorials/first-judgment.ko.md +82 -0
  78. package/dist/docs/tutorials/first-judgment.md +81 -0
  79. package/dist/docs-catalog.d.ts +25 -0
  80. package/dist/docs-catalog.js +450 -0
  81. package/dist/docs-library.d.ts +23 -0
  82. package/dist/docs-library.js +347 -0
  83. package/dist/docs-markdown.d.ts +32 -0
  84. package/dist/docs-markdown.js +150 -0
  85. package/dist/docs-query.d.ts +11 -40
  86. package/dist/docs-query.js +28 -122
  87. package/dist/docs-types.d.ts +105 -0
  88. package/dist/docs-types.js +2 -0
  89. package/dist/explain.d.ts +1 -1
  90. package/dist/explain.js +37 -22
  91. package/dist/load-config.d.ts +1 -1
  92. package/dist/load-config.js +1 -1
  93. package/dist/pre-state-reader.d.ts +1 -1
  94. package/dist/pre-state-reader.js +1 -1
  95. package/dist/scaffold-project.d.ts +2 -2
  96. package/dist/scaffold-project.js +9 -3
  97. package/dist/schema/polydeukes.schema.json +12 -0
  98. package/dist/worktree-reader.d.ts +19 -0
  99. package/dist/worktree-reader.js +30 -0
  100. package/package.json +3 -17
  101. package/dist/claude-code-hook.d.ts +0 -79
  102. package/dist/claude-code-hook.js +0 -372
  103. package/dist/claude-code.d.ts +0 -6
  104. package/dist/claude-code.js +0 -6
  105. package/dist/covenant-module.d.ts +0 -25
  106. package/dist/covenant-module.js +0 -42
  107. package/dist/docs/configuration.md +0 -103
  108. package/dist/docs/installation.md +0 -241
  109. package/dist/docs/reference/adapter-git.md +0 -100
  110. package/dist/docs/reference/covenant.md +0 -116
  111. package/dist/docs/reference/polydeukes.md +0 -315
  112. package/dist/index.d.ts +0 -22
  113. package/dist/index.js +0 -21
  114. package/dist/init-claude-code.d.ts +0 -52
  115. package/dist/init-claude-code.js +0 -469
  116. package/dist/init-grok.d.ts +0 -51
  117. package/dist/init-grok.js +0 -242
@@ -1,14 +1,14 @@
1
1
  # `@polydeukes/adapter-claude-code`
2
2
 
3
- **English** · [한국어](./adapter-claude-code.ko.md)
3
+ **English** · [한국어](adapter-claude-code.ko.md)
4
4
 
5
- > **The session surface's translator** — PreToolUse payloads become the covenant input IR,
6
- > with the file-change evidence and the transcript channel the judge reads.
5
+ > **The Claude Code install unit** — PreToolUse payloads become the covenant input IR,
6
+ > with the file-change evidence and the transcript channel the judge reads, and the
7
+ > package installs the session surface into a project.
7
8
  >
8
- > Alpha. A transitive dependency of the umbrella: you do not install it and you do not
9
- > import it. The session surface reaches it through
10
- > [`polydeukes/claude-code`](./polydeukes.md#subpaths).
9
+ > Alpha. Install it next to `polydeukes`, which it names as a `peerDependency`.
11
10
 
11
+ <a id="ownership"></a>
12
12
  ## What this package owns
13
13
 
14
14
  The boundary where Claude Code's vocabulary is translated away. Agent and tool literals
@@ -17,17 +17,25 @@ agent-neutrality a claim a test can check rather than a slogan.
17
17
 
18
18
  | Unit | What it does |
19
19
  |---|---|
20
+ | `pdks-claude-code` bin | One subcommand, `pdks-claude-code init`, which registers the session surface in a project |
21
+ | `runHook` | Translates one PreToolUse payload into the input IR and spawns the judge |
20
22
  | Payload up-translation | A raw PreToolUse payload becomes a `CovenantInput` |
21
23
  | Virtual post-state | Computes what a file *would* contain after an edit applies, without touching disk |
22
24
  | File-change evidence | Pairs the disk pre-state with the virtual post-state into union evidence |
23
25
  | Transcript provider | Turns a session JSONL file into a `CanonicalTranscript` |
24
- | Telemetry wiring | Drives the full funnel so exactly one row lands per call |
25
26
 
26
- This package never imports the covenant package. The dispatch seam is *injected* by the
27
- umbrella, which keeps dependencies one-way, through the core alone. It names
28
- `@polydeukes/core` as a `peerDependency`: the vocabulary is shared with the judge, not
29
- installed a second time here.
27
+ `runHook({ repoRoot })` is what the generated hook delegator imports. It builds the IR — the
28
+ `tools` and `session` evidence included — then spawns `pdks covenant check --enforce block` in
29
+ `repoRoot` and returns the child's exit code. The judging happens in that child process; this
30
+ package carries no judgment logic.
30
31
 
32
+ **This package writes no telemetry rows.** A failure before the spawn is sent to `pdks` on
33
+ stdin as a plain line, and `pdks` records the fail-closed row, so one call still leaves one
34
+ row. It never imports the judge: `polydeukes` and `@polydeukes/core` are both
35
+ `peerDependencies`, so the vocabulary and the judge are shared rather than installed a second
36
+ time here.
37
+
38
+ <a id="translation"></a>
31
39
  ## Payload translation and the three axes
32
40
 
33
41
  **Three axes reach the judge**, and they differ in what evidence they can carry.
@@ -56,23 +64,37 @@ witness valve human-only: an AI cannot synthesize its own witness. A read failur
56
64
  judged, an unreadable one is no evidence channel at all and is skipped. Either way the
57
65
  valve turns off, never open.
58
66
 
59
- **The precedent evaluator judges two keys.** `subagent` is exact spawn-kind equality, since
60
- a kind is a value rather than a pattern; `tool` matches observed tool names as a regular
61
- expression. Any key outside this vocabulary returns `undefined` — the handshake that tells
62
- the compiler the evidence is unjudgeable, so the entry skips instead of judging on a guess.
67
+ **Precedent is a declaration, not an adapter evaluator.** This adapter supplies the
68
+ transcript snapshot. The declaration engine extracts succeeded `toolUses` and matches them;
69
+ there is no separate precedent evaluator in this package. The grammar is in
70
+ [Configuration — disciplines](../configuration/index.md#disciplines).
63
71
 
72
+ <a id="consumer-contract"></a>
64
73
  ## Where the consumer touches it
65
74
 
66
- - **The generated hook**, which loads this adapter through the umbrella's `claude-code`
67
- subpath. Upgrading the package upgrades what runs; the hook file itself never changes.
75
+ Two lines install the Claude Code session surface, run from the project root:
76
+
77
+ ```sh
78
+ npm install --save-dev polydeukes @polydeukes/adapter-claude-code
79
+ npx pdks-claude-code init
80
+ ```
81
+
82
+ `pdks-claude-code init` resolves `polydeukes` from the project, spawns `pdks init` for the
83
+ agent-neutral scaffold, then writes the four Claude Code artifacts non-destructively. A re-run
84
+ reports each existing artifact as skipped and overwrites nothing. The full artifact list is in
85
+ [`pdks init`](../cli/init.md#init-claude-code).
86
+
87
+ - **The generated hook** imports `runHook` from this package. Upgrading the package upgrades
88
+ what runs; the hook file itself never changes.
68
89
 
69
- No import, and no configuration namespace of its own.
90
+ No configuration namespace of its own.
70
91
 
92
+ <a id="limits"></a>
71
93
  ## Declared limits
72
94
 
73
95
  - **A child process's writes are outside observation.** This surface judges *declared tool
74
96
  calls*. A command that spawns a process which then writes files — a test runner, a build
75
- — is judged on the command, not on what the child did. The commit surface is the second
97
+ — is judged on the command, not on what the child did. The change-set surface is the second
76
98
  observation that covers the same ground for tracked files.
77
99
  - **Evidence exists only where a post-state can be computed.** All four mutating tools
78
100
  contribute one, notebooks included — a `NotebookEdit` yields cell-level `modify` evidence.
@@ -82,3 +104,9 @@ No import, and no configuration namespace of its own.
82
104
  are compared for a mention rather than a proven target.
83
105
  - **Out-of-repository ancestors stay out of scope.** A path above the project root is not
84
106
  observed here; the agent's own deny policy owns that ground.
107
+ - **An unresolvable `polydeukes` leaves no row.** When the umbrella cannot be resolved from the
108
+ project there is no process to spawn and no log path to write to, so the hook exits `2` with
109
+ one line on stderr and the telemetry log gains nothing. Every other pre-spawn failure does
110
+ reach `pdks` and does leave a row.
111
+ - **Grok installs through `@polydeukes/adapter-grok`.** That package writes its own delegator
112
+ and roster. Installing both session adapters in one project can run the judge twice per call.
@@ -0,0 +1,77 @@
1
+ # `@polydeukes/adapter-grok`
2
+
3
+ [English](adapter-grok.md) · **한국어**
4
+
5
+ > **Grok의 설치 단위**입니다. PreToolUse 페이로드가 약속(covenant) 입력 IR이 되고,
6
+ > 판정기가 읽는 파일 변경 증거가 함께 실립니다. 세션 표면을 프로젝트에 설치하는 것도 이
7
+ > 패키지가 합니다.
8
+ >
9
+ > 알파입니다. `polydeukes`와 함께 설치하며, `polydeukes`는 이 패키지의 `peerDependency`입니다.
10
+
11
+ <a id="ownership"></a>
12
+ ## 담당하는 기능
13
+
14
+ Grok의 입력을 공통 형식으로 번역합니다. 에이전트와 도구의 구체적인 이름은 이 패키지에서
15
+ 처리하고 코어에는 넣지 않습니다.
16
+
17
+ | 단위 | 하는 일 |
18
+ |---|---|
19
+ | `pdks-grok` 실행 파일 | 하위 명령 하나 `pdks-grok init`으로 프로젝트에 세션 표면을 등록합니다 |
20
+ | `runHook` | PreToolUse 페이로드 하나를 입력 IR로 바꾸고 판정기를 스폰합니다 |
21
+ | 페이로드 상향 번역 | 원본 PreToolUse 페이로드가 `CovenantInput`이 됩니다 |
22
+ | 예상 변경 후 상태 | 쓰기나 치환이 적용되면 파일이 무엇을 담을지 디스크를 건드리지 않고 계산합니다 |
23
+ | 파일 변경 증거 | 디스크의 변경 전 상태와 예상 변경 후 상태를 짝지어 변경 증거를 만듭니다 |
24
+
25
+ 생성된 훅 위임자가 불러오는 것이 `runHook({ repoRoot })`입니다. `tools` 명부를 실은 입력 IR을
26
+ 만든 뒤 — `session`과 `actor` 키는 없습니다 — `repoRoot`에서
27
+ `pdks covenant check --enforce block`을 스폰하고 그 자식 프로세스의 종료 코드를 그대로
28
+ 돌려줍니다. 판정은 그 자식 프로세스가 하며, 이 패키지에는 판정 코드가 없습니다.
29
+
30
+ **이 패키지는 텔레메트리 행을 쓰지 않습니다.** 스폰 전에 실패하면 그 사실을 한 줄로 만들어
31
+ `pdks`의 표준 입력으로 보내고, `pdks`가 fail-closed 행을 기록합니다. 호출 하나에 행 하나는
32
+ 그대로입니다. 판정기를 불러오지도 않습니다. `polydeukes`와 `@polydeukes/core` 모두
33
+ `peerDependencies`이므로 어휘와 판정기를 공유할 뿐 사본을 따로 설치하지 않습니다.
34
+
35
+ 이 어댑터가 IR에 실는 명부는 Grok 원어입니다. `write`와 `search_replace`는 파일을 바꾸고,
36
+ `run_terminal_command`는 셸 한 줄을 실습니다.
37
+
38
+ <a id="consumer-contract"></a>
39
+ ## 소비자가 닿는 곳
40
+
41
+ 프로젝트 루트에서 두 줄이면 Grok 세션 표면이 설치됩니다.
42
+
43
+ ```sh
44
+ npm install --save-dev polydeukes @polydeukes/adapter-grok
45
+ npx pdks-grok init
46
+ ```
47
+
48
+ `pdks-grok init`은 프로젝트에서 `polydeukes`를 찾고, 에이전트와 무관한 초기 파일을 위해
49
+ `pdks init`을 스폰한 뒤, Grok 산출물 둘을 덮어쓰지 않고 씁니다. 다시 실행하면 이미 있는
50
+ 산출물은 `skipped`로 보고하고 내용을 바꾸지 않습니다. 산출물 목록은
51
+ [`pdks init`](../cli/init.ko.md#init-grok)에 있습니다.
52
+
53
+ 이 어댑터와 `@polydeukes/adapter-claude-code`를 한 프로젝트에 함께 설치하면 호출마다
54
+ 판정기가 두 번 실행될 수 있습니다.
55
+
56
+ - **생성된 훅**은 이 패키지의 `runHook`을 불러옵니다. 패키지를 올리면 실행되는 코드가
57
+ 올라가고, 훅 파일 자체는 바뀌지 않습니다.
58
+
59
+ 자체 설정 네임스페이스는 없습니다.
60
+
61
+ <a id="limits"></a>
62
+ ## 선언된 한계
63
+
64
+ - **자식 프로세스의 쓰기는 관측 밖입니다.** 이 표면은 *선언된 도구 호출*을 판정합니다. 파일을
65
+ 쓰는 프로세스를 띄우는 명령은 그 명령 줄로 판정되며, 자식이 한 일로 판정되지 않습니다.
66
+ - **증거는 변경 후 상태를 계산할 수 있을 때만 있습니다.** `write`와 `search_replace`가 하나를
67
+ 만듭니다. 치환이 한 번도 맞지 않거나, `replace_all` 없이 두 번 이상 맞으면 증거가 없습니다.
68
+ 호스트 도구가 그 호출을 거부하기 때문입니다.
69
+ - **증거 없는 호출은 보수적으로 판정합니다.** 증명된 대상이 없으므로 호출 인자에 보호 경로가
70
+ 언급됐는지 대조합니다.
71
+ - **대화 기록(transcript) 통로가 없습니다.** IR은 `session`과 `actor`를 생략합니다. Grok의
72
+ ACP 대화 기록은 세션 증인(witness) 밸브가 필요로 하는 인간 메시지 증거를 공급하지 않습니다.
73
+ 의도한 편집이 차단되면 본인 터미널에서 수행하세요.
74
+ - **`polydeukes`를 찾지 못하면 행이 남지 않습니다.** 프로젝트에서 우산 패키지를 찾지 못하면
75
+ 스폰할 프로세스도, 기록할 로그 경로도 없습니다. 훅은 stderr에 한 줄을 남기고 종료 코드
76
+ `2`를 내며 텔레메트리 로그에는 아무것도 추가되지 않습니다. 스폰 전 실패 가운데 이 경우만
77
+ 그렇고, 나머지는 모두 `pdks`에 도달해 행을 남깁니다.
@@ -0,0 +1,79 @@
1
+ # `@polydeukes/adapter-grok`
2
+
3
+ **English** · [한국어](adapter-grok.ko.md)
4
+
5
+ > **The Grok install unit** — PreToolUse payloads become the covenant input IR, with the
6
+ > file-change evidence the judge reads, and the package installs the session surface into a
7
+ > project.
8
+ >
9
+ > Alpha. Install it next to `polydeukes`, which it names as a `peerDependency`.
10
+
11
+ <a id="ownership"></a>
12
+ ## What this package owns
13
+
14
+ The boundary where Grok's vocabulary is translated away. Agent and tool literals live *here*
15
+ by design, so that they never reach the core.
16
+
17
+ | Unit | What it does |
18
+ |---|---|
19
+ | `pdks-grok` bin | One subcommand, `pdks-grok init`, which registers the session surface in a project |
20
+ | `runHook` | Translates one PreToolUse payload into the input IR and spawns the judge |
21
+ | Payload up-translation | A raw PreToolUse payload becomes a `CovenantInput` |
22
+ | Virtual post-state | Computes what a file *would* contain after a write or substitution applies, without touching disk |
23
+ | File-change evidence | Pairs the disk pre-state with the virtual post-state into union evidence |
24
+
25
+ `runHook({ repoRoot })` is what the generated hook delegator imports. It builds the IR — the
26
+ `tools` roster included, with no `session` or `actor` key — then spawns
27
+ `pdks covenant check --enforce block` in `repoRoot` and returns the child's exit code. The
28
+ judging happens in that child process; this package carries no judgment logic.
29
+
30
+ **This package writes no telemetry rows.** A failure before the spawn is sent to `pdks` on
31
+ stdin as a plain line, and `pdks` records the fail-closed row, so one call still leaves one
32
+ row. It never imports the judge: `polydeukes` and `@polydeukes/core` are both
33
+ `peerDependencies`, so the vocabulary and the judge are shared rather than installed a second
34
+ time here.
35
+
36
+ The roster this adapter puts on the IR is Grok-native: `write` and `search_replace` mutate a
37
+ file; `run_terminal_command` carries a shell line.
38
+
39
+ <a id="consumer-contract"></a>
40
+ ## Where the consumer touches it
41
+
42
+ Two lines install the Grok session surface, run from the project root:
43
+
44
+ ```sh
45
+ npm install --save-dev polydeukes @polydeukes/adapter-grok
46
+ npx pdks-grok init
47
+ ```
48
+
49
+ `pdks-grok init` resolves `polydeukes` from the project, spawns `pdks init` for the
50
+ agent-neutral scaffold, then writes the two Grok artifacts non-destructively. A re-run
51
+ reports each existing artifact as skipped and overwrites nothing. The full artifact list is in
52
+ [`pdks init`](../cli/init.md#init-grok).
53
+
54
+ Installing both this adapter and `@polydeukes/adapter-claude-code` in one project can run the
55
+ judge twice per call.
56
+
57
+ - **The generated hook** imports `runHook` from this package. Upgrading the package upgrades
58
+ what runs; the hook file itself never changes.
59
+
60
+ No configuration namespace of its own.
61
+
62
+ <a id="limits"></a>
63
+ ## Declared limits
64
+
65
+ - **A child process's writes are outside observation.** This surface judges *declared tool
66
+ calls*. A command that spawns a process which then writes files is judged on the command,
67
+ not on what the child did.
68
+ - **Evidence exists only where a post-state can be computed.** `write` and `search_replace`
69
+ contribute one. A substitution that matches nothing, or that matches more than once without
70
+ `replace_all`, yields no evidence — the host tool refuses those calls.
71
+ - **An evidence-free call falls back to the conservative judgment** — the call's arguments
72
+ are compared for a mention rather than a proven target.
73
+ - **There is no transcript channel.** The IR omits `session` and `actor`. Grok's ACP history
74
+ does not supply the human-message evidence the session witness valve needs. For an
75
+ intentional blocked edit, use your own terminal.
76
+ - **An unresolvable `polydeukes` leaves no row.** When the umbrella cannot be resolved from the
77
+ project there is no process to spawn and no log path to write to, so the hook exits `2` with
78
+ one line on stderr and the telemetry log gains nothing. Every other pre-spawn failure does
79
+ reach `pdks` and does leave a row.
@@ -0,0 +1,174 @@
1
+ # `@polydeukes/core`
2
+
3
+ [English](core.md) · **한국어**
4
+
5
+ > **모든 약속(covenant)이 말하는 프로토콜**입니다. 입력 IR과 판정 결과 형태, 설정 스키마,
6
+ > 텔레메트리 수집기가 여기 있습니다.
7
+ >
8
+ > 알파입니다. 일반 사용자는 이 패키지를 따로 설치하거나 불러올 필요가 없습니다. 통합 패키지의 의존성으로 설치되며, 사용자 진입점은
9
+ > [`polydeukes`](polydeukes.ko.md)입니다.
10
+
11
+ <a id="ownership"></a>
12
+ ## 담당하는 기능
13
+
14
+ 모든 약속이 사용하는 공통 프로토콜을 정의합니다. 개별 약속이 무엇을 판정하는지는 다루지 않습니다.
15
+
16
+ | 영역 | 무엇인가 |
17
+ |---|---|
18
+ | 약속 프로토콜 | 표준 입력 JSON 입력 IR, 판정 결과 형태, 종료 코드 계약 |
19
+ | 설정 스키마 | `defineConfig()`가 파싱된 yaml·json 데이터를 검증합니다. 대응하는 JSON Schema도 별도 파일로 제공합니다 |
20
+ | ROI 텔레메트리 | 모든 패키지가 공유하는 추가 전용 로그 기록기 |
21
+ | 실패 정책 | 실패 종류마다 fail-open과 fail-closed를 가르는 표 하나 |
22
+ | 보호 경로 정규화 | 선언된 목록이 디스패처가 대조하는 문자열이 됩니다 |
23
+ | 대화 기록(transcript) 이음매 | 약속이 세션 이력을 묻는 질의 인터페이스 |
24
+
25
+ 이 패키지는 두 가지 제약을 따릅니다. **런타임 의존이 없습니다.** 검증은 손으로 짰고
26
+ 배포하는 JSON Schema는 런타임 코드에서 읽지 않는 별도 파일입니다. **에이전트나 도구, 언어의
27
+ 리터럴이 없습니다.** 편집기 도구 이름과 테스트 러너 이름은 설정과 어댑터가 채워 넣는
28
+ **값**이라서, 코어의 에이전트 중립성은 grep으로 확인되는 주장입니다. 다른 모든 패키지가
29
+ 이 패키지에 의존하고, 이 패키지는 그 어느 것에도 의존하지 않습니다.
30
+
31
+ **세션 어댑터는 이 패키지를 `peerDependency`로 선언합니다.** 따로 설치하는 대신 우산과 같은 어휘를 공유합니다. `SOURCE_KINDS`와
32
+ `parseInput`은 검증기와 엔진이
33
+ 같은 값을 참조해야 합니다. 서로 다른 사본을 사용하면 설치는 성공해도 동작이 달라질 수 있습니다.
34
+ 통합 패키지가 일반 의존성으로 core를 제공하므로 사용자는 패키지 하나만 설치하면 됩니다.
35
+
36
+ <a id="protocol"></a>
37
+ ## 판정 프로토콜
38
+
39
+ 현재 판정기는 표면이 디스패처에 전달한 표준 입력 JSON 페이로드를 한 번 파싱한
40
+ `CovenantInput`을 받습니다. 판정 결과를 반환하면 래퍼가 종료 코드로 변환합니다.
41
+ `.polydeukes/roi.log`의 차단 기록도 이 판정 어휘를 사용합니다.
42
+
43
+ `world`는 표면이 공급합니다(`files`, `changes`, `channels`). 판정기가 디스크에서 읽지
44
+ 않습니다. `tools`와 `session`은 호스트가 공급합니다. 명부는 어댑터가 채우는 값이고, 세션은
45
+ IR만으로는 증명하지 못하는 두 사실, 메시지의 신선도와 호출의 결과를 담은 증거입니다.
46
+ `transcriptFromSession`은 그 키에서 증인이나 선행 조건 소비자가 읽는 대화 기록을 만들고,
47
+ `transcriptFromInput`은 그 두 사실 없이 IR에서 같은 대화 기록을 만듭니다.
48
+
49
+ ```ts
50
+ type CovenantInput = {
51
+ toolCalls: { name: string; args?: Record<string, unknown>; fileChange?: FileChange }[];
52
+ subagentSpawns: { kind: string }[];
53
+ userMessages: { text: string }[];
54
+ actor?: { agentType?: string };
55
+ world?: {
56
+ files?: Record<string, string>;
57
+ changes?: string[];
58
+ channels?: { sidecar?: string };
59
+ };
60
+ tools?: { mutating: string[]; shell: string[]; commandArgs: string[] };
61
+ session?: {
62
+ evidencePath?: string;
63
+ userMessages: { text: string; timestampMs?: number }[];
64
+ toolCalls: { name: string; args?: Record<string, unknown>; succeeded?: boolean }[];
65
+ channels?: { sidecar?: string };
66
+ };
67
+ };
68
+
69
+ type FileChange =
70
+ | { kind: 'create'; path: string; post: string }
71
+ | { kind: 'modify'; path: string; pre: string; post: string }
72
+ | { kind: 'delete'; path: string; pre?: string };
73
+
74
+ type CovenantVerdict = { upheld: true } | { upheld: false; reason: string };
75
+ ```
76
+
77
+ 이 어휘에는 도구 이름도 에이전트 이름도 없습니다. 구체적인 도구 이름은 어댑터가 `name`에
78
+ 채우는 **값**이고, 스폰의 `kind`도 마찬가지입니다. `FileChange`가 판별 유니온인 이유는
79
+ 삭제를 표현할 수 없는 예외가 아니라 일급 증거로 두기 위해서입니다. 불가능한 상태는 아예
80
+ 적을 수 없습니다. 결과 내용을 든 삭제나 기준선을 든 생성이 그렇습니다. `delete.pre`는
81
+ 기준선이 바이너리 blob이었을 때 없습니다. 삭제를 판정하는 데는 내용이 필요 없기
82
+ 때문입니다. `actor`는 호스트 봉투가 증명하는 관측의 주체(actor)입니다. 서브에이전트 안에서는
83
+ `agentType`, 주 세션에서는 `{}`이고, 표면이 주체를 증명하지 못하면 없습니다. 판정기는 기본값을
84
+ 채우지 않습니다.
85
+
86
+ **증거는 해당 호출에만 속합니다.** `fileChange`가 없다는 것은 이
87
+ 호출이 증명되지 않았다는 뜻이고, 형제 호출의 증거가 그 자리를 대신하지 않습니다.
88
+
89
+ ```ts
90
+ function parseInput(stdinJson: string):
91
+ | { ok: true; value: CovenantInput }
92
+ | { ok: false; exitCode: 2 };
93
+
94
+ function verdictToExitCode(verdict: CovenantVerdict): 0 | 1;
95
+
96
+ function allFileChanges(input: CovenantInput): FileChange[];
97
+ ```
98
+
99
+ `parseInput`은 예외를 던지지 않습니다. 파싱되지 않는 JSON, 빈 페이로드, 객체가 아닌 값,
100
+ 필수 컬렉션 누락은 모두 `{ ok: false, exitCode: 2 }`로 반환합니다. 판정할 수 없는
101
+ 입력이 유효한 입력으로 오인될 길이 없습니다.
102
+
103
+ `verdictToExitCode`는 `0`이나 `1`을 반환하고 `2`는 결코 반환하지 않습니다. 위반을 차단으로
104
+ 번역하는 것은 본체가 아니라 래퍼의 정책입니다. [종료 코드](polydeukes.ko.md#polydeukes-failure-boundaries)를
105
+ 보십시오. 내보내는 상수는 `EXIT_UPHOLD`(`0`), `EXIT_BREAK_NON_BLOCKING`(`1`),
106
+ `EXIT_BREAK_BLOCKING`(`2`)입니다.
107
+
108
+ `allFileChanges`는 귀속이 필요 없는 소비자를 위해 모든 호출의 증거를 호출 순서대로
109
+ 평탄화합니다. 증거 없는 호출은 건너뛰고 무엇으로도 대체하지 않습니다.
110
+
111
+ <a id="discipline-lists"></a>
112
+ ## 규율 목록 셋과 통로 유도
113
+
114
+ `defineConfig()`는 규율 목록 셋을 받고, 항목마다 그것이 맞는 목록에 적혔는지 판정합니다.
115
+
116
+ | 키 | 타입 | 판정하는 표면 |
117
+ |---|---|---|
118
+ | `disciplines` | `(DisciplineEntry \| DisciplineDraft)[]` | 두 표면 모두 |
119
+ | `sessionDisciplines` | `DisciplineEntry[]` | 세션 표면(session surface)만 |
120
+ | `changeSetDisciplines` | `DisciplineEntry[]` | 변경 집합 표면(change-set surface)만 |
121
+
122
+ `ResolvedConfig`도 같은 이름으로 셋을 싣되 판정 항목만 담고, 초안(draft)은 `drafts`로 갈라
123
+ 둡니다. 입력이 선언하지 않은 목록은 빈 배열이 되지 않고 없는 채로 남습니다.
124
+
125
+ 검증기와 우산 패키지가 함께 쓰는 유도는 내보내는 함수 하나입니다.
126
+
127
+ ```ts
128
+ type DeclarationChannel = 'transcript' | 'channel' | 'command' | 'actor' | 'changes';
129
+
130
+ function declarationChannels(body: Omit<AlgebraDeclaration, 'discipline'>): DeclarationChannel[];
131
+ ```
132
+
133
+ 순수하고 구문적인 함수라서 선언을 실행하지 않습니다. `transcript`는 `{ transcript: true }`
134
+ 바인딩에서, `channel`은 `{ sidecar: true }` 바인딩에서, `command`는
135
+ `scope.source === 'command'`나 `{ op: 'source', of: 'command' }` 단계에서, `actor`는
136
+ `{ op: 'source', of: 'actor' }` 단계에서, `changes`는
137
+ `{ op: 'source', of: 'changes' }` 단계에서 나옵니다. `witness` 블록 자신의 `extract`도 본체와
138
+ 함께 훑습니다. 반환 목록은 위 표의 고정 순서를 따르므로, 통로 집합을 비교하는 두 호출자가 같은
139
+ 목록을 비교합니다.
140
+
141
+ 다섯 가운데 하나도 이름 짓지 않는 본체는 변경된 파일과 저장소 파일만 읽고 그 둘은 두 표면이
142
+ 모두 공급하므로 `disciplines`에 속합니다. 그 밖은 항목과 통로와 가야 할 목록을 대는
143
+ `ConfigValidationError`이며, 메시지는
144
+ [설정 참조](../configuration/index.ko.md#placement-rule)에 있습니다. 우산 패키지는 같은 질문을
145
+ 따로 답하지 않고 이 함수를 불러 씁니다.
146
+
147
+ <a id="consumer-contract"></a>
148
+ ## 사용자와의 접점
149
+
150
+ 일반 사용자는 다음 세 경로로 이 패키지의 기능을 사용합니다.
151
+
152
+ - **설정 파일.** 그 스키마가 여기서 정의됩니다. 어휘 레퍼런스는
153
+ [설정 레퍼런스](../configuration/index.ko.md)입니다.
154
+ - **JSON Schema 자산.** `@polydeukes/core/schema.json` exports 서브패스입니다. 이 패키지를
155
+ 직접 설치한 프로젝트가 쓰는 경로입니다. 우산을 설치한 소비자는 그쪽에 동봉된 사본을
156
+ 가리킵니다. 두 철자 모두
157
+ [configuration.md의 IDE 절](../../how-to/configure-project.ko.md#add-ide-support)에 있습니다.
158
+ - **위의 프로토콜.** `blocked` 행을 읽는다는 것은 본체가 답한 어휘를 읽는다는 뜻입니다.
159
+
160
+ 그 밖의 기능은 `polydeukes`를 통해 사용합니다.
161
+
162
+ <a id="limits"></a>
163
+ ## 선언된 한계
164
+
165
+ - **어댑터 네임스페이스는 이름이 아니라 형태로 검증합니다.** `defineConfig()`는 `adapters`가
166
+ 평범한 객체의 맵인지, 각 네임스페이스 값이 객체인지를 봅니다. 네임스페이스 **이름**이
167
+ 누군가 구현한 것인지는 보지 않고, 네임스페이스 안쪽은 들여다보지 않습니다.
168
+ 네임스페이스 안의 미지 어휘는 해당 어댑터의 검증기가 자기 층위에서 거부합니다. 여기가
169
+ 아닙니다.
170
+ - **기본 대화 기록은 아무것도 하지 않습니다.** 실제 대화 기록을 주입하지 않은 소비자는
171
+ "아무 일도 없었다"는 결과를 받습니다. 이 상태에서는 증인 밸브가 작업을 허용하지 않으므로
172
+ 차단을 유지합니다. 실제 대화 기록은 어댑터 뒤에 있습니다.
173
+ - **fail-open은 텔레메트리 하나뿐입니다.** 기록이 실패해도 판정은 바뀌지 않습니다. 표에 든
174
+ 다른 모든 실패 종류는 차단으로 처리합니다.
@@ -1,13 +1,14 @@
1
1
  # `@polydeukes/core`
2
2
 
3
- **English** · [한국어](./core.ko.md)
3
+ **English** · [한국어](core.ko.md)
4
4
 
5
5
  > **The protocol every covenant speaks** — the input IR, the verdict shape, the config
6
6
  > schema, and the telemetry collector.
7
7
  >
8
8
  > Alpha. A transitive dependency of the umbrella: you do not install it and you do not import
9
- > it. The consumer entry point is [`polydeukes`](./polydeukes.md).
9
+ > it. The consumer entry point is [`polydeukes`](polydeukes.md).
10
10
 
11
+ <a id="ownership"></a>
11
12
  ## What this package owns
12
13
 
13
14
  The protocol every covenant speaks, and nothing that knows what a covenant is *about*.
@@ -27,20 +28,27 @@ hand-rolled and the published JSON Schema is a sibling artifact the source never
27
28
  *values* supplied by configs and adapters, so the core's agent-neutrality is a claim a grep
28
29
  can check. Every other package depends on this one; this one depends on none of them.
29
30
 
30
- **The judge and the two adapters name it as a `peerDependency`, not a dependency of their
31
- own.** They share the vocabulary rather than each installing a copy — `SOURCE_KINDS` and
31
+ **The session adapter names it as a `peerDependency`, not a dependency of its
32
+ own.** It shares the vocabulary with the umbrella rather than installing a copy — `SOURCE_KINDS` and
32
33
  `parseInput` have to be one set of values for the validator and the engine to agree, and two
33
34
  copies would disagree silently instead of failing at install time. The umbrella carries the
34
35
  ordinary dependency that satisfies that peer, which is why a consumer still installs one
35
36
  package and gets core transitively.
36
37
 
38
+ <a id="protocol"></a>
37
39
  ## The judged protocol
38
40
 
39
41
  This is the contract the shipped judges speak: a judge receives a `CovenantInput` — parsed
40
42
  once from the stdin-JSON payload the surface hands the dispatcher — and answers with a
41
- verdict the wrapper translates into an exit code. Every row in `.polydeukes/roi.log` traces
42
- back to one
43
- of these verdicts, so this vocabulary is what a blocked row is written in.
43
+ verdict the wrapper translates into an exit code. Blocked rows in `.polydeukes/roi.log`
44
+ use this judgment vocabulary.
45
+
46
+ `world` is supplied by the surface (`files`, `changes`, `channels`). The judge does not
47
+ read it from disk. `tools` and `session` are supplied by the host: the roster is values the
48
+ adapter fills in, and the session is the evidence a live agent session proves that a bare
49
+ IR cannot — message freshness and call outcome. `transcriptFromSession` wraps that key as
50
+ the transcript a witness or a precedent consumer reads, the way `transcriptFromInput` wraps
51
+ the bare IR without those two facts.
44
52
 
45
53
  ```ts
46
54
  type CovenantInput = {
@@ -48,6 +56,18 @@ type CovenantInput = {
48
56
  subagentSpawns: { kind: string }[];
49
57
  userMessages: { text: string }[];
50
58
  actor?: { agentType?: string };
59
+ world?: {
60
+ files?: Record<string, string>;
61
+ changes?: string[];
62
+ channels?: { sidecar?: string };
63
+ };
64
+ tools?: { mutating: string[]; shell: string[]; commandArgs: string[] };
65
+ session?: {
66
+ evidencePath?: string;
67
+ userMessages: { text: string; timestampMs?: number }[];
68
+ toolCalls: { name: string; args?: Record<string, unknown>; succeeded?: boolean }[];
69
+ channels?: { sidecar?: string };
70
+ };
51
71
  };
52
72
 
53
73
  type FileChange =
@@ -85,33 +105,75 @@ required collection — each resolves to a blocking `{ ok: false, exitCode: 2 }`
85
105
  unjudgeable input can never be mistaken for a valid one.
86
106
 
87
107
  `verdictToExitCode` returns `0` or `1` and never `2`. Translating a break into a block is
88
- the wrapper's policy, not the body's — see [exit codes](./polydeukes.md#exit-codes).
108
+ the wrapper's policy, not the body's — see [exit codes](polydeukes.md#polydeukes-failure-boundaries).
109
+ The exported constants are `EXIT_UPHOLD` (`0`), `EXIT_BREAK_NON_BLOCKING` (`1`), and
110
+ `EXIT_BREAK_BLOCKING` (`2`).
89
111
 
90
112
  `allFileChanges` flattens every call's evidence in call order for consumers that need no
91
113
  attribution. Calls without evidence are skipped, never substituted for.
92
114
 
115
+ <a id="discipline-lists"></a>
116
+ ## The three discipline lists and the channel derivation
117
+
118
+ `defineConfig()` accepts three discipline lists and decides, for each entry, whether it is
119
+ written in the right one.
120
+
121
+ | Key | Type | Judged on |
122
+ |---|---|---|
123
+ | `disciplines` | `(DisciplineEntry \| DisciplineDraft)[]` | both surfaces |
124
+ | `sessionDisciplines` | `DisciplineEntry[]` | the session surface only |
125
+ | `changeSetDisciplines` | `DisciplineEntry[]` | the change-set surface only |
126
+
127
+ `ResolvedConfig` carries the three under the same names, holding judged entries only, with the
128
+ drafts split out into `drafts`. A list the input did not declare stays absent rather than
129
+ becoming an empty array.
130
+
131
+ The derivation both the validator and the umbrella use is one exported function:
132
+
133
+ ```ts
134
+ type DeclarationChannel = 'transcript' | 'channel' | 'command' | 'actor' | 'changes';
135
+
136
+ function declarationChannels(body: Omit<AlgebraDeclaration, 'discipline'>): DeclarationChannel[];
137
+ ```
138
+
139
+ It is pure and syntactic — the declaration is never run. `transcript` comes from a
140
+ `{ transcript: true }` binding, `channel` from a `{ sidecar: true }` binding, `command` from
141
+ `scope.source === 'command'` or a `{ op: 'source', of: 'command' }` step, `actor` from a
142
+ `{ op: 'source', of: 'actor' }` step, and `changes` from a
143
+ `{ op: 'source', of: 'changes' }` step. A `witness` block's own `extract` is walked with the
144
+ body's. The returned list is in the fixed order above, so two callers comparing channel sets
145
+ compare the same list.
146
+
147
+ A body naming none of the five reads the changed file and repository files alone, which both
148
+ surfaces supply, so it belongs in `disciplines`. Anything else is a `ConfigValidationError`
149
+ naming the entry, its channels, and the list it belongs in; the messages are in [the
150
+ configuration reference](../configuration/index.md#placement-rule). The umbrella imports this
151
+ function rather than answering the same question a second time.
152
+
153
+ <a id="consumer-contract"></a>
93
154
  ## Where the consumer touches it
94
155
 
95
156
  Three places, all of them indirect.
96
157
 
97
158
  - **The config file.** Its schema is defined here. The vocabulary reference is
98
- [the configuration reference](./configuration.md).
159
+ [the configuration reference](../configuration/index.md).
99
160
  - **The JSON Schema artifact** — `@polydeukes/core/schema.json`, an exports subpath, for a
100
161
  project that installs this package directly. A consumer of the umbrella names the copy
101
162
  bundled there instead; both spellings are in
102
- [configuration.md's IDE section](../configuration.md#ide-support).
163
+ [configuration.md's IDE section](../../how-to/configure-project.md#add-ide-support).
103
164
  - **The protocol above** — reading a `blocked` row means reading the vocabulary a body
104
165
  answered in.
105
166
 
106
167
  Everything else here is reached through `polydeukes`.
107
168
 
169
+ <a id="limits"></a>
108
170
  ## Declared limits
109
171
 
110
172
  - **Adapter namespaces are validated by shape, not by name.** `defineConfig()` checks that
111
173
  `adapters` is a map of plain objects and that each namespace value is an object. It does
112
174
  not check that a namespace *name* is one anybody implements, and it does not look inside
113
- the namespace at all. Unknown vocabulary inside `adapters.git` is rejected by the git
114
- adapter's own validator, at its own layer — not here.
175
+ the namespace at all. Unknown vocabulary inside a namespace is rejected by that adapter's
176
+ own validator, at its own layer — not here.
115
177
  - **The default transcript is a noop.** A consumer that injects no real transcript
116
178
  converges on "nothing happened", which is the safe direction for a valve: it never opens.
117
179
  Real transcripts live behind adapters.