polydeukes 0.6.1 → 0.8.0
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.
- package/README.ko.md +16 -28
- package/README.md +16 -28
- package/dist/baseline.d.ts +37 -1
- package/dist/baseline.js +68 -1
- package/dist/bin.d.ts +3 -4
- package/dist/bin.js +73 -90
- package/dist/covenant/bash-line.d.ts +130 -0
- package/dist/covenant/bash-line.js +566 -0
- package/dist/covenant/declaration-engine.d.ts +108 -0
- package/dist/covenant/declaration-engine.js +415 -0
- package/dist/covenant/discipline.d.ts +109 -0
- package/dist/covenant/discipline.js +667 -0
- package/dist/covenant/dispatch.d.ts +156 -0
- package/dist/covenant/dispatch.js +250 -0
- package/dist/covenant/extract-steps.d.ts +122 -0
- package/dist/covenant/extract-steps.js +0 -0
- package/dist/covenant/mention.d.ts +117 -0
- package/dist/covenant/mention.js +209 -0
- package/dist/covenant/module.d.ts +25 -0
- package/dist/covenant/module.js +23 -0
- package/dist/covenant/mutation-rules.d.ts +40 -0
- package/dist/covenant/mutation-rules.js +146 -0
- package/dist/covenant/relations.d.ts +46 -0
- package/dist/covenant/relations.js +68 -0
- package/dist/covenant/run-covenant.d.ts +95 -0
- package/dist/covenant/run-covenant.js +164 -0
- package/dist/covenant/self-mod.d.ts +55 -0
- package/dist/covenant/self-mod.js +84 -0
- package/dist/covenant/shell-evidence.d.ts +38 -0
- package/dist/covenant/shell-evidence.js +247 -0
- package/dist/covenant/shell-mod.d.ts +84 -0
- package/dist/covenant/shell-mod.js +213 -0
- package/dist/covenant/supply.d.ts +54 -0
- package/dist/covenant/supply.js +50 -0
- package/dist/covenant/transcript-mod.d.ts +60 -0
- package/dist/covenant/transcript-mod.js +254 -0
- package/dist/covenant/ttl-witness.d.ts +47 -0
- package/dist/covenant/ttl-witness.js +80 -0
- package/dist/covenant-check.d.ts +74 -41
- package/dist/covenant-check.js +372 -129
- package/dist/diff-ir.d.ts +28 -0
- package/dist/diff-ir.js +310 -0
- package/dist/docs/README.ko.md +10 -9
- package/dist/docs/README.md +10 -9
- package/dist/docs/catalog.json +76 -28
- package/dist/docs/concepts/judgment.ko.md +2 -2
- package/dist/docs/concepts/judgment.md +2 -2
- package/dist/docs/how-to/configure-project.ko.md +16 -16
- package/dist/docs/how-to/configure-project.md +15 -12
- package/dist/docs/how-to/connect-surfaces.ko.md +67 -34
- package/dist/docs/how-to/connect-surfaces.md +67 -34
- package/dist/docs/how-to/write-disciplines.ko.md +64 -7
- package/dist/docs/how-to/write-disciplines.md +65 -7
- package/dist/docs/index.json +744 -362
- package/dist/docs/reference/cli/covenant-check.ko.md +112 -65
- package/dist/docs/reference/cli/covenant-check.md +114 -59
- package/dist/docs/reference/cli/docs.ko.md +2 -2
- package/dist/docs/reference/cli/docs.md +2 -2
- package/dist/docs/reference/cli/explain.ko.md +20 -15
- package/dist/docs/reference/cli/explain.md +22 -15
- package/dist/docs/reference/cli/init.ko.md +91 -52
- package/dist/docs/reference/cli/init.md +81 -55
- package/dist/docs/reference/configuration/index.ko.md +182 -71
- package/dist/docs/reference/configuration/index.md +188 -76
- package/dist/docs/reference/packages/adapter-claude-code.ko.md +39 -11
- package/dist/docs/reference/packages/adapter-claude-code.md +40 -14
- package/dist/docs/reference/packages/adapter-codex.ko.md +99 -0
- package/dist/docs/reference/packages/adapter-codex.md +100 -0
- package/dist/docs/reference/packages/adapter-grok.ko.md +81 -0
- package/dist/docs/reference/packages/adapter-grok.md +83 -0
- package/dist/docs/reference/packages/core.ko.md +50 -4
- package/dist/docs/reference/packages/core.md +55 -6
- package/dist/docs/reference/packages/polydeukes.ko.md +139 -77
- package/dist/docs/reference/packages/polydeukes.md +147 -81
- package/dist/docs/reference/packages/sdk-ts.ko.md +164 -0
- package/dist/docs/reference/packages/sdk-ts.md +167 -0
- package/dist/docs/troubleshooting.ko.md +51 -19
- package/dist/docs/troubleshooting.md +53 -17
- package/dist/docs/tutorials/first-judgment.ko.md +6 -4
- package/dist/docs/tutorials/first-judgment.md +6 -4
- package/dist/explain.d.ts +1 -1
- package/dist/explain.js +37 -22
- package/dist/load-config.d.ts +25 -1
- package/dist/load-config.js +21 -3
- package/dist/pre-state-reader.d.ts +1 -1
- package/dist/pre-state-reader.js +1 -1
- package/dist/scaffold-project.d.ts +2 -2
- package/dist/scaffold-project.js +12 -4
- package/dist/schema/polydeukes.schema.json +12 -0
- package/dist/worktree-reader.d.ts +19 -0
- package/dist/worktree-reader.js +30 -0
- package/package.json +5 -18
- package/dist/claude-code-hook.d.ts +0 -79
- package/dist/claude-code-hook.js +0 -372
- package/dist/claude-code.d.ts +0 -6
- package/dist/claude-code.js +0 -6
- package/dist/covenant-module.d.ts +0 -25
- package/dist/covenant-module.js +0 -42
- package/dist/docs/reference/packages/adapter-git.ko.md +0 -101
- package/dist/docs/reference/packages/adapter-git.md +0 -108
- package/dist/docs/reference/packages/covenant.ko.md +0 -115
- package/dist/docs/reference/packages/covenant.md +0 -123
- package/dist/index.d.ts +0 -22
- package/dist/index.js +0 -21
- package/dist/init-claude-code.d.ts +0 -52
- package/dist/init-claude-code.js +0 -586
- package/dist/init-grok.d.ts +0 -51
- package/dist/init-grok.js +0 -242
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# `@polydeukes/adapter-codex`
|
|
2
|
+
|
|
3
|
+
[English](adapter-codex.md) · **한국어**
|
|
4
|
+
|
|
5
|
+
> **Codex의 설치 단위**입니다. `PreToolUse` 페이로드가 약속(covenant) 입력 IR이 되고, 패치가
|
|
6
|
+
> 건드리는 파일마다 원소 하나가 실립니다. 세션 표면을 프로젝트에 설치하는 것도 이 패키지가
|
|
7
|
+
> 합니다.
|
|
8
|
+
>
|
|
9
|
+
> 베타입니다. `polydeukes`와 함께 설치하며, `polydeukes`는 이 패키지의 `peerDependency`입니다.
|
|
10
|
+
|
|
11
|
+
<a id="ownership"></a>
|
|
12
|
+
## 담당하는 기능
|
|
13
|
+
|
|
14
|
+
Codex의 입력을 공통 형식으로 번역합니다. 에이전트와 도구의 구체적인 이름은 이 패키지에서
|
|
15
|
+
처리하고 코어에는 넣지 않습니다.
|
|
16
|
+
|
|
17
|
+
| 단위 | 하는 일 |
|
|
18
|
+
|---|---|
|
|
19
|
+
| `pdks-codex` 실행 파일 | 하위 명령 하나 `pdks-codex init`으로 프로젝트에 세션 표면을 등록합니다 |
|
|
20
|
+
| `runHook` | `PreToolUse` 페이로드 하나를 입력 IR로 바꾸고 판정기를 스폰합니다 |
|
|
21
|
+
| 페이로드 검증 | 호스트의 생성 스키마가 필수로 지정한 키를 모두 요구하며, 그 호스트가 보내는 한 가지 표기만 받습니다 |
|
|
22
|
+
| 패치 해석 | `apply_patch` 호출의 원본 패치 텍스트를 건드리는 파일마다 변경 하나로 풉니다 |
|
|
23
|
+
| 경로 기준 변환 | 패치 경로를 호출의 작업 디렉터리 기준으로 해석한 뒤 프로젝트 루트 기준으로 실습니다 |
|
|
24
|
+
|
|
25
|
+
생성된 훅 위임자가 불러오는 것이 `runHook({ repoRoot })`입니다. `tools` 명부를 실은 입력 IR을
|
|
26
|
+
만든 뒤 — `session`과 `actor` 키는 없습니다 — `repoRoot`에서
|
|
27
|
+
`pdks covenant check --enforce block`을 스폰하고 그 자식 프로세스의 종료 코드를 그대로
|
|
28
|
+
돌려줍니다. 판정은 그 자식 프로세스가 하며, 이 패키지에는 판정 코드가 없습니다.
|
|
29
|
+
|
|
30
|
+
**이 패키지는 텔레메트리 행을 쓰지 않습니다.** 스폰 전에 실패하면 그 사실을 한 줄로 만들어
|
|
31
|
+
`pdks`의 stdin으로 보내므로, 그 호출이 남기는 행은 언제나 한 곳에서만 기록됩니다.
|
|
32
|
+
|
|
33
|
+
<a id="apply-patch"></a>
|
|
34
|
+
## 형제 어댑터는 인자를 읽는데 이 어댑터가 텍스트를 해석하는 이유
|
|
35
|
+
|
|
36
|
+
Codex는 모든 파일 편집을 `apply_patch`라는 이름 하나로 정규화하고, 패치 자체를
|
|
37
|
+
`tool_input.command`에 담습니다. 셸 호출이 명령줄을 싣는 것과 같은 자리입니다. 읽을 경로
|
|
38
|
+
인자가 없습니다. `Edit`과 `Write`는 `.codex/hooks.json`에 적을 수 있는 matcher 별칭이지만,
|
|
39
|
+
페이로드는 언제나 도구 이름을 `apply_patch`로 보냅니다. 그래서 별칭을 기준으로 삼은 명부나
|
|
40
|
+
분기는 실제로 도착하는 어떤 호출과도 일치하지 않습니다.
|
|
41
|
+
|
|
42
|
+
패치 하나가 한 호출에서 파일을 만들고 고치고 지우고 이름을 바꿀 수 있습니다. 이 어댑터는
|
|
43
|
+
각각을 IR 하나의 원소로 실어 한 번만 스폰합니다. 모든 파일이 판정되고, 그중 하나라도
|
|
44
|
+
차단되면 호출 전체가 차단됩니다. 이름 변경은 원소를 둘 만듭니다. 떠나는 경로와 도착하는
|
|
45
|
+
경로를 모두 바꾸기 때문입니다.
|
|
46
|
+
|
|
47
|
+
<a id="consumer"></a>
|
|
48
|
+
## 사용자가 다루는 부분
|
|
49
|
+
|
|
50
|
+
프로젝트 루트에서 두 줄이면 Codex 세션 표면이 설치됩니다.
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
npm install --save-dev polydeukes @polydeukes/core @polydeukes/adapter-codex
|
|
54
|
+
npx pdks-codex init
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`pdks-codex init`은 프로젝트에서 `polydeukes`를 찾아 확인한 뒤, 에이전트 중립 초기 구성을
|
|
58
|
+
위해 `pdks init`을 스폰하고, 위임자를 쓰고 자기 항목을 `.codex/hooks.json`에 병합합니다.
|
|
59
|
+
병합은 기존 내용을 지우지 않습니다. 다른 이벤트, 다른 matcher, 이 패키지가 모르는 키는 그대로
|
|
60
|
+
둡니다. 다시 실행하면 이미 있는 산출물을 건너뛴 것으로 보고하고 아무것도 덮어쓰지 않습니다.
|
|
61
|
+
전체 산출물 목록은 [`pdks init`](../cli/init.ko.md#init-codex)에 있습니다.
|
|
62
|
+
|
|
63
|
+
**등록 파일을 쓰는 것으로 설치가 끝나지 않습니다.** Codex는 훅 정의의 해시로 신뢰를
|
|
64
|
+
기록하므로, 생성된 훅은 검토 대상으로 표시되고 `/hooks`에서 승인하기 전까지 건너뛰어집니다.
|
|
65
|
+
`init`이 실행할 때마다 바이트가 같은 명령 문자열을 쓰는 이유가 이것입니다. 문자열이 바뀌면
|
|
66
|
+
다시 승인해야 하고, 누군가 승인하기 전까지는 아무것도 판정되지 않습니다.
|
|
67
|
+
|
|
68
|
+
이 어댑터를 `@polydeukes/adapter-claude-code`나 `@polydeukes/adapter-grok`과 한 프로젝트에
|
|
69
|
+
함께 설치하면 호출마다 판정기가 두 번 실행될 수 있습니다.
|
|
70
|
+
|
|
71
|
+
- **생성된 훅**은 이 패키지에서 `runHook`을 불러옵니다. 패키지를 올리면 실행되는 내용이
|
|
72
|
+
올라가며, 훅 파일 자체는 다시 만들 필요가 없습니다.
|
|
73
|
+
|
|
74
|
+
자체 설정 이름 공간은 없습니다. `pdks init`이 쓰는 초기 설정은 기본적으로 `.codex/hooks`를
|
|
75
|
+
보호하므로, 이 설치기가 만드는 등록 파일은 같은 설치가 만든 설정이 지킵니다.
|
|
76
|
+
|
|
77
|
+
<a id="limits"></a>
|
|
78
|
+
## 선언된 한계
|
|
79
|
+
|
|
80
|
+
앞의 셋은 호스트 자신의 한계이고 호스트 훅 문서가 밝힌 사항입니다. 어떤 어댑터도 이 범위를
|
|
81
|
+
좁힐 수 없습니다.
|
|
82
|
+
|
|
83
|
+
- **`write_stdin`은 다시 판정되지 않습니다.** 이미 `PreToolUse`를 통과한 unified-exec 세션에
|
|
84
|
+
입력을 전달합니다. 입력을 받으려고 열어 둔 셸은 그것을 연 호출에서 한 번 판정됩니다.
|
|
85
|
+
- **호스트가 제공하는 도구는 이 경로를 지나지 않습니다.** 웹 검색 같은 도구는 로컬 함수 도구
|
|
86
|
+
훅을 거치지 않으므로 어떤 약속에도 닿지 않습니다.
|
|
87
|
+
- **호스트는 자기 도구 훅을 완전한 차단 경계가 아니라 보조 장치라고 밝힙니다.** 일부 특수한
|
|
88
|
+
도구 경로는 기본 훅 경로를 지나지 않을 수 있습니다.
|
|
89
|
+
- **대화 기록 채널이 없습니다.** IR에 `session`과 `actor` 키가 없습니다. 페이로드가 대화 기록
|
|
90
|
+
경로를 지목하지만 호스트가 그 형식을 안정된 인터페이스가 아니라고 밝혔으므로 어떤 판정도
|
|
91
|
+
그것을 읽지 않습니다. 그래서 세션 증인 밸브가 필요로 하는 사람 메시지 증거를 얻을 수
|
|
92
|
+
없습니다. 의도적으로 차단된 편집을 하려면 사용자의 터미널을 쓰십시오.
|
|
93
|
+
- **프로젝트 밖으로 해석되는 패치는 판정하지 않고 거부합니다.** 그런 경로는 프로젝트 기준
|
|
94
|
+
상대 경로가 없고, 그것을 실은 원소는 어떤 관측 범위에도 들어가지 않아 판정 없이 지나가게
|
|
95
|
+
됩니다.
|
|
96
|
+
- **`polydeukes`를 찾지 못하면 행이 남지 않습니다.** 프로젝트에서 통합 패키지를 찾을 수 없으면
|
|
97
|
+
스폰할 프로세스도 기록할 로그 경로도 없으므로, 훅은 stderr에 한 줄을 남기고 `2`로 끝나며
|
|
98
|
+
텔레메트리 로그에는 아무것도 추가되지 않습니다. 그 밖의 모든 스폰 전 실패는 `pdks`에 도달해
|
|
99
|
+
행을 남깁니다.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# `@polydeukes/adapter-codex`
|
|
2
|
+
|
|
3
|
+
**English** · [한국어](adapter-codex.ko.md)
|
|
4
|
+
|
|
5
|
+
> **The Codex install unit** — `PreToolUse` payloads become the covenant input IR, with one
|
|
6
|
+
> element per file the patch touches, and the package installs the session surface into a
|
|
7
|
+
> project.
|
|
8
|
+
>
|
|
9
|
+
> Beta. 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 Codex'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-codex` bin | One subcommand, `pdks-codex 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 validation | Demands every key the host's generated schema marks required, in the one spelling that host sends |
|
|
22
|
+
| Patch parsing | Turns the raw patch text of an `apply_patch` call into one file change per file it touches |
|
|
23
|
+
| Path rebasing | Resolves a patch path against the call's working directory and carries it relative to the project root |
|
|
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, so the row that call earns is written by the one writer.
|
|
32
|
+
|
|
33
|
+
<a id="apply-patch"></a>
|
|
34
|
+
## Why this adapter parses text where its siblings read arguments
|
|
35
|
+
|
|
36
|
+
Codex normalises every file edit into a single tool name, `apply_patch`, and puts the patch
|
|
37
|
+
itself in `tool_input.command` — the same field a shell call uses for its command line. There
|
|
38
|
+
is no path argument to read. `Edit` and `Write` exist as matcher aliases you may write in
|
|
39
|
+
`.codex/hooks.json`, but the payload always names the tool `apply_patch`, so a roster or a
|
|
40
|
+
branch keyed on the aliases matches nothing that ever arrives.
|
|
41
|
+
|
|
42
|
+
One patch can create, update, delete and rename files in one call. The adapter carries each as
|
|
43
|
+
its own element of one IR, on one spawn: every file is judged, and any one of them blocking
|
|
44
|
+
blocks the whole call. A rename contributes two elements, because it changes the path it
|
|
45
|
+
leaves as well as the one it takes.
|
|
46
|
+
|
|
47
|
+
<a id="consumer"></a>
|
|
48
|
+
## Where the consumer touches it
|
|
49
|
+
|
|
50
|
+
Two lines install the Codex session surface, run from the project root:
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
npm install --save-dev polydeukes @polydeukes/core @polydeukes/adapter-codex
|
|
54
|
+
npx pdks-codex init
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`pdks-codex init` resolves `polydeukes` from the project, spawns `pdks init` for the
|
|
58
|
+
agent-neutral scaffold, then writes the delegator and merges its entry into
|
|
59
|
+
`.codex/hooks.json` non-destructively — other events, other matchers and keys it does not know
|
|
60
|
+
are left alone. A re-run reports each existing artifact as skipped and overwrites nothing. The
|
|
61
|
+
full artifact list is in [`pdks init`](../cli/init.md#init-codex).
|
|
62
|
+
|
|
63
|
+
**Writing the registration is not the end of the install.** Codex records trust against the
|
|
64
|
+
hash of a hook's definition, so the generated hook is listed for review and skipped until you
|
|
65
|
+
approve it with `/hooks`. This is why `init` writes a byte-identical command string on every
|
|
66
|
+
run: a changed one needs approving again, and until someone does, nothing is judged.
|
|
67
|
+
|
|
68
|
+
Installing this adapter beside `@polydeukes/adapter-claude-code` or
|
|
69
|
+
`@polydeukes/adapter-grok` in one project can run the judge twice per call.
|
|
70
|
+
|
|
71
|
+
- **The generated hook** imports `runHook` from this package. Upgrading the package upgrades
|
|
72
|
+
what runs; the hook file itself never changes.
|
|
73
|
+
|
|
74
|
+
No configuration namespace of its own. The scaffold `pdks init` writes protects `.codex/hooks`
|
|
75
|
+
by default, so the registration this installer creates is covered by the config it creates.
|
|
76
|
+
|
|
77
|
+
<a id="limits"></a>
|
|
78
|
+
## Declared limits
|
|
79
|
+
|
|
80
|
+
The first three are the host's own, stated in its hook documentation, and no adapter can
|
|
81
|
+
narrow them.
|
|
82
|
+
|
|
83
|
+
- **`write_stdin` is not judged again.** It delivers input to a unified-exec session that
|
|
84
|
+
already passed `PreToolUse`. A shell left open for input is judged once, at the call that
|
|
85
|
+
opened it.
|
|
86
|
+
- **Hosted tools do not take this path.** Web search and its kind do not run through the local
|
|
87
|
+
function-tool hooks, so they reach no covenant.
|
|
88
|
+
- **The host calls its tool hooks a guardrail rather than a complete enforcement boundary.**
|
|
89
|
+
Some specialized tool paths can opt out of the default hook path.
|
|
90
|
+
- **There is no transcript channel.** The IR omits `session` and `actor`. The payload names a
|
|
91
|
+
transcript path, but the host documents that format as unstable, so no judgment reads it —
|
|
92
|
+
which leaves the session witness valve without the human-message evidence it needs. For an
|
|
93
|
+
intentional blocked edit, use your own terminal.
|
|
94
|
+
- **A patch resolving outside the project is refused rather than judged.** Such a path has no
|
|
95
|
+
project-relative form, and an element carrying one would land in no scope — judged over
|
|
96
|
+
nothing, and passed.
|
|
97
|
+
- **An unresolvable `polydeukes` leaves no row.** When the umbrella cannot be resolved from the
|
|
98
|
+
project there is no process to spawn and no log path to write to, so the hook exits `2` with
|
|
99
|
+
one line on stderr and the telemetry log gains nothing. Every other pre-spawn failure does
|
|
100
|
+
reach `pdks` and does leave a row.
|
|
@@ -0,0 +1,81 @@
|
|
|
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/core @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`에 도달해 행을 남깁니다.
|
|
78
|
+
- **다른 호스트는 각자의 어댑터로 설치합니다.** Claude Code는
|
|
79
|
+
`@polydeukes/adapter-claude-code`로, Codex는 `@polydeukes/adapter-codex`로 설치합니다.
|
|
80
|
+
각 패키지가 자기 위임자와 명부를 씁니다. 한 프로젝트에 세션 어댑터를 둘 이상 설치하면
|
|
81
|
+
호출마다 판정기가 여러 번 실행될 수 있습니다.
|
|
@@ -0,0 +1,83 @@
|
|
|
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
|
+
> Beta. 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/core @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.
|
|
80
|
+
- **Other hosts install through their own adapters.** Claude Code through
|
|
81
|
+
`@polydeukes/adapter-claude-code`, Codex through `@polydeukes/adapter-codex`. Each package
|
|
82
|
+
writes its own delegator and roster. Installing more than one session adapter in a project
|
|
83
|
+
can run the judge more than once per call.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
> **모든 약속(covenant)이 말하는 프로토콜**입니다. 입력 IR과 판정 결과 형태, 설정 스키마,
|
|
6
6
|
> 텔레메트리 수집기가 여기 있습니다.
|
|
7
7
|
>
|
|
8
|
-
>
|
|
8
|
+
> 베타입니다. 일반 사용자는 이 패키지를 따로 설치하거나 불러올 필요가 없습니다. 통합 패키지의 의존성으로 설치되며, 사용자 진입점은
|
|
9
9
|
> [`polydeukes`](polydeukes.ko.md)입니다.
|
|
10
10
|
|
|
11
11
|
<a id="ownership"></a>
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
**값**이라서, 코어의 에이전트 중립성은 grep으로 확인되는 주장입니다. 다른 모든 패키지가
|
|
29
29
|
이 패키지에 의존하고, 이 패키지는 그 어느 것에도 의존하지 않습니다.
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
**세션 어댑터는 이 패키지를 `peerDependency`로 선언합니다.** 따로 설치하는 대신 우산과 같은 어휘를 공유합니다. `SOURCE_KINDS`와
|
|
32
32
|
`parseInput`은 검증기와 엔진이
|
|
33
33
|
같은 값을 참조해야 합니다. 서로 다른 사본을 사용하면 설치는 성공해도 동작이 달라질 수 있습니다.
|
|
34
34
|
통합 패키지가 일반 의존성으로 core를 제공하므로 사용자는 패키지 하나만 설치하면 됩니다.
|
|
@@ -41,7 +41,10 @@
|
|
|
41
41
|
`.polydeukes/roi.log`의 차단 기록도 이 판정 어휘를 사용합니다.
|
|
42
42
|
|
|
43
43
|
`world`는 표면이 공급합니다(`files`, `changes`, `channels`). 판정기가 디스크에서 읽지
|
|
44
|
-
않습니다.
|
|
44
|
+
않습니다. `tools`와 `session`은 호스트가 공급합니다. 명부는 어댑터가 채우는 값이고, 세션은
|
|
45
|
+
IR만으로는 증명하지 못하는 두 사실, 메시지의 신선도와 호출의 결과를 담은 증거입니다.
|
|
46
|
+
`transcriptFromSession`은 그 키에서 증인이나 선행 조건 소비자가 읽는 대화 기록을 만들고,
|
|
47
|
+
`transcriptFromInput`은 그 두 사실 없이 IR에서 같은 대화 기록을 만듭니다.
|
|
45
48
|
|
|
46
49
|
```ts
|
|
47
50
|
type CovenantInput = {
|
|
@@ -54,6 +57,13 @@ type CovenantInput = {
|
|
|
54
57
|
changes?: string[];
|
|
55
58
|
channels?: { sidecar?: string };
|
|
56
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
|
+
};
|
|
57
67
|
};
|
|
58
68
|
|
|
59
69
|
type FileChange =
|
|
@@ -98,6 +108,42 @@ function allFileChanges(input: CovenantInput): FileChange[];
|
|
|
98
108
|
`allFileChanges`는 귀속이 필요 없는 소비자를 위해 모든 호출의 증거를 호출 순서대로
|
|
99
109
|
평탄화합니다. 증거 없는 호출은 건너뛰고 무엇으로도 대체하지 않습니다.
|
|
100
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
|
+
|
|
101
147
|
<a id="consumer-contract"></a>
|
|
102
148
|
## 사용자와의 접점
|
|
103
149
|
|
|
@@ -119,7 +165,7 @@ function allFileChanges(input: CovenantInput): FileChange[];
|
|
|
119
165
|
- **어댑터 네임스페이스는 이름이 아니라 형태로 검증합니다.** `defineConfig()`는 `adapters`가
|
|
120
166
|
평범한 객체의 맵인지, 각 네임스페이스 값이 객체인지를 봅니다. 네임스페이스 **이름**이
|
|
121
167
|
누군가 구현한 것인지는 보지 않고, 네임스페이스 안쪽은 들여다보지 않습니다.
|
|
122
|
-
|
|
168
|
+
네임스페이스 안의 미지 어휘는 해당 어댑터의 검증기가 자기 층위에서 거부합니다. 여기가
|
|
123
169
|
아닙니다.
|
|
124
170
|
- **기본 대화 기록은 아무것도 하지 않습니다.** 실제 대화 기록을 주입하지 않은 소비자는
|
|
125
171
|
"아무 일도 없었다"는 결과를 받습니다. 이 상태에서는 증인 밸브가 작업을 허용하지 않으므로
|
|
@@ -5,7 +5,7 @@
|
|
|
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
|
+
> Beta. A transitive dependency of the umbrella: you do not install it and you do not import
|
|
9
9
|
> it. The consumer entry point is [`polydeukes`](polydeukes.md).
|
|
10
10
|
|
|
11
11
|
<a id="ownership"></a>
|
|
@@ -28,8 +28,8 @@ hand-rolled and the published JSON Schema is a sibling artifact the source never
|
|
|
28
28
|
*values* supplied by configs and adapters, so the core's agent-neutrality is a claim a grep
|
|
29
29
|
can check. Every other package depends on this one; this one depends on none of them.
|
|
30
30
|
|
|
31
|
-
**The
|
|
32
|
-
own.**
|
|
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
|
|
33
33
|
`parseInput` have to be one set of values for the validator and the engine to agree, and two
|
|
34
34
|
copies would disagree silently instead of failing at install time. The umbrella carries the
|
|
35
35
|
ordinary dependency that satisfies that peer, which is why a consumer still installs one
|
|
@@ -44,7 +44,11 @@ verdict the wrapper translates into an exit code. Blocked rows in `.polydeukes/r
|
|
|
44
44
|
use this judgment vocabulary.
|
|
45
45
|
|
|
46
46
|
`world` is supplied by the surface (`files`, `changes`, `channels`). The judge does not
|
|
47
|
-
read it from disk.
|
|
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.
|
|
48
52
|
|
|
49
53
|
```ts
|
|
50
54
|
type CovenantInput = {
|
|
@@ -57,6 +61,13 @@ type CovenantInput = {
|
|
|
57
61
|
changes?: string[];
|
|
58
62
|
channels?: { sidecar?: string };
|
|
59
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
|
+
};
|
|
60
71
|
};
|
|
61
72
|
|
|
62
73
|
type FileChange =
|
|
@@ -101,6 +112,44 @@ The exported constants are `EXIT_UPHOLD` (`0`), `EXIT_BREAK_NON_BLOCKING` (`1`),
|
|
|
101
112
|
`allFileChanges` flattens every call's evidence in call order for consumers that need no
|
|
102
113
|
attribution. Calls without evidence are skipped, never substituted for.
|
|
103
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
|
+
|
|
104
153
|
<a id="consumer-contract"></a>
|
|
105
154
|
## Where the consumer touches it
|
|
106
155
|
|
|
@@ -123,8 +172,8 @@ Everything else here is reached through `polydeukes`.
|
|
|
123
172
|
- **Adapter namespaces are validated by shape, not by name.** `defineConfig()` checks that
|
|
124
173
|
`adapters` is a map of plain objects and that each namespace value is an object. It does
|
|
125
174
|
not check that a namespace *name* is one anybody implements, and it does not look inside
|
|
126
|
-
the namespace at all. Unknown vocabulary inside
|
|
127
|
-
|
|
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.
|
|
128
177
|
- **The default transcript is a noop.** A consumer that injects no real transcript
|
|
129
178
|
converges on "nothing happened", which is the safe direction for a valve: it never opens.
|
|
130
179
|
Real transcripts live behind adapters.
|