@tiinex/core 0.33.0 → 0.34.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiinex/core",
3
- "version": "0.33.0",
3
+ "version": "0.34.0",
4
4
  "description": "Shared host-neutral Tiinex implementation core for artifacts, schemas, validation, lineage, grounding, Handoffs, provenance and deterministic workflows.",
5
5
  "type": "module",
6
6
  "sideEffects": true,
@@ -173,12 +173,12 @@
173
173
  "type": "git",
174
174
  "url": "git+https://github.com/Tiinex/core.git"
175
175
  },
176
- "gitHead": "a317bd83e450d04e6e9b0a5229944d958b61eb91",
176
+ "gitHead": "873ac202d2f12a6fbf43437c61b198a85dd7afb3",
177
177
  "tiinexRelease": {
178
178
  "policy": "tiinex.master-npm-release.v1",
179
- "sourceCommit": "a317bd83e450d04e6e9b0a5229944d958b61eb91",
180
- "sourceTree": "7f7ff3bb4a7926eb901476d777630c3d536ebed2",
179
+ "sourceCommit": "873ac202d2f12a6fbf43437c61b198a85dd7afb3",
180
+ "sourceTree": "90fab47ce492c14411836043f221511212b5471e",
181
181
  "repository": "Tiinex/core",
182
- "previousVersion": "0.32.0"
182
+ "previousVersion": "0.33.0"
183
183
  }
184
184
  }
