agentera 3.0.0-dev.26 → 3.0.0-dev.28

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 (385) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +13 -3
  3. package/bundle/CHANGELOG.md +14 -1
  4. package/bundle/DESIGN.md +3 -7
  5. package/bundle/README.md +1 -4
  6. package/bundle/UPGRADE.md +33 -0
  7. package/bundle/fixtures/routing/hybrid-corpus.yaml +154 -0
  8. package/bundle/references/adapters/package-registry.yaml +2 -0
  9. package/bundle/references/adapters/package-surface-characterization.md +10 -5
  10. package/bundle/references/analysis/benchmark.md +4 -0
  11. package/bundle/references/analysis/verification-policy.yaml +142 -0
  12. package/bundle/references/artifacts/state-storage-authority.yaml +303 -14
  13. package/bundle/references/cli/capability-instruction-structure.md +2 -2
  14. package/bundle/references/cli/hybrid-route-contract.yaml +416 -0
  15. package/bundle/references/cli/prime-consumer-compatibility.yaml +77 -32
  16. package/bundle/references/cli/routing-model.md +136 -91
  17. package/bundle/references/cli/trigger-schema-enrichment.md +50 -46
  18. package/bundle/references/cli/vocabulary.md +7 -9
  19. package/bundle/references/meta/documentation-inventory.md +2 -2
  20. package/bundle/skills/agentera/SKILL.md +50 -18
  21. package/bundle/skills/agentera/capabilities/audit/schemas/triggers.yaml +13 -35
  22. package/bundle/skills/agentera/capabilities/build/schemas/triggers.yaml +14 -36
  23. package/bundle/skills/agentera/capabilities/design/schemas/triggers.yaml +5 -34
  24. package/bundle/skills/agentera/capabilities/discuss/schemas/triggers.yaml +6 -40
  25. package/bundle/skills/agentera/capabilities/document/schemas/triggers.yaml +5 -34
  26. package/bundle/skills/agentera/capabilities/optimize/schemas/triggers.yaml +4 -35
  27. package/bundle/skills/agentera/capabilities/orchestrate/schemas/artifacts.yaml +3 -2
  28. package/bundle/skills/agentera/capabilities/orchestrate/schemas/exit.yaml +1 -1
  29. package/bundle/skills/agentera/capabilities/orchestrate/schemas/triggers.yaml +5 -37
  30. package/bundle/skills/agentera/capabilities/plan/schemas/triggers.yaml +8 -31
  31. package/bundle/skills/agentera/capabilities/profile/schemas/triggers.yaml +8 -37
  32. package/bundle/skills/agentera/capabilities/research/schemas/triggers.yaml +5 -29
  33. package/bundle/skills/agentera/capabilities/status/schemas/triggers.yaml +7 -47
  34. package/bundle/skills/agentera/capabilities/vision/schemas/triggers.yaml +7 -39
  35. package/bundle/skills/agentera/capability_schema_contract.yaml +29 -29
  36. package/bundle/skills/agentera/route-phrases.yaml +81 -0
  37. package/bundle/skills/agentera/schemas/artifacts/plan.yaml +23 -5
  38. package/dist/analytics/extractCorpus/cli.js.map +1 -1
  39. package/dist/analytics/extractCorpus/copilotSessions.js.map +1 -1
  40. package/dist/analytics/extractCorpus/core.js.map +1 -1
  41. package/dist/analytics/extractCorpus/corpus.js.map +1 -1
  42. package/dist/analytics/extractCorpus/coverageAudit.js.map +1 -1
  43. package/dist/analytics/extractCorpus/cursorSessions.js.map +1 -1
  44. package/dist/analytics/extractCorpus/evidenceTiers.js.map +1 -1
  45. package/dist/analytics/extractCorpus/extractCorpusParity.js +1 -1
  46. package/dist/analytics/extractCorpus/extractCorpusParity.js.map +1 -1
  47. package/dist/analytics/extractCorpus/filesystemSources.js.map +1 -1
  48. package/dist/analytics/extractCorpus/index.js.map +1 -1
  49. package/dist/analytics/extractCorpus/jsonlSessions.js.map +1 -1
  50. package/dist/analytics/extractCorpus/sqliteCaps.js.map +1 -1
  51. package/dist/analytics/extractCorpus/sqliteSessions.js.map +1 -1
  52. package/dist/analytics/extractCorpus/tierReader.js.map +1 -1
  53. package/dist/analytics/extractCorpus.js.map +1 -1
  54. package/dist/analytics/profileSignals.js.map +1 -1
  55. package/dist/analytics/usageStats.js.map +1 -1
  56. package/dist/bin/agentera.js.map +1 -1
  57. package/dist/capabilities/audit/instructions.js.map +1 -1
  58. package/dist/capabilities/build/instructions.js.map +1 -1
  59. package/dist/capabilities/design/instructions.js.map +1 -1
  60. package/dist/capabilities/discuss/instructions.js +1 -1
  61. package/dist/capabilities/discuss/instructions.js.map +1 -1
  62. package/dist/capabilities/document/instructions.js.map +1 -1
  63. package/dist/capabilities/index.js.map +1 -1
  64. package/dist/capabilities/optimize/instructions.js.map +1 -1
  65. package/dist/capabilities/orchestrate/instructions.js +1 -1
  66. package/dist/capabilities/orchestrate/instructions.js.map +1 -1
  67. package/dist/capabilities/plan/instructions.js +1 -1
  68. package/dist/capabilities/plan/instructions.js.map +1 -1
  69. package/dist/capabilities/profile/instructions.js.map +1 -1
  70. package/dist/capabilities/research/instructions.js.map +1 -1
  71. package/dist/capabilities/status/instructions.js.map +1 -1
  72. package/dist/capabilities/status/startupInstructions.js.map +1 -1
  73. package/dist/capabilities/vision/instructions.js.map +1 -1
  74. package/dist/cli/appContext.js.map +1 -1
  75. package/dist/cli/argvalidate.js.map +1 -1
  76. package/dist/cli/capabilityContext/benchmark.js.map +1 -1
  77. package/dist/cli/capabilityContext/bespoke.js.map +1 -1
  78. package/dist/cli/capabilityContext/build.js.map +1 -1
  79. package/dist/cli/capabilityContext/closeout.js.map +1 -1
  80. package/dist/cli/capabilityContext/contract.js.map +1 -1
  81. package/dist/cli/capabilityContext/evidence.js +1 -1
  82. package/dist/cli/capabilityContext/evidence.js.map +1 -1
  83. package/dist/cli/capabilityContext/index.js.map +1 -1
  84. package/dist/cli/capabilityContext/orchestration.js +15 -5
  85. package/dist/cli/capabilityContext/orchestration.js.map +1 -1
  86. package/dist/cli/capabilityContext/planState.js +1 -1
  87. package/dist/cli/capabilityContext/planState.js.map +1 -1
  88. package/dist/cli/capabilityContext/progress.js.map +1 -1
  89. package/dist/cli/capabilityContext/shared.js.map +1 -1
  90. package/dist/cli/capabilityContext/slim.js +16 -3
  91. package/dist/cli/capabilityContext/slim.js.map +1 -1
  92. package/dist/cli/capabilityContext/startup.js +3 -0
  93. package/dist/cli/capabilityContext/startup.js.map +1 -1
  94. package/dist/cli/capabilityContext/types.js.map +1 -1
  95. package/dist/cli/capabilityContext.js.map +1 -1
  96. package/dist/cli/commands/appHome.js.map +1 -1
  97. package/dist/cli/commands/capability.js.map +1 -1
  98. package/dist/cli/commands/compact.js.map +1 -1
  99. package/dist/cli/commands/doctor.js.map +1 -1
  100. package/dist/cli/commands/durability.js.map +1 -1
  101. package/dist/cli/commands/entityMigrate.js +7 -3
  102. package/dist/cli/commands/entityMigrate.js.map +1 -1
  103. package/dist/cli/commands/lint.js.map +1 -1
  104. package/dist/cli/commands/prime/briefOrientation.js +33 -8
  105. package/dist/cli/commands/prime/briefOrientation.js.map +1 -1
  106. package/dist/cli/commands/prime/bundleStatus.js.map +1 -1
  107. package/dist/cli/commands/prime/collectEntityOrientation.js +117 -18
  108. package/dist/cli/commands/prime/collectEntityOrientation.js.map +1 -1
  109. package/dist/cli/commands/prime/collectOrientationState.js +4 -2
  110. package/dist/cli/commands/prime/collectOrientationState.js.map +1 -1
  111. package/dist/cli/commands/prime/orientationOutput.js +47 -18
  112. package/dist/cli/commands/prime/orientationOutput.js.map +1 -1
  113. package/dist/cli/commands/prime/types.js.map +1 -1
  114. package/dist/cli/commands/prime/v1Migration.js.map +1 -1
  115. package/dist/cli/commands/prime.js +47 -23
  116. package/dist/cli/commands/prime.js.map +1 -1
  117. package/dist/cli/commands/query.js.map +1 -1
  118. package/dist/cli/commands/report.js.map +1 -1
  119. package/dist/cli/commands/route.js +142 -0
  120. package/dist/cli/commands/route.js.map +1 -0
  121. package/dist/cli/commands/schema.js.map +1 -1
  122. package/dist/cli/commands/state/decisions.js.map +1 -1
  123. package/dist/cli/commands/state/docs.js.map +1 -1
  124. package/dist/cli/commands/state/experimentRecords.js.map +1 -1
  125. package/dist/cli/commands/state/experiments.js.map +1 -1
  126. package/dist/cli/commands/state/get.js.map +1 -1
  127. package/dist/cli/commands/state/health.js.map +1 -1
  128. package/dist/cli/commands/state/index.js.map +1 -1
  129. package/dist/cli/commands/state/list.js.map +1 -1
  130. package/dist/cli/commands/state/objective.js.map +1 -1
  131. package/dist/cli/commands/state/plan.js.map +1 -1
  132. package/dist/cli/commands/state/planTasks.js.map +1 -1
  133. package/dist/cli/commands/state/plans.js.map +1 -1
  134. package/dist/cli/commands/state/progress.js.map +1 -1
  135. package/dist/cli/commands/state/shared.js.map +1 -1
  136. package/dist/cli/commands/state/todo.js.map +1 -1
  137. package/dist/cli/commands/state/write.js +21 -2
  138. package/dist/cli/commands/state/write.js.map +1 -1
  139. package/dist/cli/commands/upgrade.js.map +1 -1
  140. package/dist/cli/commands/upgradeVerify.js.map +1 -1
  141. package/dist/cli/commands/validate.js.map +1 -1
  142. package/dist/cli/commands/verify.js +17 -1
  143. package/dist/cli/commands/verify.js.map +1 -1
  144. package/dist/cli/contracts/bundleStatus.js.map +1 -1
  145. package/dist/cli/contracts/orientationState.js.map +1 -1
  146. package/dist/cli/dispatch/argvParser.js.map +1 -1
  147. package/dist/cli/dispatch/check.js.map +1 -1
  148. package/dist/cli/dispatch/commands.js.map +1 -1
  149. package/dist/cli/dispatch/index.js +18 -0
  150. package/dist/cli/dispatch/index.js.map +1 -1
  151. package/dist/cli/dispatch/lifecycle.js.map +1 -1
  152. package/dist/cli/dispatch/prime.js.map +1 -1
  153. package/dist/cli/dispatch/shared.js.map +1 -1
  154. package/dist/cli/dispatch/state.js.map +1 -1
  155. package/dist/cli/dispatch.js.map +1 -1
  156. package/dist/cli/errors.js +2 -2
  157. package/dist/cli/errors.js.map +1 -1
  158. package/dist/cli/help.js +20 -1
  159. package/dist/cli/help.js.map +1 -1
  160. package/dist/cli/migrationRequired.js +1 -1
  161. package/dist/cli/migrationRequired.js.map +1 -1
  162. package/dist/cli/orientation/attention.js.map +1 -1
  163. package/dist/cli/orientation/corpusCoverage.js.map +1 -1
  164. package/dist/cli/orientation.js +18 -4
  165. package/dist/cli/orientation.js.map +1 -1
  166. package/dist/cli/planArtifacts.js.map +1 -1
  167. package/dist/cli/planEvidence.js.map +1 -1
  168. package/dist/cli/planLifecycleState.js.map +1 -1
  169. package/dist/cli/planTaskIndex.js +12 -0
  170. package/dist/cli/planTaskIndex.js.map +1 -0
  171. package/dist/cli/prime-blob.js +1 -1
  172. package/dist/cli/prime-blob.js.map +1 -1
  173. package/dist/cli/startupCompletenessContract.js.map +1 -1
  174. package/dist/cli/stateQuery.js.map +1 -1
  175. package/dist/cli/structured.js.map +1 -1
  176. package/dist/cli/todoMarkdown.js.map +1 -1
  177. package/dist/cli/todoSeverity.js.map +1 -1
  178. package/dist/core/atomicWriter.js.map +1 -1
  179. package/dist/core/difflib.js.map +1 -1
  180. package/dist/core/envPaths.js.map +1 -1
  181. package/dist/core/jsonValue.js.map +1 -1
  182. package/dist/core/paths.js.map +1 -1
  183. package/dist/core/pyjson.js.map +1 -1
  184. package/dist/core/skillIdentity.js.map +1 -1
  185. package/dist/core/sourceRoot.js.map +1 -1
  186. package/dist/core/text.js.map +1 -1
  187. package/dist/core/toml.js.map +1 -1
  188. package/dist/core/yaml.js.map +1 -1
  189. package/dist/eval/evalSkills.js.map +1 -1
  190. package/dist/eval/hybridRouteEvaluation.js +156 -0
  191. package/dist/eval/hybridRouteEvaluation.js.map +1 -0
  192. package/dist/eval/semanticEval.js.map +1 -1
  193. package/dist/eval/semanticFixtures.js.map +1 -1
  194. package/dist/hooks/common.js.map +1 -1
  195. package/dist/hooks/compaction/apply.js.map +1 -1
  196. package/dist/hooks/compaction/dryRun.js.map +1 -1
  197. package/dist/hooks/compaction/index.js.map +1 -1
  198. package/dist/hooks/compaction/parse.js.map +1 -1
  199. package/dist/hooks/compaction/retention.js.map +1 -1
  200. package/dist/hooks/compaction/status.js.map +1 -1
  201. package/dist/hooks/compaction/types.js.map +1 -1
  202. package/dist/hooks/cursorPreToolUse.js.map +1 -1
  203. package/dist/hooks/cursorSessionStart.js.map +1 -1
  204. package/dist/hooks/projectHookInput.js.map +1 -1
  205. package/dist/hooks/sessionStart.js.map +1 -1
  206. package/dist/hooks/sessionStop.js.map +1 -1
  207. package/dist/hooks/validateArtifact/agentFacing.js.map +1 -1
  208. package/dist/hooks/validateArtifact/index.js.map +1 -1
  209. package/dist/hooks/validateArtifact/markdown.js.map +1 -1
  210. package/dist/hooks/validateArtifact/runtime.js.map +1 -1
  211. package/dist/hooks/validateArtifact/schema.js.map +1 -1
  212. package/dist/hooks/validateArtifact/traversal.js.map +1 -1
  213. package/dist/hooks/validateArtifact/violations.js.map +1 -1
  214. package/dist/migrate/v2HandoffManifest.js.map +1 -1
  215. package/dist/registries/artifactProtocolIds.js.map +1 -1
  216. package/dist/registries/artifactRegistry.js.map +1 -1
  217. package/dist/registries/capabilityContract.js +5 -20
  218. package/dist/registries/capabilityContract.js.map +1 -1
  219. package/dist/registries/evaluatorHandoffContract.js.map +1 -1
  220. package/dist/registries/evidenceTierContract.js.map +1 -1
  221. package/dist/registries/hybridRoute.js +203 -0
  222. package/dist/registries/hybridRoute.js.map +1 -0
  223. package/dist/registries/hybridRouteReceipt.js +221 -0
  224. package/dist/registries/hybridRouteReceipt.js.map +1 -0
  225. package/dist/registries/packageRegistry.js.map +1 -1
  226. package/dist/registries/triggerLoader.js +7 -43
  227. package/dist/registries/triggerLoader.js.map +1 -1
  228. package/dist/registries/verbosityBudgetContract.js.map +1 -1
  229. package/dist/release/releaseMetadata.js +2 -0
  230. package/dist/release/releaseMetadata.js.map +1 -1
  231. package/dist/runtime/lifecycleAdapterContract.js.map +1 -1
  232. package/dist/runtime/lifecycleAdapters.js.map +1 -1
  233. package/dist/runtime/lifecycleAuthority.js.map +1 -1
  234. package/dist/runtime/lifecycleOperationContract.js.map +1 -1
  235. package/dist/runtime/lifecycleOperations.js.map +1 -1
  236. package/dist/runtime/lifecycleOwnershipJournal.js.map +1 -1
  237. package/dist/runtime/lifecyclePublication.js.map +1 -1
  238. package/dist/runtime/lifecycleSnapshot.js.map +1 -1
  239. package/dist/runtime/retiredRuntimeCleanup.js.map +1 -1
  240. package/dist/setup/codex/agents.js.map +1 -1
  241. package/dist/setup/codex/cli.js.map +1 -1
  242. package/dist/setup/codex/configToml.js.map +1 -1
  243. package/dist/setup/codex/constants.js.map +1 -1
  244. package/dist/setup/codex/installRoot.js.map +1 -1
  245. package/dist/setup/codex/state.js.map +1 -1
  246. package/dist/setup/codex.js.map +1 -1
  247. package/dist/setup/opencode.js.map +1 -1
  248. package/dist/setup/opencodeConstants.js.map +1 -1
  249. package/dist/setup/sharedSkill.js.map +1 -1
  250. package/dist/setup/smokeChecks.js.map +1 -1
  251. package/dist/state/archiveDiscovery.js +24 -35
  252. package/dist/state/archiveDiscovery.js.map +1 -1
  253. package/dist/state/archivePublication.js.map +1 -1
  254. package/dist/state/archiveRecovery.js.map +1 -1
  255. package/dist/state/archiveReplay.js.map +1 -1
  256. package/dist/state/canonicalMigrationRecord.js +37 -0
  257. package/dist/state/canonicalMigrationRecord.js.map +1 -0
  258. package/dist/state/decisionEntities.js +73 -33
  259. package/dist/state/decisionEntities.js.map +1 -1
  260. package/dist/state/decisionLegacyValidation.js +31 -0
  261. package/dist/state/decisionLegacyValidation.js.map +1 -1
  262. package/dist/state/decisionMigrationProvenance.js +117 -0
  263. package/dist/state/decisionMigrationProvenance.js.map +1 -0
  264. package/dist/state/decisionOverlay.js.map +1 -1
  265. package/dist/state/decisionRevision.js.map +1 -1
  266. package/dist/state/decisionRevisionPublication.js.map +1 -1
  267. package/dist/state/directRetrieval.js.map +1 -1
  268. package/dist/state/durability.js +24 -5
  269. package/dist/state/durability.js.map +1 -1
  270. package/dist/state/entityCutover.js +2 -2
  271. package/dist/state/entityCutover.js.map +1 -1
  272. package/dist/state/entityCutoverGit.js.map +1 -1
  273. package/dist/state/entityMigrationCausality.js +99 -0
  274. package/dist/state/entityMigrationCausality.js.map +1 -0
  275. package/dist/state/entityMigrationPreview.js +141 -80
  276. package/dist/state/entityMigrationPreview.js.map +1 -1
  277. package/dist/state/entityPublicationContext.js.map +1 -1
  278. package/dist/state/entityStorage.js +81 -26
  279. package/dist/state/entityStorage.js.map +1 -1
  280. package/dist/state/experimentArchive.js.map +1 -1
  281. package/dist/state/experimentIdentity.js.map +1 -1
  282. package/dist/state/experimentRetrieval.js.map +1 -1
  283. package/dist/state/healthEntities.js +28 -31
  284. package/dist/state/healthEntities.js.map +1 -1
  285. package/dist/state/healthEntityValidation.js.map +1 -1
  286. package/dist/state/healthRepair.js.map +1 -1
  287. package/dist/state/installRoot.js.map +1 -1
  288. package/dist/state/legacyEntityCutoverEvidence.js.map +1 -1
  289. package/dist/state/legacyIdentity.js.map +1 -1
  290. package/dist/state/legacySummaryRecord.js +7 -0
  291. package/dist/state/legacySummaryRecord.js.map +1 -0
  292. package/dist/state/listAccounting.js.map +1 -1
  293. package/dist/state/listClassification.js.map +1 -1
  294. package/dist/state/listCursor.js +43 -0
  295. package/dist/state/listCursor.js.map +1 -0
  296. package/dist/state/listRetrieval.js.map +1 -1
  297. package/dist/state/migrationSourceBinding.js +29 -0
  298. package/dist/state/migrationSourceBinding.js.map +1 -0
  299. package/dist/state/objectiveExperimentEntities.js.map +1 -1
  300. package/dist/state/planEntities.js +46 -2
  301. package/dist/state/planEntities.js.map +1 -1
  302. package/dist/state/planIdentity.js.map +1 -1
  303. package/dist/state/planRetrieval.js.map +1 -1
  304. package/dist/state/planTaskRetrieval.js.map +1 -1
  305. package/dist/state/progressEntities.js +35 -59
  306. package/dist/state/progressEntities.js.map +1 -1
  307. package/dist/state/projectRoot.js.map +1 -1
  308. package/dist/state/projectionPolicy.js.map +1 -1
  309. package/dist/state/retrievalAuthority.js +10 -0
  310. package/dist/state/retrievalAuthority.js.map +1 -1
  311. package/dist/state/safeProjectFile.js.map +1 -1
  312. package/dist/state/startupAnalysis/benchmark.js.map +1 -1
  313. package/dist/state/startupAnalysis/contract.js.map +1 -1
  314. package/dist/state/startupAnalysis/helpers.js.map +1 -1
  315. package/dist/state/startupAnalysis/index.js.map +1 -1
  316. package/dist/state/startupAnalysis/metrics.js.map +1 -1
  317. package/dist/state/startupAnalysis/records.js.map +1 -1
  318. package/dist/state/startupAnalysis/report.js.map +1 -1
  319. package/dist/state/startupAnalysis/threshold.js.map +1 -1
  320. package/dist/state/startupAnalysis.js.map +1 -1
  321. package/dist/state/startupProjection.js +2 -1
  322. package/dist/state/startupProjection.js.map +1 -1
  323. package/dist/state/stateMode.js.map +1 -1
  324. package/dist/state/summaryEntityRead.js +26 -0
  325. package/dist/state/summaryEntityRead.js.map +1 -0
  326. package/dist/state/summaryMigrationProvenance.js +67 -0
  327. package/dist/state/summaryMigrationProvenance.js.map +1 -0
  328. package/dist/state/summarySourceRowAuthority.js +37 -0
  329. package/dist/state/summarySourceRowAuthority.js.map +1 -0
  330. package/dist/state/todoDocsEntities.js.map +1 -1
  331. package/dist/state/todoDocsEntityValidation.js.map +1 -1
  332. package/dist/state/write/assign.js.map +1 -1
  333. package/dist/state/write/candidateMutation.js.map +1 -1
  334. package/dist/state/write/errors.js.map +1 -1
  335. package/dist/state/write/experimentPublication.js.map +1 -1
  336. package/dist/state/write/explain.js +9 -3
  337. package/dist/state/write/explain.js.map +1 -1
  338. package/dist/state/write/fields.js.map +1 -1
  339. package/dist/state/write/helpers.js.map +1 -1
  340. package/dist/state/write/index.js.map +1 -1
  341. package/dist/state/write/input.js.map +1 -1
  342. package/dist/state/write/lock.js.map +1 -1
  343. package/dist/state/write/mutation.js.map +1 -1
  344. package/dist/state/write/operations.js +6 -0
  345. package/dist/state/write/operations.js.map +1 -1
  346. package/dist/state/write/planEvaluation.js +19 -5
  347. package/dist/state/write/planEvaluation.js.map +1 -1
  348. package/dist/state/write/planPublication.js +7 -0
  349. package/dist/state/write/planPublication.js.map +1 -1
  350. package/dist/state/write/serialize.js.map +1 -1
  351. package/dist/state/write/transaction.js +2 -1
  352. package/dist/state/write/transaction.js.map +1 -1
  353. package/dist/state/write/validate.js.map +1 -1
  354. package/dist/upgrade/appContentRefresh.js +15 -20
  355. package/dist/upgrade/appContentRefresh.js.map +1 -1
  356. package/dist/upgrade/appModel.js.map +1 -1
  357. package/dist/upgrade/atomicWriter.js.map +1 -1
  358. package/dist/upgrade/bundleEvidence.js.map +1 -1
  359. package/dist/upgrade/channels.js.map +1 -1
  360. package/dist/upgrade/coexistenceProbe.js.map +1 -1
  361. package/dist/upgrade/compatibility.js.map +1 -1
  362. package/dist/upgrade/doctor.js.map +1 -1
  363. package/dist/upgrade/doctorClassifier.js.map +1 -1
  364. package/dist/upgrade/installedHooksRetirement.js.map +1 -1
  365. package/dist/upgrade/legacyAgentCleanup.js.map +1 -1
  366. package/dist/upgrade/lifecycleUpgrade.js.map +1 -1
  367. package/dist/upgrade/migrateArtifactsV2ToV3.js.map +1 -1
  368. package/dist/upgrade/migrationPublication.js.map +1 -1
  369. package/dist/upgrade/nextMajorDoctor.js.map +1 -1
  370. package/dist/upgrade/npxPlatformStatus.js.map +1 -1
  371. package/dist/upgrade/projectIntegration.js.map +1 -1
  372. package/dist/upgrade/projectIntegrationDecision.js.map +1 -1
  373. package/dist/upgrade/runtimeMigration.js.map +1 -1
  374. package/dist/upgrade/upgradeCommands.js.map +1 -1
  375. package/dist/upgrade/upgradeLock.js.map +1 -1
  376. package/dist/upgrade/upgradeOrchestrator.js.map +1 -1
  377. package/dist/upgrade/v3CapabilitySurface.js.map +1 -1
  378. package/dist/upgrade/versionResolution.js.map +1 -1
  379. package/dist/validate/appHomeContract.js.map +1 -1
  380. package/dist/validate/capability.js +11 -2
  381. package/dist/validate/capability.js.map +1 -1
  382. package/dist/validate/crossCapability.js.map +1 -1
  383. package/dist/validate/selfAudit.js.map +1 -1
  384. package/dist/validate/vocabularyAuthority.js.map +1 -1
  385. package/package.json +19 -6
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Source validation identifies root corruption. Relationship validation then
3
+ * reports its downstream effects without relabelling valid source records as
4
+ * corrupt. A deterministic member roots an otherwise-valid cycle because the
5
+ * cycle itself is malformed source state and has no recovery interpretation.
6
+ */
7
+ export function applyCausalBlockers(entries, project, recoveryFor, rootReasons = new Map()) {
8
+ const byIdentity = new Map(entries.map((entry) => [entry.source_identity, entry]));
9
+ const quote = project.replaceAll("'", "'\\''");
10
+ for (const entry of entries) {
11
+ const unresolved = entry.relationships.find((relationship) => relationship.status === "unresolved");
12
+ if (unresolved) {
13
+ const target = unresolved.target_source_identity ?? "missing structured reference";
14
+ rootReasons.set(entry.source_identity, `source relationship '${unresolved.field}' references unresolved target '${target}'`);
15
+ entry.classification = "corrupt";
16
+ entry.proposed_target = null;
17
+ entry.target_sha256 = null;
18
+ entry.recovery = `Repair relationship '${unresolved.field}' on '${entry.source_identity}' to reference an inventoried source identity instead of '${target}', then run agentera state migrate entities --project '${quote}' --dry-run --format json.`;
19
+ }
20
+ if (["duplicate", "conflict", "corrupt", "unsupported"].includes(entry.classification) && !rootReasons.has(entry.source_identity))
21
+ rootReasons.set(entry.source_identity, `${entry.classification} source requires explicit recovery`);
22
+ }
23
+ const adjacency = new Map(entries.map((entry) => [entry.source_identity, entry.relationships
24
+ .filter((relationship) => relationship.status === "resolved" && relationship.target_source_identity && byIdentity.has(relationship.target_source_identity))
25
+ .map((relationship) => relationship.target_source_identity)
26
+ .sort()]));
27
+ const index = new Map();
28
+ const lowlink = new Map();
29
+ const stack = [];
30
+ const onStack = new Set();
31
+ let nextIndex = 0;
32
+ const visit = (sourceIdentity) => {
33
+ index.set(sourceIdentity, nextIndex);
34
+ lowlink.set(sourceIdentity, nextIndex++);
35
+ stack.push(sourceIdentity);
36
+ onStack.add(sourceIdentity);
37
+ for (const target of adjacency.get(sourceIdentity) ?? []) {
38
+ if (!index.has(target)) {
39
+ visit(target);
40
+ lowlink.set(sourceIdentity, Math.min(lowlink.get(sourceIdentity), lowlink.get(target)));
41
+ }
42
+ else if (onStack.has(target))
43
+ lowlink.set(sourceIdentity, Math.min(lowlink.get(sourceIdentity), index.get(target)));
44
+ }
45
+ if (lowlink.get(sourceIdentity) !== index.get(sourceIdentity))
46
+ return;
47
+ const component = [];
48
+ while (true) {
49
+ const member = stack.pop();
50
+ onStack.delete(member);
51
+ component.push(member);
52
+ if (member === sourceIdentity)
53
+ break;
54
+ }
55
+ const cyclic = component.length > 1 || (adjacency.get(sourceIdentity) ?? []).includes(sourceIdentity);
56
+ if (cyclic && !component.some((member) => rootReasons.has(member))) {
57
+ const root = component.sort()[0];
58
+ const entry = byIdentity.get(root);
59
+ rootReasons.set(root, `source relationship graph contains a cycle rooted at '${root}'`);
60
+ entry.classification = "corrupt";
61
+ entry.proposed_target = null;
62
+ entry.target_sha256 = null;
63
+ entry.recovery = `Break the relationship cycle containing '${root}', then run agentera state migrate entities --project '${quote}' --dry-run --format json.`;
64
+ }
65
+ };
66
+ for (const sourceIdentity of [...byIdentity.keys()].sort())
67
+ if (!index.has(sourceIdentity))
68
+ visit(sourceIdentity);
69
+ const roots = new Set(rootReasons.keys());
70
+ const memo = new Map();
71
+ const resolving = new Set();
72
+ const resolveRoots = (sourceIdentity) => {
73
+ if (roots.has(sourceIdentity))
74
+ return [sourceIdentity];
75
+ const existing = memo.get(sourceIdentity);
76
+ if (existing)
77
+ return existing;
78
+ // Every cycle has a root after the SCC pass. This guard keeps malformed
79
+ // graph handling fail-closed if that invariant is ever changed.
80
+ if (resolving.has(sourceIdentity))
81
+ return [];
82
+ resolving.add(sourceIdentity);
83
+ const resolved = [...new Set((adjacency.get(sourceIdentity) ?? []).flatMap(resolveRoots))].sort();
84
+ resolving.delete(sourceIdentity);
85
+ memo.set(sourceIdentity, resolved);
86
+ return resolved;
87
+ };
88
+ for (const entry of entries) {
89
+ if (roots.has(entry.source_identity))
90
+ continue;
91
+ if (resolveRoots(entry.source_identity).length > 0) {
92
+ entry.proposed_target = null;
93
+ entry.target_sha256 = null;
94
+ entry.recovery = recoveryFor(entry.source_paths[0]);
95
+ }
96
+ }
97
+ return { rootReasons, rootsFor: resolveRoots };
98
+ }
99
+ //# sourceMappingURL=entityMigrationCausality.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entityMigrationCausality.js","sourceRoot":"","sources":["../../../../../home/jgabor/git/agentera/packages/cli/src/state/entityMigrationCausality.ts"],"names":[],"mappings":"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"}
@@ -8,16 +8,20 @@ import { discoverPlanArtifacts, planDocumentParts } from "../cli/planArtifacts.j
8
8
  import { parseTodoMarkdownListItem } from "../cli/todoMarkdown.js";
