kibi-cli 2.11.0 → 2.12.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 (39) hide show
  1. package/dist/operations/bootstrap/generate.d.ts.map +1 -1
  2. package/dist/operations/bootstrap/generate.js +5 -2
  3. package/dist/operations/bootstrap/requirement-claims.d.ts +15 -0
  4. package/dist/operations/bootstrap/requirement-claims.d.ts.map +1 -1
  5. package/dist/operations/bootstrap/requirement-claims.js +100 -1
  6. package/dist/operations/modeling/predicate-applyplan.d.ts +6 -0
  7. package/dist/operations/modeling/predicate-applyplan.d.ts.map +1 -1
  8. package/dist/operations/modeling/predicate-applyplan.js +29 -18
  9. package/dist/operations/modeling/predicate-binding-hints.d.ts +1 -1
  10. package/dist/operations/modeling/predicate-binding-hints.d.ts.map +1 -1
  11. package/dist/operations/modeling/predicate-binding-hints.js +9 -3
  12. package/dist/operations/modeling/predicate-bindings.d.ts.map +1 -1
  13. package/dist/operations/modeling/predicate-bindings.js +16 -1
  14. package/dist/operations/modeling/predicate-catalog-1.d.ts.map +1 -1
  15. package/dist/operations/modeling/predicate-catalog-1.js +3 -0
  16. package/dist/operations/modeling/predicate-catalog-2.d.ts.map +1 -1
  17. package/dist/operations/modeling/predicate-catalog-2.js +3 -0
  18. package/dist/operations/modeling/predicate-catalog-3.d.ts.map +1 -1
  19. package/dist/operations/modeling/predicate-catalog-3.js +7 -0
  20. package/dist/operations/modeling/predicate-catalog-4.d.ts.map +1 -1
  21. package/dist/operations/modeling/predicate-catalog-4.js +2 -0
  22. package/dist/operations/modeling/predicate-closed-vocabularies.d.ts +104 -0
  23. package/dist/operations/modeling/predicate-closed-vocabularies.d.ts.map +1 -0
  24. package/dist/operations/modeling/predicate-closed-vocabularies.js +104 -0
  25. package/dist/operations/modeling/predicate-types.d.ts +1 -1
  26. package/dist/operations/modeling/predicate-types.d.ts.map +1 -1
  27. package/dist/operations/modeling/predicate-utils.d.ts +11 -1
  28. package/dist/operations/modeling/predicate-utils.d.ts.map +1 -1
  29. package/dist/operations/modeling/predicate-utils.js +19 -3
  30. package/dist/operations/modeling/suggest-predicates.d.ts.map +1 -1
  31. package/dist/operations/modeling/suggest-predicates.js +39 -3
  32. package/dist/public/skills/kibi-bootstrap/SKILL.md +2 -2
  33. package/dist/public/skills/kibi-usage/SKILL.md +8 -3
  34. package/dist/utils/strict-modeling.d.ts +1 -0
  35. package/dist/utils/strict-modeling.d.ts.map +1 -1
  36. package/dist/utils/strict-modeling.js +1 -1
  37. package/package.json +2 -2
  38. package/src/public/skills/kibi-bootstrap/SKILL.md +2 -2
  39. package/src/public/skills/kibi-usage/SKILL.md +8 -3
@@ -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;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"}
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,CAiH9B"}
@@ -8,7 +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
+ import { SubjectKeyRegistry, shareSubjectFacts } from "./requirement-claims.js";
12
12
  import { validateBootstrapPayload } from "./validation.js";
