kibi-cli 2.31.1 → 2.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-register-proof.d.ts.map +1 -1
- package/dist/cli-register-proof.js +19 -7
- package/dist/cli-register-reporting.d.ts.map +1 -1
- package/dist/cli-register-reporting.js +2 -0
- 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/check.d.ts +1 -0
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +14 -5
- package/dist/commands/discovery-table.d.ts.map +1 -1
- package/dist/commands/discovery-table.js +51 -4
- package/dist/commands/doctor.js +19 -4
- 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 +109 -5
- package/dist/commands/prove.d.ts +48 -1
- package/dist/commands/prove.d.ts.map +1 -1
- package/dist/commands/prove.js +293 -8
- package/dist/commands/report.d.ts +1 -0
- package/dist/commands/report.d.ts.map +1 -1
- package/dist/commands/report.js +70 -5
- package/dist/commands/signoff.d.ts.map +1 -1
- package/dist/commands/signoff.js +20 -1
- 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 +106 -17
- package/dist/commands/sync/persistence.d.ts.map +1 -1
- package/dist/commands/sync/persistence.js +16 -5
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +19 -0
- package/dist/diagnostics.js +1 -1
- package/dist/engine.js +1 -1
- package/dist/extractors/markdown.d.ts +4 -2
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +17 -0
- 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/bootstrap/candidate-helpers.d.ts +3 -0
- package/dist/operations/bootstrap/candidate-helpers.d.ts.map +1 -1
- package/dist/operations/bootstrap/candidate-helpers.js +4 -0
- package/dist/operations/migration/evidence-floor.d.ts +41 -0
- package/dist/operations/migration/evidence-floor.d.ts.map +1 -0
- package/dist/operations/migration/evidence-floor.js +230 -0
- package/dist/operations/migration/proof-contract-claims.d.ts +72 -0
- package/dist/operations/migration/proof-contract-claims.d.ts.map +1 -0
- package/dist/operations/migration/proof-contract-claims.js +215 -0
- package/dist/operations/migration/schema6.d.ts +6 -0
- package/dist/operations/migration/schema6.d.ts.map +1 -1
- package/dist/operations/migration/schema6.js +92 -0
- 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/omitted-properties.d.ts +11 -0
- package/dist/operations/mutation/omitted-properties.d.ts.map +1 -0
- package/dist/operations/mutation/omitted-properties.js +76 -0
- package/dist/operations/mutation/serialization.d.ts.map +1 -1
- package/dist/operations/mutation/serialization.js +1 -0
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +39 -20
- package/dist/operations/mutation/strict-fact.d.ts.map +1 -1
- package/dist/operations/mutation/strict-fact.js +6 -2
- package/dist/operations/mutation/symbol-granularity.d.ts.map +1 -1
- package/dist/operations/mutation/symbol-granularity.js +5 -3
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +7 -1
- package/dist/operations/mutation/validation.d.ts +2 -0
- package/dist/operations/mutation/validation.d.ts.map +1 -1
- package/dist/operations/mutation/validation.js +4 -0
- package/dist/operations/proof/claim-bindings.d.ts +41 -0
- package/dist/operations/proof/claim-bindings.d.ts.map +1 -0
- package/dist/operations/proof/claim-bindings.js +364 -0
- package/dist/operations/proof/code-certificates.d.ts +155 -0
- package/dist/operations/proof/code-certificates.d.ts.map +1 -0
- package/dist/operations/proof/code-certificates.js +894 -0
- 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 +14 -1
- package/dist/operations/proof/code-scope.d.ts.map +1 -1
- package/dist/operations/proof/code-scope.js +44 -2
- package/dist/operations/proof/compact-receipts.d.ts.map +1 -1
- package/dist/operations/proof/compact-receipts.js +4 -3
- package/dist/operations/proof/explain.d.ts +32 -0
- package/dist/operations/proof/explain.d.ts.map +1 -1
- package/dist/operations/proof/explain.js +91 -0
- package/dist/operations/proof/ingest-proof.d.ts +9 -1
- package/dist/operations/proof/ingest-proof.d.ts.map +1 -1
- package/dist/operations/proof/ingest-proof.js +42 -2
- package/dist/operations/proof/receipt-compaction.d.ts +2 -0
- package/dist/operations/proof/receipt-compaction.d.ts.map +1 -1
- package/dist/operations/proof/receipt-compaction.js +6 -2
- 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/shared.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/shared.js +4 -0
- 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 +234 -4
- package/dist/operations/semantic-advisor/types.d.ts +3 -2
- package/dist/operations/semantic-advisor/types.d.ts.map +1 -1
- package/dist/plugins/approved-source-analyzers.generated.d.ts +6 -6
- package/dist/plugins/approved-source-analyzers.generated.js +6 -6
- package/dist/prolog.d.ts.map +1 -1
- package/dist/prolog.js +13 -3
- package/dist/proof/command-test-report.d.ts +4 -3
- package/dist/proof/command-test-report.d.ts.map +1 -1
- package/dist/proof/command-test-report.js +4 -10
- package/dist/proof/evaluate.d.ts.map +1 -1
- package/dist/proof/evaluate.js +18 -2
- package/dist/proof/inspect.d.ts.map +1 -1
- package/dist/proof/inspect.js +58 -0
- package/dist/proof/producers/playwright-reporter.d.ts +3 -0
- package/dist/proof/producers/playwright-reporter.d.ts.map +1 -1
- package/dist/proof/producers/playwright-reporter.js +25 -2
- package/dist/proof/step-runner.d.ts +36 -0
- package/dist/proof/step-runner.d.ts.map +1 -0
- package/dist/proof/step-runner.js +234 -0
- package/dist/public/evidence-levels.d.ts +12 -0
- package/dist/public/evidence-levels.d.ts.map +1 -0
- package/dist/public/evidence-levels.js +19 -0
- package/dist/public/impact/coverage-depth-quality.d.ts +7 -0
- package/dist/public/impact/coverage-depth-quality.d.ts.map +1 -1
- package/dist/public/impact/coverage-depth-quality.js +59 -0
- package/dist/public/impact/full-kb-quality.d.ts.map +1 -1
- package/dist/public/impact/full-kb-quality.js +3 -1
- package/dist/public/operations/catalog.d.ts +315 -11
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/check-executor.d.ts +2 -0
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +6 -0
- package/dist/public/operations/evidence-floor.d.ts +48 -0
- package/dist/public/operations/evidence-floor.d.ts.map +1 -0
- package/dist/public/operations/evidence-floor.js +143 -0
- package/dist/public/operations/migration-plan.d.ts +19 -5
- package/dist/public/operations/migration-plan.d.ts.map +1 -1
- package/dist/public/operations/migration-plan.js +22 -5
- package/dist/public/operations/node-ports.d.ts.map +1 -1
- package/dist/public/operations/node-ports.js +4 -1
- package/dist/public/operations/proof-contract-claims.d.ts +26 -0
- package/dist/public/operations/proof-contract-claims.d.ts.map +1 -0
- package/dist/public/operations/proof-contract-claims.js +71 -0
- 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 +3 -1
- package/dist/public/operations/specs/check.d.ts +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 +289 -7
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +28 -4
- package/dist/public/operations/specs/proof.d.ts +9 -0
- package/dist/public/operations/specs/proof.d.ts.map +1 -1
- package/dist/public/operations/specs/reporting.d.ts.map +1 -1
- package/dist/public/operations/specs/reporting.js +19 -10
- package/dist/public/operations/specs/upsert.d.ts +289 -7
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/proof-certificates.d.ts +163 -0
- package/dist/public/proof-certificates.d.ts.map +1 -0
- package/dist/public/proof-certificates.js +419 -0
- package/dist/public/proof-protocol.d.ts +259 -3
- package/dist/public/proof-protocol.d.ts.map +1 -1
- package/dist/public/proof-protocol.js +524 -3
- package/dist/public/proof-receipt.d.ts +90 -6
- package/dist/public/proof-receipt.d.ts.map +1 -1
- package/dist/public/proof-receipt.js +88 -7
- 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 +39 -2
- package/dist/public/skills/kibi-bootstrap/SKILL.md +2 -2
- package/dist/public/skills/kibi-commit-review/SKILL.md +8 -8
- package/dist/public/skills/kibi-commit-review/resources/staged-gate.md +12 -7
- package/dist/public/skills/kibi-decisions/SKILL.md +13 -2
- package/dist/public/skills/kibi-decisions/resources/decision-records.md +9 -1
- package/dist/public/skills/kibi-freshness/SKILL.md +5 -1
- package/dist/public/skills/kibi-traceability/SKILL.md +12 -1
- package/dist/public/skills/kibi-usage/SKILL.md +8 -4
- package/dist/public/skills/kibi-usage/resources/proof.md +221 -20
- package/dist/public/skills/kibi-usage/resources/workflows.md +4 -4
- package/dist/report/html-report.css +83 -11
- package/dist/report/html-report.d.ts +8 -0
- package/dist/report/html-report.d.ts.map +1 -1
- package/dist/report/html-report.js +214 -22
- package/dist/report/report-view.d.ts +2 -2
- package/dist/report/report-view.d.ts.map +1 -1
- package/dist/report/report-view.js +8 -0
- package/dist/schemas/entity.schema.json +404 -5
- package/dist/search-answer.d.ts.map +1 -1
- package/dist/search-answer.js +1 -0
- package/dist/signoff/html.d.ts.map +1 -1
- package/dist/signoff/html.js +3 -0
- package/dist/signoff/markdown.d.ts.map +1 -1
- package/dist/signoff/markdown.js +3 -0
- package/dist/signoff/model.d.ts +20 -0
- package/dist/signoff/model.d.ts.map +1 -1
- package/dist/signoff/model.js +20 -1
- 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/impact-knowledge.d.ts.map +1 -1
- package/dist/traceability/impact-knowledge.js +1 -0
- 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/traceability/temp-kb.d.ts.map +1 -1
- package/dist/traceability/temp-kb.js +1 -0
- package/dist/types/entities.d.ts +5 -2
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/utils/merge-driver-setup.d.ts +8 -1
- package/dist/utils/merge-driver-setup.d.ts.map +1 -1
- package/dist/utils/merge-driver-setup.js +23 -2
- package/dist/utils/rule-registry.generated.d.ts +10 -0
- package/dist/utils/rule-registry.generated.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.js +12 -0
- 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 +7 -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 +6 -2
- package/schema/entities.pl +6 -0
- package/schema/validation.pl +7 -2
- package/src/public/evidence-levels.ts +23 -0
- package/src/public/impact/coverage-depth-quality.ts +73 -0
- package/src/public/impact/full-kb-quality.ts +6 -1
- package/src/public/operations/check-executor.ts +13 -0
- package/src/public/operations/evidence-floor.ts +203 -0
- package/src/public/operations/migration-plan.ts +39 -6
- package/src/public/operations/node-ports.ts +3 -1
- package/src/public/operations/proof-contract-claims.ts +103 -0
- package/src/public/operations/specs/check-rules.generated.ts +3 -1
- package/src/public/operations/specs/modeling.ts +24 -5
- package/src/public/operations/specs/mutation-schemas.ts +30 -4
- package/src/public/operations/specs/reporting.ts +20 -10
- package/src/public/proof-certificates.ts +566 -0
- package/src/public/proof-protocol-types.d.ts +69 -1
- package/src/public/proof-protocol.ts +694 -3
- package/src/public/proof-receipt.ts +133 -7
- package/src/public/proof-sources.ts +1656 -0
- package/src/public/schemas/entity.ts +51 -3
- package/src/public/skills/kibi-bootstrap/SKILL.md +2 -2
- package/src/public/skills/kibi-commit-review/SKILL.md +8 -8
- package/src/public/skills/kibi-commit-review/resources/staged-gate.md +12 -7
- package/src/public/skills/kibi-decisions/SKILL.md +13 -2
- package/src/public/skills/kibi-decisions/resources/decision-records.md +9 -1
- package/src/public/skills/kibi-freshness/SKILL.md +5 -1
- package/src/public/skills/kibi-traceability/SKILL.md +12 -1
- package/src/public/skills/kibi-usage/SKILL.md +8 -4
- package/src/public/skills/kibi-usage/resources/proof.md +221 -20
- package/src/public/skills/kibi-usage/resources/workflows.md +4 -4
- package/src/schemas/entity.schema.json +404 -5
- package/dist/commands/proof-impact.d.ts +0 -7
- package/dist/commands/proof-impact.d.ts.map +0 -1
- package/dist/commands/proof-impact.js +0 -39
- package/dist/operations/proof/baseline-diff.d.ts +0 -41
- package/dist/operations/proof/baseline-diff.d.ts.map +0 -1
- package/dist/operations/proof/baseline-diff.js +0 -153
- package/dist/operations/proof/impact.d.ts +0 -51
- package/dist/operations/proof/impact.d.ts.map +0 -1
- package/dist/operations/proof/impact.js +0 -138
- 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
|
@@ -5,6 +5,7 @@ const PROPERTY_VALUE_FIELDS = [
|
|
|
5
5
|
"value_int",
|
|
6
6
|
"value_number",
|
|
7
7
|
"value_bool",
|
|
8
|
+
"value_set",
|
|
8
9
|
];
|
|
9
10
|
// implements REQ-kibi-operation-interface-parity
|
|
10
11
|
export function valueFieldHint(value) {
|
|
@@ -19,7 +20,10 @@ export function valueFieldHint(value) {
|
|
|
19
20
|
if (typeof value === "string") {
|
|
20
21
|
return `Use value_type: "string" plus value_string: ${JSON.stringify(value)}.`;
|
|
21
22
|
}
|
|
22
|
-
|
|
23
|
+
if (Array.isArray(value)) {
|
|
24
|
+
return `Use value_type: "set" plus value_set: ${JSON.stringify(value)}.`;
|
|
25
|
+
}
|
|
26
|
+
return "Use value_type plus exactly one of value_string, value_int, value_number, value_bool, or value_set.";
|
|
23
27
|
}
|
|
24
28
|
// implements REQ-kibi-operation-interface-parity
|
|
25
29
|
export function factKindShapeHints(entity) {
|
|
@@ -38,7 +42,7 @@ export function factKindShapeHints(entity) {
|
|
|
38
42
|
hints.push(`fact_kind 'property_value' requires ${missing.join(", ")}.`);
|
|
39
43
|
}
|
|
40
44
|
if (present.length !== 1) {
|
|
41
|
-
hints.push("fact_kind 'property_value' requires exactly one typed value field: value_string, value_int, value_number, or
|
|
45
|
+
hints.push("fact_kind 'property_value' requires exactly one typed value field: value_string, value_int, value_number, value_bool, or value_set.");
|
|
42
46
|
}
|
|
43
47
|
if (hints.length > 0) {
|
|
44
48
|
hints.push("Next action: use kb_model_requirement for prose claims, or provide subject_key, property_key, operator, value_type, and one value_* field in kb_upsert.properties.");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"symbol-granularity.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/symbol-granularity.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAajF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AA0BpD;;;;GAIG;AAEH,eAAO,MAAM,4BAA4B,iCAAiC,CAAC;AA+B3E,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC1C,aAAa,EAAE,SAAS,iBAAiB,EAAE,EAC3C,OAAO,EAAE,gBAAgB,EACzB,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC,GAC3E,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"symbol-granularity.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/symbol-granularity.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAajF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AA0BpD;;;;GAIG;AAEH,eAAO,MAAM,4BAA4B,iCAAiC,CAAC;AA+B3E,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC1C,aAAa,EAAE,SAAS,iBAAiB,EAAE,EAC3C,OAAO,EAAE,gBAAgB,EACzB,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC,GAC3E,OAAO,CAAC,IAAI,CAAC,CAoDf"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { collectGranularityCandidates } from "kibi-plugin-builtin";
|
|
2
2
|
import { InputError } from "../../cli-errors.js";
|
|
3
|
-
import { resolveWorkspaceSourceAbsolute } from "../../utils/repo-relative-path.js";
|
|
4
3
|
import { ALLOWED_GRANULARITY_REASONS_PROSE, coarseLinkBehavioralNames, getBehavioralSymbolNames, getNonBehavioralSymbolNames, inferSymbolRole, isAllowedGranularityReason, isTraceabilityRelationshipType, } from "../../public/symbol-granularity.js";
|
|
4
|
+
import { resolveWorkspaceSourceAbsolute } from "../../utils/repo-relative-path.js";
|
|
5
5
|
function candidate(name, kind) {
|
|
6
6
|
return { name, kind, role: inferSymbolRole(kind) };
|
|
7
7
|
}
|
|
@@ -86,8 +86,10 @@ export async function validateSymbolGranularity(payload, relationships, context,
|
|
|
86
86
|
// A declaration named like the symbol is coarse only through its own
|
|
87
87
|
// behavioral members (a class and its public methods), the same test the
|
|
88
88
|
// staged gate and `kibi check` apply; any other title is judged against
|
|
89
|
-
// every behavioral declaration in the file.
|
|
90
|
-
|
|
89
|
+
// every behavioral declaration in the file. An exported constant is its
|
|
90
|
+
// own declaration with exact coordinates (a certificate proof's domain is
|
|
91
|
+
// one), so it is granular whatever its role.
|
|
92
|
+
const behavioral = exact
|
|
91
93
|
? coarseLinkBehavioralNames(entity.title, available)
|
|
92
94
|
: getBehavioralSymbolNames(available);
|
|
93
95
|
if (behavioral.length === 0)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upsert.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/upsert.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAexE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"upsert.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/upsert.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,6 +16,7 @@ import { assertLogicalGroundingClaimKeys, assertSemanticInventoryBoundary, } fro
|
|
|
16
16
|
import { entityContextWarnings } from "./context-warning.js";
|
|
17
17
|
import { buildUpsertCommitGoal, formatUpsertError } from "./contradictions.js";
|
|
18
18
|
import { assertFirmDecisionUnchanged } from "./firm-decision-guard.js";
|
|
19
|
+
import { withStoredOmittedProperties } from "./omitted-properties.js";
|
|
19
20
|
import { resolveUpsertOrigin } from "./origin.js";
|
|
20
21
|
import { planRecoveryNotes, settlePendingPlanApplyJournals, withPlanRecoveryNotes, } from "./plan-apply-journal.js";
|
|
21
22
|
import { assertPredicateArgumentVocabulary } from "./predicate-vocabulary-guard.js";
|
|
@@ -279,7 +280,12 @@ export async function validateUpsertForCommit(payload, context, options = {}) {
|
|
|
279
280
|
// than later by the staged gate.
|
|
280
281
|
if (checked.entity.sourceFile === undefined)
|
|
281
282
|
await validateSymbolGranularity(checked.entity, checked.relationships, context, async () => staged?.entities.get(payload.id) ?? (await lookup.entity()));
|
|
282
|
-
|
|
283
|
+
const withSemantics = await withStoredRequirementSemantics(payload, prolog, staged, lookup);
|
|
284
|
+
// An uncompiled file is judged as the writer will patch it (below), so only
|
|
285
|
+
// a compiled entity lends its omitted properties to the stored write.
|
|
286
|
+
let input = uncompiledSource === null
|
|
287
|
+
? await withStoredOmittedProperties(withSemantics, lookup, staged)
|
|
288
|
+
: withSemantics;
|
|
283
289
|
let validated = input === payload ? checked : validateUpsertInput(input, context.clock());
|
|
284
290
|
if (uncompiledSource !== null)
|
|
285
291
|
lookup = {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { isAllowedGranularityReason } from "../../public/symbol-granularity.js";
|
|
2
2
|
import type { UpsertInput, ValidatedUpsert } from "./types.js";
|
|
3
|
+
/** Whether the upsert entity schema defines `key` as an entity property. */
|
|
4
|
+
export declare function isUpsertEntityProperty(key: string): boolean;
|
|
3
5
|
export declare function validateUpsertInput(input: UpsertInput, now: Date): ValidatedUpsert;
|
|
4
6
|
export { isAllowedGranularityReason };
|
|
5
7
|
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/validation.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,0BAA0B,EAC3B,MAAM,oCAAoC,CAAC;AAU5C,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/validation.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,0BAA0B,EAC3B,MAAM,oCAAoC,CAAC;AAU5C,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AA2D/D,4EAA4E;AAC5E,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAK3D;AA4JD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,WAAW,EAClB,GAAG,EAAE,IAAI,GACR,eAAe,CA6DjB;AAED,OAAO,EAAE,0BAA0B,EAAE,CAAC"}
|
|
@@ -59,6 +59,10 @@ const DOCUMENT_TEXT_PROPERTIES = new Set([
|
|
|
59
59
|
"summary",
|
|
60
60
|
"details",
|
|
61
61
|
]);
|
|
62
|
+
/** Whether the upsert entity schema defines `key` as an entity property. */
|
|
63
|
+
export function isUpsertEntityProperty(key) {
|
|
64
|
+
return Object.hasOwn(upsertEntitySchema.properties, key);
|
|
65
|
+
}
|
|
62
66
|
/** Every top-level entity key the upsert entity schema does not define. */
|
|
63
67
|
function unknownEntityProperties(entity) {
|
|
64
68
|
const known = upsertEntitySchema.properties;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { OperationContext } from "../../public/operations/runtime-types.js";
|
|
2
|
+
import type { ProofContract } from "../../public/proof-protocol.js";
|
|
3
|
+
import type { ClaimBinding } from "../../public/proof-receipt.js";
|
|
4
|
+
import { type CertificateVerdict } from "./code-certificates.js";
|
|
5
|
+
/**
|
|
6
|
+
* The type-level witness Kibi writes for a typecheck claim binding: it
|
|
7
|
+
* compiles only when the domain type has exactly the fact's members.
|
|
8
|
+
*/
|
|
9
|
+
export declare function setEqualityWitness(importPath: string, members: readonly string[], membersType: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* The type-level witness Kibi writes for a required_fields claim binding: it
|
|
12
|
+
* compiles only when every field is a required key of the type whose value
|
|
13
|
+
* can be neither undefined nor null. Each field has its own two lines (`key<i>`
|
|
14
|
+
* that the field exists, `required<i>` that it is required and non-null), so
|
|
15
|
+
* a failed compile says which fields break the claim.
|
|
16
|
+
*/
|
|
17
|
+
export declare function requiredFieldsWitness(importPath: string, typeExpression: string, fields: readonly string[]): string;
|
|
18
|
+
/** Which fields a failed required-fields witness rejected, and how. */
|
|
19
|
+
export declare function requiredFieldsFailures(witness: string, fields: readonly string[], errorLines: readonly number[]): string[];
|
|
20
|
+
/**
|
|
21
|
+
* The evidence level a receipt records. A certificate that re-checks but
|
|
22
|
+
* derives none of the claims it names from the code proves nothing about
|
|
23
|
+
* the code, so the receipt supports tested, the level coverage reports. An
|
|
24
|
+
* intent-scope derivation rests on the knowledge base's own facts alone
|
|
25
|
+
* (the test read no value from the code), so it does not count either.
|
|
26
|
+
*/
|
|
27
|
+
export declare function receiptEvidenceLevel(level: "proved" | "tested", bindings: readonly ClaimBinding[] | undefined): "proved" | "tested";
|
|
28
|
+
/**
|
|
29
|
+
* How a certificate binds to each claim its contract names in proves. Kibi
|
|
30
|
+
* derives what the certificate must establish from each claim's grounding
|
|
31
|
+
* fact (claim_obligations.pl) and checks the certificate against it; a claim
|
|
32
|
+
* whose fact has no derivation is only attested by the author. Returns
|
|
33
|
+
* undefined for a contract that names no claims.
|
|
34
|
+
*/
|
|
35
|
+
export declare function judgeClaimBindings(context: OperationContext, input: Readonly<{
|
|
36
|
+
testId: string;
|
|
37
|
+
contract: ProofContract;
|
|
38
|
+
verdict: CertificateVerdict;
|
|
39
|
+
coveredBySymbols: readonly string[];
|
|
40
|
+
}>): Promise<ClaimBinding[] | undefined>;
|
|
41
|
+
//# sourceMappingURL=claim-bindings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claim-bindings.d.ts","sourceRoot":"","sources":["../../../src/operations/proof/claim-bindings.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EACL,KAAK,kBAAkB,EAIxB,MAAM,wBAAwB,CAAC;AAgDhC;;;GAGG;AAEH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,WAAW,EAAE,MAAM,GAClB,MAAM,CAWR;AAgED;;;;;;GAMG;AAEH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,SAAS,MAAM,EAAE,GACxB,MAAM,CAgBR;AAED,uEAAuE;AACvE,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,UAAU,EAAE,SAAS,MAAM,EAAE,GAC5B,MAAM,EAAE,CAaV;AA0JD;;;;;;GAMG;AAEH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,QAAQ,GAAG,QAAQ,EAC1B,QAAQ,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,GAC5C,QAAQ,GAAG,QAAQ,CAQrB;AAED;;;;;;GAMG;AAEH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,QAAQ,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,aAAa,CAAC;IACxB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC,CAAC,GACD,OAAO,CAAC,YAAY,EAAE,GAAG,SAAS,CAAC,CA+FrC"}
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Kibi — repo-local, per-branch, queryable long-term memory for software projects
|
|
3
|
+
Copyright (C) 2026 Piotr Franczyk
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU Affero General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
import { randomBytes } from "node:crypto";
|
|
19
|
+
import { rmSync, writeFileSync } from "node:fs";
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
import { runOperationJsonQuery, toPrologAtom, } from "../../public/operations/prolog-json.js";
|
|
22
|
+
import { compileWitness, loadSymbol, smtAssertion, } from "./code-certificates.js";
|
|
23
|
+
import { stringConstraintProblem } from "./code-models.js";
|
|
24
|
+
function record(value) {
|
|
25
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
26
|
+
? value
|
|
27
|
+
: null;
|
|
28
|
+
}
|
|
29
|
+
function text(value) {
|
|
30
|
+
return typeof value === "string" ? value : "";
|
|
31
|
+
}
|
|
32
|
+
function sorted(values) {
|
|
33
|
+
return [...new Set(values)].sort();
|
|
34
|
+
}
|
|
35
|
+
function setDifference(code, fact) {
|
|
36
|
+
const factSet = new Set(fact);
|
|
37
|
+
const codeSet = new Set(code);
|
|
38
|
+
const missing = fact.filter((member) => !codeSet.has(member));
|
|
39
|
+
const extra = code.filter((member) => !factSet.has(member));
|
|
40
|
+
return [
|
|
41
|
+
missing.length > 0 ? `missing ${missing.slice(0, 5).join(", ")}` : "",
|
|
42
|
+
extra.length > 0 ? `not in the set ${extra.slice(0, 5).join(", ")}` : "",
|
|
43
|
+
]
|
|
44
|
+
.filter(Boolean)
|
|
45
|
+
.join("; ");
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The type-level witness Kibi writes for a typecheck claim binding: it
|
|
49
|
+
* compiles only when the domain type has exactly the fact's members.
|
|
50
|
+
*/
|
|
51
|
+
// implements REQ-kibi-claim-bound-proofs
|
|
52
|
+
export function setEqualityWitness(importPath, members, membersType) {
|
|
53
|
+
const union = members.map((member) => JSON.stringify(member)).join(" | ");
|
|
54
|
+
return [
|
|
55
|
+
`import type * as domain from ${JSON.stringify(importPath)};`,
|
|
56
|
+
"type Equals<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true : false;",
|
|
57
|
+
`type Members = ${membersType};`,
|
|
58
|
+
`const exact: Equals<Members, ${union}> = true;`,
|
|
59
|
+
"void exact;",
|
|
60
|
+
"export {};",
|
|
61
|
+
"",
|
|
62
|
+
].join("\n");
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* How a domain export may spell its members as a type: a type alias or
|
|
66
|
+
* enum, a const array, the values of a string enum, or a const object's keys.
|
|
67
|
+
*/
|
|
68
|
+
function membersTypeCandidates(exportName) {
|
|
69
|
+
const name = `domain.${exportName}`;
|
|
70
|
+
return [
|
|
71
|
+
name,
|
|
72
|
+
`(typeof ${name})[number]`,
|
|
73
|
+
`\`\${${name}}\``,
|
|
74
|
+
`keyof typeof ${name}`,
|
|
75
|
+
];
|
|
76
|
+
}
|
|
77
|
+
async function typecheckSetProblem(context, contract, obligation) {
|
|
78
|
+
const domainId = contract.domain_source?.symbol_id ?? "";
|
|
79
|
+
const domain = await loadSymbol(context, domainId);
|
|
80
|
+
if (!domain || domain.sourceFile === "")
|
|
81
|
+
return `the domain_source symbol ${domainId} has no source file`;
|
|
82
|
+
const exportName = contract.domain_source?.export ?? domain.title;
|
|
83
|
+
const directory = path.dirname(domain.sourceFile);
|
|
84
|
+
const base = path.basename(domain.sourceFile).replace(/\.[cm]?[jt]sx?$/, "");
|
|
85
|
+
const witnessPath = path.join(directory, `.kibi-claim-witness-${randomBytes(6).toString("hex")}.ts`);
|
|
86
|
+
const absolute = path.resolve(context.workspaceRoot, witnessPath);
|
|
87
|
+
let lastReason = "";
|
|
88
|
+
try {
|
|
89
|
+
for (const membersType of membersTypeCandidates(exportName)) {
|
|
90
|
+
writeFileSync(absolute, setEqualityWitness(`./${base}.js`, obligation.members, membersType), "utf8");
|
|
91
|
+
const compiled = compileWitness(context.workspaceRoot, witnessPath);
|
|
92
|
+
if (compiled.ok)
|
|
93
|
+
return null;
|
|
94
|
+
lastReason = compiled.reason;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
rmSync(absolute, { force: true });
|
|
99
|
+
}
|
|
100
|
+
return `${exportName} as a type is not exactly the fact's set {${obligation.members.join(", ")}}${lastReason ? ` (${lastReason.replace(/ the witness \S+/, " the set-equality witness")})` : ""}`;
|
|
101
|
+
}
|
|
102
|
+
function smtNegation(obligation) {
|
|
103
|
+
const assertion = smtAssertion(obligation.variable, obligation.value_type, {
|
|
104
|
+
operator: obligation.operator,
|
|
105
|
+
value: obligation.value,
|
|
106
|
+
});
|
|
107
|
+
// (assert X) -> (assert (not X))
|
|
108
|
+
return `(assert (not ${assertion.slice("(assert ".length, -1)}))`;
|
|
109
|
+
}
|
|
110
|
+
function constraintText(obligation) {
|
|
111
|
+
return `${obligation.variable} ${obligation.operator} ${obligation.value}`;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The type-level witness Kibi writes for a required_fields claim binding: it
|
|
115
|
+
* compiles only when every field is a required key of the type whose value
|
|
116
|
+
* can be neither undefined nor null. Each field has its own two lines (`key<i>`
|
|
117
|
+
* that the field exists, `required<i>` that it is required and non-null), so
|
|
118
|
+
* a failed compile says which fields break the claim.
|
|
119
|
+
*/
|
|
120
|
+
// implements REQ-kibi-non-numeric-proof-kinds
|
|
121
|
+
export function requiredFieldsWitness(importPath, typeExpression, fields) {
|
|
122
|
+
return [
|
|
123
|
+
`import type * as domain from ${JSON.stringify(importPath)};`,
|
|
124
|
+
`type Shape = ${typeExpression};`,
|
|
125
|
+
"type HasKey<K extends PropertyKey> = K extends keyof Shape ? true : false;",
|
|
126
|
+
"type IsRequired<K extends PropertyKey> = K extends keyof Shape",
|
|
127
|
+
" ? {} extends Pick<Shape, K> ? false : undefined extends Shape[K] ? false : null extends Shape[K] ? false : true",
|
|
128
|
+
" : false;",
|
|
129
|
+
...fields.flatMap((field, index) => [
|
|
130
|
+
`const key${index}: HasKey<${JSON.stringify(field)}> = true;`,
|
|
131
|
+
`const required${index}: IsRequired<${JSON.stringify(field)}> = true;`,
|
|
132
|
+
]),
|
|
133
|
+
`void [${fields.map((_, index) => `key${index}, required${index}`).join(", ")}];`,
|
|
134
|
+
"export {};",
|
|
135
|
+
"",
|
|
136
|
+
].join("\n");
|
|
137
|
+
}
|
|
138
|
+
/** Which fields a failed required-fields witness rejected, and how. */
|
|
139
|
+
export function requiredFieldsFailures(witness, fields, errorLines) {
|
|
140
|
+
const lines = witness.split("\n");
|
|
141
|
+
const failing = new Set(errorLines);
|
|
142
|
+
const lineOf = (prefix) => lines.findIndex((line) => line.startsWith(prefix));
|
|
143
|
+
const failures = [];
|
|
144
|
+
fields.forEach((field, index) => {
|
|
145
|
+
if (failing.has(lineOf(`const key${index}:`)))
|
|
146
|
+
failures.push(`${field} is not a field`);
|
|
147
|
+
else if (failing.has(lineOf(`const required${index}:`)))
|
|
148
|
+
failures.push(`${field} is optional or nullable`);
|
|
149
|
+
});
|
|
150
|
+
return failures;
|
|
151
|
+
}
|
|
152
|
+
async function requiredFieldsProblem(context, contract, fields) {
|
|
153
|
+
const domainId = contract.domain_source?.symbol_id ?? "";
|
|
154
|
+
const domain = await loadSymbol(context, domainId);
|
|
155
|
+
if (!domain || domain.sourceFile === "")
|
|
156
|
+
return `the domain_source symbol ${domainId} has no source file`;
|
|
157
|
+
const exportName = contract.domain_source?.export ?? domain.title;
|
|
158
|
+
const directory = path.dirname(domain.sourceFile);
|
|
159
|
+
const base = path.basename(domain.sourceFile).replace(/\.[cm]?[jt]sx?$/, "");
|
|
160
|
+
const witnessPath = path.join(directory, `.kibi-claim-witness-${randomBytes(6).toString("hex")}.ts`);
|
|
161
|
+
const absolute = path.resolve(context.workspaceRoot, witnessPath);
|
|
162
|
+
let lastReason = "";
|
|
163
|
+
let failures = [];
|
|
164
|
+
try {
|
|
165
|
+
for (const typeExpression of [
|
|
166
|
+
`domain.${exportName}`,
|
|
167
|
+
`InstanceType<typeof domain.${exportName}>`,
|
|
168
|
+
]) {
|
|
169
|
+
const witness = requiredFieldsWitness(`./${base}.js`, typeExpression, fields);
|
|
170
|
+
writeFileSync(absolute, witness, "utf8");
|
|
171
|
+
const compiled = compileWitness(context.workspaceRoot, witnessPath);
|
|
172
|
+
if (compiled.ok)
|
|
173
|
+
return null;
|
|
174
|
+
lastReason = compiled.reason;
|
|
175
|
+
// The first type expression that names a real type decides which
|
|
176
|
+
// fields fail; the InstanceType form is only for classes.
|
|
177
|
+
const errorLines = compiled.errorLines ?? [];
|
|
178
|
+
const shapeLine = witness.split("\n").findIndex((line) => line.startsWith("type Shape"));
|
|
179
|
+
if (failures.length === 0 && !errorLines.includes(shapeLine))
|
|
180
|
+
failures = requiredFieldsFailures(witness, fields, errorLines);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
finally {
|
|
184
|
+
rmSync(absolute, { force: true });
|
|
185
|
+
}
|
|
186
|
+
if (failures.length > 0)
|
|
187
|
+
return `${exportName} does not have every field of {${fields.join(", ")}} as a required, non-nullable field: ${failures.join("; ")}`;
|
|
188
|
+
return `${exportName} does not have every field of {${fields.join(", ")}} as a required, non-nullable field${lastReason ? ` (${lastReason.replace(/ the witness \S+/, " the required-fields witness")})` : ""}`;
|
|
189
|
+
}
|
|
190
|
+
/** The symbols a non-numeric certificate read, which must be in code scope. */
|
|
191
|
+
function modelSymbols(contract) {
|
|
192
|
+
return [
|
|
193
|
+
contract.domain_source?.symbol_id,
|
|
194
|
+
contract.initial_source?.symbol_id,
|
|
195
|
+
contract.pattern_source?.symbol_id,
|
|
196
|
+
...Object.values(contract.domains ?? {}).map((row) => "symbol_id" in row ? row.symbol_id : undefined),
|
|
197
|
+
...Object.values(contract.predicate_source ?? {}).flatMap((row) => [
|
|
198
|
+
row.symbol_id,
|
|
199
|
+
...(row.harness_for ?? []),
|
|
200
|
+
]),
|
|
201
|
+
].filter((id) => typeof id === "string" && id !== "");
|
|
202
|
+
}
|
|
203
|
+
async function nonNumericProblem(context, contract, certificate, obligation, factId, coveredBy) {
|
|
204
|
+
const outside = modelSymbols(contract).find((id) => !coveredBy.has(id));
|
|
205
|
+
if (outside !== undefined)
|
|
206
|
+
return `the symbol ${outside} the certificate read is not in the receipt's code scope: link it covered_by the test so a change to it stales the proof`;
|
|
207
|
+
const obligationKind = text(obligation.kind);
|
|
208
|
+
if (obligationKind === "required_fields" && contract.kind === "typecheck")
|
|
209
|
+
return requiredFieldsProblem(context, contract, Array.isArray(obligation.members) ? obligation.members.map(String) : []);
|
|
210
|
+
if (obligationKind === "string_constraint")
|
|
211
|
+
return stringConstraintProblem(certificate, obligation, factId);
|
|
212
|
+
if (context.prolog === undefined)
|
|
213
|
+
return "no Prolog runtime is attached to model check the claim";
|
|
214
|
+
const checked = await runOperationJsonQuery(context.prolog, "claim_obligations.pl", `claim_obligations:claim_model_check_json(${toPrologAtom(contract.kind ?? "")}, ${toPrologAtom(JSON.stringify(obligation))}, ${toPrologAtom(JSON.stringify(certificate))}, JsonString)`, "Claim model check");
|
|
215
|
+
return checked.ok === true ? null : (checked.reason ?? "the model check failed");
|
|
216
|
+
}
|
|
217
|
+
const NON_NUMERIC_OBLIGATIONS = new Set([
|
|
218
|
+
"required_fields",
|
|
219
|
+
"string_constraint",
|
|
220
|
+
"rule_holds",
|
|
221
|
+
"predicate_holds",
|
|
222
|
+
"every_member",
|
|
223
|
+
"machine_set",
|
|
224
|
+
"machine_relation",
|
|
225
|
+
"set_relation",
|
|
226
|
+
"nullable_fields",
|
|
227
|
+
"route_middleware",
|
|
228
|
+
]);
|
|
229
|
+
async function derivedProblem(context, contract, certificate, row, coveredBy) {
|
|
230
|
+
const obligation = record(row.obligation) ?? {};
|
|
231
|
+
const kind = contract.kind;
|
|
232
|
+
const factId = row.fact_id ?? "the grounding fact";
|
|
233
|
+
if (NON_NUMERIC_OBLIGATIONS.has(text(obligation.kind)))
|
|
234
|
+
return nonNumericProblem(context, contract, certificate, obligation, factId, coveredBy);
|
|
235
|
+
if (kind === "exhaustive" || kind === "typecheck") {
|
|
236
|
+
const set = obligation;
|
|
237
|
+
const domainId = contract.domain_source?.symbol_id ?? "";
|
|
238
|
+
if (!coveredBy.has(domainId))
|
|
239
|
+
return `the domain_source symbol ${domainId} is not in the receipt's code scope: link it covered_by the test so a change to the domain stales the proof`;
|
|
240
|
+
if (kind === "exhaustive") {
|
|
241
|
+
const members = record(certificate.domain)?.members;
|
|
242
|
+
const code = sorted(Array.isArray(members) ? members.map((member) => String(member)) : []);
|
|
243
|
+
const fact = sorted(set.members ?? []);
|
|
244
|
+
if (code.join("\u0000") !== fact.join("\u0000"))
|
|
245
|
+
return `the domain members Kibi read are not ${factId}'s set (${setDifference(code, fact)})`;
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
return typecheckSetProblem(context, contract, set);
|
|
249
|
+
}
|
|
250
|
+
const numeric = obligation;
|
|
251
|
+
if (kind === "arithmetic") {
|
|
252
|
+
const claim = record(certificate.claim) ?? {};
|
|
253
|
+
if (text(certificate.variable) !== numeric.variable ||
|
|
254
|
+
text(certificate.value_type) !== numeric.value_type ||
|
|
255
|
+
text(claim.operator) !== numeric.operator ||
|
|
256
|
+
Number(claim.value) !== numeric.value)
|
|
257
|
+
return `the certificate's claim is not ${factId}'s constraint (${constraintText(numeric)})`;
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
const query = text(certificate.query).replace(/\s+/g, " ");
|
|
261
|
+
const negation = smtNegation(numeric);
|
|
262
|
+
if (!query.includes(negation))
|
|
263
|
+
return `the query does not assert the negation of ${factId}'s constraint ${negation}`;
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* The evidence level a receipt records. A certificate that re-checks but
|
|
268
|
+
* derives none of the claims it names from the code proves nothing about
|
|
269
|
+
* the code, so the receipt supports tested, the level coverage reports. An
|
|
270
|
+
* intent-scope derivation rests on the knowledge base's own facts alone
|
|
271
|
+
* (the test read no value from the code), so it does not count either.
|
|
272
|
+
*/
|
|
273
|
+
// implements REQ-kibi-claim-bound-proofs
|
|
274
|
+
export function receiptEvidenceLevel(level, bindings) {
|
|
275
|
+
if (level !== "proved" || bindings === undefined || bindings.length === 0)
|
|
276
|
+
return level;
|
|
277
|
+
return bindings.some((binding) => binding.binding === "derived" && binding.scope !== "intent")
|
|
278
|
+
? "proved"
|
|
279
|
+
: "tested";
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* How a certificate binds to each claim its contract names in proves. Kibi
|
|
283
|
+
* derives what the certificate must establish from each claim's grounding
|
|
284
|
+
* fact (claim_obligations.pl) and checks the certificate against it; a claim
|
|
285
|
+
* whose fact has no derivation is only attested by the author. Returns
|
|
286
|
+
* undefined for a contract that names no claims.
|
|
287
|
+
*/
|
|
288
|
+
// implements REQ-kibi-claim-bound-proofs, REQ-kibi-non-numeric-proof-kinds
|
|
289
|
+
export async function judgeClaimBindings(context, input) {
|
|
290
|
+
const keys = input.contract.proves ?? [];
|
|
291
|
+
if (keys.length === 0 || input.contract.kind === undefined)
|
|
292
|
+
return undefined;
|
|
293
|
+
if (context.prolog === undefined)
|
|
294
|
+
return keys.map((key) => ({
|
|
295
|
+
claim_key: key,
|
|
296
|
+
binding: "rejected",
|
|
297
|
+
reason: "no Prolog runtime is attached to resolve the claim",
|
|
298
|
+
}));
|
|
299
|
+
const rows = await runOperationJsonQuery(context.prolog, "claim_obligations.pl", `claim_obligations:test_claim_obligations_json(${toPrologAtom(input.testId)}, ${toPrologAtom(JSON.stringify(keys))}, ${toPrologAtom(input.contract.kind)}, JsonString)`, "Claim obligations");
|
|
300
|
+
const coveredBy = new Set(input.coveredBySymbols);
|
|
301
|
+
const valueSourced = (input.contract.value_source ?? []).length > 0 &&
|
|
302
|
+
(input.contract.value_source ?? []).every((source) => "source" in source || coveredBy.has(source.symbol_id));
|
|
303
|
+
// A rule decided by a test harness that drives the code is about the code
|
|
304
|
+
// through that harness, so its claims are bound with scope harness.
|
|
305
|
+
const harnessed = input.contract.kind === "rule" &&
|
|
306
|
+
Object.values(input.contract.predicate_source ?? {}).some((row) => (row.harness_for ?? []).length > 0);
|
|
307
|
+
const certificate = record(input.verdict.certificate) ?? {};
|
|
308
|
+
const bindings = [];
|
|
309
|
+
for (const row of rows) {
|
|
310
|
+
const base = {
|
|
311
|
+
claim_key: row.claim_key,
|
|
312
|
+
...(row.requirement_id ? { requirement_id: row.requirement_id } : {}),
|
|
313
|
+
...(row.fact_id ? { fact_id: row.fact_id } : {}),
|
|
314
|
+
};
|
|
315
|
+
if (row.result === "unresolved" || row.result === "incompatible") {
|
|
316
|
+
bindings.push({
|
|
317
|
+
...base,
|
|
318
|
+
binding: "rejected",
|
|
319
|
+
reason: row.reason ?? "the claim cannot be proved by this certificate",
|
|
320
|
+
});
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
if (row.result === "attested") {
|
|
324
|
+
bindings.push({ ...base, binding: "attested", scope: "code" });
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
const obligation = record(row.obligation) ?? {};
|
|
328
|
+
if (input.verdict.evidence_level !== "proved") {
|
|
329
|
+
const recheck = `the certificate did not re-check${input.verdict.certificate_rejection ? `: ${input.verdict.certificate_rejection}` : ""}`;
|
|
330
|
+
// A typecheck claim is decided from the code alone, so when the
|
|
331
|
+
// author's witness fails, lead with what the code breaks (the field
|
|
332
|
+
// that is nullable, the member that is missing) rather than only
|
|
333
|
+
// "the type checker did not accept the witness".
|
|
334
|
+
const codeProblem = input.contract.kind === "typecheck" &&
|
|
335
|
+
input.verdict.certificate !== undefined
|
|
336
|
+
? await derivedProblem(context, input.contract, certificate, row, coveredBy)
|
|
337
|
+
: null;
|
|
338
|
+
bindings.push({
|
|
339
|
+
...base,
|
|
340
|
+
binding: "rejected",
|
|
341
|
+
obligation,
|
|
342
|
+
reason: codeProblem === null ? recheck : `${codeProblem} (${recheck})`,
|
|
343
|
+
});
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
const problem = await derivedProblem(context, input.contract, certificate, row, coveredBy);
|
|
347
|
+
const numeric = text(obligation.kind) === "numeric_constraint";
|
|
348
|
+
bindings.push(problem === null
|
|
349
|
+
? {
|
|
350
|
+
...base,
|
|
351
|
+
binding: "derived",
|
|
352
|
+
scope: numeric && !valueSourced
|
|
353
|
+
? "intent"
|
|
354
|
+
: harnessed
|
|
355
|
+
? "harness"
|
|
356
|
+
: input.contract.kind === "source"
|
|
357
|
+
? "source"
|
|
358
|
+
: "code",
|
|
359
|
+
obligation,
|
|
360
|
+
}
|
|
361
|
+
: { ...base, binding: "rejected", obligation, reason: problem });
|
|
362
|
+
}
|
|
363
|
+
return bindings;
|
|
364
|
+
}
|