agentera 3.0.0-dev.72 → 3.0.0-dev.74

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 (92) 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/artifacts/glossary-entry-contract.yaml +1533 -35
  13. package/bundle/references/cli/update-channels.yaml +2 -2
  14. package/bundle/references/cli/vocabulary.md +1 -1
  15. package/bundle/references/meta/retained-reference-authority.yaml +15 -0
  16. package/bundle/skills/agentera/capabilities/profile/schemas/artifacts.yaml +11 -7
  17. package/bundle/skills/agentera/capabilities/profile/schemas/exit.yaml +6 -3
  18. package/bundle/skills/agentera/capabilities/profile/schemas/validation.yaml +13 -7
  19. package/bundle/skills/agentera/schemas/artifacts/glossary.yaml +5 -0
  20. package/bundle/skills/agentera/schemas/artifacts/plan.yaml +7 -0
  21. package/dist/.agentera-build-source.json +8 -0
  22. package/dist/analytics/extractCorpus/copilotSessions.js +13 -4
  23. package/dist/analytics/extractCorpus/core.js +223 -3
  24. package/dist/analytics/extractCorpus/corpus.js +18 -1
  25. package/dist/analytics/extractCorpus/cursorSessions.js +22 -4
  26. package/dist/analytics/extractCorpus/evidenceTiers.js +123 -17
  27. package/dist/analytics/extractCorpus/filesystemSources.js +4 -0
  28. package/dist/analytics/extractCorpus/index.js +2 -2
  29. package/dist/analytics/extractCorpus/jsonlSessions.js +52 -3
  30. package/dist/analytics/extractCorpus/sqliteSessions.js +12 -3
  31. package/dist/analytics/personalGlossaryAdmission.js +26 -46
  32. package/dist/analytics/personalGlossaryCandidateProjection.js +692 -0
  33. package/dist/analytics/personalGlossaryCandidateProjectionExcerpts.js +144 -0
  34. package/dist/analytics/personalGlossaryCandidateReadView.js +23 -0
  35. package/dist/analytics/personalGlossaryCurrentGeneration.js +25 -0
  36. package/dist/analytics/personalGlossaryDecision.js +203 -0
  37. package/dist/analytics/personalGlossaryExplicit.js +788 -0
  38. package/dist/analytics/personalGlossaryExplicitMining.js +285 -0
  39. package/dist/analytics/personalGlossaryExplicitScope.js +41 -0
  40. package/dist/analytics/personalGlossaryExplicitSegments.js +418 -0
  41. package/dist/analytics/personalGlossaryExplicitTypes.js +26 -0
  42. package/dist/analytics/personalGlossaryLexicalClassifier.js +175 -0
  43. package/dist/analytics/personalGlossaryProfile.js +13 -3
  44. package/dist/analytics/personalGlossaryRecurrence.js +618 -0
  45. package/dist/analytics/personalGlossaryReviewRecordStorage.js +428 -0
  46. package/dist/analytics/personalGlossaryReviewRecords.js +332 -0
  47. package/dist/capabilities/index.js +5 -1
  48. package/dist/capabilities/profile/instructions.js +50 -15
  49. package/dist/cli/commands/personalGlossaryCandidateReads.js +744 -0
  50. package/dist/cli/commands/personalGlossaryDecision.js +349 -0
  51. package/dist/cli/commands/personalGlossaryPublish.js +484 -0
  52. package/dist/cli/commands/personalGlossaryReviewRecordReads.js +209 -0
  53. package/dist/cli/commands/personalGlossaryReviewRecords.js +623 -0
  54. package/dist/cli/commands/prime/briefOrientation.js +118 -19
  55. package/dist/cli/commands/report.js +18 -2
  56. package/dist/cli/commands/schema.js +179 -0
  57. package/dist/cli/commands/verify.js +51 -9
  58. package/dist/cli/dispatch/lifecycle.js +51 -6
  59. package/dist/cli/help.js +48 -2
  60. package/dist/cli/migrationRequired.js +4 -1
  61. package/dist/core/atomicWriter.js +4 -1
  62. package/dist/core/developmentInvocation.js +4 -1
  63. package/dist/core/yaml.js +53 -1
  64. package/dist/eval/glossaryEvaluation.js +751 -0
  65. package/dist/eval/glossaryEvaluationProcess.js +29 -0
  66. package/dist/eval/glossaryEvaluationRunner.js +571 -0
  67. package/dist/eval/glossaryEvaluationSuccessReport.js +297 -0
  68. package/dist/registries/activationTuples.js +31 -3
  69. package/dist/registries/evidenceTierContract.js +4 -0
  70. package/dist/registries/explicitSegmentGrammarContract.js +619 -0
  71. package/dist/registries/glossaryCandidateContractPaths.js +6 -0
  72. package/dist/registries/glossaryCandidateContracts.js +820 -0
  73. package/dist/registries/glossaryCandidateDecisionAuthority.js +119 -0
  74. package/dist/registries/glossaryCandidateDecisionContract.js +62 -0
  75. package/dist/registries/glossaryCandidateProjectionAuthority.js +197 -0
  76. package/dist/registries/glossaryCandidateProjectionContract.js +104 -0
  77. package/dist/registries/glossaryEntryContract.js +105 -103
  78. package/dist/registries/glossaryEntryTemporal.js +12 -0
  79. package/dist/registries/glossaryMiningAuthority.js +764 -0
  80. package/dist/registries/glossaryProfileFullContract.js +24 -0
  81. package/dist/registries/glossaryReviewRecordsAuthority.js +426 -0
  82. package/dist/registries/glossaryReviewRecordsContract.js +129 -0
  83. package/dist/registries/glossaryTermIdentity.js +122 -0
  84. package/dist/registries/packagePublication.js +3 -3
  85. package/dist/registries/personalGlossaryContracts.js +1 -0
  86. package/dist/release/releaseMetadata.js +14 -7
  87. package/dist/upgrade/npxPlatformStatus.js +2 -1
  88. package/dist/upgrade/projectIntegration.js +7 -1
  89. package/dist/validate/activationArtifactEvidence.js +18 -4
  90. package/dist/validate/activationEvidenceManifest.js +101 -22
  91. package/package.json +2 -4
  92. package/dist/cli/commands/personalGlossary.js +0 -176
