@dtmd/temper 0.0.6 → 0.0.8

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.
Files changed (50) hide show
  1. package/README.md +84 -53
  2. package/bin/temper.js +52 -0
  3. package/dist/src/assembly.d.ts +15 -1
  4. package/dist/src/assembly.js +2 -1
  5. package/dist/src/builtins.d.ts +765 -48
  6. package/dist/src/builtins.js +767 -68
  7. package/dist/src/claude-code.d.ts +2 -2
  8. package/dist/src/claude-code.js +1 -1
  9. package/dist/src/contract.d.ts +180 -29
  10. package/dist/src/contract.js +128 -15
  11. package/dist/src/declarations.d.ts +92 -6
  12. package/dist/src/declarations.js +448 -102
  13. package/dist/src/dial.d.ts +75 -0
  14. package/dist/src/dial.js +82 -0
  15. package/dist/src/emit.d.ts +82 -1
  16. package/dist/src/emit.js +402 -56
  17. package/dist/src/generated/AssemblyFactRow.d.ts +2 -2
  18. package/dist/src/generated/BoundRow.d.ts +2 -2
  19. package/dist/src/generated/ClauseRow.d.ts +73 -3
  20. package/dist/src/generated/CollectionAddressRow.d.ts +21 -0
  21. package/dist/src/generated/CollectionAddressRow.js +2 -0
  22. package/dist/src/generated/Declarations.d.ts +17 -0
  23. package/dist/src/generated/EmbeddedMember.d.ts +3 -3
  24. package/dist/src/generated/FeatureValue.d.ts +2 -2
  25. package/dist/src/generated/Features.d.ts +52 -3
  26. package/dist/src/generated/KindFactRow.d.ts +38 -7
  27. package/dist/src/generated/MentionRow.d.ts +5 -3
  28. package/dist/src/generated/NestedMemberRow.d.ts +32 -0
  29. package/dist/src/generated/PayloadMember.d.ts +6 -0
  30. package/dist/src/generated/RegistrationRow.d.ts +35 -0
  31. package/dist/src/generated/RegistrationRow.js +2 -0
  32. package/dist/src/generated/RequirementRow.d.ts +4 -2
  33. package/dist/src/generated/SatisfiesRow.d.ts +2 -1
  34. package/dist/src/generated/SettingsRow.d.ts +25 -0
  35. package/dist/src/generated/SettingsRow.js +2 -0
  36. package/dist/src/generated/Shape.d.ts +15 -0
  37. package/dist/src/generated/Shape.js +2 -0
  38. package/dist/src/generated/TemplateRow.d.ts +24 -0
  39. package/dist/src/generated/TemplateRow.js +2 -0
  40. package/dist/src/generated/ValueType.d.ts +11 -2
  41. package/dist/src/generated/Verifier.d.ts +20 -0
  42. package/dist/src/generated/Verifier.js +2 -0
  43. package/dist/src/generated/index.d.ts +6 -0
  44. package/dist/src/index.d.ts +8 -8
  45. package/dist/src/index.js +3 -3
  46. package/dist/src/kind.d.ts +160 -29
  47. package/dist/src/kind.js +47 -16
  48. package/dist/src/prose.d.ts +81 -25
  49. package/dist/src/prose.js +91 -21
  50. package/package.json +10 -2
@@ -7,7 +7,7 @@
7
7
  * specifier like any other. The built-in default contracts join the kinds here
8
8
  * too: adoption is `import { skill, skillDefaultContract } from "@dtmd/temper/claude-code"`.
9
9
  */
10
- export type { Agent, Memory, Rule, Skill } from "./builtins.js";
11
- export { agent, agentDefaultContract, command, commandDefaultContract, memory, memoryAgentsMdDefaultContract, memoryAnthropicDefaultContract, rule, ruleDefaultContract, skill, skillDefaultContract, } from "./builtins.js";
10
+ export type { Agent, Hook, InstalledPlugin, KnownMarketplace, Marketplace, MarketplacePlugin, MarketplaceSource, McpServer, Memory, PluginManifest, Rule, SettingsLocal, Skill, SupportingDoc, } from "./builtins.js";
11
+ export { agent, agentDefaultContract, command, commandDefaultContract, hook, hookDefaultContract, installedPlugin, installedPluginDefaultContract, knownMarketplace, knownMarketplaceDefaultContract, marketplace, marketplaceDefaultContract, mcpServer, mcpServerDefaultContract, memory, memoryAnthropicDefaultContract, pluginManifest, pluginManifestDefaultContract, rule, ruleDefaultContract, settingsLocal, settingsLocalDefaultContract, skill, skillDefaultContract, supportingDoc, supportingDocDefaultContract, } from "./builtins.js";
12
12
  export type { Blocks, File, Prose, Text } from "./prose.js";
13
13
  export { blocks, file, text } from "./prose.js";
@@ -7,5 +7,5 @@
7
7
  * specifier like any other. The built-in default contracts join the kinds here
8
8
  * too: adoption is `import { skill, skillDefaultContract } from "@dtmd/temper/claude-code"`.
9
9
  */
