kibi-cli 2.32.0 → 2.36.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/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +5 -1
- package/dist/commands/check-generated.d.ts +5 -1
- package/dist/commands/check-generated.d.ts.map +1 -1
- package/dist/commands/check-generated.js +24 -35
- package/dist/commands/init-helpers.d.ts.map +1 -1
- package/dist/commands/init-helpers.js +8 -5
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +23 -5
- package/dist/commands/sync/manifest.d.ts +10 -1
- package/dist/commands/sync/manifest.d.ts.map +1 -1
- package/dist/commands/sync/manifest.js +87 -14
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +19 -0
- package/dist/extractors/markdown.d.ts +1 -1
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/symbol-coordinates.js +2 -2
- package/dist/extractors/symbols-coordinator.d.ts +2 -4
- package/dist/extractors/symbols-coordinator.d.ts.map +1 -1
- package/dist/extractors/symbols-coordinator.js +1 -2
- package/dist/operations/migration/proof-contract-claims.d.ts +23 -10
- package/dist/operations/migration/proof-contract-claims.d.ts.map +1 -1
- package/dist/operations/migration/proof-contract-claims.js +35 -2
- package/dist/operations/migration/schema6.d.ts.map +1 -1
- package/dist/operations/migration/schema6.js +2 -4
- package/dist/operations/migration/symbol-coordinates-refresh.d.ts +3 -2
- package/dist/operations/migration/symbol-coordinates-refresh.d.ts.map +1 -1
- package/dist/operations/migration/symbol-coordinates-refresh.js +4 -3
- package/dist/operations/migration/untrack-symbol-coordinates.d.ts +23 -0
- package/dist/operations/migration/untrack-symbol-coordinates.d.ts.map +1 -0
- package/dist/operations/migration/untrack-symbol-coordinates.js +67 -0
- package/dist/operations/modeling/requirement-modeler.d.ts.map +1 -1
- package/dist/operations/modeling/requirement-modeler.js +48 -1
- package/dist/operations/modeling/requirement-types.d.ts +2 -1
- package/dist/operations/modeling/requirement-types.d.ts.map +1 -1
- package/dist/operations/modeling/requirement-utils.d.ts +1 -1
- package/dist/operations/modeling/requirement-utils.d.ts.map +1 -1
- package/dist/operations/modeling/requirement-utils.js +8 -1
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +39 -20
- package/dist/operations/proof/claim-bindings.d.ts +18 -0
- package/dist/operations/proof/claim-bindings.d.ts.map +1 -1
- package/dist/operations/proof/claim-bindings.js +157 -4
- package/dist/operations/proof/code-certificates.d.ts +34 -14
- package/dist/operations/proof/code-certificates.d.ts.map +1 -1
- package/dist/operations/proof/code-certificates.js +266 -157
- package/dist/operations/proof/code-models.d.ts +96 -0
- package/dist/operations/proof/code-models.d.ts.map +1 -0
- package/dist/operations/proof/code-models.js +601 -0
- package/dist/operations/proof/code-runner.d.ts +40 -0
- package/dist/operations/proof/code-runner.d.ts.map +1 -0
- package/dist/operations/proof/code-runner.js +164 -0
- package/dist/operations/proof/code-scope.d.ts +3 -0
- package/dist/operations/proof/code-scope.d.ts.map +1 -1
- package/dist/operations/proof/code-scope.js +26 -2
- package/dist/operations/proof/ingest-proof.d.ts.map +1 -1
- package/dist/operations/proof/ingest-proof.js +2 -1
- package/dist/operations/proof/regular-language.d.ts +89 -0
- package/dist/operations/proof/regular-language.d.ts.map +1 -0
- package/dist/operations/proof/regular-language.js +943 -0
- package/dist/operations/proof/source-code-readers.d.ts +12 -0
- package/dist/operations/proof/source-code-readers.d.ts.map +1 -0
- package/dist/operations/proof/source-code-readers.js +699 -0
- package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analyze-prose.js +2 -1
- package/dist/operations/semantic-advisor/strict-count-rules.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/strict-count-rules.js +8 -2
- package/dist/operations/semantic-advisor/strict-rules.d.ts +8 -0
- package/dist/operations/semantic-advisor/strict-rules.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/strict-rules.js +231 -1
- package/dist/operations/semantic-advisor/types.d.ts +1 -1
- package/dist/operations/semantic-advisor/types.d.ts.map +1 -1
- package/dist/prolog.d.ts.map +1 -1
- package/dist/prolog.js +13 -3
- package/dist/public/operations/catalog.d.ts +156 -13
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/evidence-floor.js +1 -1
- package/dist/public/operations/proof-contract-claims.js +1 -1
- package/dist/public/operations/specs/composite.d.ts +16 -3
- package/dist/public/operations/specs/composite.d.ts.map +1 -1
- package/dist/public/operations/specs/modeling.d.ts +16 -3
- package/dist/public/operations/specs/modeling.d.ts.map +1 -1
- package/dist/public/operations/specs/modeling.js +22 -3
- package/dist/public/operations/specs/mutation-schemas.d.ts +140 -10
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +14 -3
- package/dist/public/operations/specs/upsert.d.ts +140 -10
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/proof-certificates.d.ts +75 -1
- package/dist/public/proof-certificates.d.ts.map +1 -1
- package/dist/public/proof-certificates.js +212 -0
- package/dist/public/proof-protocol.d.ts +143 -10
- package/dist/public/proof-protocol.d.ts.map +1 -1
- package/dist/public/proof-protocol.js +301 -16
- package/dist/public/proof-receipt.d.ts +4 -3
- package/dist/public/proof-receipt.d.ts.map +1 -1
- package/dist/public/proof-receipt.js +6 -1
- package/dist/public/proof-sources.d.ts +102 -0
- package/dist/public/proof-sources.d.ts.map +1 -0
- package/dist/public/proof-sources.js +1292 -0
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +21 -1
- package/dist/public/skills/kibi-commit-review/SKILL.md +8 -8
- package/dist/public/skills/kibi-commit-review/resources/staged-gate.md +6 -6
- package/dist/public/skills/kibi-decisions/SKILL.md +5 -2
- package/dist/public/skills/kibi-decisions/resources/decision-records.md +4 -1
- package/dist/public/skills/kibi-freshness/SKILL.md +2 -2
- package/dist/public/skills/kibi-traceability/SKILL.md +3 -2
- package/dist/public/skills/kibi-usage/SKILL.md +5 -3
- package/dist/public/skills/kibi-usage/resources/proof.md +105 -9
- package/dist/report/html-report.css +45 -10
- package/dist/report/html-report.d.ts.map +1 -1
- package/dist/report/html-report.js +74 -17
- package/dist/report/report-view.d.ts +1 -1
- package/dist/report/report-view.d.ts.map +1 -1
- package/dist/report/report-view.js +1 -0
- package/dist/schemas/entity.schema.json +199 -8
- package/dist/traceability/evidence-model.d.ts +13 -12
- package/dist/traceability/evidence-model.d.ts.map +1 -1
- package/dist/traceability/evidence-model.js +1 -1
- package/dist/traceability/staged-diagnostics.d.ts.map +1 -1
- package/dist/traceability/staged-diagnostics.js +24 -20
- package/dist/traceability/staged-impact-contract.d.ts +4 -4
- package/dist/traceability/staged-impact-contract.js +9 -9
- package/dist/traceability/staged-symbols-manifest.d.ts +11 -3
- package/dist/traceability/staged-symbols-manifest.d.ts.map +1 -1
- package/dist/traceability/staged-symbols-manifest.js +47 -140
- package/dist/types/entities.d.ts +1 -1
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.d.ts +1 -1
- package/dist/utils/rule-registry.generated.js +1 -1
- package/dist/utils/schema-version.d.ts +1 -1
- package/dist/utils/schema-version.d.ts.map +1 -1
- package/dist/utils/schema-version.js +3 -1
- package/dist/utils/strict-modeling.d.ts +3 -2
- package/dist/utils/strict-modeling.d.ts.map +1 -1
- package/dist/utils/strict-modeling.js +37 -4
- package/dist/workspace-cwd.d.ts +15 -0
- package/dist/workspace-cwd.d.ts.map +1 -0
- package/dist/workspace-cwd.js +86 -0
- package/package.json +2 -2
- package/schema/validation.pl +3 -1
- package/src/public/operations/evidence-floor.ts +1 -1
- package/src/public/operations/proof-contract-claims.ts +1 -1
- package/src/public/operations/specs/modeling.ts +24 -5
- package/src/public/operations/specs/mutation-schemas.ts +14 -3
- package/src/public/proof-certificates.ts +296 -1
- package/src/public/proof-protocol-types.d.ts +54 -2
- package/src/public/proof-protocol.ts +396 -20
- package/src/public/proof-receipt.ts +8 -2
- package/src/public/proof-sources.ts +1656 -0
- package/src/public/schemas/entity.ts +32 -2
- package/src/public/skills/kibi-commit-review/SKILL.md +8 -8
- package/src/public/skills/kibi-commit-review/resources/staged-gate.md +6 -6
- package/src/public/skills/kibi-decisions/SKILL.md +5 -2
- package/src/public/skills/kibi-decisions/resources/decision-records.md +4 -1
- package/src/public/skills/kibi-freshness/SKILL.md +2 -2
- package/src/public/skills/kibi-traceability/SKILL.md +3 -2
- package/src/public/skills/kibi-usage/SKILL.md +5 -3
- package/src/public/skills/kibi-usage/resources/proof.md +105 -9
- package/src/schemas/entity.schema.json +199 -8
- package/dist/traceability/reviewed-coordinate-refresh.d.ts +0 -10
- package/dist/traceability/reviewed-coordinate-refresh.d.ts.map +0 -1
- package/dist/traceability/reviewed-coordinate-refresh.js +0 -49
|
@@ -94,14 +94,66 @@ export type ProofContract = Readonly<{
|
|
|
94
94
|
| "exhaustive"
|
|
95
95
|
| "typecheck"
|
|
96
96
|
| "arithmetic"
|
|
97
|
-
| "smt"
|
|
97
|
+
| "smt"
|
|
98
|
+
| "rule"
|
|
99
|
+
| "state_machine"
|
|
100
|
+
| "regex"
|
|
101
|
+
| "source";
|
|
98
102
|
domain_source?: Readonly<{ symbol_id: string; export?: string }>;
|
|
99
103
|
witness?: Readonly<{ path: string }>;
|
|
100
104
|
constraint_source?: Readonly<{ fact_ids: readonly string[] }>;
|
|
101
|
-
value_source?: readonly
|
|
105
|
+
value_source?: readonly (
|
|
106
|
+
| Readonly<{
|
|
107
|
+
symbol_id: string;
|
|
108
|
+
export?: string;
|
|
109
|
+
/** value (default): the export is a number; count: the size of a list, set, map or object. */
|
|
110
|
+
measure?: "value" | "count";
|
|
111
|
+
}>
|
|
112
|
+
| Readonly<{
|
|
113
|
+
/** A project source whose members Kibi counts. */
|
|
114
|
+
source: ProofSourceSpec;
|
|
115
|
+
measure: "count";
|
|
116
|
+
}>
|
|
117
|
+
)[];
|
|
102
118
|
proves?: readonly string[];
|
|
119
|
+
predicate_source?: Readonly<
|
|
120
|
+
Record<
|
|
121
|
+
string,
|
|
122
|
+
Readonly<{
|
|
123
|
+
symbol_id: string;
|
|
124
|
+
export?: string;
|
|
125
|
+
/** The predicate is a test harness driving these code symbols. */
|
|
126
|
+
harness_for?: readonly string[];
|
|
127
|
+
}>
|
|
128
|
+
>
|
|
129
|
+
>;
|
|
130
|
+
domains?: Readonly<
|
|
131
|
+
Record<
|
|
132
|
+
string,
|
|
133
|
+
| Readonly<{ symbol_id: string; export?: string }>
|
|
134
|
+
| Readonly<{ source: ProofSourceSpec }>
|
|
135
|
+
>
|
|
136
|
+
>;
|
|
137
|
+
initial_source?: Readonly<{ symbol_id: string; export?: string }>;
|
|
138
|
+
pattern_source?: Readonly<{ symbol_id: string; export?: string }>;
|
|
139
|
+
/** kind source: the project source Kibi reads. */
|
|
140
|
+
source?: ProofSourceSpec;
|
|
103
141
|
}>;
|
|
104
142
|
|
|
143
|
+
/** A project source a source proof, a rule domain or a count reads; see proof-sources. */
|
|
144
|
+
export type ProofSourceSpec = Readonly<Record<string, unknown>> &
|
|
145
|
+
Readonly<{
|
|
146
|
+
reader:
|
|
147
|
+
| "json"
|
|
148
|
+
| "yaml"
|
|
149
|
+
| "glob"
|
|
150
|
+
| "openapi"
|
|
151
|
+
| "references"
|
|
152
|
+
| "schema"
|
|
153
|
+
| "routes"
|
|
154
|
+
| "validator";
|
|
155
|
+
}>;
|
|
156
|
+
|
|
105
157
|
export type ProofBinding = Readonly<{
|
|
106
158
|
symbol_id: string;
|
|
107
159
|
target: string;
|
|
@@ -70,8 +70,11 @@ export const SUCCESS_POLICIES = [
|
|
|
70
70
|
/**
|
|
71
71
|
* What a proof contract's checker establishes. Runner kinds (e2e, example,
|
|
72
72
|
* property) sample cases and support tested evidence; certificate kinds
|
|
73
|
-
* (exhaustive, typecheck, arithmetic, smt
|
|
74
|
-
* proved evidence once Kibi re-checks
|
|
73
|
+
* (exhaustive, typecheck, arithmetic, smt, rule, state_machine, regex,
|
|
74
|
+
* source) cover every case and support proved evidence once Kibi re-checks
|
|
75
|
+
* the certificate the run left. A source certificate is Kibi's own read of a
|
|
76
|
+
* project source (a JSON or YAML file, a glob, an OpenAPI document, the
|
|
77
|
+
* references the code makes, a data schema, a route table, a validator).
|
|
75
78
|
*/
|
|
76
79
|
// implements REQ-kibi-code-proof-kinds
|
|
77
80
|
export const PROOF_KINDS = [
|
|
@@ -82,14 +85,22 @@ export const PROOF_KINDS = [
|
|
|
82
85
|
"typecheck",
|
|
83
86
|
"arithmetic",
|
|
84
87
|
"smt",
|
|
88
|
+
"rule",
|
|
89
|
+
"state_machine",
|
|
90
|
+
"regex",
|
|
91
|
+
"source",
|
|
85
92
|
] as const;
|
|
86
93
|
|
|
87
|
-
// implements REQ-kibi-code-proof-kinds
|
|
94
|
+
// implements REQ-kibi-code-proof-kinds, REQ-kibi-non-numeric-proof-kinds, REQ-kibi-source-proof-kinds
|
|
88
95
|
export const CERTIFICATE_PROOF_KINDS = [
|
|
89
96
|
"exhaustive",
|
|
90
97
|
"typecheck",
|
|
91
98
|
"arithmetic",
|
|
92
99
|
"smt",
|
|
100
|
+
"rule",
|
|
101
|
+
"state_machine",
|
|
102
|
+
"regex",
|
|
103
|
+
"source",
|
|
93
104
|
] as const;
|
|
94
105
|
|
|
95
106
|
// implements REQ-kibi-code-proof-kinds
|
|
@@ -127,6 +138,12 @@ import type {
|
|
|
127
138
|
ProofResult,
|
|
128
139
|
ProofRunArtifact,
|
|
129
140
|
} from "./proof-protocol-types.js";
|
|
141
|
+
import {
|
|
142
|
+
SOURCE_READERS,
|
|
143
|
+
type SourceSpec,
|
|
144
|
+
normalizeSourceSpec,
|
|
145
|
+
sourceSpecErrors,
|
|
146
|
+
} from "./proof-sources.js";
|
|
130
147
|
|
|
131
148
|
export const PROOF_RESULT_SCHEMA = {
|
|
132
149
|
type: "object",
|
|
@@ -262,6 +279,57 @@ export const PROOF_RUN_ARTIFACT_SCHEMA = {
|
|
|
262
279
|
additionalProperties: false,
|
|
263
280
|
} as const;
|
|
264
281
|
|
|
282
|
+
const SOURCE_REFERENCE_SCHEMA = {
|
|
283
|
+
type: "object",
|
|
284
|
+
required: ["symbol_id"],
|
|
285
|
+
properties: {
|
|
286
|
+
symbol_id: { type: "string", minLength: 1 },
|
|
287
|
+
export: { type: "string", minLength: 1 },
|
|
288
|
+
},
|
|
289
|
+
additionalProperties: false,
|
|
290
|
+
} as const;
|
|
291
|
+
|
|
292
|
+
// implements REQ-kibi-source-proof-kinds
|
|
293
|
+
const SOURCE_SPEC_SCHEMA = {
|
|
294
|
+
type: "object",
|
|
295
|
+
description:
|
|
296
|
+
"A project source Kibi reads by itself. reader json or yaml: {file, path?, select?: keys|values|items}. glob: {pattern, capture?, ignore?} (capture true reads what each * matched). openapi: {file, select?: operations|unsecured_operations|security_schemes|responses}. references: {files, extract: env|imports|calls|string_args|thrown|property, callee?, key?, ignore?}. schema: {format: drizzle|prisma|sql, file (drizzle, prisma) or files (sql migrations), exports?, table?, select?: tables|columns|required_columns|nullable_columns|foreign_keys}. routes: {file, export, framework?: hono|express, path_prefix?, names_from?, select?: routes|middleware}. validator: {file, export, select?: fields|required_fields|optional_fields}. Paths are repository-relative. A member Kibi cannot read statically fails the read with its location.",
|
|
297
|
+
required: ["reader"],
|
|
298
|
+
properties: {
|
|
299
|
+
reader: { type: "string", enum: [...SOURCE_READERS] },
|
|
300
|
+
},
|
|
301
|
+
additionalProperties: true,
|
|
302
|
+
} as const;
|
|
303
|
+
|
|
304
|
+
const SOURCE_DOMAIN_SCHEMA = {
|
|
305
|
+
type: "object",
|
|
306
|
+
required: ["source"],
|
|
307
|
+
properties: { source: SOURCE_SPEC_SCHEMA },
|
|
308
|
+
additionalProperties: false,
|
|
309
|
+
} as const;
|
|
310
|
+
|
|
311
|
+
const PREDICATE_SOURCE_SCHEMA = {
|
|
312
|
+
type: "object",
|
|
313
|
+
required: ["symbol_id"],
|
|
314
|
+
properties: {
|
|
315
|
+
symbol_id: { type: "string", minLength: 1 },
|
|
316
|
+
export: {
|
|
317
|
+
type: "string",
|
|
318
|
+
minLength: 1,
|
|
319
|
+
description:
|
|
320
|
+
"The exported function's name in the symbol's source file. Without it Kibi reads the export named by the symbol's title.",
|
|
321
|
+
},
|
|
322
|
+
harness_for: {
|
|
323
|
+
type: "array",
|
|
324
|
+
minItems: 1,
|
|
325
|
+
items: { type: "string", minLength: 1 },
|
|
326
|
+
description:
|
|
327
|
+
"The predicate is a test harness that decides the predicate by driving these code symbols (for example by calling the handler with each role). The symbols must be covered_by the test; a claim the harness proves is bound with scope harness.",
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
additionalProperties: false,
|
|
331
|
+
} as const;
|
|
332
|
+
|
|
265
333
|
export const PROOF_CONTRACT_SCHEMA = {
|
|
266
334
|
type: "object",
|
|
267
335
|
description:
|
|
@@ -289,12 +357,16 @@ export const PROOF_CONTRACT_SCHEMA = {
|
|
|
289
357
|
type: "string",
|
|
290
358
|
enum: [...PROOF_KINDS],
|
|
291
359
|
description:
|
|
292
|
-
"What the checker establishes; absent means e2e. exhaustive, typecheck, arithmetic and
|
|
360
|
+
"What the checker establishes; absent means e2e. exhaustive, typecheck, arithmetic, smt, rule, state_machine and regex must leave a kibi.code-certificate.v1 that Kibi re-checks before the receipt counts as proved. source reads the contract's source itself: the run may leave {version, kind: source, test_id, source} or nothing, and Kibi stores its own read as the certificate.",
|
|
361
|
+
},
|
|
362
|
+
source: {
|
|
363
|
+
...SOURCE_SPEC_SCHEMA,
|
|
364
|
+
description: `source: the project source a source proof reads. ${SOURCE_SPEC_SCHEMA.description}`,
|
|
293
365
|
},
|
|
294
366
|
domain_source: {
|
|
295
367
|
type: "object",
|
|
296
368
|
description:
|
|
297
|
-
"exhaustive and typecheck: the symbol that defines the finite domain. The proof must import it from its source file; a hand-listed domain downgrades the receipt to example. Kibi reads the export named `export`, or the symbol's title when `export` is absent.",
|
|
369
|
+
"exhaustive and typecheck: the symbol that defines the finite domain (typecheck: also the type whose fields a required_fields fact names). state_machine: the transition table or next-state function. The proof must import it from its source file; a hand-listed domain downgrades the receipt to example. Kibi reads the export named `export`, or the symbol's title when `export` is absent.",
|
|
298
370
|
required: ["symbol_id"],
|
|
299
371
|
properties: {
|
|
300
372
|
symbol_id: { type: "string", minLength: 1 },
|
|
@@ -318,7 +390,7 @@ export const PROOF_CONTRACT_SCHEMA = {
|
|
|
318
390
|
proves: {
|
|
319
391
|
type: "array",
|
|
320
392
|
description:
|
|
321
|
-
"Certificate kinds: the requirement claim keys (CLAIM-...) this certificate proves. Each must be a modeled claim of a current requirement the test reaches through its scenarios. Kibi derives what the certificate must establish from the claim's grounding fact (a set fact for exhaustive or typecheck, a numeric fact for arithmetic or smt); a claim with no such derivation is only attested and never counts as proved.",
|
|
393
|
+
"Certificate kinds: the requirement claim keys (CLAIM-...) this certificate proves. Each must be a modeled claim of a current requirement the test reaches through its scenarios. Kibi derives what the certificate must establish from the claim's grounding fact (a set fact for exhaustive or typecheck, a numeric fact for arithmetic or smt, a rule, predicate or set fact for rule and state_machine, a string fact for regex); a claim with no such derivation is only attested and never counts as proved.",
|
|
322
394
|
minItems: 1,
|
|
323
395
|
items: { type: "string", pattern: "^CLAIM-" },
|
|
324
396
|
uniqueItems: true,
|
|
@@ -326,18 +398,50 @@ export const PROOF_CONTRACT_SCHEMA = {
|
|
|
326
398
|
value_source: {
|
|
327
399
|
type: "array",
|
|
328
400
|
description:
|
|
329
|
-
"arithmetic and smt: code constants the assumptions read. Kibi evaluates each export at ingest and requires the certificate to assume the variable equals that value, so the proof is about the code and not only the knowledge base.",
|
|
401
|
+
"arithmetic and smt: code constants the assumptions read. Kibi evaluates each export at ingest and requires the certificate to assume the variable equals that value, so the proof is about the code and not only the knowledge base. With measure count the value is the size of a list, set, map or object export, so a count claim reads the collection itself. An entry {source, measure: count} counts the members Kibi reads from a project source (routes, tables, environment variables).",
|
|
330
402
|
minItems: 1,
|
|
331
403
|
items: {
|
|
332
404
|
type: "object",
|
|
333
|
-
required: ["symbol_id"],
|
|
334
405
|
properties: {
|
|
335
406
|
symbol_id: { type: "string", minLength: 1 },
|
|
336
407
|
export: { type: "string", minLength: 1 },
|
|
408
|
+
source: SOURCE_SPEC_SCHEMA,
|
|
409
|
+
measure: {
|
|
410
|
+
type: "string",
|
|
411
|
+
enum: ["value", "count"],
|
|
412
|
+
description:
|
|
413
|
+
"value (default for an export): the export is a number. count (the only measure of a source): the number of members of a list, set, map or object export, or of a source.",
|
|
414
|
+
},
|
|
337
415
|
},
|
|
338
416
|
additionalProperties: false,
|
|
339
417
|
},
|
|
340
418
|
},
|
|
419
|
+
predicate_source: {
|
|
420
|
+
type: "object",
|
|
421
|
+
description:
|
|
422
|
+
"rule: the code function behind each predicate a claim's rule, predicate or set fact names, keyed by predicate name. Each export takes the predicate's arguments in order and returns a boolean; Kibi calls it on every combination of its argument domains.",
|
|
423
|
+
minProperties: 1,
|
|
424
|
+
additionalProperties: PREDICATE_SOURCE_SCHEMA,
|
|
425
|
+
},
|
|
426
|
+
domains: {
|
|
427
|
+
type: "object",
|
|
428
|
+
description:
|
|
429
|
+
"rule: the finite domain of each argument type, keyed by type name (an array, Set, Map or object export, or a Python list, set, dict or Enum), or {source} for the members Kibi reads from a project source (every route, every table, every environment variable). state_machine with a next-state function: the `state` and `event` domains it is called on.",
|
|
430
|
+
minProperties: 1,
|
|
431
|
+
additionalProperties: {
|
|
432
|
+
anyOf: [SOURCE_REFERENCE_SCHEMA, SOURCE_DOMAIN_SCHEMA],
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
initial_source: {
|
|
436
|
+
...SOURCE_REFERENCE_SCHEMA,
|
|
437
|
+
description:
|
|
438
|
+
"state_machine: the export holding the initial state (or states), needed for initial_states and reachable_states facts.",
|
|
439
|
+
},
|
|
440
|
+
pattern_source: {
|
|
441
|
+
...SOURCE_REFERENCE_SCHEMA,
|
|
442
|
+
description:
|
|
443
|
+
"regex: the export holding the code's pattern (a RegExp, or a Python re.Pattern) or string constant that a string fact is about.",
|
|
444
|
+
},
|
|
341
445
|
constraint_source: {
|
|
342
446
|
type: "object",
|
|
343
447
|
description:
|
|
@@ -751,29 +855,55 @@ function proofContractKindErrors(contract: Record<string, unknown>): string[] {
|
|
|
751
855
|
);
|
|
752
856
|
const valueSource = contract.value_source;
|
|
753
857
|
if (valueSource !== undefined) {
|
|
858
|
+
if (Array.isArray(valueSource))
|
|
859
|
+
valueSource.forEach((entry, index) => {
|
|
860
|
+
const row = record(entry);
|
|
861
|
+
if (row === null || row.source === undefined) return;
|
|
862
|
+
errors.push(
|
|
863
|
+
...sourceSpecErrors(
|
|
864
|
+
row.source,
|
|
865
|
+
`proof_contract.value_source[${index}].source`,
|
|
866
|
+
),
|
|
867
|
+
);
|
|
868
|
+
if (row.symbol_id !== undefined || row.export !== undefined)
|
|
869
|
+
errors.push(
|
|
870
|
+
`proof_contract.value_source[${index}] names a source, so it takes no symbol_id or export`,
|
|
871
|
+
);
|
|
872
|
+
if (row.measure !== undefined && row.measure !== "count")
|
|
873
|
+
errors.push(
|
|
874
|
+
`proof_contract.value_source[${index}].measure must be count for a source: Kibi counts the members it reads`,
|
|
875
|
+
);
|
|
876
|
+
});
|
|
754
877
|
if (
|
|
755
878
|
!Array.isArray(valueSource) ||
|
|
756
879
|
valueSource.length === 0 ||
|
|
757
880
|
!valueSource.every((entry) => {
|
|
758
881
|
const row = record(entry);
|
|
882
|
+
if (row !== null && row.source !== undefined) return true;
|
|
759
883
|
return (
|
|
760
884
|
row !== null &&
|
|
761
885
|
nonEmptyString(row.symbol_id) &&
|
|
762
886
|
(row.export === undefined || nonEmptyString(row.export)) &&
|
|
887
|
+
(row.measure === undefined ||
|
|
888
|
+
row.measure === "value" ||
|
|
889
|
+
row.measure === "count") &&
|
|
763
890
|
Object.keys(row).every(
|
|
764
|
-
(key) =>
|
|
891
|
+
(key) =>
|
|
892
|
+
key === "symbol_id" || key === "export" || key === "measure",
|
|
765
893
|
)
|
|
766
894
|
);
|
|
767
895
|
})
|
|
768
896
|
)
|
|
769
897
|
errors.push(
|
|
770
|
-
"proof_contract.value_source must be [{symbol_id, export
|
|
898
|
+
"proof_contract.value_source must be [{symbol_id, export?, measure?: value|count} or {source, measure?: count}] naming the code constants or project sources the assumptions read",
|
|
771
899
|
);
|
|
772
900
|
else if (kind !== "arithmetic" && kind !== "smt")
|
|
773
901
|
errors.push(
|
|
774
902
|
`proof_contract.value_source applies only to kind arithmetic or smt, not ${String(kind ?? "e2e")}`,
|
|
775
903
|
);
|
|
776
904
|
}
|
|
905
|
+
errors.push(...nonNumericContractErrors(contract));
|
|
906
|
+
errors.push(...sourceContractErrors(contract));
|
|
777
907
|
const proves = contract.proves;
|
|
778
908
|
if (proves !== undefined) {
|
|
779
909
|
if (
|
|
@@ -789,12 +919,164 @@ function proofContractKindErrors(contract: Record<string, unknown>): string[] {
|
|
|
789
919
|
);
|
|
790
920
|
else if (!isCertificateProofKind(kind))
|
|
791
921
|
errors.push(
|
|
792
|
-
`proof_contract.proves applies only to certificate kinds (
|
|
922
|
+
`proof_contract.proves applies only to certificate kinds (${CERTIFICATE_PROOF_KINDS.join(", ")}), not ${String(kind ?? "e2e")}`,
|
|
793
923
|
);
|
|
794
924
|
}
|
|
795
925
|
return errors;
|
|
796
926
|
}
|
|
797
927
|
|
|
928
|
+
function isSourceReference(value: unknown): boolean {
|
|
929
|
+
const row = record(value);
|
|
930
|
+
return (
|
|
931
|
+
row !== null &&
|
|
932
|
+
nonEmptyString(row.symbol_id) &&
|
|
933
|
+
(row.export === undefined || nonEmptyString(row.export)) &&
|
|
934
|
+
Object.keys(row).every((key) => key === "symbol_id" || key === "export")
|
|
935
|
+
);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
function isSourceMap(
|
|
939
|
+
value: unknown,
|
|
940
|
+
accepts: (entry: unknown) => boolean = isSourceReference,
|
|
941
|
+
): boolean {
|
|
942
|
+
const row = record(value);
|
|
943
|
+
return (
|
|
944
|
+
row !== null &&
|
|
945
|
+
Object.keys(row).length > 0 &&
|
|
946
|
+
Object.entries(row).every(
|
|
947
|
+
([key, entry]) => key.trim() !== "" && accepts(entry),
|
|
948
|
+
)
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
function isPredicateReference(value: unknown): boolean {
|
|
953
|
+
const row = record(value);
|
|
954
|
+
if (row === null || row.harness_for === undefined)
|
|
955
|
+
return isSourceReference(value);
|
|
956
|
+
const { harness_for: harness, ...reference } = row;
|
|
957
|
+
return (
|
|
958
|
+
isSourceReference(reference) &&
|
|
959
|
+
Array.isArray(harness) &&
|
|
960
|
+
harness.length > 0 &&
|
|
961
|
+
harness.every(nonEmptyString)
|
|
962
|
+
);
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
function isSourceDomain(value: unknown): boolean {
|
|
966
|
+
const row = record(value);
|
|
967
|
+
return (
|
|
968
|
+
row !== null && Object.keys(row).length === 1 && row.source !== undefined
|
|
969
|
+
);
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
/**
|
|
973
|
+
* The source kind and the source-backed rule domains: a well-formed source
|
|
974
|
+
* spec, required for kind source and only there.
|
|
975
|
+
*/
|
|
976
|
+
// implements REQ-kibi-source-proof-kinds
|
|
977
|
+
function sourceContractErrors(contract: Record<string, unknown>): string[] {
|
|
978
|
+
const errors: string[] = [];
|
|
979
|
+
const kind = contract.kind;
|
|
980
|
+
if (contract.source !== undefined) {
|
|
981
|
+
errors.push(...sourceSpecErrors(contract.source, "proof_contract.source"));
|
|
982
|
+
if (kind !== "source")
|
|
983
|
+
errors.push(
|
|
984
|
+
`proof_contract.source applies only to kind source, not ${String(kind ?? "e2e")}`,
|
|
985
|
+
);
|
|
986
|
+
} else if (kind === "source")
|
|
987
|
+
errors.push(
|
|
988
|
+
"proof_contract.source is required for kind source: name the project source Kibi reads (reader json, yaml, glob, openapi, references, schema, routes or validator)",
|
|
989
|
+
);
|
|
990
|
+
const domains = record(contract.domains);
|
|
991
|
+
for (const [type, entry] of Object.entries(domains ?? {}))
|
|
992
|
+
if (isSourceDomain(entry)) {
|
|
993
|
+
errors.push(
|
|
994
|
+
...sourceSpecErrors(
|
|
995
|
+
record(entry)?.source,
|
|
996
|
+
`proof_contract.domains.${type}.source`,
|
|
997
|
+
),
|
|
998
|
+
);
|
|
999
|
+
if (kind !== "rule")
|
|
1000
|
+
errors.push(
|
|
1001
|
+
`proof_contract.domains.${type}.source applies only to kind rule: a state machine's domains are the code's`,
|
|
1002
|
+
);
|
|
1003
|
+
}
|
|
1004
|
+
return errors;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
/**
|
|
1008
|
+
* The contract fields of the rule, state_machine and regex kinds: where the
|
|
1009
|
+
* code Kibi evaluates lives, and only on the kinds that read it.
|
|
1010
|
+
*/
|
|
1011
|
+
// implements REQ-kibi-non-numeric-proof-kinds
|
|
1012
|
+
function nonNumericContractErrors(contract: Record<string, unknown>): string[] {
|
|
1013
|
+
const errors: string[] = [];
|
|
1014
|
+
const kind = contract.kind;
|
|
1015
|
+
const only = (field: string, kinds: readonly string[]) => {
|
|
1016
|
+
if (contract[field] !== undefined && !kinds.includes(String(kind)))
|
|
1017
|
+
errors.push(
|
|
1018
|
+
`proof_contract.${field} applies only to kind ${kinds.join(" or ")}, not ${String(kind ?? "e2e")}`,
|
|
1019
|
+
);
|
|
1020
|
+
};
|
|
1021
|
+
if (
|
|
1022
|
+
contract.predicate_source !== undefined &&
|
|
1023
|
+
!isSourceMap(contract.predicate_source, isPredicateReference)
|
|
1024
|
+
)
|
|
1025
|
+
errors.push(
|
|
1026
|
+
"proof_contract.predicate_source must map each predicate name to {symbol_id, export?, harness_for?} naming the function that decides it",
|
|
1027
|
+
);
|
|
1028
|
+
if (
|
|
1029
|
+
contract.domains !== undefined &&
|
|
1030
|
+
!isSourceMap(
|
|
1031
|
+
contract.domains,
|
|
1032
|
+
(entry) => isSourceReference(entry) || isSourceDomain(entry),
|
|
1033
|
+
)
|
|
1034
|
+
)
|
|
1035
|
+
errors.push(
|
|
1036
|
+
"proof_contract.domains must map each argument type to {symbol_id, export?} naming the export that lists its values, or {source} naming the project source Kibi reads them from",
|
|
1037
|
+
);
|
|
1038
|
+
for (const field of ["initial_source", "pattern_source"])
|
|
1039
|
+
if (contract[field] !== undefined && !isSourceReference(contract[field]))
|
|
1040
|
+
errors.push(
|
|
1041
|
+
`proof_contract.${field} must be {symbol_id, export?} naming the export Kibi reads`,
|
|
1042
|
+
);
|
|
1043
|
+
only("predicate_source", ["rule"]);
|
|
1044
|
+
only("domains", ["rule", "state_machine"]);
|
|
1045
|
+
only("initial_source", ["state_machine"]);
|
|
1046
|
+
only("pattern_source", ["regex"]);
|
|
1047
|
+
if (kind === "rule") {
|
|
1048
|
+
if (contract.predicate_source === undefined)
|
|
1049
|
+
errors.push(
|
|
1050
|
+
"proof_contract.predicate_source is required for kind rule: name the function behind each predicate the claims use",
|
|
1051
|
+
);
|
|
1052
|
+
if (contract.domains === undefined)
|
|
1053
|
+
errors.push(
|
|
1054
|
+
"proof_contract.domains is required for kind rule: name the export listing each argument type's values",
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
if (kind === "state_machine") {
|
|
1058
|
+
if (contract.domain_source === undefined)
|
|
1059
|
+
errors.push(
|
|
1060
|
+
"proof_contract.domain_source is required for kind state_machine: name the transition table or next-state function",
|
|
1061
|
+
);
|
|
1062
|
+
const domains = record(contract.domains);
|
|
1063
|
+
if (
|
|
1064
|
+
domains !== null &&
|
|
1065
|
+
(Object.keys(domains).length !== 2 ||
|
|
1066
|
+
domains.state === undefined ||
|
|
1067
|
+
domains.event === undefined)
|
|
1068
|
+
)
|
|
1069
|
+
errors.push(
|
|
1070
|
+
"proof_contract.domains for kind state_machine must name exactly the state and event domains a next-state function is called on",
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1073
|
+
if (kind === "regex" && contract.pattern_source === undefined)
|
|
1074
|
+
errors.push(
|
|
1075
|
+
"proof_contract.pattern_source is required for kind regex: name the export holding the pattern or string",
|
|
1076
|
+
);
|
|
1077
|
+
return errors;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
798
1080
|
/**
|
|
799
1081
|
* The optional contract fields beyond the v1 core, copied only when present
|
|
800
1082
|
* so existing contracts keep their hash.
|
|
@@ -810,14 +1092,24 @@ export function optionalProofContractFields(
|
|
|
810
1092
|
| "constraint_source"
|
|
811
1093
|
| "value_source"
|
|
812
1094
|
| "proves"
|
|
1095
|
+
| "predicate_source"
|
|
1096
|
+
| "domains"
|
|
1097
|
+
| "initial_source"
|
|
1098
|
+
| "pattern_source"
|
|
1099
|
+
| "source"
|
|
813
1100
|
> {
|
|
814
1101
|
const fields: {
|
|
815
1102
|
kind?: ProofKind;
|
|
816
1103
|
domain_source?: { symbol_id: string; export?: string };
|
|
817
1104
|
witness?: { path: string };
|
|
818
1105
|
constraint_source?: { fact_ids: string[] };
|
|
819
|
-
value_source?:
|
|
1106
|
+
value_source?: ValueSourceEntry[];
|
|
820
1107
|
proves?: string[];
|
|
1108
|
+
predicate_source?: Record<string, PredicateReference>;
|
|
1109
|
+
domains?: Record<string, SourceReference | { source: SourceSpec }>;
|
|
1110
|
+
initial_source?: SourceReference;
|
|
1111
|
+
pattern_source?: SourceReference;
|
|
1112
|
+
source?: SourceSpec;
|
|
821
1113
|
} = {};
|
|
822
1114
|
if (typeof contract.kind === "string")
|
|
823
1115
|
fields.kind = contract.kind as ProofKind;
|
|
@@ -840,21 +1132,105 @@ export function optionalProofContractFields(
|
|
|
840
1132
|
if (Array.isArray(contract.value_source))
|
|
841
1133
|
fields.value_source = contract.value_source
|
|
842
1134
|
.map((entry) => record(entry))
|
|
843
|
-
.
|
|
844
|
-
(row
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
1135
|
+
.map((row): ValueSourceEntry | null => {
|
|
1136
|
+
if (row === null) return null;
|
|
1137
|
+
const spec = normalizeSourceSpec(row.source);
|
|
1138
|
+
if (spec !== undefined) return { source: spec, measure: "count" };
|
|
1139
|
+
if (typeof row.symbol_id !== "string") return null;
|
|
1140
|
+
return {
|
|
1141
|
+
symbol_id: row.symbol_id,
|
|
1142
|
+
...(typeof row.export === "string" ? { export: row.export } : {}),
|
|
1143
|
+
...(row.measure === "value" || row.measure === "count"
|
|
1144
|
+
? { measure: row.measure }
|
|
1145
|
+
: {}),
|
|
1146
|
+
};
|
|
1147
|
+
})
|
|
1148
|
+
.filter((row): row is ValueSourceEntry => row !== null);
|
|
851
1149
|
if (Array.isArray(contract.proves))
|
|
852
1150
|
fields.proves = contract.proves.filter(
|
|
853
1151
|
(key): key is string => typeof key === "string",
|
|
854
1152
|
);
|
|
1153
|
+
const predicates = predicateMap(contract.predicate_source);
|
|
1154
|
+
if (predicates !== undefined) fields.predicate_source = predicates;
|
|
1155
|
+
const domains = domainMap(contract.domains);
|
|
1156
|
+
if (domains !== undefined) fields.domains = domains;
|
|
1157
|
+
const spec = normalizeSourceSpec(contract.source);
|
|
1158
|
+
if (spec !== undefined) fields.source = spec;
|
|
1159
|
+
const initial = sourceReference(contract.initial_source);
|
|
1160
|
+
if (initial !== undefined) fields.initial_source = initial;
|
|
1161
|
+
const pattern = sourceReference(contract.pattern_source);
|
|
1162
|
+
if (pattern !== undefined) fields.pattern_source = pattern;
|
|
855
1163
|
return fields;
|
|
856
1164
|
}
|
|
857
1165
|
|
|
1166
|
+
type SourceReference = { symbol_id: string; export?: string };
|
|
1167
|
+
type PredicateReference = SourceReference & { harness_for?: string[] };
|
|
1168
|
+
type ValueSourceEntry =
|
|
1169
|
+
| { symbol_id: string; export?: string; measure?: "value" | "count" }
|
|
1170
|
+
| { source: SourceSpec; measure: "count" };
|
|
1171
|
+
|
|
1172
|
+
function predicateMap(
|
|
1173
|
+
value: unknown,
|
|
1174
|
+
): Record<string, PredicateReference> | undefined {
|
|
1175
|
+
const row = record(value);
|
|
1176
|
+
if (!row) return undefined;
|
|
1177
|
+
const out: Record<string, PredicateReference> = {};
|
|
1178
|
+
for (const [key, entry] of Object.entries(row)) {
|
|
1179
|
+
const reference = sourceReference(entry);
|
|
1180
|
+
if (reference === undefined) continue;
|
|
1181
|
+
const harness = record(entry)?.harness_for;
|
|
1182
|
+
out[key] = Array.isArray(harness)
|
|
1183
|
+
? {
|
|
1184
|
+
...reference,
|
|
1185
|
+
harness_for: harness.filter(
|
|
1186
|
+
(id): id is string => typeof id === "string",
|
|
1187
|
+
),
|
|
1188
|
+
}
|
|
1189
|
+
: reference;
|
|
1190
|
+
}
|
|
1191
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
function domainMap(
|
|
1195
|
+
value: unknown,
|
|
1196
|
+
): Record<string, SourceReference | { source: SourceSpec }> | undefined {
|
|
1197
|
+
const row = record(value);
|
|
1198
|
+
if (!row) return undefined;
|
|
1199
|
+
const out: Record<string, SourceReference | { source: SourceSpec }> = {};
|
|
1200
|
+
for (const [key, entry] of Object.entries(row)) {
|
|
1201
|
+
const spec = normalizeSourceSpec(record(entry)?.source);
|
|
1202
|
+
if (spec !== undefined) {
|
|
1203
|
+
out[key] = { source: spec };
|
|
1204
|
+
continue;
|
|
1205
|
+
}
|
|
1206
|
+
const reference = sourceReference(entry);
|
|
1207
|
+
if (reference !== undefined) out[key] = reference;
|
|
1208
|
+
}
|
|
1209
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
function sourceReference(value: unknown): SourceReference | undefined {
|
|
1213
|
+
const row = record(value);
|
|
1214
|
+
if (!row || typeof row.symbol_id !== "string") return undefined;
|
|
1215
|
+
return {
|
|
1216
|
+
symbol_id: row.symbol_id,
|
|
1217
|
+
...(typeof row.export === "string" ? { export: row.export } : {}),
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
function sourceMap(
|
|
1222
|
+
value: unknown,
|
|
1223
|
+
): Record<string, SourceReference> | undefined {
|
|
1224
|
+
const row = record(value);
|
|
1225
|
+
if (!row) return undefined;
|
|
1226
|
+
const out: Record<string, SourceReference> = {};
|
|
1227
|
+
for (const [key, entry] of Object.entries(row)) {
|
|
1228
|
+
const reference = sourceReference(entry);
|
|
1229
|
+
if (reference !== undefined) out[key] = reference;
|
|
1230
|
+
}
|
|
1231
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
858
1234
|
export function proofBindingsErrors(value: unknown): string[] {
|
|
859
1235
|
if (!Array.isArray(value))
|
|
860
1236
|
return ["proof_bindings must be an array of binding objects"];
|
|
@@ -183,7 +183,10 @@ export const PROOF_RECEIPT_SCHEMA = {
|
|
|
183
183
|
type: "string",
|
|
184
184
|
enum: [...CLAIM_BINDING_VERDICTS],
|
|
185
185
|
},
|
|
186
|
-
scope: {
|
|
186
|
+
scope: {
|
|
187
|
+
type: "string",
|
|
188
|
+
enum: ["code", "source", "harness", "intent"],
|
|
189
|
+
},
|
|
187
190
|
obligation: { type: "object" },
|
|
188
191
|
reason: { type: "string", minLength: 1 },
|
|
189
192
|
},
|
|
@@ -265,7 +268,8 @@ export type ClaimBinding = Readonly<{
|
|
|
265
268
|
requirement_id?: string;
|
|
266
269
|
fact_id?: string;
|
|
267
270
|
binding: ClaimBindingVerdict;
|
|
268
|
-
|
|
271
|
+
/** What the proof rests on: evaluated code, project files Kibi read (source), a test harness, or the knowledge base alone (intent). */
|
|
272
|
+
scope?: "code" | "source" | "harness" | "intent";
|
|
269
273
|
obligation?: Readonly<Record<string, unknown>>;
|
|
270
274
|
reason?: string;
|
|
271
275
|
}>;
|
|
@@ -471,6 +475,8 @@ function validClaimBindings(value: unknown): boolean {
|
|
|
471
475
|
) &&
|
|
472
476
|
(entry.scope === undefined ||
|
|
473
477
|
entry.scope === "code" ||
|
|
478
|
+
entry.scope === "source" ||
|
|
479
|
+
entry.scope === "harness" ||
|
|
474
480
|
entry.scope === "intent") &&
|
|
475
481
|
(entry.obligation === undefined || isRecord(entry.obligation)) &&
|
|
476
482
|
(entry.reason === undefined || nonEmptyString(entry.reason)),
|