agentera 3.0.0-dev.72 → 3.0.0-dev.75

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 (93) hide show
  1. package/README.md +111 -0
  2. package/bundle/.agentera-build-source.json +8 -0
  3. package/bundle/CHANGELOG.md +17 -17
  4. package/bundle/extract-corpus-parity.json +1 -1
  5. package/bundle/references/adapters/package-publication.json +49 -53
  6. package/bundle/references/adapters/package-registry.yaml +5 -1
  7. package/bundle/references/adapters/package-surface-characterization.md +6 -4
  8. package/bundle/references/analysis/evidence-tier-authority.yaml +45 -4
  9. package/bundle/references/analysis/personal-glossary-evaluation-authority.yaml +175 -0
  10. package/bundle/references/analysis/personal-glossary-evaluation-corpus.yaml +291 -0
  11. package/bundle/references/analysis/personal-glossary-holdout.yaml +192 -0
  12. package/bundle/references/analysis/verification-policy.yaml +8 -13
  13. package/bundle/references/artifacts/glossary-entry-contract.yaml +1533 -35
  14. package/bundle/references/cli/update-channels.yaml +2 -2
  15. package/bundle/references/cli/vocabulary.md +1 -1
  16. package/bundle/references/meta/retained-reference-authority.yaml +16 -1
  17. package/bundle/skills/agentera/capabilities/profile/schemas/artifacts.yaml +11 -7
  18. package/bundle/skills/agentera/capabilities/profile/schemas/exit.yaml +6 -3
  19. package/bundle/skills/agentera/capabilities/profile/schemas/validation.yaml +13 -7
  20. package/bundle/skills/agentera/schemas/artifacts/glossary.yaml +5 -0
  21. package/bundle/skills/agentera/schemas/artifacts/plan.yaml +7 -0
  22. package/dist/.agentera-build-source.json +8 -0
  23. package/dist/analytics/extractCorpus/copilotSessions.js +13 -4
  24. package/dist/analytics/extractCorpus/core.js +223 -3
  25. package/dist/analytics/extractCorpus/corpus.js +18 -1
  26. package/dist/analytics/extractCorpus/cursorSessions.js +22 -4
  27. package/dist/analytics/extractCorpus/evidenceTiers.js +123 -17
  28. package/dist/analytics/extractCorpus/filesystemSources.js +4 -0
  29. package/dist/analytics/extractCorpus/index.js +2 -2
  30. package/dist/analytics/extractCorpus/jsonlSessions.js +52 -3
  31. package/dist/analytics/extractCorpus/sqliteSessions.js +12 -3
  32. package/dist/analytics/personalGlossaryAdmission.js +26 -46
  33. package/dist/analytics/personalGlossaryCandidateProjection.js +692 -0
  34. package/dist/analytics/personalGlossaryCandidateProjectionExcerpts.js +144 -0
  35. package/dist/analytics/personalGlossaryCandidateReadView.js +23 -0
  36. package/dist/analytics/personalGlossaryCurrentGeneration.js +25 -0
  37. package/dist/analytics/personalGlossaryDecision.js +203 -0
  38. package/dist/analytics/personalGlossaryExplicit.js +788 -0
  39. package/dist/analytics/personalGlossaryExplicitMining.js +285 -0
  40. package/dist/analytics/personalGlossaryExplicitScope.js +41 -0
  41. package/dist/analytics/personalGlossaryExplicitSegments.js +418 -0
  42. package/dist/analytics/personalGlossaryExplicitTypes.js +26 -0
  43. package/dist/analytics/personalGlossaryLexicalClassifier.js +175 -0
  44. package/dist/analytics/personalGlossaryProfile.js +13 -3
  45. package/dist/analytics/personalGlossaryRecurrence.js +618 -0
  46. package/dist/analytics/personalGlossaryReviewRecordStorage.js +428 -0
  47. package/dist/analytics/personalGlossaryReviewRecords.js +332 -0
  48. package/dist/capabilities/index.js +5 -1
  49. package/dist/capabilities/profile/instructions.js +50 -15
  50. package/dist/cli/commands/personalGlossaryCandidateReads.js +744 -0
  51. package/dist/cli/commands/personalGlossaryDecision.js +349 -0
  52. package/dist/cli/commands/personalGlossaryPublish.js +484 -0
  53. package/dist/cli/commands/personalGlossaryReviewRecordReads.js +209 -0
  54. package/dist/cli/commands/personalGlossaryReviewRecords.js +623 -0
  55. package/dist/cli/commands/prime/briefOrientation.js +118 -19
  56. package/dist/cli/commands/report.js +18 -2
  57. package/dist/cli/commands/schema.js +179 -0
  58. package/dist/cli/commands/verify.js +51 -9
  59. package/dist/cli/dispatch/lifecycle.js +51 -6
  60. package/dist/cli/help.js +48 -2
  61. package/dist/cli/migrationRequired.js +4 -1
  62. package/dist/core/atomicWriter.js +4 -1
  63. package/dist/core/developmentInvocation.js +4 -1
  64. package/dist/core/yaml.js +53 -1
  65. package/dist/eval/glossaryEvaluation.js +751 -0
  66. package/dist/eval/glossaryEvaluationProcess.js +29 -0
  67. package/dist/eval/glossaryEvaluationRunner.js +571 -0
  68. package/dist/eval/glossaryEvaluationSuccessReport.js +297 -0
  69. package/dist/registries/activationTuples.js +31 -3
  70. package/dist/registries/evidenceTierContract.js +4 -0
  71. package/dist/registries/explicitSegmentGrammarContract.js +619 -0
  72. package/dist/registries/glossaryCandidateContractPaths.js +6 -0
  73. package/dist/registries/glossaryCandidateContracts.js +820 -0
  74. package/dist/registries/glossaryCandidateDecisionAuthority.js +119 -0
  75. package/dist/registries/glossaryCandidateDecisionContract.js +62 -0
  76. package/dist/registries/glossaryCandidateProjectionAuthority.js +197 -0
  77. package/dist/registries/glossaryCandidateProjectionContract.js +104 -0
  78. package/dist/registries/glossaryEntryContract.js +105 -103
  79. package/dist/registries/glossaryEntryTemporal.js +12 -0
  80. package/dist/registries/glossaryMiningAuthority.js +764 -0
  81. package/dist/registries/glossaryProfileFullContract.js +24 -0
  82. package/dist/registries/glossaryReviewRecordsAuthority.js +426 -0
  83. package/dist/registries/glossaryReviewRecordsContract.js +129 -0
  84. package/dist/registries/glossaryTermIdentity.js +122 -0
  85. package/dist/registries/packagePublication.js +3 -3
  86. package/dist/registries/personalGlossaryContracts.js +1 -0
  87. package/dist/release/releaseMetadata.js +15 -8
  88. package/dist/upgrade/npxPlatformStatus.js +2 -1
  89. package/dist/upgrade/projectIntegration.js +7 -1
  90. package/dist/validate/activationArtifactEvidence.js +18 -4
  91. package/dist/validate/activationEvidenceManifest.js +101 -22
  92. package/package.json +2 -4
  93. package/dist/cli/commands/personalGlossary.js +0 -176