10
- export { agent, agentDefaultContract, command, commandDefaultContract, memory, memoryAgentsMdDefaultContract, memoryAnthropicDefaultContract, rule, ruleDefaultContract, skill, skillDefaultContract, } from "./builtins.js";
10
+ export { agent, agentDefaultContract, command, commandDefaultContract, hook, hookDefaultContract, installedPlugin, installedPluginDefaultContract, knownMarketplace, knownMarketplaceDefaultContract, marketplace, marketplaceDefaultContract, mcpServer, mcpServerDefaultContract, memory, memoryAnthropicDefaultContract, pluginManifest, pluginManifestDefaultContract, rule, ruleDefaultContract, settingsLocal, settingsLocalDefaultContract, skill, skillDefaultContract, supportingDoc, supportingDocDefaultContract, } from "./builtins.js";
11
11
  export { blocks, file, text } from "./prose.js";
@@ -1,26 +1,40 @@
1
1
  /**
2
2
  * Contracts — clauses and requirements as typed values.
3
3
  * A clause is `predicate · severity · guidance · cite`; a requirement is
4
- * `prose · kind · required · clauses? · verifiedBy?`. Both erase to compiled data
4
+ * `prose · kind · required · clauses? · verifier?`. Both erase to compiled data
5
5
  * at the seam: the author composes typed objects, the engine
6
6
  * consumes their rows. The predicate vocabulary is the closed algebra — a clause
7
7
  * outside it is a squiggle, not a runtime rejection.
8
8
  */
9
+ import type { Shape, ValueType } from "./generated/index.js";
9
10
  import type { KindDefinition } from "./kind.js";
10
11
  /** A clause's delivery posture: `required` gate-blocks, `advisory` reports. */
11
12
  export type Severity = "required" | "advisory";
12
13
  /**
13
- * A member of the closed predicate algebra. Both a kind's
14
- * own `expect` clauses and a requirement's `clauses` compile to the row's full
15
- * `key`/`field`/`severity`/argument shape (`declarations.ts` `clauseRow`): a
16
- * floor clause's own `bound`/`charset`/`keys`/`values` ride the row alongside
17
- * a requirement's `count`/`target`/`degree`, so the lock encodes the floor
18
- * losslessly rather than identity+severity alone.
14
+ * A member of the closed predicate algebra. Both a kind's own `expect` clauses and a
15
+ * requirement's `clauses` compile to the row's full `key`/`field`/`severity`/argument
16
+ * shape (`declarations.ts` `clauseRow`) — one spelling, whichever selection the clause
17
+ * binds to: `bound`/`charset`/`keys`/`values` ride the row alongside
18
+ * `count`/`target`/`degree`, so the lock encodes the clause losslessly rather than
19
+ * identity+severity alone.
19
20
  */
20
21
  export interface Predicate {
21
- /** The predicate's clause key (`required`, `max_len`, `max_lines`, …). */
22
+ /** The predicate's clause key (`required`, `max_len`, `extent`, …). */
22
23
  readonly key: string;
23
- /** The field (or marker) the predicate constrains, when it names one. */
24
+ /**
25
+ * The field (or marker) the predicate constrains, when it names one.
26
+ *
27
+ * A value predicate's `field` is an **addressing path**: name segments walk into an
28
+ * object (`owner.name`), and `[*]` is the each-grain over an array's elements, so
29
+ * `plugins[*].source` decides once per entry and indicts each offending one by its own
30
+ * address. Nothing else is spellable — an index, a slice, a filter, and a recursive
31
+ * descent are all refused when the contract is checked, not silently evaluated. The
32
+ * subset is the whole surface on purpose: a clause names *where* a value lives, never
33
+ * a pattern that matches it.
34
+ *
35
+ * `forbidden_keys` and `must_define` name a top-level **key**, not a path, and
36
+ * `closed-keys` names neither — it reads the key set its sibling clauses declare.
37
+ */
24
38
  readonly field?: string;
25
39
  /** The predicate's scalar bounds, keyed per predicate (`min`/`max`,
26
40
  * `incoming_min`/`incoming_max`/`outgoing_min`/`outgoing_max`). */
@@ -30,6 +44,23 @@ export interface Predicate {
30
44
  * checked field) since `membership` names both.
31
45
  */
32
46
  readonly target?: string;
47
+ /**
48
+ * `mention-reachable`'s **target-side gate field** — a separate slot from `field`
49
+ * (which carries the source-side scope field) since it is the one predicate naming a
50
+ * field on *both* ends. Spelled to match the lock's own `gate` column.
51
+ */
52
+ readonly gate?: string;
53
+ /**
54
+ * `type`'s declared source kinds over the closed scalar/container lattice — the set
55
+ * the field may carry any one of. Spelled to match the lock's own `value_type`
56
+ * column.
57
+ */
58
+ readonly value_type?: readonly ValueType[];
59
+ /**
60
+ * `shape`'s declared shape — one member of the closed set, spelled to match the lock's
61
+ * own `shape` column.
62
+ */
63
+ readonly shape?: Shape;
33
64
  /** `allowed_chars`'s declared character class. */
34
65
  readonly charset?: Charset;
35
66
  /** `forbidden_keys`'s forbidden key list. */
@@ -46,7 +77,15 @@ export interface Predicate {
46
77
  readonly heading: string;
47
78
  readonly marker: string;
48
79
  };
80
+ /** `require_sections`'s required heading list. */
81
+ readonly sections?: readonly string[];
82
+ /** `extent`'s declared unit — the render-side size proxy the bound is measured in. */
83
+ readonly unit?: ExtentUnit;
49
84
  }
