kibi-cli 2.9.0 → 2.11.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.
Files changed (57) hide show
  1. package/dist/operations/bootstrap/candidates.d.ts +2 -1
  2. package/dist/operations/bootstrap/candidates.d.ts.map +1 -1
  3. package/dist/operations/bootstrap/candidates.js +2 -2
  4. package/dist/operations/bootstrap/generate.d.ts.map +1 -1
  5. package/dist/operations/bootstrap/generate.js +6 -2
  6. package/dist/operations/bootstrap/intent-claims.d.ts +2 -1
  7. package/dist/operations/bootstrap/intent-claims.d.ts.map +1 -1
  8. package/dist/operations/bootstrap/intent-claims.js +27 -5
  9. package/dist/operations/bootstrap/markdown-candidates.d.ts +8 -1
  10. package/dist/operations/bootstrap/markdown-candidates.d.ts.map +1 -1
  11. package/dist/operations/bootstrap/markdown-candidates.js +59 -5
  12. package/dist/operations/bootstrap/presentation.d.ts.map +1 -1
  13. package/dist/operations/bootstrap/presentation.js +6 -0
  14. package/dist/operations/bootstrap/requirement-claims.d.ts +61 -1
  15. package/dist/operations/bootstrap/requirement-claims.d.ts.map +1 -1
  16. package/dist/operations/bootstrap/requirement-claims.js +263 -0
  17. package/dist/operations/bootstrap/types.d.ts +6 -0
  18. package/dist/operations/bootstrap/types.d.ts.map +1 -1
  19. package/dist/operations/modeling/predicate-applyplan.d.ts +7 -0
  20. package/dist/operations/modeling/predicate-applyplan.d.ts.map +1 -1
  21. package/dist/operations/modeling/predicate-applyplan.js +39 -12
  22. package/dist/operations/modeling/predicate-binding-hints.d.ts +11 -0
  23. package/dist/operations/modeling/predicate-binding-hints.d.ts.map +1 -0
  24. package/dist/operations/modeling/predicate-binding-hints.js +91 -0
  25. package/dist/operations/modeling/predicate-bindings.d.ts +24 -1
  26. package/dist/operations/modeling/predicate-bindings.d.ts.map +1 -1
  27. package/dist/operations/modeling/predicate-bindings.js +113 -3
  28. package/dist/operations/modeling/predicate-types.d.ts +19 -1
  29. package/dist/operations/modeling/predicate-types.d.ts.map +1 -1
  30. package/dist/operations/modeling/suggest-predicates.d.ts.map +1 -1
  31. package/dist/operations/modeling/suggest-predicates.js +117 -44
  32. package/dist/operations/planning/apply-plan.d.ts +8 -0
  33. package/dist/operations/planning/apply-plan.d.ts.map +1 -1
  34. package/dist/operations/planning/apply-plan.js +69 -20
  35. package/dist/operations/semantic-advisor/observation-plan.d.ts +7 -0
  36. package/dist/operations/semantic-advisor/observation-plan.d.ts.map +1 -1
  37. package/dist/operations/semantic-advisor/observation-plan.js +13 -14
  38. package/dist/public/operations/catalog.d.ts +15 -0
  39. package/dist/public/operations/catalog.d.ts.map +1 -1
  40. package/dist/public/operations/contracts.d.ts.map +1 -1
  41. package/dist/public/operations/contracts.js +5 -1
  42. package/dist/public/operations/specs/bootstrap.d.ts +15 -0
  43. package/dist/public/operations/specs/bootstrap.d.ts.map +1 -1
  44. package/dist/public/operations/specs/bootstrap.js +15 -0
  45. package/dist/public/operations/specs/planning.d.ts +1 -1
  46. package/dist/public/operations/specs/planning.d.ts.map +1 -1
  47. package/dist/public/operations/specs/planning.js +1 -1
  48. package/dist/public/skills/kibi-bootstrap/SKILL.md +5 -5
  49. package/dist/public/skills/kibi-usage/SKILL.md +20 -8
  50. package/dist/public/skills/kibi-usage/resources/workflows.md +2 -2
  51. package/package.json +1 -1
  52. package/src/public/operations/contracts.ts +6 -1
  53. package/src/public/operations/specs/bootstrap.ts +18 -0
  54. package/src/public/operations/specs/planning.ts +4 -1
  55. package/src/public/skills/kibi-bootstrap/SKILL.md +5 -5
  56. package/src/public/skills/kibi-usage/SKILL.md +20 -8
  57. package/src/public/skills/kibi-usage/resources/workflows.md +2 -2
