kibi-cli 2.19.0 → 2.21.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-operation-metadata.d.ts +1 -1
- package/dist/cli-operation-metadata.js +1 -1
- package/dist/cli-register-maintenance.js +1 -1
- package/dist/commands/engine.d.ts +2 -1
- package/dist/commands/engine.d.ts.map +1 -1
- package/dist/commands/engine.js +6 -1
- package/dist/commands/migrate.d.ts +2 -0
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +32 -6
- package/dist/commands/sync/discovery.d.ts.map +1 -1
- package/dist/commands/sync/discovery.js +14 -2
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +24 -6
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +2 -1
- package/dist/intent-search.d.ts +7 -0
- package/dist/intent-search.d.ts.map +1 -1
- package/dist/intent-search.js +66 -4
- package/dist/operations/migration/kb-sources.d.ts +5 -1
- package/dist/operations/migration/kb-sources.d.ts.map +1 -1
- package/dist/operations/migration/kb-sources.js +28 -1
- package/dist/operations/modeling/predicate-applicability.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-applicability.js +10 -4
- package/dist/operations/modeling/predicate-applyplan.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-applyplan.js +16 -5
- package/dist/operations/modeling/predicate-catalog-4.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-catalog-4.js +3 -0
- package/dist/operations/modeling/predicate-inference-1.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-inference-1.js +34 -7
- package/dist/operations/modeling/predicate-score-3.js +1 -1
- package/dist/operations/modeling/predicate-types.d.ts +6 -0
- package/dist/operations/modeling/predicate-types.d.ts.map +1 -1
- package/dist/operations/modeling/suggest-predicates.d.ts.map +1 -1
- package/dist/operations/modeling/suggest-predicates.js +111 -0
- package/dist/operations/mutation/source-authoring.d.ts +8 -0
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +33 -0
- package/dist/operations/mutation/types.d.ts +26 -0
- package/dist/operations/mutation/types.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +8 -2
- package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
- package/dist/operations/mutation/validate-upsert.js +116 -4
- package/dist/operations/mutation/validation.d.ts.map +1 -1
- package/dist/operations/mutation/validation.js +2 -1
- package/dist/operations/mutation/warnings.d.ts +10 -0
- package/dist/operations/mutation/warnings.d.ts.map +1 -1
- package/dist/operations/mutation/warnings.js +26 -0
- package/dist/operations/mutation/what-if.d.ts +25 -0
- package/dist/operations/mutation/what-if.d.ts.map +1 -0
- package/dist/operations/mutation/what-if.js +59 -0
- package/dist/operations/planning/compile-intent.d.ts +15 -20
- package/dist/operations/planning/compile-intent.d.ts.map +1 -1
- package/dist/operations/planning/compile-intent.js +64 -53
- package/dist/operations/semantic-advisor/clauses.d.ts +9 -0
- package/dist/operations/semantic-advisor/clauses.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/clauses.js +32 -7
- package/dist/prolog/janitor.d.ts +26 -2
- package/dist/prolog/janitor.d.ts.map +1 -1
- package/dist/prolog/janitor.js +55 -3
- package/dist/prolog/store-lock.d.ts +28 -3
- package/dist/prolog/store-lock.d.ts.map +1 -1
- package/dist/prolog/store-lock.js +103 -12
- package/dist/public/operations/catalog.d.ts +49 -5
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/check-executor.d.ts +2 -2
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +35 -0
- package/dist/public/operations/check-format-shared.d.ts +16 -0
- package/dist/public/operations/check-format-shared.d.ts.map +1 -1
- package/dist/public/operations/check-format-shared.js +19 -0
- package/dist/public/operations/contracts.d.ts.map +1 -1
- package/dist/public/operations/contracts.js +10 -0
- package/dist/public/operations/discovery-executors.d.ts +3 -0
- package/dist/public/operations/discovery-executors.d.ts.map +1 -1
- package/dist/public/operations/discovery-executors.js +7 -2
- package/dist/public/operations/migration-plan.d.ts.map +1 -1
- package/dist/public/operations/migration-plan.js +37 -7
- package/dist/public/operations/specs/composite.d.ts +1 -1
- package/dist/public/operations/specs/composite.js +1 -1
- package/dist/public/operations/specs/discovery.d.ts +2 -2
- package/dist/public/operations/specs/discovery.d.ts.map +1 -1
- package/dist/public/operations/specs/discovery.js +2 -2
- package/dist/public/operations/specs/mutation-schemas.d.ts +2 -2
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +8 -17
- package/dist/public/operations/specs/upsert.d.ts +46 -2
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/operations/specs/upsert.js +14 -0
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +2 -13
- package/dist/public/skills/kibi-usage/SKILL.md +38 -1
- package/dist/public/skills/kibi-usage/resources/fact-lanes.md +5 -3
- package/dist/public/skills/kibi-usage/resources/ui-requirements.md +2 -2
- package/dist/public/skills/kibi-usage/resources/workflows.md +1 -1
- package/dist/schemas/entity.schema.json +2 -25
- package/dist/search-answer.d.ts +13 -0
- package/dist/search-answer.d.ts.map +1 -1
- package/dist/search-answer.js +45 -4
- package/dist/utils/branch-store.d.ts.map +1 -1
- package/dist/utils/branch-store.js +4 -2
- package/package.json +3 -3
- package/src/public/operations/check-executor.ts +44 -1
- package/src/public/operations/check-format-shared.ts +35 -1
- package/src/public/operations/contracts.ts +11 -0
- package/src/public/operations/discovery-executors.ts +12 -2
- package/src/public/operations/migration-plan.ts +41 -9
- package/src/public/operations/specs/composite.ts +1 -1
- package/src/public/operations/specs/discovery.ts +3 -2
- package/src/public/operations/specs/mutation-schemas.ts +8 -17
- package/src/public/operations/specs/upsert.ts +15 -0
- package/src/public/schemas/entity.ts +2 -13
- package/src/public/skills/kibi-usage/SKILL.md +38 -1
- package/src/public/skills/kibi-usage/resources/fact-lanes.md +5 -3
- package/src/public/skills/kibi-usage/resources/ui-requirements.md +2 -2
- package/src/public/skills/kibi-usage/resources/workflows.md +1 -1
- package/src/schemas/entity.schema.json +2 -25
|
@@ -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.15.
|
|
5
|
+
version: 2.15.3
|
|
6
6
|
kibiCompatibility: ">=1.0.0"
|
|
7
7
|
tags:
|
|
8
8
|
- kibi
|
|
@@ -82,6 +82,41 @@ different workspace than the one you asked for; its `detail.reason` says why.
|
|
|
82
82
|
Use the CLI from your working directory instead: `npx --no-install kibi ...`
|
|
83
83
|
runs where you are and needs no `workspaceRoot`.
|
|
84
84
|
|
|
85
|
+
## Reading a hook snippet
|
|
86
|
+
|
|
87
|
+
On hosts where Kibi hooks are installed, a short block
|
|
88
|
+
arrives before you read or edit a file whose symbols are linked to
|
|
89
|
+
requirements. It is projected from `.kb/symbols.yaml`, not from the store, so
|
|
90
|
+
it is a pointer to the knowledge, never proof. Each line answers one question:
|
|
91
|
+
|
|
92
|
+
- `Kibi knowledge for <path> (symbol manifest):` and the `- REQ-… — <symbol
|
|
93
|
+
titles>` rows: the requirements the file's symbols implement, lead
|
|
94
|
+
requirement first. Read the lead requirement with `kb_query({id})` before
|
|
95
|
+
changing behavior.
|
|
96
|
+
- `REQ-… must keep true: FACT-…` (edit only): the ground facts the lead
|
|
97
|
+
requirement requires. An edit that breaks one of them is a requirement
|
|
98
|
+
change: supersede and remodel the requirement, do not code around the fact.
|
|
99
|
+
- `Decision: ADR-…` (edit only): the decision behind the lead requirement.
|
|
100
|
+
- `Covered by: TEST-…` and `Test code for: …`: the tests that prove the
|
|
101
|
+
file's symbols; run or update them with the edit.
|
|
102
|
+
- `The edit is inside <symbol>, which implements REQ-…`: the symbol the edit
|
|
103
|
+
lands in.
|
|
104
|
+
- `Next layer: …`: the exact `kb_query` and `kb_search(... sourceLocations)`
|
|
105
|
+
calls that return the full detail.
|
|
106
|
+
- The `kb_check({sourceFiles:[…], includeImpactDiagnostics:true,
|
|
107
|
+
includeWorkingTreeDiff:true})` line (edit only): run it after the edit. The
|
|
108
|
+
Stop hook reminds you once per session of files edited without it.
|
|
109
|
+
|
|
110
|
+
A file already shown this session gets only the one-line `Kibi: this edit to
|
|
111
|
+
<path> is inside <symbol>` update; the facts and tests from its first snippet
|
|
112
|
+
still apply. `Kibi: no symbol in <path> is linked to a requirement yet` means
|
|
113
|
+
the file is unowned: find the governing requirement with `kb_search` and
|
|
114
|
+
`sourceLocations`, then link a symbol to it with `implements` through
|
|
115
|
+
`kb_upsert`. Without a readable manifest (`Kibi: the hook could not read
|
|
116
|
+
.kb/symbols.yaml`) snippets are off for this session; `kb_query({sourceFile})`
|
|
117
|
+
still answers and `kibi sync` regenerates the manifest. The search tip and the
|
|
118
|
+
`.kb/` note appear once per session and need no action.
|
|
119
|
+
|
|
85
120
|
## Safe workflow
|
|
86
121
|
|
|
87
122
|
1. Always discover before you mutate: start with `kb_search`, then exact-filter with `kb_query`. Use
|
|
@@ -334,6 +369,8 @@ For each relational clause, call `kb_model` with `mode: "predicates"`, that clau
|
|
|
334
369
|
reviewed `schemaId`. If `binding_status` is `incomplete`, supply
|
|
335
370
|
`argumentBindings` and retry. Persist `fact_kind: predicate` with the same
|
|
336
371
|
`claim_key` / `claim_text`, then link `REQ -> fact` with `requires_predicate`.
|
|
372
|
+
`claim_key` is derived from `claim_text`, so a ground fact may send the exact
|
|
373
|
+
clause alone and Kibi fills the key in; a sent key must equal the derived one.
|
|
337
374
|
Use `kb_model` with `mode: "requirement"` for strict scalar clauses. Use
|
|
338
375
|
`fact_kind: observation` only for a true ontology gap. The manifest is not
|
|
339
376
|
grounding: run `logic-coverage` so each key binds to one ground fact.
|
|
@@ -6,7 +6,7 @@ Requirement prose remains the human-readable source. Facts add queryable semanti
|
|
|
6
6
|
|
|
7
7
|
Logical coverage is clause-based, not entity-based. Give `kb_model` (`mode: "analyze"`) the complete requirement body and verify that its `clauses` list contains every atomic obligation. Supply the `clauses` input yourself when automatic splitting would combine or omit obligations. For every normative clause:
|
|
8
8
|
|
|
9
|
-
-
|
|
9
|
+
- put the exact clause as `claim_text` on its ground fact, with the returned stable key as `claim_key` or none (Kibi derives a missing key; a sent key must match);
|
|
10
10
|
- add the key to the exact current `logic_claims` set, removing only stale keys whose propositions no longer exist in the source;
|
|
11
11
|
- link it through exactly one `requires_property` for `property_value`, one `requires_predicate` for `predicate`, or one `requires_rule` for a safe `rule` fact;
|
|
12
12
|
- leave ambiguity and ontology gaps visibly unresolved—observations do not satisfy `logic-coverage`.
|
|
@@ -68,14 +68,16 @@ id: FACT-SUSPENDED-PUBLISH-DENIED
|
|
|
68
68
|
status: active
|
|
69
69
|
fact_kind: predicate
|
|
70
70
|
predicate_name: permission_rule
|
|
71
|
-
predicate_args: [suspended_user, publish,
|
|
71
|
+
predicate_args: [suspended_user, publish, article, deny]
|
|
72
72
|
polarity: deny
|
|
73
|
-
canonical_key: permission_rule(suspended_user,publish,
|
|
73
|
+
canonical_key: permission_rule(suspended_user,publish,article,deny)
|
|
74
74
|
claim_key: <advisor-issued key for this exact clause>
|
|
75
75
|
claim_text: Suspended users must not publish articles.
|
|
76
76
|
relationship: { type: requires_predicate, from: REQ-SUSPENDED-PUBLISH-DENIED, to: FACT-SUSPENDED-PUBLISH-DENIED }
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
+
Inferred bindings drop the article and singularise the resource (`articles` becomes `article`, `any analysis request` and `analysis requests` both become `analysis_request`), so an allow and a deny on the same actor, action and resource share one key. Grants read the same as `allowed`: `may`, `can`, `is allowed to`, `are permitted to`, `must be able to`, `are able to`, `have permission to` and `are entitled to` all select `permission_rule` with `polarity: assert`.
|
|
80
|
+
|
|
79
81
|
If another current requirement links an `assert` fact with the same predicate namespace, name, and ordered arguments, `domain-contradictions` reports the pair. More complex semantic conflicts require a shared canonical schema and arguments; do not assume Kibi can prove arbitrary equivalence between differently shaped predicates.
|
|
80
82
|
|
|
81
83
|
The full logical representation of a requirement is the conjunction of all of its linked ground property and predicate terms. Conditions, exceptions, permissions, and ordering constraints remain explicit arguments of their declared schemas. Contradiction detection therefore depends on equivalent prose reusing the same predicate name, argument roles, ordered canonical values, and opposing polarity rather than inventing synonymous terms.
|
|
@@ -126,8 +126,8 @@ diagnostics (`symbol_semantic_review_needed`).
|
|
|
126
126
|
`requires_predicate`.
|
|
127
127
|
3. Scalar placement/alignment/order clauses: `kb_model` (`mode: "requirement"`), apply the strict
|
|
128
128
|
subject/property plan and `constrains` / `requires_property`.
|
|
129
|
-
4. Preserve `claim_key` / `claim_text
|
|
130
|
-
`logic_claims` manifest.
|
|
129
|
+
4. Preserve `claim_key` / `claim_text` (a missing key is derived from the
|
|
130
|
+
text); merge every key into the requirement `logic_claims` manifest.
|
|
131
131
|
5. `kb_upsert` with `dryRun: true`, create endpoints first, then sequential `kb_upsert`.
|
|
132
132
|
6. `kb_check` with `logic-coverage`, `predicate-verifiability`, `domain-contradictions`,
|
|
133
133
|
then a final unfiltered `kb_check`.
|
|
@@ -203,7 +203,7 @@ Optional per-project workflow for recording what the screen should look like. No
|
|
|
203
203
|
2. Run `kb_model` with `mode: "analyze"` on the description; audit or supply `clauses`.
|
|
204
204
|
3. For relational layout clauses ("X must remain visually aligned with Y"), call `kb_model` with `mode: "predicates"`, apply the returned `fact_kind: predicate` plan with `predicate_name: visual_layout_rule` and `requires_predicate`.
|
|
205
205
|
4. For scalar placement, alignment, and ordering clauses, call `kb_model` with `mode: "requirement"` and apply strict `fact_kind: subject` / `fact_kind: property_value` facts linked with `constrains` / `requires_property`. Model header order as indexed property keys (`nav_order_1`, `nav_order_2`, ...) against one subject region.
|
|
206
|
-
5. Preserve `claim_key` / `claim_text` on every ground fact and merge every key into the requirement `logic_claims` manifest.
|
|
206
|
+
5. Preserve `claim_key` / `claim_text` on every ground fact (a missing `claim_key` is derived from `claim_text`) and merge every key into the requirement `logic_claims` manifest.
|
|
207
207
|
6. Model UI components as `symbol` entities with `sourceFile` and `symbol_role: behavioral`, linked `implements` to the requirement.
|
|
208
208
|
7. `kb_upsert` with `dryRun: true`, create endpoints first, then sequential `kb_upsert`. Run `kb_check` with `logic-coverage`, `predicate-verifiability`, and `domain-contradictions`, then a final unfiltered `kb_check`.
|
|
209
209
|
|
|
@@ -1675,35 +1675,12 @@
|
|
|
1675
1675
|
},
|
|
1676
1676
|
{
|
|
1677
1677
|
"if": {
|
|
1678
|
-
"
|
|
1679
|
-
|
|
1680
|
-
"required": [
|
|
1681
|
-
"claim_key"
|
|
1682
|
-
]
|
|
1683
|
-
},
|
|
1684
|
-
{
|
|
1685
|
-
"required": [
|
|
1686
|
-
"claim_text"
|
|
1687
|
-
],
|
|
1688
|
-
"not": {
|
|
1689
|
-
"properties": {
|
|
1690
|
-
"fact_kind": {
|
|
1691
|
-
"enum": [
|
|
1692
|
-
"observation",
|
|
1693
|
-
"meta"
|
|
1694
|
-
]
|
|
1695
|
-
}
|
|
1696
|
-
},
|
|
1697
|
-
"required": [
|
|
1698
|
-
"fact_kind"
|
|
1699
|
-
]
|
|
1700
|
-
}
|
|
1701
|
-
}
|
|
1678
|
+
"required": [
|
|
1679
|
+
"claim_key"
|
|
1702
1680
|
]
|
|
1703
1681
|
},
|
|
1704
1682
|
"then": {
|
|
1705
1683
|
"required": [
|
|
1706
|
-
"claim_key",
|
|
1707
1684
|
"claim_text"
|
|
1708
1685
|
]
|
|
1709
1686
|
}
|
package/dist/search-answer.d.ts
CHANGED
|
@@ -94,6 +94,17 @@ export type SearchAnswerScope = Readonly<{
|
|
|
94
94
|
snapshotId: string;
|
|
95
95
|
syncedAt: string | null;
|
|
96
96
|
}>;
|
|
97
|
+
/**
|
|
98
|
+
* A matched fact, scenario, test or symbol that no requirement owns, with
|
|
99
|
+
* its 1-based `rank` in the search results. When the top-ranked match is
|
|
100
|
+
* here, the governing list was reached through lower-ranked matches, and
|
|
101
|
+
* the answer says so instead of presenting those requirements as the top
|
|
102
|
+
* match's.
|
|
103
|
+
*/
|
|
104
|
+
export type SearchAnswerUngoverned = SearchAnswerFact & Readonly<{
|
|
105
|
+
type: string;
|
|
106
|
+
rank: number;
|
|
107
|
+
}>;
|
|
97
108
|
export type SearchAnswer = Readonly<{
|
|
98
109
|
version: "kibi.search-answer.v1";
|
|
99
110
|
governing: readonly SearchAnswerRequirement[];
|
|
@@ -102,6 +113,7 @@ export type SearchAnswer = Readonly<{
|
|
|
102
113
|
supersededBy?: string;
|
|
103
114
|
})[];
|
|
104
115
|
observations: readonly SearchAnswerEntity[];
|
|
116
|
+
ungoverned: readonly SearchAnswerUngoverned[];
|
|
105
117
|
scope: SearchAnswerScope;
|
|
106
118
|
truncated: boolean;
|
|
107
119
|
note: string;
|
|
@@ -119,6 +131,7 @@ export declare const SEARCH_ANSWER_LIMITS: {
|
|
|
119
131
|
readonly rationale: 3;
|
|
120
132
|
readonly notGoverning: 5;
|
|
121
133
|
readonly observations: 3;
|
|
134
|
+
readonly ungoverned: 5;
|
|
122
135
|
/** Entity rows loaded per answer, the matched seeds included. */
|
|
123
136
|
readonly entityLoads: 70;
|
|
124
137
|
readonly maxBytes: 16384;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-answer.d.ts","sourceRoot":"","sources":["../src/search-answer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAW5D,OAAO,KAAK,EACV,UAAU,EAEX,MAAM,sCAAsC,CAAC;AAI9C;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC,CAAC;AAEH;;;GAGG;AAEH,MAAM,MAAM,gBAAgB,GAAG,kBAAkB,GAAG,QAAQ,CAAC;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE9E,sEAAsE;AAEtE,MAAM,MAAM,qBAAqB,GAAG,kBAAkB,GACpD,QAAQ,CAAC;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAElD,0EAA0E;AAE1E,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,KAAK,EAAE,uBAAuB,GAAG,sBAAsB,CAAC;IACxD,MAAM,EAAE,eAAe,GAAG,YAAY,CAAC;IACvC,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CAAC;AAEH;;;;;GAKG;AAEH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,IAAI,EACA,0BAA0B,GAC1B,qBAAqB,GACrB,wBAAwB,GACxB,qBAAqB,GACrB,qBAAqB,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B,CAAC,CAAC;AAGH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC;;;;OAIG;IACH,MAAM,EAAE,eAAe,GAAG,YAAY,GAAG,SAAS,GAAG,MAAM,CAAC;IAC5D,SAAS,EAAE,SAAS,mBAAmB,EAAE,CAAC;CAC3C,CAAC,CAAC;AAEH,sDAAsD;AAEtD,MAAM,MAAM,qBAAqB,GAAG,kBAAkB,GACpD,QAAQ,CAAC;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEpC;;;;;GAKG;AAEH,MAAM,MAAM,gBAAgB,GAAG,kBAAkB,GAC/C,QAAQ,CAAC;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAGhE,MAAM,MAAM,uBAAuB,GAAG,kBAAkB,GACtD,QAAQ,CAAC;IACP,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACnC,SAAS,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACzC,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACnC,IAAI,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACpC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,UAAU,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC7C,QAAQ,EAAE,SAAS,mBAAmB,EAAE,CAAC;CAC1C,CAAC,CAAC;AAEL,2CAA2C;AAE3C,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"search-answer.d.ts","sourceRoot":"","sources":["../src/search-answer.ts"],"names":[],"mappings":"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"}
|
package/dist/search-answer.js
CHANGED
|
@@ -65,6 +65,7 @@ export const SEARCH_ANSWER_LIMITS = {
|
|
|
65
65
|
rationale: 3,
|
|
66
66
|
notGoverning: 5,
|
|
67
67
|
observations: 3,
|
|
68
|
+
ungoverned: 5,
|
|
68
69
|
/** Entity rows loaded per answer, the matched seeds included. */
|
|
69
70
|
entityLoads: 70,
|
|
70
71
|
maxBytes: 16_384,
|
|
@@ -513,11 +514,12 @@ export async function buildSearchAnswer(prolog, matches, options = {}) {
|
|
|
513
514
|
candidates.set(owner, { score, via });
|
|
514
515
|
};
|
|
515
516
|
const observations = [];
|
|
517
|
+
const ungoverned = [];
|
|
516
518
|
const rationaleRows = new Map();
|
|
517
519
|
// A matched test may verify a scenario rather than a requirement; its
|
|
518
520
|
// targets are resolved to their governing requirements after the loop.
|
|
519
521
|
const testTargets = [];
|
|
520
|
-
for (const match of seeds) {
|
|
522
|
+
for (const [index, match] of seeds.entries()) {
|
|
521
523
|
const id = text(match.entity.id);
|
|
522
524
|
const entity = graph.row(id) ?? match.entity;
|
|
523
525
|
const type = text(entity.type || match.entity.type);
|
|
@@ -548,6 +550,18 @@ export async function buildSearchAnswer(prolog, matches, options = {}) {
|
|
|
548
550
|
testTargets.push({ id, score: match.score, targets: owners });
|
|
549
551
|
continue;
|
|
550
552
|
}
|
|
553
|
+
if (owners.length === 0 && ["fact", "scenario", "symbol"].includes(type)) {
|
|
554
|
+
if (ungoverned.length < limits.ungoverned)
|
|
555
|
+
ungoverned.push({
|
|
556
|
+
...brief(entity),
|
|
557
|
+
...(type === "fact" ? factDetail(entity) : {}),
|
|
558
|
+
type,
|
|
559
|
+
rank: index + 1,
|
|
560
|
+
});
|
|
561
|
+
else
|
|
562
|
+
truncated = true;
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
551
565
|
for (const owner of owners)
|
|
552
566
|
propose(owner, match.score * 0.9, `${type} ${id}`);
|
|
553
567
|
}
|
|
@@ -562,6 +576,15 @@ export async function buildSearchAnswer(prolog, matches, options = {}) {
|
|
|
562
576
|
});
|
|
563
577
|
const targetEdges = graph.edgesOf(targetIds);
|
|
564
578
|
for (const test of testTargets) {
|
|
579
|
+
if (test.targets.length === 0) {
|
|
580
|
+
const row = graph.row(test.id);
|
|
581
|
+
const rank = seedIds.indexOf(test.id) + 1;
|
|
582
|
+
if (row !== null && ungoverned.length < limits.ungoverned)
|
|
583
|
+
ungoverned.push({ ...brief(row), type: "test", rank });
|
|
584
|
+
else if (row !== null)
|
|
585
|
+
truncated = true;
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
565
588
|
for (const target of test.targets) {
|
|
566
589
|
// A target that some requirement specifies is a scenario: lift the
|
|
567
590
|
// test to that requirement. Anything else is a directly verified
|
|
@@ -746,20 +769,36 @@ export async function buildSearchAnswer(prolog, matches, options = {}) {
|
|
|
746
769
|
? verdicts.scope.syncedAt
|
|
747
770
|
: null,
|
|
748
771
|
};
|
|
772
|
+
ungoverned.sort((left, right) => left.rank - right.rank);
|
|
749
773
|
const answer = {
|
|
750
774
|
version: "kibi.search-answer.v1",
|
|
751
775
|
governing,
|
|
752
776
|
rationale,
|
|
753
777
|
notGoverning,
|
|
754
778
|
observations: observations.slice(0, limits.observations),
|
|
779
|
+
ungoverned,
|
|
755
780
|
scope,
|
|
756
781
|
truncated: truncated || graph.truncated,
|
|
757
|
-
note: governing.length
|
|
758
|
-
? "No current requirement matched or owns a matched entity. Absence here is not evidence that nothing governs the change; refine the query or pass sourceLocations."
|
|
759
|
-
: "Governing requirements are current requirements matched by the query or linked to a matched entity. Links are discovery, not proof. A verdict lists the contradiction and scenario-feasibility witnesses that name the requirement; none means no check named it, not that it is proven. Use kb_check and kb_coverage for consistency and proof status.",
|
|
782
|
+
note: answerNote(governing.length, ungoverned),
|
|
760
783
|
};
|
|
761
784
|
return fitSearchAnswer(answer, limits.maxBytes);
|
|
762
785
|
}
|
|
786
|
+
// implements REQ-search-answer-hygiene
|
|
787
|
+
/**
|
|
788
|
+
* How to read the layer. When the top-ranked match is owned by no
|
|
789
|
+
* requirement, the note says so first: the governing list, if any, came from
|
|
790
|
+
* lower-ranked matches and is not the top match's requirement.
|
|
791
|
+
*/
|
|
792
|
+
function answerNote(governingCount, ungoverned) {
|
|
793
|
+
const top = ungoverned.find((entry) => entry.rank === 1);
|
|
794
|
+
const lead = top === undefined
|
|
795
|
+
? ""
|
|
796
|
+
: `The top-ranked match ${top.id} (${top.type}) is linked to no requirement${governingCount === 0 ? "" : "; the governing requirements below were reached through lower-ranked matches"}. `;
|
|
797
|
+
return (lead +
|
|
798
|
+
(governingCount === 0
|
|
799
|
+
? "No current requirement matched or owns a matched entity. Absence here is not evidence that nothing governs the change; refine the query or pass sourceLocations."
|
|
800
|
+
: "Governing requirements are current requirements matched by the query or linked to a matched entity. Links are discovery, not proof. A verdict lists the contradiction and scenario-feasibility witnesses that name the requirement; none means no check named it, not that it is proven. Use kb_check and kb_coverage for consistency and proof status."));
|
|
801
|
+
}
|
|
763
802
|
function byteSize(value) {
|
|
764
803
|
return Buffer.byteLength(JSON.stringify(value), "utf8");
|
|
765
804
|
}
|
|
@@ -784,6 +823,7 @@ function withoutExcerpt(entity) {
|
|
|
784
823
|
const ANSWER_TRIM_ORDER = [
|
|
785
824
|
"observations",
|
|
786
825
|
"notGoverning",
|
|
826
|
+
"ungoverned",
|
|
787
827
|
"rationale",
|
|
788
828
|
];
|
|
789
829
|
const REQUIREMENT_TRIM_ORDER = [
|
|
@@ -838,6 +878,7 @@ export function fitSearchAnswer(answer, maxBytes = SEARCH_ANSWER_LIMITS.maxBytes
|
|
|
838
878
|
rationale: current.rationale.map((adr) => clipRationale(adr, titleChars)),
|
|
839
879
|
notGoverning: clipAll(current.notGoverning),
|
|
840
880
|
observations: clipAll(current.observations),
|
|
881
|
+
ungoverned: clipAll(current.ungoverned),
|
|
841
882
|
};
|
|
842
883
|
// Excerpts are the most expendable text: drop them before any entry.
|
|
843
884
|
for (let index = current.rationale.length - 1; index >= 0 && over(); index -= 1) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch-store.d.ts","sourceRoot":"","sources":["../../src/utils/branch-store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"branch-store.d.ts","sourceRoot":"","sources":["../../src/utils/branch-store.ts"],"names":[],"mappings":"AA2BA,mEAAmE;AACnE,eAAO,MAAM,yBAAyB,8BAA8B,CAAC;AACrE,yCAAyC;AACzC,eAAO,MAAM,8BAA8B,8BAA8B,CAAC;AAE1E,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,SAAS,GACT,YAAY,GACZ,YAAY,CAAC;AAEjB,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC3C,KAAK,EAAE,gBAAgB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC,CAAC;AAEH;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,GACb,qBAAqB,CA0GvB;AAED;;;;GAIG;AAEH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,GAChB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAiBhC;AAED;;;;;;GAMG;AAEH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,IAAiB,GACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAmBhC;AAED,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,qBAAqB,GAChC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAWhC;AA6BD;;;;GAIG;AAEH,wBAAgB,sBAAsB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAOpE;AAED,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,oEAAoE;IACpE,QAAQ,EAAE,OAAO,CAAC;IAClB,0EAA0E;IAC1E,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC,CAAC;AAEH;;;;;;GAMG;AAEH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,qBAAqB,GAChC,sBAAsB,CAwBxB;AAkBD;;;;;;GAMG;AAEH,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,qBAAqB,EACjC,MAAM,EAAE,MAAM,GACb,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAwBhC"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { existsSync, readFileSync, readdirSync, statSync, } from "node:fs";
|
|
6
6
|
import * as path from "node:path";
|
|
7
|
-
import { STORE_LOCK_TAKEOVER_VISIBLE_MS, classifyStoreLockHolder, readStoreLockOwner, readStoreLockTakeover, } from "../prolog/store-lock.js";
|
|
7
|
+
import { FOREIGN_STORE_LOCK_REASON_PREFIX, STORE_LOCK_TAKEOVER_VISIBLE_MS, classifyStoreLockHolder, readStoreLockOwner, readStoreLockTakeover, } from "../prolog/store-lock.js";
|
|
8
8
|
import { branchStoreManifestMatches, branchStorePath, legacyBranchStorePath, } from "./branch-store-locator.js";
|
|
9
9
|
import { ENTITY_LANES, KB_ROOT } from "./kb-paths.js";
|
|
10
10
|
/** Stale-reason code of a branch store that was never compiled. */
|
|
@@ -170,7 +170,9 @@ export function storeLockTakeoverReason(storePath, now = new Date()) {
|
|
|
170
170
|
brokenPid: record.brokenPid,
|
|
171
171
|
reason: record.reason,
|
|
172
172
|
at: record.at,
|
|
173
|
-
detail: `Kibi broke a stale branch-store lock at ${record.at} (${record.reason || "holder no longer running"}) and reattached. Nothing needs repair;
|
|
173
|
+
detail: `Kibi broke a stale branch-store lock at ${record.at} (${record.reason || "holder no longer running"}) and reattached. Nothing needs repair; ${record.reason.startsWith(FOREIGN_STORE_LOCK_REASON_PREFIX)
|
|
174
|
+
? "the lock files were copied with the .kb directory (for example by cp -a) while another workspace's engine held its own store."
|
|
175
|
+
: "a holder that died while it held the store usually means an engine or kibi prove run crashed or was killed."}`,
|
|
174
176
|
};
|
|
175
177
|
}
|
|
176
178
|
export function branchStoreReason(inspection) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kibi-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.21.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Kibi CLI for knowledge base management",
|
|
6
6
|
"engines": {
|
|
@@ -235,8 +235,8 @@
|
|
|
235
235
|
"fast-glob": "^3.2.12",
|
|
236
236
|
"gray-matter": "^4.0.3",
|
|
237
237
|
"js-yaml": "^4.1.0",
|
|
238
|
-
"kibi-core": "^0.
|
|
239
|
-
"kibi-plugin-builtin": "^0.5.
|
|
238
|
+
"kibi-core": "^0.21.0",
|
|
239
|
+
"kibi-plugin-builtin": "^0.5.1",
|
|
240
240
|
"kibi-plugin-sdk": "^0.5.0",
|
|
241
241
|
"kibi-swipl": "^1.0.1",
|
|
242
242
|
"saxes": "^6.0.0",
|
|
@@ -26,6 +26,7 @@ import type { Violation } from "../check-types.js";
|
|
|
26
26
|
import { collectFullKbQualityDiagnostics } from "../impact-diagnostics.js";
|
|
27
27
|
import {
|
|
28
28
|
type CheckDiagnostic,
|
|
29
|
+
type CheckEvaluated,
|
|
29
30
|
type CheckStructuredContent,
|
|
30
31
|
buildStructuredContent,
|
|
31
32
|
buildSummary,
|
|
@@ -70,7 +71,7 @@ export type CheckInput = {
|
|
|
70
71
|
};
|
|
71
72
|
|
|
72
73
|
export type CheckPayload = CheckStructuredContent;
|
|
73
|
-
export type { CheckDiagnostic, CheckStructuredContent };
|
|
74
|
+
export type { CheckDiagnostic, CheckEvaluated, CheckStructuredContent };
|
|
74
75
|
export {
|
|
75
76
|
buildStructuredContent,
|
|
76
77
|
buildSummary,
|
|
@@ -90,6 +91,38 @@ export type CheckExecutionOptions = {
|
|
|
90
91
|
readonly branchStoreAttached?: boolean;
|
|
91
92
|
};
|
|
92
93
|
|
|
94
|
+
// implements REQ-search-answer-hygiene
|
|
95
|
+
/**
|
|
96
|
+
* What this run evaluated: the rules that ran, in registry order, and for
|
|
97
|
+
* `domain-contradictions` the number of requirement fact pairs the rule
|
|
98
|
+
* compared, read from the engine after the rules ran on the same store. A
|
|
99
|
+
* count the engine cannot give (an older engine) is left out rather than
|
|
100
|
+
* reported as zero.
|
|
101
|
+
*/
|
|
102
|
+
async function describeEvaluation(
|
|
103
|
+
prolog: PrologPort,
|
|
104
|
+
rules: ReadonlySet<string>,
|
|
105
|
+
): Promise<CheckEvaluated> {
|
|
106
|
+
const evaluated: {
|
|
107
|
+
rules: string[];
|
|
108
|
+
domainContradictions?: { factPairsExamined: number };
|
|
109
|
+
} = {
|
|
110
|
+
rules: [...rules],
|
|
111
|
+
};
|
|
112
|
+
if (!rules.has("domain-contradictions")) return evaluated;
|
|
113
|
+
try {
|
|
114
|
+
const result = await prolog.query(
|
|
115
|
+
"kb_domain_contradiction_pairs_examined(Count)",
|
|
116
|
+
);
|
|
117
|
+
const count = Number(result.bindings.Count);
|
|
118
|
+
if (result.success && Number.isInteger(count) && count >= 0)
|
|
119
|
+
evaluated.domainContradictions = { factPairsExamined: count };
|
|
120
|
+
} catch {
|
|
121
|
+
// An engine without the predicate leaves the count out.
|
|
122
|
+
}
|
|
123
|
+
return evaluated;
|
|
124
|
+
}
|
|
125
|
+
|
|
93
126
|
function requireProlog(context: OperationContext): PrologPort {
|
|
94
127
|
if (context.prolog === undefined) {
|
|
95
128
|
throw new Error("Check operation requires a Prolog runtime");
|
|
@@ -226,12 +259,15 @@ export async function executeCheck(
|
|
|
226
259
|
[],
|
|
227
260
|
statusPlan,
|
|
228
261
|
);
|
|
262
|
+
// Every store-backed rule was skipped: only this one was evaluated.
|
|
263
|
+
const evaluated = { rules: [BRANCH_STORE_NOT_COMPILED_RULE] };
|
|
229
264
|
return {
|
|
230
265
|
content: [
|
|
231
266
|
{
|
|
232
267
|
type: "text",
|
|
233
268
|
text: buildSummary({
|
|
234
269
|
violations,
|
|
270
|
+
evaluated,
|
|
235
271
|
impactResult,
|
|
236
272
|
qualityDiagnostics: [],
|
|
237
273
|
}),
|
|
@@ -239,6 +275,7 @@ export async function executeCheck(
|
|
|
239
275
|
],
|
|
240
276
|
structuredContent: buildStructuredContent({
|
|
241
277
|
violations,
|
|
278
|
+
evaluated,
|
|
242
279
|
diagnostics: [
|
|
243
280
|
{
|
|
244
281
|
category: "SYNC_ERROR",
|
|
@@ -283,12 +320,14 @@ export async function executeCheck(
|
|
|
283
320
|
>[],
|
|
284
321
|
statusPlan,
|
|
285
322
|
);
|
|
323
|
+
const evaluated = { rules: [] };
|
|
286
324
|
return {
|
|
287
325
|
content: [
|
|
288
326
|
{
|
|
289
327
|
type: "text",
|
|
290
328
|
text: buildSummary({
|
|
291
329
|
violations: [],
|
|
330
|
+
evaluated,
|
|
292
331
|
impactResult,
|
|
293
332
|
qualityDiagnostics,
|
|
294
333
|
}),
|
|
@@ -296,6 +335,7 @@ export async function executeCheck(
|
|
|
296
335
|
],
|
|
297
336
|
structuredContent: buildStructuredContent({
|
|
298
337
|
violations: [],
|
|
338
|
+
evaluated,
|
|
299
339
|
diagnostics: [],
|
|
300
340
|
qualityDiagnostics,
|
|
301
341
|
impactResult,
|
|
@@ -351,6 +391,7 @@ export async function executeCheck(
|
|
|
351
391
|
...checkPolicyFindings,
|
|
352
392
|
]);
|
|
353
393
|
const violations: Violation[] = partitioned.violations;
|
|
394
|
+
const evaluated = await describeEvaluation(prolog, rulesAllowlist);
|
|
354
395
|
|
|
355
396
|
const diagnostics: CheckDiagnostic[] = violations.map((v) => ({
|
|
356
397
|
category: "SYNC_ERROR",
|
|
@@ -396,6 +437,7 @@ export async function executeCheck(
|
|
|
396
437
|
type: "text",
|
|
397
438
|
text: buildSummary({
|
|
398
439
|
violations,
|
|
440
|
+
evaluated,
|
|
399
441
|
impactResult,
|
|
400
442
|
qualityDiagnostics,
|
|
401
443
|
}),
|
|
@@ -403,6 +445,7 @@ export async function executeCheck(
|
|
|
403
445
|
],
|
|
404
446
|
structuredContent: buildStructuredContent({
|
|
405
447
|
violations,
|
|
448
|
+
evaluated,
|
|
406
449
|
diagnostics,
|
|
407
450
|
qualityDiagnostics,
|
|
408
451
|
impactResult,
|
|
@@ -29,10 +29,22 @@ export interface CheckDiagnostic {
|
|
|
29
29
|
readonly suggestion?: string;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
/**
|
|
33
|
+
* What a check run evaluated, so "no violations" can be told apart from
|
|
34
|
+
* "nothing evaluated": the rules that ran, and for `domain-contradictions`
|
|
35
|
+
* how many pairs of requirement facts it compared.
|
|
36
|
+
*/
|
|
37
|
+
// implements REQ-search-answer-hygiene
|
|
38
|
+
export interface CheckEvaluated {
|
|
39
|
+
readonly rules: readonly string[];
|
|
40
|
+
readonly domainContradictions?: Readonly<{ factPairsExamined: number }>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// implements REQ-mcp-tool-check, REQ-search-answer-hygiene
|
|
33
44
|
export interface CheckStructuredContent {
|
|
34
45
|
readonly violations: readonly Violation[];
|
|
35
46
|
readonly count: number;
|
|
47
|
+
readonly evaluated: CheckEvaluated;
|
|
36
48
|
readonly diagnostics: readonly CheckDiagnostic[];
|
|
37
49
|
readonly qualityDiagnostics?: readonly QualityDiagnostic[];
|
|
38
50
|
readonly impactDiagnostics?: ChangedFileImpactResult["impactDiagnostics"];
|
|
@@ -139,6 +151,7 @@ export function formatViolationText(violations: readonly Violation[]): string {
|
|
|
139
151
|
// implements REQ-mcp-tool-check
|
|
140
152
|
export function buildStructuredContent(input: {
|
|
141
153
|
violations: readonly Violation[];
|
|
154
|
+
evaluated: CheckEvaluated;
|
|
142
155
|
diagnostics: readonly CheckDiagnostic[];
|
|
143
156
|
qualityDiagnostics?: readonly QualityDiagnostic[];
|
|
144
157
|
impactResult: ChangedFileImpactResult | undefined;
|
|
@@ -148,6 +161,12 @@ export function buildStructuredContent(input: {
|
|
|
148
161
|
return {
|
|
149
162
|
violations: [...input.violations],
|
|
150
163
|
count: input.violations.length,
|
|
164
|
+
evaluated: {
|
|
165
|
+
rules: [...input.evaluated.rules],
|
|
166
|
+
...(input.evaluated.domainContradictions !== undefined
|
|
167
|
+
? { domainContradictions: input.evaluated.domainContradictions }
|
|
168
|
+
: {}),
|
|
169
|
+
},
|
|
151
170
|
diagnostics: formatDiagnostics(input.diagnostics),
|
|
152
171
|
...(qualityDiagnostics.length > 0
|
|
153
172
|
? { qualityDiagnostics: [...qualityDiagnostics] }
|
|
@@ -168,12 +187,27 @@ export function buildStructuredContent(input: {
|
|
|
168
187
|
}
|
|
169
188
|
|
|
170
189
|
// implements REQ-mcp-tool-check
|
|
190
|
+
// implements REQ-search-answer-hygiene
|
|
191
|
+
/** One line saying what the check evaluated, so a clean result is readable. */
|
|
192
|
+
export function formatEvaluatedText(evaluated: CheckEvaluated): string {
|
|
193
|
+
const rules =
|
|
194
|
+
evaluated.rules.length === 0
|
|
195
|
+
? "Evaluated no rules"
|
|
196
|
+
: `Evaluated ${evaluated.rules.length} rule${evaluated.rules.length === 1 ? "" : "s"}`;
|
|
197
|
+
const pairs = evaluated.domainContradictions;
|
|
198
|
+
if (pairs === undefined) return `${rules}.`;
|
|
199
|
+
return `${rules}; domain-contradictions compared ${pairs.factPairsExamined} fact pair${pairs.factPairsExamined === 1 ? "" : "s"}${pairs.factPairsExamined === 0 ? " (no two current requirements constrain the same subject or predicate case)" : ""}.`;
|
|
200
|
+
}
|
|
201
|
+
|
|
171
202
|
export function buildSummary(input: {
|
|
172
203
|
readonly violations: readonly Violation[];
|
|
204
|
+
readonly evaluated?: CheckEvaluated;
|
|
173
205
|
readonly impactResult: ChangedFileImpactResult | undefined;
|
|
174
206
|
readonly qualityDiagnostics: readonly QualityDiagnostic[];
|
|
175
207
|
}): string {
|
|
176
208
|
const sections = [formatViolationText(input.violations)];
|
|
209
|
+
if (input.evaluated !== undefined)
|
|
210
|
+
sections.push(formatEvaluatedText(input.evaluated));
|
|
177
211
|
if (input.impactResult !== undefined) {
|
|
178
212
|
sections.push(formatImpactText(input.impactResult));
|
|
179
213
|
}
|
|
@@ -449,6 +449,7 @@ const BASE_DATA_SCHEMAS: Readonly<
|
|
|
449
449
|
{
|
|
450
450
|
results: valueArray,
|
|
451
451
|
count: integerValue,
|
|
452
|
+
returned: integerValue,
|
|
452
453
|
truncated: booleanValue,
|
|
453
454
|
queryAnalysis: recordValue,
|
|
454
455
|
answer: recordValue,
|
|
@@ -573,6 +574,11 @@ const BASE_DATA_SCHEMAS: Readonly<
|
|
|
573
574
|
recommendedPredicateSchema: { type: ["object", "null"] },
|
|
574
575
|
applyPlan: recordArray,
|
|
575
576
|
relationshipPlan: { type: ["object", "null"] },
|
|
577
|
+
plan: {
|
|
578
|
+
type: ["object", "null"],
|
|
579
|
+
description:
|
|
580
|
+
"With requirementId and a complete candidate: the hash-bound kibi.compile-plan.v1 that writes the predicate fact and links requires_predicate in one kb_apply_plan call (approvedPlanHash = plan.planHash). Its contradictionAnalysis is the what-if over the current KB plus the plan; a conflict leaves the plan blocked. Null when no plan applies.",
|
|
581
|
+
},
|
|
576
582
|
relationshipTarget: {
|
|
577
583
|
type: ["string", "null"],
|
|
578
584
|
description:
|
|
@@ -629,6 +635,8 @@ const BASE_DATA_SCHEMAS: Readonly<
|
|
|
629
635
|
warnings: valueArray,
|
|
630
636
|
semanticAdvisor: nullableJsonSchema(recordValue),
|
|
631
637
|
normalizedPreview: nullableJsonSchema(recordValue),
|
|
638
|
+
stagedFacts: stringArray,
|
|
639
|
+
whatIf: recordValue,
|
|
632
640
|
}),
|
|
633
641
|
kb_upsert: {
|
|
634
642
|
description:
|
|
@@ -653,6 +661,8 @@ const BASE_DATA_SCHEMAS: Readonly<
|
|
|
653
661
|
warnings: valueArray,
|
|
654
662
|
semanticAdvisor: nullableJsonSchema(recordValue),
|
|
655
663
|
normalizedPreview: nullableJsonSchema(recordValue),
|
|
664
|
+
stagedFacts: stringArray,
|
|
665
|
+
whatIf: recordValue,
|
|
656
666
|
dryRun: { const: true },
|
|
657
667
|
skippedEffects: stringArray,
|
|
658
668
|
},
|
|
@@ -683,6 +693,7 @@ const BASE_DATA_SCHEMAS: Readonly<
|
|
|
683
693
|
objectData({
|
|
684
694
|
violations: valueArray,
|
|
685
695
|
count: integerValue,
|
|
696
|
+
evaluated: recordValue,
|
|
686
697
|
diagnostics: recordArray,
|
|
687
698
|
qualityDiagnostics: recordArray,
|
|
688
699
|
impactDiagnostics: recordArray,
|