kibi-cli 2.21.0 → 2.21.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-operation-metadata.d.ts +1 -1
- package/dist/cli-operation-metadata.js +1 -1
- package/dist/commands/doctor.js +13 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +15 -3
- package/dist/commands/legacy-storage-migration.d.ts.map +1 -1
- package/dist/commands/legacy-storage-migration.js +26 -1
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +123 -5
- package/dist/commands/sync/persistence.d.ts.map +1 -1
- package/dist/commands/sync/persistence.js +4 -0
- package/dist/decision-firmness.d.ts +39 -0
- package/dist/decision-firmness.d.ts.map +1 -0
- package/dist/decision-firmness.js +115 -0
- package/dist/extractors/markdown.d.ts +2 -0
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +14 -0
- package/dist/operations/migration/schema6.d.ts +2 -0
- package/dist/operations/migration/schema6.d.ts.map +1 -1
- package/dist/operations/migration/schema6.js +44 -1
- package/dist/operations/migration/supersedes-reason.d.ts +26 -0
- package/dist/operations/migration/supersedes-reason.d.ts.map +1 -0
- package/dist/operations/migration/supersedes-reason.js +69 -0
- package/dist/operations/modeling/predicate-applyplan.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-applyplan.js +10 -2
- package/dist/operations/modeling/predicate-loader.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-loader.js +11 -0
- package/dist/operations/modeling/predicate-types.d.ts +32 -1
- package/dist/operations/modeling/predicate-types.d.ts.map +1 -1
- package/dist/operations/modeling/suggest-predicates.d.ts.map +1 -1
- package/dist/operations/modeling/suggest-predicates.js +175 -35
- package/dist/operations/mutation/delete.d.ts +5 -1
- package/dist/operations/mutation/delete.d.ts.map +1 -1
- package/dist/operations/mutation/delete.js +223 -17
- package/dist/operations/mutation/serialization.d.ts.map +1 -1
- package/dist/operations/mutation/serialization.js +1 -0
- package/dist/operations/mutation/types.d.ts +37 -0
- package/dist/operations/mutation/types.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +54 -2
- package/dist/operations/planning/apply-plan.d.ts +6 -1
- package/dist/operations/planning/apply-plan.d.ts.map +1 -1
- package/dist/operations/planning/apply-plan.js +8 -2
- package/dist/public/operations/catalog.d.ts +12 -3
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +3 -0
- package/dist/public/operations/contracts.d.ts.map +1 -1
- package/dist/public/operations/contracts.js +29 -1
- package/dist/public/operations/decision-firmness.d.ts +34 -0
- package/dist/public/operations/decision-firmness.d.ts.map +1 -0
- package/dist/public/operations/decision-firmness.js +216 -0
- package/dist/public/operations/discovery-executors.d.ts.map +1 -1
- package/dist/public/operations/discovery-executors.js +16 -2
- package/dist/public/operations/migration-plan.js +1 -1
- package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
- package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
- package/dist/public/operations/specs/check-rules.generated.js +5 -1
- package/dist/public/operations/specs/check.d.ts +1 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts +5 -0
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +5 -0
- package/dist/public/operations/specs/mutation.d.ts +6 -2
- package/dist/public/operations/specs/mutation.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation.js +6 -2
- package/dist/public/operations/specs/upsert.d.ts +5 -0
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +11 -0
- package/dist/public/skills/kibi-traceability/SKILL.md +6 -4
- package/dist/public/skills/kibi-usage/SKILL.md +50 -10
- package/dist/public/skills/kibi-usage/resources/source-authoring.md +4 -2
- package/dist/relationships/shards.d.ts +10 -0
- package/dist/relationships/shards.d.ts.map +1 -1
- package/dist/relationships/shards.js +27 -11
- package/dist/schemas/entity.schema.json +28 -0
- package/dist/search-answer.d.ts +31 -2
- package/dist/search-answer.d.ts.map +1 -1
- package/dist/search-answer.js +115 -17
- package/dist/types/entities.d.ts +4 -0
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/utils/kb-manifest.d.ts +6 -0
- package/dist/utils/kb-manifest.d.ts.map +1 -1
- package/dist/utils/kb-manifest.js +6 -0
- package/dist/utils/rule-registry.generated.d.ts +21 -0
- package/dist/utils/rule-registry.generated.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.js +25 -0
- package/dist/utils/schema-version.d.ts +1 -1
- package/dist/utils/schema-version.d.ts.map +1 -1
- package/dist/utils/schema-version.js +3 -1
- package/package.json +2 -2
- package/schema/entities.pl +6 -0
- package/src/public/operations/check-executor.ts +6 -0
- package/src/public/operations/contracts.ts +33 -1
- package/src/public/operations/decision-firmness.ts +280 -0
- package/src/public/operations/discovery-executors.ts +17 -2
- package/src/public/operations/migration-plan.ts +1 -1
- package/src/public/operations/specs/check-rules.generated.ts +5 -1
- package/src/public/operations/specs/mutation-schemas.ts +6 -0
- package/src/public/operations/specs/mutation.ts +7 -2
- package/src/public/schemas/entity.ts +12 -0
- package/src/public/skills/kibi-traceability/SKILL.md +6 -4
- package/src/public/skills/kibi-usage/SKILL.md +50 -10
- package/src/public/skills/kibi-usage/resources/source-authoring.md +4 -2
- package/src/schemas/entity.schema.json +28 -0
|
@@ -162,10 +162,13 @@ function unquoted(value) {
|
|
|
162
162
|
* The logical grounding relationships an existing requirement already has for
|
|
163
163
|
* this claim. A modeled claim takes exactly one grounding relationship, so a
|
|
164
164
|
* second link (for example requires_predicate beside a bootstrap
|
|
165
|
-
* requires_property) fails the proposition-complete rule.
|
|
165
|
+
* requires_property) fails the proposition-complete rule. A grounding fact is
|
|
166
|
+
* recognised by the claim's key (the same proposition text) or, for a
|
|
167
|
+
* predicate fact, by the recommended candidate's canonical_key (the same
|
|
168
|
+
* predicate tuple stated in other words).
|
|
166
169
|
*/
|
|
167
|
-
// implements REQ-model-predicates-grounding-aware-v2
|
|
168
|
-
async function existingClaimGrounding(prolog, requirementId, claimKey, warnings) {
|
|
170
|
+
// implements REQ-model-predicates-grounding-aware-v2, REQ-model-predicates-grounding-guards
|
|
171
|
+
async function existingClaimGrounding(prolog, requirementId, claimKey, canonicalKey, warnings) {
|
|
169
172
|
if (prolog === null || !requirementId)
|
|
170
173
|
return [];
|
|
171
174
|
const found = [];
|
|
@@ -175,16 +178,27 @@ async function existingClaimGrounding(prolog, requirementId, claimKey, warnings)
|
|
|
175
178
|
if (!targets.success)
|
|
176
179
|
continue;
|
|
177
180
|
for (const target of parsePrologList(targets.bindings.Targets ?? "[]")) {
|
|
178
|
-
const fact = await prolog.query(`once((kb_entity('${escapeAtom(target)}', fact, _GroundProps), memberchk(claim_key=_GroundClaimRaw, _GroundProps), normalize_term_atom(_GroundClaimRaw, ClaimKey), (memberchk(fact_kind=_GroundKindRaw, _GroundProps) -> normalize_term_atom(_GroundKindRaw, FactKind) ; FactKind = '')))`);
|
|
181
|
+
const fact = await prolog.query(`once((kb_entity('${escapeAtom(target)}', fact, _GroundProps), memberchk(claim_key=_GroundClaimRaw, _GroundProps), normalize_term_atom(_GroundClaimRaw, ClaimKey), (memberchk(fact_kind=_GroundKindRaw, _GroundProps) -> normalize_term_atom(_GroundKindRaw, FactKind) ; FactKind = ''), (memberchk(canonical_key=_GroundCanonicalRaw, _GroundProps) -> normalize_term_atom(_GroundCanonicalRaw, CanonicalKey) ; CanonicalKey = '')))`);
|
|
179
182
|
if (!fact.success)
|
|
180
183
|
continue;
|
|
181
|
-
|
|
184
|
+
const storedClaimKey = unquoted(fact.bindings.ClaimKey);
|
|
185
|
+
const storedCanonicalKey = unquoted(fact.bindings.CanonicalKey);
|
|
186
|
+
const matchedBy = storedClaimKey === claimKey
|
|
187
|
+
? "claim_key"
|
|
188
|
+
: canonicalKey !== null &&
|
|
189
|
+
storedCanonicalKey !== "" &&
|
|
190
|
+
storedCanonicalKey === canonicalKey
|
|
191
|
+
? "canonical_key"
|
|
192
|
+
: null;
|
|
193
|
+
if (matchedBy === null)
|
|
182
194
|
continue;
|
|
183
195
|
found.push({
|
|
184
196
|
relationship: { type, from: requirementId, to: target },
|
|
185
197
|
factId: target,
|
|
186
198
|
factKind: unquoted(fact.bindings.FactKind) || null,
|
|
187
|
-
claimKey,
|
|
199
|
+
claimKey: storedClaimKey,
|
|
200
|
+
canonicalKey: storedCanonicalKey || null,
|
|
201
|
+
matchedBy,
|
|
188
202
|
});
|
|
189
203
|
}
|
|
190
204
|
}
|
|
@@ -324,11 +338,30 @@ export async function handleKbSuggestPredicates(prolog, args, context) {
|
|
|
324
338
|
// Stage 3/4: bind only after eligibility, then decide conservatively.
|
|
325
339
|
const unavailableSchema = Boolean(args.schemaId && selectedSchemas.length === 0);
|
|
326
340
|
const claimKey = semanticClaimKey(text);
|
|
327
|
-
const existingGrounding = await existingClaimGrounding(prolog, args.requirementId, claimKey, warnings);
|
|
341
|
+
const existingGrounding = await existingClaimGrounding(prolog, args.requirementId, claimKey, recommendedCandidate?.canonical_key ?? null, warnings);
|
|
328
342
|
const alreadyGrounded = existingGrounding.length > 0;
|
|
343
|
+
// implements REQ-model-predicates-grounding-guards
|
|
344
|
+
// The requirement already grounds the very predicate tuple the candidate
|
|
345
|
+
// names (in other words, or the same text again): nothing to write or
|
|
346
|
+
// swap, whatever the candidate's binding status.
|
|
347
|
+
const sameTupleGrounding = existingGrounding.filter((row) => recommendedCandidate !== undefined &&
|
|
348
|
+
row.canonicalKey !== null &&
|
|
349
|
+
row.canonicalKey === recommendedCandidate.canonical_key);
|
|
350
|
+
const keepExistingGrounding = sameTupleGrounding.length > 0;
|
|
329
351
|
const completeCandidate = recommendedCandidate && recommendedCandidate.binding_status === "complete"
|
|
330
352
|
? recommendedCandidate
|
|
331
353
|
: undefined;
|
|
354
|
+
// The stored requirement and its proposition ledger, read once for the
|
|
355
|
+
// ledger guard, the replacement plan and the hash-bound plan.
|
|
356
|
+
const storedRequirement = prolog !== null && context !== undefined && args.requirementId
|
|
357
|
+
? await storedRequirementContract(prolog, args.requirementId, warnings)
|
|
358
|
+
: null;
|
|
359
|
+
const ledger = ledgerState(storedRequirement, claimKey);
|
|
360
|
+
// A requirement grounds only the propositions its prose states, so a
|
|
361
|
+
// claim its ledger does not carry cannot be linked to it: the predicate
|
|
362
|
+
// fact would be written and stay unlinked. The requirement's prose has to
|
|
363
|
+
// be extended first.
|
|
364
|
+
const ledgerMissing = ledger === "missing" && completeCandidate !== undefined && !alreadyGrounded;
|
|
332
365
|
// implements REQ-model-predicates-participant-not-subject
|
|
333
366
|
// A schema whose participant argument (actor, role, owner) the claim never
|
|
334
367
|
// names does not fit the claim: no binding the agent could supply would be
|
|
@@ -350,13 +383,17 @@ export async function handleKbSuggestPredicates(prolog, args, context) {
|
|
|
350
383
|
? unavailableSchema
|
|
351
384
|
? "resolve_schema_reference"
|
|
352
385
|
: "record_ontology_gap"
|
|
353
|
-
:
|
|
354
|
-
?
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
386
|
+
: keepExistingGrounding
|
|
387
|
+
? "keep_existing_grounding"
|
|
388
|
+
: completeCandidate
|
|
389
|
+
? alreadyGrounded
|
|
390
|
+
? "replace_grounding"
|
|
391
|
+
: ledgerMissing
|
|
392
|
+
? "extend_requirement"
|
|
393
|
+
: "apply_requires_predicate"
|
|
394
|
+
: schemaDoesNotFit
|
|
395
|
+
? "record_ontology_gap"
|
|
396
|
+
: "provide_argument_bindings";
|
|
360
397
|
const predicatePlan = completeCandidate
|
|
361
398
|
? buildPredicateApplyPlan(completeCandidate, args)
|
|
362
399
|
: [];
|
|
@@ -365,18 +402,23 @@ export async function handleKbSuggestPredicates(prolog, args, context) {
|
|
|
365
402
|
// replacement plan below swaps the grounding instead. The ontology-gap
|
|
366
403
|
// observation is not a grounding relationship, so it is planned either way.
|
|
367
404
|
const applyPlan = completeCandidate
|
|
368
|
-
? alreadyGrounded
|
|
405
|
+
? alreadyGrounded || ledgerMissing
|
|
369
406
|
? []
|
|
370
407
|
: predicatePlan
|
|
371
408
|
: (!recommendedCandidate && !unavailableSchema) || schemaDoesNotFit
|
|
372
409
|
? buildGapApplyPlan(text, args)
|
|
373
410
|
: [];
|
|
374
411
|
const plannedFactId = typeof predicatePlan[0]?.id === "string" ? predicatePlan[0].id : null;
|
|
375
|
-
const relationshipPlan = completeCandidate && !alreadyGrounded
|
|
412
|
+
const relationshipPlan = completeCandidate && !alreadyGrounded && !ledgerMissing
|
|
376
413
|
? buildRelationshipPlan(plannedFactId ?? "", args.requirementId, text, args.existingLogicClaims)
|
|
377
414
|
: null;
|
|
378
|
-
const replacementPlan = alreadyGrounded &&
|
|
379
|
-
|
|
415
|
+
const replacementPlan = alreadyGrounded &&
|
|
416
|
+
!keepExistingGrounding &&
|
|
417
|
+
plannedFactId !== null &&
|
|
418
|
+
args.requirementId
|
|
419
|
+
? buildGroundingReplacementPlan(args.requirementId, plannedFactId, predicatePlan, existingGrounding, storedRequirement !== null
|
|
420
|
+
? restatedRequirementFields(storedRequirement)
|
|
421
|
+
: await storedRequirementProperties(prolog, args.requirementId, warnings))
|
|
380
422
|
: null;
|
|
381
423
|
const relationshipTarget = relationshipPlan !== null || replacementPlan !== null
|
|
382
424
|
? plannedFactId
|
|
@@ -384,9 +426,18 @@ export async function handleKbSuggestPredicates(prolog, args, context) {
|
|
|
384
426
|
const groundingSummary = existingGrounding
|
|
385
427
|
.map((row) => `${row.relationship.type} -> ${row.factId}`)
|
|
386
428
|
.join(", ");
|
|
387
|
-
|
|
429
|
+
const sameTupleSummary = sameTupleGrounding
|
|
430
|
+
.map((row) => `${row.relationship.type} -> ${row.factId}${row.matchedBy === "canonical_key" ? ` (matched by canonical_key; its claim_key ${row.claimKey} differs from this text's ${claimKey})` : ""}`)
|
|
431
|
+
.join(", ");
|
|
432
|
+
if (keepExistingGrounding) {
|
|
433
|
+
warnings.push(`${args.requirementId} already grounds the predicate ${recommendedCandidate?.canonical_key} through ${sameTupleSummary}. Keep that grounding: no fact or link is needed. If this text is a further proposition of the requirement, extend its prose and run kb_model mode analyze before grounding it separately.`);
|
|
434
|
+
}
|
|
435
|
+
else if (alreadyGrounded) {
|
|
388
436
|
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."}`);
|
|
389
437
|
}
|
|
438
|
+
if (ledger === "missing" && !alreadyGrounded && recommendedCandidate) {
|
|
439
|
+
warnings.push(`The proposition ledger of ${args.requirementId} has no claim ${claimKey} for this text, so the requirement cannot ground it: a requirement grounds only the propositions its prose states. ${ledgerMissing ? "No fact was planned, because it would be written without a link. " : ""}Extend the requirement's prose with this clause (kb_model mode requirement, or kb_upsert with the extended semantic_text and the ledger kb_model mode analyze returns), then call mode predicates again.`);
|
|
440
|
+
}
|
|
390
441
|
// The hints stay on a schema that does not fit, so the agent can see which
|
|
391
442
|
// participant the claim would have to name.
|
|
392
443
|
const bindingHints = (recommendedAction === "provide_argument_bindings" || schemaDoesNotFit) &&
|
|
@@ -399,23 +450,27 @@ export async function handleKbSuggestPredicates(prolog, args, context) {
|
|
|
399
450
|
const recommendedPredicateSchema = !recommendedCandidate && !unavailableSchema
|
|
400
451
|
? buildPredicateSchemaDraft(text, subject)
|
|
401
452
|
: null;
|
|
402
|
-
const groundedPrefix = alreadyGrounded
|
|
453
|
+
const groundedPrefix = alreadyGrounded && !keepExistingGrounding
|
|
403
454
|
? `${args.requirementId} already grounds this claim through ${groundingSummary}. `
|
|
404
455
|
: "";
|
|
405
456
|
const textSummary = groundedPrefix +
|
|
406
|
-
(
|
|
407
|
-
?
|
|
408
|
-
:
|
|
409
|
-
? `
|
|
410
|
-
:
|
|
411
|
-
? `Matched ${
|
|
412
|
-
:
|
|
413
|
-
? `
|
|
414
|
-
:
|
|
415
|
-
? `
|
|
416
|
-
:
|
|
417
|
-
?
|
|
418
|
-
:
|
|
457
|
+
(keepExistingGrounding
|
|
458
|
+
? `${args.requirementId} already grounds ${recommendedCandidate?.canonical_key} through ${sameTupleSummary}. Nothing to apply; keep that grounding.`
|
|
459
|
+
: replacementPlan
|
|
460
|
+
? `To use ${completeCandidate?.predicate_name} instead, follow replacementPlan and link requires_predicate to ${plannedFactId}; otherwise keep the existing grounding.`
|
|
461
|
+
: ledgerMissing && completeCandidate
|
|
462
|
+
? `Matched ${completeCandidate.predicate_name} as ${completeCandidate.canonical_key}, but ${args.requirementId} does not state this claim (its ledger has no ${claimKey}). Extend the requirement's prose with this clause first; no fact or link was planned.`
|
|
463
|
+
: completeCandidate
|
|
464
|
+
? `Suggested ${candidates.length} predicate candidate(s). Top applicable match: ${completeCandidate.predicate_name}. Apply the predicate fact ${plannedFactId}, then link requires_predicate to that fact id (not a candidate id).`
|
|
465
|
+
: schemaDoesNotFit && recommendedCandidate
|
|
466
|
+
? `Matched ${recommendedCandidate.predicate_name}, but the claim names no ${unnamedParticipants.join(" or ")} (${describeBindingHints(bindingHints)}), so this schema does not fit the claim. Record the ontology-gap observation in applyPlan instead of inventing a participant; a predicate_schema whose arguments the claim names would fit.`
|
|
467
|
+
: recommendedCandidate
|
|
468
|
+
? `Matched ${recommendedCandidate.predicate_name}, but exact reviewed values are still required for: ${recommendedCandidate.unbound_arguments.join(", ")}. Bind them from the claim text: ${describeBindingHints(bindingHints)}. A value that repeats an argument name or a stop word stays unbound. No apply plan was generated.`
|
|
469
|
+
: unavailableSchema
|
|
470
|
+
? `Requested predicate schema ${args.schemaId} is unavailable or semantically inapplicable. No apply plan was generated.`
|
|
471
|
+
: alreadyGrounded
|
|
472
|
+
? "No predicate candidate passed the semantic applicability gate; keep the existing grounding and record the ontology-gap observation in applyPlan so the missing schema stays visible."
|
|
473
|
+
: "No predicate candidate passed the semantic applicability gate; record an ontology gap and review the generated schema draft instead of silently writing prose.");
|
|
419
474
|
const logicClaims = Array.from(new Set([...(args.existingLogicClaims ?? []), claimKey]));
|
|
420
475
|
const plan = relationshipPlan !== null && plannedFactId !== null && args.requirementId
|
|
421
476
|
? await groundingPlan(prolog, context, {
|
|
@@ -425,9 +480,21 @@ export async function handleKbSuggestPredicates(prolog, args, context) {
|
|
|
425
480
|
factStep: predicatePlan[0] ?? {},
|
|
426
481
|
relationship: relationshipPlan.relationship,
|
|
427
482
|
logicClaims,
|
|
483
|
+
stored: storedRequirement,
|
|
428
484
|
warnings,
|
|
429
485
|
})
|
|
430
486
|
: null;
|
|
487
|
+
// Without a plan nothing ran the contradiction analysis, so the decision
|
|
488
|
+
// conflicts a complete candidate would introduce are looked up directly.
|
|
489
|
+
const decisionConflicts = plan === null &&
|
|
490
|
+
completeCandidate !== undefined &&
|
|
491
|
+
!keepExistingGrounding &&
|
|
492
|
+
args.requirementId
|
|
493
|
+
? await candidateDecisionConflicts(prolog, completeCandidate, warnings)
|
|
494
|
+
: [];
|
|
495
|
+
for (const conflict of decisionConflicts) {
|
|
496
|
+
warnings.push(`The proposed ${conflict.canonicalKey} (${conflict.proposedEffect}) contradicts ${conflict.factId} (${conflict.effect}) under ${conflict.requirementId}${conflict.requirementId === args.requirementId ? ", the requirement this claim would ground" : ""}: both decide ${completeCandidate?.predicate_name} on the same key arguments. kb_upsert refuses a grounding link that introduces this conflict; supersede or close the conflicting requirement, or correct the decision, before applying.`);
|
|
497
|
+
}
|
|
431
498
|
return {
|
|
432
499
|
content: [{ type: "text", text: textSummary }],
|
|
433
500
|
structuredContent: {
|
|
@@ -445,6 +512,7 @@ export async function handleKbSuggestPredicates(prolog, args, context) {
|
|
|
445
512
|
plan,
|
|
446
513
|
relationshipTarget,
|
|
447
514
|
existingGrounding,
|
|
515
|
+
decisionConflicts,
|
|
448
516
|
replacementPlan,
|
|
449
517
|
bindingHints,
|
|
450
518
|
warnings,
|
|
@@ -452,6 +520,67 @@ export async function handleKbSuggestPredicates(prolog, args, context) {
|
|
|
452
520
|
applyPlan,
|
|
453
521
|
};
|
|
454
522
|
}
|
|
523
|
+
/**
|
|
524
|
+
* Whether the stored requirement's proposition ledger carries the claim:
|
|
525
|
+
* "unknown" when the requirement or its ledger is not readable.
|
|
526
|
+
*/
|
|
527
|
+
// implements REQ-model-predicates-grounding-guards
|
|
528
|
+
function ledgerState(stored, claimKey) {
|
|
529
|
+
if (stored === null || !Array.isArray(stored.semantic_inventory))
|
|
530
|
+
return "unknown";
|
|
531
|
+
return stored.semantic_inventory.some((row) => row !== null &&
|
|
532
|
+
typeof row === "object" &&
|
|
533
|
+
row.claim_key === claimKey)
|
|
534
|
+
? "present"
|
|
535
|
+
: "missing";
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Stored decision-predicate facts of current requirements that agree with
|
|
539
|
+
* the candidate on every key argument and decide the opposite: the pairs
|
|
540
|
+
* the domain-contradictions rule would report once the candidate is linked.
|
|
541
|
+
*/
|
|
542
|
+
// implements REQ-model-predicates-grounding-guards
|
|
543
|
+
async function candidateDecisionConflicts(prolog, candidate, warnings) {
|
|
544
|
+
if (prolog === null)
|
|
545
|
+
return [];
|
|
546
|
+
if (candidate.predicate_args.length === 0 ||
|
|
547
|
+
candidate.predicate_args.some((value) => !value))
|
|
548
|
+
return [];
|
|
549
|
+
const candidateArgs = `[${candidate.predicate_args
|
|
550
|
+
.map((value) => `'${escapeAtom(value)}'`)
|
|
551
|
+
.join(",")}]`;
|
|
552
|
+
try {
|
|
553
|
+
const result = await prolog.query(`findall(Row, (kb:decision_signatures(_Signatures), memberchk(decision_signature(${candidate.schema.predicate_namespace ? `'${escapeAtom(candidate.schema.predicate_namespace)}'` : "_Namespace"}, '${escapeAtom(candidate.predicate_name)}', ${candidate.predicate_args.length}, _KeyPositions, _DecisionPosition), _Signatures), nth1(_DecisionPosition, ${candidateArgs}, _ProposedDecision), kb:effective_decision(_ProposedDecision, ${candidate.polarity}, _ProposedEffect), kb:decision_req_fact(_Signatures, _Req, _Fact, ${candidate.schema.predicate_namespace ? `'${escapeAtom(candidate.schema.predicate_namespace)}'` : "_Namespace"}, '${escapeAtom(candidate.predicate_name)}', _Args, _Polarity, _KeyPositions, _DecisionPosition), kb:bind_key_arguments(_KeyPositions, ${candidateArgs}, _Args), nth1(_DecisionPosition, _Args, _Decision), kb:effective_decision(_Decision, _Polarity, _Effect), _Effect \\== _ProposedEffect, atomic_list_concat([_Req, _Fact, _Effect, _ProposedEffect], '|', Row)), Rows)`);
|
|
554
|
+
if (!result.success)
|
|
555
|
+
return [];
|
|
556
|
+
const conflicts = [];
|
|
557
|
+
for (const row of parsePrologList(result.bindings.Rows ?? "[]")) {
|
|
558
|
+
const [requirementId, factId, effect, proposedEffect] = row.split("|");
|
|
559
|
+
if (!requirementId || !factId || !effect || !proposedEffect)
|
|
560
|
+
continue;
|
|
561
|
+
conflicts.push({
|
|
562
|
+
requirementId,
|
|
563
|
+
factId,
|
|
564
|
+
effect,
|
|
565
|
+
proposedEffect,
|
|
566
|
+
canonicalKey: candidate.canonical_key,
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
return conflicts.sort((left, right) => `${left.requirementId}|${left.factId}`.localeCompare(`${right.requirementId}|${right.factId}`));
|
|
570
|
+
}
|
|
571
|
+
catch (error) {
|
|
572
|
+
warnings.push(`Decision conflicts for ${candidate.canonical_key} could not be read (${error instanceof Error ? error.message : String(error)}); preview the grounding with kb_upsert dryRun and plannedFacts before applying.`);
|
|
573
|
+
return [];
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
/** The stored requirement fields a relationship-only update must restate. */
|
|
577
|
+
function restatedRequirementFields(stored) {
|
|
578
|
+
const restated = {};
|
|
579
|
+
for (const field of RESTATED_REQUIREMENT_FIELDS)
|
|
580
|
+
if (stored[field] !== undefined && stored[field] !== null)
|
|
581
|
+
restated[field] = stored[field];
|
|
582
|
+
return restated;
|
|
583
|
+
}
|
|
455
584
|
/**
|
|
456
585
|
* Why the recommended predicate is not offered for grounding: it is not about
|
|
457
586
|
* a subject the requirement constrains, so kb_check would keep reporting
|
|
@@ -484,7 +613,7 @@ const RESTATED_REQUIREMENT_FIELDS = [
|
|
|
484
613
|
async function groundingPlan(prolog, context, input) {
|
|
485
614
|
if (prolog === null || context === undefined)
|
|
486
615
|
return null;
|
|
487
|
-
const stored =
|
|
616
|
+
const stored = input.stored === null ? null : { ...input.stored };
|
|
488
617
|
if (stored === null) {
|
|
489
618
|
input.warnings.push(`No hash-bound plan: requirement ${input.requirementId} is not stored, so its upsert step cannot restate the stored title and status. Apply applyPlan and relationshipPlan with kb_upsert.`);
|
|
490
619
|
return null;
|
|
@@ -521,7 +650,17 @@ async function groundingPlan(prolog, context, input) {
|
|
|
521
650
|
{
|
|
522
651
|
type: "req",
|
|
523
652
|
id: input.requirementId,
|
|
524
|
-
|
|
653
|
+
// The manifest must name every assertive ledger claim, so the
|
|
654
|
+
// stored manifest is kept and this claim merged into it.
|
|
655
|
+
properties: {
|
|
656
|
+
...stored,
|
|
657
|
+
logic_claims: Array.from(new Set([
|
|
658
|
+
...(Array.isArray(stored.logic_claims)
|
|
659
|
+
? stored.logic_claims.filter((claim) => typeof claim === "string")
|
|
660
|
+
: []),
|
|
661
|
+
...input.logicClaims,
|
|
662
|
+
])),
|
|
663
|
+
},
|
|
525
664
|
relationships: [input.relationship],
|
|
526
665
|
},
|
|
527
666
|
],
|
|
@@ -550,6 +689,7 @@ const STORED_LEDGER_FIELDS = [
|
|
|
550
689
|
"semantic_inventory_version",
|
|
551
690
|
"semantic_source_field",
|
|
552
691
|
"semantic_source_hash",
|
|
692
|
+
"logic_claims",
|
|
553
693
|
];
|
|
554
694
|
// implements REQ-model-what-if-planned-facts
|
|
555
695
|
/**
|
|
@@ -3,6 +3,10 @@ import type { OperationResult } from "../../public/operations/types.js";
|
|
|
3
3
|
import { type RelationshipSelector } from "../../relationships/shards.js";
|
|
4
4
|
import type { DeleteInput, DeletePayload } from "./types.js";
|
|
5
5
|
export declare function assertFilesystemCapableRuntime(fs: OperationContext["fs"]): asserts fs is NonNullable<OperationContext["fs"]>;
|
|
6
|
-
|
|
6
|
+
type DeleteExecutionOptions = Readonly<{
|
|
7
|
+
dryRun?: boolean;
|
|
8
|
+
}>;
|
|
9
|
+
export declare function executeRelationshipDelete(selectors: readonly RelationshipSelector[], context: OperationContext, onCommitted?: () => void, options?: DeleteExecutionOptions): Promise<DeletePayload>;
|
|
7
10
|
export declare function executeDelete(input: DeleteInput, context: OperationContext): Promise<OperationResult<DeletePayload>>;
|
|
11
|
+
export {};
|
|
8
12
|
//# sourceMappingURL=delete.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/delete.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EACL,KAAK,oBAAoB,
|
|
1
|
+
{"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/delete.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EACL,KAAK,oBAAoB,EAO1B,MAAM,+BAA+B,CAAC;AAqBvC,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAc7D,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,gBAAgB,CAAC,IAAI,CAAC,GACzB,OAAO,CAAC,EAAE,IAAI,WAAW,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAMnD;AA2CD,KAAK,sBAAsB,GAAG,QAAQ,CAAC;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAwZ7D,wBAAsB,yBAAyB,CAC7C,SAAS,EAAE,SAAS,oBAAoB,EAAE,EAC1C,OAAO,EAAE,gBAAgB,EACzB,WAAW,GAAE,MAAM,IAAsB,EACzC,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,aAAa,CAAC,CAkCxB;AAoHD,wBAAsB,aAAa,CACjC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC,CAkXzC"}
|