polydeukes 0.6.1 → 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 +14 -28
- package/README.md +14 -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 +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 +8 -8
- package/dist/docs/README.md +8 -8
- package/dist/docs/catalog.json +44 -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 +39 -34
- package/dist/docs/how-to/connect-surfaces.md +36 -33
- package/dist/docs/how-to/write-disciplines.ko.md +61 -6
- package/dist/docs/how-to/write-disciplines.md +62 -6
- package/dist/docs/index.json +607 -373
- 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 +14 -9
- package/dist/docs/reference/cli/explain.md +15 -10
- package/dist/docs/reference/cli/init.ko.md +52 -52
- package/dist/docs/reference/cli/init.md +43 -55
- package/dist/docs/reference/configuration/index.ko.md +171 -66
- package/dist/docs/reference/configuration/index.md +178 -71
- package/dist/docs/reference/packages/adapter-claude-code.ko.md +38 -11
- package/dist/docs/reference/packages/adapter-claude-code.md +38 -14
- 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 +49 -3
- package/dist/docs/reference/packages/core.md +54 -5
- package/dist/docs/reference/packages/polydeukes.ko.md +138 -77
- package/dist/docs/reference/packages/polydeukes.md +146 -81
- 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 +17 -15
- package/dist/docs/troubleshooting.md +18 -14
- package/dist/docs/tutorials/first-judgment.ko.md +2 -2
- package/dist/docs/tutorials/first-judgment.md +2 -2
- 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/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
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
# `@polydeukes/adapter-git`
|
|
2
|
-
|
|
3
|
-
**English** · [한국어](adapter-git.ko.md)
|
|
4
|
-
|
|
5
|
-
> **The commit surface's translator** — a staged diff becomes the covenant input IR, and
|
|
6
|
-
> the `adapters.git` config namespace is defined here.
|
|
7
|
-
>
|
|
8
|
-
> Alpha. A transitive dependency of the umbrella: you do not install it and you do not
|
|
9
|
-
> import it. The commit surface reaches it through
|
|
10
|
-
> [`pdks covenant check`](polydeukes.md#polydeukes-bin).
|
|
11
|
-
|
|
12
|
-
<a id="ownership"></a>
|
|
13
|
-
## What this package owns
|
|
14
|
-
|
|
15
|
-
The boundary where git's vocabulary is translated away. A staged diff becomes the same
|
|
16
|
-
agent-neutral input IR the session surface produces — the same judgment for every hand,
|
|
17
|
-
AI or human.
|
|
18
|
-
|
|
19
|
-
| Unit | What it does |
|
|
20
|
-
|---|---|
|
|
21
|
-
| Staged-change collection | Reads the staging area into a list of changes with their content baselines |
|
|
22
|
-
| Pure translation | Folds those changes into one `CovenantInput` |
|
|
23
|
-
| Settings vocabulary | Validates this adapter's own config namespace |
|
|
24
|
-
|
|
25
|
-
This is a pure library. It knows the staged-diff shape and nothing about installation, hook
|
|
26
|
-
runners, or valves — wiring it into a pre-commit hook is a deployment act that lives in the
|
|
27
|
-
umbrella. It names `@polydeukes/core` as a `peerDependency`: the vocabulary is shared with
|
|
28
|
-
the judge, not installed a second time here.
|
|
29
|
-
|
|
30
|
-
<a id="collection"></a>
|
|
31
|
-
## Collection and the `adapters.git` namespace
|
|
32
|
-
|
|
33
|
-
**Three collectors, one shape.** `collectStagedChanges`, `collectWorktreeChanges`, and
|
|
34
|
-
`collectRangeChanges({ repoRoot, range: '<base>..<head>' | '<base>...<head>' })` each return the
|
|
35
|
-
same
|
|
36
|
-
`StagedChange[]`, so the translator and everything after it is one path.
|
|
37
|
-
|
|
38
|
-
| Collector | `pre` | `post` | Also |
|
|
39
|
-
|---|---|---|---|
|
|
40
|
-
| staged | HEAD blob | The **staged** blob — never the worktree, which may have diverged after `git add` | |
|
|
41
|
-
| worktree | HEAD blob | The bytes on disk | Untracked, non-ignored files join as `added`; a file missing from disk is `deleted`, whether HEAD held it or only the index did; an unreadable path (a dangling symlink) yields null content and is judged on its path |
|
|
42
|
-
| range | base blob | head blob | `...` resolves the base to `git merge-base`; a ref git cannot resolve, or two refs with no merge-base, throws |
|
|
43
|
-
|
|
44
|
-
**Collection is deliberately narrow about what it trusts.**
|
|
45
|
-
|
|
46
|
-
| Decision | Why |
|
|
47
|
-
|---|---|
|
|
48
|
-
| `--no-renames` forced on, in every collector | A rename is judged as a deletion plus an addition. A `git mv` of a protected file must not slip through as one opaque rename entry |
|
|
49
|
-
| A binary blob or file yields null content | Rather than lossily decoded bytes |
|
|
50
|
-
| The unborn first commit narrows to all-added | Rather than throwing — staged and worktree alike |
|
|
51
|
-
| A type change (`T`) keeps its `pre` side | A symlink replaced by a file is a modification, so a delta judgment still sees what was removed |
|
|
52
|
-
| Every listing ends with `--` | A branch that shares its name with a file is a ref, never an ambiguous argument |
|
|
53
|
-
|
|
54
|
-
Translation produces one tool call per change, under the adapter-owned names `staged-write`
|
|
55
|
-
and `staged-delete`. A deletion always carries its evidence. A write carries it unless the
|
|
56
|
-
staged blob was binary — there is no text to compare, so the call arrives with no
|
|
57
|
-
`fileChange` at all and is judged on its path alone, the same as any unproven call.
|
|
58
|
-
**The session collections are honestly empty** — the commit surface has no session, and a
|
|
59
|
-
key is never fabricated to look like one. There is no `actor` either: the hook cannot tell a
|
|
60
|
-
human's `git commit` from an agent's, so it proves none.
|
|
61
|
-
|
|
62
|
-
**The namespace is this adapter's own vocabulary.** The core validates only the container
|
|
63
|
-
shape — one settings object per adapter — and passes the contents through verbatim, so the
|
|
64
|
-
vocabulary, its validator, and its defaults all live here.
|
|
65
|
-
|
|
66
|
-
| Key | Values | Default | Means |
|
|
67
|
-
|---|---|---|---|
|
|
68
|
-
| `adapters.git.enforce` | `block` \| `advise` | `block` | What a commit-surface verdict *does* |
|
|
69
|
-
| `adapters.git.protectedPaths` | string[] | `[]` | The commit surface's **additive** protection scope, judged on top of the common list |
|
|
70
|
-
|
|
71
|
-
An unknown key, an `enforce` outside the two values, or a `protectedPaths` that is not an
|
|
72
|
-
array of strings each fail fast with the full field path. The writing reference is
|
|
73
|
-
[the configuration reference's `adapters` section](../configuration/index.md#adapters).
|
|
74
|
-
|
|
75
|
-
**The additive scope is additive for a reason.** The level belongs to the observer, and so
|
|
76
|
-
does the scope: entries listed here are judged when work becomes history, and the session
|
|
77
|
-
surface never reads them. That is what lets a repository leave judge *sources* editable in
|
|
78
|
-
a session while still stopping the commit that promotes them.
|
|
79
|
-
|
|
80
|
-
Under `enforce: advise` the valve is structurally absent: a verdict is recorded as
|
|
81
|
-
`advised`, one advisory line lands on stderr, and the commit proceeds. The response to a violation
|
|
82
|
-
changes, not the judgment criteria: a run that cannot judge still fails closed at exit `2` at either
|
|
83
|
-
level.
|
|
84
|
-
|
|
85
|
-
<a id="consumer-contract"></a>
|
|
86
|
-
## Where the consumer touches it
|
|
87
|
-
|
|
88
|
-
- **The `adapters.git` block** in your config.
|
|
89
|
-
- **The pre-commit hook** that runs `pdks covenant check`, wired by hand — the manual
|
|
90
|
-
procedure for three hook managers is in
|
|
91
|
-
[installation](../../how-to/connect-surfaces.md#commit-surface).
|
|
92
|
-
|
|
93
|
-
No import.
|
|
94
|
-
|
|
95
|
-
<a id="limits"></a>
|
|
96
|
-
## Declared limits
|
|
97
|
-
|
|
98
|
-
- **A declaration that reads the session cannot be judged here.** A `precedent` needs
|
|
99
|
-
session history and a commit has none. The entry records `skipped` with `supply-pass`
|
|
100
|
-
only when its own `supply` is `pass`; with no policy the missing session is unjudgeable
|
|
101
|
-
(exit 2). A permanent condition of this surface, not a fault in the entry.
|
|
102
|
-
- **Untracked ignored files are invisible here; already-tracked files are not.** `.gitignore`
|
|
103
|
-
does not hide a path git already tracks. A built `dist` that was never added stays
|
|
104
|
-
invisible; a tracked file that later matches an ignore line still appears in `git diff`.
|
|
105
|
-
That is why the session surface carries generated paths on the common list instead.
|
|
106
|
-
- **The valve needs a human at a terminal.** No TTY means no prompt and no way through: a
|
|
107
|
-
CI run and an agent-spawned `git commit` reach the same closed door. Nothing is ever
|
|
108
|
-
persisted, so one answer never covers a later commit.
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
# `@polydeukes/covenant`
|
|
2
|
-
|
|
3
|
-
[English](covenant.md) · **한국어**
|
|
4
|
-
|
|
5
|
-
> **판정기**입니다. 디스패처와 규율(discipline) 라이브러리, 메타 약속(covenant), TTL 증인
|
|
6
|
-
> 밸브가 여기 있습니다.
|
|
7
|
-
>
|
|
8
|
-
> 알파입니다. 일반 사용자는 통합 패키지를 통해 설치하며 직접 불러올 필요가 없습니다.
|
|
9
|
-
> 설정의 `disciplines:` 블록과 `.polydeukes/roi.log`의 기록을 통해 동작을 확인합니다.
|
|
10
|
-
|
|
11
|
-
<a id="ownership"></a>
|
|
12
|
-
## 담당하는 기능
|
|
13
|
-
|
|
14
|
-
**판정 기능을 별도로 사용할 때 설치하는 패키지입니다.** 통합 패키지의 표면 없이 판정 기능만 연결하려면 이 패키지와 `@polydeukes/core`를 함께 제공합니다.
|
|
15
|
-
core가 여기서 `peerDependency`라서 어휘가
|
|
16
|
-
복제되지 않고 공유됩니다. 일반 사용자에게는 통합 패키지가 이 의존성을 제공합니다.
|
|
17
|
-
|
|
18
|
-
선언된 약속(covenant)을 평가해 판정 결과를 내는 기능을 모두 이 패키지에서 구현합니다.
|
|
19
|
-
|
|
20
|
-
| 단위 | 하는 일 |
|
|
21
|
-
|---|---|
|
|
22
|
-
| `runCovenant` 래퍼 | 판정 본체를 실행하고, 비차단 `1`을 차단하는 `2`로 번역하고, 모든 호출을 기록합니다. 측정되지 않고 실행되는 약속은 없습니다 |
|
|
23
|
-
| 경로 라우팅 디스패처 | 보호 경로에 약속을 등록하고 일치하는 항목을 **모두** 실행합니다. 하나가 실패했다고 뒤의 판정을 생략하지 않습니다 |
|
|
24
|
-
| 메타 약속 | 판정 사슬 자신을 지키는 등록 셋 |
|
|
25
|
-
| TTL 증인 | 유효 시간이 있는 인간의 증인 밸브입니다. 차단 판정 뒤에만 확인합니다 |
|
|
26
|
-
| 델타 층 | 파일의 전후 쌍에 대한 신규 위반 전용 판정 |
|
|
27
|
-
| 규율(discipline) 라이브러리 | 설정의 `disciplines:` 항목을 별도 사용자 코드 없이 판정합니다 |
|
|
28
|
-
|
|
29
|
-
<a id="disciplines-and-meta-covenants"></a>
|
|
30
|
-
## 규율 계열과 메타 약속
|
|
31
|
-
|
|
32
|
-
**`disciplines:` 항목은 선언 하나입니다.** 관측한 증거를 입력으로 받아 `judge = relate ∘ extract`를 계산합니다. 선언의 소스가 무엇을 묶는지가
|
|
33
|
-
판정에 필요한 증거를 정하고, 그것이 곧 어느 표면에서
|
|
34
|
-
판정될 수 있는지를 정합니다.
|
|
35
|
-
|
|
36
|
-
| 소스 | 판정 대상 | 필요한 증거 |
|
|
37
|
-
|---|---|---|
|
|
38
|
-
| 고정 이름 `target.path` · `pre` · `post` · `state` · `changes` | 변경 자체 | 파일 변경 |
|
|
39
|
-
| 고정 이름 `command` | 셸 호출의 명령줄 | 셸 호출입니다. Edit에는 없습니다 |
|
|
40
|
-
| `{ transcript: true }` | 세션 이력입니다. 이 호출 **앞에** 자격을 갖춘 호출이 실제로 실행됐는가 | 세션 |
|
|
41
|
-
| `{ file: … }` · `{ sidecar: true }` | 다른 파일, 또는 스폰 기록 채널 | 표면의 리더 |
|
|
42
|
-
|
|
43
|
-
이 항목들을 쓰는 가이드는 [설정 레퍼런스의 `disciplines` 절](../configuration/index.ko.md#disciplines)에
|
|
44
|
-
있습니다. 선언 문법은 코어의 `algebra-declaration.schema.json`입니다.
|
|
45
|
-
|
|
46
|
-
**메타 약속 셋**이 판정 사슬을 지킵니다. 다른 약속과 똑같은 약속이고, 아래 어휘가 그대로
|
|
47
|
-
적용됩니다.
|
|
48
|
-
|
|
49
|
-
| 등록 | 축 | 판정 대상 |
|
|
50
|
-
|---|---|---|
|
|
51
|
-
| self-mod | 도구 | 편집 도구를 통한 보호 경로 변형입니다. 호출의 증명된 변형 대상만 대조하므로, 편집 **내용** 안의 보호 경로는 언급이고 통과합니다 |
|
|
52
|
-
| shell-mod | 셸 | 같은 것을 명령줄로 합니다. 보호 경로를 언급하는 명령은 첫 낱말이 읽기 전용임을 증명할 때만 통과합니다 |
|
|
53
|
-
| transcript-mod | 대화 기록 | 라이브 세션 대화 기록에 대한 쓰기입니다. 전체 경로 **등가**로 판정하고 보호 조상으로는 결코 보지 않습니다 |
|
|
54
|
-
|
|
55
|
-
**낱말 여섯**이 텔레메트리 계약입니다. 판정 결과 다섯과 관측 하나입니다. `.polydeukes/roi.log`의
|
|
56
|
-
한 행은 이 중 정확히 하나를 담고, CLI와 문서와 테스트가 같은 사건에 같은 낱말을 씁니다.
|
|
57
|
-
행을 읽는 법은 [문제 해결](../../troubleshooting.ko.md#reading-verdict)에 있습니다.
|
|
58
|
-
|
|
59
|
-
| 판정 결과 | 뜻 |
|
|
60
|
-
|---|---|
|
|
61
|
-
| `passed` | 호출이 판정됐고 약속을 지켰습니다 |
|
|
62
|
-
| `blocked` | 호출이 판정됐고 약속을 깼습니다 |
|
|
63
|
-
| `witnessed` | **차단된** 작업을 인간의 증언으로 허용했습니다. 위반이 없었다는 뜻이 아니며 허용 사실을 기록합니다 |
|
|
64
|
-
| `advised` | 호출을 멈추지 않고 위반을 기록했습니다. 두 표면 모두에서 규율 항목의 기본 처분이고, `adapters.git.enforce: advise`인 커밋 표면의 결과이기도 합니다 |
|
|
65
|
-
| `skipped` | 적용 범위가 일치했지만 판정할 수 없었습니다. **정상 판정이 아니라** 판정하지 못했다는 기록입니다 |
|
|
66
|
-
| `unattributed` | 보호 항목의 디스크 상태가 변했는데 그것을 설명하는 판정 기록이 없습니다. **판정이 아닙니다.** 이 행 때문에 차단되거나 통과하는 호출은 없으며, 세션 표면이 저장된 기준선과 상태를 대조한 뒤에 기록합니다 |
|
|
67
|
-
|
|
68
|
-
`unattributed`는 나머지 다섯이 답할 수 없는 물음에 답합니다. 다섯은 전부 판정기가 건네받은
|
|
69
|
-
호출에 관해 쓰는 낱말이라, 선언된 호출 없이 도착한 쓰기는 행을 하나도 남기지 않습니다.
|
|
70
|
-
인터프리터 안의 쓰기, 테스트 러너 자식 프로세스의 쓰기, 대상 경로를 자기 인자에서 조립하는
|
|
71
|
-
스크립트가 그런 경우입니다. 상태 대조는 철자가 아니라 결과를 관측하므로 그 쓰기를 사후에
|
|
72
|
-
기록합니다. 차단하지는 않습니다. 이미 일어난 쓰기이고, 대조는 판정의 양쪽 모두에서
|
|
73
|
-
fail-open입니다.
|
|
74
|
-
|
|
75
|
-
<a id="consumer-contract"></a>
|
|
76
|
-
## 사용자와의 접점
|
|
77
|
-
|
|
78
|
-
- **설정의 `disciplines:` 블록.** 항목 하나가 등록 하나로 컴파일되고 자기 텔레메트리
|
|
79
|
-
라벨을 답니다.
|
|
80
|
-
- **`protectedPaths`.** 경로 라우팅 디스패처가 여기에 대조합니다.
|
|
81
|
-
- **`witness` 블록.** TTL 증인 밸브를 설정합니다.
|
|
82
|
-
- **`.polydeukes/roi.log`.** 판정 기록을 추가하는 로그입니다.
|
|
83
|
-
|
|
84
|
-
일반 사용자가 직접 불러올 필요는 없습니다. 통합 패키지가 두 표면에 필요한 구성을 조립합니다.
|
|
85
|
-
|
|
86
|
-
<a id="limits"></a>
|
|
87
|
-
## 선언된 한계
|
|
88
|
-
|
|
89
|
-
- **셸 축은 `skipped` 행을 남기고, 그 행이 계약입니다.** 셸 명령의 대상을 텍스트에서
|
|
90
|
-
예측하는 일은 결정 불가능합니다. 그래서 이 축이 지키는 불변식은 "아무것도 빠져나가지
|
|
91
|
-
못한다"가 아니라 **기록 없이 통과하는 호출이 없다**입니다. 새로운 명령 형태가 `skipped`로 기록되면 판정하지 못한 한계를 확인할 수 있습니다. 행이 아예 없는
|
|
92
|
-
통과, 또는
|
|
93
|
-
판정하지 않고 `passed`로 기록된 통과가 결함입니다.
|
|
94
|
-
- **세션을 읽는 선언은 세션 없이 판정할 수 없습니다.** 커밋 표면에는 세션이 없습니다. 적용 범위가 일치한
|
|
95
|
-
`precedent`(그리고 대화 기록을 읽는 다른) 선언이 사유 `supply-pass`로 `skipped`를 남기는
|
|
96
|
-
것은 그 선언의 `supply`가 `pass`일 때뿐입니다. 정책이 없으면 없는 세션은 판정 불가(exit
|
|
97
|
-
2)로 처리하며 자동으로 건너뛰지 않습니다. 이 표면에서 세션 증거가 없다는 조건은 변하지 않습니다.
|
|
98
|
-
- **`command`를 적용 범위의 소스로 쓰는 선언은 커밋 표면에서 실행되지 않으며 기록도 남기지
|
|
99
|
-
않습니다.** 스테이징한 변경에는 명령줄이 없으므로 그 선언의 관측 대상이 되지 않습니다.
|
|
100
|
-
`.polydeukes/roi.log`에 아무것도 남지 않아서, 발동한 적 없는 명령 규율과 명령을 관측한 적
|
|
101
|
-
없는 표면의 규율을 로그로 가를 수 없습니다.
|
|
102
|
-
- **컴파일러가 해석하지 못하는 선언은 스킵 등록으로 컴파일됩니다.** 라우팅은 그대로 두고
|
|
103
|
-
본체를 두지 않습니다. 등재 표 밖의 단계, 단계의 키 밖의 인자, 컴파일되지 않는 패턴,
|
|
104
|
-
쌍/단일 불일치가 그 경우입니다. 그래서 조립은 예외를 던지지 않습니다. 해소되지 않는 항목
|
|
105
|
-
하나가 형제 항목과 메타 약속과 밸브까지 무너뜨리면, 그것을 일으킨 설정을 고칠 길이
|
|
106
|
-
사라지기 때문입니다. 예약 기전, 또는 카탈로그가 거부하는 축·관계는 다른 단계입니다.
|
|
107
|
-
`loadConfig`가 파일을 거부하고(exit 2) skip 행은 남지 않습니다. 판정 시점에 세계에 없는
|
|
108
|
-
소스는 세 번째 경우입니다. 선언 자신의 `supply` 정책이 처분하고, 정책이 없으면 본체가
|
|
109
|
-
판정 불가(exit 2)로 답합니다. 통과로 답하지 않습니다.
|
|
110
|
-
- **완전 봉쇄는 목표가 아닙니다.** 여기에 차단 목록은 없습니다. 우회 철자를 열거하는 일은
|
|
111
|
-
언제나 한 걸음 뒤지므로 논리를 뒤집었습니다. 보호 경로를 언급하면 안전이 증명되지 않는
|
|
112
|
-
한 차단합니다. 간접 경로 계산 같은 잔여 벡터는 차단 대상이 아니라 텔레메트리 대상입니다.
|
|
113
|
-
마찰 밸브 둘, 곧 읽기 전용 허용 목록과 TTL 증인은 둘 다 측정 가능한 흔적을 남깁니다.
|
|
114
|
-
- **밸브는 판정 뒤에 확인합니다.** 실제로 차단한 판정만 증언으로 열 수 있고, 문장 중간의 토큰
|
|
115
|
-
언급은 밸브를 무장시키지 않으며, AI는 자기 밸브를 결코 스스로 열 수 없습니다.
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
# `@polydeukes/covenant`
|
|
2
|
-
|
|
3
|
-
**English** · [한국어](covenant.ko.md)
|
|
4
|
-
|
|
5
|
-
> **The judge** — the dispatcher, the discipline library, the meta-covenants, and the TTL
|
|
6
|
-
> witness valve.
|
|
7
|
-
>
|
|
8
|
-
> Alpha. A transitive dependency of the umbrella: you do not install it and you do not
|
|
9
|
-
> import it. What you reach is its behaviour, through the `disciplines:` block in your config
|
|
10
|
-
> and the rows it writes to `.polydeukes/roi.log`.
|
|
11
|
-
|
|
12
|
-
<a id="ownership"></a>
|
|
13
|
-
## What this package owns
|
|
14
|
-
|
|
15
|
-
The judge. Everything that turns a declared promise into a verdict lives here.
|
|
16
|
-
|
|
17
|
-
**This is the install unit for judgment.** An embedder that wants verdicts without the
|
|
18
|
-
umbrella's surfaces installs this package and provides `@polydeukes/core` alongside it — core
|
|
19
|
-
is a `peerDependency` here, so the vocabulary is shared rather than duplicated. The umbrella
|
|
20
|
-
is what satisfies that peer for an ordinary consumer.
|
|
21
|
-
|
|
22
|
-
| Unit | What it does |
|
|
23
|
-
|---|---|
|
|
24
|
-
| `runCovenant` wrapper | Runs a judge body, translates its non-blocking `1` into the blocking `2`, and logs every call. No covenant runs unmeasured |
|
|
25
|
-
| Path-routing dispatcher | Registers covenants against protected paths and runs *every* matching one — no short-circuit, so the telemetry never under-counts |
|
|
26
|
-
| Meta-covenants | Three registrations that protect the judging chain itself |
|
|
27
|
-
| TTL witness | The time-boxed human valve, consulted only after a verdict blocked |
|
|
28
|
-
| Delta layer | New-violation-only judgment over a file's before/after pair |
|
|
29
|
-
| Discipline library | Config `disciplines:` entries become enforcement without a line of code |
|
|
30
|
-
|
|
31
|
-
<a id="disciplines-and-meta-covenants"></a>
|
|
32
|
-
## Discipline families and meta-covenants
|
|
33
|
-
|
|
34
|
-
**A `disciplines:` entry is one declaration** — `judge = relate ∘ extract` over the
|
|
35
|
-
observation as a world. What the declaration's sources bind decides what evidence the
|
|
36
|
-
judgment needs, which is also what decides whether it can be judged on a given surface.
|
|
37
|
-
|
|
38
|
-
| Sources | Judges | Evidence needed |
|
|
39
|
-
|---|---|---|
|
|
40
|
-
| the fixed names `target.path` · `pre` · `post` · `state` · `changes` | The change itself | A file change |
|
|
41
|
-
| the fixed name `command` | The shell call's command line | A shell call — an Edit carries none |
|
|
42
|
-
| `{ transcript: true }` | Session history — was a qualifying call actually executed *before* this one | A session |
|
|
43
|
-
| `{ file: … }` · `{ sidecar: true }` | Another file, or the spawn-record channel | The surface's reader for it |
|
|
44
|
-
|
|
45
|
-
The writing guide for these entries is [the configuration reference's `disciplines`
|
|
46
|
-
section](../configuration/index.md#disciplines); the declaration grammar is the core's
|
|
47
|
-
`algebra-declaration.schema.json`.
|
|
48
|
-
|
|
49
|
-
**Three meta-covenants** protect the judging chain. They are covenants like any other; the
|
|
50
|
-
vocabulary below applies to them unchanged.
|
|
51
|
-
|
|
52
|
-
| Registration | Axis | Judges |
|
|
53
|
-
|---|---|---|
|
|
54
|
-
| self-mod | Tool | Mutations to protected paths through editing tools. Only the call's proven mutation target is compared — a protected path inside an edit's *content* is a mention and passes |
|
|
55
|
-
| shell-mod | Shell | The same, through a command line. A command mentioning a protected path passes only if its leading word proves it read-only |
|
|
56
|
-
| transcript-mod | Transcript | Writes to the live session transcript, judged by whole-path **equality** — never as a protected ancestor |
|
|
57
|
-
|
|
58
|
-
**Six words** are the telemetry contract — five verdicts and one observation. A row in
|
|
59
|
-
`.polydeukes/roi.log` carries exactly one of them, and the CLI, the docs, and the tests use
|
|
60
|
-
the same word for the same event. How to read a row is in
|
|
61
|
-
[troubleshooting](../../troubleshooting.md#reading-a-verdict).
|
|
62
|
-
|
|
63
|
-
| Verdict | Means |
|
|
64
|
-
|---|---|
|
|
65
|
-
| `passed` | The call was judged and upheld the covenant |
|
|
66
|
-
| `blocked` | The call was judged and broke it |
|
|
67
|
-
| `witnessed` | A **blocked** verdict a human opened in person. Never silent, never a clean call |
|
|
68
|
-
| `advised` | A break recorded without stopping the call — the default for every discipline entry on both surfaces, and the commit surface's outcome under `adapters.git.enforce: advise` |
|
|
69
|
-
| `skipped` | The call reached a registration that could not judge it. **Not a pass** — the recorded absence of a judgment |
|
|
70
|
-
| `unattributed` | A protected entry's on-disk state moved and no judgment row explains it. **Not a verdict** — no call is blocked or passed by it; the session surface writes it after comparing state against a stored baseline |
|
|
71
|
-
|
|
72
|
-
`unattributed` answers a question the other five cannot. They are all written by a judge
|
|
73
|
-
about a call it was handed, so a write that arrives without a declared call — through an
|
|
74
|
-
interpreter, a test runner's child process, a script that assembles the path from its own
|
|
75
|
-
arguments — leaves no row at all. The comparison observes the result rather than the
|
|
76
|
-
spelling, so it records that write after the fact. It never blocks: the write already
|
|
77
|
-
happened, and the comparison fails open on both sides of the verdict.
|
|
78
|
-
|
|
79
|
-
<a id="consumer-contract"></a>
|
|
80
|
-
## Where the consumer touches it
|
|
81
|
-
|
|
82
|
-
- **The `disciplines:` block** in your config. One entry compiles into one registration,
|
|
83
|
-
carrying its own telemetry label.
|
|
84
|
-
- **`protectedPaths`**, which the path-routing dispatcher matches against.
|
|
85
|
-
- **The `witness` block**, which arms the TTL valve.
|
|
86
|
-
- **`.polydeukes/roi.log`**, where every judgment lands as one row.
|
|
87
|
-
|
|
88
|
-
No import. The umbrella assembles this package for both surfaces.
|
|
89
|
-
|
|
90
|
-
<a id="limits"></a>
|
|
91
|
-
## Declared limits
|
|
92
|
-
|
|
93
|
-
- **The shell axis leaves `skipped` rows, and that row is the contract.** Predicting a
|
|
94
|
-
shell command's target from its text is undecidable, so the invariant this axis holds is
|
|
95
|
-
not "nothing gets through" — it is that **no call passes unrecorded**. A new spelling
|
|
96
|
-
landing in `skipped` is the declared limit showing itself. A pass with no row at all, or
|
|
97
|
-
one recorded `passed` without a judgment, is the defect class.
|
|
98
|
-
- **A declaration that reads the session cannot be judged without one.** On the commit
|
|
99
|
-
surface there is none. A matching `precedent` (or any other transcript-reading)
|
|
100
|
-
declaration records `skipped` with the reason `supply-pass` only when that declaration's
|
|
101
|
-
own `supply` is `pass`. With no policy the missing session is unjudgeable (exit 2), not
|
|
102
|
-
an automatic skip. That skip-with-pass is a permanent condition of that surface.
|
|
103
|
-
- **A declaration scoped on `command` is absent from the commit surface, and absent without
|
|
104
|
-
a row.** A staged diff carries no command line, so no world such a declaration observes is
|
|
105
|
-
admitted there. This leaves nothing in `.polydeukes/roi.log`, so the log cannot separate a
|
|
106
|
-
command discipline that never triggered from one whose surface never observed a command.
|
|
107
|
-
- **A declaration the compiler cannot resolve compiles to a skip registration** — routing
|
|
108
|
-
intact, no body: a step outside the registry, an argument outside a step's keys, a pattern
|
|
109
|
-
that does not compile, a paired/single mismatch. Assembly therefore never throws: one
|
|
110
|
-
unresolvable entry cannot take down its siblings, the meta-covenants, and the valve, which
|
|
111
|
-
would leave no way to fix the config that caused it. A reserved mechanism, or one whose
|
|
112
|
-
axes and relations the catalogue refuses, is a different stage: `loadConfig` rejects the
|
|
113
|
-
file (exit 2), and no skip row is written. A source the world lacks at judgment time is a
|
|
114
|
-
third case — the declaration's own `supply` policy disposes of it, and with no policy the
|
|
115
|
-
body answers unjudgeable (exit 2), never upheld.
|
|
116
|
-
- **Complete containment is a non-goal.** There are no blocklists here — enumerating bypass
|
|
117
|
-
spellings is always one step behind, so the logic is inverted: a mention of a protected
|
|
118
|
-
path blocks unless proven safe. Residual vectors such as indirect path computation are
|
|
119
|
-
telemetry targets, not block targets. The two friction valves — the read-only allowlist
|
|
120
|
-
and the TTL witness — both leave a measurable trace.
|
|
121
|
-
- **The valve stands after the verdict.** Only a judgment that actually blocked can be
|
|
122
|
-
witnessed open, a mid-sentence mention of the token does not arm it, and an AI can never
|
|
123
|
-
open the valve for itself.
|
package/dist/index.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Polydeukes — a development discipline framework for building alongside an AI
|
|
3
|
-
* coding partner.
|
|
4
|
-
*
|
|
5
|
-
* Pre-alpha. This package reserves the unscoped `polydeukes` name and is the umbrella /
|
|
6
|
-
* `pdks` CLI entry point. It owns the config discovery loader and both surfaces'
|
|
7
|
-
* composition roots — `runCovenantCheck` for the commit surface and `runClaudeCodeHook`
|
|
8
|
-
* for the session one — because assembly needs an adapter and the covenant package at
|
|
9
|
-
* once, which no sibling is allowed to depend on. The covenant, ledger, memory, and verify
|
|
10
|
-
* modules live in their own `@polydeukes/*` packages.
|
|
11
|
-
*
|
|
12
|
-
* This file is a barrel and nothing more. ESM re-exports are eager, so anything defined
|
|
13
|
-
* here would be instantiated by every consumer of any other export. Keep definitions in
|
|
14
|
-
* their own modules and let importers reach them directly. A session call enters through
|
|
15
|
-
* the published `./claude-code` subpath instead, which keeps the commit surface and its git
|
|
16
|
-
* adapter off that load path.
|
|
17
|
-
*
|
|
18
|
-
* See https://github.com/huskyhoochu/polydeukes
|
|
19
|
-
*/
|
|
20
|
-
export type { ResolvedConfig } from '@polydeukes/core';
|
|
21
|
-
export { type CheckDomain, type CovenantCheckOutcome, type CovenantCheckSpec, runCovenantCheck, } from './covenant-check.ts';
|
|
22
|
-
export { type LoadConfigSpec, type LoadedConfig, loadConfig } from './load-config.ts';
|
package/dist/index.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Polydeukes — a development discipline framework for building alongside an AI
|
|
3
|
-
* coding partner.
|
|
4
|
-
*
|
|
5
|
-
* Pre-alpha. This package reserves the unscoped `polydeukes` name and is the umbrella /
|
|
6
|
-
* `pdks` CLI entry point. It owns the config discovery loader and both surfaces'
|
|
7
|
-
* composition roots — `runCovenantCheck` for the commit surface and `runClaudeCodeHook`
|
|
8
|
-
* for the session one — because assembly needs an adapter and the covenant package at
|
|
9
|
-
* once, which no sibling is allowed to depend on. The covenant, ledger, memory, and verify
|
|
10
|
-
* modules live in their own `@polydeukes/*` packages.
|
|
11
|
-
*
|
|
12
|
-
* This file is a barrel and nothing more. ESM re-exports are eager, so anything defined
|
|
13
|
-
* here would be instantiated by every consumer of any other export. Keep definitions in
|
|
14
|
-
* their own modules and let importers reach them directly. A session call enters through
|
|
15
|
-
* the published `./claude-code` subpath instead, which keeps the commit surface and its git
|
|
16
|
-
* adapter off that load path.
|
|
17
|
-
*
|
|
18
|
-
* See https://github.com/huskyhoochu/polydeukes
|
|
19
|
-
*/
|
|
20
|
-
export { runCovenantCheck, } from './covenant-check.js';
|
|
21
|
-
export { loadConfig } from './load-config.js';
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `initClaudeCode` — the session-surface installer.
|
|
3
|
-
*
|
|
4
|
-
* One command wires a project into the session surface: prove the package resolves, run the
|
|
5
|
-
* shared project-side scaffold ({@link scaffoldProject}), then add what this distribution
|
|
6
|
-
* path owns — the delegator hook file, its `.claude/settings.json` registration, the
|
|
7
|
-
* discipline file that tells an agent the docs query exists, and the classification skill
|
|
8
|
-
* that turns a described problem into a config entry.
|
|
9
|
-
*
|
|
10
|
-
* Preflight comes first and nothing is written before it clears. A generated hook whose
|
|
11
|
-
* import can never resolve blocks every call through its own fail-closed catch, and a tree
|
|
12
|
-
* that also has no config and no valve to open cannot be edited back into shape from inside
|
|
13
|
-
* the session.
|
|
14
|
-
*
|
|
15
|
-
* Nothing existing is overwritten. The settings file in particular is merged, never
|
|
16
|
-
* replaced: a consumer's other PreToolUse registrations and permissions are live
|
|
17
|
-
* configuration, and replacing them would disarm every other tool they wired. A grok JSON
|
|
18
|
-
* whose command still names the grok mjs is rewritten to this hook's command so the two
|
|
19
|
-
* installers do not leave two spawn strings.
|
|
20
|
-
*/
|
|
21
|
-
import { type ScaffoldReport } from './scaffold-project.ts';
|
|
22
|
-
/**
|
|
23
|
-
* The generated classification skill — the procedure that turns a described problem into a
|
|
24
|
-
* registered entry. A classification procedure an agent never learns about is one that never
|
|
25
|
-
* runs, so it ships as an artifact of the install rather than as prose in a README.
|
|
26
|
-
*
|
|
27
|
-
* Its advise-consumption section is the delivery path for advised rows: the session surface
|
|
28
|
-
* lets an advised call through with exit 0, and the reason never reaches the model at call
|
|
29
|
-
* time — reading the telemetry log at task boundaries is the only way it arrives.
|
|
30
|
-
*/
|
|
31
|
-
export declare const GENERATED_SKILL = "---\nname: discipline-draft\ndescription: Turn a described discipline problem into a registered entry in polydeukes.config \u2014 a judged entry when the declaration grammar and observed evidence can express it, a draft entry otherwise. Use when the user describes a recurring problem they want promised away (\"I keep...\", \"stop X from happening\", \"we should never...\", \"how do I enforce Y\").\n---\n\n# discipline-draft \u2014 from a problem description to a registered discipline\n\nThis project is judged by Polydeukes. A discipline starts as prose and climbs a ladder \u2014\n`draft` (registered, read, never judged) \u2192 `advise` (judged, recorded, never stops a call) \u2192\n`block` (stops the call; the user's explicit choice, never the default). This skill walks a\nproblem description down to the right first rung and registers it.\n\n## Procedure\n\n### 1. Restate the problem as a promise\n\nRewrite the description as one sentence of the form \"X must not happen\" or \"when A happens,\nB must also happen\". If the sentence needs \"unless\" more than once, split it into two\npromises and classify each separately.\n\n### 2. Classify the shape\n\nChoose from the current catalogue, then check whether the intended surface can supply the\nrequired evidence. A mechanism name constrains the declaration; it does not implement the\npromise by itself. The extracted axes and body relations must be subsets of the admitted\nsets below. Scope filtering is separate from the extracted axes.\n\n| Mechanism | Admitted axes | Body relations | Evidence or structural condition |\n| --- | --- | --- | --- |\n| `pairing` | `world` | `equal` | Compare supplied files or channels; extract keys when values may differ. |\n| `companion` | `change`, `world` | `implies` | Compare presence by key; a multi-file promise needs the observed change set. |\n| `monotonic-order` | `change`, `world` | `ordered` | Extract a sequence with an explicit comparison field; order is not presence. |\n| `fingerprint-sync` | `world` | `equal` | Compare supplied stamps; no generator or compiler runs during judgment. |\n| `producer-owned` | `actor` | `empty`, `nonEmpty` | Requires host-provided actor evidence, not an artifact's self-reported producer. |\n| `self-absolution-ban` | `change` | `unchanged`, `empty` | Extract protected fields or path changes; choose creation/deletion supply explicitly. |\n| `actor-scope` | `actor` | `empty`, `nonEmpty` | Requires a proven actor; a missing actor is not proof of the main session. |\n| `precedent` | `history`, `world` | `nonEmpty` | Requires an observed earlier call in a transcript or supplied channel. |\n| `phase-order` | `history` | `ordered` | Compare observed call ordinals; missing phases need a separate presence promise. |\n| `turn-locality` | `history` | `nonEmpty` | Requires observed turns and time or ordinal boundaries. |\n| `stated-ground` | `history` | `nonEmpty` | Can require recorded text, not establish whether its reasoning is sound. |\n| `controlled-vocabulary` | `change`, `world` | `subset` | Extract values and an explicit allowed set. |\n| `naming` | `change` | `empty`, `nonEmpty` | Scope must read `target.path`; match the intended name pattern. |\n| `added-only` | `change` | `empty` | Compare pre/post extractions and judge only newly added matches. |\n| `one-way-marker` | `change` | `subset` | Existing markers must remain in the extracted post-change set. |\n| `delegated-scope` | \u2014 | \u2014 | Reserved for a definition-time evaluator; not accepted in current declarations. |\n| `scoped-valve` | `change`, `actor`, `world`, `history` | `empty`, `nonEmpty`, `equal`, `subset`, `implies`, `ordered`, `unchanged` | Requires a `witness` block expressing the exception condition. |\n| `forbidden-command` | `change` | `empty` | Scope must read `command`; a text pattern is not shell semantic analysis. |\n\nThese four requests illustrate the classification boundary:\n\n| Request | Classification | Proof |\n| --- | --- | --- |\n| The English and Korean locale files must carry identical keys. | `pairing`, with two supplied files. | An unmatched key breaks; translated values may differ. |\n| Every status must belong to an allowed list. | `controlled-vocabulary`, with a supplied allowed set. | An unknown status breaks; an allowed status passes. |\n| A successful package lookup must precede a manifest edit. | `precedent`, with observed session history. | Failed or absent lookups break; an unavailable transcript is a supply case. |\n| A fresh benchmark must execute during judgment to prove a performance claim. | `draft`: the engine does not execute benchmarks. | Comparing an existing report would be a different promise. |\n\nRun `pdks docs show write-disciplines` for the key-pairing walkthrough and\n`pdks docs show configuration --section disciplines` for the declaration grammar.\nUse `--lang ko` for Korean; these commands read the installed version offline.\n\nAn `added-only` declaration forgives existing occurrences \u2014 only what the edit adds breaks\nthe promise. That is usually what you want: a discipline adopted today should not indict\nyesterday's code.\n\nOne path-shaped promise takes no `disciplines:` entry at all: a path nobody may touch\nbelongs in the top-level `protectedPaths:` list \u2014 its own config block, never an entry key.\n\n### 3. Check the observation boundary\n\nDo not confuse an expressible relation with available evidence:\n\n- **Files outside the repository** \u2014 file-change protection observes the project root.\n Use the host's permission policy for comprehensive protection outside it. A command-text\n pattern may recognize a particular string, but does not observe all resulting writes.\n- **Writes by child processes** \u2014 arbitrary writes inside a test runner or script are not\n individually observed by the session surface. A commit comparison can observe the resulting\n files when they enter its selected diff; it does not recover the originating tool history.\n- **Missing history or actor channels** \u2014 choose the declaration's supply policy explicitly.\n Commit observations have no session transcript; `supply: pass` records a skip, not success.\n- **Fresh execution or semantic proof** \u2014 the engine compares supplied evidence. It does not\n run a new benchmark or prove that a written explanation is true. Preserve that unmet promise\n as a draft rather than silently replacing it with a weaker text check.\n\n### 4a. Expressible now \u2014 register a judged entry\n\nAdd the entry to the `disciplines:` array in `polydeukes.config.yaml`. Advise is the default\nlanding \u2014 a break is recorded as `advised` and the call goes on \u2014 and the `enforce: advise`\nline below only spells that default out. NEVER write `enforce: block` from this skill:\npromotion to block is the user's own choice, made after the advise measurements have been\nread.\n\nThe examples below are whole documents, so `languages:` \u2014 the schema's one required block \u2014\nappears alongside the entry; in a config that already has one, copy the entry only.\n\n```yaml\nlanguages:\n placeholder:\n productionGlob: 'src/**'\n testCmd: 'echo \"set a verification command for {scope}\"'\ndisciplines:\n - id: 'no-focused-tests'\n why: 'a committed .only silently shrinks the suite to one test'\n declare:\n mechanism: 'added-only'\n scope: { source: 'target.path', include: ['^src/'] }\n supply: { pre: 'empty', post: 'empty' }\n extract:\n before:\n - { op: 'source', of: 'pre' }\n - { op: 'lines' }\n - { op: 'keyByPattern', re: '(\\.only\\()' }\n after:\n - { op: 'source', of: 'post' }\n - { op: 'lines' }\n - { op: 'keyByPattern', re: '(\\.only\\()' }\n added:\n - { op: 'onlyIn', of: 'after', notIn: 'before' }\n relate:\n - id: 'nothing-added'\n relation: { op: 'empty', of: 'added' }\n message: 'adds {key}: {value}'\n enforce: advise\n```\n\nA command-line ban reads the fixed source `command` and scopes on it \u2014 the scope is part of\nthe mechanism's shape, so a `forbidden-command` entry without it is refused at load time:\n\n```yaml\nlanguages:\n placeholder:\n productionGlob: 'src/**'\n testCmd: 'echo \"set a verification command for {scope}\"'\ndisciplines:\n - id: 'no-force-push'\n why: 'a force push rewrites history nobody reviewed'\n declare:\n mechanism: 'forbidden-command'\n scope: { source: 'command' }\n extract:\n hits:\n - { op: 'source', of: 'command' }\n - { op: 'lines' }\n - { op: 'matches', re: 'git push\\b.*--force(?![\\w-])' }\n relate:\n - { id: 'no-force', relation: { op: 'empty', of: 'hits' }, message: '{value}' }\n enforce: advise\n```\n\nThe following examples implement the first three classification cases. Both locale files and\nthe allowed-status file must exist and contain valid JSON. File bindings use the proposed\ncontents for a file changed by the current observation, not a second stale disk read.\n\n```yaml\nlanguages:\n json:\n productionGlob: 'locales/**/*.json'\n testCmd: 'pnpm test'\ndisciplines:\n - id: 'locale-key-parity'\n why: 'the ko and en locales must carry the same keys'\n declare:\n mechanism: 'pairing'\n scope: { source: 'target.path', include: ['^locales/(ko|en)[.]json$'] }\n sources:\n ko: { file: 'locales/ko.json' }\n en: { file: 'locales/en.json' }\n supply: { ko: 'error', en: 'error' }\n extract:\n koKeys: [{ op: 'source', of: 'ko' }, { op: 'json' }, { op: 'flattenKeys' }]\n enKeys: [{ op: 'source', of: 'en' }, { op: 'json' }, { op: 'flattenKeys' }]\n relate:\n - id: 'parity'\n relation: { op: 'equal', of: ['koKeys', 'enKeys'] }\n messageBySide:\n left: '{key} is in ko only'\n right: '{key} is in en only'\n enforce: advise\n```\n\n```yaml\nlanguages:\n json:\n productionGlob: '*.json'\n testCmd: 'pnpm test'\ndisciplines:\n - id: 'status-vocabulary'\n why: 'statuses.json may contain only values listed in allowed-statuses.json'\n declare:\n mechanism: 'controlled-vocabulary'\n scope: { source: 'target.path', include: ['^statuses[.]json$'] }\n sources: { allowed: { file: 'allowed-statuses.json' } }\n supply: { post: 'error', allowed: 'error' }\n extract:\n selected: [{ op: 'source', of: 'post' }, { op: 'json' }, { op: 'items' }]\n permitted: [{ op: 'source', of: 'allowed' }, { op: 'json' }, { op: 'items' }]\n relate:\n - id: 'allowed-status'\n relation: { op: 'subset', of: 'selected', in: 'permitted' }\n message: 'unknown status: {value}'\n enforce: advise\n```\n\nHere both status files are JSON arrays of strings. This declaration scopes on statuses.json;\nediting only the allowed list does not trigger it. Broaden the observation deliberately if\nchanges to that list must recheck all dependent files.\n\n```yaml\nlanguages:\n typescript:\n productionGlob: 'src/**'\n testCmd: 'pnpm test'\ndisciplines:\n - id: 'manifest-needs-npm-view'\n why: 'a successful package lookup must precede a manifest edit'\n declare:\n mechanism: 'precedent'\n scope: { source: 'target.path', include: ['^(packages/[^/]+/)?package[.]json$'] }\n sources: { session: { transcript: true } }\n supply: { session: 'pass' }\n extract:\n npmView:\n - { op: 'source', of: 'session' }\n - { op: 'toolUses', names: ['Bash'] }\n - { op: 'filter', when: [{ field: 'succeeded', eq: true }] }\n - { op: 'select', path: 'args.command' }\n - { op: 'matches', re: '^npm view ' }\n relate:\n - id: 'npm-view'\n relation: { op: 'nonEmpty', of: 'npmView' }\n message: 'no successful npm view precedes this edit'\n enforce: advise\n```\n\nThe precedent example proves only that an observed successful Bash call starts with npm view;\nit does not prove that the lookup concerns the dependency being edited. The commit surface has\nno transcript and therefore skips this example by its explicit supply policy.\n\n**Write the regex yourself \u2014 the user states the promise, you author the pattern.** The\npattern is the part users find hardest, so never hand the prose back and ask for one. Three\nauthoring traps, each measured on a live config:\n\n- **A pattern answers a syntactic question only.** \"Is this string a forbidden word\" is\n syntax; \"is this a new dependency version\" is meaning, and a regex leaks both ways on a\n semantic question. When the question is semantic, narrow the declaration's own `scope`\n block to the files where any match IS a break, or accept \"editing this file at all\" as\n the trigger.\n- **`^` means what the preceding step left.** After a `lines` step a declaration's\n pattern sees one line at a time, so `^` anchors to that line; over an unsplit source it\n anchors to the whole text and matches the first line only. A ban over the command line\n puts `lines` before its `matches` for exactly that reason.\n- **Author both directions.** Before registering, write down one string the pattern must\n match and one nearby string it must not (`only(` vs `only_helper(`, a flag vs its\n substring). A pattern checked in only the breaking direction over-fires in review-proof\n ways.\n\n### 4b. Not expressible yet \u2014 register a draft\n\nA draft is prose with a handle: `id`, `why`, and the literal marker `draft: true` \u2014 no other\nkeys. It produces no judgment and no telemetry; `pdks explain` lists it as unpromoted.\nRecord the intended promise and the exact missing capability inside `why`. Do not classify\npairing, vocabulary, or history promises as drafts merely because they are absent from a short\nexample list. Check the catalogue, extraction steps, and observation channel first. A reserved\n`delegated-scope` declaration cannot be registered as a judged entry.\n\n```yaml\nlanguages:\n placeholder:\n productionGlob: 'src/**'\n testCmd: 'echo \"set a verification command for {scope}\"'\ndisciplines:\n - id: 'benchmark-supports-performance-claim'\n why: 'a performance claim needs a fresh benchmark run during judgment; the engine cannot execute it'\n draft: true\n```\n\n### 5. Prove it fires, then close\n\nRun `pdks explain` and confirm the new entry is listed (a judged entry with its mechanism\nand surfaces; a draft as unpromoted).\n\nFor a judged entry, registration is not the finish \u2014 a pattern that never fires protects\nnothing while looking installed. Fire it once for real, with the proof run the declaration's\nown mechanism can actually reach:\n\n| Mechanism | Break it once | The entry's id shows up in |\n| --- | --- | --- |\n| a file-reading one (`added-only`, `naming`, \u2026) | one scratch edit matching the must-match direction | `pdks covenant check --worktree` output \u2014 the exit stays 0 at advise, the id is the proof |\n| `forbidden-command` | run one harmless command matching the pattern | the telemetry log tail \u2014 at advise the call proceeds and its row records the id |\n| `precedent` | one in-scope edit made without the required precedent | the telemetry log tail \u2014 a declaration reading the session judges on the session surface only (the commit surface has none, so its `supply` policy records it `skipped`) |\n\nThen undo the scratch break, repeat the same observation, and confirm a passing row for the\nmust-NOT-match case. Silence alone may mean a scope miss, unchanged files, or unavailable evidence;\ncheck `pdks explain` and telemetry for `config-fault`, `no-observation`, or `supply-pass`. Close by telling the user which rung the entry landed on and\nthat `enforce: block` is theirs to add later if the advise record earns it.\n\n## Updating this skill without losing local edits\n\nAn upgrade does not overwrite an existing skill; rerunning `pdks init claude-code` reports it\nskipped. Generate a fresh copy in a disposable project using the installed package, compare it\nwith this file, and merge the changes you want. Keep a backup of local additions. Do not delete\nthe existing skill to force regeneration in the working project.\n\n## Reading the advise record\n\nAn `advised` row means a promise was broken and the call went through anyway. Rows land in\nthe telemetry log at the path configured by `telemetry.logPath` (default\n`.polydeukes/roi.log`). The hook's stderr note is not shown to you, so consult the log at\ntask boundaries: before committing, or after a batch of edits, read the tail and act on any\n`advised` row \u2014 fix the break, or tell the user why it should stand. An advisory nobody\nreads measures nothing.\n";
|
|
32
|
-
/** `initClaudeCode` input — the target tree and the preflight seam. */
|
|
33
|
-
export type InitClaudeCodeSpec = {
|
|
34
|
-
/** Project root to install into — every write below is relative to it. */
|
|
35
|
-
projectRoot: string;
|
|
36
|
-
/**
|
|
37
|
-
* Preflight seam: throws when the package cannot be resolved from the given root.
|
|
38
|
-
* ABSENT uses the real resolution, anchored at that root and nowhere else — anchoring it
|
|
39
|
-
* at the installer's own module would answer for the installer's install graph rather
|
|
40
|
-
* than the target project's, which is precisely the case that must fail.
|
|
41
|
-
*/
|
|
42
|
-
resolvePolydeukes?: (projectRoot: string) => void;
|
|
43
|
-
};
|
|
44
|
-
/**
|
|
45
|
-
* Install the session surface into `spec.projectRoot`, skipping whatever is already there
|
|
46
|
-
* and reporting both halves per artifact.
|
|
47
|
-
*
|
|
48
|
-
* Throws before any write when the package cannot be resolved from that root or when two
|
|
49
|
-
* config spellings already coexist there — both leave zero files. Translating a throw into
|
|
50
|
-
* exit 2 with the install command is the bin's job.
|
|
51
|
-
*/
|
|
52
|
-
export declare function initClaudeCode(spec: InitClaudeCodeSpec): ScaffoldReport;
|