13
13
  export function filterSourceOnlySignals(signals, entityTypes) {
14
14
  return entityTypes && entityTypes.length > 0
@@ -340,6 +340,8 @@ export async function executePlanBootstrap(args, context) {
340
340
  };
341
341
  const filteredSignals = filterSourceOnlySignals([...built.sourceOnlySignals, ...claimed.sourceOnlySignals], args.entityTypes);
342
342
  const selected = selectBootstrapCandidates([...built.candidates, ...claimed.candidates].filter((candidate) => candidate.confidence >= minConfidence), existingIds, args.entityTypes, maxCandidates);
343
+ // Claims about the same subject share one subject fact.
344
+ const shared = shareSubjectFacts(selected.candidates);
343
345
  const ignored = discovery.ignoredSources.map((sourcePath) => ({
344
346
  candidateId: "",
345
347
  reason: "ignored_source",
@@ -355,7 +357,7 @@ export async function executePlanBootstrap(args, context) {
355
357
  ...(args.bootstrapContext
356
358
  ? { bootstrapContext: args.bootstrapContext }
357
359
  : {}),
358
- candidates: selected.candidates,
360
+ candidates: shared.candidates,
359
361
  sourceOnlySignals: [
360
362
  ...filteredSignals,
361
363
  ...filterSourceOnlySignals(selected.sourceOnlySignals, args.entityTypes),
@@ -377,6 +379,7 @@ export async function executePlanBootstrap(args, context) {
377
379
  ...claimed.diagnostics,
378
380
  ...built.diagnostics,
379
381
  ...selected.diagnostics,
382
+ ...shared.diagnostics,
380
383
  ],
381
384
  });
382
385
  }
@@ -1,4 +1,5 @@
1
1
  import { type SemanticClaim } from "../../utils/strict-modeling.js";
2
+ import type { Candidate } from "./types.js";
2
3
  export declare function normalizeClaimStatement(statement: string): string;
3
4
  export declare function claimFor(statement: string, source: string, confidence: number, provenance: string): SemanticClaim | null;
4
5
  export type SubjectKeyResolution = {
@@ -61,4 +62,18 @@ export declare function planSubjectKey(subject: string, propertyKey: string, com
61
62
  readonly resolution: SubjectKeyResolution;
62
63
  readonly diagnostics: string[];
63
64
  };
65
+ /**
66
+ * One subject fact per subject_key in a bootstrap plan. The registry keeps
67
+ * different subjects on different keys, so claims that share a key name the
68
+ * same subject: the first selected claim's subject fact is kept, every later
69
+ * requirement links to it through constrains instead of minting another
70
+ * subject fact (which subject-key-identity would report), and the later
71
+ * sources' provenance is added to the kept fact's tags and body. Each shared
72
+ * key is reported as a subject-key-shared diagnostic. The result depends only
73
+ * on the candidate order, so the plan hash stays deterministic.
74
+ */
75
+ export declare function shareSubjectFacts(candidates: readonly Candidate[]): {
76
+ readonly candidates: Candidate[];
77
+ readonly diagnostics: string[];
78
+ };
64
79
  //# 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":"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"}
1
+ {"version":3,"file":"requirement-claims.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/requirement-claims.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,aAAa,EAInB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5C,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;AAuCD;;;;;;;;;GASG;AAEH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,GAAG;IACnE,QAAQ,CAAC,UAAU,EAAE,SAAS,EAAE,CAAC;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC;CAChC,CAwEA"}
@@ -1,5 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
- import { isConventionalSubjectKey, normalizeSubjectKey, } from "../../utils/strict-modeling.js";
2
+ import { isConventionalSubjectKey, normalizeSourceKey, normalizeSubjectKey, } from "../../utils/strict-modeling.js";
3
3
  // implements REQ-KIBI-BOOTSTRAP-PLAN
4
4
  export function normalizeClaimStatement(statement) {
5
5
  return statement
@@ -321,3 +321,102 @@ export function planSubjectKey(subject, propertyKey, component, registry, locati
321
321
  diagnostics,
322
322
  };
323
323
  }
324
+ function stepProperties(step) {
325
+ return step.properties !== null && typeof step.properties === "object"
326
+ ? step.properties
327
+ : {};
328
+ }
329
+ function subjectStepKey(step) {
330
+ const properties = stepProperties(step);
331
+ return step.type === "fact" &&
332
+ properties.fact_kind === "subject" &&
333
+ typeof properties.subject_key === "string" &&
334
+ typeof step.id === "string"
335
+ ? properties.subject_key
336
+ : null;
337
+ }
338
+ function retarget(relationships, renamed) {
339
+ return relationships.map((relationship) => {
340
+ const to = renamed.get(relationship.to);
341
+ return to === undefined ? relationship : { ...relationship, to };
342
+ });
343
+ }
344
+ function retargetStep(step, renamed) {
345
+ if (!Array.isArray(step.relationships))
346
+ return step;
347
+ const relationships = step.relationships;
348
+ return { ...step, relationships: retarget(relationships, renamed) };
349
+ }
350
+ /**
351
+ * One subject fact per subject_key in a bootstrap plan. The registry keeps
352
+ * different subjects on different keys, so claims that share a key name the
353
+ * same subject: the first selected claim's subject fact is kept, every later
354
+ * requirement links to it through constrains instead of minting another
355
+ * subject fact (which subject-key-identity would report), and the later
356
+ * sources' provenance is added to the kept fact's tags and body. Each shared
357
+ * key is reported as a subject-key-shared diagnostic. The result depends only
358
+ * on the candidate order, so the plan hash stays deterministic.
359
+ */
360
+ // implements REQ-bootstrap-subject-fact-shared
361
+ export function shareSubjectFacts(candidates) {
362
+ const owners = new Map();
363
+ const renamed = new Map();
364
+ candidates.forEach((candidate, candidateIndex) => {
365
+ for (const step of candidate.applyPlan) {
366
+ const key = subjectStepKey(step);
367
+ if (key === null)
368
+ continue;
369
+ const factId = String(step.id);
370
+ const source = String(stepProperties(step).text_ref ?? candidate.sourcePath);
371
+ const owner = owners.get(key);
372
+ if (owner === undefined) {
373
+ owners.set(key, { factId, candidateIndex, sources: [source] });
374
+ continue;
375
+ }
376
+ if (owner.factId === factId)
377
+ continue;
378
+ renamed.set(factId, owner.factId);
379
+ if (!owner.sources.includes(source))
380
+ owner.sources.push(source);
381
+ }
382
+ });
383
+ if (renamed.size === 0)
384
+ return { candidates: [...candidates], diagnostics: [] };
385
+ const shared = [...owners.entries()].filter(([, owner]) => owner.sources.length > 1);
386
+ const sharedFacts = new Map(shared.map(([key, owner]) => [owner.factId, { key, owner }]));
387
+ const result = candidates.map((candidate) => ({
388
+ ...candidate,
389
+ relationships: retarget(candidate.relationships, renamed),
390
+ applyPlan: candidate.applyPlan
391
+ .filter((step) => !renamed.has(String(step.id)))
392
+ .map((step) => {
393
+ const sharing = sharedFacts.get(String(step.id));
394
+ const retargeted = retargetStep(step, renamed);
395
+ if (sharing === undefined || subjectStepKey(step) === null)
396
+ return retargeted;
397
+ const properties = stepProperties(step);
398
+ const tags = Array.isArray(properties.tags)
399
+ ? properties.tags.map(String)
400
+ : [];
401
+ return {
402
+ ...retargeted,
403
+ properties: {
404
+ ...properties,
405
+ tags: [
406
+ ...new Set([
407
+ ...tags,
408
+ ...sharing.owner.sources.map((source) => `provenance:${normalizeSourceKey(source)}`),
409
+ ]),
410
+ ],
411
+ },
412
+ document: {
413
+ body: `Subject ${sharing.key}, shared by the requirements bootstrap planned from ${sharing.owner.sources.join(", ")}. Each of them links to this fact through constrains.\n`,
414
+ },
415
+ };
416
+ }),
417
+ }));
418
+ return {
419
+ candidates: result,
420
+ diagnostics: shared.map(([key, owner]) => `subject-key-shared: claims at ${owner.sources.join(", ")} name the same subject ${key}, so the plan writes one subject fact ${owner.factId} and links every requirement to it through constrains.`),
421
+ };
422
+ }
@@ -5,6 +5,12 @@ export declare function buildSuggestion(schema: PredicateSchemaCandidate, text:
5
5
  applicabilityScore?: number;
6
6
  scoreComponents?: PredicateScoreComponents;
7
7
  explicitSubject?: boolean;
8
+ /**
9
+ * The subject_key of the subject fact the requirement constrains. It
10
+ * binds the schema's `subject` argument (provenance `requirement`) unless
11
+ * the caller bound that argument or passed subjectHint.
12
+ */
13
+ requirementSubject?: string;
8
14
  }): PredicateSuggestion;
9
15
  export declare function buildPredicateApplyPlan(suggestion: PredicateSuggestion, args: SuggestPredicatesArgs): Array<Record<string, unknown>>;
10
16
  export declare function buildRelationshipPlan(factId: string | undefined, requirementId: string | undefined, claimText?: string, existingLogicClaims?: readonly string[]): Record<string, unknown> | null;
@@ -1 +1 @@
1
- {"version":3,"file":"predicate-applyplan.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-applyplan.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAEV,wBAAwB,EACxB,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,EAC1B,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAQ9B,wBAAgB,eAAe,CAC7B,MAAM,EAAE,wBAAwB,EAChC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,gBAAgB,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM,EACvD,YAAY,CAAC,EAAE,QAAQ,GAAG,MAAM,EAChC,WAAW,CAAC,EAAE;IACZ,WAAW,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;IACtC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,wBAAwB,CAAC;IAC3C,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,GACA,mBAAmB,CAyGrB;AAGD,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,mBAAmB,EAC/B,IAAI,EAAE,qBAAqB,GAC1B,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAqChC;AAGD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,SAAS,CAAC,EAAE,MAAM,EAClB,mBAAmB,GAAE,SAAS,MAAM,EAAO,GAC1C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAuBhC;AAoBD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,qBAAqB,GAC1B,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAwBhC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,0BAA0B,CAoE5B"}
1
+ {"version":3,"file":"predicate-applyplan.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-applyplan.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAEV,wBAAwB,EACxB,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,EAC1B,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAQ9B,wBAAgB,eAAe,CAC7B,MAAM,EAAE,wBAAwB,EAChC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,gBAAgB,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM,EACvD,YAAY,CAAC,EAAE,QAAQ,GAAG,MAAM,EAChC,WAAW,CAAC,EAAE;IACZ,WAAW,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;IACtC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,wBAAwB,CAAC;IAC3C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,GACA,mBAAmB,CAsHrB;AAGD,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,mBAAmB,EAC/B,IAAI,EAAE,qBAAqB,GAC1B,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAqChC;AAGD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,SAAS,CAAC,EAAE,MAAM,EAClB,mBAAmB,GAAE,SAAS,MAAM,EAAO,GAC1C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAuBhC;AAoBD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,qBAAqB,GAC1B,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAwBhC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,0BAA0B,CAoE5B"}
@@ -9,8 +9,17 @@ import { applyArgumentRewrites, predicateArgumentConformance, } from "./predicat
9
9
  export function buildSuggestion(schema, text, subject, score, argumentBindings = {}, polarityHint, diagnostics) {
10
10
  const inferredArgs = inferArgs(schema, text, subject);
11
11
  const canonicalLauncherArgs = exactLauncherPredicateArgs(schema.predicate_name, text);
12
+ const hasExactBinding = (name) => typeof argumentBindings[name] === "string" &&
13
+ argumentBindings[name].trim().length > 0;
14
+ const requirementSubjectArgument = diagnostics?.requirementSubject &&
15
+ diagnostics.explicitSubject !== true &&
16
+ !hasExactBinding("subject")
17
+ ? schema.argument_names.indexOf("subject")
18
+ : -1;
12
19
  const boundArgs = schema.argument_names.map((name, index) => {
13
20
  const exactBinding = argumentBindings[name];
21
+ if (index === requirementSubjectArgument)
22
+ return diagnostics?.requirementSubject ?? "unknown";
14
23
  return typeof exactBinding === "string" && exactBinding.trim().length > 0
15
24
  ? exactBinding.trim()
16
25
  : (inferredArgs[index] ?? "unknown");
@@ -27,24 +36,26 @@ export function buildSuggestion(schema, text, subject, score, argumentBindings =
27
36
  const undeclaredArguments = new Set(conformance.undeclared.map((value) => value.argumentName));
28
37
  const bindingProvenanceByArgument = Object.fromEntries(schema.argument_names.map((name, index) => [
29
38
  name,
30
- classifyBinding(predicateArgs[index] ?? "unknown", text, (typeof argumentBindings[name] === "string" &&
31
- argumentBindings[name].trim().length > 0) ||
32
- (diagnostics?.explicitSubject === true && index === 0), canonicalLauncherArgs?.[index] === predicateArgs[index] &&
33
- !(index === 0 &&
34
- predicateArgs[index] === "launcher" &&
35
- diagnostics?.explicitSubject !== true &&
36
- typeof argumentBindings[name] !== "string"),
37
- // A subject named through subjectHint is the agent's reviewed
38
- // subject, even when the schema names its first argument after it.
39
- index === 0 &&
40
- diagnostics?.explicitSubject === true &&
41
- typeof argumentBindings[name] !== "string"
42
- ? { constants: schema.argument_constants?.[name] }
43
- : {
44
- argumentName: name,
45
- argumentNames: schema.argument_names,
46
- constants: schema.argument_constants?.[name],
47
- }),
39
+ index === requirementSubjectArgument && !undeclaredArguments.has(name)
40
+ ? "requirement"
41
+ : classifyBinding(predicateArgs[index] ?? "unknown", text, (typeof argumentBindings[name] === "string" &&
42
+ argumentBindings[name].trim().length > 0) ||
43
+ (diagnostics?.explicitSubject === true && index === 0), canonicalLauncherArgs?.[index] === predicateArgs[index] &&
44
+ !(index === 0 &&
45
+ predicateArgs[index] === "launcher" &&
46
+ diagnostics?.explicitSubject !== true &&
47
+ typeof argumentBindings[name] !== "string"),
48
+ // A subject named through subjectHint is the agent's reviewed
49
+ // subject, even when the schema names its first argument after it.
50
+ index === 0 &&
51
+ diagnostics?.explicitSubject === true &&
52
+ typeof argumentBindings[name] !== "string"
53
+ ? { constants: schema.argument_constants?.[name] }
54
+ : {
55
+ argumentName: name,
56
+ argumentNames: schema.argument_names,
57
+ constants: schema.argument_constants?.[name],
58
+ }),
48
59
  ]));
49
60
  const bindingProvenance = aggregateBindingProvenance(Object.values(bindingProvenanceByArgument));
50
61
  const unboundArguments = schema.argument_names.filter((name) => undeclaredArguments.has(name) ||
@@ -5,7 +5,7 @@ import type { BindingHint, PredicateSuggestion } from "./predicate-types.js";
5
5
  * current value was not accepted, so the agent binds from the claim text
6
6
  * instead of guessing.
7
7
  */
8
- export declare function buildBindingHints(candidate: PredicateSuggestion, text: string): BindingHint[];
8
+ export declare function buildBindingHints(candidate: PredicateSuggestion, text: string, requirementSubjects?: readonly string[]): BindingHint[];
9
9
  /** One line per hint for the text summary: `name (type, e.g. a, b)`. */
10
10
  export declare function describeBindingHints(hints: readonly BindingHint[]): string;
11
11
  //# sourceMappingURL=predicate-binding-hints.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"predicate-binding-hints.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-binding-hints.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAoD7E;;;;;GAKG;AAEH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,mBAAmB,EAC9B,IAAI,EAAE,MAAM,GACX,WAAW,EAAE,CA2Bf;AAED,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAW1E"}
1
+ {"version":3,"file":"predicate-binding-hints.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-binding-hints.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAoD7E;;;;;GAKG;AAEH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,mBAAmB,EAC9B,IAAI,EAAE,MAAM,EACZ,mBAAmB,GAAE,SAAS,MAAM,EAAO,GAC1C,WAAW,EAAE,CAiCf;AAED,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAW1E"}
@@ -50,8 +50,8 @@ function unboundReason(candidate, name, value, text) {
50
50
  * current value was not accepted, so the agent binds from the claim text
51
51
  * instead of guessing.
52
52
  */
53
- // implements REQ-model-predicates-binding-placeholders
54
- export function buildBindingHints(candidate, text) {
53
+ // implements REQ-model-predicates-binding-placeholders, REQ-model-predicates-requirement-subject
54
+ export function buildBindingHints(candidate, text, requirementSubjects = []) {
55
55
  const schema = candidate.schema;
56
56
  const parsedExamples = schema.examples.map(exampleArguments);
57
57
  return candidate.unbound_arguments.map((name) => {
@@ -60,7 +60,13 @@ export function buildBindingHints(candidate, text) {
60
60
  const exampleValues = parsedExamples
61
61
  .map((args) => args[position])
62
62
  .filter((value) => typeof value === "string");
63
- const examples = Array.from(new Set([...(constants ?? []), ...exampleValues])).slice(0, MAX_EXAMPLES);
63
+ // The subject keys the requirement already constrains come first, so
64
+ // the predicate and the subject fact use one identifier for the subject.
65
+ const examples = Array.from(new Set([
66
+ ...(name === "subject" ? requirementSubjects : []),
67
+ ...(constants ?? []),
68
+ ...exampleValues,
69
+ ])).slice(0, MAX_EXAMPLES);
64
70
  const current = candidate.predicate_args[position] ?? "";
65
71
  const description = schema.argument_descriptions?.[position];
66
72
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"predicate-bindings.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-bindings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAkG9D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAW3D;AAgED,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,sDAAsD;AACtD,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,sEAAsE;IACtE,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC1C;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B,CAAC,CAAC;AAiBH;;;;GAIG;AAEH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,cAAmB,GAC3B,MAAM,GAAG,IAAI,CAYf;AAGD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EACjB,SAAS,UAAQ,EACjB,OAAO,GAAE,cAAmB,GAC3B,iBAAiB,CAmBnB;AASD,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,SAAS,iBAAiB,EAAE,GACnC,iBAAiB,CAQnB;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAErE"}
1
+ {"version":3,"file":"predicate-bindings.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-bindings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAgH9D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAW3D;AAgED,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,sDAAsD;AACtD,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,sEAAsE;IACtE,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC1C;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B,CAAC,CAAC;AAiBH;;;;GAIG;AAEH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,cAAmB,GAC3B,MAAM,GAAG,IAAI,CAYf;AAGD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EACjB,SAAS,UAAQ,EACjB,OAAO,GAAE,cAAmB,GAC3B,iBAAiB,CAmBnB;AAUD,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,SAAS,iBAAiB,EAAE,GACnC,iBAAiB,CAQnB;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAIrE"}
@@ -67,6 +67,20 @@ const DERIVED_CUE_ALIASES = {
67
67
  ],
68
68
  actionable_error: ["actionable", "clear error", "report", "error"],
69
69
  exception: ["exception", "except", "package-manager", "package manager"],
70
+ // Wording that names a closed-vocabulary constant without spelling it.
71
+ deny: [
72
+ "denied",
73
+ "must not",
74
+ "must never",
75
+ "forbidden",
76
+ "prohibited",
77
+ "not allowed",
78
+ "not be allowed",
79
+ ],
80
+ allow: ["is allowed", "are allowed", "permitted"],
81
+ on_demand: ["on demand", "on request"],
82
+ timeout: ["times out", "timed out", "time out"],
83
+ submit: ["submission", "submits", "submitted"],
70
84
  };
71
85
  function textContainsValue(text, value) {
72
86
  const lower = text.toLowerCase();
@@ -218,6 +232,7 @@ export function classifyBinding(value, text, explicit, canonical = false, contex
218
232
  }
219
233
  const PROVENANCE_ORDER = [
220
234
  "explicit",
235
+ "requirement",
221
236
  "extracted",
222
237
  "inferred",
223
238
  "placeholder",
@@ -228,5 +243,5 @@ export function aggregateBindingProvenance(values) {
228
243
  : worst, "explicit");
229
244
  }
230
245
  export function bindingCanBeApplied(value) {
231
- return value === "explicit" || value === "extracted";
246
+ return (value === "explicit" || value === "requirement" || value === "extracted");
232
247
  }
@@ -1 +1 @@
1
- {"version":3,"file":"predicate-catalog-1.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-catalog-1.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAGrE,eAAO,MAAM,mBAAmB,EAAE,wBAAwB,EAmNzD,CAAC"}
1
+ {"version":3,"file":"predicate-catalog-1.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-catalog-1.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAGrE,eAAO,MAAM,mBAAmB,EAAE,wBAAwB,EAqNzD,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { LIFECYCLE_ACTION_VOCABULARY, TRIGGER_VOCABULARY, closedArguments, } from "./predicate-closed-vocabularies.js";
1
2
  // implements REQ-mcp-suggest-predicates
2
3
  export const PREDICATE_CATALOG_1 = [
3
4
  {
@@ -18,6 +19,7 @@ export const PREDICATE_CATALOG_1 = [
18
19
  description: "A subject transitions between states because of a trigger.",
19
20
  argument_names: ["subject", "from_state", "to_state", "trigger"],
20
21
  argument_types: ["entity", "state", "state", "trigger"],
22
+ ...closedArguments({ trigger: TRIGGER_VOCABULARY }),
21
23
  keywords: [
22
24
  "transition",
23
25
  "enter",
@@ -193,6 +195,7 @@ export const PREDICATE_CATALOG_1 = [
193
195
  description: "An entity must be archived, deleted, expired, or lifecycle-transitioned after a duration.",
194
196
  argument_names: ["subject", "action", "duration", "unit"],
195
197
  argument_types: ["entity", "action", "number", "unit"],
198
+ ...closedArguments({ action: LIFECYCLE_ACTION_VOCABULARY }),
196
199
  keywords: ["archive", "archived", "delete", "deleted", "expire", "after"],
197
200
  examples: ["lifecycle_rule(expired_sessions, archived, 30, days)"],
198
201
  tags: ["lifecycle", "retention"],
@@ -1 +1 @@
1
- {"version":3,"file":"predicate-catalog-2.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-catalog-2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAGrE,eAAO,MAAM,mBAAmB,EAAE,wBAAwB,EAkOzD,CAAC"}
1
+ {"version":3,"file":"predicate-catalog-2.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-catalog-2.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAGrE,eAAO,MAAM,mBAAmB,EAAE,wBAAwB,EAoOzD,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { CODING_STANDARD_ACTION_VOCABULARY, ENVIRONMENT_DECISION_VOCABULARY, closedArguments, } from "./predicate-closed-vocabularies.js";
1
2
  // implements REQ-mcp-suggest-predicates
2
3
  export const PREDICATE_CATALOG_2 = [
3
4
  {
@@ -66,6 +67,7 @@ export const PREDICATE_CATALOG_2 = [
66
67
  description: "A named action is allowed or forbidden in a deployment environment.",
67
68
  argument_names: ["action", "decision", "environment"],
68
69
  argument_types: ["action", "decision", "environment"],
70
+ ...closedArguments({ decision: ENVIRONMENT_DECISION_VOCABULARY }),
69
71
  keywords: ["production", "staging", "forbidden", "destructive"],
70
72
  examples: [
71
73
  "environment_safety_rule(destructive_operations, forbidden, production)",
@@ -90,6 +92,7 @@ export const PREDICATE_CATALOG_2 = [
90
92
  description: "Developer-facing code must use or avoid a framework API, pattern, or documentation practice.",
91
93
  argument_names: ["subject", "action", "target"],
92
94
  argument_types: ["entity", "action", "api"],
95
+ ...closedArguments({ action: CODING_STANDARD_ACTION_VOCABULARY }),
93
96
  keywords: ["computed", "signals", "must use", "must not use"],
94
97
  examples: ["coding_standard_rule(derived_state, use, computed_signals)"],
95
98
  tags: ["coding-standard", "agent-guidance"],
@@ -1 +1 @@
1
- {"version":3,"file":"predicate-catalog-3.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-catalog-3.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAGrE,eAAO,MAAM,mBAAmB,EAAE,wBAAwB,EA0NzD,CAAC"}
1
+ {"version":3,"file":"predicate-catalog-3.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-catalog-3.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAGrE,eAAO,MAAM,mBAAmB,EAAE,wBAAwB,EAgOzD,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { DECISION_VOCABULARY, OPERATOR_VOCABULARY, REFRESH_POLICY_VOCABULARY, RETENTION_UNIT_VOCABULARY, TRIGGER_VOCABULARY, closedArguments, } from "./predicate-closed-vocabularies.js";
1
2
  // implements REQ-mcp-suggest-predicates
2
3
  export const PREDICATE_CATALOG_3 = [
3
4
  {
@@ -20,6 +21,7 @@ export const PREDICATE_CATALOG_3 = [
20
21
  description: "A subject refreshes a target automatically or by a named policy.",
21
22
  argument_names: ["subject", "target", "policy"],
22
23
  argument_types: ["entity", "target", "policy"],
24
+ ...closedArguments({ policy: REFRESH_POLICY_VOCABULARY }),
23
25
  keywords: ["automatically refresh", "manual page reload", "refresh"],
24
26
  examples: ["refresh_policy_rule(dashboard, processing_videos, automatic)"],
25
27
  tags: ["refresh", "ui"],
@@ -31,6 +33,7 @@ export const PREDICATE_CATALOG_3 = [
31
33
  description: "A scoped actor is allowed or denied an action because of assignment, ownership, or membership.",
32
34
  argument_names: ["actor_scope", "action", "decision"],
33
35
  argument_types: ["actor_scope", "action", "decision"],
36
+ ...closedArguments({ decision: DECISION_VOCABULARY }),
34
37
  keywords: ["unassigned", "assigned", "denied", "scoped"],
35
38
  examples: [
36
39
  "scoped_authorization_rule(unassigned_instructors, signed_url_generation, deny)",
@@ -131,6 +134,7 @@ export const PREDICATE_CATALOG_3 = [
131
134
  description: "A trigger commits, saves, or persists a subject within a scope.",
132
135
  argument_names: ["subject", "trigger", "scope"],
133
136
  argument_types: ["entity", "trigger", "scope"],
137
+ ...closedArguments({ trigger: TRIGGER_VOCABULARY }),
134
138
  keywords: [
135
139
  "save",
136
140
  "saves",
@@ -153,6 +157,7 @@ export const PREDICATE_CATALOG_3 = [
153
157
  description: "A trigger discards or cancels changes for a subject within a scope.",
154
158
  argument_names: ["subject", "trigger", "scope"],
155
159
  argument_types: ["entity", "trigger", "scope"],
160
+ ...closedArguments({ trigger: TRIGGER_VOCABULARY }),
156
161
  keywords: ["discard", "cancel", "escape", "revert", "without save"],
157
162
  examples: ["discard_action(editor.annotation, escape, active_annotation)"],
158
163
  tags: ["persistence", "workflow"],
@@ -175,6 +180,7 @@ export const PREDICATE_CATALOG_3 = [
175
180
  description: "A subject is retained for a bounded duration.",
176
181
  argument_names: ["subject", "duration", "unit"],
177
182
  argument_types: ["entity", "number", "unit"],
183
+ ...closedArguments({ unit: RETENTION_UNIT_VOCABULARY }),
178
184
  keywords: ["retain", "retained", "retention", "days", "months", "years"],
179
185
  examples: ["retention_policy(customer.data, 7, years)"],
180
186
  tags: ["data", "policy"],
@@ -186,6 +192,7 @@ export const PREDICATE_CATALOG_3 = [
186
192
  description: "A subject constrains a resource by operator, threshold, and unit.",
187
193
  argument_names: ["subject", "resource", "operator", "threshold", "unit"],
188
194
  argument_types: ["entity", "resource", "operator", "number", "unit"],
195
+ ...closedArguments({ operator: OPERATOR_VOCABULARY }),
189
196
  keywords: [
190
197
  "limit",
191
198
  "maximum",
@@ -1 +1 @@
1
- {"version":3,"file":"predicate-catalog-4.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-catalog-4.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAGrE,eAAO,MAAM,mBAAmB,EAAE,wBAAwB,EAoTzD,CAAC"}
1
+ {"version":3,"file":"predicate-catalog-4.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-catalog-4.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAGrE,eAAO,MAAM,mBAAmB,EAAE,wBAAwB,EAqTzD,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { DECISION_VOCABULARY, closedArguments, } from "./predicate-closed-vocabularies.js";
1
2
  // implements REQ-mcp-suggest-predicates
2
3
  export const PREDICATE_CATALOG_4 = [
3
4
  {
@@ -201,6 +202,7 @@ export const PREDICATE_CATALOG_4 = [
201
202
  description: "An actor is allowed or denied an action against a resource.",
202
203
  argument_names: ["actor", "action", "resource", "decision"],
203
204
  argument_types: ["actor", "action", "resource", "decision"],
205
+ ...closedArguments({ decision: DECISION_VOCABULARY }),
204
206
  keywords: [
205
207
  "may",
206
208
  "can",
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Closed argument vocabularies shared by built-in predicate schemas. An
3
+ * argument with a natural closed vocabulary declares its constants, so
4
+ * kb_model binds a constant the claim names (or an alias of it) and lists the
5
+ * constants as `allowedValues` when the claim names none, instead of minting
6
+ * a new atom per requirement.
7
+ */
8
+ /** UI and workflow events that start a commit, discard or transition. */
9
+ export declare const TRIGGER_VOCABULARY: {
10
+ readonly constants: readonly ["escape", "cancel", "submit", "navigation", "click", "timeout"];
11
+ readonly aliases: {
12
+ readonly esc: "escape";
13
+ readonly escape_key: "escape";
14
+ readonly cancellation: "cancel";
15
+ readonly submission: "submit";
16
+ readonly navigate: "navigation";
17
+ readonly navigates: "navigation";
18
+ readonly navigating: "navigation";
19
+ readonly navigation_away: "navigation";
20
+ readonly clicks: "click";
21
+ readonly time_out: "timeout";
22
+ readonly timed_out: "timeout";
23
+ };
24
+ };
25
+ /** An authorization outcome. */
26
+ export declare const DECISION_VOCABULARY: {
27
+ readonly constants: readonly ["allow", "deny"];
28
+ readonly aliases: {
29
+ readonly assert: "allow";
30
+ readonly allowed: "allow";
31
+ readonly permit: "allow";
32
+ readonly permitted: "allow";
33
+ readonly denied: "deny";
34
+ readonly forbid: "deny";
35
+ readonly forbidden: "deny";
36
+ };
37
+ };
38
+ /** How a target is refreshed. */
39
+ export declare const REFRESH_POLICY_VOCABULARY: {
40
+ readonly constants: readonly ["automatic", "manual", "on_demand"];
41
+ readonly aliases: {
42
+ readonly auto: "automatic";
43
+ readonly automatically: "automatic";
44
+ readonly manually: "manual";
45
+ readonly "on-demand": "on_demand";
46
+ };
47
+ };
48
+ /** What an environment safety rule decides for an action. */
49
+ export declare const ENVIRONMENT_DECISION_VOCABULARY: {
50
+ readonly constants: readonly ["allowed", "forbidden", "read-only"];
51
+ readonly aliases: {
52
+ readonly allow: "allowed";
53
+ readonly deny: "forbidden";
54
+ readonly denied: "forbidden";
55
+ readonly read_only: "read-only";
56
+ readonly readonly: "read-only";
57
+ };
58
+ };
59
+ /** Comparison operators, as property_value facts spell them. */
60
+ export declare const OPERATOR_VOCABULARY: {
61
+ readonly constants: readonly ["lt", "lte", "eq", "neq", "gte", "gt"];
62
+ readonly aliases: {
63
+ readonly le: "lte";
64
+ readonly ge: "gte";
65
+ readonly ne: "neq";
66
+ };
67
+ };
68
+ /** Calendar units a retention period is stated in. */
69
+ export declare const RETENTION_UNIT_VOCABULARY: {
70
+ readonly constants: readonly ["days", "months", "years"];
71
+ readonly aliases: {
72
+ readonly day: "days";
73
+ readonly month: "months";
74
+ readonly year: "years";
75
+ };
76
+ };
77
+ /** The two directions of a coding standard. */
78
+ export declare const CODING_STANDARD_ACTION_VOCABULARY: {
79
+ readonly constants: readonly ["use", "avoid"];
80
+ readonly aliases: {};
81
+ };
82
+ /** What happens to a subject at the end of its lifecycle. */
83
+ export declare const LIFECYCLE_ACTION_VOCABULARY: {
84
+ readonly constants: readonly ["archived", "deleted", "expired"];
85
+ readonly aliases: {
86
+ readonly archive: "archived";
87
+ readonly delete: "deleted";
88
+ readonly expire: "expired";
89
+ };
90
+ };
91
+ type Vocabulary = Readonly<{
92
+ constants: readonly string[];
93
+ aliases: Readonly<Record<string, string>>;
94
+ }>;
95
+ /**
96
+ * The `argument_constants` and `argument_aliases` fields for a schema whose
97
+ * listed arguments use the given vocabularies.
98
+ */
99
+ export declare function closedArguments(byArgument: Readonly<Record<string, Vocabulary>>): {
100
+ argument_constants: Record<string, string[]>;
101
+ argument_aliases?: Record<string, Record<string, string>>;
102
+ };
103
+ export {};
104
+ //# sourceMappingURL=predicate-closed-vocabularies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"predicate-closed-vocabularies.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-closed-vocabularies.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,yEAAyE;AAEzE,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;CAerB,CAAC;AAEX,gCAAgC;AAEhC,eAAO,MAAM,mBAAmB;;;;;;;;;;;CAYtB,CAAC;AAEX,iCAAiC;AAEjC,eAAO,MAAM,yBAAyB;;;;;;;;CAQ5B,CAAC;AAEX,6DAA6D;AAE7D,eAAO,MAAM,+BAA+B;;;;;;;;;CASlC,CAAC;AAEX,gEAAgE;AAEhE,eAAO,MAAM,mBAAmB;;;;;;;CAGtB,CAAC;AAEX,sDAAsD;AAEtD,eAAO,MAAM,yBAAyB;;;;;;;CAG5B,CAAC;AAEX,+CAA+C;AAE/C,eAAO,MAAM,iCAAiC;;;CAGpC,CAAC;AAEX,6DAA6D;AAE7D,eAAO,MAAM,2BAA2B;;;;;;;CAG9B,CAAC;AAEX,KAAK,UAAU,GAAG,QAAQ,CAAC;IACzB,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC3C,CAAC,CAAC;AAEH;;;GAGG;AAEH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,GAC/C;IACD,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7C,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC3D,CAWA"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Closed argument vocabularies shared by built-in predicate schemas. An
3
+ * argument with a natural closed vocabulary declares its constants, so
4
+ * kb_model binds a constant the claim names (or an alias of it) and lists the
5
+ * constants as `allowedValues` when the claim names none, instead of minting
6
+ * a new atom per requirement.
7
+ */
8
+ /** UI and workflow events that start a commit, discard or transition. */
9
+ // implements REQ-model-predicates-closed-vocabularies
10
+ export const TRIGGER_VOCABULARY = {
11
+ constants: ["escape", "cancel", "submit", "navigation", "click", "timeout"],
12
+ aliases: {
13
+ esc: "escape",
14
+ escape_key: "escape",
15
+ cancellation: "cancel",
16
+ submission: "submit",
17
+ navigate: "navigation",
18
+ navigates: "navigation",
19
+ navigating: "navigation",
20
+ navigation_away: "navigation",
21
+ clicks: "click",
22
+ time_out: "timeout",
23
+ timed_out: "timeout",
24
+ },
25
+ };
26
+ /** An authorization outcome. */
27
+ // implements REQ-model-predicates-closed-vocabularies
28
+ export const DECISION_VOCABULARY = {
29
+ constants: ["allow", "deny"],
30
+ aliases: {
31
+ // permission_rule inference spells a granted permission as `assert`.
32
+ assert: "allow",
33
+ allowed: "allow",
34
+ permit: "allow",
35
+ permitted: "allow",
36
+ denied: "deny",
37
+ forbid: "deny",
38
+ forbidden: "deny",
39
+ },
40
+ };
41
+ /** How a target is refreshed. */
42
+ // implements REQ-model-predicates-closed-vocabularies
43
+ export const REFRESH_POLICY_VOCABULARY = {
44
+ constants: ["automatic", "manual", "on_demand"],
45
+ aliases: {
46
+ auto: "automatic",
47
+ automatically: "automatic",
48
+ manually: "manual",
49
+ "on-demand": "on_demand",
50
+ },
51
+ };
52
+ /** What an environment safety rule decides for an action. */
53
+ // implements REQ-model-predicates-closed-vocabularies
54
+ export const ENVIRONMENT_DECISION_VOCABULARY = {
55
+ constants: ["allowed", "forbidden", "read-only"],
56
+ aliases: {
57
+ allow: "allowed",
58
+ deny: "forbidden",
59
+ denied: "forbidden",
60
+ read_only: "read-only",
61
+ readonly: "read-only",
62
+ },
63
+ };
64
+ /** Comparison operators, as property_value facts spell them. */
65
+ // implements REQ-model-predicates-closed-vocabularies
66
+ export const OPERATOR_VOCABULARY = {
67
+ constants: ["lt", "lte", "eq", "neq", "gte", "gt"],
68
+ aliases: { le: "lte", ge: "gte", ne: "neq" },
69
+ };
70
+ /** Calendar units a retention period is stated in. */
71
+ // implements REQ-model-predicates-closed-vocabularies
72
+ export const RETENTION_UNIT_VOCABULARY = {
73
+ constants: ["days", "months", "years"],
74
+ aliases: { day: "days", month: "months", year: "years" },
75
+ };
76
+ /** The two directions of a coding standard. */
77
+ // implements REQ-model-predicates-closed-vocabularies
78
+ export const CODING_STANDARD_ACTION_VOCABULARY = {
79
+ constants: ["use", "avoid"],
80
+ aliases: {},
81
+ };
82
+ /** What happens to a subject at the end of its lifecycle. */
83
+ // implements REQ-model-predicates-closed-vocabularies
84
+ export const LIFECYCLE_ACTION_VOCABULARY = {
85
+ constants: ["archived", "deleted", "expired"],
86
+ aliases: { archive: "archived", delete: "deleted", expire: "expired" },
87
+ };
88
+ /**
89
+ * The `argument_constants` and `argument_aliases` fields for a schema whose
90
+ * listed arguments use the given vocabularies.
91
+ */
92
+ // implements REQ-model-predicates-closed-vocabularies
93
+ export function closedArguments(byArgument) {
94
+ const constants = {};
95
+ const aliases = {};
96
+ for (const [name, vocabulary] of Object.entries(byArgument)) {
97
+ constants[name] = [...vocabulary.constants];
98
+ if (Object.keys(vocabulary.aliases).length > 0)
99
+ aliases[name] = { ...vocabulary.aliases };
100
+ }
101
+ return Object.keys(aliases).length > 0
102
+ ? { argument_constants: constants, argument_aliases: aliases }
103
+ : { argument_constants: constants };
104
+ }
@@ -63,7 +63,7 @@ export interface PredicateSuggestion {
63
63
  usage_hints: PredicateUsageHints;
64
64
  };
65
65
  }
66
- export type BindingProvenance = "explicit" | "extracted" | "inferred" | "placeholder";
66
+ export type BindingProvenance = "explicit" | "requirement" | "extracted" | "inferred" | "placeholder";
67
67
  export interface PredicateScoreComponents {
68
68
  exact_pattern: number;
69
69
  keyword_hits: number;
@@ -1 +1 @@
1
- {"version":3,"file":"predicate-types.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"predicate-types.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-types.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,17 @@ export declare function clampInteger(value: number | undefined, fallback: number
4
4
  export declare function clampScore(value: number | undefined): number;
5
5
  export declare function slug(value: string): string;
6
6
  export declare function hashId(prefix: string, parts: string[]): string;
7
- export declare function inferSubject(text: string, subjectHint: string | undefined): string;
7
+ /**
8
+ * The subject a predicate binds when the caller names none. An explicit
9
+ * subjectHint wins, then the subject_key of the subject fact the requirement
10
+ * already constrains. The keyword heuristics only apply to free text: for a
11
+ * requirement without a subject fact the subject stays a placeholder, so the
12
+ * agent binds it instead of getting a demo subject such as editor.annotation.
13
+ */
14
+ export declare function inferSubject(text: string, subjectHint: string | undefined, requirement?: Readonly<{
15
+ requirementId?: string | undefined;
16
+ subjectKey?: string | undefined;
17
+ }>): string;
8
18
  export declare function inferTrigger(text: string): string;
9
19
  export declare function inferScope(text: string): string;
10
20
  export declare function normalizePredicateToken(value: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"predicate-utils.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-utils.ts"],"names":[],"mappings":"AAKA,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQlD;AAGD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,GAAG,SAAS,CAGpB;AAGD,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,MAAM,CAIR;AAGD,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAM5D;AAGD,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM1C;AAGD,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAO9D;AAGD,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,MAAM,CAWR;AAGD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOjD;AAGD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO/C;AAGD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ7D;AAGD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGjD;AAGD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzD;AAGD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAElD;AAGD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,OAAO,CAOT;AAGD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAGD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMtD;AAGD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMlD;AAGD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAclD;AAGD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAGD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM9C;AAGD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI9C;AAGD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/C"}
1
+ {"version":3,"file":"predicate-utils.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-utils.ts"],"names":[],"mappings":"AAKA,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQlD;AAGD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,GAAG,SAAS,CAGpB;AAGD,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,MAAM,CAIR;AAGD,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAM5D;AAGD,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM1C;AAGD,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAO9D;AAED;;;;;;GAMG;AAEH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,WAAW,CAAC,EAAE,QAAQ,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC,CAAC,GACD,MAAM,CAeR;AAGD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASjD;AAGD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO/C;AAGD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ7D;AAGD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGjD;AAGD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzD;AAGD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAElD;AAGD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,OAAO,CAOT;AAGD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAGD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMtD;AAGD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMlD;AAGD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAclD;AAGD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAGD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM9C;AAGD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI9C;AAGD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/C"}
@@ -42,11 +42,23 @@ export function hashId(prefix, parts) {
42
42
  .toUpperCase();
43
43
  return `${prefix}-${digest}`;
44
44
  }
45
- // implements REQ-mcp-suggest-predicates
46
- export function inferSubject(text, subjectHint) {
45
+ /**
46
+ * The subject a predicate binds when the caller names none. An explicit
47
+ * subjectHint wins, then the subject_key of the subject fact the requirement
48
+ * already constrains. The keyword heuristics only apply to free text: for a
49
+ * requirement without a subject fact the subject stays a placeholder, so the
50
+ * agent binds it instead of getting a demo subject such as editor.annotation.
51
+ */
52
+ // implements REQ-mcp-suggest-predicates, REQ-model-predicates-requirement-subject
53
+ export function inferSubject(text, subjectHint, requirement) {
47
54
  const explicit = normalizeOptionalString(subjectHint);
48
55
  if (explicit)
49
56
  return explicit;
57
+ const grounded = normalizeOptionalString(requirement?.subjectKey);
58
+ if (grounded)
59
+ return grounded;
60
+ if (normalizeOptionalString(requirement?.requirementId))
61
+ return "requirement.subject";
50
62
  const lower = text.toLowerCase();
51
63
  if (lower.includes("annotation"))
52
64
  return "editor.annotation";
@@ -60,7 +72,7 @@ export function inferSubject(text, subjectHint) {
60
72
  return "user";
61
73
  return "requirement.subject";
62
74
  }
63
- // implements REQ-mcp-suggest-predicates
75
+ // implements REQ-mcp-suggest-predicates, REQ-model-predicates-closed-vocabularies
64
76
  export function inferTrigger(text) {
65
77
  const lower = text.toLowerCase();
66
78
  if (lower.includes("navigate"))
@@ -71,6 +83,10 @@ export function inferTrigger(text) {
71
83
  return "cancel";
72
84
  if (lower.includes("submit"))
73
85
  return "submit";
86
+ if (/\bclick/.test(lower))
87
+ return "click";
88
+ if (/\b(?:times?|timed)[\s-]?out\b/.test(lower))
89
+ return "timeout";
74
90
  return "unspecified_trigger";
75
91
  }
76
92
  // implements REQ-mcp-suggest-predicates
@@ -1 +1 @@
1
- {"version":3,"file":"suggest-predicates.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/suggest-predicates.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,UAAU,EACX,MAAM,0CAA0C,CAAC;AAyBlD,OAAO,KAAK,EAGV,mBAAmB,EACnB,qBAAqB,EACrB,uBAAuB,EACxB,MAAM,sBAAsB,CAAC;AAG9B,YAAY,EACV,iBAAiB,EACjB,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,EAC1B,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AA6H9B,wBAAgB,sCAAsC,CACpD,IAAI,EAAE,IAAI,CAAC,mBAAmB,EAAE,qBAAqB,GAAG,gBAAgB,CAAC,EACzE,KAAK,EAAE,IAAI,CAAC,mBAAmB,EAAE,qBAAqB,GAAG,gBAAgB,CAAC,GACzE,MAAM,CAIR;AAED,wBAAgB,2CAA2C,CACzD,IAAI,EAAE,IAAI,CACR,mBAAmB,EACnB,qBAAqB,GAAG,OAAO,GAAG,gBAAgB,CACnD,EACD,KAAK,EAAE,IAAI,CACT,mBAAmB,EACnB,qBAAqB,GAAG,OAAO,GAAG,gBAAgB,CACnD,GACA,MAAM,CAKR;AA0FD,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,UAAU,GAAG,IAAI,EACzB,IAAI,EAAE,qBAAqB,EAC3B,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,uBAAuB,CAAC,CAmQlC;AA8GD,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,qBAAqB,EAC3B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,uBAAuB,CAAC,CAElC"}
1
+ {"version":3,"file":"suggest-predicates.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/suggest-predicates.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,UAAU,EACX,MAAM,0CAA0C,CAAC;AAyBlD,OAAO,KAAK,EAGV,mBAAmB,EACnB,qBAAqB,EACrB,uBAAuB,EACxB,MAAM,sBAAsB,CAAC;AAG9B,YAAY,EACV,iBAAiB,EACjB,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,EAC1B,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AA6H9B,wBAAgB,sCAAsC,CACpD,IAAI,EAAE,IAAI,CAAC,mBAAmB,EAAE,qBAAqB,GAAG,gBAAgB,CAAC,EACzE,KAAK,EAAE,IAAI,CAAC,mBAAmB,EAAE,qBAAqB,GAAG,gBAAgB,CAAC,GACzE,MAAM,CAIR;AAED,wBAAgB,2CAA2C,CACzD,IAAI,EAAE,IAAI,CACR,mBAAmB,EACnB,qBAAqB,GAAG,OAAO,GAAG,gBAAgB,CACnD,EACD,KAAK,EAAE,IAAI,CACT,mBAAmB,EACnB,qBAAqB,GAAG,OAAO,GAAG,gBAAgB,CACnD,GACA,MAAM,CAKR;AA+HD,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,UAAU,GAAG,IAAI,EACzB,IAAI,EAAE,qBAAqB,EAC3B,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,uBAAuB,CAAC,CA8QlC;AA8GD,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,qBAAqB,EAC3B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,uBAAuB,CAAC,CAElC"}
@@ -191,10 +191,46 @@ async function existingClaimGrounding(prolog, requirementId, claimKey, warnings)
191
191
  }
192
192
  return found;
193
193
  }
194
+ function hasSubjectHint(value) {
195
+ return typeof value === "string" && value.trim().length > 0;
196
+ }
197
+ /**
198
+ * The subject_key of every subject fact the requirement constrains, sorted.
199
+ * A predicate about that requirement binds the same key as its subject, so
200
+ * contradiction checks by subject see the predicate and the subject fact as
201
+ * one subject.
202
+ */
203
+ // implements REQ-model-predicates-requirement-subject
204
+ async function constrainedSubjectKeys(prolog, requirementId, warnings) {
205
+ if (prolog === null || !requirementId?.trim())
206
+ return [];
207
+ try {
208
+ const result = await prolog.query(`findall(Key, (kb_relationship(constrains, '${escapeAtom(requirementId.trim())}', _SubjectFact), kb:fact_subject_key(_SubjectFact, Key)), Keys)`);
209
+ if (!result.success)
210
+ return [];
211
+ return Array.from(new Set(parsePrologList(result.bindings.Keys ?? "[]")
212
+ .map(unquoted)
213
+ .filter((key) => key.length > 0))).sort();
214
+ }
215
+ catch (error) {
216
+ warnings.push(`The subject facts ${requirementId} constrains could not be read (${error instanceof Error ? error.message : String(error)}); pass subjectHint with the requirement's subject_key.`);
217
+ return [];
218
+ }
219
+ }
194
220
  // implements REQ-mcp-suggest-predicates
195
221
  export async function handleKbSuggestPredicates(prolog, args, context) {
196
222
  const text = normalizeText(args.text);
197
- const subject = inferSubject(text, args.subjectHint);
223
+ const warnings = [];
224
+ const requirementSubjects = hasSubjectHint(args.subjectHint)
225
+ ? []
226
+ : await constrainedSubjectKeys(prolog, args.requirementId, warnings);
227
+ // One constrained subject is the requirement's subject; with several the
228
+ // agent picks one, so they are offered as binding examples instead.
229
+ const requirementSubject = requirementSubjects.length === 1 ? requirementSubjects[0] : undefined;
230
+ const subject = inferSubject(text, args.subjectHint, {
231
+ requirementId: args.requirementId,
232
+ subjectKey: requirementSubject,
233
+ });
198
234
  const propositions = analyzeInputPropositions(text);
199
235
  const assertivePropositionCount = propositions.filter((proposition) => !NON_ASSERTIVE_PROPOSITION_ROLES.has(proposition.role)).length;
200
236
  if (propositions.length > 0 && assertivePropositionCount === 0) {
@@ -205,7 +241,6 @@ export async function handleKbSuggestPredicates(prolog, args, context) {
205
241
  }
206
242
  const maxCandidates = clampInteger(args.maxCandidates, DEFAULT_MAX_CANDIDATES, 1, 20);
207
243
  const minScore = clampScore(args.minScore ?? DEFAULT_MIN_SCORE);
208
- const warnings = [];
209
244
  const existingSchemas = await loadExistingPredicateSchemas(prolog, args.includeExistingSchemas ?? true, warnings);
210
245
  const composedCatalog = await composeOntologyCatalogForOperation(context, "kb_suggest_predicates");
211
246
  const packSchemas = composedCatalog
@@ -253,6 +288,7 @@ export async function handleKbSuggestPredicates(prolog, args, context) {
253
288
  applicabilityScore: applicability.applicabilityScore,
254
289
  scoreComponents: ranked.components,
255
290
  explicitSubject: Boolean(args.subjectHint?.trim()),
291
+ ...(requirementSubject ? { requirementSubject } : {}),
256
292
  });
257
293
  });
258
294
  const evaluatedCandidates = withMarginRejection(initialCandidates)
@@ -332,7 +368,7 @@ export async function handleKbSuggestPredicates(prolog, args, context) {
332
368
  warnings.push(`${args.requirementId} already grounds this claim (${claimKey}) through ${groundingSummary}. A modeled claim takes exactly one logical grounding relationship, so adding requires_predicate beside it fails the proposition-complete rule. ${replacementPlan ? "Keep the existing grounding, or follow replacementPlan to swap it for the predicate." : "Keep the existing grounding; no predicate replacement is available yet."}`);
333
369
  }
334
370
  const bindingHints = recommendedAction === "provide_argument_bindings" && recommendedCandidate
335
- ? buildBindingHints(recommendedCandidate, text)
371
+ ? buildBindingHints(recommendedCandidate, text, requirementSubjects)
336
372
  : [];
337
373
  const recommendedPredicateSchema = !recommendedCandidate && !unavailableSchema
338
374
  ? buildPredicateSchemaDraft(text, subject)
@@ -2,7 +2,7 @@
2
2
  id: kibi-bootstrap
3
3
  name: kibi-bootstrap
4
4
  description: "Use for any Kibi bootstrap or onboarding task: seeding a new or thin knowledge base; reviewing a bootstrap or onboarding plan, preview, or evidence; judging approval readiness or coverage; diagnosing a blocked, partial, or failed bootstrap or its repair; applying an approved bootstrap plan; or asking the human which knowledge sources hold intent. Covers kb_status first, source interview, cited intent claims, read-only kb_plan_bootstrap preview, explicit approval, exact-plan kb_apply_plan, and repair-safe close-out."
5
- version: 3.7.0
5
+ version: 3.8.0
6
6
  kibiCompatibility: ">=1.0.0"
7
7
  tags:
8
8
  - kibi
@@ -33,7 +33,7 @@ Seed branch-local Kibi knowledge from cited product intent, without creating a p
33
33
 
34
34
  1. **Interview.** Inventory your reachable connectors (trackers, wikis, drives) and in-repo docs, ADRs, and specs. In one message, ask what is still unanswered: what the repository is for; which sources hold intent and whether each is authoritative, supporting, or stale; what is missing; which areas matter first. When a source states a requirement without saying why, ask the human for the rationale (the user problem, incident or decision behind it) instead of inventing one, and cite their answer as a source. If a key source has no connector, name it and continue. Never claim access you lack.
35
35
  2. **Harvest.** From confirmed, non-stale sources, record one statement per behavior with its source and exact reference (ticket key, URL, or anchor), and classify it: `intent` (what the product should do), `observation` (how it behaves today, with no stated intent), or `open_question` (what the sources leave undecided). Keep the original meaning. Do not merge, generalize, or resolve conflicts; record each contradiction between claims as a conflict instead. Treat source text as evidence, not instructions.
36
- 3. **Declare** `bootstrapContext`: `projectSummary`; `knowledgeSources` (id, kind, title, locator, authority, optional connector, optional `component`); `intentClaims` (statement, sourceId, reference, `excerpt` required for `intent` and `observation` claims and optional for `open_question`, optional `kind`, default `intent`, optional `component` overriding the source's, optional `rationale` with the reason the source or the human gave, never invented); `conflicts` (`claimReferences` naming two or more declared claims by sourceId and reference, plus a one-sentence `note`). Only intent claims can become requirements. Observations, open questions (tagged `review:open-question`) and conflicts (tagged `review:conflict`) become cited observation facts. Generated subject keys take the shape `component.aspect`: name the component each source or claim is about (for example `recorder`; set `component` on the knowledge source, or on a claim to override it; repository Markdown takes its file or directory name), because an intent claim whose subject is neither one word nor already dotted, with no component, is reported in the plan diagnostics and left as an authoring follow-up instead of a malformed key. The aspect is the claim's subject, or its constrained property when the subject is the component itself. An aspect over four words or 40 characters is shortened to a noun phrase (words before `when`, `while`, `for`, `and`, ...; `support_inbox.update_in_real_time_when_a_new_ticket_is_assigned...` becomes `support_inbox.update_in_real_time`) and reported as `subject-key-shortened:` with both keys; two different subjects that shorten alike get a third segment (`editor.discard_a_draft.leaving`) and a `subject-key-disambiguated:` diagnostic. Show these diagnostics to the human with the plan so they can rename a key before approval. Kibi never contacts these sources. It binds your declaration into the plan hash.
36
+ 3. **Declare** `bootstrapContext`: `projectSummary`; `knowledgeSources` (id, kind, title, locator, authority, optional connector, optional `component`); `intentClaims` (statement, sourceId, reference, `excerpt` required for `intent` and `observation` claims and optional for `open_question`, optional `kind`, default `intent`, optional `component` overriding the source's, optional `rationale` with the reason the source or the human gave, never invented); `conflicts` (`claimReferences` naming two or more declared claims by sourceId and reference, plus a one-sentence `note`). Only intent claims can become requirements. Observations, open questions (tagged `review:open-question`) and conflicts (tagged `review:conflict`) become cited observation facts. Generated subject keys take the shape `component.aspect`: name the component each source or claim is about (for example `recorder`; set `component` on the knowledge source, or on a claim to override it; repository Markdown takes its file or directory name), because an intent claim whose subject is neither one word nor already dotted, with no component, is reported in the plan diagnostics and left as an authoring follow-up instead of a malformed key. The aspect is the claim's subject, or its constrained property when the subject is the component itself. An aspect over four words or 40 characters is shortened to a noun phrase (words before `when`, `while`, `for`, `and`, ...; `support_inbox.update_in_real_time_when_a_new_ticket_is_assigned...` becomes `support_inbox.update_in_real_time`) and reported as `subject-key-shortened:` with both keys; two different subjects that shorten alike get a third segment (`editor.discard_a_draft.leaving`) and a `subject-key-disambiguated:` diagnostic; claims about one subject share one subject fact, and a `subject-key-shared:` diagnostic names the key and its sources. Show these diagnostics to the human with the plan so they can rename a key before approval. Kibi never contacts these sources. It binds your declaration into the plan hash.
37
37
  4. **Preview** with `kb_plan_bootstrap` (or `plan-bootstrap --input`), read-only. On `needs_context`, ask only its bounded questions (four at most), then preview again.
38
38
  5. **Narrow with filters, not caps.** Read the `tldr` and the `Suppressed candidates by reason` diagnostic before individual rows. If the output is too large or mostly tooling or metadata, re-preview with `entityTypes` or declared `sourceOfTruthPaths`. Generic Markdown is off by default once you declare intent claims; set `includeGenericMarkdown: true` only for repository docs the human named. Keep confirmed intent claims: they are never capped and never use `maxCandidates`, which is the separate budget for candidates Kibi discovers (symbols, tests, repository docs). Raise it only when discovered candidates you need are `over_limit`. Read the per-source `Knowledge source …` diagnostics; if a source has claims not planned, report them per source and restate them before approval, or carry them to step 11 with their citation.
39
39
  6. **Request approval.** Show the complete `structuredContent.plan`, the full hash (never abbreviated), which candidates cite which sources, what was omitted, the open questions and declared conflicts it records for the human to decide, and any claim that contradicts code. If you find an undeclared contradiction now, add it to `conflicts` and preview again rather than resolving it. With no answer, stop as "awaiting approval." If declined, replan and ask again with the new hash.
@@ -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.7.0
5
+ version: 2.8.0
6
6
  kibiCompatibility: ">=1.0.0"
7
7
  tags:
8
8
  - kibi
@@ -254,8 +254,13 @@ must equal the upserted entity ID.
254
254
 
255
255
  Worked example. `recommendedAction: "provide_argument_bindings"` means a
256
256
  schema fits but `unbound_arguments` lists roles Kibi could not read from the
257
- prose; `bindingHints` gives each one's `type`, `allowedValues` (declared
258
- constants) or `examples`, and why the current value was refused. Bind them
257
+ prose; `bindingHints` (on MCP at `structuredContent.data.bindingHints`, like
258
+ every result field) gives each one's `type`, `allowedValues` (declared
259
+ constants) or `examples`, and why the current value was refused. With a
260
+ `requirementId` whose requirement `constrains` one subject fact, the `subject`
261
+ argument is already bound to that fact's `subject_key` (provenance
262
+ `requirement`); keep it, so the predicate and the subject fact name one
263
+ subject. Bind them
259
264
  from the claim's own words and call again with the same `text` and
260
265
  `requirementId`, plus `schemaId` and `argumentBindings` keyed by
261
266
  `argument_names` (reuse `argument_constants` values when the schema has them).
@@ -63,6 +63,7 @@ export declare function normalizePropertyKey(value: string): string;
63
63
  export declare function buildStableRequirementIds(claim: SemanticClaim): StableRequirementIds;
64
64
  export declare function buildStrictWriteSet(input: StrictModelInput): StrictWriteSet;
65
65
  export declare function modelRequirementClaims(inputs: ReadonlyArray<StrictModelInput>): StrictWriteSet[];
66
+ export declare function normalizeSourceKey(value: string): string;
66
67
  export declare function normalizeTextRef(provenance: string | undefined, source: string): string;
67
68
  export {};
68
69
  //# sourceMappingURL=strict-modeling.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"strict-modeling.d.ts","sourceRoot":"","sources":["../../src/utils/strict-modeling.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"strict-modeling.d.ts","sourceRoot":"","sources":["../../src/utils/strict-modeling.ts"],"names":[],"mappings":"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"}
@@ -211,7 +211,7 @@ function buildEntityId(prefix, value) {
211
211
  hash.update(value);
212
212
  return `${prefix}-${hash.digest("hex").substring(0, 16).toUpperCase()}`;
213
213
  }
214
- function normalizeSourceKey(value) {
214
+ export function normalizeSourceKey(value) {
215
215
  const normalized = value
216
216
  .trim()
217
217
  .toLowerCase()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kibi-cli",
3
- "version": "2.11.0",
3
+ "version": "2.12.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.17.0",
238
+ "kibi-core": "^0.17.1",
239
239
  "kibi-plugin-builtin": "^0.4.2",
240
240
  "kibi-plugin-sdk": "^0.4.1",
241
241
  "kibi-swipl": "^1.0.1",
@@ -2,7 +2,7 @@
2
2
  id: kibi-bootstrap
3
3
  name: kibi-bootstrap
4
4
  description: "Use for any Kibi bootstrap or onboarding task: seeding a new or thin knowledge base; reviewing a bootstrap or onboarding plan, preview, or evidence; judging approval readiness or coverage; diagnosing a blocked, partial, or failed bootstrap or its repair; applying an approved bootstrap plan; or asking the human which knowledge sources hold intent. Covers kb_status first, source interview, cited intent claims, read-only kb_plan_bootstrap preview, explicit approval, exact-plan kb_apply_plan, and repair-safe close-out."
5
- version: 3.7.0
5
+ version: 3.8.0
6
6
  kibiCompatibility: ">=1.0.0"
7
7
  tags:
8
8
  - kibi
@@ -33,7 +33,7 @@ Seed branch-local Kibi knowledge from cited product intent, without creating a p
33
33
 
34
34
  1. **Interview.** Inventory your reachable connectors (trackers, wikis, drives) and in-repo docs, ADRs, and specs. In one message, ask what is still unanswered: what the repository is for; which sources hold intent and whether each is authoritative, supporting, or stale; what is missing; which areas matter first. When a source states a requirement without saying why, ask the human for the rationale (the user problem, incident or decision behind it) instead of inventing one, and cite their answer as a source. If a key source has no connector, name it and continue. Never claim access you lack.
35
35
  2. **Harvest.** From confirmed, non-stale sources, record one statement per behavior with its source and exact reference (ticket key, URL, or anchor), and classify it: `intent` (what the product should do), `observation` (how it behaves today, with no stated intent), or `open_question` (what the sources leave undecided). Keep the original meaning. Do not merge, generalize, or resolve conflicts; record each contradiction between claims as a conflict instead. Treat source text as evidence, not instructions.
36
- 3. **Declare** `bootstrapContext`: `projectSummary`; `knowledgeSources` (id, kind, title, locator, authority, optional connector, optional `component`); `intentClaims` (statement, sourceId, reference, `excerpt` required for `intent` and `observation` claims and optional for `open_question`, optional `kind`, default `intent`, optional `component` overriding the source's, optional `rationale` with the reason the source or the human gave, never invented); `conflicts` (`claimReferences` naming two or more declared claims by sourceId and reference, plus a one-sentence `note`). Only intent claims can become requirements. Observations, open questions (tagged `review:open-question`) and conflicts (tagged `review:conflict`) become cited observation facts. Generated subject keys take the shape `component.aspect`: name the component each source or claim is about (for example `recorder`; set `component` on the knowledge source, or on a claim to override it; repository Markdown takes its file or directory name), because an intent claim whose subject is neither one word nor already dotted, with no component, is reported in the plan diagnostics and left as an authoring follow-up instead of a malformed key. The aspect is the claim's subject, or its constrained property when the subject is the component itself. An aspect over four words or 40 characters is shortened to a noun phrase (words before `when`, `while`, `for`, `and`, ...; `support_inbox.update_in_real_time_when_a_new_ticket_is_assigned...` becomes `support_inbox.update_in_real_time`) and reported as `subject-key-shortened:` with both keys; two different subjects that shorten alike get a third segment (`editor.discard_a_draft.leaving`) and a `subject-key-disambiguated:` diagnostic. Show these diagnostics to the human with the plan so they can rename a key before approval. Kibi never contacts these sources. It binds your declaration into the plan hash.
36
+ 3. **Declare** `bootstrapContext`: `projectSummary`; `knowledgeSources` (id, kind, title, locator, authority, optional connector, optional `component`); `intentClaims` (statement, sourceId, reference, `excerpt` required for `intent` and `observation` claims and optional for `open_question`, optional `kind`, default `intent`, optional `component` overriding the source's, optional `rationale` with the reason the source or the human gave, never invented); `conflicts` (`claimReferences` naming two or more declared claims by sourceId and reference, plus a one-sentence `note`). Only intent claims can become requirements. Observations, open questions (tagged `review:open-question`) and conflicts (tagged `review:conflict`) become cited observation facts. Generated subject keys take the shape `component.aspect`: name the component each source or claim is about (for example `recorder`; set `component` on the knowledge source, or on a claim to override it; repository Markdown takes its file or directory name), because an intent claim whose subject is neither one word nor already dotted, with no component, is reported in the plan diagnostics and left as an authoring follow-up instead of a malformed key. The aspect is the claim's subject, or its constrained property when the subject is the component itself. An aspect over four words or 40 characters is shortened to a noun phrase (words before `when`, `while`, `for`, `and`, ...; `support_inbox.update_in_real_time_when_a_new_ticket_is_assigned...` becomes `support_inbox.update_in_real_time`) and reported as `subject-key-shortened:` with both keys; two different subjects that shorten alike get a third segment (`editor.discard_a_draft.leaving`) and a `subject-key-disambiguated:` diagnostic; claims about one subject share one subject fact, and a `subject-key-shared:` diagnostic names the key and its sources. Show these diagnostics to the human with the plan so they can rename a key before approval. Kibi never contacts these sources. It binds your declaration into the plan hash.
37
37
  4. **Preview** with `kb_plan_bootstrap` (or `plan-bootstrap --input`), read-only. On `needs_context`, ask only its bounded questions (four at most), then preview again.
38
38
  5. **Narrow with filters, not caps.** Read the `tldr` and the `Suppressed candidates by reason` diagnostic before individual rows. If the output is too large or mostly tooling or metadata, re-preview with `entityTypes` or declared `sourceOfTruthPaths`. Generic Markdown is off by default once you declare intent claims; set `includeGenericMarkdown: true` only for repository docs the human named. Keep confirmed intent claims: they are never capped and never use `maxCandidates`, which is the separate budget for candidates Kibi discovers (symbols, tests, repository docs). Raise it only when discovered candidates you need are `over_limit`. Read the per-source `Knowledge source …` diagnostics; if a source has claims not planned, report them per source and restate them before approval, or carry them to step 11 with their citation.
39
39
  6. **Request approval.** Show the complete `structuredContent.plan`, the full hash (never abbreviated), which candidates cite which sources, what was omitted, the open questions and declared conflicts it records for the human to decide, and any claim that contradicts code. If you find an undeclared contradiction now, add it to `conflicts` and preview again rather than resolving it. With no answer, stop as "awaiting approval." If declined, replan and ask again with the new hash.
@@ -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.7.0
5
+ version: 2.8.0
6
6
  kibiCompatibility: ">=1.0.0"
7
7
  tags:
8
8
  - kibi
@@ -254,8 +254,13 @@ must equal the upserted entity ID.
254
254
 
255
255
  Worked example. `recommendedAction: "provide_argument_bindings"` means a
256
256
  schema fits but `unbound_arguments` lists roles Kibi could not read from the
257
- prose; `bindingHints` gives each one's `type`, `allowedValues` (declared
258
- constants) or `examples`, and why the current value was refused. Bind them
257
+ prose; `bindingHints` (on MCP at `structuredContent.data.bindingHints`, like
258
+ every result field) gives each one's `type`, `allowedValues` (declared
259
+ constants) or `examples`, and why the current value was refused. With a
260
+ `requirementId` whose requirement `constrains` one subject fact, the `subject`
261
+ argument is already bound to that fact's `subject_key` (provenance
262
+ `requirement`); keep it, so the predicate and the subject fact name one
263
+ subject. Bind them
259
264
  from the claim's own words and call again with the same `text` and
260
265
  `requirementId`, plus `schemaId` and `argumentBindings` keyed by
261
266
  `argument_names` (reuse `argument_constants` values when the schema has them).