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.
- package/README.ko.md +30 -70
- package/README.md +31 -84
- package/dist/baseline.d.ts +37 -1
- package/dist/baseline.js +68 -1
- package/dist/bin.d.ts +3 -4
- package/dist/bin.js +79 -93
- 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 +103 -0
- package/dist/covenant/discipline.js +667 -0
- package/dist/covenant/dispatch.d.ts +153 -0
- package/dist/covenant/dispatch.js +237 -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 +72 -39
- package/dist/covenant-check.js +260 -121
- package/dist/diff-ir.d.ts +28 -0
- package/dist/diff-ir.js +310 -0
- package/dist/docs/README.ko.md +60 -0
- package/dist/docs/README.md +64 -0
- package/dist/docs/catalog.json +480 -0
- package/dist/docs/concepts/judgment.ko.md +113 -0
- package/dist/docs/concepts/judgment.md +113 -0
- package/dist/docs/how-to/configure-project.ko.md +99 -0
- package/dist/docs/how-to/configure-project.md +98 -0
- package/dist/docs/how-to/connect-surfaces.ko.md +120 -0
- package/dist/docs/how-to/connect-surfaces.md +121 -0
- package/dist/docs/how-to/write-disciplines.ko.md +179 -0
- package/dist/docs/how-to/write-disciplines.md +181 -0
- package/dist/docs/index.json +2280 -0
- package/dist/docs/reference/cli/covenant-check.ko.md +148 -0
- package/dist/docs/reference/cli/covenant-check.md +153 -0
- package/dist/docs/reference/cli/docs.ko.md +97 -0
- package/dist/docs/reference/cli/docs.md +95 -0
- package/dist/docs/reference/cli/explain.ko.md +84 -0
- package/dist/docs/reference/cli/explain.md +89 -0
- package/dist/docs/reference/cli/init.ko.md +119 -0
- package/dist/docs/reference/cli/init.md +119 -0
- package/dist/docs/reference/configuration/index.ko.md +553 -0
- package/dist/docs/reference/{configuration.md → configuration/index.md} +215 -90
- package/dist/docs/reference/packages/adapter-claude-code.ko.md +110 -0
- package/dist/docs/reference/{adapter-claude-code.md → packages/adapter-claude-code.md} +47 -19
- package/dist/docs/reference/packages/adapter-grok.ko.md +77 -0
- package/dist/docs/reference/packages/adapter-grok.md +79 -0
- package/dist/docs/reference/packages/core.ko.md +174 -0
- package/dist/docs/reference/{core.md → packages/core.md} +74 -12
- package/dist/docs/reference/packages/polydeukes.ko.md +195 -0
- package/dist/docs/reference/packages/polydeukes.md +204 -0
- package/dist/docs/reference/packages/sdk-ts.ko.md +161 -0
- package/dist/docs/reference/packages/sdk-ts.md +164 -0
- package/dist/docs/troubleshooting.ko.md +144 -0
- package/dist/docs/troubleshooting.md +103 -151
- package/dist/docs/tutorials/first-judgment.ko.md +82 -0
- package/dist/docs/tutorials/first-judgment.md +81 -0
- package/dist/docs-catalog.d.ts +25 -0
- package/dist/docs-catalog.js +450 -0
- package/dist/docs-library.d.ts +23 -0
- package/dist/docs-library.js +347 -0
- package/dist/docs-markdown.d.ts +32 -0
- package/dist/docs-markdown.js +150 -0
- package/dist/docs-query.d.ts +11 -40
- package/dist/docs-query.js +28 -122
- package/dist/docs-types.d.ts +105 -0
- package/dist/docs-types.js +2 -0
- package/dist/explain.d.ts +1 -1
- package/dist/explain.js +37 -22
- package/dist/load-config.d.ts +1 -1
- package/dist/load-config.js +1 -1
- 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 +9 -3
- 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 +3 -17
- 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/configuration.md +0 -103
- package/dist/docs/installation.md +0 -241
- package/dist/docs/reference/adapter-git.md +0 -100
- package/dist/docs/reference/covenant.md +0 -116
- package/dist/docs/reference/polydeukes.md +0 -315
- 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 -469
- package/dist/init-grok.d.ts +0 -51
- package/dist/init-grok.js +0 -242
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# 규율 작성하기
|
|
2
|
+
|
|
3
|
+
[English](../how-to/write-disciplines.md) · **한국어**
|
|
4
|
+
|
|
5
|
+
규율(discipline)은 확인하고 싶은 개발 관행을 선언한 항목입니다. 관측할 파일이나 세션의
|
|
6
|
+
증거를 고르고, 추출 과정과 관계를 적은 다음 위반과 정상 사례를 각각 실행합니다.
|
|
7
|
+
관측 결과를 보고 차단이 필요하다고 판단하기 전까지는 기본 강제 수준인 `advise`를 유지합니다.
|
|
8
|
+
|
|
9
|
+
<a id="locale-key-pairing"></a>
|
|
10
|
+
## 번역 키 짝 맞춤
|
|
11
|
+
|
|
12
|
+
두 JSON 번역 파일의 키 집합을 비교합니다. 중첩된 키도 비교 대상입니다.
|
|
13
|
+
아래 전체 YAML을 **예제 프로젝트**의 `polydeukes.config.yaml`로 저장합니다. 기존 프로젝트의
|
|
14
|
+
설정을 덮어쓰지 마세요. 기존 설정에 추가할 때는 규율 항목만 복사합니다.
|
|
15
|
+
설치 절차는 [첫 판정 튜토리얼](../tutorials/first-judgment.ko.md)에 있습니다.
|
|
16
|
+
|
|
17
|
+
```yaml
|
|
18
|
+
languages:
|
|
19
|
+
json:
|
|
20
|
+
productionGlob: 'locales/**/*.json'
|
|
21
|
+
testCmd: 'pnpm test'
|
|
22
|
+
telemetry:
|
|
23
|
+
logPath: '.polydeukes/roi.log'
|
|
24
|
+
disciplines:
|
|
25
|
+
- id: 'locale-key-parity'
|
|
26
|
+
why: 'the ko and en locales must carry the same keys'
|
|
27
|
+
declare:
|
|
28
|
+
mechanism: 'pairing'
|
|
29
|
+
sources:
|
|
30
|
+
ko: { file: 'locales/ko.json' }
|
|
31
|
+
en: { file: 'locales/en.json' }
|
|
32
|
+
supply: { ko: 'error', en: 'error' }
|
|
33
|
+
scope: { source: 'target.path', include: ['^locales/(ko|en)\.json$'] }
|
|
34
|
+
extract:
|
|
35
|
+
koKeys:
|
|
36
|
+
- { op: 'source', of: 'ko' }
|
|
37
|
+
- { op: 'json' }
|
|
38
|
+
- { op: 'flattenKeys' }
|
|
39
|
+
enKeys:
|
|
40
|
+
- { op: 'source', of: 'en' }
|
|
41
|
+
- { op: 'json' }
|
|
42
|
+
- { op: 'flattenKeys' }
|
|
43
|
+
relate:
|
|
44
|
+
- id: 'parity'
|
|
45
|
+
relation: { op: 'equal', of: ['koKeys', 'enKeys'] }
|
|
46
|
+
messageBySide:
|
|
47
|
+
left: '{key} is in ko only'
|
|
48
|
+
right: '{key} is in en only'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`flattenKeys`는 번역 값이 아니라 키를 추출합니다. `equal`은 양방향으로 비교하고,
|
|
52
|
+
`messageBySide`는 어느 파일에 짝이 없는 키가 있는지 알려 줍니다. 기본 강제 수준은
|
|
53
|
+
`advise`입니다. 소스 파일 둘 다 존재하고 올바른 JSON이어야 합니다. 변경 집합 표면은 선택한
|
|
54
|
+
관측 범위에서 파일을 읽고, 세션 편집에서는 바뀌는 파일의 편집 후 내용을 사용합니다.
|
|
55
|
+
|
|
56
|
+
예제 프로젝트 루트에서 키가 같은 파일을 만들고 git 추적 대상으로 등록합니다.
|
|
57
|
+
아래 커밋에는 평소 사용하는 git 작성자 설정이 필요합니다. 이 커밋이 작업 트리 비교의
|
|
58
|
+
기준이 됩니다.
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
mkdir -p locales
|
|
62
|
+
printf '{"home":"Home"}\n' > locales/en.json
|
|
63
|
+
printf '{"home":"홈"}\n' > locales/ko.json
|
|
64
|
+
git add locales/en.json locales/ko.json
|
|
65
|
+
git commit -m 'docs: prepare locale example'
|
|
66
|
+
printf '{"home":"Home","settings":"Settings"}\n' > locales/en.json
|
|
67
|
+
git diff HEAD | pnpm exec pdks covenant check --diff
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`locale-key-parity`의 `advised` 진단에 영어에만 있는 `settings` 키가 나와야 합니다.
|
|
71
|
+
권고이므로 명령은 종료 코드 0으로 끝납니다. 한국어 파일에 빠진 키를 추가하고 같은 검사를 반복합니다.
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
printf '{"home":"홈","settings":"설정"}\n' > locales/ko.json
|
|
75
|
+
git diff HEAD | pnpm exec pdks covenant check --diff
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
이제 키 비교 진단이 없어야 합니다. 번역 값은 서로 다르지만 키는 같습니다.
|
|
79
|
+
확인이 끝나면 두 예제 파일을 커밋한 기준 상태로 되돌립니다.
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
git restore -- locales/en.json locales/ko.json
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`git diff HEAD`는 마지막 커밋과의 차이를 냅니다. 아직 git이 추적하지 않는 파일은
|
|
86
|
+
`git add -N`을 거쳐야 diff에 나타납니다. 이 예제는 수정 사례를 검사하고 쉽게 원상 복구하기
|
|
87
|
+
위해 기준 상태를 커밋합니다.
|
|
88
|
+
소스 파일이 존재한다는 이유만으로 선언이 실행되지는 않습니다. 관측된 변경 중 하나
|
|
89
|
+
이상이 해당 선언의 적용 범위와 일치해야 합니다.
|
|
90
|
+
|
|
91
|
+
<a id="which-list"></a>
|
|
92
|
+
## 어느 목록에 적는가
|
|
93
|
+
|
|
94
|
+
규율 목록은 셋이고, 항목이 어느 목록에 속하는지는 소스 축이 정합니다. 기전이 정하지도 않고
|
|
95
|
+
관계가 정하지도 않습니다. 같은 `companion` 기전이라도 `file` 소스 위에 서면 `disciplines`에
|
|
96
|
+
있고 `changes` 위에 서면 `changeSetDisciplines`에 있습니다. 선언의 소스를 읽으면 목록이
|
|
97
|
+
따라 나옵니다.
|
|
98
|
+
|
|
99
|
+
| 선언이 읽는 것 | 목록 | 예 |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| 변경된 파일과 `file` 소스만 | `disciplines` | 파일 형상 유형들. 신규분 한정, 비가역 표식, 자기사면 금지, 통제 어휘, 이름 규약, `file` 소스 위의 동반 의무, 지문 동기, 순서 불변 |
|
|
102
|
+
| 대화 기록(transcript) | `sessionDisciplines` | 이력 4종. 선행 요구, 단계 순서, 턴 근접, 사전 언명 |
|
|
103
|
+
| 주체(actor) | `sessionDisciplines` | 생산자 전속, 주체 한정 |
|
|
104
|
+
| 명령줄 | `sessionDisciplines` | 명령줄 금지 |
|
|
105
|
+
| 스폰 기록 통로(`sidecar`) | `sessionDisciplines` | `{ sidecar: true }`를 묶는 모든 선언 |
|
|
106
|
+
| `changes` | `changeSetDisciplines` | 변경 집합 위의 짝 맞춤. 함께 움직여야 하는 경로 둘 사이의 `implies` |
|
|
107
|
+
|
|
108
|
+
항목은 그 소스가 가리키는 목록에 적습니다. 자리를 잘못 잡은 항목은 로드 시점 오류이고,
|
|
109
|
+
메시지가 항목과 그 항목이 읽는 통로와 가야 할 목록을 함께 대므로, 본문을 그대로 옮기면
|
|
110
|
+
됩니다. 규칙 자체와 오류 모양은
|
|
111
|
+
[설정 참조](../reference/configuration/index.ko.md#placement-rule)에 있습니다.
|
|
112
|
+
|
|
113
|
+
표면이 공급해야 할 것을 본체가 읽지 않아도 실제로는 표면에 묶이는 항목이 있습니다. 대화
|
|
114
|
+
기록을 읽는 밸브(`witness`)가 달린 항목은 밸브 자신의 `extract`가 대화 기록을 묶으므로 세션
|
|
115
|
+
항목이 됩니다.
|
|
116
|
+
|
|
117
|
+
<a id="posture"></a>
|
|
118
|
+
## 무인 실시간 표면의 기본 자세
|
|
119
|
+
|
|
120
|
+
무인 실시간 표면은 터미널 앞에 사람이 없는 어댑터 훅이나 SDK 호출자입니다. 사람이 지켜보는
|
|
121
|
+
자리에는 적용되지 않는 규칙 둘이 이곳에 적용됩니다.
|
|
122
|
+
|
|
123
|
+
**루프가 회차 안에서 스스로 고치지 못하는 항목을 `enforce: block`으로 올립니다.** 기준은
|
|
124
|
+
"되돌릴 수 없는가"가 아닙니다. 실시간 차단의 비용은 초 단위입니다. 모델이 stderr의 사유를
|
|
125
|
+
읽고 다시 시도하므로 위반이 그 회차 안에서 고쳐집니다. `advise`로 두면 같은 위반이 뒤의
|
|
126
|
+
검사, 곧 테스트 실행이나 CI나 리뷰어에게까지 가서 회차 하나를 쓰며 최대 45분이 듭니다.
|
|
127
|
+
"무인이니 전부 차단"이라는 뜻은 아닙니다. 차단은 회피를 낳고 회피는 텔레메트리 행을 남기지
|
|
128
|
+
않으므로, 루프가 손댈 수 없는 항목은 위반이라도 기록되는 `advise`에 두는 편이 낫습니다. 이
|
|
129
|
+
기준은 설정 저자의 것입니다.
|
|
130
|
+
|
|
131
|
+
**밸브가 없으므로 사유가 값으로 돌아옵니다.** 실시간 무인 표면에는 증인 밸브가 없습니다.
|
|
132
|
+
TTY도 사람의 턴도 없고, SDK는 증인 인자를 받지 않으며 세션을 지어내지도 않습니다. 그 자리를
|
|
133
|
+
대신하는 것이 사유를 데이터로 돌려주는 일입니다. `checkCovenant`는
|
|
134
|
+
`{ verdict: 'blocked', reason }`을 돌려주며 `reason`은 판정기 자신의 stderr이고,
|
|
135
|
+
`{ verdict: 'upheld', advisories }`는 종료 코드 0인 실행의 권고 줄을 싣습니다. 소비자는 그
|
|
136
|
+
텍스트를 사람이 나중에 읽는 자리, 곧 이슈나 로그에 적고 멈춥니다. 권고 텍스트를 모델에게
|
|
137
|
+
보일지도 소비자가 정합니다. 무인 루프에는 stderr 한 줄을 읽을 사람이 없으므로, 호출자가
|
|
138
|
+
전달해야 권고가 소비됩니다. 판정 결과의 모양은
|
|
139
|
+
[`@polydeukes/sdk-ts` 참조](../reference/packages/sdk-ts.ko.md)에 있습니다.
|
|
140
|
+
|
|
141
|
+
SDK 자신의 기본값은 실행 전체에 대한 `enforce: 'block'`이며, 이것은 표면의 강제 수준이지
|
|
142
|
+
항목의 것이 아닙니다. 보호 경로와 `enforce: block` 항목이 호출을 멈추고, 나머지 위반은
|
|
143
|
+
`advised`로 기록됩니다. 두 어댑터도 같은 방식으로 판정기를 스폰합니다.
|
|
144
|
+
|
|
145
|
+
<a id="when-to-draft"></a>
|
|
146
|
+
## 선언 대신 초안으로 남길 때
|
|
147
|
+
|
|
148
|
+
필요한 약속이지만 현재 문법으로 표현할 수 없다면 `draft`로 등록합니다.
|
|
149
|
+
|
|
150
|
+
```yaml
|
|
151
|
+
languages:
|
|
152
|
+
json:
|
|
153
|
+
productionGlob: 'locales/**/*.json'
|
|
154
|
+
testCmd: 'pnpm test'
|
|
155
|
+
disciplines:
|
|
156
|
+
- id: 'benchmark-supports-performance-claim'
|
|
157
|
+
why: 'a performance claim must be supported by a fresh benchmark run during judgment.'
|
|
158
|
+
draft: true
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
`draft: true`인 항목은 판정 결과나 텔레메트리 행을 남기지 않습니다. 설정에는 등록돼
|
|
162
|
+
있으므로 `pdks explain`에서 확인할 수 있습니다.
|
|
163
|
+
|
|
164
|
+
<a id="proof-runs"></a>
|
|
165
|
+
## 한 번은 실제로 판정해 보기
|
|
166
|
+
|
|
167
|
+
설정을 저장한 뒤에는 필요한 증거를 공급할 수 있는 판정 경로로 위반과 정상 사례를 모두
|
|
168
|
+
검사합니다. `git diff HEAD | pdks covenant check --diff`는 현재 작업 트리의 변경을 판정하고,
|
|
169
|
+
`pdks explain`은 선언과 초안의 등록 상태를 보여 줍니다. 위 번역 예제처럼 한쪽 파일만
|
|
170
|
+
바꾼 경우와 양쪽 키를 맞춘 경우를 비교하세요.
|
|
171
|
+
|
|
172
|
+
판정 결과가 나타나지 않으면 먼저 관측 조건을 확인합니다. 무시 대상이 아닌 관측 파일인지,
|
|
173
|
+
선택한 비교에서 실제로 바뀌었는지, 적용 범위가 맞는지, 해당 표면이 증거를 공급할 수 있는지
|
|
174
|
+
차례로 살펴봅니다. `pdks explain`과 로그에서 `config-fault`, `no-observation`,
|
|
175
|
+
`supply-pass`도 확인합니다. 진단이 없다는 사실만으로 선언이 작동한다고 판단하지 마세요.
|
|
176
|
+
|
|
177
|
+
위 초안은 키 비교와 다른 요구입니다. 현재 엔진은 판정 도중 새 벤치마크를 실행하지 않습니다.
|
|
178
|
+
이미 공급된 증거를 비교하는 것과 판정 도중 새 벤치마크를 실행하는 것은 다른 요구입니다.
|
|
179
|
+
[선언과 관측 한계](../concepts/judgment.ko.md#declarations)를 참고하세요.
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Write disciplines
|
|
2
|
+
|
|
3
|
+
**English** · [한국어](../how-to/write-disciplines.ko.md)
|
|
4
|
+
|
|
5
|
+
A discipline describes a practice you want checked. Choose the observed files or session evidence,
|
|
6
|
+
write an extraction and relation, then exercise both a violation and a valid case. Leave enforcement
|
|
7
|
+
at `advise` until you decide that the observed results justify blocking.
|
|
8
|
+
|
|
9
|
+
<a id="locale-key-pairing"></a>
|
|
10
|
+
## Locale key pairing
|
|
11
|
+
|
|
12
|
+
This declaration compares the key sets of two JSON translation files, including nested keys.
|
|
13
|
+
Save the complete YAML below as `polydeukes.config.yaml` in an **example project**, not over an
|
|
14
|
+
existing project's configuration. In an existing project, copy only the discipline entry.
|
|
15
|
+
The [first-judgment tutorial](../tutorials/first-judgment.md) supplies installation steps.
|
|
16
|
+
|
|
17
|
+
```yaml
|
|
18
|
+
languages:
|
|
19
|
+
json:
|
|
20
|
+
productionGlob: 'locales/**/*.json'
|
|
21
|
+
testCmd: 'pnpm test'
|
|
22
|
+
telemetry:
|
|
23
|
+
logPath: '.polydeukes/roi.log'
|
|
24
|
+
disciplines:
|
|
25
|
+
- id: 'locale-key-parity'
|
|
26
|
+
why: 'the ko and en locales must carry the same keys'
|
|
27
|
+
declare:
|
|
28
|
+
mechanism: 'pairing'
|
|
29
|
+
sources:
|
|
30
|
+
ko: { file: 'locales/ko.json' }
|
|
31
|
+
en: { file: 'locales/en.json' }
|
|
32
|
+
supply: { ko: 'error', en: 'error' }
|
|
33
|
+
scope: { source: 'target.path', include: ['^locales/(ko|en)\.json$'] }
|
|
34
|
+
extract:
|
|
35
|
+
koKeys:
|
|
36
|
+
- { op: 'source', of: 'ko' }
|
|
37
|
+
- { op: 'json' }
|
|
38
|
+
- { op: 'flattenKeys' }
|
|
39
|
+
enKeys:
|
|
40
|
+
- { op: 'source', of: 'en' }
|
|
41
|
+
- { op: 'json' }
|
|
42
|
+
- { op: 'flattenKeys' }
|
|
43
|
+
relate:
|
|
44
|
+
- id: 'parity'
|
|
45
|
+
relation: { op: 'equal', of: ['koKeys', 'enKeys'] }
|
|
46
|
+
messageBySide:
|
|
47
|
+
left: '{key} is in ko only'
|
|
48
|
+
right: '{key} is in en only'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`flattenKeys` extracts keys, not translation values. `equal` compares both directions and
|
|
52
|
+
`messageBySide` reports which file has an unmatched key. The default enforcement is `advise`.
|
|
53
|
+
Both source files must exist and contain valid JSON. The change-set surface reads them from the
|
|
54
|
+
chosen observation; a session edit uses that edit's proposed new contents for the file it changes.
|
|
55
|
+
|
|
56
|
+
From the example project's root, prepare matching tracked files. The commit below requires your
|
|
57
|
+
usual local git identity; it creates the baseline for the worktree comparison.
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
mkdir -p locales
|
|
61
|
+
printf '{"home":"Home"}\n' > locales/en.json
|
|
62
|
+
printf '{"home":"홈"}\n' > locales/ko.json
|
|
63
|
+
git add locales/en.json locales/ko.json
|
|
64
|
+
git commit -m 'docs: prepare locale example'
|
|
65
|
+
printf '{"home":"Home","settings":"Settings"}\n' > locales/en.json
|
|
66
|
+
git diff HEAD | pnpm exec pdks covenant check --diff
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Expect an `advised` diagnostic for `locale-key-parity` naming `settings` as present only in English.
|
|
70
|
+
The command still exits 0. Fix the mismatch and run the same observation again:
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
printf '{"home":"홈","settings":"설정"}\n' > locales/ko.json
|
|
74
|
+
git diff HEAD | pnpm exec pdks covenant check --diff
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The parity diagnostic should disappear. The values differ intentionally; the keys now match.
|
|
78
|
+
Restore the two example files to their committed baseline when finished:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
git restore -- locales/en.json locales/ko.json
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`git diff HEAD` reports changes against the last commit, so an untracked file needs `git add -N`
|
|
85
|
+
before it appears in the diff. This example commits a baseline to exercise modifications and make
|
|
86
|
+
cleanup predictable. A declaration does not run
|
|
87
|
+
merely because its source exists: at least one observed change must match its scope.
|
|
88
|
+
|
|
89
|
+
<a id="which-list"></a>
|
|
90
|
+
## Which list does it go in
|
|
91
|
+
|
|
92
|
+
There are three discipline lists, and the source axis decides which one an entry belongs to.
|
|
93
|
+
The mechanism does not decide it and the relation does not decide it: the same `companion`
|
|
94
|
+
mechanism sits in `disciplines` when it stands over `file` sources, and in
|
|
95
|
+
`changeSetDisciplines` when it stands over `changes`. Read the declaration's sources and the
|
|
96
|
+
list follows.
|
|
97
|
+
|
|
98
|
+
| The declaration reads | List | Examples |
|
|
99
|
+
|---|---|---|
|
|
100
|
+
| the changed file and `file` sources only | `disciplines` | the file-shaped types — added-only, one-way markers, self-absolution bans, controlled vocabulary, naming, companion over a `file` source, fingerprint sync, monotonic order |
|
|
101
|
+
| the transcript | `sessionDisciplines` | the four history types — precedent, phase order, turn locality, stated ground |
|
|
102
|
+
| the actor | `sessionDisciplines` | producer-owned, actor scope |
|
|
103
|
+
| the command line | `sessionDisciplines` | forbidden command |
|
|
104
|
+
| the spawn-record channel (`sidecar`) | `sessionDisciplines` | any declaration binding `{ sidecar: true }` |
|
|
105
|
+
| `changes` | `changeSetDisciplines` | pairing over a change set — `implies` between two paths that must move together |
|
|
106
|
+
|
|
107
|
+
Write the entry in the list its sources point at. A misplaced entry is a load-time error that
|
|
108
|
+
names the entry, the channels it reads, and the list it belongs in, so the fix is to move the
|
|
109
|
+
body unchanged. The rule itself and the error shapes are in [the configuration
|
|
110
|
+
reference](../reference/configuration/index.md#placement-rule).
|
|
111
|
+
|
|
112
|
+
An entry can also read nothing a surface has to supply and still be surface-bound in practice:
|
|
113
|
+
a valve (`witness`) that reads the transcript makes its entry a session entry, because the
|
|
114
|
+
valve's own `extract` binds the transcript.
|
|
115
|
+
|
|
116
|
+
<a id="posture"></a>
|
|
117
|
+
## Posture on an unattended real-time surface
|
|
118
|
+
|
|
119
|
+
An unattended real-time surface is an adapter hook or an SDK caller with no human at the
|
|
120
|
+
terminal. Two rules apply there that do not apply where a person is watching.
|
|
121
|
+
|
|
122
|
+
**Promote an entry to `enforce: block` when the loop cannot fix it inside the turn.** The
|
|
123
|
+
criterion is not "is this irreversible". A real-time block costs seconds: the model reads the
|
|
124
|
+
reason on stderr and retries, so the violation is corrected within the turn. Left at `advise`,
|
|
125
|
+
the same violation travels to a later check — a test run, CI, a reviewer — and costs a whole
|
|
126
|
+
turn, up to 45 minutes. This is not "block everything because nobody is watching": blocking
|
|
127
|
+
produces avoidance, and avoidance leaves no telemetry row, so an entry the loop cannot act on
|
|
128
|
+
belongs at `advise` where its break is at least recorded. The criterion is the config author's.
|
|
129
|
+
|
|
130
|
+
**The reason comes back as a value, because there is no valve.** A real-time unattended
|
|
131
|
+
surface has no witness valve: there is no TTY and no human turn, and the SDK takes no witness
|
|
132
|
+
argument and invents no session. What stands in its place is the reason travelling as data.
|
|
133
|
+
`checkCovenant` returns `{ verdict: 'blocked', reason }` where `reason` is the judge's own
|
|
134
|
+
stderr, and `{ verdict: 'upheld', advisories }` carries the advisory lines of an exit-0 run.
|
|
135
|
+
The consumer writes that text where a person reads it later — an issue, a log — and stops.
|
|
136
|
+
Whether the model sees the advisory text is the consumer's decision too: an unattended loop has
|
|
137
|
+
no reader for a stderr line, so advise is only consumed if the caller passes it on. The
|
|
138
|
+
[`@polydeukes/sdk-ts` reference](../reference/packages/sdk-ts.md) has the verdict shapes.
|
|
139
|
+
|
|
140
|
+
The SDK's own default is `enforce: 'block'` for the run, which is the surface's level, not an
|
|
141
|
+
entry's: protected paths and `enforce: block` entries stop the call, and every other break is
|
|
142
|
+
recorded as `advised`. Both adapters spawn the judge the same way.
|
|
143
|
+
|
|
144
|
+
<a id="when-to-draft"></a>
|
|
145
|
+
## When to draft instead of declaring
|
|
146
|
+
|
|
147
|
+
If the promise is real but the grammar cannot express it yet, write a draft.
|
|
148
|
+
|
|
149
|
+
```yaml
|
|
150
|
+
languages:
|
|
151
|
+
json:
|
|
152
|
+
productionGlob: 'locales/**/*.json'
|
|
153
|
+
testCmd: 'pnpm test'
|
|
154
|
+
disciplines:
|
|
155
|
+
- id: 'benchmark-supports-performance-claim'
|
|
156
|
+
why: 'a performance claim must be supported by a fresh benchmark run during judgment.'
|
|
157
|
+
draft: true
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Use `draft: true` only for a promise the current engine cannot judge. A draft does not produce a
|
|
161
|
+
verdict or telemetry. It is still part of the config, so the file remains loadable.
|
|
162
|
+
|
|
163
|
+
<a id="proof-runs"></a>
|
|
164
|
+
## Verify both outcomes
|
|
165
|
+
|
|
166
|
+
After you save the config, run the judgment path that can actually see it.
|
|
167
|
+
|
|
168
|
+
- `git diff HEAD | pdks covenant check --diff` shows the same entry against the current tree.
|
|
169
|
+
- `pdks explain` shows the registration and whether it is a declare or a draft.
|
|
170
|
+
- A one-sided edit to `locales/en.json` or `locales/ko.json` is a good smoke test for the pairing
|
|
171
|
+
example.
|
|
172
|
+
|
|
173
|
+
If no judgment appears, first check the observation: is the file included rather than ignored,
|
|
174
|
+
did it change in the selected comparison, does the scope match, and can the surface supply the
|
|
175
|
+
evidence? Inspect
|
|
176
|
+
`pdks explain` and the telemetry log for `config-fault`, `no-observation`, or `supply-pass`.
|
|
177
|
+
Do not treat a missing diagnostic as proof that the declaration works.
|
|
178
|
+
|
|
179
|
+
The draft above is deliberately different from key pairing. The current engine does not run a
|
|
180
|
+
new benchmark during judgment. It can compare supplied evidence, but that is not the same promise.
|
|
181
|
+
See [declarations and their limits](../concepts/judgment.md#declarations).
|