85
+ /** The unit an `extent` bound is measured in — the closed set of stable render-side size
86
+ * proxies. Token count is deliberately absent: a verdict that moves when a tokenizer
87
+ * updates is a gate that changes its mind with no diff. */
88
+ export type ExtentUnit = "lines" | "characters";
50
89
  /**
51
90
  * The character class `allowed_chars` admits — inclusive ranges plus individual
52
91
  * characters, e.g. `[a-z0-9-]`. Each range is a `"<lo>-<hi>"` two-character
@@ -56,24 +95,60 @@ export interface Charset {
56
95
  readonly ranges?: readonly string[];
57
96
  readonly chars?: string;
58
97
  }
59
- /** A field or marker is present. */
98
+ /**
99
+ * A field or marker is present. Presence is asked of the path's trailing name segment,
100
+ * so `required("plugins[*].source")` fires once per entry that omits it — and a path
101
+ * ending in `[*]` names elements rather than a key, which is refused.
102
+ */
60
103
  export declare const required: (field: string) => Predicate;
61
- /** The field's parsed scalar type is as declared. */
62
- export declare const type: (field: string) => Predicate;
104
+ /**
105
+ * The field's parsed source kind is one of the declared ones. `kinds` is a set: a
106
+ * format that documents a field as `string|array` is gated by `["string", "list"]`,
107
+ * and a one-element `["list"]` is the plain single-kind check.
108
+ */
109
+ export declare const type: (field: string, kinds: readonly ValueType[]) => Predicate;
63
110
  /** The field's value is at least `n` characters. */
64
111
  export declare const minLen: (field: string, n: number) => Predicate;
65
112
  /** The field's value is at most `n` characters. */
66
113
  export declare const maxLen: (field: string, n: number) => Predicate;
67
114
  /** The field's characters are drawn from a declared class (`allowed_chars`). */
68
115
  export declare const allowedChars: (field: string, charset: Charset) => Predicate;
69
- /** The member's body is at most `n` lines. */
70
- export declare const maxLines: (n: number) => Predicate;
116
+ /**
117
+ * The field's value holds one named `Shape` from the closed set the engine generates
118
+ * across the seam — the union *is* the vocabulary, so an author picks a member and can
119
+ * spell nothing else. There is no escape to a hand-written pattern, which is the point.
120
+ *
121
+ * - `hyphen-placement` — a hyphen neither leads, trails, nor doubles (`pdf-processing`,
122
+ * never `-pdf`, `pdf-`, or `pdf--processing`). Says nothing about the alphabet; pair it
123
+ * with `allowedChars` where the character set matters.
124
+ * - `no-xml-tags` — the value carries no XML tag (`<br/>`, `</note>`, `<a href="x">`).
125
+ * Prose spelling a comparison (`use when x < y`) is not a tag and does not fire.
126
+ */
127
+ export declare const shape: (field: string, shape: Shape) => Predicate;
128
+ /**
129
+ * The selected item's **rendered** extent is at most `bound`, in the declared `unit`
130
+ * (`lines` or `characters`). Node-scope and render-side: the measure is the bytes the
131
+ * item contributes to its projection, not the source body a count reads before a
132
+ * reference resolves or a render hook runs.
133
+ */
134
+ export declare const extent: (unit: ExtentUnit, bound: number) => Predicate;
71
135
  /** The forbidden keys (e.g. the Cursor `globs`/`alwaysApply` keys) are absent. */
72
136
  export declare const forbiddenKeys: (keys: readonly string[]) => Predicate;
137
+ /**
138
+ * The kind's declared key set is exhaustive — a member carrying any other top-level key
139
+ * is a finding. `forbiddenKeys`' complement: a deny-list names a finite set over an open
140
+ * key space, this closes the space.
141
+ *
142
+ * It takes no arguments, and that is the point: the allow-list is the contract's own
143
+ * `required`/`optional` clauses, so the key set is declared once. Adding `optional("x")`
144
+ * admits `x` with no second edit here — and a contract declaring no key at all fails
145
+ * admissibility rather than indicting every key of every member.
146
+ */
147
+ export declare const closedKeys: () => Predicate;
73
148
  /** The field's value is none of `values` (forbidden values). */
74
149
  export declare const deny: (field: string, values: readonly string[]) => Predicate;
75
150
  /** The named headings are present. */
76
- export declare const requireSections: () => Predicate;
151
+ export declare const requireSections: (sections: readonly string[]) => Predicate;
77
152
  /** The member's name matches its directory. */
78
153
  export declare const nameMatchesDir: () => Predicate;
79
154
  /** Names are unique within the artifact kind (a scope-wide identity collision). */
@@ -93,16 +168,41 @@ export declare const enumOf: (field: string, values: readonly string[]) => Predi
93
168
  export declare const mustDefine: (marker: string) => Predicate;
94
169
  /** Every body section whose heading *starts with* `heading` carries `marker` in its body. */
95
170
  export declare const sectionContains: (heading: string, marker: string) => Predicate;