@@ -76,6 +76,24 @@ function projectDocument(record = {}, records = [], lineageInspection = null, re
76
76
  diagnostics.push(...referenceResolution.diagnostics);
77
77
  actions.push(...referenceResolution.actions);
78
78
 
79
+ const lineageArtifact = (lineageInspection?.artifacts || []).find((item) => norm(item?.path || '') === recordPath) || null;
80
+ const parentIntegrityRepair = deterministicParentIntegrityRepair(markdown, lineageArtifact);
81
+ const parentRepairQualification = parentIntegrityRepair.state === 'ready'
82
+ ? qualifyReplacementAgainstSharedGuardrails(record, records, parentIntegrityRepair.markdown, {
83
+ allowExistingWarningCodes: sharedFindings.filter((item) => item.severity === 'warning').map((item) => String(item.code || ''))
84
+ })
85
+ : { state: 'unavailable' };
86
+ if (parentIntegrityRepair.state === 'ready' && parentIntegrityRepair.markdown !== markdown && parentRepairQualification.state === 'qualified') actions.push(freeze({
87
+ id: 'refresh-parent-integrity-and-self-seal',
88
+ title: 'Refresh Tiinex Parent integrity and self seal',
89
+ kind: 'replace-document',
90
+ qualification: 'deterministic-shared-core',
91
+ sourceSha256: sha256Hex(new TextEncoder().encode(markdown)),
92
+ replacementMarkdown: parentIntegrityRepair.markdown,
93
+ diagnosticCodes: ['portable.lineage-integrity.parent-target-mismatch', 'integrity.c14n-v2.mismatch', 'portable.lineage-integrity.child-self-mismatch'],
94
+ boundary: 'Refreshes only an existing Parent integrity digest whose declared locator already matches the exact resolved Parent and whose verified Parent self digest is available locally; the focused artifact is resealed and the action is withheld when loaded descendants would become inconsistent.'
95
+ }));
96
+
79
97
  const integrityRepair = deterministicIntegrityHygieneRepair(markdown, sharedFindings);
80
98
  const repairQualification = integrityRepair.state === 'ready'
81
99
  ? qualifyReplacementAgainstSharedGuardrails(record, records, integrityRepair.markdown, {
@@ -394,9 +412,12 @@ export function locateFindingLine(finding = {}, markdown = '') {
394
412
  const code = String(finding.code || '');
395
413
 
396
414
  // Integrity findings often carry the generic field name `Value`. That field
397
- // appears once per integrity relation, so resolving `field:Value` first would
398
- // incorrectly anchor a self-integrity finding on the first Parent digest.
399
- // Resolve semantically-owned integrity locations before generic field lookup.
415
+ // appears once per integrity relation, so resolve semantically-owned relation
416
+ // locations before generic field lookup.
417
+ if (code === 'portable.lineage-integrity.parent-target-mismatch') {
418
+ const parentValueIndex = primaryParentIntegrityValueLine(lines);
419
+ if (parentValueIndex >= 0) return locatedLine(lines, parentValueIndex, 'deterministic', 'continuity-integrity-primary-parent-value');
420
+ }
400
421
  if (code === 'integrity.c14n-v2.mismatch' || code === 'integrity.c14n-v2.ambiguous' || code === 'portable.lineage-integrity.child-self-mismatch' || code === 'portable.lineage-integrity.child-self-unavailable') {
401
422
  const selfValueIndex = primarySelfIntegrityValueLine(lines);
402
423
  if (selfValueIndex >= 0) return locatedLine(lines, selfValueIndex, 'deterministic', 'continuity-integrity-primary-self-value');
@@ -451,6 +472,24 @@ export function locateFindingLine(finding = {}, markdown = '') {
451
472
  return freeze({ state: 'unresolved', line: null, sourceRange: null, basis: 'shared-finding-has-no-deterministic-line-evidence' });
452
473
  }
453
474
 
475
+ function primaryParentIntegrityValueLine(lines = []) {
476
+ const headingIndex = lines.findIndex((line) => String(line || '').trim() === '# Continuity Integrity');
477
+ if (headingIndex < 0) return -1;
478
+ let parentTowards = -1;
479
+ for (let index = headingIndex + 1; index < lines.length; index += 1) {
480
+ const line = String(lines[index] || '');
481
+ if (index > headingIndex + 1 && /^#\s+/.test(line)) break;
482
+ const towards = line.match(/^\s+-\s+Towards\s*:\s*(.+?)\s*$/i);
483
+ if (towards) {
484
+ parentTowards = String(towards[1] || '').trim().toLowerCase() === 'self' ? -1 : index;
485
+ continue;
486
+ }
487
+ if (parentTowards >= 0 && /^\s+-\s+Value\s*:/.test(line)) return index;
488
+ if (parentTowards >= 0 && /^-\s+/.test(line)) parentTowards = -1;
489
+ }
490
+ return -1;
491
+ }
492
+
454
493
  function primarySelfIntegrityValueLine(lines = []) {
455
494
  const headingIndex = lines.findIndex((line) => String(line || '').trim() === '# Continuity Integrity');
456
495
  if (headingIndex < 0) return -1;
@@ -465,6 +504,43 @@ function primarySelfIntegrityValueLine(lines = []) {
465
504
  return -1;
466
505
  }
467
506
 
507
+ function deterministicParentIntegrityRepair(markdown = '', artifact = null) {
508
+ const source = String(markdown || '');
509
+ if (!source || !artifact || artifact.state !== 'parent-target-mismatch') return freeze({ state: 'unavailable' });
510
+ if (String(artifact?.parentTarget?.reason || '') !== 'target-self-digest-mismatch') return freeze({ state: 'unavailable' });
511
+ if (artifact?.parentAvailability?.state !== 'resolved' || artifact?.parentPrimarySelf?.state !== 'verified') return freeze({ state: 'unavailable' });
512
+ const declaredTarget = String(artifact?.parentTarget?.declaredTarget || '').trim();
513
+ const expectedTarget = String(artifact?.exactParent?.expectedIntegrityTarget || '').trim();
514
+ const digest = String(artifact?.repairCandidate?.candidateTargetDigest || artifact?.parentPrimarySelf?.value || '').trim();
515
+ if (!declaredTarget || !expectedTarget || declaredTarget !== expectedTarget || !digest) return freeze({ state: 'unavailable' });
516
+
517
+ const lines = source.replace(/\r\n?/g, '\n').split('\n');
518
+ const headingIndex = lines.findIndex((line) => String(line || '').trim() === '# Continuity Integrity');
519
+ if (headingIndex < 0) return freeze({ state: 'unavailable' });
520
+ let targetMatched = false;
521
+ let changed = false;
522
+ for (let index = headingIndex + 1; index < lines.length; index += 1) {
523
+ const line = String(lines[index] || '');
524
+ if (index > headingIndex + 1 && /^#\s+/.test(line)) break;
525
+ const towards = line.match(/^\s+-\s+Towards\s*:\s*(?:\[[^\]]+\]\(([^)]+)\)|(\S.*))\s*$/i);
526
+ if (towards) {
527
+ const value = String(towards[1] || towards[2] || '').trim();
528
+ targetMatched = value === declaredTarget;
529
+ continue;
530
+ }
531
+ if (targetMatched && /^(\s+-\s+Value\s*:\s*)(.*)$/.test(line)) {
532
+ const match = line.match(/^(\s+-\s+Value\s*:\s*)(.*)$/);
533
+ lines[index] = `${match?.[1] || ' - Value: '}${digest}`;
534
+ changed = String(match?.[2] || '').trim() !== digest;
535
+ break;
536
+ }
537
+ }
538
+ if (!changed) return freeze({ state: 'unavailable' });
539
+ const sealed = sealC14nV2Self(lines.join('\n'));
540
+ if (sealed.state !== 'sealed' && sealed.state !== 'unchanged') return freeze({ state: 'unavailable' });
541
+ return freeze({ state: 'ready', markdown: String(sealed.markdown || lines.join('\n')) });
542
+ }
543
+
468
544
  function deterministicIntegrityHygieneRepair(markdown = '', findings = []) {
469
545
  const source = String(markdown || '');
470
546
  const codes = new Set((findings || []).map((item) => String(item?.code || '')));
@@ -223,11 +223,15 @@ function choosePrimaryState({ parentResolution, parentSchema, parentPrimarySelf,
223
223
  || consider(parentSchema.state !== 'verified', 'parent-schema-unavailable', parentSchema.reason)
224
224
  || consider(parentPrimarySelf.state === 'mismatch', 'parent-self-mismatch', parentPrimarySelf.reason)
225
225
  || consider(parentPrimarySelf.state !== 'verified', 'parent-self-unavailable', parentPrimarySelf.reason)
226
- || consider(childSelf.state === 'mismatch', 'child-self-mismatch', childSelf.reason)
227
- || consider(childSelf.state !== 'verified', 'child-self-unavailable', childSelf.reason)
226
+ // Parent-target corruption is more specific than the consequential child-self
227
+ // mismatch caused by changing footer bytes. Surface the owned Parent relation
228
+ // first so editors can locate and repair the actual mutated digest.
228
229
  || consider(targetInspection.state === 'missing', 'parent-target-missing', targetInspection.reason)
229
230
  || consider(targetInspection.state === 'mismatch', 'parent-target-mismatch', targetInspection.reason)
230
- || consider(targetInspection.state !== 'verified', targetInspection.state === 'ambiguous' ? 'parent-target-ambiguous' : 'unsupported', targetInspection.reason)
231
+ || consider(targetInspection.state === 'ambiguous', 'parent-target-ambiguous', targetInspection.reason)
232
+ || consider(childSelf.state === 'mismatch', 'child-self-mismatch', childSelf.reason)
233
+ || consider(childSelf.state !== 'verified', 'child-self-unavailable', childSelf.reason)
234
+ || consider(targetInspection.state !== 'verified', 'unsupported', targetInspection.reason)
231
235
  || consider(publicationOrigin.state === 'contradictory', 'publication-origin-contradictory', publicationOrigin.reason)
232
236
  || consider(publicationOrigin.state === 'stale', 'publication-origin-stale', publicationOrigin.reason)
233
237
  || consider(publicationOrigin.state === 'unresolved', 'publication-origin-unresolved', publicationOrigin.reason)