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
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
# Installing Polydeukes
|
|
2
|
-
|
|
3
|
-
**English** · [한국어](./installation.ko.md)
|
|
4
|
-
|
|
5
|
-
> Alpha. This guide covers the install paths that ship today, and everything here is the
|
|
6
|
-
> measured behaviour of the published packages.
|
|
7
|
-
|
|
8
|
-
This is the getting-started layer: from an empty project to a first judged call.
|
|
9
|
-
|
|
10
|
-
One devDependency, one command per surface. The umbrella package `polydeukes` is the only
|
|
11
|
-
thing you install — it carries the core, the judge, and the adapters as its own
|
|
12
|
-
dependencies, and `pdks` is its CLI (an alias of `polydeukes`).
|
|
13
|
-
|
|
14
|
-
**Two surfaces ship, for two different situations — pick the one that matches how the
|
|
15
|
-
project is developed.** A project built alongside an AI partner in Claude Code wires the
|
|
16
|
-
**session surface**: a PreToolUse hook that judges every editing tool call and shell
|
|
17
|
-
command as it is declared. A project you develop yourself wires the **commit surface**: a
|
|
18
|
-
pre-commit hook that judges the staged diff, so the discipline you declared for yourself
|
|
19
|
-
is applied at the moment work becomes history. They enforce the same config vocabulary,
|
|
20
|
-
but they answer different situations — there is no general reason to wire both in one
|
|
21
|
-
project.
|
|
22
|
-
|
|
23
|
-
## Prerequisites
|
|
24
|
-
|
|
25
|
-
- **Node.js ≥ 24** — the engines floor of every published package.
|
|
26
|
-
- **A package manager** — pnpm and npm both work; examples below use pnpm.
|
|
27
|
-
- **Claude Code** — only for the session surface. The commit surface needs no AI tool at
|
|
28
|
-
all: just git and a way to run a pre-commit hook.
|
|
29
|
-
|
|
30
|
-
## Install
|
|
31
|
-
|
|
32
|
-
```sh
|
|
33
|
-
pnpm add -D polydeukes
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
(or `npm install --save-dev polydeukes`.)
|
|
37
|
-
|
|
38
|
-
This must be a real project dependency, not a one-off `npx` run — both surfaces load the
|
|
39
|
-
judge from your project's own installed package.
|
|
40
|
-
|
|
41
|
-
## The session surface — developing with an AI partner
|
|
42
|
-
|
|
43
|
-
From the project root:
|
|
44
|
-
|
|
45
|
-
```sh
|
|
46
|
-
pnpm exec pdks init claude-code # Claude Code
|
|
47
|
-
pnpm exec pdks init grok # Grok
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
The command installs into the directory it is invoked from, and it proves the `polydeukes`
|
|
51
|
-
package resolves there **before writing anything** — if it does not (say, the install step
|
|
52
|
-
was skipped), it prints the install command and exits 2 with zero files written, never a
|
|
53
|
-
half-wired tree.
|
|
54
|
-
|
|
55
|
-
Nothing existing is overwritten. What exists is reported and kept — the hook, the config,
|
|
56
|
-
and the discipline files are left alone, the settings file is merged, and `.gitignore` is
|
|
57
|
-
only ever appended to — so re-running is always safe. One command-field exception: if
|
|
58
|
-
`.grok/hooks/covenant-pretooluse.json` still names the grok delegator and a Claude
|
|
59
|
-
delegator is on disk, the JSON `command` is rewritten to that Claude file so the host
|
|
60
|
-
does not spawn two judges. Grok collapses two registrations only when `command` AND
|
|
61
|
-
`matcher` are identical, so every grok entry naming that Claude file also takes the matcher
|
|
62
|
-
of the `.claude/settings.json` entry that registers the same command — on a fresh write and
|
|
63
|
-
on every re-run; `timeout` stays. A command you pointed elsewhere is left as it was.
|
|
64
|
-
|
|
65
|
-
`pdks init claude-code` writes six artifacts:
|
|
66
|
-
|
|
67
|
-
| Artifact | What it is |
|
|
68
|
-
|---|---|
|
|
69
|
-
| `.claude/hooks/covenant-pretooluse.mjs` | The hook — a thin delegator that loads the judge from the installed package. Upgrading the package upgrades the judge; this file never changes. |
|
|
70
|
-
| `.claude/settings.json` | The PreToolUse registration for editing tools and shell calls. **Merged, never replaced** — your other hooks and permissions stay. |
|
|
71
|
-
| `polydeukes.config.yaml` | The starter protection policy: a placeholder `languages` block, a minimum `protectedPaths` list, and the witness block. The comments in the file explain why each entry is there. |
|
|
72
|
-
| `.claude/rules/polydeukes.md` | A scoped discipline file telling your AI partner that `pdks docs` exists and which topic answers what. It carries `paths` frontmatter, so it loads when a Polydeukes path is in play rather than sitting in every session's context. |
|
|
73
|
-
| `.claude/skills/discipline-draft/SKILL.md` | The classification procedure. Describe a recurring problem to your AI partner and it lands as a config entry — judged at advise when a current family can express it, a `draft: true` entry otherwise — and the same file tells the agent to consult `advised` rows in the telemetry log at task boundaries. |
|
|
74
|
-
| `.gitignore` | An appended ignore rule for `.polydeukes/`, with its comment line — telemetry is local observation data and never belongs in history. |
|
|
75
|
-
|
|
76
|
-
`pdks init grok` shares the scaffold (config and the ignore line) and writes Grok's own
|
|
77
|
-
registration. A Grok-only tree has four artifacts, and no `.claude/` directory:
|
|
78
|
-
|
|
79
|
-
| Artifact | What it is |
|
|
80
|
-
|---|---|
|
|
81
|
-
| `.grok/hooks/covenant-pretooluse.mjs` | The hook — the same delegator text, only when no Claude delegator is already on disk. |
|
|
82
|
-
| `.grok/hooks/covenant-pretooluse.json` | The PreToolUse matcher, `timeout` 60 (the host default is 5 seconds, and a timed-out hook fails open), and the command that names one delegator file. In a tree that also has `.claude/settings.json`, the matcher is copied from the settings entry with the same command — Grok reads that file too, and collapses the two registrations into one spawn only when `command` and `matcher` match exactly. That copy leans on Grok's tool-name aliases, so if you later remove `.claude/settings.json`, delete this JSON and run `pdks init grok` again to get the Grok-native matcher back. |
|
|
83
|
-
| `polydeukes.config.yaml` | The same starter policy as above. |
|
|
84
|
-
| `.gitignore` | The same appended ignore line. |
|
|
85
|
-
|
|
86
|
-
If `.claude/hooks/covenant-pretooluse.mjs` already exists, the JSON command points at that
|
|
87
|
-
file instead of planting a second one. A later `pdks init grok` or `pdks init claude-code`
|
|
88
|
-
retargets an installer-generated grok-mjs command the same way.
|
|
89
|
-
|
|
90
|
-
An already-open Grok session keeps the hook snapshot from start. Reload from the Hooks tab
|
|
91
|
-
(`r`) or start a new session. The witness valve does not open on Grok — the session log is
|
|
92
|
-
ACP `updates.jsonl`, not Claude's JSONL. A block is recovered from another terminal or the
|
|
93
|
-
commit-surface TTY.
|
|
94
|
-
|
|
95
|
-
## First edit — `languages`
|
|
96
|
-
|
|
97
|
-
The generated config ships a placeholder language profile, because the installer cannot
|
|
98
|
-
know your stack:
|
|
99
|
-
|
|
100
|
-
```yaml
|
|
101
|
-
languages:
|
|
102
|
-
placeholder:
|
|
103
|
-
productionGlob: 'src/**'
|
|
104
|
-
testCmd: 'echo "set a verification command for {scope}"'
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
Rename the key to your language, point `productionGlob` at your production sources, and put
|
|
108
|
-
your real verification command in `testCmd`. (On the commit-surface path you write this
|
|
109
|
-
block yourself as part of the config below.) The placeholder is valid as generated and no
|
|
110
|
-
judgment path reads these values yet, so it cannot produce a wrong verdict while it waits —
|
|
111
|
-
but `languages` is the schema's one required block, so *removing* it (or emptying it) makes
|
|
112
|
-
the config invalid, and an invalid config blocks every call. Edit it, don't delete it.
|
|
113
|
-
|
|
114
|
-
## The commit surface — developing by yourself
|
|
115
|
-
|
|
116
|
-
This path is for applying your own discipline to your own commits — no AI tool involved.
|
|
117
|
-
It has no installer today; the wiring is two small manual steps.
|
|
118
|
-
|
|
119
|
-
**First, the config.** Create `polydeukes.config.yaml` at the project root (there is no
|
|
120
|
-
generator on this path — the file is yours from the first line):
|
|
121
|
-
|
|
122
|
-
```yaml
|
|
123
|
-
languages:
|
|
124
|
-
typescript:
|
|
125
|
-
productionGlob: 'src/**'
|
|
126
|
-
testCmd: 'pnpm test'
|
|
127
|
-
|
|
128
|
-
# Judged at commit time: a staged change to these paths stops the commit
|
|
129
|
-
# until you answer the witness prompt in person.
|
|
130
|
-
protectedPaths:
|
|
131
|
-
- 'db/migrations'
|
|
132
|
-
|
|
133
|
-
witness:
|
|
134
|
-
token: 'pdks witness'
|
|
135
|
-
ttlMinutes: 10
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
Add `.polydeukes/` to your `.gitignore` too — telemetry is local observation data.
|
|
139
|
-
|
|
140
|
-
**Then, the hook.** One command judges what is currently staged and exits 2 on a broken
|
|
141
|
-
covenant:
|
|
142
|
-
|
|
143
|
-
```sh
|
|
144
|
-
pnpm exec pdks covenant check
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
Register it as a pre-commit hook. With **lefthook**:
|
|
148
|
-
|
|
149
|
-
```yaml
|
|
150
|
-
# lefthook.yml
|
|
151
|
-
pre-commit:
|
|
152
|
-
commands:
|
|
153
|
-
covenant:
|
|
154
|
-
priority: 1
|
|
155
|
-
interactive: true # keep the witness prompt visible — see below
|
|
156
|
-
run: ./node_modules/.bin/pdks covenant check
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
With **husky**:
|
|
160
|
-
|
|
161
|
-
```sh
|
|
162
|
-
# .husky/pre-commit
|
|
163
|
-
./node_modules/.bin/pdks covenant check
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
With plain **`.git/hooks`** (make it executable):
|
|
167
|
-
|
|
168
|
-
```sh
|
|
169
|
-
#!/bin/sh
|
|
170
|
-
# .git/hooks/pre-commit
|
|
171
|
-
./node_modules/.bin/pdks covenant check
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
Three things to know about this surface:
|
|
175
|
-
|
|
176
|
-
- **The valve is a TTY prompt.** At the default `block` level, a commit that stages a
|
|
177
|
-
protected change stops at a prompt only a human at a terminal can answer. Configure your
|
|
178
|
-
hook runner so it does not swallow that prompt (lefthook needs `interactive: true`).
|
|
179
|
-
- **Declarations judge here.** A staged diff carries file changes and nothing else, so
|
|
180
|
-
protection lists and every `declare` entry over the change judge in full. A declaration
|
|
181
|
-
scoped on `command` has no command line to read in a staged diff and observes nothing on
|
|
182
|
-
this surface, and a declaration that reads the session (`precedent` and the other history
|
|
183
|
-
mechanisms) is recorded as `skipped` — declare those where an AI partner's session exists
|
|
184
|
-
to be judged.
|
|
185
|
-
- **The commit surface has its own additive scope.** Paths that are fine to edit freely
|
|
186
|
-
but whose promotion into history deserves a judged checkpoint go under the adapter
|
|
187
|
-
namespace, judged on top of the shared list:
|
|
188
|
-
|
|
189
|
-
```yaml
|
|
190
|
-
adapters:
|
|
191
|
-
git:
|
|
192
|
-
protectedPaths:
|
|
193
|
-
- 'src/policy'
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
## The witness valve
|
|
197
|
-
|
|
198
|
-
Both surfaces carry the same valve, spelled for their situation. It sits **after** the
|
|
199
|
-
verdict — only a judgment that actually blocked can be witnessed open — and every allowance
|
|
200
|
-
is recorded as `witnessed`, never silent.
|
|
201
|
-
|
|
202
|
-
```yaml
|
|
203
|
-
witness:
|
|
204
|
-
token: 'pdks witness'
|
|
205
|
-
ttlMinutes: 10
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
- **Session surface:** a human types the token so it stands alone on the first line of a
|
|
209
|
-
conversation message; the window holds for `ttlMinutes`, then blocking resumes. An agent
|
|
210
|
-
cannot open the valve for itself — only human-authored messages count.
|
|
211
|
-
- **Commit surface:** the blocked commit shows a TTY prompt, and typing the full token
|
|
212
|
-
there opens that one commit.
|
|
213
|
-
|
|
214
|
-
Change the token and window as you like — the token is not a secret; the defence is
|
|
215
|
-
provenance, not confidentiality. **Keep the block**: on the session surface the generated
|
|
216
|
-
protection list covers `.claude/hooks` and `.grok/hooks`, so without a valve the first
|
|
217
|
-
blocked call would freeze the project until a human edits the config from their own
|
|
218
|
-
terminal.
|
|
219
|
-
|
|
220
|
-
## Prove the gate is live
|
|
221
|
-
|
|
222
|
-
Prove it once on the surface you wired, then read the telemetry.
|
|
223
|
-
|
|
224
|
-
- **Session surface:** ask your agent to append a line to
|
|
225
|
-
`.claude/hooks/covenant-pretooluse.mjs` (a protected path). The call must come back
|
|
226
|
-
blocked.
|
|
227
|
-
- **Commit surface:** stage an edit to a path on your protection list and run
|
|
228
|
-
`git commit`. It must stop at the witness prompt (answer it, or abort with Ctrl-C).
|
|
229
|
-
|
|
230
|
-
```sh
|
|
231
|
-
cat .polydeukes/roi.log
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
Every judgment appends exactly one record — `passed`, `blocked`, `witnessed`, `advised`, or
|
|
235
|
-
`skipped` — so the block you just caused is the last line. A gate you have watched block
|
|
236
|
-
once is a gate you know is wired.
|
|
237
|
-
|
|
238
|
-
From here: [the configuration guide](./configuration.md) for the file and its wiring,
|
|
239
|
-
[the configuration reference](./reference/configuration.md) for every field and for
|
|
240
|
-
writing your own disciplines, and [troubleshooting](./troubleshooting.md) when something
|
|
241
|
-
blocks and you don't know why.
|
|
@@ -1,100 +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#pdks-covenant-check).
|
|
11
|
-
|
|
12
|
-
## What this package owns
|
|
13
|
-
|
|
14
|
-
The boundary where git's vocabulary is translated away. A staged diff becomes the same
|
|
15
|
-
agent-neutral input IR the session surface produces — the same judgment for every hand,
|
|
16
|
-
AI or human.
|
|
17
|
-
|
|
18
|
-
| Unit | What it does |
|
|
19
|
-
|---|---|
|
|
20
|
-
| Staged-change collection | Reads the staging area into a list of changes with their content baselines |
|
|
21
|
-
| Pure translation | Folds those changes into one `CovenantInput` |
|
|
22
|
-
| Settings vocabulary | Validates this adapter's own config namespace |
|
|
23
|
-
|
|
24
|
-
This is a pure library. It knows the staged-diff shape and nothing about installation, hook
|
|
25
|
-
runners, or valves — wiring it into a pre-commit hook is a deployment act that lives in the
|
|
26
|
-
umbrella. It names `@polydeukes/core` as a `peerDependency`: the vocabulary is shared with
|
|
27
|
-
the judge, not installed a second time here.
|
|
28
|
-
|
|
29
|
-
## Collection and the `adapters.git` namespace
|
|
30
|
-
|
|
31
|
-
**Three collectors, one shape.** `collectStagedChanges`, `collectWorktreeChanges`, and
|
|
32
|
-
`collectRangeChanges({ repoRoot, range: '<base>..<head>' | '<base>...<head>' })` each return the same
|
|
33
|
-
`StagedChange[]`, so the translator and everything after it is one path.
|
|
34
|
-
|
|
35
|
-
| Collector | `pre` | `post` | Also |
|
|
36
|
-
|---|---|---|---|
|
|
37
|
-
| staged | HEAD blob | The **staged** blob — never the worktree, which may have diverged after `git add` | |
|
|
38
|
-
| 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 |
|
|
39
|
-
| 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 |
|
|
40
|
-
|
|
41
|
-
**Collection is deliberately narrow about what it trusts.**
|
|
42
|
-
|
|
43
|
-
| Decision | Why |
|
|
44
|
-
|---|---|
|
|
45
|
-
| `--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 |
|
|
46
|
-
| A binary blob or file yields null content | Rather than lossily decoded bytes |
|
|
47
|
-
| The unborn first commit narrows to all-added | Rather than throwing — staged and worktree alike |
|
|
48
|
-
| 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 |
|
|
49
|
-
| Every listing ends with `--` | A branch that shares its name with a file is a ref, never an ambiguous argument |
|
|
50
|
-
|
|
51
|
-
Translation produces one tool call per change, under the adapter-owned names `staged-write`
|
|
52
|
-
and `staged-delete`. A deletion always carries its evidence. A write carries it unless the
|
|
53
|
-
staged blob was binary — there is no text to compare, so the call arrives with no
|
|
54
|
-
`fileChange` at all and is judged on its path alone, the same as any unproven call.
|
|
55
|
-
**The session collections are honestly empty** — the commit surface has no session, and a
|
|
56
|
-
key is never fabricated to look like one. There is no `actor` either: the hook cannot tell a
|
|
57
|
-
human's `git commit` from an agent's, so it proves none.
|
|
58
|
-
|
|
59
|
-
**The namespace is this adapter's own vocabulary.** The core validates only the container
|
|
60
|
-
shape — one settings object per adapter — and passes the contents through verbatim, so the
|
|
61
|
-
vocabulary, its validator, and its defaults all live here.
|
|
62
|
-
|
|
63
|
-
| Key | Values | Default | Means |
|
|
64
|
-
|---|---|---|---|
|
|
65
|
-
| `adapters.git.enforce` | `block` \| `advise` | `block` | What a commit-surface verdict *does* |
|
|
66
|
-
| `adapters.git.protectedPaths` | string[] | `[]` | The commit surface's **additive** protection scope, judged on top of the common list |
|
|
67
|
-
|
|
68
|
-
An unknown key, an `enforce` outside the two values, or a `protectedPaths` that is not an
|
|
69
|
-
array of strings each fail fast with the full field path. The writing reference is
|
|
70
|
-
[the configuration reference's `adapters` section](./configuration.md#adapters).
|
|
71
|
-
|
|
72
|
-
**The additive scope is additive for a reason.** The level belongs to the observer, and so
|
|
73
|
-
does the scope: entries listed here are judged when work becomes history, and the session
|
|
74
|
-
surface never reads them. That is what lets a repository leave judge *sources* editable in
|
|
75
|
-
a session while still stopping the commit that promotes them.
|
|
76
|
-
|
|
77
|
-
Under `enforce: advise` the valve is structurally absent: a verdict is recorded as
|
|
78
|
-
`advised`, one advisory line lands on stderr, and the commit proceeds. Only the verdict is
|
|
79
|
-
relaxed — a run that cannot judge still fails closed at exit `2` at either level.
|
|
80
|
-
|
|
81
|
-
## Where the consumer touches it
|
|
82
|
-
|
|
83
|
-
- **The `adapters.git` block** in your config.
|
|
84
|
-
- **The pre-commit hook** that runs `pdks covenant check`, wired by hand — the manual
|
|
85
|
-
procedure for three hook managers is in
|
|
86
|
-
[installation](../installation.md#the-commit-surface--developing-by-yourself).
|
|
87
|
-
|
|
88
|
-
No import.
|
|
89
|
-
|
|
90
|
-
## Declared limits
|
|
91
|
-
|
|
92
|
-
- **A declaration that reads the session cannot be judged here.** A `precedent` needs
|
|
93
|
-
session history and a commit has none, so a matching entry records `skipped`. A permanent
|
|
94
|
-
condition of this surface, not a fault in the entry.
|
|
95
|
-
- **A commit never shows a gitignored file.** Anything outside version control — a built
|
|
96
|
-
`dist`, a generated hook script — is invisible to this surface by nature. That is why the
|
|
97
|
-
session surface carries those paths on the common list instead.
|
|
98
|
-
- **The valve needs a human at a terminal.** No TTY means no prompt and no way through: a
|
|
99
|
-
CI run and an agent-spawned `git commit` reach the same closed door. Nothing is ever
|
|
100
|
-
persisted, so one answer never covers a later commit.
|
|
@@ -1,116 +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
|
-
## What this package owns
|
|
13
|
-
|
|
14
|
-
The judge. Everything that turns a declared promise into a verdict lives here.
|
|
15
|
-
|
|
16
|
-
**This is the install unit for judgment.** An embedder that wants verdicts without the
|
|
17
|
-
umbrella's surfaces installs this package and provides `@polydeukes/core` alongside it — core
|
|
18
|
-
is a `peerDependency` here, so the vocabulary is shared rather than duplicated. The umbrella
|
|
19
|
-
is what satisfies that peer for an ordinary consumer.
|
|
20
|
-
|
|
21
|
-
| Unit | What it does |
|
|
22
|
-
|---|---|
|
|
23
|
-
| `runCovenant` wrapper | Runs a judge body, translates its non-blocking `1` into the blocking `2`, and logs every call. No covenant runs unmeasured |
|
|
24
|
-
| Path-routing dispatcher | Registers covenants against protected paths and runs *every* matching one — no short-circuit, so the telemetry never under-counts |
|
|
25
|
-
| Meta-covenants | Three registrations that protect the judging chain itself |
|
|
26
|
-
| TTL witness | The time-boxed human valve, consulted only after a verdict blocked |
|
|
27
|
-
| Delta layer | New-violation-only judgment over a file's before/after pair |
|
|
28
|
-
| Discipline library | Config `disciplines:` entries become enforcement without a line of code |
|
|
29
|
-
|
|
30
|
-
## Discipline families and meta-covenants
|
|
31
|
-
|
|
32
|
-
**A `disciplines:` entry is one declaration** — `judge = relate ∘ extract` over the
|
|
33
|
-
observation as a world. What the declaration's sources bind decides what evidence the
|
|
34
|
-
judgment needs, which is also what decides whether it can be judged on a given surface.
|
|
35
|
-
|
|
36
|
-
| Sources | Judges | Evidence needed |
|
|
37
|
-
|---|---|---|
|
|
38
|
-
| the fixed names `target.path` · `pre` · `post` · `state` · `changes` | The change itself | A file change |
|
|
39
|
-
| the fixed name `command` | The shell call's command line | A shell call — an Edit carries none |
|
|
40
|
-
| `{ transcript: true }` | Session history — was a qualifying call actually executed *before* this one | A session |
|
|
41
|
-
| `{ file: … }` · `{ sidecar: true }` | Another file, or the spawn-record channel | The surface's reader for it |
|
|
42
|
-
|
|
43
|
-
The writing guide for these entries is [the configuration reference's `disciplines`
|
|
44
|
-
section](./configuration.md#disciplines); the declaration grammar is the core's
|
|
45
|
-
`algebra-declaration.schema.json`.
|
|
46
|
-
|
|
47
|
-
**Three meta-covenants** protect the judging chain. They are covenants like any other; the
|
|
48
|
-
vocabulary below applies to them unchanged.
|
|
49
|
-
|
|
50
|
-
| Registration | Axis | Judges |
|
|
51
|
-
|---|---|---|
|
|
52
|
-
| 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 |
|
|
53
|
-
| 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 |
|
|
54
|
-
| transcript-mod | Transcript | Writes to the live session transcript, judged by whole-path **equality** — never as a protected ancestor |
|
|
55
|
-
|
|
56
|
-
**Six words** are the telemetry contract — five verdicts and one observation. A row in
|
|
57
|
-
`.polydeukes/roi.log` carries exactly one of them, and the CLI, the docs, and the tests use
|
|
58
|
-
the same word for the same event. How to read a row is in
|
|
59
|
-
[troubleshooting](../troubleshooting.md#reading-a-verdict).
|
|
60
|
-
|
|
61
|
-
| Verdict | Means |
|
|
62
|
-
|---|---|
|
|
63
|
-
| `passed` | The call was judged and upheld the covenant |
|
|
64
|
-
| `blocked` | The call was judged and broke it |
|
|
65
|
-
| `witnessed` | A **blocked** verdict a human opened in person. Never silent, never a clean call |
|
|
66
|
-
| `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` |
|
|
67
|
-
| `skipped` | The call reached a registration that could not judge it. **Not a pass** — the recorded absence of a judgment |
|
|
68
|
-
| `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 |
|
|
69
|
-
|
|
70
|
-
`unattributed` answers a question the other five cannot. They are all written by a judge
|
|
71
|
-
about a call it was handed, so a write that arrives without a declared call — through an
|
|
72
|
-
interpreter, a test runner's child process, a script that assembles the path from its own
|
|
73
|
-
arguments — leaves no row at all. The comparison observes the result rather than the
|
|
74
|
-
spelling, so it records that write after the fact. It never blocks: the write already
|
|
75
|
-
happened, and the comparison fails open on both sides of the verdict.
|
|
76
|
-
|
|
77
|
-
## Where the consumer touches it
|
|
78
|
-
|
|
79
|
-
- **The `disciplines:` block** in your config. One entry compiles into one registration,
|
|
80
|
-
carrying its own telemetry label.
|
|
81
|
-
- **`protectedPaths`**, which the path-routing dispatcher matches against.
|
|
82
|
-
- **The `witness` block**, which arms the TTL valve.
|
|
83
|
-
- **`.polydeukes/roi.log`**, where every judgment lands as one row.
|
|
84
|
-
|
|
85
|
-
No import. The umbrella assembles this package for both surfaces.
|
|
86
|
-
|
|
87
|
-
## Declared limits
|
|
88
|
-
|
|
89
|
-
- **The shell axis leaves `skipped` rows, and that row is the contract.** Predicting a
|
|
90
|
-
shell command's target from its text is undecidable, so the invariant this axis holds is
|
|
91
|
-
not "nothing gets through" — it is that **no call passes unrecorded**. A new spelling
|
|
92
|
-
landing in `skipped` is the declared limit showing itself. A pass with no row at all, or
|
|
93
|
-
one recorded `passed` without a judgment, is the defect class.
|
|
94
|
-
- **A declaration that reads the session cannot be judged without one.** On the commit
|
|
95
|
-
surface there is none, so a matching `precedent` (or any other transcript-reading)
|
|
96
|
-
declaration records `skipped` with the reason `supply-pass`. That is a permanent
|
|
97
|
-
condition of that surface.
|
|
98
|
-
- **A declaration scoped on `command` is absent from the commit surface, and absent without
|
|
99
|
-
a row.** A staged diff carries no command line, so no world such a declaration observes is
|
|
100
|
-
admitted there. This leaves nothing in `.polydeukes/roi.log`, so the log cannot separate a
|
|
101
|
-
command discipline that never triggered from one whose surface never observed a command.
|
|
102
|
-
- **A declaration the compiler cannot resolve compiles to a skip registration** — routing
|
|
103
|
-
intact, no body: a step outside the registry, an argument outside a step's keys, a pattern
|
|
104
|
-
that does not compile, a mechanism whose shape the syntax does not fit. Assembly therefore
|
|
105
|
-
never throws: one unresolvable entry cannot take down its siblings, the meta-covenants, and
|
|
106
|
-
the valve, which would leave no way to fix the config that caused it. A source the world
|
|
107
|
-
lacks at judgment time is a different case — the declaration's own `supply` policy
|
|
108
|
-
disposes of it, and with no policy the body answers unjudgeable (exit 2), never upheld.
|
|
109
|
-
- **Complete containment is a non-goal.** There are no blocklists here — enumerating bypass
|
|
110
|
-
spellings is always one step behind, so the logic is inverted: a mention of a protected
|
|
111
|
-
path blocks unless proven safe. Residual vectors such as indirect path computation are
|
|
112
|
-
telemetry targets, not block targets. The two friction valves — the read-only allowlist
|
|
113
|
-
and the TTL witness — both leave a measurable trace.
|
|
114
|
-
- **The valve stands after the verdict.** Only a judgment that actually blocked can be
|
|
115
|
-
witnessed open, a mid-sentence mention of the token does not arm it, and an AI can never
|
|
116
|
-
open the valve for itself.
|