9
9
  import { assertRealpathBoundary, docsPathOverridesFromBytes, loadArtifactRecord, resolveArtifactPath } from "../registries/artifactRegistry.js";
10
10
  import { canonicalRecordJson, validateStateRecord } from "./archiveDiscovery.js";
11
- import { canonicalEntityEnvelopeBytes, validateCanonicalEntityTargets } from "./entityStorage.js";
11
+ import { canonicalEntityEnvelopeBytes, entityForbiddenCanonicalAliases, entityPreservedAggregateCollections, validateCanonicalEntityTargets } from "./entityStorage.js";
12
12
  import { discoverObjectiveArtifacts, inspectExperimentIdentities } from "./experimentIdentity.js";
13
13
  import { decisionRevisionContract, decisionRevisionViolations } from "./decisionRevision.js";
14
+ import { classifyCompleteDecisionConfidence, decisionLegacyCoexistence } from "./decisionLegacyValidation.js";
14
15
  import { assertValidatedProjectRoot, validateRealProjectRoot } from "./projectRoot.js";
15
16
  import { todoDocsRecordViolations } from "./todoDocsEntityValidation.js";
16
17
  import { yamlArchiveEntry } from "../hooks/compaction/retention.js";
17
18
  import { truncateWords } from "../hooks/compaction/dryRun.js";
