kibi-runtime 2.13.1 → 2.13.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.
@@ -102,7 +102,7 @@ function manifestVersion(manifestPath, expectedName) {
102
102
  }
103
103
  function cliVersion() {
104
104
  if (true)
105
- return "2.16.0";
105
+ return "2.17.0";
106
106
  return manifestVersion(path.join(moduleDirectory, "..", "package.json"), "kibi-cli") ?? "unknown";
107
107
  }
108
108
  function coreVersion() {
package/dist/index.js CHANGED
@@ -6757,7 +6757,7 @@ function manifestVersion(manifestPath, expectedName) {
6757
6757
  }
6758
6758
  function cliVersion() {
6759
6759
  if (true)
6760
- return "2.16.0";
6760
+ return "2.17.0";
6761
6761
  return manifestVersion(path2.join(moduleDirectory, "..", "package.json"), "kibi-cli") ?? "unknown";
6762
6762
  }
6763
6763
  function coreVersion() {
@@ -13780,7 +13780,7 @@ async function executeStatus(_input, context) {
13780
13780
  const enrichedPayload = {
13781
13781
  ...payload,
13782
13782
  ...compilerReason ? { syncState: "stale", dirty: true } : {},
13783
- ...storeUncompiled && store.state === "healthy" ? { syncState: "stale", dirty: true } : {},
13783
+ ...storeUncompiled ? { syncState: "stale", dirty: true } : {},
13784
13784
  branchAttachment: attachment,
13785
13785
  branchStore: store,
13786
13786
  ...engineStatus ? { engineStatus } : {},
@@ -14087,10 +14087,21 @@ function sourceOf(payload) {
14087
14087
  function normalizeKey(value) {
14088
14088
  return value.trim().toLowerCase().replace(/['’]/g, "").replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
14089
14089
  }
14090
- function singularize(value) {
14091
- if (["status", "results"].includes(value))
14090
+ function singularizeToken(value, keep = []) {
14091
+ if (value.length <= 3 || keep.includes(value))
14092
+ return value;
14093
+ if (value.endsWith("ies") && value.length > 4) {
14094
+ return `${value.slice(0, -3)}y`;
14095
+ }
14096
+ if (ES_PLURAL_SUFFIXES.some((suffix) => value.endsWith(suffix))) {
14097
+ return value.slice(0, -2);
14098
+ }
14099
+ if (!value.endsWith("s") || /(?:ss|us|is)$/.test(value))
14092
14100
  return value;
14093
- return value.endsWith("s") && value.length > 3 ? value.slice(0, -1) : value;
14101
+ return value.slice(0, -1);
14102
+ }
14103
+ function singularize(value) {
14104
+ return singularizeToken(value, ["status", "results"]);
14094
14105
  }
14095
14106
  function normalizeSubjectKey(value) {
14096
14107
  return normalizeKey(value).split("_").map(singularize).join(".");
@@ -14220,9 +14231,10 @@ function predicateSuggestion(payload, evidence, name, args, rationale, polarity
14220
14231
  } : null
14221
14232
  };
14222
14233
  }
14223
- var SEMANTIC_INVENTORY_VERSION = "kibi.semantic-inventory.v1";
14234
+ var SEMANTIC_INVENTORY_VERSION = "kibi.semantic-inventory.v1", ES_PLURAL_SUFFIXES;
14224
14235
  var init_shared = __esm(() => {
14225
14236
  init_clauses();
14237
+ ES_PLURAL_SUFFIXES = ["ches", "shes", "sses", "xes"];
14226
14238
  });
14227
14239
 
14228
14240
  // ../cli/dist/operations/semantic-advisor/ingestion-boundary.js
@@ -43374,13 +43386,34 @@ function coverageForRequirement(result, manifestResults, entities) {
43374
43386
  scenarioTests
43375
43387
  };
43376
43388
  }
43389
+ function supersededRequirementIds(manifestResults) {
43390
+ return new Set(manifestResults.flatMap((result) => result.entity.type === "req" ? result.relationships.flatMap((relationship) => relationship.type === "supersedes" ? [relationship.to] : []) : []));
43391
+ }
43392
+ function isReviewableRequirement(requirement, superseded) {
43393
+ if (superseded.has(requirement.id))
43394
+ return false;
43395
+ const status = requirement.status.trim().toLowerCase();
43396
+ if (REVIEWED_REQUIREMENT_STATUSES.has(status))
43397
+ return true;
43398
+ return status === "closed" && (requirement.tags ?? []).includes("implemented");
43399
+ }
43377
43400
  function createCoverageDepthQualityDiagnostics(manifestResults, proofByRequirement = new Map) {
43378
43401
  const entities = entitiesById(manifestResults);
43379
- return manifestResults.filter((result) => result.entity.type === "req").flatMap((result) => {
43402
+ const superseded = supersededRequirementIds(manifestResults);
43403
+ return manifestResults.filter((result) => result.entity.type === "req" && isReviewableRequirement(result.entity, superseded)).flatMap((result) => {
43380
43404
  const diagnostic = createDiagnostic(coverageForRequirement(result, manifestResults, entities), proofByRequirement.get(result.entity.id));
43381
43405
  return diagnostic === undefined ? [] : [diagnostic];
43382
43406
  }).toSorted((left, right) => (left.entityId ?? "").localeCompare(right.entityId ?? ""));
43383
43407
  }
43408
+ var REVIEWED_REQUIREMENT_STATUSES;
43409
+ var init_coverage_depth_quality = __esm(() => {
43410
+ REVIEWED_REQUIREMENT_STATUSES = new Set([
43411
+ "open",
43412
+ "in_progress",
43413
+ "active",
43414
+ "approved"
43415
+ ]);
43416
+ });
43384
43417
 
43385
43418
  // ../cli/dist/public/impact/requirement-quality.js
43386
43419
  function isRequirement2(result) {
@@ -44053,6 +44086,7 @@ var init_full_kb_quality = __esm(() => {
44053
44086
  init_proof_receipt();
44054
44087
  init_relationship();
44055
44088
  init_telemetry_acceptance();
44089
+ init_coverage_depth_quality();
44056
44090
  init_requirement_quality();
44057
44091
  init_symbol_quality();
44058
44092
  RELATIONSHIP_TYPES = relationship_default.properties.type.enum;
@@ -55597,9 +55631,7 @@ function normalizePredicateToken(value) {
55597
55631
  return value.trim().replace(/\b(?:a|an|the)\b\s*/gi, "").replace(/['’]/g, "").replace(/\s+/g, "_").replace(/[^A-Za-z0-9_-]+/g, "_").replace(/^_+|_+$/g, "");
55598
55632
  }
55599
55633
  function singularize2(value) {
55600
- if (["changes", "status", "results"].includes(value))
55601
- return value;
55602
- return value.endsWith("s") && value.length > 3 ? value.slice(0, -1) : value;
55634
+ return singularizeToken(value, ["changes", "status", "results"]);
55603
55635
  }
55604
55636
  function normalizeSubjectKey3(value) {
55605
55637
  return slug2(value).split("_").map(singularize2).join(".");
@@ -55671,7 +55703,9 @@ function inferEvent(text) {
55671
55703
  return eventName ?? "domain_event";
55672
55704
  }
55673
55705
  var DEFAULT_MIN_SCORE = 0.35;
55674
- var init_predicate_utils = () => {};
55706
+ var init_predicate_utils = __esm(() => {
55707
+ init_shared();
55708
+ });
55675
55709
 
55676
55710
  // ../cli/dist/operations/modeling/predicate-ranker.js
55677
55711
  function tokens3(value) {
@@ -56016,7 +56050,10 @@ var init_predicate_applicability = __esm(() => {
56016
56050
  permission_rule: {
56017
56051
  allOf: [
56018
56052
  [/only|may|can|allowed|denied|forbidden|must\s+not|cannot/i],
56019
- [/delete|export|access|read|write|update|remove|manage|permission/i]
56053
+ [
56054
+ /delete|export|access|read|write|update|remove|manage|permission/i,
56055
+ /\b(?:may|can|cannot|can't|must\s+(?:not|never)|never|(?:is|are)\s+(?:not\s+)?(?:allowed|permitted|forbidden)\s+to)\s+(?:only\s+)?(?:publish|unpublish|approve|assign|view|see|edit|modify|create|submit|share|invite|upload|download|comment|post|complete|archive|restore|grant|revoke|purchase|cancel|execute|invoke|configure|moderate|ban|join|book|reserve|transfer|close|reopen|merge)\b/i
56056
+ ]
56020
56057
  ]
56021
56058
  },
56022
56059
  resource_constraint: {
@@ -74965,6 +75002,17 @@ var init_cli_operation_metadata = __esm(() => {
74965
75002
  // ../cli/dist/cli-validate.js
74966
75003
  var init_cli_validate = () => {};
74967
75004
 
75005
+ // ../cli/dist/operations/planning/migration-refusal.js
75006
+ var MigrationActionRefusedError, MIGRATION_PLAN_REFUSED = "MIGRATION_PLAN_REFUSED";
75007
+ var init_migration_refusal = __esm(() => {
75008
+ MigrationActionRefusedError = class MigrationActionRefusedError extends Error {
75009
+ constructor(message) {
75010
+ super(message);
75011
+ this.name = "MigrationActionRefusedError";
75012
+ }
75013
+ };
75014
+ });
75015
+
74968
75016
  // ../cli/dist/public/operations/result-envelope.js
74969
75017
  function record4(value) {
74970
75018
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -75056,23 +75104,33 @@ function extraFailedEffects(declared, data) {
75056
75104
  function resultVersion(spec) {
75057
75105
  return spec.resultVersion ?? `kibi.${spec.name}.v1`;
75058
75106
  }
75107
+ function refusalDetail(row) {
75108
+ const results = Array.isArray(row.actionResults) ? row.actionResults : [];
75109
+ const failure = results.find((entry) => record4(entry) && entry.outcome === "failed");
75110
+ return record4(failure) && typeof failure.detail === "string" ? failure.detail : "";
75111
+ }
75059
75112
  function toKibiResult(spec, data, options2 = {}) {
75060
75113
  const row = record4(data) ? data : undefined;
75114
+ const migrationRefused = row?.version === "kibi.migration-apply-result.v1" && row.outcome === "refused";
75061
75115
  let status = options2.status;
75062
75116
  if (!status) {
75063
75117
  status = "success";
75064
75118
  if (row?.status === "committed_with_repairs")
75065
75119
  status = "committed_with_repairs";
75066
- if (row?.status === "rejected")
75120
+ if (row?.status === "rejected" || migrationRefused)
75067
75121
  status = "error";
75068
75122
  }
75069
75123
  const terminalError = row?.status === "rejected" ? {
75070
75124
  code: "BOOTSTRAP_PLAN_REJECTED",
75071
75125
  message: "Bootstrap stopped at a deterministic failure. Inspect actionResults for committed actions and re-plan from the current state.",
75072
75126
  retryable: false
75127
+ } : migrationRefused ? {
75128
+ code: MIGRATION_PLAN_REFUSED,
75129
+ message: `Migration plan refused; nothing was changed. ${refusalDetail(row)}`.trim(),
75130
+ retryable: false
75073
75131
  } : undefined;
75074
75132
  const resultError = options2.error ?? terminalError;
75075
- const outcome = effectOutcome(status, options2);
75133
+ const outcome = effectOutcome(status, migrationRefused && options2.attempted === undefined ? { ...options2, attempted: false } : options2);
75076
75134
  return {
75077
75135
  kibiProtocol: KIBI_PROTOCOL_VERSION,
75078
75136
  operation: spec.name,
@@ -75121,6 +75179,9 @@ function appendPayloadCountField(fields, countKey, noun, payload) {
75121
75179
  fields.result_summary = count === null ? `${noun} count unavailable` : `${count} ${noun}`;
75122
75180
  }
75123
75181
  var KIBI_PROTOCOL_VERSION = 1;
75182
+ var init_result_envelope = __esm(() => {
75183
+ init_migration_refusal();
75184
+ });
75124
75185
 
75125
75186
  // ../cli/dist/cli-protocol.js
75126
75187
  var import__2020, outputValidator;
@@ -75130,6 +75191,7 @@ var init_cli_protocol = __esm(() => {
75130
75191
  init_cli_operation_metadata();
75131
75192
  init_cli_validate();
75132
75193
  init_engine_limits();
75194
+ init_result_envelope();
75133
75195
  init_detached_snapshot();
75134
75196
  import__2020 = __toESM(require__2020(), 1);
75135
75197
  outputValidator = new import__2020.default({ strict: false, allErrors: true });
@@ -75138,6 +75200,7 @@ var init_cli_protocol = __esm(() => {
75138
75200
  // ../cli/dist/public/diagnostic-usage.js
75139
75201
  var RECEIPT_GAP_CODES;
75140
75202
  var init_diagnostic_usage = __esm(() => {
75203
+ init_result_envelope();
75141
75204
  RECEIPT_GAP_CODES = new Set([
75142
75205
  "missing_proof_receipt",
75143
75206
  "stale_proof_receipt",
@@ -76010,32 +76073,32 @@ function applyProofIntegrationAction(action, root) {
76010
76073
  const evidence = action.evidence;
76011
76074
  const integration = evidence.integration;
76012
76075
  if (evidence.path !== PROOF_INTEGRATIONS_PATH || evidence.mode !== "create" && evidence.mode !== "update" || !isRecord22(integration) || typeof integration.id !== "string")
76013
- throw new Error(`Proof integration action '${action.id}' is malformed; rerun kibi proof inspect for a new plan.`);
76076
+ throw new MigrationActionRefusedError(`Proof integration action '${action.id}' is malformed; rerun kibi proof inspect for a new plan.`);
76014
76077
  const planned = isRecord22(evidence.sourceHashes) ? evidence.sourceHashes : {};
76015
76078
  const live = sourceHashes(root);
76016
76079
  const changed = [
76017
76080
  ...new Set([...Object.keys(planned), ...Object.keys(live)])
76018
76081
  ].filter((file) => planned[file] !== live[file]);
76019
76082
  if (changed.length > 0)
76020
- throw new Error(`Proof integration plan refused: ${changed.join(", ")} changed since planning; rerun kibi proof inspect and review the new plan.`);
76083
+ throw new MigrationActionRefusedError(`Proof integration plan refused: ${changed.join(", ")} changed since planning; rerun kibi proof inspect and review the new plan.`);
76021
76084
  const filePath = integrationsPath(root);
76022
76085
  let integrations;
76023
76086
  if (evidence.mode === "create") {
76024
76087
  if (existsSync42(filePath))
76025
- throw new Error(`Proof integration plan refused: ${PROOF_INTEGRATIONS_PATH} already exists and this plan only creates it. Run kibi proof inspect --update <integration id> for a plan that adds or replaces one named integration.`);
76088
+ throw new MigrationActionRefusedError(`Proof integration plan refused: ${PROOF_INTEGRATIONS_PATH} already exists and this plan only creates it. Run kibi proof inspect --update <integration id> for a plan that adds or replaces one named integration.`);
76026
76089
  integrations = [integration];
76027
76090
  } else {
76028
76091
  if (fileHash3(filePath) !== evidence.previousFileHash)
76029
- throw new Error(`Proof integration plan refused: ${PROOF_INTEGRATIONS_PATH} changed since planning; rerun kibi proof inspect --update ${integration.id}.`);
76092
+ throw new MigrationActionRefusedError(`Proof integration plan refused: ${PROOF_INTEGRATIONS_PATH} changed since planning; rerun kibi proof inspect --update ${integration.id}.`);
76030
76093
  const current = readIntegrationsFile(root);
76031
76094
  if (current === null)
76032
- throw new Error(`Proof integration plan refused: ${PROOF_INTEGRATIONS_PATH} is not a valid ${PROOF_INTEGRATION_VERSION} file.`);
76095
+ throw new MigrationActionRefusedError(`Proof integration plan refused: ${PROOF_INTEGRATIONS_PATH} is not a valid ${PROOF_INTEGRATION_VERSION} file.`);
76033
76096
  integrations = current.integrations.some((entry) => entry.id === integration.id) ? current.integrations.map((entry) => entry.id === integration.id ? integration : entry) : [...current.integrations, integration];
76034
76097
  }
76035
76098
  const file = { version: PROOF_INTEGRATION_VERSION, integrations };
76036
76099
  const errors = proofIntegrationErrors(file);
76037
76100
  if (errors.length > 0)
76038
- throw new Error(`Proof integration plan refused: the result would be invalid (${errors.join("; ")}).`);
76101
+ throw new MigrationActionRefusedError(`Proof integration plan refused: the result would be invalid (${errors.join("; ")}).`);
76039
76102
  mkdirSync17(path80.dirname(filePath), { recursive: true });
76040
76103
  const temporary = `${filePath}.${process.pid}.tmp`;
76041
76104
  writeFileSync20(temporary, `${JSON.stringify(file, null, 2)}
@@ -76044,6 +76107,7 @@ function applyProofIntegrationAction(action, root) {
76044
76107
  }
76045
76108
  var PROOF_INTEGRATION_CONFIGURE = "proof_integration_configure", PROPOSAL_SOURCES;
76046
76109
  var init_integration_plan = __esm(() => {
76110
+ init_migration_refusal();
76047
76111
  init_migration_plan();
76048
76112
  init_proof_protocol();
76049
76113
  init_integrations();
@@ -78531,6 +78595,8 @@ async function applyMigrationPlan(args, context, onCommitted = () => {
78531
78595
  }
78532
78596
  const results = [];
78533
78597
  let failed = false;
78598
+ let refusals = 0;
78599
+ let failures = 0;
78534
78600
  for (const action of actions) {
78535
78601
  if (failed) {
78536
78602
  results.push({
@@ -78550,6 +78616,9 @@ async function applyMigrationPlan(args, context, onCommitted = () => {
78550
78616
  });
78551
78617
  } catch (error) {
78552
78618
  failed = true;
78619
+ failures += 1;
78620
+ if (error instanceof MigrationActionRefusedError)
78621
+ refusals += 1;
78553
78622
  results.push({
78554
78623
  actionId: action.id,
78555
78624
  outcome: "failed",
@@ -78596,7 +78665,7 @@ async function applyMigrationPlan(args, context, onCommitted = () => {
78596
78665
  });
78597
78666
  }
78598
78667
  }
78599
- const outcome = failed ? results.some((result) => result.outcome === "applied") ? "partially_applied" : "reconciliation_required" : "applied";
78668
+ const outcome = failed ? results.some((result) => result.outcome === "applied") ? "partially_applied" : failures > 0 && refusals === failures ? "refused" : "reconciliation_required" : "applied";
78600
78669
  const kbState = finalStatus.branchAttachment?.migrationRequired ? "legacy_compat" : finalStatus.syncState === "stale" ? "stale" : finalStatus.dirty ? "dirty" : finalStatus.syncState === "fresh" ? "clean_fresh" : "not_evaluated";
78601
78670
  const snapshotState = finalStatus.proofSnapshotAvailable === false ? "unavailable" : finalStatus.proofSnapshotDirty === true ? "dirty" : finalStatus.proofSnapshotDirty === false ? "fresh" : "not_evaluated";
78602
78671
  const proven = coverageSummary?.proofProven;
@@ -78617,7 +78686,7 @@ async function applyMigrationPlan(args, context, onCommitted = () => {
78617
78686
  ],
78618
78687
  ...remainingPlan !== undefined ? { remainingPlan } : {},
78619
78688
  closeout: {
78620
- taskOutcome: outcome === "applied" ? "complete" : outcome === "reconciliation_required" ? "blocked" : "interim",
78689
+ taskOutcome: outcome === "applied" ? "complete" : outcome === "reconciliation_required" || outcome === "refused" ? "blocked" : "interim",
78621
78690
  kbState,
78622
78691
  snapshotState,
78623
78692
  proofState,
@@ -78628,7 +78697,7 @@ async function applyMigrationPlan(args, context, onCommitted = () => {
78628
78697
  content: [
78629
78698
  {
78630
78699
  type: "text",
78631
- text: `${outcome === "applied" ? "Applied" : "Stopped after"} migration plan ${args.plan.planHash.slice(0, 12)}.`
78700
+ text: outcome === "applied" ? `Applied migration plan ${args.plan.planHash.slice(0, 12)}.` : outcome === "refused" ? `Refused migration plan ${args.plan.planHash.slice(0, 12)}; nothing was changed.` : `Stopped after migration plan ${args.plan.planHash.slice(0, 12)}.`
78632
78701
  }
78633
78702
  ],
78634
78703
  structuredContent: payload
@@ -78703,16 +78772,16 @@ async function applyMigrationAction(action, context) {
78703
78772
  await applySchema6MigrationAction(action, context);
78704
78773
  return;
78705
78774
  }
78706
- throw new Error(`Migration action '${action.code}' has no automatic executor.`);
78775
+ throw new MigrationActionRefusedError(`Migration action '${action.code}' has no automatic executor.`);
78707
78776
  }
78708
78777
  }
78709
78778
  async function applyPredicateSchemaAlignment(action, context) {
78710
78779
  const invocation = action.invocation;
78711
78780
  if (invocation.kind !== "operation" || invocation.name !== "kb_upsert")
78712
- throw new Error("Predicate schema alignment requires its planned kb_upsert invocation.");
78781
+ throw new MigrationActionRefusedError("Predicate schema alignment requires its planned kb_upsert invocation.");
78713
78782
  const input = asUpsert(invocation.input);
78714
78783
  if (input.type !== "fact")
78715
- throw new Error("Predicate schema alignment only rewrites fact entities.");
78784
+ throw new MigrationActionRefusedError("Predicate schema alignment only rewrites fact entities.");
78716
78785
  const prolog = context.prolog ?? await context.ensureProlog?.();
78717
78786
  if (!prolog)
78718
78787
  throw new Error("Predicate schema alignment requires a Prolog runtime.");
@@ -78724,7 +78793,7 @@ async function applyPredicateSchemaAlignment(action, context) {
78724
78793
  const rewrites = Array.isArray(evidence.rewrites) ? evidence.rewrites : [];
78725
78794
  const unchanged = current !== undefined && current.fact_kind === "predicate" && currentNamespace === evidence.namespace && rewrites.every((rewrite) => isRecord24(rewrite) && typeof rewrite.index === "number" && currentArgs[rewrite.index] === rewrite.from);
78726
78795
  if (!unchanged)
78727
- throw new Error(`Predicate fact ${input.id} changed since planning; rerun kibi check and approve the new plan.`);
78796
+ throw new MigrationActionRefusedError(`Predicate fact ${input.id} changed since planning; rerun kibi check and approve the new plan.`);
78728
78797
  await executeUpsert(input, operationContext);
78729
78798
  }
78730
78799
  var PLAN_APPLY_RESULT_VERSION = "kibi.plan-apply-result.v1", ENTITY_TYPES4;
@@ -78752,6 +78821,7 @@ var init_apply_plan = __esm(() => {
78752
78821
  init_upsert();
78753
78822
  init_workspace_mutation_lock();
78754
78823
  init_compile_intent();
78824
+ init_migration_refusal();
78755
78825
  ENTITY_TYPES4 = new Set([
78756
78826
  "req",
78757
78827
  "scenario",
@@ -80347,6 +80417,7 @@ init_branch_store_locator();
80347
80417
  init_detached_snapshot();
80348
80418
 
80349
80419
  // src/index.ts
80420
+ init_result_envelope();
80350
80421
  init_engine();
80351
80422
 
80352
80423
  // ../cli/dist/public/prolog/index.js
@@ -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.12.0
5
+ version: 2.13.0
6
6
  kibiCompatibility: ">=1.0.0"
7
7
  tags:
8
8
  - kibi
@@ -148,7 +148,13 @@ error `BOOTSTRAP_PLAN_REJECTED` can follow earlier committed actions: inspect
148
148
  `data.actionResults` and `data.applied`, then re-plan from the current state.
149
149
  Its journal is terminal; never recover or replay it. `BOOTSTRAP_PLAN_INVALID`
150
150
  fails preflight before bootstrap writes or a new journal; obtain a corrected
151
- plan. If the status is
151
+ plan. A migration plan whose actions were refused before changing anything
152
+ returns `status: error`, `MIGRATION_PLAN_REFUSED` and `data.outcome:
153
+ refused`: nothing changed, so read the action `detail` and get a new plan.
154
+ `data.outcome: reconciliation_required` (status success) means an action
155
+ failed mid-way: inspect its effect before retrying. `kb_delete` of an
156
+ authored entity returns status success with `deleted: 0`; its `errors` say
157
+ why nothing was deleted. If the status is
152
158
  `committed_with_repairs`, the mutation already committed: inspect failed effects,
153
159
  execute each required repair action in order, and never retry the original
154
160
  operation. Record effect failures, followed actions, and unsafe retries in
@@ -61,16 +61,16 @@ A schema can close an argument with `argument_constants` (allowed values keyed b
61
61
 
62
62
  ### Deny predicate
63
63
 
64
- Claim: “Suspended users must not publish articles.” When `permission_rule` fits, preserve its positive schema name and encode prohibition as polarity:
64
+ Claim: “Suspended users must not publish articles.” When `permission_rule` fits, preserve its positive schema name and encode prohibition as polarity. `kb_model` (`mode: "predicates"`) plans this fact for the claim; the built-in schema's fourth argument, `decision`, repeats the polarity:
65
65
 
66
66
  ```yaml
67
67
  id: FACT-SUSPENDED-PUBLISH-DENIED
68
68
  status: active
69
69
  fact_kind: predicate
70
70
  predicate_name: permission_rule
71
- predicate_args: [suspended_user, publish, article]
71
+ predicate_args: [suspended_user, publish, articles, deny]
72
72
  polarity: deny
73
- canonical_key: permission_rule(suspended_user,publish,article)
73
+ canonical_key: permission_rule(suspended_user,publish,articles,deny)
74
74
  claim_key: <advisor-issued key for this exact clause>
75
75
  claim_text: Suspended users must not publish articles.
76
76
  relationship: { type: requires_predicate, from: REQ-SUSPENDED-PUBLISH-DENIED, to: FACT-SUSPENDED-PUBLISH-DENIED }
@@ -51,6 +51,15 @@ proof_bindings: # optional provenance metadata
51
51
 
52
52
  Provenance lives in `proof_bindings`; the contract stays semantic.
53
53
 
54
+ - Every `required_proofs[].symbol_id` must name an existing `symbol` entity,
55
+ or `kb_check` reports `proof-contract-symbols`. Create the symbols first
56
+ (`kb_upsert`, narrow method-level granularity, never a `type-shape`
57
+ symbol): a production symbol `implements` the requirement and is
58
+ `covered_by` the test; an executable test symbol is `executable_for` it.
59
+ - `proof_bindings[].source_file`, when set, must equal the named symbol's
60
+ `sourceFile`: for a production symbol that is the production file, not the
61
+ spec file that exercises it. Omit it when unsure.
62
+
54
63
  ## Integration configuration
55
64
 
56
65
  `.kb/proof/integrations.json` (`kibi.proof-integration.v1`) is tracked,
@@ -62,12 +71,21 @@ returns `integrationPlan`, a hash-bound `kibi.migration-plan.v2`, plus the
62
71
  proposal to the human, then apply the plan with `kb_apply_plan` (or
63
72
  `kibi apply-plan --input -`) passing `plan`, `approvedPlanHash` (the plan's
64
73
  `planHash`) and `approvedActionIds`. Once the file exists, a create plan is
65
- refused; `kibi proof inspect --update <id> --json` plans adding or replacing
66
- one named integration.
74
+ refused (`status: error`, `MIGRATION_PLAN_REFUSED`, `data.outcome: refused`;
75
+ nothing is written); `kibi proof inspect --update <id> --json` plans adding or
76
+ replacing one named integration.
67
77
 
68
78
  - `producer: command` — Kibi synthesizes the envelope from the process
69
79
  outcome; obligations are bound with `aggregate_run` provenance and the
70
- single process invocation counts as the known first attempt.
80
+ single process invocation counts as the known first attempt. The run is
81
+ judged as a whole: any failing test in it fails every obligation of every
82
+ test that names the integration, so a suite with unrelated failures proves
83
+ nothing. Narrow the command to the proof-bearing tests with
84
+ `kibi proof inspect --update <id> --command "<command>" --json` (without
85
+ `--command` the proposal is the `package.json` `test` script or the
86
+ detected runner again), or make the run attributable per test: have the
87
+ command write a `kibi.proof-test-report.v1` to the path in
88
+ `KIBI_PROOF_TEST_REPORT` so each test is judged by its own steps.
71
89
  - `producer: playwright` (or custom) — the child emits `kibi.proof-run.v1`
72
90
  itself (bundled reporter: `kibi-cli/playwright-reporter`).
73
91
  - `producer: junit` / `tap` — Kibi converts the native report at `artifact`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kibi-runtime",
3
- "version": "2.13.1",
3
+ "version": "2.13.2",
4
4
  "description": "Narrow first-party runtime contracts and adapters for Kibi operations.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -18,7 +18,7 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "gray-matter": "^4.0.3",
21
- "kibi-core": "^0.18.1",
21
+ "kibi-core": "^0.18.2",
22
22
  "kibi-plugin-builtin": "^0.5.0",
23
23
  "kibi-swipl": "^1.0.1"
24
24
  },