96
- /** The satisfier set's size lies in the inclusive `[min, max]` bound. */
171
+ /** Every glob the field carries parses under globset (brace-expansion aware). */
172
+ export declare const globValid: (field: string) => Predicate;
173
+ /**
174
+ * Every mention a selected member authors can fire where its target can be invoked. A
175
+ * target whose `gateField` carries globs is gated — removed from every invocation
176
+ * channel until the agent reads a matching file — so a mention of it is actionable only
177
+ * inside that gate. Fires on a scoped source whose `scopeField` globs are not contained
178
+ * in the target's gate, and on an unscoped source mentioning a gated target.
179
+ *
180
+ * Generic over both ends, hard-coding no kind: the trigger is the target's gate field
181
+ * carrying a value, never its registration set. Containment is *literal* — every source
182
+ * glob must appear verbatim in the gate — since true glob-set containment is
183
+ * undecidable, so it false-fires on a semantically contained narrower glob
184
+ * (`src/**\/*.ts` inside `src/**`). Declare it at advisory severity: a check that can be
185
+ * wrong must not block.
186
+ */
187
+ export declare const mentionReachable: (scopeField: string, gateField: string) => Predicate;
188
+ /**
189
+ * Every edge the member's kind declares is placed by the format that renders the member
190
+ * — a format that omits one renders a contract the prose does not represent. Names no
191
+ * field: the selection is the member's whole incident edge set, at the `each` grain.
192
+ * Decided over the placement `emit` observes while rendering and lowers into the
193
+ * member's `nested_member` row, since the engine never sees a format.
194
+ */
195
+ export declare const formatPlacesEdges: () => Predicate;
196
+ /** The selection's size lies in the inclusive `[min, max]` bound. */
97
197
  export declare const count: (bounds: {
98
198
  min?: number;
99
199
  max?: number;
100
200
  }) => Predicate;
101
- /** The field's extracted value does not repeat across the satisfier set. */
201
+ /** The field's extracted value does not repeat across the selection. */
102
202
  export declare const unique: (field: string) => Predicate;
103
- /** Every satisfier's `field` value is drawn from a feature over `target`'s own satisfier set. */
203
+ /** Every selected member's `field` value is drawn from a feature over the selection `target` declares. */
104
204
  export declare const membership: (field: string, target: string) => Predicate;
