kibi-cli 2.39.0 → 2.40.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-register-foundation.js +2 -2
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +33 -9
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +15 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +4 -0
- package/dist/commands/migrate-plan-record.d.ts +18 -0
- package/dist/commands/migrate-plan-record.d.ts.map +1 -0
- package/dist/commands/migrate-plan-record.js +112 -0
- package/dist/commands/migrate.d.ts +11 -2
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +53 -7
- package/dist/commands/prove.d.ts.map +1 -1
- package/dist/commands/prove.js +18 -3
- package/dist/commands/sync/manifest.d.ts.map +1 -1
- package/dist/commands/sync/manifest.js +17 -4
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +8 -0
- package/dist/commands/telemetry.d.ts.map +1 -1
- package/dist/commands/telemetry.js +12 -2
- package/dist/extractors/symbol-title-match.d.ts +31 -0
- package/dist/extractors/symbol-title-match.d.ts.map +1 -0
- package/dist/extractors/symbol-title-match.js +133 -0
- package/dist/extractors/symbols-coordinator.d.ts.map +1 -1
- package/dist/extractors/symbols-coordinator.js +81 -12
- package/dist/operations/bootstrap/discovery-evidence.js +2 -2
- package/dist/operations/bootstrap/guidance-actions.d.ts.map +1 -1
- package/dist/operations/bootstrap/guidance-actions.js +12 -1
- package/dist/operations/bootstrap/plugin-offers.d.ts +7 -1
- package/dist/operations/bootstrap/plugin-offers.d.ts.map +1 -1
- package/dist/operations/bootstrap/plugin-offers.js +73 -3
- package/dist/operations/modeling/logic-modeling.d.ts.map +1 -1
- package/dist/operations/modeling/logic-modeling.js +2 -1
- package/dist/operations/modeling/model-requirement.d.ts.map +1 -1
- package/dist/operations/modeling/model-requirement.js +2 -1
- package/dist/operations/mutation/symbol-refresh.d.ts +2 -0
- package/dist/operations/mutation/symbol-refresh.d.ts.map +1 -1
- package/dist/operations/mutation/symbol-refresh.js +6 -1
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +7 -0
- package/dist/operations/planning/compile-intent.d.ts.map +1 -1
- package/dist/operations/planning/compile-intent.js +2 -1
- package/dist/operations/proof/claim-bindings.d.ts +11 -0
- package/dist/operations/proof/claim-bindings.d.ts.map +1 -1
- package/dist/operations/proof/claim-bindings.js +144 -1
- package/dist/operations/proof/code-certificates.d.ts +10 -3
- package/dist/operations/proof/code-certificates.d.ts.map +1 -1
- package/dist/operations/proof/code-certificates.js +65 -13
- package/dist/operations/proof/code-languages.d.ts +104 -0
- package/dist/operations/proof/code-languages.d.ts.map +1 -0
- package/dist/operations/proof/code-languages.js +119 -0
- package/dist/operations/proof/code-models.d.ts +2 -0
- package/dist/operations/proof/code-models.d.ts.map +1 -1
- package/dist/operations/proof/code-models.js +11 -5
- package/dist/operations/proof/code-runner.d.ts +12 -9
- package/dist/operations/proof/code-runner.d.ts.map +1 -1
- package/dist/operations/proof/code-runner.js +81 -38
- package/dist/operations/proof/code-scope.d.ts +8 -0
- package/dist/operations/proof/code-scope.d.ts.map +1 -1
- package/dist/operations/proof/code-scope.js +30 -1
- package/dist/operations/proof/explain.d.ts +13 -0
- package/dist/operations/proof/explain.d.ts.map +1 -1
- package/dist/operations/proof/explain.js +66 -0
- package/dist/operations/proof/ingest-proof.d.ts +2 -0
- package/dist/operations/proof/ingest-proof.d.ts.map +1 -1
- package/dist/operations/proof/ingest-proof.js +1 -0
- package/dist/operations/proof/java-package-shadow.d.ts +14 -0
- package/dist/operations/proof/java-package-shadow.d.ts.map +1 -0
- package/dist/operations/proof/java-package-shadow.js +389 -0
- package/dist/operations/proof/prolog-evaluator.d.ts +14 -0
- package/dist/operations/proof/prolog-evaluator.d.ts.map +1 -0
- package/dist/operations/proof/prolog-evaluator.js +247 -0
- package/dist/operations/proof/prolog-source-reader.d.ts +20 -0
- package/dist/operations/proof/prolog-source-reader.d.ts.map +1 -0
- package/dist/operations/proof/prolog-source-reader.js +1123 -0
- package/dist/operations/proof/source-code-readers.d.ts +6 -0
- package/dist/operations/proof/source-code-readers.d.ts.map +1 -1
- package/dist/operations/proof/source-code-readers.js +879 -75
- package/dist/plugins/approved-source-analyzers.generated.d.ts +13 -35
- package/dist/plugins/approved-source-analyzers.generated.d.ts.map +1 -1
- package/dist/plugins/approved-source-analyzers.generated.js +13 -35
- package/dist/plugins/plugin-install-check.d.ts +21 -0
- package/dist/plugins/plugin-install-check.d.ts.map +1 -0
- package/dist/plugins/plugin-install-check.js +62 -0
- package/dist/plugins/proof-reference-extractors.d.ts +20 -0
- package/dist/plugins/proof-reference-extractors.d.ts.map +1 -0
- package/dist/plugins/proof-reference-extractors.js +104 -0
- package/dist/plugins/reference-language-suggestion.d.ts +51 -0
- package/dist/plugins/reference-language-suggestion.d.ts.map +1 -0
- package/dist/plugins/reference-language-suggestion.js +277 -0
- package/dist/plugins/registry.d.ts.map +1 -1
- package/dist/plugins/registry.js +3 -1
- package/dist/plugins/source-analysis-service.d.ts.map +1 -1
- package/dist/plugins/source-analysis-service.js +4 -0
- package/dist/plugins/source-change-analysis.d.ts +26 -1
- package/dist/plugins/source-change-analysis.d.ts.map +1 -1
- package/dist/plugins/source-change-analysis.js +77 -5
- package/dist/plugins/source-classification.d.ts.map +1 -1
- package/dist/plugins/source-classification.js +23 -3
- package/dist/public/operations/catalog.d.ts +32 -7
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +3 -0
- package/dist/public/operations/evidence-floor.d.ts +8 -0
- package/dist/public/operations/evidence-floor.d.ts.map +1 -1
- package/dist/public/operations/evidence-floor.js +19 -1
- package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
- package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
- package/dist/public/operations/specs/check-rules.generated.js +2 -1
- package/dist/public/operations/specs/check.d.ts +1 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts +31 -6
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/reporting.d.ts +8 -0
- package/dist/public/operations/specs/reporting.d.ts.map +1 -1
- package/dist/public/operations/specs/reporting.js +26 -3
- package/dist/public/operations/specs/semantic.d.ts.map +1 -1
- package/dist/public/operations/specs/semantic.js +2 -1
- package/dist/public/operations/specs/upsert.d.ts +31 -6
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/operations/symbol-coordinates-check.d.ts +11 -0
- package/dist/public/operations/symbol-coordinates-check.d.ts.map +1 -0
- package/dist/public/operations/symbol-coordinates-check.js +66 -0
- package/dist/public/proof-protocol.d.ts +31 -6
- package/dist/public/proof-protocol.d.ts.map +1 -1
- package/dist/public/proof-protocol.js +45 -15
- package/dist/public/proof-sources.d.ts +4 -2
- package/dist/public/proof-sources.d.ts.map +1 -1
- package/dist/public/proof-sources.js +43 -4
- package/dist/public/skills/kibi-usage/SKILL.md +6 -3
- package/dist/public/skills/kibi-usage/resources/prolog-proofs.md +207 -0
- package/dist/public/skills/kibi-usage/resources/proof.md +44 -3
- package/dist/schemas/entity.schema.json +34 -6
- package/dist/traceability/analysis-gate.d.ts +3 -1
- package/dist/traceability/analysis-gate.d.ts.map +1 -1
- package/dist/traceability/analysis-gate.js +9 -1
- package/dist/traceability/staged-file-coverage.d.ts.map +1 -1
- package/dist/traceability/staged-file-coverage.js +7 -2
- package/dist/traceability/symbol-extract.d.ts +17 -0
- package/dist/traceability/symbol-extract.d.ts.map +1 -1
- package/dist/traceability/symbol-extract.js +69 -15
- package/dist/traceability/validate.d.ts.map +1 -1
- package/dist/traceability/validate.js +5 -7
- package/dist/utils/first-sentence.d.ts +9 -0
- package/dist/utils/first-sentence.d.ts.map +1 -0
- package/dist/utils/first-sentence.js +52 -0
- package/dist/utils/rule-registry.generated.d.ts +6 -0
- package/dist/utils/rule-registry.generated.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.js +7 -0
- package/package.json +5 -5
- package/src/public/operations/check-executor.ts +8 -0
- package/src/public/operations/evidence-floor.ts +29 -1
- package/src/public/operations/specs/check-rules.generated.ts +2 -1
- package/src/public/operations/specs/reporting.ts +38 -3
- package/src/public/operations/specs/semantic.ts +2 -1
- package/src/public/operations/symbol-coordinates-check.ts +79 -0
- package/src/public/proof-protocol-types.d.ts +22 -5
- package/src/public/proof-protocol.ts +78 -19
- package/src/public/proof-sources.ts +51 -3
- package/src/public/skills/kibi-usage/SKILL.md +6 -3
- package/src/public/skills/kibi-usage/resources/prolog-proofs.md +207 -0
- package/src/public/skills/kibi-usage/resources/proof.md +44 -3
- package/src/schemas/entity.schema.json +34 -6
|
@@ -279,21 +279,29 @@ export const PROOF_RUN_ARTIFACT_SCHEMA = {
|
|
|
279
279
|
additionalProperties: false,
|
|
280
280
|
} as const;
|
|
281
281
|
|
|
282
|
+
const ARG_SCHEMA = {
|
|
283
|
+
type: "integer",
|
|
284
|
+
minimum: 1,
|
|
285
|
+
description:
|
|
286
|
+
"A SWI-Prolog predicate's argument (1-based) whose solutions Kibi reads, when the predicate takes more than one argument (operator/2 with arg 1 lists each operator's name).",
|
|
287
|
+
} as const;
|
|
288
|
+
|
|
282
289
|
const SOURCE_REFERENCE_SCHEMA = {
|
|
283
290
|
type: "object",
|
|
284
291
|
required: ["symbol_id"],
|
|
285
292
|
properties: {
|
|
286
293
|
symbol_id: { type: "string", minLength: 1 },
|
|
287
294
|
export: { type: "string", minLength: 1 },
|
|
295
|
+
arg: ARG_SCHEMA,
|
|
288
296
|
},
|
|
289
297
|
additionalProperties: false,
|
|
290
298
|
} as const;
|
|
291
299
|
|
|
292
|
-
// implements REQ-kibi-source-proof-kinds
|
|
300
|
+
// implements REQ-kibi-source-proof-kinds, REQ-kibi-prolog-source-readers
|
|
293
301
|
const SOURCE_SPEC_SCHEMA = {
|
|
294
302
|
type: "object",
|
|
295
303
|
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.",
|
|
304
|
+
"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?} over TypeScript, JavaScript, Python and SWI-Prolog files. 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}. prolog: {file, functor: Name/Arity, arg?} reads one argument of every fact with that functor in a SWI-Prolog file (requires/1 in pack.pl), without running it. Paths are repository-relative. A member Kibi cannot read statically fails the read with its location.",
|
|
297
305
|
required: ["reader"],
|
|
298
306
|
properties: {
|
|
299
307
|
reader: { type: "string", enum: [...SOURCE_READERS] },
|
|
@@ -382,6 +390,7 @@ export const PROOF_CONTRACT_SCHEMA = {
|
|
|
382
390
|
description:
|
|
383
391
|
"exhaustive: when the export is a list of records, the field of each record that names a domain member (a catalog's name).",
|
|
384
392
|
},
|
|
393
|
+
arg: ARG_SCHEMA,
|
|
385
394
|
},
|
|
386
395
|
additionalProperties: false,
|
|
387
396
|
},
|
|
@@ -411,6 +420,7 @@ export const PROOF_CONTRACT_SCHEMA = {
|
|
|
411
420
|
properties: {
|
|
412
421
|
symbol_id: { type: "string", minLength: 1 },
|
|
413
422
|
export: { type: "string", minLength: 1 },
|
|
423
|
+
arg: ARG_SCHEMA,
|
|
414
424
|
source: SOURCE_SPEC_SCHEMA,
|
|
415
425
|
measure: {
|
|
416
426
|
type: "string",
|
|
@@ -819,17 +829,30 @@ function proofContractKindErrors(contract: Record<string, unknown>): string[] {
|
|
|
819
829
|
!nonEmptyString(row.symbol_id) ||
|
|
820
830
|
(row.export !== undefined && !nonEmptyString(row.export)) ||
|
|
821
831
|
(row.field !== undefined && !nonEmptyString(row.field)) ||
|
|
832
|
+
(row.arg !== undefined && !isArgIndex(row.arg)) ||
|
|
822
833
|
Object.keys(row).some(
|
|
823
|
-
(key) =>
|
|
834
|
+
(key) =>
|
|
835
|
+
key !== "symbol_id" &&
|
|
836
|
+
key !== "export" &&
|
|
837
|
+
key !== "field" &&
|
|
838
|
+
key !== "arg",
|
|
824
839
|
)
|
|
825
840
|
)
|
|
826
841
|
errors.push(
|
|
827
|
-
"proof_contract.domain_source must be {symbol_id, export?, field?} naming the symbol that defines the domain, the export to read when its title is not the export name,
|
|
842
|
+
"proof_contract.domain_source must be {symbol_id, export?, field?, arg?} naming the symbol that defines the domain, the export to read when its title is not the export name, the record field that names each member, and for a SWI-Prolog predicate the argument (1-based) that names it",
|
|
843
|
+
);
|
|
844
|
+
else if (row.field !== undefined && row.arg !== undefined)
|
|
845
|
+
errors.push(
|
|
846
|
+
"proof_contract.domain_source takes field (a record field) or arg (a Prolog argument), not both",
|
|
828
847
|
);
|
|
829
848
|
else if (row.field !== undefined && kind !== "exhaustive")
|
|
830
849
|
errors.push(
|
|
831
850
|
`proof_contract.domain_source.field applies only to kind exhaustive, not ${String(kind ?? "e2e")}`,
|
|
832
851
|
);
|
|
852
|
+
else if (row.arg !== undefined && kind !== "exhaustive")
|
|
853
|
+
errors.push(
|
|
854
|
+
`proof_contract.domain_source.arg applies only to kind exhaustive, not ${String(kind ?? "e2e")}`,
|
|
855
|
+
);
|
|
833
856
|
} else if (kind === "exhaustive" || kind === "typecheck")
|
|
834
857
|
errors.push(
|
|
835
858
|
`proof_contract.domain_source is required for kind ${String(kind)}: name the symbol the proof reads its domain from`,
|
|
@@ -878,9 +901,13 @@ function proofContractKindErrors(contract: Record<string, unknown>): string[] {
|
|
|
878
901
|
`proof_contract.value_source[${index}].source`,
|
|
879
902
|
),
|
|
880
903
|
);
|
|
881
|
-
if (
|
|
904
|
+
if (
|
|
905
|
+
row.symbol_id !== undefined ||
|
|
906
|
+
row.export !== undefined ||
|
|
907
|
+
row.arg !== undefined
|
|
908
|
+
)
|
|
882
909
|
errors.push(
|
|
883
|
-
`proof_contract.value_source[${index}] names a source, so it takes no symbol_id or
|
|
910
|
+
`proof_contract.value_source[${index}] names a source, so it takes no symbol_id, export or arg`,
|
|
884
911
|
);
|
|
885
912
|
if (row.measure !== undefined && row.measure !== "count")
|
|
886
913
|
errors.push(
|
|
@@ -897,18 +924,22 @@ function proofContractKindErrors(contract: Record<string, unknown>): string[] {
|
|
|
897
924
|
row !== null &&
|
|
898
925
|
nonEmptyString(row.symbol_id) &&
|
|
899
926
|
(row.export === undefined || nonEmptyString(row.export)) &&
|
|
927
|
+
(row.arg === undefined || isArgIndex(row.arg)) &&
|
|
900
928
|
(row.measure === undefined ||
|
|
901
929
|
row.measure === "value" ||
|
|
902
930
|
row.measure === "count") &&
|
|
903
931
|
Object.keys(row).every(
|
|
904
932
|
(key) =>
|
|
905
|
-
key === "symbol_id" ||
|
|
933
|
+
key === "symbol_id" ||
|
|
934
|
+
key === "export" ||
|
|
935
|
+
key === "arg" ||
|
|
936
|
+
key === "measure",
|
|
906
937
|
)
|
|
907
938
|
);
|
|
908
939
|
})
|
|
909
940
|
)
|
|
910
941
|
errors.push(
|
|
911
|
-
"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",
|
|
942
|
+
"proof_contract.value_source must be [{symbol_id, export?, arg?, measure?: value|count} or {source, measure?: count}] naming the code constants or project sources the assumptions read",
|
|
912
943
|
);
|
|
913
944
|
else if (kind !== "arithmetic" && kind !== "smt")
|
|
914
945
|
errors.push(
|
|
@@ -938,13 +969,23 @@ function proofContractKindErrors(contract: Record<string, unknown>): string[] {
|
|
|
938
969
|
return errors;
|
|
939
970
|
}
|
|
940
971
|
|
|
941
|
-
function
|
|
972
|
+
function isArgIndex(value: unknown): boolean {
|
|
973
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 1;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
function isSourceReference(
|
|
977
|
+
value: unknown,
|
|
978
|
+
options: Readonly<{ arg?: boolean }> = { arg: true },
|
|
979
|
+
): boolean {
|
|
942
980
|
const row = record(value);
|
|
943
981
|
return (
|
|
944
982
|
row !== null &&
|
|
945
983
|
nonEmptyString(row.symbol_id) &&
|
|
946
984
|
(row.export === undefined || nonEmptyString(row.export)) &&
|
|
947
|
-
|
|
985
|
+
(row.arg === undefined || (options.arg === true && isArgIndex(row.arg))) &&
|
|
986
|
+
Object.keys(row).every(
|
|
987
|
+
(key) => key === "symbol_id" || key === "export" || key === "arg",
|
|
988
|
+
)
|
|
948
989
|
);
|
|
949
990
|
}
|
|
950
991
|
|
|
@@ -964,11 +1005,12 @@ function isSourceMap(
|
|
|
964
1005
|
|
|
965
1006
|
function isPredicateReference(value: unknown): boolean {
|
|
966
1007
|
const row = record(value);
|
|
1008
|
+
// A predicate is called with every argument, so it projects none.
|
|
967
1009
|
if (row === null || row.harness_for === undefined)
|
|
968
|
-
return isSourceReference(value);
|
|
1010
|
+
return isSourceReference(value, { arg: false });
|
|
969
1011
|
const { harness_for: harness, ...reference } = row;
|
|
970
1012
|
return (
|
|
971
|
-
isSourceReference(reference) &&
|
|
1013
|
+
isSourceReference(reference, { arg: false }) &&
|
|
972
1014
|
Array.isArray(harness) &&
|
|
973
1015
|
harness.length > 0 &&
|
|
974
1016
|
harness.every(nonEmptyString)
|
|
@@ -998,7 +1040,7 @@ function sourceContractErrors(contract: Record<string, unknown>): string[] {
|
|
|
998
1040
|
);
|
|
999
1041
|
} else if (kind === "source")
|
|
1000
1042
|
errors.push(
|
|
1001
|
-
"proof_contract.source is required for kind source: name the project source Kibi reads (reader json, yaml, glob, openapi, references, schema, routes or
|
|
1043
|
+
"proof_contract.source is required for kind source: name the project source Kibi reads (reader json, yaml, glob, openapi, references, schema, routes, validator or prolog)",
|
|
1002
1044
|
);
|
|
1003
1045
|
const domains = record(contract.domains);
|
|
1004
1046
|
for (const [type, entry] of Object.entries(domains ?? {}))
|
|
@@ -1046,12 +1088,12 @@ function nonNumericContractErrors(contract: Record<string, unknown>): string[] {
|
|
|
1046
1088
|
)
|
|
1047
1089
|
)
|
|
1048
1090
|
errors.push(
|
|
1049
|
-
"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",
|
|
1091
|
+
"proof_contract.domains must map each argument type to {symbol_id, export?, arg?} naming the export (or SWI-Prolog predicate and argument) that lists its values, or {source} naming the project source Kibi reads them from",
|
|
1050
1092
|
);
|
|
1051
1093
|
for (const field of ["initial_source", "pattern_source"])
|
|
1052
1094
|
if (contract[field] !== undefined && !isSourceReference(contract[field]))
|
|
1053
1095
|
errors.push(
|
|
1054
|
-
`proof_contract.${field} must be {symbol_id, export?} naming the export Kibi reads`,
|
|
1096
|
+
`proof_contract.${field} must be {symbol_id, export?, arg?} naming the export (or SWI-Prolog predicate and argument) Kibi reads`,
|
|
1055
1097
|
);
|
|
1056
1098
|
only("predicate_source", ["rule"]);
|
|
1057
1099
|
only("domains", ["rule", "state_machine"]);
|
|
@@ -1113,7 +1155,12 @@ export function optionalProofContractFields(
|
|
|
1113
1155
|
> {
|
|
1114
1156
|
const fields: {
|
|
1115
1157
|
kind?: ProofKind;
|
|
1116
|
-
domain_source?: {
|
|
1158
|
+
domain_source?: {
|
|
1159
|
+
symbol_id: string;
|
|
1160
|
+
export?: string;
|
|
1161
|
+
field?: string;
|
|
1162
|
+
arg?: number;
|
|
1163
|
+
};
|
|
1117
1164
|
witness?: { path: string };
|
|
1118
1165
|
constraint_source?: { fact_ids: string[] };
|
|
1119
1166
|
value_source?: ValueSourceEntry[];
|
|
@@ -1132,6 +1179,7 @@ export function optionalProofContractFields(
|
|
|
1132
1179
|
symbol_id: domain.symbol_id,
|
|
1133
1180
|
...(typeof domain.export === "string" ? { export: domain.export } : {}),
|
|
1134
1181
|
...(typeof domain.field === "string" ? { field: domain.field } : {}),
|
|
1182
|
+
...(isArgIndex(domain.arg) ? { arg: domain.arg as number } : {}),
|
|
1135
1183
|
};
|
|
1136
1184
|
const witness = record(contract.witness);
|
|
1137
1185
|
if (witness && typeof witness.path === "string")
|
|
@@ -1154,6 +1202,7 @@ export function optionalProofContractFields(
|
|
|
1154
1202
|
return {
|
|
1155
1203
|
symbol_id: row.symbol_id,
|
|
1156
1204
|
...(typeof row.export === "string" ? { export: row.export } : {}),
|
|
1205
|
+
...(isArgIndex(row.arg) ? { arg: row.arg as number } : {}),
|
|
1157
1206
|
...(row.measure === "value" || row.measure === "count"
|
|
1158
1207
|
? { measure: row.measure }
|
|
1159
1208
|
: {}),
|
|
@@ -1177,10 +1226,19 @@ export function optionalProofContractFields(
|
|
|
1177
1226
|
return fields;
|
|
1178
1227
|
}
|
|
1179
1228
|
|
|
1180
|
-
type SourceReference = { symbol_id: string; export?: string };
|
|
1181
|
-
type PredicateReference =
|
|
1229
|
+
type SourceReference = { symbol_id: string; export?: string; arg?: number };
|
|
1230
|
+
type PredicateReference = {
|
|
1231
|
+
symbol_id: string;
|
|
1232
|
+
export?: string;
|
|
1233
|
+
harness_for?: string[];
|
|
1234
|
+
};
|
|
1182
1235
|
type ValueSourceEntry =
|
|
1183
|
-
| {
|
|
1236
|
+
| {
|
|
1237
|
+
symbol_id: string;
|
|
1238
|
+
export?: string;
|
|
1239
|
+
arg?: number;
|
|
1240
|
+
measure?: "value" | "count";
|
|
1241
|
+
}
|
|
1184
1242
|
| { source: SourceSpec; measure: "count" };
|
|
1185
1243
|
|
|
1186
1244
|
function predicateMap(
|
|
@@ -1229,6 +1287,7 @@ function sourceReference(value: unknown): SourceReference | undefined {
|
|
|
1229
1287
|
return {
|
|
1230
1288
|
symbol_id: row.symbol_id,
|
|
1231
1289
|
...(typeof row.export === "string" ? { export: row.export } : {}),
|
|
1290
|
+
...(isArgIndex(row.arg) ? { arg: row.arg as number } : {}),
|
|
1232
1291
|
};
|
|
1233
1292
|
}
|
|
1234
1293
|
|
|
@@ -22,8 +22,9 @@
|
|
|
22
22
|
* JSON or YAML file, the files a glob matches, an OpenAPI document, the
|
|
23
23
|
* references the code makes (environment variables, imports, calls, string
|
|
24
24
|
* arguments, thrown error codes, property values), a data schema (drizzle,
|
|
25
|
-
* Prisma or SQL migrations), a web app's route table (Hono, Express)
|
|
26
|
-
* validator object (zod and anything with safeParse)
|
|
25
|
+
* Prisma or SQL migrations), a web app's route table (Hono, Express), a
|
|
26
|
+
* validator object (zod and anything with safeParse) and the facts of a
|
|
27
|
+
* SWI-Prolog file (a pack's requires/1).
|
|
27
28
|
*
|
|
28
29
|
* Every reader is exact or refuses: a member Kibi cannot read statically (a
|
|
29
30
|
* computed environment variable name, a dynamic import, an ALTER TABLE form
|
|
@@ -47,6 +48,7 @@ export const SOURCE_READERS = [
|
|
|
47
48
|
"schema",
|
|
48
49
|
"routes",
|
|
49
50
|
"validator",
|
|
51
|
+
"prolog",
|
|
50
52
|
] as const;
|
|
51
53
|
|
|
52
54
|
export type SourceReader = (typeof SOURCE_READERS)[number];
|
|
@@ -148,6 +150,7 @@ const KEYS: Readonly<Record<SourceReader, readonly string[]>> = {
|
|
|
148
150
|
"select",
|
|
149
151
|
],
|
|
150
152
|
validator: ["reader", "file", "export", "select"],
|
|
153
|
+
prolog: ["reader", "file", "functor", "arg"],
|
|
151
154
|
};
|
|
152
155
|
|
|
153
156
|
function record(value: unknown): Record<string, unknown> | null {
|
|
@@ -322,6 +325,23 @@ export function sourceSpecErrors(value: unknown, label: string): string[] {
|
|
|
322
325
|
`${label}.export is required for reader validator: name the object schema`,
|
|
323
326
|
);
|
|
324
327
|
break;
|
|
328
|
+
case "prolog":
|
|
329
|
+
file("file", true);
|
|
330
|
+
if (
|
|
331
|
+
typeof row.functor !== "string" ||
|
|
332
|
+
!/^[a-z][A-Za-z0-9_]*\/(?:0|[1-9][0-9]*)$/.test(row.functor)
|
|
333
|
+
)
|
|
334
|
+
errors.push(
|
|
335
|
+
`${label}.functor is required for reader prolog: name the facts read as Name/Arity (requires/1)`,
|
|
336
|
+
);
|
|
337
|
+
if (
|
|
338
|
+
row.arg !== undefined &&
|
|
339
|
+
!(Number.isInteger(row.arg) && (row.arg as number) >= 1)
|
|
340
|
+
)
|
|
341
|
+
errors.push(
|
|
342
|
+
`${label}.arg must be the 1-based argument of each fact that holds the member`,
|
|
343
|
+
);
|
|
344
|
+
break;
|
|
325
345
|
}
|
|
326
346
|
return errors;
|
|
327
347
|
}
|
|
@@ -352,15 +372,28 @@ export function matchWorkspaceFiles(
|
|
|
352
372
|
workspaceRoot: string,
|
|
353
373
|
patterns: readonly string[],
|
|
354
374
|
ignore: readonly string[] = [],
|
|
375
|
+
caseSensitive = true,
|
|
355
376
|
): string[] {
|
|
377
|
+
// A symbolic link to a file is read as that file (git and compilers read
|
|
378
|
+
// it so); links to folders are not walked.
|
|
356
379
|
return fg
|
|
357
380
|
.sync([...patterns], {
|
|
358
381
|
cwd: workspaceRoot,
|
|
359
382
|
ignore: [...DEFAULT_IGNORE, ...ignore],
|
|
383
|
+
caseSensitiveMatch: caseSensitive,
|
|
360
384
|
dot: true,
|
|
361
|
-
onlyFiles:
|
|
385
|
+
onlyFiles: false,
|
|
386
|
+
markDirectories: true,
|
|
362
387
|
followSymbolicLinks: false,
|
|
363
388
|
})
|
|
389
|
+
.filter((file) => {
|
|
390
|
+
if (file.endsWith("/")) return false;
|
|
391
|
+
try {
|
|
392
|
+
return statSync(path.join(workspaceRoot, file)).isFile();
|
|
393
|
+
} catch {
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
})
|
|
364
397
|
.map((file) => file.split(path.sep).join("/"))
|
|
365
398
|
.sort();
|
|
366
399
|
}
|
|
@@ -451,6 +484,9 @@ export function sourceDependencies(
|
|
|
451
484
|
addFile(String(spec.file));
|
|
452
485
|
for (const file of globList(spec.names_from)) addFile(file);
|
|
453
486
|
break;
|
|
487
|
+
case "prolog":
|
|
488
|
+
addFile(String(spec.file));
|
|
489
|
+
break;
|
|
454
490
|
}
|
|
455
491
|
if (
|
|
456
492
|
spec.reader === "routes" ||
|
|
@@ -1617,6 +1653,14 @@ export async function readSource(
|
|
|
1617
1653
|
ok: true,
|
|
1618
1654
|
model: { members: sortedUnique(evaluated.members ?? []) },
|
|
1619
1655
|
};
|
|
1656
|
+
if (spec.reader === "prolog")
|
|
1657
|
+
return {
|
|
1658
|
+
ok: true,
|
|
1659
|
+
model: {
|
|
1660
|
+
members: sortedUnique(evaluated.members ?? []),
|
|
1661
|
+
sequence: evaluated.sequence ?? [],
|
|
1662
|
+
},
|
|
1663
|
+
};
|
|
1620
1664
|
if (spec.reader === "routes") {
|
|
1621
1665
|
const routes = selectedRoutes(spec, evaluated.routes ?? []).sort((a, b) =>
|
|
1622
1666
|
`${a.path} ${a.method}` < `${b.path} ${b.method}` ? -1 : 1,
|
|
@@ -1644,6 +1688,8 @@ export type SourceCodeEvaluation =
|
|
|
1644
1688
|
| {
|
|
1645
1689
|
ok: true;
|
|
1646
1690
|
members?: string[];
|
|
1691
|
+
/** The prolog reader's members in file order, duplicates kept. */
|
|
1692
|
+
sequence?: string[];
|
|
1647
1693
|
entities?: SourceEntity[];
|
|
1648
1694
|
routes?: SourceRoute[];
|
|
1649
1695
|
}
|
|
@@ -1671,6 +1717,8 @@ export function describeSource(spec: SourceSpec): string {
|
|
|
1671
1717
|
return `routes of ${spec.export} in ${spec.file}${spec.path_prefix ? ` under ${spec.path_prefix}` : ""}`;
|
|
1672
1718
|
case "validator":
|
|
1673
1719
|
return `validator ${spec.export} in ${spec.file}`;
|
|
1720
|
+
case "prolog":
|
|
1721
|
+
return `${spec.functor} facts in ${spec.file}${spec.arg ? ` (argument ${spec.arg})` : ""}`;
|
|
1674
1722
|
}
|
|
1675
1723
|
}
|
|
1676
1724
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
id: kibi-usage
|
|
3
3
|
name: Kibi Usage
|
|
4
4
|
description: Use Kibi's source-first, exact-Git, migration-aware, proof-aware operations safely across MCP or the trusted local CLI, including partial completion repair.
|
|
5
|
-
version: 2.
|
|
5
|
+
version: 2.40.1
|
|
6
6
|
kibiCompatibility: ">=1.0.0"
|
|
7
7
|
tags:
|
|
8
8
|
- kibi
|
|
@@ -20,6 +20,7 @@ resources:
|
|
|
20
20
|
- resources/fact-lanes.md
|
|
21
21
|
- resources/workflows.md
|
|
22
22
|
- resources/proof.md
|
|
23
|
+
- resources/prolog-proofs.md
|
|
23
24
|
- resources/ui-requirements.md
|
|
24
25
|
- resources/logic-ir.md
|
|
25
26
|
- resources/kb-improvement.md
|
|
@@ -94,8 +95,10 @@ it is a pointer to the knowledge, never proof. Each line answers one question:
|
|
|
94
95
|
requirement first. Read the lead requirement with `kb_query({id})` before
|
|
95
96
|
changing behavior; add `includeBody: true` to see its authored prose, and
|
|
96
97
|
fix a stale sentence there with `kb_upsert` `document.body`.
|
|
97
|
-
- `REQ-… must keep true:
|
|
98
|
-
|
|
98
|
+
- `REQ-… must keep true: <claim>` (edit only): what the lead requirement
|
|
99
|
+
requires, as the claims its facts model (with the operator and members,
|
|
100
|
+
such as "The greet function must not call console.log") or, without
|
|
101
|
+
them, its own statement. An edit that breaks one of them is a requirement
|
|
99
102
|
change: ask before changing the rule (see Decision firmness), and never
|
|
100
103
|
code around the fact.
|
|
101
104
|
- `Decision: ADR-…` (edit only): the decision behind the lead requirement.
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# SWI-Prolog Code Proofs
|
|
2
|
+
|
|
3
|
+
Kibi reads code models from SWI-Prolog files (`.pl`, `.plt`) with the
|
|
4
|
+
SWI-Prolog it runs on (KIBI_SWIPL, the bundled runtime, then `swipl` on
|
|
5
|
+
PATH). It loads the file a symbol names (a module, or a plain file into
|
|
6
|
+
`user`) and reads a predicate named by its indicator, the symbol's title
|
|
7
|
+
(`operator/2`, `lists:append/3`, `greeting//1`) or `export`.
|
|
8
|
+
|
|
9
|
+
- A domain (`exhaustive`, `domains`, `value_source` with `measure: count`)
|
|
10
|
+
is the distinct solutions of one argument. A one-argument predicate needs
|
|
11
|
+
nothing more; for more arguments set `arg` (1-based) to the one that names
|
|
12
|
+
each member: `domain_source: {symbol_id: SYM-operator, arg: 1}` lists every
|
|
13
|
+
`Name` of `operator(Name, Description)`. A solution that leaves that
|
|
14
|
+
argument unbound refuses the read.
|
|
15
|
+
- A value (`value_source`) is the single number a constant holds:
|
|
16
|
+
`hard_limit_seconds(10).` Zero or several solutions refuse the read.
|
|
17
|
+
- A `rule` predicate is called once per row of its argument domains; success
|
|
18
|
+
is true, failure false, an exception an error row (which rejects).
|
|
19
|
+
- A `state_machine` transition table is a `Name/2` (from, to) or `Name/3`
|
|
20
|
+
(from, event, to) fact table: every solution is an edge. With `domains:
|
|
21
|
+
{state, event}` a `Name/3` next-state predicate is called on every state
|
|
22
|
+
and event. `initial_source` names an `initial/1`-style fact.
|
|
23
|
+
- A `regex` reads an atom or string constant as a `type: string` pattern;
|
|
24
|
+
Kibi decides string facts on it. Patterns for `library(pcre)` are not read.
|
|
25
|
+
|
|
26
|
+
Loading a module runs its directives, the same trust a JavaScript import
|
|
27
|
+
gives. The proof file must name the predicate and load its file
|
|
28
|
+
(`use_module`, `ensure_loaded`, `consult`, a `:- [..]` load list, or
|
|
29
|
+
`library(X)` for a pack's `prolog/X.pl`), or be the plunit `.plt` file
|
|
30
|
+
beside it; otherwise Kibi treats the domain as hand-listed. `arg` on a
|
|
31
|
+
TypeScript, JavaScript or Python export is refused, and so is `field` on a
|
|
32
|
+
Prolog predicate.
|
|
33
|
+
|
|
34
|
+
## Writing the certificate
|
|
35
|
+
|
|
36
|
+
A Prolog test writes the `kibi.code-certificate.v1` JSON into the directory
|
|
37
|
+
`kibi prove` sets in `KIBI_PROOF_CERTIFICATES`. Copy this module into the
|
|
38
|
+
project's test directory (for example `test/kibi_certificate.pl`) and call it
|
|
39
|
+
from the proof. Read members from the code with `findall/3` over the domain
|
|
40
|
+
predicate; never list them by hand.
|
|
41
|
+
|
|
42
|
+
```prolog
|
|
43
|
+
:- module(kibi_certificate,
|
|
44
|
+
[ kibi_exhaustive_certificate/5, % +TestId, +SymbolId, +Members, :Check, -Certificate
|
|
45
|
+
kibi_rule_certificate/4, % +TestId, +Domains, +Predicates, -Certificate
|
|
46
|
+
kibi_machine_certificate/5, % +TestId, +SymbolId, +Edges, +Initial, -Certificate
|
|
47
|
+
kibi_pattern_certificate/4, % +TestId, +SymbolId, +Text, -Certificate
|
|
48
|
+
kibi_write_certificate/1 % +Certificate
|
|
49
|
+
]).
|
|
50
|
+
:- use_module(library(http/json)).
|
|
51
|
+
:- use_module(library(apply)).
|
|
52
|
+
:- use_module(library(lists)).
|
|
53
|
+
|
|
54
|
+
:- meta_predicate
|
|
55
|
+
kibi_exhaustive_certificate(+, +, +, 1, -).
|
|
56
|
+
|
|
57
|
+
% Members as Kibi reads them: atoms and strings as text, numbers as written,
|
|
58
|
+
% other terms quoted.
|
|
59
|
+
kibi_text(Value, Text) :- string(Value), !, Text = Value.
|
|
60
|
+
kibi_text(Value, Text) :- atom(Value), !, atom_string(Value, Text).
|
|
61
|
+
kibi_text(Value, Text) :- number(Value), !, number_string(Value, Text).
|
|
62
|
+
kibi_text(Value, Text) :- format(string(Text), "~q", [Value]).
|
|
63
|
+
|
|
64
|
+
%! kibi_exhaustive_certificate(+TestId, +SymbolId, +Members, :Check, -Certificate)
|
|
65
|
+
%
|
|
66
|
+
% Run Check on every member of the domain and record each outcome. Read
|
|
67
|
+
% Members from the code (findall over the domain predicate), never list
|
|
68
|
+
% them by hand: Kibi re-reads the predicate and rejects a different set.
|
|
69
|
+
kibi_exhaustive_certificate(TestId, SymbolId, Members, Check, Certificate) :-
|
|
70
|
+
maplist(kibi_text, Members, Texts),
|
|
71
|
+
maplist(exhaustive_result(Check), Members, Texts, Results),
|
|
72
|
+
Certificate = _{version: "kibi.code-certificate.v1", kind: "exhaustive",
|
|
73
|
+
test_id: TestId,
|
|
74
|
+
domain: _{symbol_id: SymbolId, members: Texts},
|
|
75
|
+
results: Results}.
|
|
76
|
+
|
|
77
|
+
exhaustive_result(Check, Member, Text, Result) :-
|
|
78
|
+
catch(( call(Check, Member)
|
|
79
|
+
-> Result = _{member: Text, outcome: "passed"}
|
|
80
|
+
; Result = _{member: Text, outcome: "failed", message: "the check failed"}
|
|
81
|
+
),
|
|
82
|
+
Error,
|
|
83
|
+
( message_to_text(Error, Message),
|
|
84
|
+
Result = _{member: Text, outcome: "failed", message: Message} )).
|
|
85
|
+
|
|
86
|
+
%! kibi_rule_certificate(+TestId, +Domains, +Predicates, -Certificate)
|
|
87
|
+
%
|
|
88
|
+
% Domains is a list of domain(Type, SymbolId, Members); Predicates a list
|
|
89
|
+
% of predicate(Name, SymbolId, ArgTypes, Goal), where Goal is called with
|
|
90
|
+
% one argument per type appended and decides the row by success or
|
|
91
|
+
% failure.
|
|
92
|
+
kibi_rule_certificate(TestId, Domains, Predicates, Certificate) :-
|
|
93
|
+
findall(Type-_{symbol_id: SymbolId, members: Texts},
|
|
94
|
+
( member(domain(Type, SymbolId, Members), Domains), maplist(kibi_text, Members, Texts) ),
|
|
95
|
+
DomainPairs),
|
|
96
|
+
dict_pairs(DomainDict, _, DomainPairs),
|
|
97
|
+
findall(Name-_{symbol_id: SymbolId, arg_types: ArgTypes, rows: Rows},
|
|
98
|
+
( member(predicate(Name, SymbolId, ArgTypes, Goal), Predicates),
|
|
99
|
+
maplist(domain_members(Domains), ArgTypes, Lists),
|
|
100
|
+
findall(Row, (maplist(member, Tuple, Lists), rule_row(Goal, Tuple, Row)), Rows)
|
|
101
|
+
),
|
|
102
|
+
PredicatePairs),
|
|
103
|
+
dict_pairs(PredicateDict, _, PredicatePairs),
|
|
104
|
+
Certificate = _{version: "kibi.code-certificate.v1", kind: "rule",
|
|
105
|
+
test_id: TestId, domains: DomainDict, predicates: PredicateDict}.
|
|
106
|
+
|
|
107
|
+
domain_members(Domains, Type, Members) :-
|
|
108
|
+
memberchk(domain(Type, _, Members), Domains).
|
|
109
|
+
|
|
110
|
+
rule_row(Goal, Tuple, Row) :-
|
|
111
|
+
maplist(kibi_text, Tuple, Args),
|
|
112
|
+
Call =.. [call, Goal|Tuple],
|
|
113
|
+
catch(( once(Call) -> Row = _{args: Args, value: true} ; Row = _{args: Args, value: false} ),
|
|
114
|
+
Error,
|
|
115
|
+
( message_to_text(Error, Message), Row = _{args: Args, error: Message} )).
|
|
116
|
+
|
|
117
|
+
%! kibi_machine_certificate(+TestId, +SymbolId, +Edges, +Initial, -Certificate)
|
|
118
|
+
%
|
|
119
|
+
% Edges is the list of From-To pairs of the transition table (findall over
|
|
120
|
+
% it); Initial is the list of initial states, or [] when the contract names
|
|
121
|
+
% no initial_source.
|
|
122
|
+
kibi_machine_certificate(TestId, SymbolId, Edges, Initial, Certificate) :-
|
|
123
|
+
findall([F, T], (member(From-To, Edges), kibi_text(From, F), kibi_text(To, T)), Pairs0),
|
|
124
|
+
sort(Pairs0, Pairs),
|
|
125
|
+
findall(S, (member([A, B], Pairs), member(S, [A, B])), Ends),
|
|
126
|
+
sort(Ends, States),
|
|
127
|
+
Machine0 = _{symbol_id: SymbolId, states: States, transitions: Pairs},
|
|
128
|
+
( Initial == []
|
|
129
|
+
-> Machine = Machine0
|
|
130
|
+
; maplist(kibi_text, Initial, InitialTexts0),
|
|
131
|
+
sort(InitialTexts0, InitialTexts),
|
|
132
|
+
Machine = Machine0.put(initial, InitialTexts)
|
|
133
|
+
),
|
|
134
|
+
Certificate = _{version: "kibi.code-certificate.v1", kind: "state_machine",
|
|
135
|
+
test_id: TestId, machine: Machine}.
|
|
136
|
+
|
|
137
|
+
%! kibi_pattern_certificate(+TestId, +SymbolId, +Text, -Certificate)
|
|
138
|
+
%
|
|
139
|
+
% The string or atom constant a string claim is about.
|
|
140
|
+
kibi_pattern_certificate(TestId, SymbolId, Value, Certificate) :-
|
|
141
|
+
kibi_text(Value, Text),
|
|
142
|
+
Certificate = _{version: "kibi.code-certificate.v1", kind: "regex", test_id: TestId,
|
|
143
|
+
pattern: _{symbol_id: SymbolId, type: "string", value: Text}}.
|
|
144
|
+
|
|
145
|
+
%! kibi_write_certificate(+Certificate)
|
|
146
|
+
%
|
|
147
|
+
% Leave the certificate where kibi prove reads it (the directory in
|
|
148
|
+
% KIBI_PROOF_CERTIFICATES). Does nothing outside a kibi prove run.
|
|
149
|
+
kibi_write_certificate(Certificate) :-
|
|
150
|
+
( getenv('KIBI_PROOF_CERTIFICATES', Directory), Directory \== ''
|
|
151
|
+
-> make_directory_path(Directory),
|
|
152
|
+
format(atom(Name), "~w.json", [Certificate.test_id]),
|
|
153
|
+
directory_file_path(Directory, Name, File),
|
|
154
|
+
setup_call_cleanup(open(File, write, Out, [encoding(utf8)]),
|
|
155
|
+
json_write_dict(Out, Certificate, [width(0)]),
|
|
156
|
+
close(Out))
|
|
157
|
+
; true
|
|
158
|
+
).
|
|
159
|
+
|
|
160
|
+
message_to_text(Error, Text) :-
|
|
161
|
+
catch(message_to_codes(Error, Text), _, fail), !.
|
|
162
|
+
message_to_text(Error, Text) :- format(string(Text), "~q", [Error]).
|
|
163
|
+
|
|
164
|
+
message_to_codes(Error, Text) :-
|
|
165
|
+
'$messages':translate_message(Error, Lines, []),
|
|
166
|
+
with_output_to(string(Raw), print_message_lines(current_output, '', Lines)),
|
|
167
|
+
split_string(Raw, "", "\n ", [Text]).
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
A proof that the operators are exactly the claimed set:
|
|
171
|
+
|
|
172
|
+
```prolog
|
|
173
|
+
:- use_module('../prolog/operators').
|
|
174
|
+
:- use_module(kibi_certificate).
|
|
175
|
+
:- initialization(main, main).
|
|
176
|
+
|
|
177
|
+
main :-
|
|
178
|
+
findall(Name, operator(Name, _), Names0),
|
|
179
|
+
list_to_set(Names0, Names),
|
|
180
|
+
kibi_exhaustive_certificate('TEST-operator-set', 'SYM-operator', Names,
|
|
181
|
+
[Name]>>operator(Name, _), Certificate),
|
|
182
|
+
kibi_write_certificate(Certificate).
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Its contract: `kind: exhaustive`, `domain_source: {symbol_id: SYM-operator,
|
|
186
|
+
arg: 1}`, `proves: [CLAIM-...]`. A rule proof passes
|
|
187
|
+
`[domain(status, 'SYM-status', Statuses)]` and
|
|
188
|
+
`[predicate(detected, 'SYM-detected', [status], detected)]`; its contract
|
|
189
|
+
names `predicate_source: {detected: {symbol_id: SYM-detected}}` and
|
|
190
|
+
`domains: {status: {symbol_id: SYM-status}}`.
|
|
191
|
+
|
|
192
|
+
## Source proofs over Prolog code
|
|
193
|
+
|
|
194
|
+
A `source` proof needs no certificate: Kibi reads the Prolog files itself,
|
|
195
|
+
term by term, and never runs them. Use the `references` reader on `.pl` and
|
|
196
|
+
`.plt` files for what modules load (`extract: imports`, members as written:
|
|
197
|
+
`library(lists)`, `helpers`), call (`calls`, `Name/Arity` or
|
|
198
|
+
`Module:Name/Arity`), read from the environment (`env`, `getenv/2`), pass as
|
|
199
|
+
a first argument (`string_args` with `callee`) and throw (`thrown`: the error
|
|
200
|
+
of `error(type_error(...), _)` is `type_error`). Use the `prolog` reader for
|
|
201
|
+
facts: `{reader: prolog, file: pack.pl, functor: requires/1}` lists a pack's
|
|
202
|
+
requirements, and `arg` picks the argument of a fact with several. A goal or
|
|
203
|
+
closure held in a variable (`call(Goal)`, `maplist(G, L)`), a goal with a
|
|
204
|
+
variable module, a clause asserted from a variable and `:- if(...)` fail the
|
|
205
|
+
read with their place: name the predicate instead. The claim cannot be
|
|
206
|
+
decided for a file the read refuses; never drop a file the claim is about
|
|
207
|
+
from `files`.
|