@@ -3,6 +3,9 @@ import { projectGlossaryDevelopmentValue } from "../core/developmentInvocation.j
3
3
  import { resolveSourceRoot } from "../core/sourceRoot.js";
4
4
  import { loadYamlMappingFile } from "../core/yaml.js";
5
5
  import { validateConsumerBoundary, validateConsumerEvidenceOwner, } from "./glossaryConsumerContractValidation.js";
6
+ import { validatePersonalCandidateContracts } from "./glossaryCandidateContracts.js";
7
+ import { validateConversationProvenance, validateHistoryEvidence, validatePersonalMiningAuthority, validateProvenanceVariants, } from "./glossaryMiningAuthority.js";
8
+ import { isGlossaryIsoCalendarDate } from "./glossaryEntryTemporal.js";
6
9
  export class GlossaryEntryBoundError extends Error {
7
10
  }
8
11
  const DEFERRED_CAPABILITIES = ["profile", "audit", "discuss", "plan", "build"];
@@ -24,10 +27,33 @@ export function personalGlossaryAdmissionContract(pathname = glossaryEntryAuthor
24
27
  const authority = contract(pathname);
25
28
  const personal = mapping(mapping(authority.ownership_contracts)?.personal);
26
29
  const admission = mapping(personal?.admission);
30
+ const conversation = mapping(mapping(authority.provenance_variants)?.personal_inferred_conversation);
31
+ const explicitVariant = mapping(mapping(authority.provenance_variants)?.personal_explicit_definition);
32
+ const explicitDiscovery = mapping(mapping(authority.personal_mining_authority)?.explicit_discovery);
33
+ const explicitGrammar = mapping(explicitDiscovery?.grammar);
34
+ const expectedEvidence = mapping(conversation?.expected_evidence);
27
35
  return {
28
36
  explicitSignalTypes: strings(mapping(admission?.explicit)?.candidate_signal_types),
37
+ explicitGrammarIds: (Array.isArray(explicitGrammar?.forms) ? explicitGrammar.forms : [])
38
+ .map((item) => mapping(item))
39
+ .filter((item) => item !== null)
40
+ .map((item) => String(item.id))
41
+ .filter(Boolean),
42
+ explicitProvenanceFields: strings(mapping(explicitVariant?.source_provenance)?.required_fields),
29
43
  inferredSignalTypes: strings(mapping(admission?.inferred)?.candidate_signal_types),
30
44
  inferredSourceKinds: strings(mapping(admission?.inferred)?.source_kinds),
45
+ conversationSignalTypes: strings(conversation?.allowed_signal_types),
46
+ conversationSourceKinds: strings(conversation?.allowed_source_kinds),
47
+ conversationAuthorClasses: strings(conversation?.allowed_author_classes),
48
+ conversationEvidenceFields: strings(conversation?.required_evidence_fields),
49
+ conversationExpectedEvidenceContextFields: strings(expectedEvidence?.context_fields),
50
+ conversationMinimumEvidenceCount: typeof conversation?.minimum_evidence_count === "number"
51
+ ? conversation.minimum_evidence_count
52
+ : 0,
53
+ conversationCompletenessAuthority: typeof conversation?.completeness_authority === "string"
54
+ ? conversation.completeness_authority
55
+ : "",
56
+ conversationAdmission: typeof conversation?.admission === "string" ? conversation.admission : "",
31
57
  insufficientRecovery: typeof admission?.insufficient_recovery === "string"
32
58
  ? admission.insufficient_recovery.trim()
33
59
  : "",
@@ -45,12 +71,22 @@ export function personalGlossaryOutputContract(pathname = glossaryEntryAuthority
45
71
  const output = mapping(personal?.profile_output);
46
72
  const command = mapping(output?.command);
47
73
  const request = mapping(command?.request);
74
+ const result = mapping(command?.result);
48
75
  const section = mapping(output?.section);
76
+ const reviewAuthorization = mapping(request?.review_authorization);
49
77
  return {
50
78
  command: projectGlossaryDevelopmentValue(command?.canonical, "profile_output.command"),
51
79
  requestSchemaVersion: typeof request?.schema_version === "string" ? request.schema_version : "",
80
+ requestFields: strings(request?.required_fields),
81
+ requestOptionalFields: strings(request?.optional_fields),
82
+ maxRequestUtf8Bytes: typeof request?.max_utf8_bytes === "number" ? request.max_utf8_bytes : 0,
83
+ resultSchemaVersion: typeof result?.schema_version === "string" ? result.schema_version : "",
84
+ resultFields: strings(result?.fields),
85
+ maxResultUtf8Bytes: typeof result?.max_utf8_bytes === "number" ? result.max_utf8_bytes : 0,
52
86
  sectionSchemaVersion: typeof section?.document_schema_version === "string" ? section.document_schema_version : "",
53
87
  outputStatuses: strings(command?.output_statuses),
88
+ reviewAuthorizationFields: strings(reviewAuthorization?.required_fields),
89
+ reviewAuthorizationDispositions: strings(reviewAuthorization?.dispositions),
54
90
  };
55
91
  }
56
92
  export function personalProfileGroundingContract(pathname = glossaryEntryAuthorityPath()) {
@@ -119,19 +155,6 @@ export function isSafeProjectSourcePath(value) {
119
155
  !path.win32.isAbsolute(value) &&
120
156
  !value.split(/[\\/]/).includes(".."));
121
157
  }
122
- function isIsoCalendarDate(value) {
123
- if (typeof value !== "string")
124
- return false;
125
- const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
126
- if (!match)
127
- return false;
128
- const [, year, month, day] = match.map(Number);
129
- const date = new Date(`${value}T00:00:00.000Z`);
130
- return (!Number.isNaN(date.getTime()) &&
131
- date.getUTCFullYear() === year &&
132
- date.getUTCMonth() + 1 === month &&
133
- date.getUTCDate() === day);
134
- }
135
158
  export function validateGlossaryEntryContract(pathname = glossaryEntryAuthorityPath()) {
136
159
  let authority;
137
160
  try {
@@ -144,6 +167,8 @@ export function validateGlossaryEntryContract(pathname = glossaryEntryAuthorityP
144
167
  if (authority.schema_version !== "agentera.glossaryEntryContract.v1") {
145
168
  errors.push("schema_version must be agentera.glossaryEntryContract.v1");
146
169
  }
170
+ errors.push(...validatePersonalMiningAuthority(authority));
171
+ errors.push(...validatePersonalCandidateContracts(authority));
147
172
  const occurrence = mapping(authority.term_occurrence);
148
173
  if (occurrence?.runtime !==
149
174
  "packages/cli/src/registries/glossaryTermOccurrence.ts#containsGlossaryTerm" ||
@@ -201,51 +226,7 @@ export function validateGlossaryEntryContract(pathname = glossaryEntryAuthorityP
201
226
  errors.push("provenance must derive its kind and evidence variants from provenance_variants");
202
227
  }
203
228
  const variants = mapping(authority.provenance_variants);
204
- const variantExpectations = {
205
- personal_explicit_definition: {
206
- owner: "personal",
207
- evidence_count: 1,
208
- required_evidence_fields: ["source_id", "evidence_anchor", "signal_type"],
209
- allowed_signal_types: ["correction", "decision", "instruction"],
210
- },
211
- personal_inferred_usage: {
212
- owner: "personal",
213
- evidence_count: 2,
214
- required_evidence_fields: ["source_id", "evidence_anchor", "source_kind"],
215
- allowed_source_kinds: ["instruction_document", "project_config_signal"],
216
- },
217
- project_file: {
218
- owner: "project",
219
- evidence_count: 1,
220
- required_evidence_fields: ["source_path", "source_record_sha256"],
221
- },
222
- };
223
- for (const [kind, expectedVariant] of Object.entries(variantExpectations)) {
224
- const variant = mapping(variants?.[kind]);
225
- if (!variant) {
226
- errors.push(`provenance variant ${kind} is required`);
227
- continue;
228
- }
229
- if (variant.owner !== expectedVariant.owner)
230
- errors.push(`${kind}.owner must be ${expectedVariant.owner}`);
231
- if (variant.evidence_count !== expectedVariant.evidence_count) {
232
- errors.push(`${kind}.evidence_count must be ${expectedVariant.evidence_count}`);
233
- }
234
- if (!sameStrings(variant.required_evidence_fields, expectedVariant.required_evidence_fields)) {
235
- errors.push(`${kind}.required_evidence_fields must match its provenance variant`);
236
- }
237
- if (variant.additional_evidence_fields !== "forbidden") {
238
- errors.push(`${kind}.additional_evidence_fields must be forbidden`);
239
- }
240
- for (const allowedField of ["allowed_signal_types", "allowed_source_kinds"]) {
241
- if (allowedField in expectedVariant &&
242
- !sameStrings(variant[allowedField], expectedVariant[allowedField])) {
243
- errors.push(`${kind}.${allowedField} must preserve the admitted evidence classes`);
244
- }
245
- }
246
- if (!nonEmpty(variant.resolution_rule))
247
- errors.push(`${kind}.resolution_rule is required`);
248
- }
229
+ errors.push(...validateProvenanceVariants(variants));
249
230
  const ownership = mapping(authority.ownership_contracts);
250
231
  const personal = mapping(ownership?.personal);
251
232
  if (personal?.scope !== "user")
@@ -253,6 +234,7 @@ export function validateGlossaryEntryContract(pathname = glossaryEntryAuthorityP
253
234
  if (!sameStrings(personal?.allowed_provenance, [
254
235
  "personal_explicit_definition",
255
236
  "personal_inferred_usage",
237
+ "personal_inferred_conversation",
256
238
  ])) {
257
239
  errors.push("personal ownership must admit only personal provenance variants");
258
240
  }
@@ -280,13 +262,19 @@ export function validateGlossaryEntryContract(pathname = glossaryEntryAuthorityP
280
262
  if (personalImplementation?.status !== "active_partial" ||
281
263
  !sameStrings(personalImplementation?.active, [
282
264
  "bounded_admission",
265
+ "bounded_explicit_discovery",
266
+ "bounded_candidate_projection",
267
+ "bounded_candidate_retrieval",
268
+ "public_receipt_construction",
269
+ "host_classification_receipt_validation",
270
+ "deterministic_cli_admission_decision",
283
271
  "explicit_classification",
284
272
  "inferred_evidence_check",
285
- "profile_full_rendering",
286
- "profile_persistence",
273
+ "authorized_personal_publication",
274
+ "profile_section_persistence",
287
275
  ]) ||
288
276
  !sameStrings(personalImplementation?.inactive, ["lookup"])) {
289
- errors.push("personal rendering and persistence must be active_partial while lookup remains inactive");
277
+ errors.push("personal implementation must be active_partial while lookup remains inactive");
290
278
  }
291
279
  if (!sameStrings(mapping(admission?.explicit)?.candidate_signal_types, [
292
280
  "correction",
@@ -316,37 +304,36 @@ export function validateGlossaryEntryContract(pathname = glossaryEntryAuthorityP
316
304
  if (!nonEmpty(decay?.[field]))
317
305
  errors.push(`personal retention_and_decay.${field} is required`);
318
306
  }
319
- const profileOutput = mapping(personal?.profile_output);
320
- const profileSection = mapping(profileOutput?.section);
307
+ const profileOutput = mapping(personal?.profile_output), profileSection = mapping(profileOutput?.section);
321
308
  const mergeIdentity = mapping(profileOutput?.merge_identity);
322
- const profileCommand = mapping(profileOutput?.command);
323
- const profileRequest = mapping(profileCommand?.request);
324
- if (profileOutput?.owner !== "profile_full" ||
325
- profileOutput?.lifecycle_callable !==
326
- "packages/cli/src/analytics/personalGlossaryProfile.ts#updatePersonalGlossaryProfile" ||
327
- profileCommand?.canonical !== "npx -y agentera@next report profile-glossary" ||
309
+ const profileCommand = mapping(profileOutput?.command), profileRequest = mapping(profileCommand?.request), profileFilesystem = mapping(profileOutput?.filesystem);
310
+ const reviewAuthorization = mapping(profileRequest?.review_authorization);
311
+ if (profileOutput?.owner !== "personal_profile_publication" ||
312
+ profileOutput?.lifecycle_callable !== "packages/cli/src/analytics/personalGlossaryProfile.ts#updatePersonalGlossaryProfile" ||
313
+ profileCommand?.canonical !== "npx -y agentera@next report personal-glossary-publish" ||
328
314
  profileCommand?.namespace !== "report" ||
329
315
  profileCommand?.input_flag !== "--input" ||
330
316
  profileCommand?.stdin_value !== "-" ||
331
317
  profileCommand?.format !== "json" ||
332
318
  profileCommand?.dry_run_flag !== "--dry-run" ||
333
319
  profileCommand?.project_checkout !== "not_required" ||
334
- profileRequest?.schema_version !== "agentera.personalGlossaryUpdateRequest.v1" ||
335
- !sameStrings(profileRequest?.required_fields, [
336
- "schema_version",
337
- "profile_path",
338
- "as_of",
339
- "fresh_entries",
340
- "retained_history",
341
- ]) ||
320
+ profileRequest?.schema_version !== "agentera.personalGlossaryPublishRequest.v1" ||
321
+ !sameStrings(profileRequest?.required_fields, ["schema_version", "receipt", "decision", "as_of"]) ||
322
+ !sameStrings(profileRequest?.optional_fields, ["review_authorization"]) ||
342
323
  profileRequest?.additional_fields !== "forbidden" ||
324
+ profileRequest?.max_utf8_bytes !== 16384 ||
343
325
  !nonEmpty(profileRequest?.profile_path_rule) ||
344
- !nonEmpty(profileRequest?.retained_history_shape) ||
345
- !sameStrings(profileCommand?.output_statuses, [
346
- "changed",
347
- "unchanged_replay",
348
- "dry_run_candidate",
349
- ]) ||
326
+ !nonEmpty(profileRequest?.current_decision_rule) ||
327
+ !sameStrings(reviewAuthorization?.required_fields, ["review_id", "review_record_sha256"]) ||
328
+ reviewAuthorization?.additional_fields !== "forbidden" ||
329
+ !sameStrings(reviewAuthorization?.dispositions, ["accept", "correct"]) ||
330
+ reviewAuthorization?.source !== "personal_mining_authority.review_records.disposition.publication_authorization" ||
331
+ !nonEmpty(reviewAuthorization?.rule) ||
332
+ !nonEmpty(profileRequest?.date_rule) ||
333
+ mapping(profileCommand?.result)?.schema_version !==
334
+ "agentera.personalGlossaryPublicationResult.v1" ||
335
+ mapping(profileCommand?.result)?.max_utf8_bytes !== 4096 ||
336
+ !sameStrings(profileCommand?.output_statuses, ["changed", "unchanged_replay", "dry_run_candidate"]) ||
350
337
  !nonEmpty(profileCommand?.rule) ||
351
338
  profileSection?.heading !== "## Glossary" ||
352
339
  profileSection?.start_marker !== "<!-- agentera:personal-glossary:start -->" ||
@@ -360,7 +347,13 @@ export function validateGlossaryEntryContract(pathname = glossaryEntryAuthorityP
360
347
  !nonEmpty(mergeIdentity?.rule) ||
361
348
  !nonEmpty(profileOutput?.refresh_rule) ||
362
349
  !nonEmpty(profileOutput?.decay_rule) ||
363
- !nonEmpty(profileOutput?.isolation_rule)) {
350
+ !nonEmpty(profileOutput?.isolation_rule) ||
351
+ profileFilesystem?.authority !== "host_filesystem" ||
352
+ profileFilesystem?.configured_path !== "canonical_user_profile_authority" ||
353
+ profileFilesystem?.outcomes !== "ordinary_permissions_and_io" ||
354
+ profileFilesystem?.same_user_path_manipulation !== "outside_agentera_threat_model" ||
355
+ profileFilesystem?.symlink_confinement !== "not_claimed" ||
356
+ !nonEmpty(profileFilesystem?.rule)) {
364
357
  errors.push("personal profile output must define deterministic isolated rendering and lifecycle rules");
365
358
  }
366
359
  const project = mapping(ownership?.project);
@@ -458,7 +451,8 @@ export function validateGlossaryEntryContract(pathname = glossaryEntryAuthorityP
458
451
  errors.push("project entry derivation must produce only the shared project_file primitive");
459
452
  }
460
453
  if (publication?.owner !== "build" ||
461
- publication?.command !== "npx -y agentera@next state glossary publish --input REQUEST --format json" ||
454
+ publication?.command !==
455
+ "npx -y agentera@next state glossary publish --input REQUEST --format json" ||
462
456
  publicationRequest?.schema_version !== "agentera.glossaryPublicationRequest.v1" ||
463
457
  !sameStrings(publicationRequest?.required_fields, [
464
458
  "schema_version",
@@ -502,8 +496,21 @@ export function validateGlossaryEntryContract(pathname = glossaryEntryAuthorityP
502
496
  profileGrounding?.parser !==
503
497
  "packages/cli/src/analytics/personalGlossaryProfile.ts#personalProfileGrounding" ||
504
498
  profileGrounding?.max_profile_utf8_bytes !== 65536 ||
505
- !sameStrings(mapping(profileGrounding?.validity)?.statuses, ["absent", "valid", "repair_needed"]) ||
506
- !sameStrings(mapping(profileGrounding?.validity)?.classes, ["absent", "valid", "malformed", "ambiguous", "unreadable", "unsafe", "oversized", "invalid_utf8"]) ||
499
+ !sameStrings(mapping(profileGrounding?.validity)?.statuses, [
500
+ "absent",
501
+ "valid",
502
+ "repair_needed",
503
+ ]) ||
504
+ !sameStrings(mapping(profileGrounding?.validity)?.classes, [
505
+ "absent",
506
+ "valid",
507
+ "malformed",
508
+ "ambiguous",
509
+ "unreadable",
510
+ "unsafe",
511
+ "oversized",
512
+ "invalid_utf8",
513
+ ]) ||
507
514
  !sameStrings(mapping(profileGrounding?.freshness)?.states, ["current", "stale", "unknown"]) ||
508
515
  !nonEmpty(mapping(profileGrounding?.recovery)?.repair) ||
509
516
  !nonEmpty(mapping(profileGrounding?.recovery)?.absent) ||
@@ -532,15 +539,19 @@ export function validateGlossaryEntryContract(pathname = glossaryEntryAuthorityP
532
539
  !sameStrings(profile?.capabilities, ["profile"]) ||
533
540
  !sameStrings(profile?.active_behavior, [
534
541
  "ownership_contracts.personal.admission",
535
- "ownership_contracts.personal.profile_output",
542
+ "personal_mining_authority.profile_full",
536
543
  ]) ||
537
544
  !sameStrings(profile?.inactive_behavior, ["lookup"]) ||
538
545
  profileContracts?.admission !== "ownership_contracts.personal.input" ||
539
546
  profileContracts?.provenance !== "ownership_contracts.personal.allowed_provenance" ||
540
547
  profileContracts?.confidence !== "shared_primitive.fields.confidence" ||
541
548
  profileContracts?.retention_and_decay !== "ownership_contracts.personal.retention_and_decay" ||
542
- !sameStrings(profile?.forbidden_current_claims, ["lookup", "project_glossary_consumption"])) {
543
- errors.push("profile glossary rendering and persistence must be active while Profile itself performs no consumer lookup");
549
+ profileContracts?.profile_full !== "personal_mining_authority.profile_full" ||
550
+ !sameStrings(profile?.forbidden_current_claims, [
551
+ "lookup",
552
+ "project_glossary_consumption",
553
+ ])) {
554
+ errors.push("profile glossary synthesis must reuse existing consented input and only canonical authorized personal publication");
544
555
  }
545
556
  const audit = mapping(capabilities?.audit);
546
557
  const findingFamily = mapping(audit?.finding_family);
@@ -647,7 +658,7 @@ function requiredEntryShape(entry, authority) {
647
658
  }
648
659
  const temporal = mapping(entry.temporal);
649
660
  for (const field of strings(mapping(fields?.temporal)?.required_fields)) {
650
- if (!isIsoCalendarDate(temporal?.[field])) {
661
+ if (!isGlossaryIsoCalendarDate(temporal?.[field])) {
651
662
  errors.push(`temporal.${field} must be an ISO date`);
652
663
  }
653
664
  }
@@ -665,18 +676,6 @@ function evidenceShape(evidence, requiredFields, kind, index) {
665
676
  }
666
677
  return errors;
667
678
  }
668
- function validateHistoryEvidence(evidence, context, index) {
669
- const errors = [];
670
- const sourceId = typeof evidence.source_id === "string" ? evidence.source_id : "";
671
- const anchor = typeof evidence.evidence_anchor === "string" ? evidence.evidence_anchor : "";
672
- const retained = context.retainedHistory.get(anchor);
673
- if (!sourceId || !anchor)
674
- errors.push(`provenance.evidence[${index}] requires source_id and evidence_anchor`);
675
- if (!retained || retained.sourceId !== sourceId) {
676
- errors.push(`provenance.evidence[${index}].evidence_anchor must resolve to its retained source_id`);
677
- }
678
- return errors;
679
- }
680
679
  export function validateGlossaryEntry(entry, owner, context = { retainedHistory: new Map() }, pathname = glossaryEntryAuthorityPath()) {
681
680
  const authorityErrors = validateGlossaryEntryContract(pathname);
682
681
  if (authorityErrors.length > 0) {
@@ -738,6 +737,9 @@ export function validateGlossaryEntry(entry, owner, context = { retainedHistory:
738
737
  }
739
738
  }
740
739
  }
740
+ if (kind === "personal_inferred_conversation") {
741
+ errors.push(...validateConversationProvenance(evidence, provenance, variant, context));
742
+ }
741
743
  if (kind === "project_file") {
742
744
  if (evidence.length !== evidenceCount || evidence[0] === null) {
743
745
  errors.push("project file provenance requires exactly one source record");
@@ -0,0 +1,12 @@
1
+ /** Validate a calendar date without accepting normalized JavaScript date overflow. */
2
+ export function isGlossaryIsoCalendarDate(value) {
3
+ if (typeof value !== "string")
4
+ return false;
5
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/u.exec(value);
6
+ if (!match)
7
+ return false;
8
+ const [, year, month, day] = match.map(Number);
9
+ const date = new Date(`${value}T00:00:00.000Z`);
10
+ return !Number.isNaN(date.getTime()) && date.getUTCFullYear() === year &&
11
+ date.getUTCMonth() + 1 === month && date.getUTCDate() === day;
12
+ }