105
- /** The in/out edge-count bound every satisfier must land in. At least one direction must be given. */
205
+ /** The in/out edge-count bound every selected member must land in. At least one direction must be given. */
106
206
  export declare const degree: (bounds: {
107
207
  incoming?: {
108
208
  min?: number;
@@ -113,16 +213,38 @@ export declare const degree: (bounds: {
113
213
  max?: number;
114
214
  };
115
215
  }) => Predicate;
216
+ /**
217
+ * A guarded clause — a predicate (restricted to `type` or `enum`) that acts as a
218
+ * guard, with a body of ordinary clauses that fire only where the guard holds.
219
+ * The guard and body share the guard's address binding: the body's field paths
220
+ * evaluate at the concrete element address the guard locates.
221
+ *
222
+ * The guard must be a `type` or `enumOf` predicate, named for the decidable
223
+ * field it addresses. Neither is enforced here; emit validates admissibility.
224
+ *
225
+ * Options for `severity`, `guidance`, and `cite` are supported and follow the
226
+ * same pattern as `clause()`. Default severity is `required`.
227
+ */
228
+ export declare function when(guard: Predicate, body: readonly Clause[], opts?: {
229
+ severity?: Severity;
230
+ guidance?: string;
231
+ cite?: string;
232
+ }): Clause;
116
233
  /**
117
234
  * A clause — a predicate the author marks with a severity, the just-in-time
118
235
  * guidance the predicate cannot encode, and the external-fact `cite` that makes
119
- * a maintained floor auditable.
236
+ * a maintained floor auditable. A `when` clause carries an additional guard
237
+ * predicate and a body of nested clauses that fire only where the guard holds.
120
238
  */
121
239
  export interface Clause {
122
240
  readonly predicate: Predicate;
123
241
  readonly severity: Severity;
124
242
  readonly guidance?: string;
125
243
  readonly cite?: string;
244
+ /** The guard predicate for a `when` clause; absent for all others. */
245
+ readonly when_guard?: Predicate;
246
+ /** The nested body clauses for a `when` clause; absent for all others. */
247
+ readonly when_body?: readonly Clause[];
126
248
  }
127
249
  /** Compose a clause value — a predicate under a declared severity, with optional guidance/cite. */
128
250
  export declare function clause(predicate: Predicate, opts: {
@@ -130,22 +252,51 @@ export declare function clause(predicate: Predicate, opts: {
130
252
  guidance?: string;
131
253
  cite?: string;
132
254
  }): Clause;
255
+ /**
256
+ * A requirement's **typed verifier** — the declared delegate that judges the
257
+ * behavioral remainder, a species-tagged union the gate resolves at admissibility
258
+ * and never runs. Two species this slice: a `script` (path-resolved) and a
259
+ * `telemetry` declaration (named documented harness events). A probe stays a
260
+ * documented pattern until a consumer types it — no `probe()` constructor is minted.
261
+ */
262
+ export type Verifier = {
263
+ readonly species: "script";
264
+ readonly path: string;
265
+ } | {
266
+ readonly species: "telemetry";
267
+ readonly events: readonly string[];
268
+ };
269
+ /**
270
+ * A script verifier — a path-resolved reference to the test or CI job that executes
271
+ * the behavioral judgment. The gate checks the `path` resolves, never runs it.
272
+ */
273
+ export declare const script: (path: string) => Verifier;
274
+ /**
275
+ * A telemetry verifier — the named documented harness events the emitted tap records
276
+ * to a local-locus log, judged by reading the field record. Each name must be a
277
+ * documented harness lifecycle event (`InstructionsLoaded`, `Skill`,
278
+ * `UserPromptExpansion`, `PostToolUse`; code.claude.com/docs/en/hooks, retrieved
279
+ * 2026-07-17) — the gate checks each resolves, never records into it.
280
+ */
281
+ export declare const telemetry: (events: readonly string[]) => Verifier;
133
282
  /**
134
283
  * A requirement — a named obligation on the harness. `prose` is the authored
135
- * intent, carried never interpreted; `kind` constrains what may fill it **by
136
- * import** (a value, never a string); `required` is the posture declaration;
137
- * `clauses` are the requirement's own set-/edge-scope demands — ordinary
138
- * [`Clause`] values whose predicates range over the satisfier set
139
- * (`count`/`unique`/`membership`) or its graph neighborhood (`degree`), the
140
- * same four-channel clause as everywhere; `verifiedBy` wires the behavioral
141
- * remainder.
284
+ * intent, carried never interpreted; `kind` constrains what may fill it —
285
+ * either a bare kind-name string or the kind's `KindDefinition`, since the slot
286
+ * carries only the kind's *identity* for coverage resolution, never its field
287
+ * type: a kind whose fields carry required members (skill, hook) assigns here,
288
+ * where `KindDefinition<never>` would have rejected it. `required` is the
289
+ * posture declaration; `clauses` bind to the requirement's **opt-in selection** —
290
+ * ordinary [`Clause`] values, the same four-channel clause as everywhere, judged
291
+ * over that selection by the same algebra a kind's own clauses are judged over its
292
+ * population; `verifier` wires the behavioral remainder as a typed species union.
142
293
  */
143
294
  export interface Requirement {
144
295
  readonly prose: string;
145
- readonly kind?: KindDefinition<never>;
296
+ readonly kind?: string | KindDefinition<any>;
146
297
  readonly required?: boolean;
147
298
  readonly clauses?: readonly Clause[];
148
- readonly verifiedBy?: string;
299
+ readonly verifier?: Verifier;
149
300
  }
150
301
  /** An identity helper — types a requirement literal at the keystroke. */
151
302
  export declare function requirement(init: Requirement): Requirement;
@@ -1,16 +1,30 @@
1
1
  /**
2
2
  * Contracts — clauses and requirements as typed values.
3
3
  * A clause is `predicate · severity · guidance · cite`; a requirement is
4
- * `prose · kind · required · clauses? · verifiedBy?`. Both erase to compiled data
4
+ * `prose · kind · required · clauses? · verifier?`. Both erase to compiled data
5
5
  * at the seam: the author composes typed objects, the engine
6
6
  * consumes their rows. The predicate vocabulary is the closed algebra — a clause
7
7
  * outside it is a squiggle, not a runtime rejection.
8
8
  */
9
- // Node-scope predicates.
10
- /** A field or marker is present. */
9
+ // Node-scope predicates. A value predicate takes an addressing path as its `field` — see
10
+ // `Predicate.field` for the subset an author may spell, and for the key-naming and
11
+ // fieldless exceptions that sit here too.
12
+ /**
13
+ * A field or marker is present. Presence is asked of the path's trailing name segment,
14
+ * so `required("plugins[*].source")` fires once per entry that omits it — and a path
15
+ * ending in `[*]` names elements rather than a key, which is refused.
16
+ */
11
17
  export const required = (field) => ({ key: "required", field });
12
- /** The field's parsed scalar type is as declared. */
13
- export const type = (field) => ({ key: "type", field });
18
+ /**
19
+ * The field's parsed source kind is one of the declared ones. `kinds` is a set: a
20
+ * format that documents a field as `string|array` is gated by `["string", "list"]`,
21
+ * and a one-element `["list"]` is the plain single-kind check.
22
+ */
23
+ export const type = (field, kinds) => ({
24
+ key: "type",
25
+ field,
26
+ value_type: kinds,
27
+ });
14
28
  /** The field's value is at least `n` characters. */
15
29
  export const minLen = (field, n) => ({ key: "min_len", field, args: { min: n } });
16
30
  /** The field's value is at most `n` characters. */
@@ -21,10 +35,42 @@ export const allowedChars = (field, charset) => ({
21
35
  field,
22
36
  charset,
23
37
  });
24
- /** The member's body is at most `n` lines. */
25
- export const maxLines = (n) => ({ key: "max_lines", args: { max: n } });
38
+ /**
39
+ * The field's value holds one named `Shape` from the closed set the engine generates
40
+ * across the seam — the union *is* the vocabulary, so an author picks a member and can
41
+ * spell nothing else. There is no escape to a hand-written pattern, which is the point.
42
+ *
43
+ * - `hyphen-placement` — a hyphen neither leads, trails, nor doubles (`pdf-processing`,
44
+ * never `-pdf`, `pdf-`, or `pdf--processing`). Says nothing about the alphabet; pair it
45
+ * with `allowedChars` where the character set matters.
46
+ * - `no-xml-tags` — the value carries no XML tag (`<br/>`, `</note>`, `<a href="x">`).
47
+ * Prose spelling a comparison (`use when x < y`) is not a tag and does not fire.
48
+ */
49
+ export const shape = (field, shape) => ({ key: "shape", field, shape });
50
+ /**
51
+ * The selected item's **rendered** extent is at most `bound`, in the declared `unit`
52
+ * (`lines` or `characters`). Node-scope and render-side: the measure is the bytes the
53
+ * item contributes to its projection, not the source body a count reads before a
54
+ * reference resolves or a render hook runs.
55
+ */
56
+ export const extent = (unit, bound) => ({
57
+ key: "extent",
58
+ unit,
59
+ args: { max: bound },
60
+ });
26
61
  /** The forbidden keys (e.g. the Cursor `globs`/`alwaysApply` keys) are absent. */
27
62
  export const forbiddenKeys = (keys) => ({ key: "forbidden_keys", keys });
63
+ /**
64
+ * The kind's declared key set is exhaustive — a member carrying any other top-level key
65
+ * is a finding. `forbiddenKeys`' complement: a deny-list names a finite set over an open
66
+ * key space, this closes the space.
67
+ *
68
+ * It takes no arguments, and that is the point: the allow-list is the contract's own
69
+ * `required`/`optional` clauses, so the key set is declared once. Adding `optional("x")`
70
+ * admits `x` with no second edit here — and a contract declaring no key at all fails
71
+ * admissibility rather than indicting every key of every member.
72
+ */
73
+ export const closedKeys = () => ({ key: "closed-keys" });
28
74
  /** The field's value is none of `values` (forbidden values). */
29
75
  export const deny = (field, values) => ({
30
76
  key: "deny",
@@ -32,7 +78,7 @@ export const deny = (field, values) => ({
32
78
  values,
33
79
  });
34
80
  /** The named headings are present. */
35
- export const requireSections = () => ({ key: "require_sections" });
81
+ export const requireSections = (sections) => ({ key: "require_sections", sections });
36
82
  /** The member's name matches its directory. */
37
83
  export const nameMatchesDir = () => ({ key: "name-matches-dir" });
38
84
  /** Names are unique within the artifact kind (a scope-wide identity collision). */
@@ -63,10 +109,42 @@ export const sectionContains = (heading, marker) => ({
63
109
  key: "section_contains",
64
110
  section: { heading, marker },
65
111
  });
66
- // Node-set/edge-scope predicates — a requirement's set-scope demands ride
67
- // these as ordinary clause values, the same four-channel `clause()` shape as
68
- // the node-scope predicates above.
69
- /** The satisfier set's size lies in the inclusive `[min, max]` bound. */
112
+ /** Every glob the field carries parses under globset (brace-expansion aware). */
113
+ export const globValid = (field) => ({ key: "glob-valid", field });
114
+ /**
115
+ * Every mention a selected member authors can fire where its target can be invoked. A
116
+ * target whose `gateField` carries globs is gated — removed from every invocation
117
+ * channel until the agent reads a matching file — so a mention of it is actionable only
118
+ * inside that gate. Fires on a scoped source whose `scopeField` globs are not contained
119
+ * in the target's gate, and on an unscoped source mentioning a gated target.
120
+ *
121
+ * Generic over both ends, hard-coding no kind: the trigger is the target's gate field
122
+ * carrying a value, never its registration set. Containment is *literal* — every source
123
+ * glob must appear verbatim in the gate — since true glob-set containment is
124
+ * undecidable, so it false-fires on a semantically contained narrower glob
125
+ * (`src/**\/*.ts` inside `src/**`). Declare it at advisory severity: a check that can be
126
+ * wrong must not block.
127
+ */
128
+ export const mentionReachable = (scopeField, gateField) => ({
129
+ key: "mention-reachable",
130
+ field: scopeField,
131
+ gate: gateField,
132
+ });
133
+ /**
134
+ * Every edge the member's kind declares is placed by the format that renders the member
135
+ * — a format that omits one renders a contract the prose does not represent. Names no
136
+ * field: the selection is the member's whole incident edge set, at the `each` grain.
137
+ * Decided over the placement `emit` observes while rendering and lowers into the
138
+ * member's `nested_member` row, since the engine never sees a format.
139
+ */
140
+ export const formatPlacesEdges = () => ({ key: "format-places-edges" });
141
+ // Set predicates — they range over the **selection** their clause binds to, not one
142
+ // member's own fields: a kind's `expect` binds them to that kind's whole population
143
+ // (the universal binding), a requirement's `clauses` to its opt-in satisfiers (the
144
+ // existential one). The quantifier is the clause's grain, so the same value says the
145
+ // same thing in either place, riding the same four-channel `clause()` shape as the
146
+ // member-scope predicates above.
147
+ /** The selection's size lies in the inclusive `[min, max]` bound. */
70
148
  export const count = (bounds) => {
71
149
  const args = {};
72
150
  if (bounds.min !== undefined)
@@ -75,15 +153,15 @@ export const count = (bounds) => {
75
153
  args.max = bounds.max;
76
154
  return { key: "count", args };
77
155
  };
78
- /** The field's extracted value does not repeat across the satisfier set. */
156
+ /** The field's extracted value does not repeat across the selection. */
79
157
  export const unique = (field) => ({ key: "unique", field });
80
- /** Every satisfier's `field` value is drawn from a feature over `target`'s own satisfier set. */
158
+ /** Every selected member's `field` value is drawn from a feature over the selection `target` declares. */
81
159
  export const membership = (field, target) => ({
82
160
  key: "membership",
83
161
  field,
84
162
  target,
85
163
  });
86
- /** The in/out edge-count bound every satisfier must land in. At least one direction must be given. */
164
+ /** The in/out edge-count bound every selected member must land in. At least one direction must be given. */
87
165
  export const degree = (bounds) => {
88
166
  const args = {};
89
167
  if (bounds.incoming?.min !== undefined)
@@ -96,10 +174,45 @@ export const degree = (bounds) => {
96
174
  args.outgoing_max = bounds.outgoing.max;
97
175
  return { key: "degree", args };
98
176
  };
177
+ /**
178
+ * A guarded clause — a predicate (restricted to `type` or `enum`) that acts as a
179
+ * guard, with a body of ordinary clauses that fire only where the guard holds.
180
+ * The guard and body share the guard's address binding: the body's field paths
181
+ * evaluate at the concrete element address the guard locates.
182
+ *
183
+ * The guard must be a `type` or `enumOf` predicate, named for the decidable
184
+ * field it addresses. Neither is enforced here; emit validates admissibility.
185
+ *
186
+ * Options for `severity`, `guidance`, and `cite` are supported and follow the
187
+ * same pattern as `clause()`. Default severity is `required`.
188
+ */
189
+ export function when(guard, body, opts) {
190
+ return {
191
+ predicate: { key: "when" },
192
+ severity: opts?.severity ?? "required",
193
+ guidance: opts?.guidance,
194
+ cite: opts?.cite,
195
+ when_guard: guard,
196
+ when_body: body,
197
+ };
198
+ }
99
199
  /** Compose a clause value — a predicate under a declared severity, with optional guidance/cite. */
100
200
  export function clause(predicate, opts) {
101
201
  return { predicate, severity: opts.severity, guidance: opts.guidance, cite: opts.cite };
102
202
  }
203
+ /**
204
+ * A script verifier — a path-resolved reference to the test or CI job that executes
205
+ * the behavioral judgment. The gate checks the `path` resolves, never runs it.
206
+ */
207
+ export const script = (path) => ({ species: "script", path });
208
+ /**
209
+ * A telemetry verifier — the named documented harness events the emitted tap records
210
+ * to a local-locus log, judged by reading the field record. Each name must be a
211
+ * documented harness lifecycle event (`InstructionsLoaded`, `Skill`,
212
+ * `UserPromptExpansion`, `PostToolUse`; code.claude.com/docs/en/hooks, retrieved
213
+ * 2026-07-17) — the gate checks each resolves, never records into it.
214
+ */
215
+ export const telemetry = (events) => ({ species: "telemetry", events });
103
216
  /** An identity helper — types a requirement literal at the keystroke. */
104
217
  export function requirement(init) {
105
218
  return init;
@@ -9,21 +9,107 @@
9
9
  * in lockstep.
10
10
  */
11
11
  import type { Harness } from "./assembly.js";
12
- import type { Declarations, Payload } from "./generated/index.js";
12
+ import type { MentionScope } from "./prose.js";
13
+ import type { Declarations, Payload, RegistrationRow, SettingsRow } from "./generated/index.js";
13
14
  export type { AssemblyFactRow, ClauseRow, Declarations, KindFactRow, RequirementRow, SatisfiesRow, } from "./generated/index.js";
14
15
  /** The stable-sort ordering every declaration row family shares. */
15
16
  export declare function compareStrings(a: string, b: string): number;
17
+ /**
18
+ * One composed embedded value's key in an {@link EdgePlacements} table — its host's
19
+ * `kind:name` address plus the value's own kind and key, the same triple the
20
+ * `nested_member` row it feeds is identified by.
21
+ */
22
+ export declare function placementKey(host: string, kind: string, key: string): string;
23
+ /**
24
+ * Each composed embedded value's placed edge fields, by {@link placementKey} — `emit`'s
25
+ * record of which declared edges each value's format actually rendered (`emit.ts`'s
26
+ * `edgePlacements`). A value with no entry had no format observe it, which is distinct
27
+ * from a format that placed nothing: the row omits the column entirely and the
28
+ * `format-places-edges` clause stays undecided rather than indict a format that never ran.
29
+ */
30
+ export type EdgePlacements = ReadonlyMap<string, readonly string[]>;
31
+ /** One composed embedded value's rendered extent — the line and character count of the
32
+ * block `emit` projected for it ({@link RenderedExtents}), the span an `extent` clause
33
+ * budgets. */
34
+ export interface RenderedExtent {
35
+ readonly lines: number;
36
+ readonly chars: number;
37
+ }
38
+ /**
39
+ * Each composed embedded value's rendered extent, by {@link placementKey} — `emit`'s
40
+ * record of the span it projected for each value (`emit.ts`'s `renderedExtents`). A value
41
+ * with no entry had no format rendered it (a member read off a layout host's source),
42
+ * which the row spells by omitting both span columns rather than a captured zero: an
43
+ * unmeasured member's `extent` stays undecidable, never a zero read as a pass.
44
+ */
45
+ export type RenderedExtents = ReadonlyMap<string, RenderedExtent>;
46
+ /**
47
+ * The `registration` rows — every fields-only registration member (a hook, an MCP server)
48
+ * erased for the manifest write face, kind-then-key sorted so double emit is byte-stable.
49
+ * Each carries its identity (`kind`/`key`), its collection address (`manifest`/`keyPath`,
50
+ * the wire's snake_case `key_path`), and its folded typed fields — the entry value the
51
+ * engine's write face places under `key`. The one source `emit.ts`'s public
52
+ * {@link RegistrationFact} view also maps from, so the seam and the `EmitResult` sibling
53
+ * cannot disagree on what a manifest carries.
54
+ *
55
+ * # Throws
56
+ * If a fields-only member declares no collection address — it surfaces in no host manifest.
57
+ */
58
+ export declare function registrationRows(harness: Harness): RegistrationRow[];
59
+ /**
60
+ * The synthesized tap-hook `registration` rows — one deduped `hooks.<Event>`
61
+ * registration per (lifecycle event, matcher) any telemetry verifier names. Scans the
62
+ * same requirement sources {@link requirementRows} reads (assembly `require` ∪ each
63
+ * member's `requires`), keeps the telemetry-species verifiers ({@link Verifier}), and
64
+ * unions the lifecycle events they name into one dumb registration apiece: the tap
65
+ * records every fire and read time joins raw events to members, so however many
66
+ * verifiers name an event it takes exactly one hook — the derived-aggregate precedent
67
+ * the permission union sets ({@link permissionUnion}). Each row runs {@link TAP_COMMAND}
68
+ * under the event's documented matcher ({@link TELEMETRY_EVENT_HOOKS}); an event-name
69
+ * outside that table is the roster's inadmissibility finding, never a row.
70
+ */
71
+ export declare function tapHookRows(harness: Harness): RegistrationRow[];
72
+ /**
73
+ * The `settings` rows — the assembly's harness-level residual settings keys, each folded
74
+ * into the settings.json manifest's opaque residue at emit. Key-sorted so double emit is
75
+ * byte-stable. Seam-inbound: the value lives in the projected manifest, never the lock.
76
+ */
77
+ export declare function settingsRows(harness: Harness): SettingsRow[];
16
78
  /** Every requirement name a `satisfies` claim may fill — assembly `require` ∪ member `requires`. */
17
79
  export declare function declaredRequirements(harness: Harness): Set<string>;
18
80
  /**
19
81
  * Every address a mention may name — declared requirement names ∪ each member's
20
- * `kind:name`. Shared by `emit.ts` (a member-level `Text` body's mentions) and
21
- * this module (an embedded member's `Text` leaves) — the one resolution-check
22
- * set, so a leaf mention and a member mention are held to the identical bar.
82
+ * `kind:name` ∪ each `blocks()`-declared embedded member's host-scoped
83
+ * `<host-kind>:<host-name>/<kind>/<key>` address. Shared by `emit.ts` (a
84
+ * member-level `Text` body's mentions) and this module (an embedded member's
85
+ * `Text` leaves) — the one resolution-check set, so a leaf mention and a member
86
+ * mention are held to the identical bar. The embedded address is host-scoped,
87
+ * never a flat `<kind>:<key>` — flat would force corpus-wide key uniqueness on
88
+ * embedded kinds.
23
89
  */
24
90
  export declare function declaredAddresses(harness: Harness): Set<string>;
25
- /** Compile a harness into its seven declaration families — the erased program. */
26
- export declare function compileDeclarations(harness: Harness): Declarations;
91
+ /**
92
+ * Every discoverable (`at`-locus) kind the program declares — the deferral signal a
93
+ * dangling mention is measured against (`prose.ts`'s `defersToGate`): a mention naming
94
+ * one of these whose member is not a composed value defers to `check`, while a mention
95
+ * naming no declared kind refuses at emit. Member kinds ∪ `expect` kinds; an embedded
96
+ * kind is excluded — its members are composed within a host, never discovered, so a
97
+ * flat `kind:name` mention of one has no discovery locus to defer to.
98
+ */
99
+ export declare function declaredAtLocusKinds(harness: Harness): Set<string>;
100
+ /** The full {@link MentionScope} the program resolves a mention against — its addresses and its deferral kinds. */
101
+ export declare function mentionScope(harness: Harness): MentionScope;
102
+ /**
103
+ * Compile a harness into its seven declaration families — the erased program.
104
+ *
105
+ * `placements` and `extents` are `emit`'s record of what each embedded value's format
106
+ * rendered (`emit.ts`'s `edgePlacements`) and the span it spanned (`renderedExtents`); this
107
+ * pass compiles declarations and never renders, so it observes neither itself. Omitted,
108
+ * every `nested_member` row omits its `placed_edges`/`rendered_lines`/`rendered_chars`
109
+ * columns — honest (nothing observed a render) but undecidable for a `format-places-edges`
110
+ * or `extent` clause, so a whole compile goes through `emit`, never this alone.
111
+ */
112
+ export declare function compileDeclarations(harness: Harness, placements?: EdgePlacements, extents?: RenderedExtents): Declarations;
27
113
  /** The SDK's pinned engine/interchange version — the JSON pipe rides it in lockstep. */
28
114
  export declare const SEAM_VERSION = 2;
29
115
  /**