18
19
  import { legacyIdentity } from "./legacyIdentity.js";
20
+ import { canonicalMigrationRecord } from "./canonicalMigrationRecord.js";
21
+ import { legacySummaryRecord } from "./legacySummaryRecord.js";
22
+ import { applyCausalBlockers } from "./entityMigrationCausality.js";
19
23
  import { projectPathIsStable as migrationPathIsStable, readProjectFileSnapshot, resolveProjectDescriptorPath, snapshotProjectPath as snapshotMigrationPath, } from "./safeProjectFile.js";
20
- const MAX_OUTPUT_BYTES = 32_768;
24
+ export const ENTITY_MIGRATION_PREVIEW_MAX_OUTPUT_BYTES = 32_768;
21
25
  const DEFAULT_LIMIT = 100;
22
26
  const MAX_LIMIT = 1000;
23
27
  const NUMBERED = {
@@ -25,7 +29,8 @@ const NUMBERED = {
25
29
  decisions: { file: ".agentera/decisions.yaml", collection: "decisions", boundary: "decision" },
26
30
  health: { file: ".agentera/health.yaml", collection: "audits", boundary: "health_audit" },
27
31
  };
28
- const BLOCKING = new Set(["irrecoverable_summary_only", "duplicate", "conflict", "corrupt", "unsupported"]);
32
+ const COMPACTED_SUMMARY_ARTIFACTS = new Set(["progress", "decisions", "health"]);
33
+ const BLOCKING = new Set(["duplicate", "conflict", "corrupt", "unsupported"]);
29
34
  const INVENTORY_ORDER = "artifact_then_boundary_then_source_identity_then_source_path";
30
35
  const INVENTORY_FILTER = "complete_declared_inventory";
31
36
  const AUTHORITY_PATH = "references/artifacts/state-storage-authority.yaml";
@@ -36,6 +41,24 @@ function mapping(value) {
36
41
  function hash(value) {
37
42
  return createHash("sha256").update(value).digest("hex");
38
43
  }
44
+ function completeRecordAssessment(sourceRoot, artifact, record, source, sourcePath) {
45
+ if (artifact !== "decisions") {
46
+ const violations = validateStateRecord(sourceRoot, artifact, record);
47
+ return { valid: violations.length === 0, violations };
48
+ }
49
+ const assessment = classifyCompleteDecisionConfidence(record, decisionLegacyCoexistence(sourceRoot), (candidate) => validateStateRecord(sourceRoot, artifact, candidate), source);
50
+ return {
51
+ valid: assessment.status !== "invalid",
52
+ violations: assessment.violations,
53
+ ...(assessment.status === "inherited" ? { inheritedConfidenceProvenance: {
54
+ kind: "inherited_decision_confidence",
55
+ source: source === "active" ? "current_projection" : "verified_archive",
56
+ source_path: sourcePath,
57
+ source_record_sha256: hash(canonicalRecordJson(record)),
58
+ confidence: record.confidence,
59
+ } } : {}),
60
+ };
61
+ }
39
62
  function relative(root, target) {
40
63
  return path.relative(root, target).replaceAll(path.sep, "/");
41
64
  }
@@ -172,7 +195,7 @@ function inventoryFailureObservations(files, observations) {
172
195
  });
173
196
  }