@@ -1,4 +1,5 @@
1
1
  import { type CandidateBuildResult } from "./markdown-candidates.js";
2
+ import type { SubjectKeyRegistry } from "./requirement-claims.js";
2
3
  import type { BootstrapEvidence } from "./types.js";
3
- export declare function buildBootstrapCandidates(evidence: readonly BootstrapEvidence[], existingIds: ReadonlySet<string>, minConfidence: number, includeGenericMarkdown: boolean): CandidateBuildResult;
4
+ export declare function buildBootstrapCandidates(evidence: readonly BootstrapEvidence[], existingIds: ReadonlySet<string>, minConfidence: number, includeGenericMarkdown: boolean, subjectKeys?: SubjectKeyRegistry): CandidateBuildResult;
4
5
  //# sourceMappingURL=candidates.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"candidates.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/candidates.ts"],"names":[],"mappings":"AAYA,OAAO,EACL,KAAK,oBAAoB,EAE1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,YAAY,CAAC;AAuHpB,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,EACtC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,aAAa,EAAE,MAAM,EACrB,sBAAsB,EAAE,OAAO,GAC9B,oBAAoB,CA4DtB"}
1
+ {"version":3,"file":"candidates.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/candidates.ts"],"names":[],"mappings":"AAYA,OAAO,EACL,KAAK,oBAAoB,EAE1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,YAAY,CAAC;AAuHpB,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,EACtC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,aAAa,EAAE,MAAM,EACrB,sBAAsB,EAAE,OAAO,EAC/B,WAAW,CAAC,EAAE,kBAAkB,GAC/B,oBAAoB,CAiEtB"}
@@ -90,7 +90,7 @@ function providerCandidate(item, existingIds, minConfidence) {
90
90
  }
91
91
  // implements REQ-KIBI-BOOTSTRAP-PLAN, REQ-kibi-operation-interface-parity
92
92
  // implements REQ-KIBI-BOOTSTRAP-PLAN
