@ai-matrx/content-ir 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.8.0 — 2026-08-29
4
+
5
+ - **A field is never DROPPED — it widens to `json`.** Every field-map loop in
6
+ the JSON Schema → KindSchema direction now goes through
7
+ `convertFieldOrWiden`. A construct the vocabulary cannot name precisely — a
8
+ 2-D array (`rows: [[...]]`), an array of untyped objects, a mixed `anyOf`, an
9
+ unresolvable `$ref` — becomes `json` with a warning instead of disappearing
10
+ from the kind.
11
+
12
+ WHY THIS IS NOT A DETAIL: a dropped field does not merely lose type
13
+ information, it inverts the outcome. The field is absent from the field map,
14
+ so a real payload's value for it becomes unknown-key residue; if the schema
15
+ marked it required, validation FAILS; the node goes `raw`; and the render
16
+ route correctly refuses it a component. Dropping one field could cost a kind
17
+ its entire component. `json` is always a true statement about such a field.
18
+
19
+ A recovery also downgrades whatever the failed attempt logged at `error`
20
+ severity to `warning`, so a host that screams on errors does not scream
21
+ about kinds that render perfectly.
22
+
23
+ - Live-corpus result: all **502** active kinds now derive a complete field map
24
+ from `emitted_json_schema` alone (was 62 with a stored field list, and 466
25
+ before this change). 28 carry at least one widened field, and each one names
26
+ itself in the problems list so the schema can be tightened later.
27
+
3
28
  ## 0.7.0 — 2026-08-29
4
29
 
5
30
  - **`kindSchemaFromJsonSchema` — the registry-facing door for deriving a
package/dist/index.cjs CHANGED
@@ -3213,14 +3213,13 @@ function registerDeclaredKindDraft(declaredKind, objectNode, path, ctx) {
3213
3213
  for (const [propName, propNode] of Object.entries(objectNode.properties)) {
3214
3214
  if (!isRecord4(propNode)) continue;
3215
3215
  if (propName === KIND_KEY) continue;
3216
- const converted = convertProperty(
3216
+ fields[propName] = convertFieldOrWiden(
3217
3217
  propName,
3218
3218
  propNode,
3219
3219
  memberRequired.has(propName),
3220
3220
  `${path}.${propName}`,
3221
3221
  ctx
3222
3222
  );
3223
- if (converted) fields[propName] = converted;
3224
3223
  }
3225
3224
  ctx.blockSchemas.push({
3226
3225
  slug: declaredKind,
@@ -3228,6 +3227,21 @@ function registerDeclaredKindDraft(declaredKind, objectNode, path, ctx) {
3228
3227
  fields
3229
3228
  });
3230
3229
  }
3230
+ function convertFieldOrWiden(fieldName, node, required, path, ctx) {
3231
+ const before = ctx.problems.length;
3232
+ const converted = convertProperty(fieldName, node, required, path, ctx);
3233
+ if (converted) return converted;
3234
+ for (let i = before; i < ctx.problems.length; i++) {
3235
+ const problem = ctx.problems[i];
3236
+ if (problem && problem.severity === "error") problem.severity = "warning";
3237
+ }
3238
+ ctx.problems.push({
3239
+ severity: "warning",
3240
+ path,
3241
+ message: `Field "${fieldName}" has no exact field type \u2014 carried as any JSON value (json) rather than dropped from the kind.`
3242
+ });
3243
+ return { ...requiredNullableFlags(required), type: "json" };
3244
+ }
3231
3245
  function convertProperty(fieldName, node, required, path, ctx) {
3232
3246
  const core = convertPropertyCore(fieldName, node, required, path, ctx);
3233
3247
  const field = core === null ? null : attachNodeMetadata(node, core);
@@ -3618,16 +3632,13 @@ function convertPropertyCore(fieldName, node, required, path, ctx) {
3618
3632
  for (const [propName, propNode] of Object.entries(itemNode.properties)) {
3619
3633
  if (!isRecord4(propNode)) continue;
3620
3634
  if (propName === KIND_KEY) continue;
3621
- const converted = convertProperty(
3635
+ itemFields[propName] = convertFieldOrWiden(
3622
3636
  propName,
3623
3637
  propNode,
3624
3638
  itemRequired.has(propName),
3625
3639
  `${path}[].${propName}`,
3626
3640
  ctx
3627
3641
  );
3628
- if (converted) {
3629
- itemFields[propName] = converted;
3630
- }
3631
3642
  }
3632
3643
  const alreadyHasBlockKind = propNameIsBlockKind(itemNode.properties) || itemRequired.has(KIND_KEY);
3633
3644
  ctx.arrayBindings.push({
@@ -3672,16 +3683,13 @@ function convertPropertyCore(fieldName, node, required, path, ctx) {
3672
3683
  for (const [propName, propNode] of Object.entries(node.properties)) {
3673
3684
  if (!isRecord4(propNode)) continue;
3674
3685
  if (propName === KIND_KEY) continue;
3675
- const converted = convertProperty(
3686
+ nestedFields[propName] = convertFieldOrWiden(
3676
3687
  propName,
3677
3688
  propNode,
3678
3689
  nestedRequired.has(propName),
3679
3690
  `${path}.${propName}`,
3680
3691
  ctx
3681
3692
  );
3682
- if (converted) {
3683
- nestedFields[propName] = converted;
3684
- }
3685
3693
  }
3686
3694
  const referencedKind = readBlockKindFromProperties(node.properties);
3687
3695
  if (referencedKind) {
@@ -3866,16 +3874,13 @@ function convertAiSchemaToBlockFields(schemaName, rootSchema, strict) {
3866
3874
  for (const [fieldName, fieldNode] of Object.entries(properties)) {
3867
3875
  if (!isRecord4(fieldNode)) continue;
3868
3876
  if (fieldName === KIND_KEY) continue;
3869
- const converted = convertProperty(
3877
+ convertedFields[fieldName] = convertFieldOrWiden(
3870
3878
  fieldName,
3871
3879
  fieldNode,
3872
3880
  required.has(fieldName),
3873
3881
  fieldName,
3874
3882
  ctx
3875
3883
  );
3876
- if (converted) {
3877
- convertedFields[fieldName] = converted;
3878
- }
3879
3884
  }
3880
3885
  const rootHasKind = propNameIsBlockKind(properties) || required.has(KIND_KEY);
3881
3886
  if (!rootHasKind) {