174
197
  }
175
- function numberedObservations(root, sourceRoot, files, observations) {
198
+ function numberedObservations(root, sourceRoot, files, observations, aggregateCollections) {
176
199
  const correlationSource = files.find((source) => source.relative === ".agentera/archive/recovery/projection-correlation.yaml");
177
200
  let correlationManifest = null;
178
201
  if (correlationSource?.kind === "file") {
@@ -197,6 +220,10 @@ function numberedObservations(root, sourceRoot, files, observations) {
197
220
  if (current?.kind === "file") {
198
221
  try {
199
222
  const document = parseYaml(current);
223
+ const allowedCollections = new Set(aggregateCollections[declaration.file] ?? []);
224
+ for (const field of Object.keys(document).filter((field) => Array.isArray(document[field]) && !allowedCollections.has(field)).sort()) {
225
+ observations.push({ key: `${artifact}:undeclared_collection:${field}`, artifact, boundary: "migration_inventory", path: declaration.file, provenance: "source_inventory", record: null, detail: "corrupt", relationships: [], message: `aggregate collection '${field}' is not declared for '${declaration.file}' by the state storage authority` });
226
+ }
200
227
  const currentValues = document[declaration.collection];
201
228
  if (!Array.isArray(currentValues))
202
229
  throw new Error(`field '${declaration.collection}' must be a list`);
@@ -204,17 +231,20 @@ function numberedObservations(root, sourceRoot, files, observations) {
204
231
  if (Array.isArray(document.archive))
205
232
  collections.push(["archive", document.archive]);
206
233
  collections.flatMap(([collection, values]) => values.map((value, index) => ({ collection, value, index }))).forEach(({ collection, value, index }) => {
207
- const record = mapping(value) ?? (typeof value === "string" ? { summary: value } : null);
234
+ const record = legacySummaryRecord(value);
208
235
  const identity = legacyIdentity(record, artifact, "number");
209
236
  const number = identity.number;
210
237
  const key = number ? `${artifact}:${number}` : `${artifact}:${collection}[${index}]`;
211
- const valid = record && typeof record.number === "number" ? validateStateRecord(sourceRoot, artifact, record).length === 0 : false;
238
+ const assessment = record && typeof record.number === "number"
239
+ ? completeRecordAssessment(sourceRoot, artifact, record, "active", declaration.file)
240
+ : { valid: false, violations: ["record number is required"] };
241
+ const valid = assessment.valid;
212
242
  const summary = Boolean(record && (typeof record.summary === "string" || record.detail_availability === "summary_only"));
213
243
  const text = typeof record?.summary === "string" ? record.summary : "";
214
244
  const decisionRefs = artifact === "decisions" ? [...text.matchAll(/\bD([1-9][0-9]*)\b/g)] : [];
215
245
  const residue = artifact === "decisions" && decisionRefs.length > 1 && !number;
216
- observations.push({ key: residue ? `historical_projection_residue:${declaration.file}:${collection}[${index}]` : key, artifact, boundary: residue ? "historical_projection_residue" : declaration.boundary, path: declaration.file, provenance: residue ? "historical_projection_residue" : "current_projection", record, detail: valid ? "full" : summary ? "summary" : "corrupt", relationships: [], message: valid || summary ? undefined : "projection record does not satisfy the declared full-detail schema", ...(residue ? { migrationProvenance: { classification: "historical_projection_residue", path: declaration.file, collection, index, content_sha256: hash(canonicalRecordJson(record)), text, inbound_structured_references: 0 } } : {}) });
217
- if (artifact === "decisions" && mapping(record?.satisfaction)) {
246
+ observations.push({ key: residue ? `historical_projection_residue:${declaration.file}:${collection}[${index}]` : key, artifact, boundary: residue ? "historical_projection_residue" : declaration.boundary, path: declaration.file, provenance: residue ? "historical_projection_residue" : "current_projection", record, detail: valid ? "full" : summary ? "summary" : "corrupt", relationships: [], sourceRecordSha256: hash(canonicalRecordJson(value)), message: valid || summary ? undefined : "projection record does not satisfy the declared full-detail schema", ...(assessment.inheritedConfidenceProvenance ? { inheritedConfidenceProvenance: assessment.inheritedConfidenceProvenance } : {}), ...(residue ? { migrationProvenance: { classification: "historical_projection_residue", path: declaration.file, collection, index, content_sha256: hash(canonicalRecordJson(record)), text, inbound_structured_references: 0 } } : {}) });
247
+ if (artifact === "decisions" && valid && mapping(record?.satisfaction)) {
218
248
  observations.push({ key: `decision_satisfaction:${key}`, artifact: "decisions", boundary: "decision_satisfaction", path: declaration.file, provenance: "current_projection", record: mapping(record?.satisfaction), detail: "full", relationships: [{ field: "decision", target: key }] });
219
249
  }
220
250
  });
@@ -249,10 +279,10 @@ function numberedObservations(root, sourceRoot, files, observations) {
249
279
  || mapping(correlation.overlay)?.final_record_sha256 !== expected)
250
280
  throw new Error("recovered archive does not match its immutable projection correlation manifest entry");
251
281
  }
252
- const violations = validateStateRecord(sourceRoot, artifact, record);
253
- if (violations.length > 0)
254
- throw new Error(`archive record is invalid: ${violations.join("; ")}`);
255
- observations.push({ key, artifact, boundary: declaration.boundary, path: source.relative, provenance: "verified_archive", record, detail: "full", relationships: [], ...(mapping(envelope.recovery_provenance) ? { migrationProvenance: mapping(envelope.recovery_provenance) } : {}) });
282
+ const assessment = completeRecordAssessment(sourceRoot, artifact, record, "archive", source.relative);
283
+ if (!assessment.valid)
284
+ throw new Error(`archive record is invalid: ${assessment.violations.join("; ")}`);
285
+ observations.push({ key, artifact, boundary: declaration.boundary, path: source.relative, provenance: "verified_archive", record, detail: "full", relationships: [], ...(assessment.inheritedConfidenceProvenance ? { inheritedConfidenceProvenance: assessment.inheritedConfidenceProvenance } : {}), ...(mapping(envelope.recovery_provenance) ? { migrationProvenance: mapping(envelope.recovery_provenance) } : {}) });
256
286
  if (artifact === "decisions" && mapping(record.satisfaction)) {
257
287
  observations.push({
258
288
  key: `decision_satisfaction:${key}`,
@@ -506,15 +536,26 @@ function previewId(fingerprint, key) {
506
536
  const bytes = createHash("sha256").update(`agentera.entity-preview.v1\0${fingerprint}\0${key}`, "utf8").digest();
507
537
  return Array.from(bytes.subarray(0, 10), (byte) => String.fromCharCode(97 + byte % 26)).join("");
508
538
  }
509
- function classify(group) {
539
+ function summaryBoundary(artifact, fallback) {
540
+ return { progress: "progress_summary", decisions: "decision_summary", health: "health_summary" }[artifact] ?? fallback;
541
+ }
542
+ function canonicalSummaryBodies(group, forbiddenAliases) {
543
+ return new Set(group.flatMap((item) => item.record
544
+ ? [canonicalRecordJson(canonicalMigrationRecord(summaryBoundary(item.artifact, item.boundary), item.record, forbiddenAliases))]
545
+ : []));
546
+ }
547
+ function classify(group, forbiddenAliases) {
510
548
  if (group.some((item) => item.provenance === "historical_projection_residue"))
511
549
  return "historical_projection_residue";
512
550
  if (group.some((item) => item.key.startsWith("unsupported:")))
513
551
  return "unsupported";
514
552
  if (group.some((item) => item.detail === "corrupt"))
515
553
  return "corrupt";
516
- if (group.every((item) => item.detail === "summary"))
517
- return "irrecoverable_summary_only";
554
+ if (group.every((item) => item.detail === "summary")) {
555
+ if (!COMPACTED_SUMMARY_ARTIFACTS.has(group[0]?.artifact ?? ""))
556
+ return "corrupt";
557
+ return canonicalSummaryBodies(group, forbiddenAliases).size === 1 ? "valid_compacted_summary" : "conflict";
558
+ }
518
559
  const full = group.filter((item) => item.detail === "full" && item.record);
519
560
  const bodies = new Set(full.map((item) => canonicalRecordJson(item.record)));
520
561
  if (bodies.size > 1)
@@ -522,11 +563,12 @@ function classify(group) {
522
563
  const projections = full.filter((item) => item.provenance === "current_projection");
523
564
  const archive = group.find((item) => item.provenance === "verified_archive" && item.record);
524
565
  const summaries = group.filter((item) => item.detail === "summary" && item.record);
525
- if (archive && summaries.length) {
526
- const recovery = archive.migrationProvenance;
566
+ if (full.length && summaries.length) {
567
+ const selected = archive ?? full[0];
568
+ const recovery = selected.migrationProvenance;
527
569
  const recorded = mapping(recovery?.current_projection)?.record_sha256;
528
- const proven = summaries.every((item) => exactProjectionMirror(item.artifact, archive.record, item.record, recorded));
529
- return proven ? "verified_full" : "conflict";
570
+ if (!summaries.every((item) => exactProjectionMirror(item.artifact, selected.record, item.record, recorded)))
571
+ return "conflict";
530
572
  }
531
573
  if (archive || group.some((item) => item.provenance === "verified_plan_archive"))
532
574
  return "verified_full";
@@ -538,52 +580,26 @@ function exactProjectionMirror(artifact, full, summary, recorded) {
538
580
  if (recorded === hash(canonicalRecordJson(summary)))
539
581
  return true;
540
582
  if (artifact === "health" && typeof summary.summary === "string" && typeof full.number === "number" && typeof full.date === "string" && typeof full.trajectory === "string") {
541
- return summary.summary === `Audit ${full.number} · ${full.date} (${truncateWords(full.trajectory, 10)})`;
583
+ if (summary.summary === `Audit ${full.number} · ${full.date} (${truncateWords(full.trajectory, 10)})`)
584
+ return true;
542
585
  }
543
586
  if (artifact !== "progress" && artifact !== "decisions" && artifact !== "health")
544
587
  return false;
545
588
  return canonicalRecordJson(yamlArchiveEntry(artifact, full)) === canonicalRecordJson(summary);
546
589
  }
547
- function canonicalMigrationRecord(boundary, source, relationships) {
548
- const record = structuredClone(source);
549
- for (const field of ["id", "artifact", "number", "stable_id", "artifact_id", "entry_number", "task_number", "plan_id", "objective_id", "experiment_number"])
550
- delete record[field];
551
- if (boundary === "decision")
552
- delete record.satisfaction;
553
- if (boundary === "plan" || boundary === "objective") {
554
- const header = record.header;
555
- if (mapping(header))
556
- delete header.id;
557
- }
558
- if (boundary === "plan") {
559
- delete record.tasks;
560
- delete record.previous_plan_archived;
561
- const header = record.header;
562
- if (mapping(header)) {
563
- const planHeader = header;
564
- if (planHeader.status === "active")
565
- planHeader.status = "open";
566
- if (planHeader.status === "completed")
567
- planHeader.status = "complete";
568
- }
569
- }
570
- for (const relationship of relationships) {
571
- if (relationship.field === "depends_on") {
572
- record.depends_on = relationships.filter(({ field }) => field === "depends_on").map(({ target_id }) => target_id);
573
- }
574
- else {
575
- record[relationship.field] = relationship.target_id;
576
- }
577
- }
578
- return record;
579
- }
580
- function buildEntries(project, fingerprint, observations) {
590
+ function buildEntries(project, fingerprint, observations, forbiddenAliases) {
581
591
  const groups = new Map();
582
592
  for (const observation of observations)
583
593
  groups.set(observation.key, [...(groups.get(observation.key) ?? []), observation]);
584
594
  const ids = new Map();
585
- for (const key of [...groups.keys()].sort())
586
- ids.set(key, previewId(fingerprint, key));
595
+ for (const key of [...groups.keys()].sort()) {
596
+ const group = groups.get(key);
597
+ const canonicalSummaries = group.every((item) => item.detail === "summary") && COMPACTED_SUMMARY_ARTIFACTS.has(group[0]?.artifact ?? "")
598
+ ? [...canonicalSummaryBodies(group, forbiddenAliases)].sort()
599
+ : [];
600
+ const identityBinding = canonicalSummaries.length === 1 ? hash(canonicalRecordJson(canonicalSummaries)) : fingerprint;
601
+ ids.set(key, previewId(identityBinding, key));
602
+ }
587
603
  const collisions = new Set();
588
604
  const idOwners = new Map();
589
605
  for (const [key, id] of ids) {
@@ -595,12 +611,16 @@ function buildEntries(project, fingerprint, observations) {
595
611
  else
596
612
  idOwners.set(id, key);
597
613
  }
598
- const entries = [...groups.entries()].map(([key, group]) => {
599
- let classification = classify(group);
614
+ const entries = [...groups.entries()].map(([key, unsortedGroup]) => {
615
+ const group = [...unsortedGroup].sort((left, right) => `${left.path}\0${left.provenance}\0${canonicalRecordJson(left.record)}\0${left.sourceRecordSha256 ?? ""}`.localeCompare(`${right.path}\0${right.provenance}\0${canonicalRecordJson(right.record)}\0${right.sourceRecordSha256 ?? ""}`));
616
+ let classification = classify(group, forbiddenAliases);
600
617
  if (collisions.has(key))
601
618
  classification = "conflict";
602
619
  const primary = group[0];
603
- const content = group.find((item) => item.provenance === "verified_archive" && item.record)?.record ?? group.find((item) => item.record)?.record ?? null;
620
+ const contentObservation = group.find((item) => item.provenance === "verified_archive" && item.detail === "full" && item.record)
621
+ ?? group.find((item) => item.detail === "full" && item.record)
622
+ ?? group.find((item) => item.detail === "summary" && item.record);
623
+ const content = contentObservation?.record ?? null;
604
624
  const contentSha256s = [...new Set(group.flatMap((item) => item.record ? [hash(canonicalRecordJson(item.record))] : []))].sort();
605
625
  const mirrored = contentSha256s.length === 1 && group.filter((item) => item.record).length > 1;
606
626
  const id = ids.get(key);
@@ -611,25 +631,35 @@ function buildEntries(project, fingerprint, observations) {
611
631
  target_id: relationship.target ? ids.get(relationship.target) ?? null : null,
612
632
  status: relationship.target && groups.has(relationship.target) ? "resolved" : "unresolved",
613
633
  }));
614
- const record = content ? canonicalMigrationRecord(primary.boundary, content, relationships) : {};
634
+ const summary = classification === "valid_compacted_summary";
635
+ const boundary = summary ? summaryBoundary(primary.artifact, primary.boundary) : contentObservation?.boundary ?? primary.boundary;
636
+ const record = content ? canonicalMigrationRecord(boundary, content, forbiddenAliases, summary ? [] : relationships) : {};
637
+ if (summary && contentObservation && content) {
638
+ record.migration_provenance = {
639
+ source_path: contentObservation.path,
640
+ source_record_sha256: contentObservation.sourceRecordSha256 ?? hash(canonicalRecordJson(content)),
641
+ };
642
+ }
615
643
  const residue = classification === "historical_projection_residue";
616
644
  const blocked = BLOCKING.has(classification) || relationships.some((relationship) => relationship.status === "unresolved");
617
645
  return {
618
646
  source_identity: key,
619
647
  source_paths: [...new Set(group.map((item) => item.path))].sort(),
620
648
  artifact: primary.artifact,
621
- boundary: primary.boundary,
649
+ boundary,
622
650
  classification,
623
- detail_availability: classification === "irrecoverable_summary_only" ? "summary_only" : content ? "full" : "unavailable",
651
+ detail_availability: summary ? "summary" : content ? "full" : "unavailable",
652
+ compatibility: summary ? "degraded" : "current",
624
653
  provenance: [...new Set([...group.map((item) => item.provenance), ...(mirrored ? ["mirrored"] : [])])].sort(),
625
654
  content_sha256: contentSha256s.length === 1 ? contentSha256s[0] : null,
626
655
  content_sha256s: contentSha256s,
627
656
  physical_record_count: group.length,
628
- proposed_target: blocked || residue ? null : { id, path: `.agentera/entities/${primary.artifact}/${primary.boundary}/${id}.yaml` },
657
+ proposed_target: blocked || residue ? null : { id, path: `.agentera/entities/${primary.artifact}/${boundary}/${id}.yaml` },
629
658
  target_sha256: null,
630
659
  relationships,
631
660
  record,
632
661
  recovery: blocked ? recovery(project, primary.path) : "none",
662
+ ...(contentObservation?.inheritedConfidenceProvenance ? { canonical_migration_provenance: contentObservation.inheritedConfidenceProvenance } : {}),
633
663
  ...(group.some((item) => item.migrationProvenance) ? { migration_provenance: group.flatMap((item) => item.migrationProvenance ? [item.migrationProvenance] : []) } : {}),
634
664
  };
635
665
  }).sort((a, b) => `${a.artifact}\0${a.boundary}\0${a.source_identity}\0${a.source_paths[0]}`.localeCompare(`${b.artifact}\0${b.boundary}\0${b.source_identity}\0${b.source_paths[0]}`));
@@ -651,12 +681,12 @@ function buildEntries(project, fingerprint, observations) {
651
681
  return entries;
652
682
  }
653
683
  export function validateEntityMigrationTargets(project, entries, sourceRoot) {
654
- const targets = entries.flatMap((entry) => entry.proposed_target && entry.artifact && entry.boundary ? [{ sourceIdentity: entry.source_identity, path: entry.proposed_target.path, id: entry.proposed_target.id, artifact: entry.artifact, boundary: entry.boundary, record: entry.record }] : []);
684
+ const targets = entries.flatMap((entry) => entry.proposed_target && entry.artifact && entry.boundary ? [{ sourceIdentity: entry.source_identity, path: entry.proposed_target.path, id: entry.proposed_target.id, artifact: entry.artifact, boundary: entry.boundary, record: entry.record, migrationProvenance: entry.canonical_migration_provenance }] : []);
655
685
  const diagnostics = validateCanonicalEntityTargets(project, targets, sourceRoot);
656
686
  for (const entry of entries) {
657
687
  if (!entry.proposed_target || !entry.artifact)
658
688
  continue;
659
- const actual = hash(canonicalEntityEnvelopeBytes({ id: entry.proposed_target.id, artifact: entry.artifact, record: entry.record }));
689
+ const actual = hash(canonicalEntityEnvelopeBytes({ id: entry.proposed_target.id, artifact: entry.artifact, record: entry.record, migrationProvenance: entry.canonical_migration_provenance }));
660
690
  if (entry.target_sha256 !== actual)
661
691
  diagnostics.push({ sourceIdentity: entry.source_identity, path: entry.proposed_target.path, message: `canonical target bytes have SHA-256 '${actual}', not manifest binding '${entry.target_sha256 ?? "missing"}'` });
662
692
  }
@@ -679,19 +709,20 @@ function migrationInventory(projectRoot, sourceRoot, resolveDescriptorPath) {
679
709
  const fingerprint = sourceFingerprint(files);
680
710
  const observations = [];
681
711
  inventoryFailureObservations(files, observations);
682
- numberedObservations(project, sourceRoot, files, observations);
712
+ numberedObservations(project, sourceRoot, files, observations, entityPreservedAggregateCollections(sourceRoot));
683
713
  decisionEvidence(sourceRoot, files, observations);
684
714
  planObservations(project, files, observations);
685
715
  objectiveObservations(project, files, observations);
686
716
  todoAndDocs(project, todoPath, files, observations);
687
717
  const preserved = preservedSingletons(files);
688
- const completeInventory = buildEntries(project, fingerprint, observations);
718
+ const completeInventory = buildEntries(project, fingerprint, observations, entityForbiddenCanonicalAliases(sourceRoot));
689
719
  const preservedResidues = completeInventory.filter((entry) => entry.classification === "historical_projection_residue");
690
720
  const completeEntries = completeInventory.filter((entry) => entry.classification !== "historical_projection_residue");
691
721
  for (const entry of completeEntries) {
692
722
  if (entry.proposed_target && entry.artifact)
693
- entry.target_sha256 = hash(canonicalEntityEnvelopeBytes({ id: entry.proposed_target.id, artifact: entry.artifact, record: entry.record }));
723
+ entry.target_sha256 = hash(canonicalEntityEnvelopeBytes({ id: entry.proposed_target.id, artifact: entry.artifact, record: entry.record, migrationProvenance: entry.canonical_migration_provenance }));
694
724
  }
725
+ let causal = applyCausalBlockers(completeEntries, project, (sourcePath) => recovery(project, sourcePath));
695
726
  const targetDiagnostics = validateEntityMigrationTargets(project, completeEntries, sourceRoot);
696
727
  for (const diagnostic of targetDiagnostics) {
697
728
  const entry = completeEntries.find((candidate) => candidate.source_identity === diagnostic.sourceIdentity);
@@ -701,8 +732,10 @@ function migrationInventory(projectRoot, sourceRoot, resolveDescriptorPath) {
701
732
  entry.proposed_target = null;
702
733
  entry.target_sha256 = null;
703
734
  entry.recovery = recovery(project, entry.source_paths[0]);
735
+ causal.rootReasons.set(entry.source_identity, `target_invalid: ${diagnostic.message}`);
704
736
  }
705
- const classes = ["verified_full", "recoverable_degraded_full_projection", "irrecoverable_summary_only", "duplicate", "conflict", "corrupt", "unsupported", "historical_projection_residue"];
737
+ causal = applyCausalBlockers(completeEntries, project, (sourcePath) => recovery(project, sourcePath), causal.rootReasons);
738
+ const classes = ["verified_full", "recoverable_degraded_full_projection", "valid_compacted_summary", "duplicate", "conflict", "corrupt", "unsupported", "historical_projection_residue"];
706
739
  const counts = Object.fromEntries(classes.map((classification) => [classification, completeInventory.filter((entry) => entry.classification === classification).length]));
707
740
  counts.total = completeInventory.length;
708
741
  counts.publishable_entities = completeEntries.filter(({ proposed_target }) => proposed_target !== null).length;
@@ -713,15 +746,43 @@ function migrationInventory(projectRoot, sourceRoot, resolveDescriptorPath) {
713
746
  counts.conflicts = counts.duplicate + counts.conflict;
714
747
  counts.relationships = completeEntries.reduce((total, entry) => total + entry.relationships.length, 0);
715
748
  counts.unresolved_relationships = completeEntries.reduce((total, entry) => total + entry.relationships.filter((relationship) => relationship.status === "unresolved").length, 0);
716
- counts.blockers = completeEntries.filter((entry) => BLOCKING.has(entry.classification) || entry.relationships.some((relationship) => relationship.status === "unresolved")).length;
717
- const diagnostics = completeEntries.flatMap((entry) => [
718
- ...(BLOCKING.has(entry.classification) ? [{ classification: entry.classification, path: entry.source_paths[0], source_identity: entry.source_identity, message: observations.find((item) => item.key === entry.source_identity)?.message ?? `${entry.classification} source requires explicit recovery`, recovery: entry.recovery }] : []),
719
- ...entry.relationships.filter((relationship) => relationship.status === "unresolved").map((relationship) => {
720
- const target = relationship.target_source_identity ?? "missing structured reference";
721
- return { classification: "unresolved_relationship", path: entry.source_paths[0], source_identity: entry.source_identity, relationship_field: relationship.field, target_source_identity: relationship.target_source_identity, message: `source '${entry.source_identity}' relationship '${relationship.field}' references unresolved target '${target}'`, recovery: `Repair relationship '${relationship.field}' on '${entry.source_identity}' to reference an inventoried source identity instead of '${target}', then run agentera state migrate entities --project '${project.replaceAll("'", "'\\''")}' --dry-run --format json.` };
722
- }),
723
- ...targetDiagnostics.filter(({ sourceIdentity }) => sourceIdentity === entry.source_identity).map((diagnostic) => ({ classification: "corrupt", path: entry.source_paths[0], source_identity: entry.source_identity, message: `target_invalid: ${diagnostic.message}`, recovery: entry.recovery })),
724
- ]);
749
+ const rootDiagnostics = completeEntries
750
+ .filter((entry) => causal.rootReasons.has(entry.source_identity))
751
+ .map((entry) => {
752
+ const unresolved = entry.relationships.find((relationship) => relationship.status === "unresolved");
753
+ const reason = causal.rootReasons.get(entry.source_identity) ?? `${entry.classification} source requires explicit recovery`;
754
+ const observationMessage = observations.find((item) => item.key === entry.source_identity)?.message;
755
+ return {
756
+ classification: entry.classification,
757
+ path: entry.source_paths[0],
758
+ source_identity: entry.source_identity,
759
+ ...(unresolved ? { relationship_field: unresolved.field, target_source_identity: unresolved.target_source_identity } : {}),
760
+ message: reason === `${entry.classification} source requires explicit recovery` && observationMessage ? observationMessage : reason,
761
+ recovery: entry.recovery,
762
+ };
763
+ });
764
+ const dependentDiagnostics = completeEntries.flatMap((entry) => {
765
+ if (causal.rootReasons.has(entry.source_identity))
766
+ return [];
767
+ return entry.relationships.flatMap((relationship) => {
768
+ if (relationship.status !== "resolved" || !relationship.target_source_identity)
769
+ return [];
770
+ return causal.rootsFor(relationship.target_source_identity).map((rootSourceIdentity) => ({
771
+ classification: "dependent_blocker",
772
+ path: entry.source_paths[0],
773
+ source_identity: entry.source_identity,
774
+ relationship_field: relationship.field,
775
+ target_source_identity: relationship.target_source_identity,
776
+ root_source_identity: rootSourceIdentity,
777
+ message: `source '${entry.source_identity}' relationship '${relationship.field}' is blocked by root source '${rootSourceIdentity}'`,
778
+ recovery: recovery(project, entry.source_paths[0]),
779
+ }));
780
+ });
781
+ });
782
+ const diagnostics = [...rootDiagnostics, ...dependentDiagnostics].sort((left, right) => `${left.source_identity}\0${left.classification}\0${left.relationship_field ?? ""}\0${left.target_source_identity ?? ""}\0${left.root_source_identity ?? ""}`.localeCompare(`${right.source_identity}\0${right.classification}\0${right.relationship_field ?? ""}\0${right.target_source_identity ?? ""}\0${right.root_source_identity ?? ""}`));
783
+ counts.root_blockers = rootDiagnostics.length;
784
+ counts.dependent_blockers = dependentDiagnostics.length;
785
+ counts.blockers = counts.root_blockers + counts.dependent_blockers;
725
786
  const digestEntries = completeEntries.map(({ record: _record, ...entry }) => entry);
726
787
  const digestResidues = preservedResidues.map(({ record: _record, ...entry }) => entry);
727
788
  const digestBody = { source_fingerprint: fingerprint, authority, selectors: { project, filter: INVENTORY_FILTER, order: INVENTORY_ORDER }, entries: digestEntries, preserved_residues: digestResidues, preserved_singletons: preserved, counts, diagnostics };
@@ -763,12 +824,12 @@ export function previewEntityMigration(projectRoot, sourceRoot, options = {}) {
763
824
  const body = { ...base, entries, diagnostics: pageDiagnostics, omitted: start > 0 || entries.length < completeEntries.length, omitted_count: completeEntries.length - entries.length, diagnostics_omitted_count: diagnostics.length - pageDiagnostics.length, omission_reason: omissionReason, page_after: options.after ?? null, next_after: nextAfter, retrieval: { command } };
764
825
  return Math.max(Buffer.byteLength(JSON.stringify(body, null, 2), "utf8"), Buffer.byteLength(YAML.stringify(body), "utf8"));
765
826
  };
766
- while (entries.length > 0 && serializedBytes() > MAX_OUTPUT_BYTES) {
827
+ while (entries.length > 0 && serializedBytes() > ENTITY_MIGRATION_PREVIEW_MAX_OUTPUT_BYTES) {
767
828
  entries = entries.slice(0, -1);
768
829
  omissionReason = "output_byte_budget";
769
830
  }
770
831
  if (entries.length === 0 && start < completeEntries.length)
771
- throw new Error("the next whole migration entry exceeds the 32768-byte output budget; repair that source before retrying");
832
+ throw new Error(`the next whole migration entry exceeds the ${ENTITY_MIGRATION_PREVIEW_MAX_OUTPUT_BYTES}-byte output budget; repair that source before retrying`);
772
833
  const outputDiagnostics = diagnosticsForEntries();
773
834
  const nextAfter = start + entries.length < completeEntries.length ? entries.at(-1)?.source_identity ?? null : null;
774
835
  const retrieval = { command: nextAfter ? `agentera state migrate entities --project '${quotedProject}' --after '${nextAfter.replaceAll("'", "'\\''")}' --source-fingerprint ${fingerprint} --preview-digest ${previewDigest} --limit ${requestedLimit} --dry-run --format json` : restartCommand };