polydeukes 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +9 -3
- package/README.md +12 -4
- package/dist/baseline.d.ts +82 -0
- package/dist/baseline.js +166 -0
- package/dist/bin.d.ts +1 -1
- package/dist/bin.js +19 -2
- package/dist/claude-code-hook.d.ts +7 -5
- package/dist/claude-code-hook.js +69 -17
- package/dist/claude-code.d.ts +6 -0
- package/dist/claude-code.js +6 -0
- package/dist/covenant-check.d.ts +10 -17
- package/dist/covenant-check.js +44 -12
- package/dist/covenant-module.d.ts +2 -2
- package/dist/covenant-module.js +9 -1
- package/dist/docs/configuration.md +1 -1
- package/dist/docs/installation.md +41 -12
- package/dist/docs/reference/adapter-claude-code.md +6 -4
- package/dist/docs/reference/adapter-git.md +8 -6
- package/dist/docs/reference/configuration.md +222 -104
- package/dist/docs/reference/core.md +11 -5
- package/dist/docs/reference/covenant.md +31 -23
- package/dist/docs/reference/polydeukes.md +62 -34
- package/dist/docs/troubleshooting.md +36 -9
- package/dist/explain.d.ts +3 -5
- package/dist/explain.js +48 -47
- package/dist/index.d.ts +2 -3
- package/dist/index.js +1 -2
- package/dist/init-claude-code.d.ts +5 -3
- package/dist/init-claude-code.js +76 -30
- package/dist/init-grok.d.ts +51 -0
- package/dist/init-grok.js +242 -0
- package/dist/load-config.d.ts +5 -1
- package/dist/load-config.js +2 -1
- package/dist/pre-state-reader.d.ts +22 -0
- package/dist/pre-state-reader.js +32 -0
- package/dist/scaffold-project.js +48 -8
- package/dist/schema/polydeukes.schema.json +38 -91
- package/package.json +7 -7
package/dist/covenant-check.js
CHANGED
|
@@ -11,10 +11,11 @@
|
|
|
11
11
|
* blocked record. An empty domain is an explicit pass with no records.
|
|
12
12
|
*/
|
|
13
13
|
import { resolve } from 'node:path';
|
|
14
|
-
import { collectRangeChanges, collectStagedChanges, collectWorktreeChanges, covenantInputFromStagedChanges, resolveGitAdapterSettings, STAGED_DELETE, STAGED_WRITE, } from '@polydeukes/adapter-git';
|
|
14
|
+
import { collectRangeChanges, collectStagedChanges, collectWorktreeChanges, covenantInputFromStagedChanges, observationSourceReader, resolveGitAdapterSettings, STAGED_DELETE, STAGED_WRITE, } from '@polydeukes/adapter-git';
|
|
15
15
|
import { appendRecordFailOpen, DEFAULT_TELEMETRY_LOG_PATH, normalizeProtectedPaths, } from '@polydeukes/core';
|
|
16
16
|
import { loadCovenantModule, resolveCovenantDist } from './covenant-module.js';
|
|
17
17
|
import { loadConfig } from './load-config.js';
|
|
18
|
+
import { unobservedPreStateReader } from './pre-state-reader.js';
|
|
18
19
|
/**
|
|
19
20
|
* The TTY witness predicate, or undefined when no valve can exist (no witness configured
|
|
20
21
|
* or no TTY seam). It fires on the first registration that broke, names it from the
|
|
@@ -61,7 +62,9 @@ function recordFailClosed(telemetryPath) {
|
|
|
61
62
|
*/
|
|
62
63
|
export function assembleCommitRegistrations(spec) {
|
|
63
64
|
const { config, rootDir, covenant, witness } = spec;
|
|
64
|
-
const { protectedPaths: gitAdditivePaths } = resolveGitAdapterSettings(
|
|
65
|
+
const { protectedPaths: gitAdditivePaths } = resolveGitAdapterSettings({
|
|
66
|
+
namespace: config.adapters?.git,
|
|
67
|
+
});
|
|
65
68
|
// Union of the common list and the git-additive one, common first so first-occurrence
|
|
66
69
|
// dedupe is deterministic. The session hook reads the common list alone.
|
|
67
70
|
const protectedPaths = normalizeProtectedPaths({
|
|
@@ -74,14 +77,13 @@ export function assembleCommitRegistrations(spec) {
|
|
|
74
77
|
mutatingToolNames: [STAGED_WRITE, STAGED_DELETE],
|
|
75
78
|
witness,
|
|
76
79
|
}),
|
|
77
|
-
// No shell axis here, so command-family entries are left out. Context-family entries
|
|
78
|
-
// stay in: with no transcript the compiler gives them skip registrations, which record
|
|
79
|
-
// `skipped` on a match.
|
|
80
80
|
...covenant.compileDisciplineRegistrations({
|
|
81
|
-
disciplines
|
|
81
|
+
disciplines,
|
|
82
82
|
rootDir,
|
|
83
83
|
shellTools: [],
|
|
84
84
|
commandArgs: [],
|
|
85
|
+
readPreState: unobservedPreStateReader,
|
|
86
|
+
observesChangeSet: true,
|
|
85
87
|
witness,
|
|
86
88
|
}),
|
|
87
89
|
];
|
|
@@ -104,7 +106,7 @@ function settleConfig(spec) {
|
|
|
104
106
|
let telemetryPath;
|
|
105
107
|
try {
|
|
106
108
|
telemetryPath = spec.telemetryPath ?? resolve(spec.repoRoot, DEFAULT_TELEMETRY_LOG_PATH);
|
|
107
|
-
const { config } = loadConfig(spec.repoRoot);
|
|
109
|
+
const { config } = loadConfig({ rootDir: spec.repoRoot });
|
|
108
110
|
telemetryPath = spec.telemetryPath ?? resolve(spec.repoRoot, config.telemetry.logPath);
|
|
109
111
|
return { settled: true, telemetryPath, config };
|
|
110
112
|
}
|
|
@@ -118,12 +120,32 @@ function settleConfig(spec) {
|
|
|
118
120
|
*/
|
|
119
121
|
function collectDomain(repoRoot, domain) {
|
|
120
122
|
if (domain.kind === 'worktree')
|
|
121
|
-
return collectWorktreeChanges(repoRoot);
|
|
123
|
+
return collectWorktreeChanges({ repoRoot });
|
|
122
124
|
if (domain.kind === 'range') {
|
|
123
125
|
const separator = domain.ancestry === 'merge-base' ? '...' : '..';
|
|
124
|
-
return collectRangeChanges(
|
|
126
|
+
return collectRangeChanges({
|
|
127
|
+
repoRoot,
|
|
128
|
+
range: `${domain.base}${separator}${domain.head}`,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return collectStagedChanges({ repoRoot });
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* The observation's change set: the paths of the collected changes that carry file-change
|
|
135
|
+
* evidence, in collection order.
|
|
136
|
+
*
|
|
137
|
+
* The same definition the judge derives its own set from, so both surfaces name the same
|
|
138
|
+
* changes. A deletion carries evidence and stays; a binary blob, which the collector gives
|
|
139
|
+
* a call with no evidence, produces no world of its own — listing it would hand the
|
|
140
|
+
* change-set relations a path no world can ever answer for.
|
|
141
|
+
*/
|
|
142
|
+
function changedPaths(changes) {
|
|
143
|
+
const paths = [];
|
|
144
|
+
for (const call of covenantInputFromStagedChanges({ changes }).toolCalls) {
|
|
145
|
+
if (call.fileChange !== undefined)
|
|
146
|
+
paths.push(call.fileChange.path);
|
|
125
147
|
}
|
|
126
|
-
return
|
|
148
|
+
return paths;
|
|
127
149
|
}
|
|
128
150
|
/**
|
|
129
151
|
* Assemble the registrations and dispatch every collected change. Any throw here (an
|
|
@@ -132,7 +154,7 @@ function collectDomain(repoRoot, domain) {
|
|
|
132
154
|
async function judgeChanges(spec, domain, telemetryPath, config, changes) {
|
|
133
155
|
try {
|
|
134
156
|
// Inside the try so an invalid adapter namespace fails closed.
|
|
135
|
-
const { enforce } = resolveGitAdapterSettings(config.adapters?.git);
|
|
157
|
+
const { enforce } = resolveGitAdapterSettings({ namespace: config.adapters?.git });
|
|
136
158
|
// Real Node resolution of the covenant package, so the commit surface runs the same
|
|
137
159
|
// judges the session hook does; tests inject a directory instead. Awaited before any
|
|
138
160
|
// registration is composed, so a dist the barrel cannot load fails the run closed here
|
|
@@ -155,14 +177,24 @@ async function judgeChanges(spec, domain, telemetryPath, config, changes) {
|
|
|
155
177
|
covenant,
|
|
156
178
|
witness,
|
|
157
179
|
});
|
|
180
|
+
// One plan and one supply for the run: the per-change loop shares them, so the tree is
|
|
181
|
+
// read once per named file rather than once per change. `changes` carries the whole
|
|
182
|
+
// observation because this surface dispatches one change at a time to keep telemetry at
|
|
183
|
+
// one row per file — a set no judge could derive from the input it is handed.
|
|
184
|
+
const { files } = covenant.supplySources({
|
|
185
|
+
plan: covenant.planSources({ registrations }),
|
|
186
|
+
read: observationSourceReader({ repoRoot: spec.repoRoot, observation: domain }),
|
|
187
|
+
});
|
|
188
|
+
const world = { files, changes: changedPaths(changes) };
|
|
158
189
|
for (const change of changes) {
|
|
159
|
-
const input = covenantInputFromStagedChanges([change]);
|
|
190
|
+
const input = covenantInputFromStagedChanges({ changes: [change] });
|
|
160
191
|
const { exitCode, results } = await covenant.dispatchCovenants({
|
|
161
192
|
stdinPayload: JSON.stringify(input),
|
|
162
193
|
registrations,
|
|
163
194
|
telemetryPath,
|
|
164
195
|
dispatcherLabel: 'covenant-check',
|
|
165
196
|
enforce,
|
|
197
|
+
world,
|
|
166
198
|
});
|
|
167
199
|
if (exitCode === 2)
|
|
168
200
|
blocked = true;
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
* mirror where real Node resolution would always land on the healthy build.
|
|
13
13
|
*/
|
|
14
14
|
import type * as covenant from '@polydeukes/covenant';
|
|
15
|
-
/** The covenant surface both roots assemble against. */
|
|
16
|
-
export type CovenantModule = typeof covenant
|
|
15
|
+
/** The covenant surface both roots assemble against — the members they call, and no more. */
|
|
16
|
+
export type CovenantModule = Pick<typeof covenant, 'dispatchCovenants' | 'compileDisciplineRegistrations' | 'selfModRegistration' | 'shellModRegistration' | 'transcriptModRegistration' | 'planSources' | 'supplySources'>;
|
|
17
17
|
/** Where real Node resolution puts the covenant package's built barrel. */
|
|
18
18
|
export declare function resolveCovenantDist(): string;
|
|
19
19
|
/**
|
package/dist/covenant-module.js
CHANGED
|
@@ -11,6 +11,14 @@
|
|
|
11
11
|
* The `covenantDist` seam selects WHICH dist is imported, so a fixture can inject a gutted
|
|
12
12
|
* mirror where real Node resolution would always land on the healthy build.
|
|
13
13
|
*/
|
|
14
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
15
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
16
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
17
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return path;
|
|
21
|
+
};
|
|
14
22
|
import { createRequire } from 'node:module';
|
|
15
23
|
import { join } from 'node:path';
|
|
16
24
|
import { pathToFileURL } from 'node:url';
|
|
@@ -26,7 +34,7 @@ export function resolveCovenantDist() {
|
|
|
26
34
|
*/
|
|
27
35
|
export async function loadCovenantModule(distDir) {
|
|
28
36
|
try {
|
|
29
|
-
return (await import(pathToFileURL(join(distDir, 'index.js')).href));
|
|
37
|
+
return (await import(__rewriteRelativeImportExtension(pathToFileURL(join(distDir, 'index.js')).href)));
|
|
30
38
|
}
|
|
31
39
|
catch (error) {
|
|
32
40
|
throw new Error(`the covenant judges could not be loaded from ${distDir} — run 'pnpm build' to rebuild them: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**English** · [한국어](./configuration.ko.md)
|
|
4
4
|
|
|
5
5
|
> Alpha. This guide covers the config surface as shipped today (schema v2, loader, and
|
|
6
|
-
> the
|
|
6
|
+
> the declaration grammar). Fields and steps will grow; what is
|
|
7
7
|
> written here is tested and enforced now.
|
|
8
8
|
|
|
9
9
|
`polydeukes.config.yaml` is the one file where a project declares its disciplines — the
|
|
@@ -43,7 +43,8 @@ judge from your project's own installed package.
|
|
|
43
43
|
From the project root:
|
|
44
44
|
|
|
45
45
|
```sh
|
|
46
|
-
pnpm exec pdks init claude-code
|
|
46
|
+
pnpm exec pdks init claude-code # Claude Code
|
|
47
|
+
pnpm exec pdks init grok # Grok
|
|
47
48
|
```
|
|
48
49
|
|
|
49
50
|
The command installs into the directory it is invoked from, and it proves the `polydeukes`
|
|
@@ -51,9 +52,17 @@ package resolves there **before writing anything** — if it does not (say, the
|
|
|
51
52
|
was skipped), it prints the install command and exits 2 with zero files written, never a
|
|
52
53
|
half-wired tree.
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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:
|
|
57
66
|
|
|
58
67
|
| Artifact | What it is |
|
|
59
68
|
|---|---|
|
|
@@ -64,6 +73,25 @@ config, and the discipline files are left alone, the settings file is merged, an
|
|
|
64
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. |
|
|
65
74
|
| `.gitignore` | An appended ignore rule for `.polydeukes/`, with its comment line — telemetry is local observation data and never belongs in history. |
|
|
66
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
|
+
|
|
67
95
|
## First edit — `languages`
|
|
68
96
|
|
|
69
97
|
The generated config ships a placeholder language profile, because the installer cannot
|
|
@@ -148,12 +176,12 @@ Three things to know about this surface:
|
|
|
148
176
|
- **The valve is a TTY prompt.** At the default `block` level, a commit that stages a
|
|
149
177
|
protected change stops at a prompt only a human at a terminal can answer. Configure your
|
|
150
178
|
hook runner so it does not swallow that prompt (lefthook needs `interactive: true`).
|
|
151
|
-
- **
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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.
|
|
157
185
|
- **The commit surface has its own additive scope.** Paths that are fine to edit freely
|
|
158
186
|
but whose promotion into history deserves a judged checkpoint go under the adapter
|
|
159
187
|
namespace, judged on top of the shared list:
|
|
@@ -185,8 +213,9 @@ witness:
|
|
|
185
213
|
|
|
186
214
|
Change the token and window as you like — the token is not a secret; the defence is
|
|
187
215
|
provenance, not confidentiality. **Keep the block**: on the session surface the generated
|
|
188
|
-
protection list covers `.claude/hooks`, so without a valve the first
|
|
189
|
-
freeze the project until a human edits the config from their own
|
|
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.
|
|
190
219
|
|
|
191
220
|
## Prove the gate is live
|
|
192
221
|
|
|
@@ -21,11 +21,12 @@ agent-neutrality a claim a test can check rather than a slogan.
|
|
|
21
21
|
| Virtual post-state | Computes what a file *would* contain after an edit applies, without touching disk |
|
|
22
22
|
| File-change evidence | Pairs the disk pre-state with the virtual post-state into union evidence |
|
|
23
23
|
| Transcript provider | Turns a session JSONL file into a `CanonicalTranscript` |
|
|
24
|
-
| Precedent evaluator | This adapter's own evidence vocabulary for the context family |
|
|
25
24
|
| Telemetry wiring | Drives the full funnel so exactly one row lands per call |
|
|
26
25
|
|
|
27
26
|
This package never imports the covenant package. The dispatch seam is *injected* by the
|
|
28
|
-
umbrella, which keeps dependencies one-way, through the core alone.
|
|
27
|
+
umbrella, which keeps dependencies one-way, through the core alone. It names
|
|
28
|
+
`@polydeukes/core` as a `peerDependency`: the vocabulary is shared with the judge, not
|
|
29
|
+
installed a second time here.
|
|
29
30
|
|
|
30
31
|
## Payload translation and the three axes
|
|
31
32
|
|
|
@@ -39,7 +40,9 @@ umbrella, which keeps dependencies one-way, through the core alone.
|
|
|
39
40
|
|
|
40
41
|
Translation is fail-closed at every step. A `Task` call carrying a subagent type maps to a
|
|
41
42
|
spawn; a payload that cannot be classified is a translation *failure* that logs one
|
|
42
|
-
`blocked` record and exits `2`, rather than degrading into a guess.
|
|
43
|
+
`blocked` record and exits `2`, rather than degrading into a guess. The envelope's top-level
|
|
44
|
+
`agent_type` becomes the IR's `actor` — `{ agentType }` inside a subagent, `{}` otherwise;
|
|
45
|
+
`tool_input` is never read for it, since that is the agent's own text.
|
|
43
46
|
|
|
44
47
|
**Evidence is computed, never read back.** The virtual post-state applies `Edit`, `Write`,
|
|
45
48
|
and `MultiEdit` in memory — sequential multi-edit application included — so a content-aware
|
|
@@ -62,7 +65,6 @@ the compiler the evidence is unjudgeable, so the entry skips instead of judging
|
|
|
62
65
|
|
|
63
66
|
- **The generated hook**, which loads this adapter through the umbrella's `claude-code`
|
|
64
67
|
subpath. Upgrading the package upgrades what runs; the hook file itself never changes.
|
|
65
|
-
- **`requirePrecedent` entries** using the `subagent` or `tool` evidence keys.
|
|
66
68
|
|
|
67
69
|
No import, and no configuration namespace of its own.
|
|
68
70
|
|
|
@@ -23,12 +23,13 @@ AI or human.
|
|
|
23
23
|
|
|
24
24
|
This is a pure library. It knows the staged-diff shape and nothing about installation, hook
|
|
25
25
|
runners, or valves — wiring it into a pre-commit hook is a deployment act that lives in the
|
|
26
|
-
umbrella.
|
|
26
|
+
umbrella. It names `@polydeukes/core` as a `peerDependency`: the vocabulary is shared with
|
|
27
|
+
the judge, not installed a second time here.
|
|
27
28
|
|
|
28
29
|
## Collection and the `adapters.git` namespace
|
|
29
30
|
|
|
30
31
|
**Three collectors, one shape.** `collectStagedChanges`, `collectWorktreeChanges`, and
|
|
31
|
-
`collectRangeChanges(repoRoot, '<base>..<head>' | '<base>...<head>')` each return the same
|
|
32
|
+
`collectRangeChanges({ repoRoot, range: '<base>..<head>' | '<base>...<head>' })` each return the same
|
|
32
33
|
`StagedChange[]`, so the translator and everything after it is one path.
|
|
33
34
|
|
|
34
35
|
| Collector | `pre` | `post` | Also |
|
|
@@ -52,7 +53,8 @@ and `staged-delete`. A deletion always carries its evidence. A write carries it
|
|
|
52
53
|
staged blob was binary — there is no text to compare, so the call arrives with no
|
|
53
54
|
`fileChange` at all and is judged on its path alone, the same as any unproven call.
|
|
54
55
|
**The session collections are honestly empty** — the commit surface has no session, and a
|
|
55
|
-
key is never fabricated to look like one.
|
|
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.
|
|
56
58
|
|
|
57
59
|
**The namespace is this adapter's own vocabulary.** The core validates only the container
|
|
58
60
|
shape — one settings object per adapter — and passes the contents through verbatim, so the
|
|
@@ -87,9 +89,9 @@ No import.
|
|
|
87
89
|
|
|
88
90
|
## Declared limits
|
|
89
91
|
|
|
90
|
-
- **
|
|
91
|
-
and a commit has none, so a matching entry records `skipped`. A permanent
|
|
92
|
-
this surface, not a fault in the entry.
|
|
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.
|
|
93
95
|
- **A commit never shows a gitignored file.** Anything outside version control — a built
|
|
94
96
|
`dist`, a generated hook script — is invisible to this surface by nature. That is why the
|
|
95
97
|
session surface carries those paths on the common list instead.
|