93
- export function buildBootstrapCandidates(evidence, existingIds, minConfidence, includeGenericMarkdown) {
93
+ export function buildBootstrapCandidates(evidence, existingIds, minConfidence, includeGenericMarkdown, subjectKeys) {
94
94
  const candidates = [];
95
95
  const sourceOnlySignals = [];
96
96
  const diagnostics = [];
@@ -114,7 +114,7 @@ export function buildBootstrapCandidates(evidence, existingIds, minConfidence, i
114
114
  }
115
115
  }
116
116
  if (item.kind === "generic_markdown" && includeGenericMarkdown) {
117
- const built = markdownCandidates(item, existingIds, minConfidence);
117
+ const built = markdownCandidates(item, existingIds, minConfidence, subjectKeys);
118
118
  candidates.push(...built.candidates);
119
119
  sourceOnlySignals.push(...built.sourceOnlySignals);
120
120
  diagnostics.push(...built.diagnostics);
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/generate.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAUjF,OAAO,KAAK,EACV,SAAS,EACT,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAGpB,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,SAAS,gBAAgB,EAAE,EACpC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GACzC,SAAS,gBAAgB,EAAE,CAI7B;AA+BD,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAC1C,OAAO,EAAE,MAAM,GACd;IACD,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,UAAU,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;IAClE,QAAQ,CAAC,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACxD,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC,CA6IA;AA+JD,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,iBAAiB,EACvB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CAqG9B"}
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/generate.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAWjF,OAAO,KAAK,EACV,SAAS,EACT,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAGpB,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,SAAS,gBAAgB,EAAE,EACpC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GACzC,SAAS,gBAAgB,EAAE,CAI7B;AA+BD,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAC1C,OAAO,EAAE,MAAM,GACd;IACD,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,UAAU,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;IAClE,QAAQ,CAAC,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACxD,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC,CA6IA;AA+JD,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,iBAAiB,EACvB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CA8G9B"}
@@ -8,6 +8,7 @@ import { buildBootstrapCandidates } from "./candidates.js";
8
8
  import { discoverBootstrap } from "./discovery.js";
9
9
  import { buildIntentClaimCandidates } from "./intent-claims.js";
10
10
  import { normalizeBootstrapContext, presentBootstrap } from "./presentation.js";
11
+ import { SubjectKeyRegistry } from "./requirement-claims.js";
11
12
  import { validateBootstrapPayload } from "./validation.js";
12
13
  export function filterSourceOnlySignals(signals, entityTypes) {
13
14
  return entityTypes && entityTypes.length > 0
@@ -316,8 +317,11 @@ export async function executePlanBootstrap(args, context) {
316
317
  const bound = await expectedSnapshots(context, discovery.evidence
317
318
  .map((evidence) => evidence.relativePath)
318
319
  .filter((value) => Boolean(value)));
320
+ // One registry per plan keeps subject keys distinct across repository
321
+ // documents and declared intent claims.
322
+ const subjectKeys = new SubjectKeyRegistry();
319
323
  const built = discovery.activation.allowCandidateGeneration
320
- ? buildBootstrapCandidates(discovery.evidence, new Set(), minConfidence, includeGenericMarkdown)
324
+ ? buildBootstrapCandidates(discovery.evidence, new Set(), minConfidence, includeGenericMarkdown, subjectKeys)
321
325
  : {
322
326
  candidates: [],
323
327
  sourceOnlySignals: [],
@@ -327,7 +331,7 @@ export async function executePlanBootstrap(args, context) {
327
331
  // Intent harvested from declared knowledge sources joins the repository
328
332
  // evidence under the same activation policy, filters, and selection.
329
333
  const claimed = discovery.activation.allowCandidateGeneration
330
- ? buildIntentClaimCandidates(declared, existingIds, minConfidence)
334
+ ? buildIntentClaimCandidates(declared, existingIds, minConfidence, subjectKeys)
331
335
  : {
332
336
  candidates: [],
333
337
  sourceOnlySignals: [],
@@ -1,3 +1,4 @@
1
+ import { type SubjectKeyRegistry } from "./requirement-claims.js";
1
2
  import type { BootstrapDeclaredContext, Candidate, SourceOnlySignal } from "./types.js";
2
3
  export type IntentClaimBuildResult = {
3
4
  readonly candidates: readonly Candidate[];
@@ -13,5 +14,5 @@ export type IntentClaimBuildResult = {
13
14
  * strict modeler cannot ground stays an explicit authoring follow-up instead
14
15
  * of becoming unverifiable knowledge.
15
16
  */
16
- export declare function buildIntentClaimCandidates(declared: BootstrapDeclaredContext, existingIds: ReadonlySet<string>, minConfidence: number): IntentClaimBuildResult;
17
+ export declare function buildIntentClaimCandidates(declared: BootstrapDeclaredContext, existingIds: ReadonlySet<string>, minConfidence: number, subjectKeys?: SubjectKeyRegistry): IntentClaimBuildResult;
17
18
  //# sourceMappingURL=intent-claims.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"intent-claims.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/intent-claims.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,wBAAwB,EAGxB,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAQpB,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACxD,QAAQ,CAAC,UAAU,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;IAClE,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC,CAAC;AA0NF;;;;;;;GAOG;AAEH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,wBAAwB,EAClC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,aAAa,EAAE,MAAM,GACpB,sBAAsB,CAmJxB"}
1
+ {"version":3,"file":"intent-claims.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/intent-claims.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,KAAK,kBAAkB,EAGxB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EACV,wBAAwB,EAGxB,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAQpB,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACxD,QAAQ,CAAC,UAAU,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;IAClE,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC,CAAC;AAyOF;;;;;;;GAOG;AAEH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,wBAAwB,EAClC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,aAAa,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,kBAAkB,GAC/B,sBAAsB,CAyKxB"}
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
2
2
  import { renderRequirementBody } from "../../entity-body-context.js";
3
3
  import { buildStrictWriteSet } from "../../utils/strict-modeling.js";
4
4
  import { confidenceBand, strictPlan, upsert } from "./candidate-helpers.js";
5
- import { claimFor } from "./requirement-claims.js";
5
+ import { claimFor, planSubjectKey, } from "./requirement-claims.js";
6
6
  /** How much a claim is trusted follows the authority the human assigned. */
7
7
  const AUTHORITY_CONFIDENCE = {
8
8
  authoritative: 0.9,
@@ -33,6 +33,7 @@ function digest(...parts) {
33
33
  function claimBody(source, claim) {
34
34
  return renderRequirementBody({
35
35
  statement: claim.statement,
36
+ context: claim.rationale,
36
37
  source: {
37
38
  excerpt: claim.excerpt,
38
39
  title: source.title,
@@ -49,6 +50,16 @@ function claimBody(source, claim) {
49
50
  function withClaimBody(step, body) {
50
51
  return { ...step, document: { body } };
51
52
  }
53
+ /** Carry the claim's stated rationale onto the requirement step. */
54
+ // implements REQ-bootstrap-subject-key-shape
55
+ function withRationale(step, rationale) {
56
+ if (!rationale)
57
+ return step;
58
+ const properties = step.properties !== null && typeof step.properties === "object"
59
+ ? step.properties
60
+ : {};
61
+ return { ...step, properties: { ...properties, rationale } };
62
+ }
52
63
  /**
53
64
  * An observation or open question from a declared source is evidence for the
54
65
  * human, not a requirement: it becomes a cited, non-blocking observation fact
@@ -188,7 +199,7 @@ function conflictCandidates(declared, sources, existingIds, minConfidence) {
188
199
  * of becoming unverifiable knowledge.
189
200
  */
190
201
  // implements REQ-kibi-bootstrap-knowledge-sources, REQ-bootstrap-claim-kinds-and-conflicts
191
- export function buildIntentClaimCandidates(declared, existingIds, minConfidence) {
202
+ export function buildIntentClaimCandidates(declared, existingIds, minConfidence, subjectKeys) {
192
203
  const sources = new Map((declared.knowledgeSources ?? []).map((source) => [source.id, source]));
193
204
  const candidates = [];
194
205
  const sourceOnlySignals = [];
@@ -249,11 +260,22 @@ export function buildIntentClaimCandidates(declared, existingIds, minConfidence)
249
260
  let writeSet = null;
250
261
  try {
251
262
  const modeled = claimFor(claim.statement, `knowledge-source:${source.id}`, confidence, provenance);
252
- writeSet = modeled
253
- ? buildStrictWriteSet({ claim: modeled, statement: claim.statement })
263
+ const planned = modeled
264
+ ? planSubjectKey(modeled.subjectKey, modeled.propertyKey, claim.component ?? source.component, subjectKeys, `${source.id}:${claim.reference}`)
254
265
  : null;
266
+ const subjectKey = planned?.resolution ?? null;
267
+ diagnostics.push(...(planned?.diagnostics ?? []));
268
+ writeSet =
269
+ modeled && subjectKey?.ok
270
+ ? buildStrictWriteSet({
271
+ claim: { ...modeled, subjectKey: subjectKey.subjectKey },
272
+ statement: claim.statement,
273
+ })
274
+ : null;
255
275
  if (!modeled)
256
276
  diagnostics.push(`Intent claim needs authoring at ${source.id}:${claim.reference}: ${claim.statement}`);
277
+ else if (subjectKey && !subjectKey.ok)
278
+ diagnostics.push(`Intent claim at ${source.id}:${claim.reference} was not planned as a requirement: its ${subjectKey.reason}. Declare component on the claim or on knowledge source ${source.id} and re-plan, or author it with kb_model: ${claim.statement}`);
257
279
  }
258
280
  catch (error) {
259
281
  diagnostics.push(`Intent claim extraction failed at ${source.id}:${claim.reference}: ${error instanceof Error ? error.message : String(error)}`);
@@ -276,7 +298,7 @@ export function buildIntentClaimCandidates(declared, existingIds, minConfidence)
276
298
  to,
277
299
  })),
278
300
  applyPlan: strictPlan(writeSet).map((step) => step.type === "req"
279
- ? withClaimBody(step, claimBody(source, claim))
301
+ ? withClaimBody(withRationale(step, claim.rationale), claimBody(source, claim))
280
302
  : step),
281
303
  });
282
304
  continue;
@@ -1,3 +1,4 @@
1
+ import { type SubjectKeyRegistry } from "./requirement-claims.js";
1
2
  import type { BootstrapEvidence, Candidate, SourceOnlySignal } from "./types.js";
2
3
  export type CandidateBuildResult = {
3
4
  readonly candidates: readonly Candidate[];
@@ -5,5 +6,11 @@ export type CandidateBuildResult = {
5
6
  readonly diagnostics: readonly string[];
6
7
  readonly suppressed: readonly Readonly<Record<string, unknown>>[];
7
8
  };
8
- export declare function markdownCandidates(item: BootstrapEvidence, existingIds: ReadonlySet<string>, minConfidence: number): CandidateBuildResult;
9
+ /**
10
+ * The component a repository document covers, from its file name or, for a
11
+ * generic name such as README.md, its directory (packages/recorder/README.md
12
+ * covers recorder). A root README names no component.
13
+ */
14
+ export declare function markdownComponentHint(relativePath: string): string | undefined;
15
+ export declare function markdownCandidates(item: BootstrapEvidence, existingIds: ReadonlySet<string>, minConfidence: number, subjectKeys?: SubjectKeyRegistry): CandidateBuildResult;
9
16
  //# sourceMappingURL=markdown-candidates.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"markdown-candidates.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/markdown-candidates.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,iBAAiB,EACjB,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACxD,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,UAAU,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;CACnE,CAAC;AAuJF,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,iBAAiB,EACvB,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,aAAa,EAAE,MAAM,GACpB,oBAAoB,CAkFtB"}
1
+ {"version":3,"file":"markdown-candidates.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/markdown-candidates.ts"],"names":[],"mappings":"AAaA,OAAO,EACL,KAAK,kBAAkB,EAIxB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EACV,iBAAiB,EACjB,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACxD,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,UAAU,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;CACnE,CAAC;AAyGF;;;;GAIG;AAEH,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,GACnB,MAAM,GAAG,SAAS,CAYpB;AA4FD,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,iBAAiB,EACvB,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,aAAa,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,kBAAkB,GAC/B,oBAAoB,CAoFtB"}
@@ -1,7 +1,7 @@
1
1
  import path from "node:path";
2
2
  import { buildStrictWriteSet } from "../../utils/strict-modeling.js";
3
3
  import { bootstrapProvenance, confidenceBand, provenanceBody, provenanceRequirementBody, slug, strictPlan, upsert, withDocumentBody, } from "./candidate-helpers.js";
4
- import { claimFor, normalizeClaimStatement } from "./requirement-claims.js";
4
+ import { claimFor, normalizeClaimStatement, planSubjectKey, } from "./requirement-claims.js";
5
5
  function headingSignals(heading, sourcePath, textRef, minConfidence) {
6
6
  const result = [];
7
7
  for (const [kind, pattern, confidence] of [
@@ -58,7 +58,51 @@ function genericHeadingCandidate(item, heading, line, existingIds, minConfidence
58
58
  ],
59
59
  };
60
60
  }
61
- function requirementCandidate(item, statement, line, heading, headingLine, existingIds, minConfidence) {
61
+ /** File and directory names that say what a document is, not what it covers. */
62
+ const GENERIC_DOCUMENT_NAMES = new Set([
63
+ "readme",
64
+ "index",
65
+ "overview",
66
+ "requirements",
67
+ "requirement",
68
+ "spec",
69
+ "specs",
70
+ "specification",
71
+ "notes",
72
+ "changelog",
73
+ "contributing",
74
+ "agents",
75
+ "claude",
76
+ "todo",
77
+ "docs",
78
+ "doc",
79
+ "documentation",
80
+ "src",
81
+ "packages",
82
+ "github",
83
+ ]);
84
+ /**
85
+ * The component a repository document covers, from its file name or, for a
86
+ * generic name such as README.md, its directory (packages/recorder/README.md
87
+ * covers recorder). A root README names no component.
88
+ */
89
+ // implements REQ-bootstrap-subject-key-shape
90
+ export function markdownComponentHint(relativePath) {
91
+ const segments = relativePath
92
+ .split(/[\\/]+/)
93
+ .filter((segment) => segment.length > 0);
94
+ const stem = (segments.pop() ?? "").replace(/\.[^.]*$/, "");
95
+ for (const name of [stem, ...segments.reverse()]) {
96
+ const normalized = name.toLowerCase().replace(/^[._-]+/, "");
97
+ if (!/^[a-z]/.test(normalized))
98
+ continue;
99
+ if (GENERIC_DOCUMENT_NAMES.has(normalized))
100
+ continue;
101
+ return normalized;
102
+ }
103
+ return undefined;
104
+ }
105
+ function requirementCandidate(item, statement, line, heading, headingLine, existingIds, minConfidence, subjectKeys, diagnostics) {
62
106
  const relativePath = item.relativePath ?? item.label;
63
107
  const base = /\bshall\b/i.test(statement)
64
108
  ? 0.86
@@ -75,9 +119,19 @@ function requirementCandidate(item, statement, line, heading, headingLine, exist
75
119
  const claim = claimFor(statement, relativePath, confidence, `${relativePath}#L${line}`);
76
120
  if (!claim)
77
121
  return null;
78
- const writeSet = buildStrictWriteSet({ claim, statement });
122
+ const planned = planSubjectKey(claim.subjectKey, claim.propertyKey, markdownComponentHint(relativePath), subjectKeys, `${relativePath}#L${line}`);
123
+ const subjectKey = planned.resolution;
124
+ // Reported by the caller as an extraction failure with this reason,
125
+ // instead of writing a subject key outside component.aspect[.sub].
126
+ if (!subjectKey.ok)
127
+ throw new Error(`${subjectKey.reason}; author it with kb_model and a component.aspect subjectKey`);
128
+ const writeSet = buildStrictWriteSet({
129
+ claim: { ...claim, subjectKey: subjectKey.subjectKey },
130
+ statement,
131
+ });
79
132
  if (!writeSet.isStrict)
80
133
  return null;
134
+ diagnostics.push(...planned.diagnostics);
81
135
  return {
82
136
  candidateId: `norm:${writeSet.req.id.toLowerCase()}`,
83
137
  entityType: "req",
@@ -101,7 +155,7 @@ function requirementCandidate(item, statement, line, heading, headingLine, exist
101
155
  };
102
156
  }
103
157
  // implements REQ-KIBI-BOOTSTRAP-PLAN
104
- export function markdownCandidates(item, existingIds, minConfidence) {
158
+ export function markdownCandidates(item, existingIds, minConfidence, subjectKeys) {
105
159
  const candidates = [];
106
160
  const sourceOnlySignals = [];
107
161
  const diagnostics = [];
@@ -130,7 +184,7 @@ export function markdownCandidates(item, existingIds, minConfidence) {
130
184
  if (!statement || !/\b(must|shall|should)\b/i.test(statement))
131
185
  continue;
132
186
  try {
133
- const candidate = requirementCandidate(item, statement, index + 1, heading, headingLine, existingIds, minConfidence);
187
+ const candidate = requirementCandidate(item, statement, index + 1, heading, headingLine, existingIds, minConfidence, subjectKeys, diagnostics);
134
188
  if (candidate) {
135
189
  if (!candidate.applyPlan.some((payload) => payload.type === "req" && existingIds.has(String(payload.id))))
136
190
  candidates.push(candidate);
@@ -1 +1 @@
1
- {"version":3,"file":"presentation.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/presentation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAGhB,gBAAgB,EAChB,wBAAwB,EAGxB,eAAe,EACf,SAAS,EACT,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAuGpB,wBAAgB,yBAAyB,CACvC,KAAK,CAAC,EAAE,gBAAgB,GACvB,wBAAwB,CAe1B;AAgBD;;;GAGG;AAEH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,GACjD,SAAS;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAYhE;AA0CD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACxD,QAAQ,CAAC,oBAAoB,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;IAC5E,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChD,wEAAwE;IACxE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACjD,GAAG,mBAAmB,CAmNtB"}
1
+ {"version":3,"file":"presentation.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/presentation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAGhB,gBAAgB,EAChB,wBAAwB,EAGxB,eAAe,EACf,SAAS,EACT,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AA6GpB,wBAAgB,yBAAyB,CACvC,KAAK,CAAC,EAAE,gBAAgB,GACvB,wBAAwB,CAe1B;AAgBD;;;GAGG;AAEH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,GACjD,SAAS;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAYhE;AA0CD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACxD,QAAQ,CAAC,oBAAoB,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;IAC5E,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChD,wEAAwE;IACxE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACjD,GAAG,mBAAmB,CAmNtB"}
@@ -22,6 +22,7 @@ function knowledgeSources(values) {
22
22
  seen.add(id);
23
23
  const connector = value.connector?.trim();
24
24
  const notes = value.notes?.trim();
25
+ const component = value.component?.trim();
25
26
  result.push({
26
27
  id,
27
28
  kind: value.kind,
@@ -30,6 +31,7 @@ function knowledgeSources(values) {
30
31
  authority: value.authority,
31
32
  ...(connector ? { connector } : {}),
32
33
  ...(notes ? { notes } : {}),
34
+ ...(component ? { component } : {}),
33
35
  });
34
36
  }
35
37
  return result;
@@ -51,11 +53,15 @@ function intentClaims(values) {
51
53
  continue;
52
54
  seen.add(key);
53
55
  const excerpt = value.excerpt?.trim();
56
+ const component = value.component?.trim();
57
+ const rationale = value.rationale?.trim().replace(/\s+/g, " ");
54
58
  result.push({
55
59
  statement,
56
60
  sourceId,
57
61
  reference,
58
62
  ...(excerpt ? { excerpt } : {}),
63
+ ...(component ? { component } : {}),
64
+ ...(rationale ? { rationale } : {}),
59
65
  // The default stays implicit so plans that declare no kinds keep
60
66
  // their established shape and hash.
61
67
  ...(kind !== "intent" ? { kind } : {}),
@@ -1,4 +1,64 @@
1
- import type { SemanticClaim } from "../../utils/strict-modeling.js";
1
+ import { type SemanticClaim } from "../../utils/strict-modeling.js";
2
2
  export declare function normalizeClaimStatement(statement: string): string;
3
3
  export declare function claimFor(statement: string, source: string, confidence: number, provenance: string): SemanticClaim | null;
4
+ export type SubjectKeyResolution = {
5
+ readonly ok: true;
6
+ readonly subjectKey: string;
7
+ /** The key before its aspect was shortened, when it was. */
8
+ readonly shortenedFrom?: string;
9
+ } | {
10
+ readonly ok: false;
11
+ readonly reason: string;
12
+ };
13
+ /** The longest aspect a bootstrap key keeps as derived. */
14
+ export declare const MAX_ASPECT_WORDS = 4;
15
+ export declare const MAX_ASPECT_CHARS = 40;
16
+ /**
17
+ * A short noun-phrase aspect for a long one, deterministically: the words
18
+ * before the first clause boundary (when, while, for, and, ...), without
19
+ * leading or trailing stop words; if that is still longer than four words or
20
+ * forty characters, its content words (no stop words or -ly adverbs); if
21
+ * those are still too long, the first content word and the last two, where a
22
+ * noun phrase keeps its head noun. An aspect that already fits is returned
23
+ * unchanged.
24
+ */
25
+ export declare function shortenSubjectAspect(aspect: string): string;
26
+ /**
27
+ * The bootstrap subject key in the component.aspect[.sub] shape that
28
+ * subject-key-shape checks. A subject that already has that shape is kept.
29
+ * Otherwise the component comes from the declared `component` (claim or
30
+ * knowledge source) and the aspect from the claim's subject; a one-word
31
+ * subject is itself the component and the constrained property becomes the
32
+ * aspect. An aspect longer than four words or forty characters is shortened
33
+ * to a noun phrase and the original key is returned in `shortenedFrom`. When
34
+ * no component can be named the claim is not resolved, so the caller reports
35
+ * it instead of writing a malformed key.
36
+ */
37
+ export declare function resolveBootstrapSubjectKey(subject: string, propertyKey: string, component?: string): SubjectKeyResolution;
38
+ /**
39
+ * Keeps the subject keys of one bootstrap plan distinct. Claims about the
40
+ * same subject (the same full key) share a key; when shortening collapses two
41
+ * different subjects onto one key, the later one gets a third segment from
42
+ * its own wording (or a short digest) instead of colliding.
43
+ */
44
+ export declare class SubjectKeyRegistry {
45
+ private readonly owners;
46
+ private readonly assigned;
47
+ /** The plan-wide key for a resolution, and the key it collided with, if any. */
48
+ assign(resolution: {
49
+ readonly subjectKey: string;
50
+ readonly shortenedFrom?: string;
51
+ }): {
52
+ readonly subjectKey: string;
53
+ readonly collidedWith?: string;
54
+ };
55
+ }
56
+ /**
57
+ * Resolve a claim's subject key for a plan and describe any renaming as a
58
+ * plan diagnostic, so the operator can pick a better name before applying.
59
+ */
60
+ export declare function planSubjectKey(subject: string, propertyKey: string, component: string | undefined, registry: SubjectKeyRegistry | undefined, location: string): {
61
+ readonly resolution: SubjectKeyResolution;
62
+ readonly diagnostics: string[];
63
+ };
4
64
  //# sourceMappingURL=requirement-claims.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"requirement-claims.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/requirement-claims.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAGpE,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAKjE;AAED,wBAAgB,QAAQ,CACtB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,aAAa,GAAG,IAAI,CA0DtB"}
1
+ {"version":3,"file":"requirement-claims.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/requirement-claims.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,aAAa,EAGnB,MAAM,gCAAgC,CAAC;AAGxC,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAKjE;AAED,wBAAgB,QAAQ,CACtB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,aAAa,GAAG,IAAI,CA0DtB;AAED,MAAM,MAAM,oBAAoB,GAC5B;IACE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,4DAA4D;IAC5D,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC,GACD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAWpD,2DAA2D;AAC3D,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAClC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAsGnC;;;;;;;;GAQG;AAEH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA4B3D;AAmBD;;;;;;;;;;GAUG;AAEH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,oBAAoB,CA2BtB;AAED;;;;;GAKG;AAEH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IAEtD,gFAAgF;IAChF,MAAM,CAAC,UAAU,EAAE;QACjB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;KACjC,GAAG;QAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE;CAyBpE;AAMD;;;GAGG;AAEH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,QAAQ,EAAE,kBAAkB,GAAG,SAAS,EACxC,QAAQ,EAAE,MAAM,GACf;IACD,QAAQ,CAAC,UAAU,EAAE,oBAAoB,CAAC;IAC1C,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC;CAChC,CAyBA"}