@@ -0,0 +1,24 @@
1
+ import { loadYamlMappingFile } from "../core/yaml.js";
2
+ import { glossaryEntryAuthorityPath } from "./glossaryEntryContract.js";
3
+ function mapping(value) {
4
+ return value !== null && typeof value === "object" && !Array.isArray(value)
5
+ ? value
6
+ : null;
7
+ }
8
+ function exactPositiveLimit(value, expected) {
9
+ if (!Number.isSafeInteger(value) || value !== expected) {
10
+ throw new TypeError("personal glossary Profile Full contract is unavailable");
11
+ }
12
+ return value;
13
+ }
14
+ /** Load the bounded Profile Full integration settings from the glossary authority. */
15
+ export function personalGlossaryProfileFullContract(pathname = glossaryEntryAuthorityPath()) {
16
+ const authority = loadYamlMappingFile(pathname);
17
+ const profileFull = mapping(mapping(authority.personal_mining_authority)?.profile_full);
18
+ const existingGeneration = mapping(profileFull?.existing_generation);
19
+ const review = mapping(profileFull?.review);
20
+ return {
21
+ candidateListLimit: exactPositiveLimit(existingGeneration?.list_limit, 20),
22
+ questionReviewMaximum: exactPositiveLimit(review?.question_channel_maximum, 3),
23
+ };
24
+ }
@@ -0,0 +1,426 @@
1
+ import { createHash, verify as verifySignature } from "node:crypto";
2
+ function mapping(value) {
3
+ return value !== null && typeof value === "object" && !Array.isArray(value)
4
+ ? value
5
+ : null;
6
+ }
7
+ function strings(value) {
8
+ return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : [];
9
+ }
10
+ function sameStrings(actual, expected) {
11
+ return JSON.stringify(strings(actual)) === JSON.stringify(expected);
12
+ }
13
+ function nonEmpty(value) {
14
+ return typeof value === "string" && value.trim().length > 0;
15
+ }
16
+ function sha256Utf8(value) {
17
+ return createHash("sha256").update(value, "utf8").digest("hex");
18
+ }
19
+ const REVIEW_RECEIPT_FIELDS = [
20
+ "schema_version",
21
+ "issuer",
22
+ "subject",
23
+ "trusted_channel",
24
+ "review_id",
25
+ "candidate_id",
26
+ "candidate_revision",
27
+ "candidate_projection_sha256",
28
+ "semantic_fingerprint",
29
+ "generation",
30
+ "policy_version",
31
+ "disposition",
32
+ "corrected_meaning",
33
+ "corrected_scope",
34
+ "disposed_at",
35
+ "expires_at",
36
+ "nonce",
37
+ "signature",
38
+ ];
39
+ const REVIEW_RECEIPT_SIGNED_FIELDS = REVIEW_RECEIPT_FIELDS.filter((field) => field !== "signature");
40
+ export const PERSONAL_REVIEW_DISPOSITIONS = ["accept", "correct", "reject", "defer"];
41
+ function receiptField(receipt, field) {
42
+ const value = receipt[field];
43
+ if (typeof value !== "string" || value.length === 0) {
44
+ throw new TypeError(`review approval receipt field ${field} must be a non-empty string`);
45
+ }
46
+ return value;
47
+ }
48
+ function nullableReceiptField(receipt, field) {
49
+ const value = receipt[field];
50
+ if (value !== null && typeof value !== "string") {
51
+ throw new TypeError(`review approval receipt field ${field} must be a string or null`);
52
+ }
53
+ return value;
54
+ }
55
+ function signedReviewReceiptPayload(receipt) {
56
+ return JSON.stringify(Object.fromEntries(REVIEW_RECEIPT_SIGNED_FIELDS.map((field) => [
57
+ field,
58
+ ["corrected_meaning", "corrected_scope"].includes(field)
59
+ ? nullableReceiptField(receipt, field)
60
+ : receiptField(receipt, field),
61
+ ])));
62
+ }
63
+ export function personalReviewApprovalReceiptDigest(receipt) {
64
+ const payload = signedReviewReceiptPayload(receipt);
65
+ return sha256Utf8(JSON.stringify({
66
+ signed: JSON.parse(payload),
67
+ signature: receiptField(receipt, "signature"),
68
+ }));
69
+ }
70
+ export function personalReviewApprovalReplayStatus(receipt, consumedReceiptDigests = new Map(), replayNonceKey) {
71
+ const nonce = receiptField(receipt, "nonce");
72
+ const key = replayNonceKey ?? nonce;
73
+ if (typeof key !== "string" || key.length === 0) {
74
+ throw new TypeError("review approval replay nonce key must be a non-empty string");
75
+ }
76
+ const consumedDigest = consumedReceiptDigests.get(key);
77
+ if (!consumedDigest)
78
+ return "new";
79
+ return consumedDigest === personalReviewApprovalReceiptDigest(receipt)
80
+ ? "exact_replay"
81
+ : "conflicting_replay";
82
+ }
83
+ export function validatePersonalReviewApprovalReceipt(receipt, expected) {
84
+ const errors = [];
85
+ const extraFields = Object.keys(receipt).filter((field) => !REVIEW_RECEIPT_FIELDS.includes(field));
86
+ if (extraFields.length > 0)
87
+ errors.push(`review approval receipt has forbidden fields: ${extraFields.join(", ")}`);
88
+ let payload = "";
89
+ let signature = "";
90
+ try {
91
+ payload = signedReviewReceiptPayload(receipt);
92
+ signature = receiptField(receipt, "signature");
93
+ }
94
+ catch (error) {
95
+ errors.push(error.message);
96
+ }
97
+ if (receipt.schema_version !== "agentera.personalGlossaryReviewApproval.v1") {
98
+ errors.push("review approval receipt schema_version is invalid");
99
+ }
100
+ if (receipt.issuer !== "agentera-local-host") {
101
+ errors.push("review approval receipt issuer is not trusted");
102
+ }
103
+ if (receipt.subject !== expected.currentUserSubject ||
104
+ ["agent", "model", "imported_record", "generic_consent"].includes(String(receipt.subject))) {
105
+ errors.push("review approval receipt subject is not the trusted current user");
106
+ }
107
+ if (receipt.trusted_channel !== "agentera-local-host-ipc") {
108
+ errors.push("review approval receipt trusted channel is invalid");
109
+ }
110
+ if (receipt.review_id !== expected.reviewId) {
111
+ errors.push("review approval receipt review binding is invalid");
112
+ }
113
+ if (receipt.candidate_id !== expected.candidateId) {
114
+ errors.push("review approval receipt candidate binding is invalid");
115
+ }
116
+ if (receipt.candidate_revision !== expected.candidateRevision) {
117
+ errors.push("review approval receipt revision binding is invalid");
118
+ }
119
+ if (receipt.candidate_projection_sha256 !== expected.candidateProjectionSha256) {
120
+ errors.push("review approval receipt projection binding is invalid");
121
+ }
122
+ if (receipt.semantic_fingerprint !== expected.semanticFingerprint) {
123
+ errors.push("review approval receipt semantic fingerprint binding is invalid");
124
+ }
125
+ if (receipt.generation !== expected.generation) {
126
+ errors.push("review approval receipt generation binding is invalid");
127
+ }
128
+ if (receipt.policy_version !== expected.policyVersion) {
129
+ errors.push("review approval receipt policy binding is invalid");
130
+ }
131
+ if (!PERSONAL_REVIEW_DISPOSITIONS.includes(receipt.disposition)) {
132
+ errors.push("review approval receipt disposition is invalid");
133
+ }
134
+ if (receipt.disposition === "correct") {
135
+ if (typeof receipt.corrected_meaning !== "string" ||
136
+ receipt.corrected_meaning.trim().length === 0 ||
137
+ Buffer.byteLength(receipt.corrected_meaning, "utf8") > 4_096) {
138
+ errors.push("review approval receipt corrected_meaning is invalid");
139
+ }
140
+ if (receipt.corrected_scope !== "personal") {
141
+ errors.push("review approval receipt corrected_scope is invalid");
142
+ }
143
+ }
144
+ else if (receipt.corrected_meaning !== null || receipt.corrected_scope !== null) {
145
+ errors.push("review approval receipt correction fields are invalid");
146
+ }
147
+ const disposedAt = Date.parse(String(receipt.disposed_at));
148
+ const expiresAt = Date.parse(String(receipt.expires_at));
149
+ const now = expected.now.getTime();
150
+ if (!Number.isFinite(disposedAt) || !Number.isFinite(expiresAt)) {
151
+ errors.push("review approval receipt freshness timestamps are invalid");
152
+ }
153
+ else {
154
+ if (disposedAt > now)
155
+ errors.push("review approval receipt disposed_at is in the future");
156
+ if (now - disposedAt > 300_000)
157
+ errors.push("review approval receipt is stale");
158
+ if (expiresAt <= now || expiresAt <= disposedAt) {
159
+ errors.push("review approval receipt expires_at is not current");
160
+ }
161
+ if (expiresAt - disposedAt > 300_000) {
162
+ errors.push("review approval receipt freshness window is too long");
163
+ }
164
+ }
165
+ if (!/^[A-Za-z0-9_-]+$/.test(signature)) {
166
+ errors.push("review approval receipt signature encoding is invalid");
167
+ }
168
+ else if (payload) {
169
+ try {
170
+ if (!verifySignature(null, Buffer.from(payload, "utf8"), expected.trustedHostPublicKey, Buffer.from(signature, "base64url"))) {
171
+ errors.push("review approval receipt signature is not from the trusted host");
172
+ }
173
+ }
174
+ catch {
175
+ errors.push("review approval receipt signature verification failed");
176
+ }
177
+ }
178
+ try {
179
+ if (personalReviewApprovalReplayStatus(receipt, expected.consumedReceiptDigests, expected.replayNonceKey) === "conflicting_replay") {
180
+ errors.push("review approval receipt nonce was replayed with changed content");
181
+ }
182
+ }
183
+ catch (error) {
184
+ errors.push(error.message);
185
+ }
186
+ return errors;
187
+ }
188
+ export function personalReviewDispositionLifecycle(disposition) {
189
+ if (["accept", "correct", "reject"].includes(disposition))
190
+ return "terminal";
191
+ if (disposition === "defer")
192
+ return "pending";
193
+ throw new TypeError("review disposition is invalid");
194
+ }
195
+ export function projectPersonalReviewRetention(disposition, ageDays, purgeRequested = false) {
196
+ if (!Number.isFinite(ageDays) || ageDays < 0)
197
+ throw new TypeError("review age must be non-negative");
198
+ if (purgeRequested)
199
+ return { excerpt: "purged", metadata: "purged" };
200
+ if (personalReviewDispositionLifecycle(disposition) === "pending") {
201
+ return {
202
+ excerpt: ageDays >= 30 ? "expired" : "retained",
203
+ metadata: "retained",
204
+ };
205
+ }
206
+ return {
207
+ excerpt: "purged",
208
+ metadata: ageDays >= 90 ? "expired" : "retained",
209
+ };
210
+ }
211
+ /** Validate the authority-owned private review-record persistence and read contract. */
212
+ export function validatePersonalGlossaryReviewRecordsAuthority(authority) {
213
+ const mining = mapping(authority.personal_mining_authority);
214
+ const records = mapping(mining?.review_records);
215
+ const persistence = mapping(records?.persistence);
216
+ const compatibility = mapping(persistence?.compatibility);
217
+ const queue = mapping(records?.queue);
218
+ const queueCommand = mapping(queue?.command);
219
+ const request = mapping(queue?.request);
220
+ const queueResult = mapping(queue?.result);
221
+ const disposition = mapping(records?.disposition);
222
+ const dispositionCommand = mapping(disposition?.command);
223
+ const dispositionRequest = mapping(disposition?.request);
224
+ const dispositionResult = mapping(disposition?.result);
225
+ const publicationAuthorization = mapping(disposition?.publication_authorization);
226
+ const trustedHostKey = mapping(records?.trusted_host_key);
227
+ const retrieval = mapping(records?.retrieval);
228
+ const retrievalCommand = mapping(retrieval?.command);
229
+ const list = mapping(retrieval?.list);
230
+ const filters = mapping(list?.filters);
231
+ const cursor = mapping(list?.cursor);
232
+ const exact = mapping(retrieval?.exact);
233
+ const maintenance = mapping(records?.maintenance);
234
+ if (records?.status !== "active" ||
235
+ records?.owner !== "user_local_review_lifecycle" ||
236
+ records?.runtime !==
237
+ "packages/cli/src/analytics/personalGlossaryReviewRecords.ts#queuePersonalGlossaryReviewRecord" ||
238
+ records?.input !== "current_validated_review_required_cli_decision_and_host_receipt" ||
239
+ persistence?.root !== "$AGENTERA_PROFILE_DIR/intermediate/personal-glossary" ||
240
+ persistence?.file !== "review-records.json" ||
241
+ persistence?.schema_version !== "agentera.personalGlossaryReviewStore.v2" ||
242
+ persistence?.record_schema_version !== "agentera.personalGlossaryReviewRecord.v2" ||
243
+ persistence?.owner !== "current_user" ||
244
+ !sameStrings(persistence?.fields, ["schema_version", "owner", "records", "replay_index", "store_sha256"]) ||
245
+ !sameStrings(persistence?.record_fields, [
246
+ "schema_version",
247
+ "owner",
248
+ "review_id",
249
+ "candidate_id",
250
+ "candidate_revision",
251
+ "candidate_capsule_sha256",
252
+ "candidate_projection_sha256",
253
+ "host_receipt_sha256",
254
+ "cli_decision_sha256",
255
+ "semantic_fingerprint",
256
+ "generation",
257
+ "policy_version",
258
+ "scope",
259
+ "reason",
260
+ "status",
261
+ "disposition",
262
+ "review_record",
263
+ "reopen_reason",
264
+ "queued_at",
265
+ "terminal_at",
266
+ "expires_at",
267
+ "record_sha256",
268
+ ]) ||
269
+ persistence?.records_max !== 100 ||
270
+ !sameStrings(persistence?.replay_index_fields, ["nonce_sha256", "receipt_sha256", "expires_at"]) ||
271
+ persistence?.replay_entries_max !== 100 ||
272
+ persistence?.record_max_serialized_utf8_bytes !== 8_192 ||
273
+ persistence?.max_serialized_utf8_bytes !== 1_048_576 ||
274
+ persistence?.canonicalization !== "candidate_contracts.canonicalization" ||
275
+ persistence?.order !== "review_id_asc" ||
276
+ persistence?.replay !== "exact_current_binding_is_unchanged_replay_and_exact_receipt_is_idempotent" ||
277
+ persistence?.conflict !== "changed_receipt_nonce_binding_or_signature_fails_before_effects" ||
278
+ !sameStrings(compatibility?.accepted_store_schema_versions, [
279
+ "agentera.personalGlossaryReviewStore.v1",
280
+ "agentera.personalGlossaryReviewStore.v2",
281
+ ]) ||
282
+ !sameStrings(compatibility?.accepted_record_schema_versions, [
283
+ "agentera.personalGlossaryPendingReviewRecord.v1",
284
+ "agentera.personalGlossaryReviewRecord.v2",
285
+ ]) ||
286
+ compatibility?.read_mutation !== "forbidden" ||
287
+ compatibility?.migration_operation !== "disposition_only" ||
288
+ compatibility?.scope_derivation !== "current_validated_host_receipt_only" ||
289
+ compatibility?.invalid_behavior !== "fail_before_effects" ||
290
+ !sameStrings(compatibility?.preserved_bindings, [
291
+ "review_id",
292
+ "candidate_id",
293
+ "candidate_revision",
294
+ "candidate_capsule_sha256",
295
+ "candidate_projection_sha256",
296
+ "host_receipt_sha256",
297
+ "cli_decision_sha256",
298
+ "semantic_fingerprint",
299
+ "generation",
300
+ "policy_version",
301
+ "reason",
302
+ ]) ||
303
+ compatibility?.legacy_digest !== "validate_before_migration" ||
304
+ compatibility?.migrated_digest !== "reseal_v2_lifecycle_record" ||
305
+ !nonEmpty(compatibility?.rule) ||
306
+ !sameStrings(persistence?.suppression_binding, ["candidate_id", "semantic_fingerprint", "scope", "policy_version"]) ||
307
+ !sameStrings(persistence?.suppression_dispositions, ["reject", "defer"]) ||
308
+ !sameStrings(persistence?.reopen_reasons, ["policy_changed", "scope_changed", "meaning_changed"]) ||
309
+ persistence?.project_storage !== "forbidden" ||
310
+ !sameStrings(persistence?.forbidden_fields, [
311
+ "term",
312
+ "meaning",
313
+ "excerpt",
314
+ "raw_evidence",
315
+ "source_id",
316
+ "evidence_anchor",
317
+ "session_id",
318
+ "project_id",
319
+ "source_path",
320
+ "tool_content",
321
+ "review_approval",
322
+ "signature",
323
+ "nonce",
324
+ ]) ||
325
+ !nonEmpty(persistence?.rule) ||
326
+ trustedHostKey?.root !== "$AGENTERA_PROFILE_DIR/intermediate/personal-glossary" ||
327
+ trustedHostKey?.file !== "trusted-local-host.json" ||
328
+ trustedHostKey?.schema_version !== "agentera.personalGlossaryTrustedLocalHost.v1" ||
329
+ !sameStrings(trustedHostKey?.fields, ["schema_version", "owner", "subject", "public_key_spki_base64url"]) ||
330
+ trustedHostKey?.owner !== "current_user" ||
331
+ trustedHostKey?.public_key_algorithm !== "ed25519" ||
332
+ trustedHostKey?.max_serialized_utf8_bytes !== 4_096 ||
333
+ !nonEmpty(trustedHostKey?.rule) ||
334
+ queueCommand?.canonical !== "npx -y agentera@next report personal-glossary-reviews" ||
335
+ queueCommand?.namespace !== "report" ||
336
+ queueCommand?.input_flag !== "--input" ||
337
+ queueCommand?.stdin_value !== "-" ||
338
+ queueCommand?.format !== "json" ||
339
+ queueCommand?.project_checkout !== "not_required" ||
340
+ request?.schema_version !== "agentera.personalGlossaryReviewQueueRequest.v1" ||
341
+ !sameStrings(request?.required_fields, ["schema_version", "receipt"]) ||
342
+ request?.additional_fields !== "forbidden" ||
343
+ request?.max_utf8_bytes !== 16_384 ||
344
+ queue?.decision_outcome !== "review_required" ||
345
+ !sameStrings(queue?.current_bindings, [
346
+ "candidate_id",
347
+ "candidate_revision",
348
+ "candidate_capsule_sha256",
349
+ "candidate_projection_sha256",
350
+ "host_receipt_sha256",
351
+ "cli_decision_sha256",
352
+ "semantic_fingerprint",
353
+ "generation",
354
+ "policy_version",
355
+ "reason",
356
+ ]) ||
357
+ queueResult?.schema_version !== "agentera.personalGlossaryReviewQueueResult.v1" ||
358
+ !sameStrings(queueResult?.statuses, ["queued", "unchanged_replay", "suppressed", "reopened"]) ||
359
+ queueResult?.max_utf8_bytes !== 4_096 ||
360
+ queue?.no_question_channel !== "queue_without_prompt_or_disposition" ||
361
+ !nonEmpty(queue?.rule) ||
362
+ dispositionCommand?.canonical !== "npx -y agentera@next report personal-glossary-reviews" ||
363
+ dispositionCommand?.namespace !== "report" ||
364
+ dispositionCommand?.input_flag !== "--input" ||
365
+ dispositionCommand?.stdin_value !== "-" ||
366
+ dispositionCommand?.format !== "json" ||
367
+ dispositionCommand?.project_checkout !== "not_required" ||
368
+ dispositionRequest?.schema_version !== "agentera.personalGlossaryReviewDispositionRequest.v1" ||
369
+ !sameStrings(dispositionRequest?.required_fields, ["schema_version", "review_id", "receipt", "approval"]) ||
370
+ dispositionRequest?.additional_fields !== "forbidden" ||
371
+ dispositionRequest?.max_utf8_bytes !== 16_384 ||
372
+ dispositionResult?.schema_version !== "agentera.personalGlossaryReviewDispositionResult.v1" ||
373
+ !sameStrings(dispositionResult?.statuses, ["disposed", "unchanged_replay"]) ||
374
+ dispositionResult?.max_utf8_bytes !== 4_096 ||
375
+ !sameStrings(publicationAuthorization?.dispositions, ["accept", "correct"]) ||
376
+ !sameStrings(publicationAuthorization?.fields, ["review_id", "review_record_sha256"]) ||
377
+ !nonEmpty(disposition?.rule) ||
378
+ retrievalCommand?.canonical !== "npx -y agentera@next report personal-glossary-reviews" ||
379
+ retrievalCommand?.namespace !== "report" ||
380
+ retrievalCommand?.format !== "json" ||
381
+ retrievalCommand?.project_checkout !== "not_required" ||
382
+ retrieval?.owner !== "current_user" ||
383
+ retrieval?.schema_version !== "agentera.personalGlossaryReviewRetrieval.v1" ||
384
+ list?.default_limit !== 20 ||
385
+ list?.maximum_limit !== 50 ||
386
+ list?.max_serialized_utf8_bytes !== 32_768 ||
387
+ list?.order !== "queued_at_desc_then_review_id_asc" ||
388
+ !sameStrings(filters?.status, ["pending", "terminal"]) ||
389
+ cursor?.authority !==
390
+ "references/artifacts/state-storage-authority.yaml#entity_target.public_retrieval.policy.cursor" ||
391
+ cursor?.vocabulary !== "opaque_snapshot_cursor" ||
392
+ !sameStrings(cursor?.binding, ["collection", "owner", "filters", "limit", "order", "snapshot"]) ||
393
+ cursor?.invalid_behavior !== "cursor_invalid" ||
394
+ cursor?.unavailable_behavior !== "cursor_snapshot_unavailable" ||
395
+ !nonEmpty(list?.summaries) ||
396
+ !sameStrings(exact?.required_bindings, [
397
+ "review_id",
398
+ "candidate_id",
399
+ "candidate_revision",
400
+ "generation",
401
+ "policy_version",
402
+ ]) ||
403
+ exact?.current_binding_field !== "candidate_projection_sha256" ||
404
+ exact?.max_serialized_utf8_bytes !== 8_192 ||
405
+ !nonEmpty(exact?.rule) ||
406
+ !nonEmpty(retrieval?.rule) ||
407
+ maintenance?.entrypoint !==
408
+ "packages/cli/src/analytics/personalGlossaryReviewRecords.ts#maintainPersonalGlossaryReviewRecords" ||
409
+ maintenance?.exposure !== "authenticated_review_owner_only" ||
410
+ maintenance?.terminal_metadata_days !== 90 ||
411
+ maintenance?.pending_metadata !== "retained_until_terminal_or_purge" ||
412
+ maintenance?.cache !== "replay_index_until_receipt_expiry" ||
413
+ maintenance?.purge !== "current_user_authorized_review_records_only" ||
414
+ !sameStrings(maintenance?.forbidden_effects, [
415
+ "profile_entry",
416
+ "project_state",
417
+ "candidate_projection",
418
+ "publication",
419
+ ]) ||
420
+ !nonEmpty(maintenance?.rule)) {
421
+ return [
422
+ "personal_mining_authority review records must remain bounded, current-user local, privacy-safe, replay-safe, and independently retained",
423
+ ];
424
+ }
425
+ return [];
426
+ }
@@ -0,0 +1,129 @@
1
+ import { loadYamlMappingFile } from "../core/yaml.js";
2
+ import { projectGlossaryDevelopmentValue } from "../core/developmentInvocation.js";
3
+ import { glossaryEntryAuthorityPath } from "./glossaryEntryContract.js";
4
+ function mapping(value) {
5
+ return value !== null && typeof value === "object" && !Array.isArray(value)
6
+ ? value
7
+ : null;
8
+ }
9
+ function strings(value) {
10
+ return Array.isArray(value) && value.every((item) => typeof item === "string")
11
+ ? [...value]
12
+ : [];
13
+ }
14
+ /** Load the authority-owned private review persistence, retrieval, and maintenance settings. */
15
+ export function personalGlossaryReviewRecordsContract(pathname = glossaryEntryAuthorityPath()) {
16
+ const authority = loadYamlMappingFile(pathname);
17
+ const mining = mapping(authority.personal_mining_authority);
18
+ const records = mapping(mining?.review_records);
19
+ const persistence = mapping(records?.persistence);
20
+ const compatibility = mapping(persistence?.compatibility);
21
+ const queue = mapping(records?.queue);
22
+ const queueCommand = mapping(queue?.command);
23
+ const request = mapping(queue?.request);
24
+ const queueResult = mapping(queue?.result);
25
+ const disposition = mapping(records?.disposition);
26
+ const dispositionCommand = mapping(disposition?.command);
27
+ const dispositionRequest = mapping(disposition?.request);
28
+ const dispositionResult = mapping(disposition?.result);
29
+ const publicationAuthorization = mapping(disposition?.publication_authorization);
30
+ const trustedHostKey = mapping(records?.trusted_host_key);
31
+ const retrieval = mapping(records?.retrieval);
32
+ const retrievalCommand = mapping(retrieval?.command);
33
+ const list = mapping(retrieval?.list);
34
+ const filters = mapping(list?.filters);
35
+ const cursor = mapping(list?.cursor);
36
+ const exact = mapping(retrieval?.exact);
37
+ const maintenance = mapping(records?.maintenance);
38
+ const command = projectGlossaryDevelopmentValue(queueCommand?.canonical, "review_records.command");
39
+ const retrievalCommandValue = projectGlossaryDevelopmentValue(retrievalCommand?.canonical, "review_records.command");
40
+ if (command !== retrievalCommandValue) {
41
+ throw new TypeError("invalid development command projection: personal glossary review commands differ");
42
+ }
43
+ const dispositionCommandValue = projectGlossaryDevelopmentValue(dispositionCommand?.canonical, "review_records.command");
44
+ if (command !== dispositionCommandValue) {
45
+ throw new TypeError("invalid development command projection: personal glossary review disposition commands differ");
46
+ }
47
+ return {
48
+ command,
49
+ queueRequestSchemaVersion: typeof request?.schema_version === "string" ? request.schema_version : "",
50
+ queueRequestFields: strings(request?.required_fields),
51
+ queueMaxRequestUtf8Bytes: typeof request?.max_utf8_bytes === "number" ? request.max_utf8_bytes : 0,
52
+ queueDecisionOutcome: typeof queue?.decision_outcome === "string" ? queue.decision_outcome : "",
53
+ queueCurrentBindings: strings(queue?.current_bindings),
54
+ queueResultSchemaVersion: typeof queueResult?.schema_version === "string" ? queueResult.schema_version : "",
55
+ queueResultStatuses: strings(queueResult?.statuses),
56
+ queueMaxResultUtf8Bytes: typeof queueResult?.max_utf8_bytes === "number" ? queueResult.max_utf8_bytes : 0,
57
+ queueNoQuestionChannel: typeof queue?.no_question_channel === "string" ? queue.no_question_channel : "",
58
+ dispositionRequestSchemaVersion: typeof dispositionRequest?.schema_version === "string" ? dispositionRequest.schema_version : "",
59
+ dispositionRequestFields: strings(dispositionRequest?.required_fields),
60
+ dispositionMaxRequestUtf8Bytes: typeof dispositionRequest?.max_utf8_bytes === "number" ? dispositionRequest.max_utf8_bytes : 0,
61
+ dispositionResultSchemaVersion: typeof dispositionResult?.schema_version === "string" ? dispositionResult.schema_version : "",
62
+ dispositionResultStatuses: strings(dispositionResult?.statuses),
63
+ dispositionMaxResultUtf8Bytes: typeof dispositionResult?.max_utf8_bytes === "number" ? dispositionResult.max_utf8_bytes : 0,
64
+ dispositionPublicationAuthorizationDispositions: strings(publicationAuthorization?.dispositions),
65
+ dispositionPublicationAuthorizationFields: strings(publicationAuthorization?.fields),
66
+ trustedHostKeyFile: typeof trustedHostKey?.file === "string" ? trustedHostKey.file : "",
67
+ trustedHostKeySchemaVersion: typeof trustedHostKey?.schema_version === "string" ? trustedHostKey.schema_version : "",
68
+ trustedHostKeyFields: strings(trustedHostKey?.fields),
69
+ trustedHostKeyOwner: typeof trustedHostKey?.owner === "string" ? trustedHostKey.owner : "",
70
+ trustedHostKeyAlgorithm: typeof trustedHostKey?.public_key_algorithm === "string" ? trustedHostKey.public_key_algorithm : "",
71
+ trustedHostKeyMaxSerializedUtf8Bytes: typeof trustedHostKey?.max_serialized_utf8_bytes === "number"
72
+ ? trustedHostKey.max_serialized_utf8_bytes
73
+ : 0,
74
+ storeSchemaVersion: typeof persistence?.schema_version === "string" ? persistence.schema_version : "",
75
+ recordSchemaVersion: typeof persistence?.record_schema_version === "string" ? persistence.record_schema_version : "",
76
+ storeOwner: typeof persistence?.owner === "string" ? persistence.owner : "",
77
+ storeFile: typeof persistence?.file === "string" ? persistence.file : "",
78
+ storeFields: strings(persistence?.fields),
79
+ recordFields: strings(persistence?.record_fields),
80
+ recordsMax: typeof persistence?.records_max === "number" ? persistence.records_max : 0,
81
+ replayIndexFields: strings(persistence?.replay_index_fields),
82
+ replayEntriesMax: typeof persistence?.replay_entries_max === "number" ? persistence.replay_entries_max : 0,
83
+ recordMaxSerializedUtf8Bytes: typeof persistence?.record_max_serialized_utf8_bytes === "number"
84
+ ? persistence.record_max_serialized_utf8_bytes
85
+ : 0,
86
+ storeMaxSerializedUtf8Bytes: typeof persistence?.max_serialized_utf8_bytes === "number"
87
+ ? persistence.max_serialized_utf8_bytes
88
+ : 0,
89
+ storeOrder: typeof persistence?.order === "string" ? persistence.order : "",
90
+ replay: typeof persistence?.replay === "string" ? persistence.replay : "",
91
+ conflict: typeof persistence?.conflict === "string" ? persistence.conflict : "",
92
+ compatibilityStoreSchemaVersions: strings(compatibility?.accepted_store_schema_versions),
93
+ compatibilityRecordSchemaVersions: strings(compatibility?.accepted_record_schema_versions),
94
+ compatibilityReadMutation: typeof compatibility?.read_mutation === "string" ? compatibility.read_mutation : "",
95
+ compatibilityMigrationOperation: typeof compatibility?.migration_operation === "string" ? compatibility.migration_operation : "",
96
+ compatibilityScopeDerivation: typeof compatibility?.scope_derivation === "string" ? compatibility.scope_derivation : "",
97
+ compatibilityInvalidBehavior: typeof compatibility?.invalid_behavior === "string" ? compatibility.invalid_behavior : "",
98
+ compatibilityPreservedBindings: strings(compatibility?.preserved_bindings),
99
+ compatibilityLegacyDigest: typeof compatibility?.legacy_digest === "string" ? compatibility.legacy_digest : "",
100
+ compatibilityMigratedDigest: typeof compatibility?.migrated_digest === "string" ? compatibility.migrated_digest : "",
101
+ suppressionBinding: strings(persistence?.suppression_binding),
102
+ suppressionDispositions: strings(persistence?.suppression_dispositions),
103
+ reopenReasons: strings(persistence?.reopen_reasons),
104
+ forbiddenFields: strings(persistence?.forbidden_fields),
105
+ retrievalSchemaVersion: typeof retrieval?.schema_version === "string" ? retrieval.schema_version : "",
106
+ retrievalOwner: typeof retrieval?.owner === "string" ? retrieval.owner : "",
107
+ listDefaultLimit: typeof list?.default_limit === "number" ? list.default_limit : 0,
108
+ listMaximumLimit: typeof list?.maximum_limit === "number" ? list.maximum_limit : 0,
109
+ listMaxSerializedUtf8Bytes: typeof list?.max_serialized_utf8_bytes === "number" ? list.max_serialized_utf8_bytes : 0,
110
+ listOrder: typeof list?.order === "string" ? list.order : "",
111
+ listStatuses: strings(filters?.status),
112
+ cursorAuthority: typeof cursor?.authority === "string" ? cursor.authority : "",
113
+ cursorVocabulary: typeof cursor?.vocabulary === "string" ? cursor.vocabulary : "",
114
+ cursorBinding: strings(cursor?.binding),
115
+ cursorInvalidBehavior: typeof cursor?.invalid_behavior === "string" ? cursor.invalid_behavior : "",
116
+ cursorUnavailableBehavior: typeof cursor?.unavailable_behavior === "string" ? cursor.unavailable_behavior : "",
117
+ exactRequiredBindings: strings(exact?.required_bindings),
118
+ exactCurrentBindingField: typeof exact?.current_binding_field === "string" ? exact.current_binding_field : "",
119
+ exactMaxSerializedUtf8Bytes: typeof exact?.max_serialized_utf8_bytes === "number"
120
+ ? exact.max_serialized_utf8_bytes
121
+ : 0,
122
+ terminalMetadataDays: typeof maintenance?.terminal_metadata_days === "number"
123
+ ? maintenance.terminal_metadata_days
124
+ : 0,
125
+ maintenanceExposure: typeof maintenance?.exposure === "string" ? maintenance.exposure : "",
126
+ maintenancePurge: typeof maintenance?.purge === "string" ? maintenance.purge : "",
127
+ maintenanceForbiddenEffects: strings(maintenance?.forbidden_effects),
128
+ };
129
+ }