kibi-cli 2.29.0 → 2.31.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 +8 -8
- package/dist/cli-operation-metadata.js +8 -8
- package/dist/cli-register-reporting.d.ts.map +1 -1
- package/dist/cli-register-reporting.js +35 -2
- package/dist/commands/check-certificates.d.ts +52 -0
- package/dist/commands/check-certificates.d.ts.map +1 -0
- package/dist/commands/check-certificates.js +163 -0
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +4 -0
- package/dist/commands/discovery-table.d.ts.map +1 -1
- package/dist/commands/discovery-table.js +14 -2
- package/dist/commands/report.js +3 -3
- package/dist/commands/signoff.d.ts +37 -0
- package/dist/commands/signoff.d.ts.map +1 -0
- package/dist/commands/signoff.js +155 -0
- package/dist/operations/modeling/predicate-applicability.d.ts +5 -1
- package/dist/operations/modeling/predicate-applicability.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-applicability.js +35 -2
- package/dist/operations/modeling/suggest-predicates.d.ts.map +1 -1
- package/dist/operations/modeling/suggest-predicates.js +3 -1
- package/dist/operations/mutation/contradictions.d.ts +7 -5
- package/dist/operations/mutation/contradictions.d.ts.map +1 -1
- package/dist/operations/mutation/contradictions.js +8 -6
- package/dist/operations/mutation/source-authoring.d.ts +15 -0
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +19 -7
- package/dist/operations/mutation/types.d.ts +5 -0
- package/dist/operations/mutation/types.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.d.ts +14 -0
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +42 -36
- package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
- package/dist/operations/mutation/validate-upsert.js +61 -37
- package/dist/operations/planning/apply-plan.js +5 -5
- package/dist/operations/proof/baseline-diff.d.ts +1 -1
- package/dist/operations/proof/baseline-diff.js +1 -1
- package/dist/operations/proof/impact.d.ts +10 -4
- package/dist/operations/proof/impact.d.ts.map +1 -1
- package/dist/operations/proof/impact.js +27 -7
- package/dist/public/diagnostic-usage.js +2 -2
- package/dist/public/operations/catalog.d.ts +31 -10
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/contracts.d.ts.map +1 -1
- package/dist/public/operations/contracts.js +2 -0
- package/dist/public/operations/specs/bootstrap.d.ts +1 -1
- package/dist/public/operations/specs/bootstrap.js +1 -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 +3 -1
- package/dist/public/operations/specs/check.d.ts +1 -1
- 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 +1 -1
- package/dist/public/operations/specs/discovery.js +1 -1
- package/dist/public/operations/specs/impact-review-preparation.d.ts +2 -1
- package/dist/public/operations/specs/impact-review-preparation.d.ts.map +1 -1
- package/dist/public/operations/specs/impact-review-preparation.js +2 -1
- package/dist/public/operations/specs/planning.d.ts +1 -1
- package/dist/public/operations/specs/planning.js +1 -1
- package/dist/public/operations/specs/reporting.d.ts +25 -5
- package/dist/public/operations/specs/reporting.d.ts.map +1 -1
- package/dist/public/operations/specs/reporting.js +102 -26
- package/dist/public/skills/kibi-commit-review/SKILL.md +125 -0
- package/dist/public/skills/kibi-commit-review/resources/staged-gate.md +98 -0
- package/dist/public/skills/kibi-decisions/SKILL.md +130 -0
- package/dist/public/skills/kibi-decisions/resources/decision-records.md +142 -0
- package/dist/public/skills/kibi-decisions/resources/signoff-views.md +66 -0
- package/dist/public/skills/kibi-freshness/SKILL.md +3 -1
- package/dist/public/skills/kibi-traceability/SKILL.md +4 -0
- package/dist/public/skills/kibi-usage/SKILL.md +21 -16
- package/dist/public/skills/kibi-usage/resources/proof.md +36 -4
- package/dist/public/skills/kibi-usage/resources/workflows.md +1 -1
- package/dist/report/html-report.css +11 -4
- package/dist/report/html-report.d.ts +2 -2
- package/dist/report/html-report.d.ts.map +1 -1
- package/dist/report/html-report.js +27 -21
- package/dist/report/report-view.d.ts +2 -2
- package/dist/report/report-view.js +2 -2
- package/dist/signoff/collect.d.ts +39 -0
- package/dist/signoff/collect.d.ts.map +1 -0
- package/dist/signoff/collect.js +402 -0
- package/dist/signoff/html.d.ts +4 -0
- package/dist/signoff/html.d.ts.map +1 -0
- package/dist/signoff/html.js +210 -0
- package/dist/signoff/markdown.d.ts +20 -0
- package/dist/signoff/markdown.d.ts.map +1 -0
- package/dist/signoff/markdown.js +203 -0
- package/dist/signoff/model.d.ts +139 -0
- package/dist/signoff/model.d.ts.map +1 -0
- package/dist/signoff/model.js +142 -0
- package/dist/traceability/staged-consistency.d.ts.map +1 -1
- package/dist/traceability/staged-consistency.js +3 -1
- 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/package.json +2 -2
- package/src/public/diagnostic-usage.ts +3 -3
- package/src/public/operations/contracts.ts +2 -0
- package/src/public/operations/specs/bootstrap.ts +1 -1
- package/src/public/operations/specs/check-rules.generated.ts +3 -1
- package/src/public/operations/specs/composite.ts +1 -1
- package/src/public/operations/specs/discovery.ts +1 -1
- package/src/public/operations/specs/impact-review-preparation.ts +3 -1
- package/src/public/operations/specs/planning.ts +1 -1
- package/src/public/operations/specs/reporting.ts +114 -26
- package/src/public/skills/kibi-commit-review/SKILL.md +125 -0
- package/src/public/skills/kibi-commit-review/resources/staged-gate.md +98 -0
- package/src/public/skills/kibi-decisions/SKILL.md +130 -0
- package/src/public/skills/kibi-decisions/resources/decision-records.md +142 -0
- package/src/public/skills/kibi-decisions/resources/signoff-views.md +66 -0
- package/src/public/skills/kibi-freshness/SKILL.md +3 -1
- package/src/public/skills/kibi-traceability/SKILL.md +4 -0
- package/src/public/skills/kibi-usage/SKILL.md +21 -16
- package/src/public/skills/kibi-usage/resources/proof.md +36 -4
- package/src/public/skills/kibi-usage/resources/workflows.md +1 -1
- package/templates/github/kibi-badge.yml +1 -1
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { SIGNOFF_CHANGE_LABELS, SIGNOFF_FENCES, approvalNumbers, approvalSentence, awaitsApproval, proofLabel, questionKind, questionOpen, statementSentenceDiff, } from "./model.js";
|
|
2
|
+
/** Rows shown in chat before the rest is left to the HTML view. */
|
|
3
|
+
export const SIGNOFF_MARKDOWN_LIMIT = 15;
|
|
4
|
+
const CHANGE_ORDER = [
|
|
5
|
+
"new",
|
|
6
|
+
"changed",
|
|
7
|
+
"affected",
|
|
8
|
+
"retired",
|
|
9
|
+
];
|
|
10
|
+
function quote(text) {
|
|
11
|
+
return `> ${text.replace(/\s+/g, " ").trim()}`;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A rewritten statement as lines under a list item: the new statement with
|
|
15
|
+
* added sentences in bold and removed ones struck through when sentences
|
|
16
|
+
* survive the rewrite, or the old and new statements otherwise.
|
|
17
|
+
*/
|
|
18
|
+
function rewriteLines(previous, statement, labels = ["Was", "Now"]) {
|
|
19
|
+
const diff = statementSentenceDiff(previous, statement);
|
|
20
|
+
if (diff === undefined) {
|
|
21
|
+
return [
|
|
22
|
+
`- ${labels[0]}:`,
|
|
23
|
+
` ${quote(previous)}`,
|
|
24
|
+
`- ${labels[1]}:`,
|
|
25
|
+
` ${quote(statement)}`,
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
const added = diff.filter((part) => part.change === "added").length;
|
|
29
|
+
const removed = diff.filter((part) => part.change === "removed").length;
|
|
30
|
+
const counts = [
|
|
31
|
+
added > 0 ? `${added} added in bold` : undefined,
|
|
32
|
+
removed > 0 ? `${removed} removed struck through` : undefined,
|
|
33
|
+
].filter(Boolean);
|
|
34
|
+
const text = diff
|
|
35
|
+
.map((part) => part.change === "added"
|
|
36
|
+
? `**${part.text}**`
|
|
37
|
+
: part.change === "removed"
|
|
38
|
+
? `~~${part.text}~~`
|
|
39
|
+
: part.text)
|
|
40
|
+
.join(" ");
|
|
41
|
+
return [
|
|
42
|
+
`- ${labels[1]}, sentences ${counts.join(", ")}:`,
|
|
43
|
+
` ${quote(text)}`,
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
function firmnessTag(firmness) {
|
|
47
|
+
return firmness === "firm"
|
|
48
|
+
? "firm"
|
|
49
|
+
: firmness === "exploratory"
|
|
50
|
+
? "exploratory"
|
|
51
|
+
: "default";
|
|
52
|
+
}
|
|
53
|
+
function originLine(requirement) {
|
|
54
|
+
const parts = [];
|
|
55
|
+
if (requirement.originKind)
|
|
56
|
+
parts.push(requirement.originKind);
|
|
57
|
+
if (requirement.originRef)
|
|
58
|
+
parts.push(`"${requirement.originRef}"`);
|
|
59
|
+
if (requirement.approvedBy)
|
|
60
|
+
parts.push(`approved by ${requirement.approvedBy}`);
|
|
61
|
+
if (awaitsApproval(requirement))
|
|
62
|
+
parts.push("**awaiting your approval**");
|
|
63
|
+
return parts.length > 0 ? `- Origin: ${parts.join(", ")}` : undefined;
|
|
64
|
+
}
|
|
65
|
+
function requirementBlock(requirement, number) {
|
|
66
|
+
const lines = [
|
|
67
|
+
`**${number}. ${requirement.id}** · ${firmnessTag(requirement.firmness)} · ${requirement.title}`,
|
|
68
|
+
];
|
|
69
|
+
if (requirement.previousStatement !== undefined) {
|
|
70
|
+
lines.push(...rewriteLines(requirement.previousStatement, requirement.statement));
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
lines.push(quote(requirement.statement));
|
|
74
|
+
}
|
|
75
|
+
const origin = originLine(requirement);
|
|
76
|
+
if (origin)
|
|
77
|
+
lines.push(origin);
|
|
78
|
+
for (const superseded of requirement.supersedes) {
|
|
79
|
+
lines.push(`- Replaces ${superseded.id} (${firmnessTag(superseded.firmness)}): ${superseded.statement}`);
|
|
80
|
+
}
|
|
81
|
+
if (requirement.symbols.length > 0) {
|
|
82
|
+
lines.push(`- Changed code: ${requirement.symbols.join(", ")}`);
|
|
83
|
+
}
|
|
84
|
+
if (requirement.change !== "retired") {
|
|
85
|
+
lines.push(requirement.scenarios.length > 0
|
|
86
|
+
? `- Scenarios: ${requirement.scenarios.map((scenario) => (scenario.title === scenario.id ? scenario.id : `${scenario.id} (${scenario.title})`)).join("; ")}`
|
|
87
|
+
: "- Scenarios: none yet");
|
|
88
|
+
lines.push(`- Proof: ${proofLabel(requirement.proof)}`);
|
|
89
|
+
for (const conflict of requirement.proof?.contradictions ?? []) {
|
|
90
|
+
lines.push(`- Contradiction: ${conflict}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return lines;
|
|
94
|
+
}
|
|
95
|
+
function headline(summary) {
|
|
96
|
+
const counts = CHANGE_ORDER.map((change) => [
|
|
97
|
+
change,
|
|
98
|
+
summary.requirements.filter((row) => row.change === change).length,
|
|
99
|
+
])
|
|
100
|
+
.filter(([, count]) => count > 0)
|
|
101
|
+
.map(([change, count]) => `${count} ${change}`);
|
|
102
|
+
return counts.length === 0
|
|
103
|
+
? "## Requirements signoff: no requirement changes"
|
|
104
|
+
: `## Requirements signoff: ${counts.join(", ")}`;
|
|
105
|
+
}
|
|
106
|
+
// implements REQ-kibi-signoff-views
|
|
107
|
+
/** The end-of-work summary as Markdown, without the fence. */
|
|
108
|
+
export function renderSummaryMarkdownBody(summary, limit = SIGNOFF_MARKDOWN_LIMIT) {
|
|
109
|
+
const lines = [headline(summary)];
|
|
110
|
+
const approvals = approvalNumbers(CHANGE_ORDER.flatMap((change) => summary.requirements.filter((row) => row.change === change)));
|
|
111
|
+
if (approvals.length > 0)
|
|
112
|
+
lines.push("", `**${approvalSentence(approvals)}**`);
|
|
113
|
+
let number = 0;
|
|
114
|
+
for (const change of CHANGE_ORDER) {
|
|
115
|
+
const rows = summary.requirements.filter((row) => row.change === change);
|
|
116
|
+
const shown = rows.slice(0, Math.max(0, limit - number));
|
|
117
|
+
if (shown.length === 0)
|
|
118
|
+
continue;
|
|
119
|
+
lines.push("", `### ${SIGNOFF_CHANGE_LABELS[change]}`);
|
|
120
|
+
for (const row of shown) {
|
|
121
|
+
number += 1;
|
|
122
|
+
lines.push("", ...requirementBlock(row, number));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const hidden = summary.requirements.length - limit;
|
|
126
|
+
if (hidden > 0) {
|
|
127
|
+
lines.push("", `…and ${hidden} more. Run \`kibi signoff --format html --open\` to see them all.`);
|
|
128
|
+
}
|
|
129
|
+
if (approvals.length > 0) {
|
|
130
|
+
lines.push("", 'Reply by number, for example "approve 1" or "1: reword …".');
|
|
131
|
+
}
|
|
132
|
+
for (const note of summary.notes)
|
|
133
|
+
lines.push("", `Note: ${note}`);
|
|
134
|
+
return lines.join("\n");
|
|
135
|
+
}
|
|
136
|
+
// implements REQ-kibi-signoff-views
|
|
137
|
+
/** The mid-work decision questions as Markdown, without the fence. */
|
|
138
|
+
export function renderQuestionsMarkdownBody(view) {
|
|
139
|
+
const open = view.questions.filter(questionOpen).length;
|
|
140
|
+
const answered = view.questions.length - open;
|
|
141
|
+
const lines = [
|
|
142
|
+
`## Decisions to confirm: ${open} open${answered > 0 ? `, ${answered} answered` : ""}`,
|
|
143
|
+
];
|
|
144
|
+
for (const question of view.questions) {
|
|
145
|
+
const title = question.title ?? question.current?.title ?? question.id;
|
|
146
|
+
const heading = `${question.number}. ${questionKind(question)}${title ? `: ${title}` : ""}`;
|
|
147
|
+
lines.push("");
|
|
148
|
+
if (!questionOpen(question)) {
|
|
149
|
+
lines.push(`~~**${heading}**~~ · answered: ${question.answer}`);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
lines.push(`**${heading}**${question.firmness ? ` · would be ${question.firmness}` : ""}`);
|
|
153
|
+
if (question.current) {
|
|
154
|
+
lines.push(...rewriteLines(question.current.statement, question.statement, [
|
|
155
|
+
`Recorded now (${firmnessTag(question.current.firmness)})`,
|
|
156
|
+
"Proposed",
|
|
157
|
+
]));
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
lines.push(quote(question.statement));
|
|
161
|
+
}
|
|
162
|
+
if (question.quote)
|
|
163
|
+
lines.push(`- Your words: "${question.quote}"`);
|
|
164
|
+
if (question.governs?.length) {
|
|
165
|
+
lines.push(`- Governs: ${question.governs.join(", ")}`);
|
|
166
|
+
}
|
|
167
|
+
for (const conflict of question.conflicts) {
|
|
168
|
+
lines.push(`- Conflicts with ${conflict.id} (${firmnessTag(conflict.firmness)}): ${conflict.statement}`);
|
|
169
|
+
}
|
|
170
|
+
if (question.question)
|
|
171
|
+
lines.push(`- Question: ${question.question}`);
|
|
172
|
+
}
|
|
173
|
+
if (open > 0) {
|
|
174
|
+
lines.push("", 'Reply by number, for example "1 yes, 2 exploratory, 3 reword: …".');
|
|
175
|
+
}
|
|
176
|
+
for (const note of view.notes)
|
|
177
|
+
lines.push("", `Note: ${note}`);
|
|
178
|
+
return lines.join("\n");
|
|
179
|
+
}
|
|
180
|
+
// implements REQ-kibi-signoff-views
|
|
181
|
+
/**
|
|
182
|
+
* A signoff view as plain Markdown for a chat reply or a messaging tool
|
|
183
|
+
* (headings, quotes and lists that any Markdown surface renders), with no
|
|
184
|
+
* fence for a host renderer to find.
|
|
185
|
+
*/
|
|
186
|
+
export function renderSignoffChatMarkdown(view) {
|
|
187
|
+
return view.kind === "summary"
|
|
188
|
+
? renderSummaryMarkdownBody(view)
|
|
189
|
+
: renderQuestionsMarkdownBody(view);
|
|
190
|
+
}
|
|
191
|
+
// implements REQ-kibi-signoff-views
|
|
192
|
+
/**
|
|
193
|
+
* A signoff view as the fenced block agents paste into chat. Host renderers
|
|
194
|
+
* (the Claude Code display hook, the OpenCode TUI) key on the fence's info
|
|
195
|
+
* string; hosts without one show it as a code block, so they get `chat`.
|
|
196
|
+
*/
|
|
197
|
+
export function renderSignoffMarkdown(view) {
|
|
198
|
+
const fence = SIGNOFF_FENCES[view.kind];
|
|
199
|
+
const body = renderSignoffChatMarkdown(view);
|
|
200
|
+
// A body line starting with ``` would close the fence early.
|
|
201
|
+
const safe = body.replace(/^```/gm, "'''");
|
|
202
|
+
return `\`\`\`${fence}\n${safe}\n\`\`\`\n`;
|
|
203
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Requirement signoff views. A person signs off requirements at two moments:
|
|
3
|
+
* mid-work, when the agent asks them to confirm rules before recording them
|
|
4
|
+
* (questions), and at the end of the work, before the commit (summary). Both
|
|
5
|
+
* views are one JSON document that every host renders: the CLI prints it as a
|
|
6
|
+
* fenced Markdown block or a self-contained HTML page, and editor plugins read
|
|
7
|
+
* the copies written to `.kb/briefs/signoff/` (latest.json, latest.md and
|
|
8
|
+
* latest.html; `.kb/briefs/` is git-ignored and never synced).
|
|
9
|
+
*/
|
|
10
|
+
export declare const SIGNOFF_VERSION = "kibi.signoff.v1";
|
|
11
|
+
/** The fence info strings host renderers key on. */
|
|
12
|
+
export declare const SIGNOFF_FENCES: {
|
|
13
|
+
readonly summary: "kibi-signoff";
|
|
14
|
+
readonly questions: "kibi-questions";
|
|
15
|
+
};
|
|
16
|
+
/** Where the latest signoff view is written, relative to the workspace. */
|
|
17
|
+
export declare const SIGNOFF_BRIEF_DIR = ".kb/briefs/signoff";
|
|
18
|
+
export declare const SIGNOFF_LATEST_JSON = ".kb/briefs/signoff/latest.json";
|
|
19
|
+
/** The latest view's Markdown body (no fence), for plain-text host views. */
|
|
20
|
+
export declare const SIGNOFF_LATEST_MARKDOWN = ".kb/briefs/signoff/latest.md";
|
|
21
|
+
/** The latest view as a self-contained page, for browsers and webviews. */
|
|
22
|
+
export declare const SIGNOFF_LATEST_HTML = ".kb/briefs/signoff/latest.html";
|
|
23
|
+
export type SignoffFirmness = "firm" | "default" | "exploratory";
|
|
24
|
+
/** How a requirement entered the change. */
|
|
25
|
+
export type SignoffChange = "new" | "changed" | "affected" | "retired";
|
|
26
|
+
export type SignoffStatementRef = Readonly<{
|
|
27
|
+
id: string;
|
|
28
|
+
title: string;
|
|
29
|
+
statement: string;
|
|
30
|
+
firmness?: SignoffFirmness;
|
|
31
|
+
}>;
|
|
32
|
+
export type SignoffProof = Readonly<{
|
|
33
|
+
/** Coverage proof status: tested, missing, unresolved or not_applicable. */
|
|
34
|
+
status: string;
|
|
35
|
+
/** The earliest unmet proof gate, or "tested". */
|
|
36
|
+
gate: string;
|
|
37
|
+
testCount: number;
|
|
38
|
+
/**
|
|
39
|
+
* How strong the evidence is: proved, tested, asserted (a person stands
|
|
40
|
+
* behind it, nothing current checks it) or unverified.
|
|
41
|
+
*/
|
|
42
|
+
evidenceLevel?: string;
|
|
43
|
+
contradictions: readonly string[];
|
|
44
|
+
}>;
|
|
45
|
+
export type SignoffRequirement = Readonly<{
|
|
46
|
+
id: string;
|
|
47
|
+
title: string;
|
|
48
|
+
change: SignoffChange;
|
|
49
|
+
status: string;
|
|
50
|
+
statement: string;
|
|
51
|
+
/** The statement at the base commit, when the change rewrote it. */
|
|
52
|
+
previousStatement?: string;
|
|
53
|
+
firmness?: SignoffFirmness;
|
|
54
|
+
originKind?: string;
|
|
55
|
+
originRef?: string;
|
|
56
|
+
approvedBy?: string;
|
|
57
|
+
supersedes: readonly SignoffStatementRef[];
|
|
58
|
+
scenarios: readonly Readonly<{
|
|
59
|
+
id: string;
|
|
60
|
+
title: string;
|
|
61
|
+
}>[];
|
|
62
|
+
/** Changed code symbols that implement it (affected requirements). */
|
|
63
|
+
symbols: readonly string[];
|
|
64
|
+
proof?: SignoffProof;
|
|
65
|
+
source: string;
|
|
66
|
+
}>;
|
|
67
|
+
export type SignoffSummary = Readonly<{
|
|
68
|
+
version: typeof SIGNOFF_VERSION;
|
|
69
|
+
kind: "summary";
|
|
70
|
+
scope: "staged" | "working";
|
|
71
|
+
generatedAt: string;
|
|
72
|
+
branch?: string;
|
|
73
|
+
requirements: readonly SignoffRequirement[];
|
|
74
|
+
/** Parts of the view Kibi could not compute, in plain words. */
|
|
75
|
+
notes: readonly string[];
|
|
76
|
+
}>;
|
|
77
|
+
/** One decision the agent asks the person to confirm. */
|
|
78
|
+
export type SignoffQuestionInput = Readonly<{
|
|
79
|
+
/** Existing or proposed requirement id. */
|
|
80
|
+
id?: string;
|
|
81
|
+
title?: string;
|
|
82
|
+
/** The rule as it would be recorded. */
|
|
83
|
+
statement: string;
|
|
84
|
+
/** The person's words that would go in origin.ref. */
|
|
85
|
+
quote?: string;
|
|
86
|
+
firmness?: SignoffFirmness;
|
|
87
|
+
/** Files or symbols the rule governs. */
|
|
88
|
+
governs?: readonly string[];
|
|
89
|
+
/** Recorded requirements the rule conflicts with. */
|
|
90
|
+
conflictsWith?: readonly string[];
|
|
91
|
+
/** What the agent asks, when it is more than "record this?". */
|
|
92
|
+
question?: string;
|
|
93
|
+
/** The person's answer, once given. */
|
|
94
|
+
answer?: string;
|
|
95
|
+
}>;
|
|
96
|
+
export type SignoffQuestion = SignoffQuestionInput & Readonly<{
|
|
97
|
+
number: number;
|
|
98
|
+
/** The recorded requirement this question would change. */
|
|
99
|
+
current?: SignoffStatementRef;
|
|
100
|
+
conflicts: readonly SignoffStatementRef[];
|
|
101
|
+
}>;
|
|
102
|
+
export type SignoffQuestions = Readonly<{
|
|
103
|
+
version: typeof SIGNOFF_VERSION;
|
|
104
|
+
kind: "questions";
|
|
105
|
+
generatedAt: string;
|
|
106
|
+
questions: readonly SignoffQuestion[];
|
|
107
|
+
notes: readonly string[];
|
|
108
|
+
}>;
|
|
109
|
+
export type SignoffView = SignoffSummary | SignoffQuestions;
|
|
110
|
+
export declare const SIGNOFF_CHANGE_LABELS: Readonly<Record<SignoffChange, string>>;
|
|
111
|
+
export declare const SIGNOFF_GATE_LABELS: Readonly<Record<string, string>>;
|
|
112
|
+
/** A short proof label for one requirement. */
|
|
113
|
+
export declare function proofLabel(proof: SignoffProof | undefined): string;
|
|
114
|
+
/** Whether a question still waits for the person. */
|
|
115
|
+
export declare function questionOpen(question: SignoffQuestionInput): boolean;
|
|
116
|
+
/** The kind of decision a question asks for. */
|
|
117
|
+
export declare function questionKind(question: SignoffQuestion): string;
|
|
118
|
+
/** One sentence of a rewritten statement and how the rewrite changed it. */
|
|
119
|
+
export type StatementSentence = Readonly<{
|
|
120
|
+
text: string;
|
|
121
|
+
change: "kept" | "added" | "removed";
|
|
122
|
+
}>;
|
|
123
|
+
/**
|
|
124
|
+
* A rewrite of a statement as its sentences in reading order, each kept,
|
|
125
|
+
* added or removed (a longest-common-subsequence diff), so the person reads
|
|
126
|
+
* what changed instead of comparing two paragraphs. Undefined when no
|
|
127
|
+
* sentence survives the rewrite, where before and after reads better.
|
|
128
|
+
*/
|
|
129
|
+
export declare function statementSentenceDiff(previous: string, statement: string): readonly StatementSentence[] | undefined;
|
|
130
|
+
/**
|
|
131
|
+
* Whether the change asks the person to approve a requirement: the agent
|
|
132
|
+
* wrote or rewrote it and nobody has approved it.
|
|
133
|
+
*/
|
|
134
|
+
export declare function awaitsApproval(requirement: SignoffRequirement): boolean;
|
|
135
|
+
/** The numbers (in view order) of the requirements awaiting approval. */
|
|
136
|
+
export declare function approvalNumbers(ordered: readonly SignoffRequirement[]): number[];
|
|
137
|
+
/** One sentence naming the requirements that wait for the person. */
|
|
138
|
+
export declare function approvalSentence(numbers: readonly number[]): string;
|
|
139
|
+
//# sourceMappingURL=model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/signoff/model.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Requirement signoff views. A person signs off requirements at two moments:
|
|
3
|
+
* mid-work, when the agent asks them to confirm rules before recording them
|
|
4
|
+
* (questions), and at the end of the work, before the commit (summary). Both
|
|
5
|
+
* views are one JSON document that every host renders: the CLI prints it as a
|
|
6
|
+
* fenced Markdown block or a self-contained HTML page, and editor plugins read
|
|
7
|
+
* the copies written to `.kb/briefs/signoff/` (latest.json, latest.md and
|
|
8
|
+
* latest.html; `.kb/briefs/` is git-ignored and never synced).
|
|
9
|
+
*/
|
|
10
|
+
export const SIGNOFF_VERSION = "kibi.signoff.v1";
|
|
11
|
+
/** The fence info strings host renderers key on. */
|
|
12
|
+
export const SIGNOFF_FENCES = {
|
|
13
|
+
summary: "kibi-signoff",
|
|
14
|
+
questions: "kibi-questions",
|
|
15
|
+
};
|
|
16
|
+
/** Where the latest signoff view is written, relative to the workspace. */
|
|
17
|
+
export const SIGNOFF_BRIEF_DIR = ".kb/briefs/signoff";
|
|
18
|
+
export const SIGNOFF_LATEST_JSON = `${SIGNOFF_BRIEF_DIR}/latest.json`;
|
|
19
|
+
/** The latest view's Markdown body (no fence), for plain-text host views. */
|
|
20
|
+
export const SIGNOFF_LATEST_MARKDOWN = `${SIGNOFF_BRIEF_DIR}/latest.md`;
|
|
21
|
+
/** The latest view as a self-contained page, for browsers and webviews. */
|
|
22
|
+
export const SIGNOFF_LATEST_HTML = `${SIGNOFF_BRIEF_DIR}/latest.html`;
|
|
23
|
+
export const SIGNOFF_CHANGE_LABELS = {
|
|
24
|
+
new: "New",
|
|
25
|
+
changed: "Changed",
|
|
26
|
+
affected: "Affected by the code change (statement unchanged)",
|
|
27
|
+
retired: "Superseded or retired",
|
|
28
|
+
};
|
|
29
|
+
export const SIGNOFF_GATE_LABELS = {
|
|
30
|
+
semantic: "semantic model incomplete",
|
|
31
|
+
scenario: "no scenario yet",
|
|
32
|
+
implementation: "no owning code yet",
|
|
33
|
+
e2e: "no end-to-end test yet",
|
|
34
|
+
evidence: "end-to-end evidence not current",
|
|
35
|
+
tested: "tested",
|
|
36
|
+
};
|
|
37
|
+
/** A short proof label for one requirement. */
|
|
38
|
+
// implements REQ-kibi-evidence-levels
|
|
39
|
+
export function proofLabel(proof) {
|
|
40
|
+
if (proof === undefined)
|
|
41
|
+
return "not checked";
|
|
42
|
+
if (proof.status === "not_applicable")
|
|
43
|
+
return "not applicable";
|
|
44
|
+
const gate = SIGNOFF_GATE_LABELS[proof.gate] ?? proof.gate;
|
|
45
|
+
const tests = `${proof.testCount} ${proof.testCount === 1 ? "test" : "tests"}`;
|
|
46
|
+
const label = proof.gate === "tested" ? `tested, ${tests}` : `${gate}, ${tests}`;
|
|
47
|
+
return proof.evidenceLevel === undefined || proof.evidenceLevel === "tested"
|
|
48
|
+
? label
|
|
49
|
+
: `${label}; evidence ${proof.evidenceLevel}`;
|
|
50
|
+
}
|
|
51
|
+
/** Whether a question still waits for the person. */
|
|
52
|
+
export function questionOpen(question) {
|
|
53
|
+
return (question.answer ?? "").trim() === "";
|
|
54
|
+
}
|
|
55
|
+
/** The kind of decision a question asks for. */
|
|
56
|
+
export function questionKind(question) {
|
|
57
|
+
if (question.current)
|
|
58
|
+
return `Change ${question.current.id}`;
|
|
59
|
+
if (question.conflicts.length > 0)
|
|
60
|
+
return "Conflict with a recorded rule";
|
|
61
|
+
return "New rule";
|
|
62
|
+
}
|
|
63
|
+
function sentences(statement) {
|
|
64
|
+
return statement
|
|
65
|
+
.replace(/\s+/g, " ")
|
|
66
|
+
.trim()
|
|
67
|
+
.split(/(?<=[.!?])\s+(?=[A-Z0-9"'`(])/)
|
|
68
|
+
.filter((sentence) => sentence.length > 0);
|
|
69
|
+
}
|
|
70
|
+
// implements REQ-kibi-signoff-views
|
|
71
|
+
/**
|
|
72
|
+
* A rewrite of a statement as its sentences in reading order, each kept,
|
|
73
|
+
* added or removed (a longest-common-subsequence diff), so the person reads
|
|
74
|
+
* what changed instead of comparing two paragraphs. Undefined when no
|
|
75
|
+
* sentence survives the rewrite, where before and after reads better.
|
|
76
|
+
*/
|
|
77
|
+
export function statementSentenceDiff(previous, statement) {
|
|
78
|
+
const before = sentences(previous);
|
|
79
|
+
const after = sentences(statement);
|
|
80
|
+
const table = before.map(() => new Array(after.length + 1).fill(0));
|
|
81
|
+
table.push(new Array(after.length + 1).fill(0));
|
|
82
|
+
for (let i = before.length - 1; i >= 0; i -= 1) {
|
|
83
|
+
for (let j = after.length - 1; j >= 0; j -= 1) {
|
|
84
|
+
const row = table[i];
|
|
85
|
+
const next = table[i + 1];
|
|
86
|
+
row[j] =
|
|
87
|
+
before[i] === after[j]
|
|
88
|
+
? next[j + 1] + 1
|
|
89
|
+
: Math.max(next[j], row[j + 1]);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if ((table[0]?.[0] ?? 0) === 0)
|
|
93
|
+
return undefined;
|
|
94
|
+
const result = [];
|
|
95
|
+
let i = 0;
|
|
96
|
+
let j = 0;
|
|
97
|
+
while (i < before.length || j < after.length) {
|
|
98
|
+
if (i < before.length && j < after.length && before[i] === after[j]) {
|
|
99
|
+
result.push({ text: after[j], change: "kept" });
|
|
100
|
+
i += 1;
|
|
101
|
+
j += 1;
|
|
102
|
+
}
|
|
103
|
+
else if (j < after.length &&
|
|
104
|
+
(i >= before.length ||
|
|
105
|
+
table[i]?.[j + 1] >= table[i + 1]?.[j])) {
|
|
106
|
+
result.push({ text: after[j], change: "added" });
|
|
107
|
+
j += 1;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
result.push({ text: before[i], change: "removed" });
|
|
111
|
+
i += 1;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
// implements REQ-kibi-signoff-views
|
|
117
|
+
/**
|
|
118
|
+
* Whether the change asks the person to approve a requirement: the agent
|
|
119
|
+
* wrote or rewrote it and nobody has approved it.
|
|
120
|
+
*/
|
|
121
|
+
export function awaitsApproval(requirement) {
|
|
122
|
+
return ((requirement.change === "new" || requirement.change === "changed") &&
|
|
123
|
+
requirement.originKind === "agent" &&
|
|
124
|
+
!requirement.approvedBy);
|
|
125
|
+
}
|
|
126
|
+
// implements REQ-kibi-signoff-views
|
|
127
|
+
/** The numbers (in view order) of the requirements awaiting approval. */
|
|
128
|
+
export function approvalNumbers(ordered) {
|
|
129
|
+
return ordered.flatMap((requirement, index) => awaitsApproval(requirement) ? [index + 1] : []);
|
|
130
|
+
}
|
|
131
|
+
// implements REQ-kibi-signoff-views
|
|
132
|
+
/** One sentence naming the requirements that wait for the person. */
|
|
133
|
+
export function approvalSentence(numbers) {
|
|
134
|
+
if (numbers.length === 0)
|
|
135
|
+
return "";
|
|
136
|
+
const list = numbers.length === 1
|
|
137
|
+
? `${numbers[0]}`
|
|
138
|
+
: `${numbers.slice(0, -1).join(", ")} and ${numbers.at(-1)}`;
|
|
139
|
+
return numbers.length === 1
|
|
140
|
+
? `Requirement ${list} was written by the agent and waits for your approval.`
|
|
141
|
+
: `Requirements ${list} were written by the agent and wait for your approval.`;
|
|
142
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"staged-consistency.d.ts","sourceRoot":"","sources":["../../src/traceability/staged-consistency.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"staged-consistency.d.ts","sourceRoot":"","sources":["../../src/traceability/staged-consistency.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAwB1D,KAAK,cAAc,GAAG,QAAQ,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC;IACzC,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjE,CAAC,CAAC;AAEH;;;;GAIG;AAEH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAMjE;AAkDD;;;;;GAKG;AAEH,wBAAsB,sCAAsC,CAC1D,QAAQ,EAAE,cAAc,EACxB,aAAa,EAAE,gBAAgB,EAAE,GAChC,OAAO,CAAC,SAAS,EAAE,CAAC,CAYtB;AAED,8EAA8E;AAE9E,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,SAAS,SAAS,EAAE,EAChC,IAAI,SAAgB,GACnB,MAAM,EAAE,CAWV"}
|
|
@@ -4,7 +4,8 @@ import { readSnapshotKnowledge } from "./snapshot-knowledge.js";
|
|
|
4
4
|
import { cleanupTempKb, createTempKb, projectStagedEntities, } from "./temp-kb.js";
|
|
5
5
|
/**
|
|
6
6
|
* Canonical rules that decide whether the staged knowledge is consistent:
|
|
7
|
-
* requirement contradictions,
|
|
7
|
+
* requirement contradictions (pairwise, and joint ones whose certificate the
|
|
8
|
+
* independent checker re-verifies), success scenarios a current requirement
|
|
8
9
|
* forbids, and exceptions that name claims they cannot waive. They read only
|
|
9
10
|
* authored knowledge, so the staged tree alone decides them.
|
|
10
11
|
*/
|
|
@@ -13,6 +14,7 @@ const STAGED_CONSISTENCY_RULES = [
|
|
|
13
14
|
"domain-contradictions",
|
|
14
15
|
"scenario-feasibility",
|
|
15
16
|
"exception-claim-keys",
|
|
17
|
+
"kb-consistency",
|
|
16
18
|
];
|
|
17
19
|
/**
|
|
18
20
|
* True when the staged change set touches entity documents or relationship
|
|
@@ -269,5 +269,15 @@ export declare const GENERATED_RULES: readonly [{
|
|
|
269
269
|
readonly description: "When a plugin activated for kibi.check-policy.v1 declares marker rules, every file implementing a requirement grounded in the rule's pattern predicate (with its declared sibling files) must contain each marker the KB declares for that pattern";
|
|
270
270
|
readonly enforcementClass: "canonical";
|
|
271
271
|
readonly category: "traceability";
|
|
272
|
+
}, {
|
|
273
|
+
readonly name: "kb-consistency";
|
|
274
|
+
readonly description: "The facts current requirements name must hold together, jointly and not only pairwise: every property context needs a value that satisfies all its facts, every atom and decision key one truth value, and stored rules a stratification. Each finding is a contradiction certificate (an irreducible core, two disagreeing facts or a negation cycle) re-verified by the independent checker, or a certificate that checker rejects";
|
|
275
|
+
readonly enforcementClass: "canonical";
|
|
276
|
+
readonly category: "integrity";
|
|
277
|
+
}, {
|
|
278
|
+
readonly name: "kb-consistency-unresolved";
|
|
279
|
+
readonly description: "Advisory: a property context, atom or decision key whose facts the consistency checker cannot compare (mixed value types or units, an unsupported operator or polarity, or a contradiction whose validity windows never overlap); it never counts as consistent";
|
|
280
|
+
readonly enforcementClass: "advisory";
|
|
281
|
+
readonly category: "integrity";
|
|
272
282
|
}];
|
|
273
283
|
//# sourceMappingURL=rule-registry.generated.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-registry.generated.d.ts","sourceRoot":"","sources":["../../src/utils/rule-registry.generated.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,eAAe
|
|
1
|
+
{"version":3,"file":"rule-registry.generated.d.ts","sourceRoot":"","sources":["../../src/utils/rule-registry.generated.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqYlB,CAAC"}
|
|
@@ -332,4 +332,16 @@ export const GENERATED_RULES = [
|
|
|
332
332
|
enforcementClass: "canonical",
|
|
333
333
|
category: "traceability",
|
|
334
334
|
},
|
|
335
|
+
{
|
|
336
|
+
name: "kb-consistency",
|
|
337
|
+
description: "The facts current requirements name must hold together, jointly and not only pairwise: every property context needs a value that satisfies all its facts, every atom and decision key one truth value, and stored rules a stratification. Each finding is a contradiction certificate (an irreducible core, two disagreeing facts or a negation cycle) re-verified by the independent checker, or a certificate that checker rejects",
|
|
338
|
+
enforcementClass: "canonical",
|
|
339
|
+
category: "integrity",
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
name: "kb-consistency-unresolved",
|
|
343
|
+
description: "Advisory: a property context, atom or decision key whose facts the consistency checker cannot compare (mixed value types or units, an unsupported operator or polarity, or a contradiction whose validity windows never overlap); it never counts as consistent",
|
|
344
|
+
enforcementClass: "advisory",
|
|
345
|
+
category: "integrity",
|
|
346
|
+
},
|
|
335
347
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kibi-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.31.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Kibi CLI for knowledge base management",
|
|
6
6
|
"engines": {
|
|
@@ -235,7 +235,7 @@
|
|
|
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.
|
|
238
|
+
"kibi-core": "^0.23.0",
|
|
239
239
|
"kibi-plugin-builtin": "^0.5.3",
|
|
240
240
|
"kibi-plugin-sdk": "^0.5.0",
|
|
241
241
|
"kibi-swipl": "^1.0.1",
|
|
@@ -147,7 +147,7 @@ function appendCoverageFields(
|
|
|
147
147
|
const scope = isRecord(repairPlan?.scope) ? repairPlan.scope : undefined;
|
|
148
148
|
fields.coverage_by = typeof args.by === "string" ? args.by : "req";
|
|
149
149
|
fields.coverage_requirement_count = Number(summary.total ?? rows.length);
|
|
150
|
-
fields.
|
|
150
|
+
fields.coverage_tested_count = Number(summary.proofTested ?? 0);
|
|
151
151
|
fields.coverage_proof_missing_count = Number(summary.proofMissing ?? 0);
|
|
152
152
|
fields.coverage_proof_gap_count = gapCodes.length;
|
|
153
153
|
fields.coverage_gap_codes = [...new Set(gapCodes)].sort();
|
|
@@ -223,8 +223,8 @@ export function deriveDiagnosticUsageFields(
|
|
|
223
223
|
if (tool === "kb_coverage" && structured) {
|
|
224
224
|
appendCoverageFields(fields, args, structured);
|
|
225
225
|
fields.result_summary = `${String(
|
|
226
|
-
fields.
|
|
227
|
-
)}
|
|
226
|
+
fields.coverage_tested_count,
|
|
227
|
+
)} tested; ${String(fields.coverage_proof_gap_count)} proof gaps`;
|
|
228
228
|
}
|
|
229
229
|
if (tool === "kb_semantic_advisor" && structured) {
|
|
230
230
|
appendSemanticFields(fields, structured.receipt);
|
|
@@ -652,6 +652,7 @@ const BASE_DATA_SCHEMAS: Readonly<
|
|
|
652
652
|
warnings: valueArray,
|
|
653
653
|
semanticAdvisor: nullableJsonSchema(recordValue),
|
|
654
654
|
normalizedPreview: nullableJsonSchema(recordValue),
|
|
655
|
+
errorCode: stringValue,
|
|
655
656
|
stagedFacts: stringArray,
|
|
656
657
|
whatIf: recordValue,
|
|
657
658
|
}),
|
|
@@ -683,6 +684,7 @@ const BASE_DATA_SCHEMAS: Readonly<
|
|
|
683
684
|
warnings: valueArray,
|
|
684
685
|
semanticAdvisor: nullableJsonSchema(recordValue),
|
|
685
686
|
normalizedPreview: nullableJsonSchema(recordValue),
|
|
687
|
+
errorCode: stringValue,
|
|
686
688
|
stagedFacts: stringArray,
|
|
687
689
|
whatIf: recordValue,
|
|
688
690
|
dryRun: { const: true },
|
|
@@ -20,7 +20,7 @@ export const planBootstrapSpec = {
|
|
|
20
20
|
name: "kb_plan_bootstrap",
|
|
21
21
|
cliName: "plan-bootstrap",
|
|
22
22
|
description:
|
|
23
|
-
"Generate a deterministic, snapshot-bound kibi.bootstrap-plan.v1 for repository onboarding. Read-only analysis of the repository plus any declared knowledge sources and cited intent claims returns evidence, bounded context questions, exact dependency-ordered actions, a canonical plan hash, and no mutation side effects.",
|
|
23
|
+
"Generate a deterministic, snapshot-bound kibi.bootstrap-plan.v1 for repository onboarding. Use it only to onboard a repository whose KB is empty or incomplete (the kibi-bootstrap skill drives it); for a change in an onboarded project use kb_compile_intent. Read-only analysis of the repository plus any declared knowledge sources and cited intent claims returns evidence, bounded context questions, exact dependency-ordered actions, a canonical plan hash, and no mutation side effects.",
|
|
24
24
|
businessInputSchema: {
|
|
25
25
|
type: "object",
|
|
26
26
|
properties: {
|
|
@@ -63,9 +63,11 @@ export const SELECTABLE_RULE_NAMES: readonly string[] = [
|
|
|
63
63
|
"supersedes-reason-acknowledged",
|
|
64
64
|
"policy-ownership",
|
|
65
65
|
"policy-markers",
|
|
66
|
+
"kb-consistency",
|
|
67
|
+
"kb-consistency-unresolved",
|
|
66
68
|
];
|
|
67
69
|
|
|
68
70
|
// implements REQ-006
|
|
69
71
|
/** Comma-separated "Allowed:" fragment for the kb_check rules description. */
|
|
70
72
|
export const SELECTABLE_RULES_ALLOWED =
|
|
71
|
-
"must-priority-coverage, symbol-coverage, symbol-traceability, symbol-granularity, no-dangling-refs, source-relationship-parity, branch-store-not-compiled, source-path-dangling, no-cycles, required-fields, deprecated-adr-no-successor, superseded-requirement-open, scenario-feasibility, scenario-feasibility-unknown, exception-claim-keys, numeric-string-value, rule-key-arguments-missing, domain-contradictions, logic-coverage, rule-safety, rule-verifiability, query-plan-safety, req-status-vocabulary, strict-fact-shape, strict-req-fact-pairing, predicate-verifiability, strict-readiness, semantic-completeness, related-requirement-unmodeled, proof-contract-symbols, entity-id-style, domain-redundancy, domain-implication, subject-key-identity, subject-key-shape, ontology-quality, exception-unapproved, exception-approval-self-attested, agent-requirement-unapproved, requirement-rationale-missing, symbol-owner-superseded, adr-unlinked, adr-proposed, predicate-schema-conformance, entity-context-missing, entity-context-acknowledged, decision-firm-unreferenced, decision-firm-superseded, decision-firm-edited, supersedes-reason-missing, supersedes-reason-acknowledged, policy-ownership, policy-markers";
|
|
73
|
+
"must-priority-coverage, symbol-coverage, symbol-traceability, symbol-granularity, no-dangling-refs, source-relationship-parity, branch-store-not-compiled, source-path-dangling, no-cycles, required-fields, deprecated-adr-no-successor, superseded-requirement-open, scenario-feasibility, scenario-feasibility-unknown, exception-claim-keys, numeric-string-value, rule-key-arguments-missing, domain-contradictions, logic-coverage, rule-safety, rule-verifiability, query-plan-safety, req-status-vocabulary, strict-fact-shape, strict-req-fact-pairing, predicate-verifiability, strict-readiness, semantic-completeness, related-requirement-unmodeled, proof-contract-symbols, entity-id-style, domain-redundancy, domain-implication, subject-key-identity, subject-key-shape, ontology-quality, exception-unapproved, exception-approval-self-attested, agent-requirement-unapproved, requirement-rationale-missing, symbol-owner-superseded, adr-unlinked, adr-proposed, predicate-schema-conformance, entity-context-missing, entity-context-acknowledged, decision-firm-unreferenced, decision-firm-superseded, decision-firm-edited, supersedes-reason-missing, supersedes-reason-acknowledged, policy-ownership, policy-markers, kb-consistency, kb-consistency-unresolved";
|
|
@@ -217,7 +217,7 @@ export const modelSpec = {
|
|
|
217
217
|
name: "kb_model",
|
|
218
218
|
cliName: "model",
|
|
219
219
|
description:
|
|
220
|
-
"Turn requirement prose into checkable structure without writing the KB. mode:analyze returns the semantic advisor receipt: the clause ledger, what is grounded, what is ambiguous and suggested modeling (pass clauses for compound prose and optional typed kibi.logic.v1 interpretations). mode:requirement converts one claim (subjectKey, propertyKey, operator, value, or typed logic) into a strict-lane write set and applyPlan. mode:predicates ranks ontology predicate schemas and returns an applicable predicate-fact plan only for reviewed bindings, otherwise an ontology-gap observation. With requirementId, mode:predicates also returns a hash-bound plan (fact write plus requires_predicate link) for kb_apply_plan, whose contradictionAnalysis is the what-if over the current KB; other returned plans apply with kb_upsert, and kb_upsert dryRun with plannedFacts previews a requirement before its facts exist.",
|
|
220
|
+
"Turn requirement prose into checkable structure without writing the KB. Use it for one requirement's prose; to plan a whole change request use kb_compile_intent. mode:analyze returns the semantic advisor receipt: the clause ledger, what is grounded, what is ambiguous and suggested modeling (pass clauses for compound prose and optional typed kibi.logic.v1 interpretations). mode:requirement converts one claim (subjectKey, propertyKey, operator, value, or typed logic) into a strict-lane write set and applyPlan. mode:predicates ranks ontology predicate schemas and returns an applicable predicate-fact plan only for reviewed bindings, otherwise an ontology-gap observation. With requirementId, mode:predicates also returns a hash-bound plan (fact write plus requires_predicate link) for kb_apply_plan, whose contradictionAnalysis is the what-if over the current KB; other returned plans apply with kb_upsert, and kb_upsert dryRun with plannedFacts previews a requirement before its facts exist.",
|
|
221
221
|
businessInputSchema: {
|
|
222
222
|
type: "object",
|
|
223
223
|
required: ["mode", "text"],
|