unaltraweb 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (444) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/Makefile +412 -0
  4. data/README.md +226 -0
  5. data/_config.yml +842 -0
  6. data/_data/i18n/ca.yml +278 -0
  7. data/_data/i18n/en.yml +278 -0
  8. data/_data/i18n/es.yml +278 -0
  9. data/_includes/audio.liquid +30 -0
  10. data/_includes/bib_search.liquid +5 -0
  11. data/_includes/blog-list.liquid +66 -0
  12. data/_includes/book-citation.liquid +33 -0
  13. data/_includes/citation.liquid +26 -0
  14. data/_includes/custom_head.liquid +3 -0
  15. data/_includes/custom_scripts.liquid +5 -0
  16. data/_includes/cv/list.liquid +5 -0
  17. data/_includes/cv/list_groups.liquid +51 -0
  18. data/_includes/cv/map.liquid +29 -0
  19. data/_includes/cv/nested_list.liquid +16 -0
  20. data/_includes/cv/time_table.liquid +118 -0
  21. data/_includes/cv-download-card.liquid +26 -0
  22. data/_includes/developer-mode-switcher.liquid +24 -0
  23. data/_includes/disqus.liquid +13 -0
  24. data/_includes/distill_scripts.liquid +298 -0
  25. data/_includes/documentation-download-detail.liquid +76 -0
  26. data/_includes/documentation-downloads.liquid +71 -0
  27. data/_includes/documentation-profile-attributes.liquid +4 -0
  28. data/_includes/documentation-section-toc.liquid +9 -0
  29. data/_includes/documentation-sidebar.liquid +112 -0
  30. data/_includes/figure.liquid +87 -0
  31. data/_includes/footer.liquid +66 -0
  32. data/_includes/giscus.liquid +25 -0
  33. data/_includes/head.liquid +220 -0
  34. data/_includes/header.liquid +544 -0
  35. data/_includes/latest_posts.liquid +61 -0
  36. data/_includes/localized-date.liquid +5 -0
  37. data/_includes/manual-bibliography.liquid +2 -0
  38. data/_includes/manual-featured-readings.liquid +12 -0
  39. data/_includes/manual-other-readings.liquid +12 -0
  40. data/_includes/manual-page-toc.liquid +11 -0
  41. data/_includes/manual-sidebar.liquid +58 -0
  42. data/_includes/manual-teachers.liquid +74 -0
  43. data/_includes/metadata.liquid +278 -0
  44. data/_includes/news.liquid +48 -0
  45. data/_includes/newsletter.liquid +68 -0
  46. data/_includes/page-hero.liquid +96 -0
  47. data/_includes/page-link.liquid +8 -0
  48. data/_includes/pagination.liquid +22 -0
  49. data/_includes/post-reading-time.liquid +29 -0
  50. data/_includes/previous-next.liquid +37 -0
  51. data/_includes/profile-card.liquid +49 -0
  52. data/_includes/profile-feature-matrix.liquid +75 -0
  53. data/_includes/profile-highlights.liquid +122 -0
  54. data/_includes/project-grid.liquid +26 -0
  55. data/_includes/project-resource-link.liquid +45 -0
  56. data/_includes/project-resources.liquid +21 -0
  57. data/_includes/projects.liquid +38 -0
  58. data/_includes/projects_horizontal.liquid +37 -0
  59. data/_includes/publications-metrics-summary.liquid +69 -0
  60. data/_includes/publications-summary.liquid +127 -0
  61. data/_includes/reading-biblio-controls.liquid +65 -0
  62. data/_includes/reading-cover-card.liquid +93 -0
  63. data/_includes/reading-rating.liquid +11 -0
  64. data/_includes/recommended-readings.liquid +30 -0
  65. data/_includes/related_posts.liquid +39 -0
  66. data/_includes/repository/repo.liquid +48 -0
  67. data/_includes/repository/repo_trophies.liquid +44 -0
  68. data/_includes/repository/repo_user.liquid +35 -0
  69. data/_includes/resume/awards.liquid +19 -0
  70. data/_includes/resume/basics.liquid +28 -0
  71. data/_includes/resume/certificates.liquid +35 -0
  72. data/_includes/resume/education.liquid +54 -0
  73. data/_includes/resume/interests.liquid +34 -0
  74. data/_includes/resume/languages.liquid +31 -0
  75. data/_includes/resume/projects.liquid +32 -0
  76. data/_includes/resume/publications.liquid +28 -0
  77. data/_includes/resume/references.liquid +31 -0
  78. data/_includes/resume/skills.liquid +33 -0
  79. data/_includes/resume/volunteer.liquid +52 -0
  80. data/_includes/resume/work.liquid +52 -0
  81. data/_includes/scripts.liquid +364 -0
  82. data/_includes/search-data.js.liquid +341 -0
  83. data/_includes/selected_papers.liquid +3 -0
  84. data/_includes/t.liquid +31 -0
  85. data/_includes/team-grid.liquid +172 -0
  86. data/_includes/video.liquid +97 -0
  87. data/_layouts/about.liquid +93 -0
  88. data/_layouts/archive.liquid +45 -0
  89. data/_layouts/bib.liquid +677 -0
  90. data/_layouts/book-review.liquid +225 -0
  91. data/_layouts/book-shelf.liquid +66 -0
  92. data/_layouts/cv.liquid +127 -0
  93. data/_layouts/default.liquid +70 -0
  94. data/_layouts/distill.liquid +132 -0
  95. data/_layouts/documentation-download-detail.liquid +5 -0
  96. data/_layouts/documentation-home.liquid +100 -0
  97. data/_layouts/documentation-page.liquid +45 -0
  98. data/_layouts/manual-bib.liquid +73 -0
  99. data/_layouts/manual-chapter.liquid +99 -0
  100. data/_layouts/manual-featured-bib.liquid +100 -0
  101. data/_layouts/manual-home.liquid +120 -0
  102. data/_layouts/none.liquid +1 -0
  103. data/_layouts/outputs.liquid +29 -0
  104. data/_layouts/page.liquid +52 -0
  105. data/_layouts/post.liquid +95 -0
  106. data/_layouts/profile.liquid +36 -0
  107. data/_layouts/profiles.liquid +36 -0
  108. data/_layouts/project.liquid +7 -0
  109. data/_layouts/repositories.liquid +58 -0
  110. data/_layouts/theses.liquid +126 -0
  111. data/_plugins/bibliography_profiles.rb +164 -0
  112. data/_plugins/callouts.rb +104 -0
  113. data/_plugins/code_blocks.rb +277 -0
  114. data/_plugins/computation_figure_images.rb +266 -0
  115. data/_plugins/computation_sources.rb +42 -0
  116. data/_plugins/content_search_index.rb +210 -0
  117. data/_plugins/details.rb +23 -0
  118. data/_plugins/external-posts.rb +124 -0
  119. data/_plugins/figure_captions.rb +800 -0
  120. data/_plugins/file-exists.rb +22 -0
  121. data/_plugins/google-scholar-citations.rb +86 -0
  122. data/_plugins/hide-custom-bibtex.rb +18 -0
  123. data/_plugins/inspirehep-citations.rb +57 -0
  124. data/_plugins/localized_visual_sources.rb +145 -0
  125. data/_plugins/manual_release_metadata.rb +47 -0
  126. data/_plugins/mermaid_mmd_images.rb +233 -0
  127. data/_plugins/profile-pages.rb +28 -0
  128. data/_plugins/remove-accents.rb +32 -0
  129. data/_plugins/reproducible_build_time.rb +55 -0
  130. data/_plugins/search-data.rb +83 -0
  131. data/_plugins/theme-cache-bust.rb +56 -0
  132. data/_plugins/vega_visual_images.rb +290 -0
  133. data/_plugins/web_capture_images.rb +154 -0
  134. data/_sass/_base.scss +2133 -0
  135. data/_sass/_blog.scss +67 -0
  136. data/_sass/_callouts.scss +100 -0
  137. data/_sass/_custom.scss +437 -0
  138. data/_sass/_cv.scss +274 -0
  139. data/_sass/_developer.scss +97 -0
  140. data/_sass/_distill.scss +185 -0
  141. data/_sass/_documentation.scss +2220 -0
  142. data/_sass/_layout.scss +218 -0
  143. data/_sass/_manual.scss +2691 -0
  144. data/_sass/_profile.scss +323 -0
  145. data/_sass/_projects.scss +163 -0
  146. data/_sass/_reading.scss +465 -0
  147. data/_sass/_site-custom.scss +3 -0
  148. data/_sass/_tabs.scss +48 -0
  149. data/_sass/_team.scss +230 -0
  150. data/_sass/_themes.scss +254 -0
  151. data/_sass/_typograms.scss +132 -0
  152. data/_sass/_variables.scss +52 -0
  153. data/_sass/font-awesome/_animated.scss +152 -0
  154. data/_sass/font-awesome/_bordered-pulled.scss +20 -0
  155. data/_sass/font-awesome/_core.scss +49 -0
  156. data/_sass/font-awesome/_fixed-width.scss +7 -0
  157. data/_sass/font-awesome/_functions.scss +57 -0
  158. data/_sass/font-awesome/_icons.scss +13 -0
  159. data/_sass/font-awesome/_list.scss +18 -0
  160. data/_sass/font-awesome/_mixins.scss +65 -0
  161. data/_sass/font-awesome/_rotated-flipped.scss +31 -0
  162. data/_sass/font-awesome/_screen-reader.scss +14 -0
  163. data/_sass/font-awesome/_shims.scss +1578 -0
  164. data/_sass/font-awesome/_sizing.scss +16 -0
  165. data/_sass/font-awesome/_stacked.scss +32 -0
  166. data/_sass/font-awesome/_variables.scss +5044 -0
  167. data/_sass/font-awesome/brands.scss +30 -0
  168. data/_sass/font-awesome/fontawesome.scss +21 -0
  169. data/_sass/font-awesome/regular.scss +27 -0
  170. data/_sass/font-awesome/solid.scss +27 -0
  171. data/_sass/font-awesome/v4-shims.scss +11 -0
  172. data/_sass/tabler-icons/tabler-icons-filled.scss +1646 -0
  173. data/_sass/tabler-icons/tabler-icons-outline.scss +9859 -0
  174. data/_sass/tabler-icons/tabler-icons.scss +11463 -0
  175. data/_scripts/cronitor-analytics-setup.js +9 -0
  176. data/_scripts/giscus-setup.js +48 -0
  177. data/_scripts/google-analytics-setup.js +9 -0
  178. data/_scripts/open-panel-analytics-setup.js +14 -0
  179. data/_scripts/photoswipe-setup.js +11 -0
  180. data/assets/audio/epicaly-short-113909.mp3 +0 -0
  181. data/assets/bibliography/2018-12-22-distill.bib +7 -0
  182. data/assets/css/academicons.min.css +1 -0
  183. data/assets/css/bootstrap-toc.min.css +4 -0
  184. data/assets/css/bootstrap.min.css +7 -0
  185. data/assets/css/bootstrap.min.css.map +1 -0
  186. data/assets/css/jekyll-pygments-themes-github.css +209 -0
  187. data/assets/css/jekyll-pygments-themes-native.css +232 -0
  188. data/assets/css/jupyter-grade3.css +3758 -0
  189. data/assets/css/jupyter-monokai.css +3758 -0
  190. data/assets/css/jupyter.css +383 -0
  191. data/assets/css/main.scss +36 -0
  192. data/assets/css/mdb.min.css +48 -0
  193. data/assets/css/mdb.min.css.map +1 -0
  194. data/assets/css/scholar-icons.css +386 -0
  195. data/assets/fonts/academicons.ttf +0 -0
  196. data/assets/fonts/academicons.woff +0 -0
  197. data/assets/fonts/scholar-icons.ttf +0 -0
  198. data/assets/fonts/scholar-icons.woff +0 -0
  199. data/assets/fonts/tabler-icons-filled.ttf +0 -0
  200. data/assets/fonts/tabler-icons-filled.woff +0 -0
  201. data/assets/fonts/tabler-icons-filled.woff2 +0 -0
  202. data/assets/fonts/tabler-icons-outline.ttf +0 -0
  203. data/assets/fonts/tabler-icons-outline.woff +0 -0
  204. data/assets/fonts/tabler-icons-outline.woff2 +0 -0
  205. data/assets/fonts/tabler-icons.ttf +0 -0
  206. data/assets/fonts/tabler-icons.woff +0 -0
  207. data/assets/fonts/tabler-icons.woff2 +0 -0
  208. data/assets/html/relativity.html +15 -0
  209. data/assets/img/1.jpg +0 -0
  210. data/assets/img/10.jpg +0 -0
  211. data/assets/img/11.jpg +0 -0
  212. data/assets/img/12.jpg +0 -0
  213. data/assets/img/2.jpg +0 -0
  214. data/assets/img/3.jpg +0 -0
  215. data/assets/img/4.jpg +0 -0
  216. data/assets/img/5.jpg +0 -0
  217. data/assets/img/6.jpg +0 -0
  218. data/assets/img/7.jpg +0 -0
  219. data/assets/img/8.jpg +0 -0
  220. data/assets/img/9.jpg +0 -0
  221. data/assets/img/book_covers/the_godfather.jpg +0 -0
  222. data/assets/img/brand/dosquartsdedocs-logo-cafe.svg +31 -0
  223. data/assets/img/brand/dosquartsdedocs-logo-footer-cafe.svg +31 -0
  224. data/assets/img/brand/dosquartsdedocs-logo-white.svg +31 -0
  225. data/assets/img/brand/dosquartsdedocs-logo.svg +31 -0
  226. data/assets/img/prof_pic.jpg +0 -0
  227. data/assets/img/prof_pic_color.png +0 -0
  228. data/assets/img/profile-placeholder.svg +8 -0
  229. data/assets/img/publication_preview/brownian-motion.gif +0 -0
  230. data/assets/img/publication_preview/goodchild1992-gis-cover.jpg +0 -0
  231. data/assets/img/publication_preview/gutierrez2020-jtrg-preview.jpg +0 -0
  232. data/assets/img/publication_preview/harvey1989-postmodernity-cover.jpg +0 -0
  233. data/assets/img/publication_preview/tobler1970-economic-geography-cover.jpg +0 -0
  234. data/assets/img/publication_preview/tuan1977-space-place-cover.jpg +0 -0
  235. data/assets/img/publication_preview/wave-mechanics.gif +0 -0
  236. data/assets/img/publication_preview/zaragozi2025-rooftop-pv-preview.jpg +0 -0
  237. data/assets/img/rhino.png +0 -0
  238. data/assets/img/team/aaron-gutierrez.png +0 -0
  239. data/assets/img/team/alba-font.png +0 -0
  240. data/assets/img/team/alba-viana.png +0 -0
  241. data/assets/img/team/alejandro-gonzalez.png +0 -0
  242. data/assets/img/team/ana-pastor.png +0 -0
  243. data/assets/img/team/antoni-domenech.png +0 -0
  244. data/assets/img/team/benito-zaragozi.png +0 -0
  245. data/assets/img/team/cinta-sanz.png +0 -0
  246. data/assets/img/team/daniel-miravet.png +0 -0
  247. data/assets/img/team/eugenia-altamirano.png +0 -0
  248. data/assets/img/team/fiammetta-brandajs.png +0 -0
  249. data/assets/img/team/francesc-gonzalez.png +0 -0
  250. data/assets/img/team/isabel-paulino.png +0 -0
  251. data/assets/img/team/joan-borras.png +0 -0
  252. data/assets/img/team/julie-wilson.png +0 -0
  253. data/assets/img/team/liliana-sole.png +0 -0
  254. data/assets/img/team/maria-casado.png +0 -0
  255. data/assets/img/team/maria-medina.png +0 -0
  256. data/assets/img/team/marta-nello.png +0 -0
  257. data/assets/img/team/mogrify +1 -0
  258. data/assets/img/team/oscar-saladie.png +0 -0
  259. data/assets/img/team/paolo-russo.png +0 -0
  260. data/assets/img/team/raquel-santos.png +0 -0
  261. data/assets/img/team/salvador-anton.png +0 -0
  262. data/assets/img/team/sunsi-huertas.png +0 -0
  263. data/assets/img/team/user-placeholder.png +0 -0
  264. data/assets/img/team/wilbert-den-hoed.png +0 -0
  265. data/assets/img/team/xavier-delclos.png +0 -0
  266. data/assets/img/template_error.png +0 -0
  267. data/assets/js/bibsearch.js +70 -0
  268. data/assets/js/bootstrap-toc.min.js +5 -0
  269. data/assets/js/bootstrap.bundle.min.js +7 -0
  270. data/assets/js/bootstrap.bundle.min.js.map +1 -0
  271. data/assets/js/callouts.js +115 -0
  272. data/assets/js/chartjs-setup.js +14 -0
  273. data/assets/js/common.js +117 -0
  274. data/assets/js/content-search-match.js +159 -0
  275. data/assets/js/content-search.js +441 -0
  276. data/assets/js/copy_code.js +60 -0
  277. data/assets/js/custom.js +6 -0
  278. data/assets/js/developer-mode.js +103 -0
  279. data/assets/js/diff2html-setup.js +20 -0
  280. data/assets/js/distillpub/overrides.js +27 -0
  281. data/assets/js/distillpub/template.v2.js +9616 -0
  282. data/assets/js/distillpub/template.v2.js.map +1 -0
  283. data/assets/js/distillpub/transforms.v2.js +14557 -0
  284. data/assets/js/distillpub/transforms.v2.js.map +1 -0
  285. data/assets/js/documentation.js +435 -0
  286. data/assets/js/echarts-setup.js +29 -0
  287. data/assets/js/highlight-search-term.js +110 -0
  288. data/assets/js/jupyter_new_tab.js +18 -0
  289. data/assets/js/leaflet-setup.js +22 -0
  290. data/assets/js/manual.js +308 -0
  291. data/assets/js/masonry.js +12 -0
  292. data/assets/js/mathjax-setup.js +46 -0
  293. data/assets/js/mermaid-setup.js +37 -0
  294. data/assets/js/newsletter.js +105 -0
  295. data/assets/js/no_defer.js +24 -0
  296. data/assets/js/plotly-setup.js +52 -0
  297. data/assets/js/profile-nav.js +92 -0
  298. data/assets/js/progress-bar.js +73 -0
  299. data/assets/js/pseudocode-setup.js +18 -0
  300. data/assets/js/search/base-styles.min.js +286 -0
  301. data/assets/js/search/command-score.min.js +7 -0
  302. data/assets/js/search/hotkeys-js/hotkeys.esm.min.js +18 -0
  303. data/assets/js/search/lit/decorators.min.js +7 -0
  304. data/assets/js/search/lit/directives/class-map.min.js +7 -0
  305. data/assets/js/search/lit/directives/join.min.js +7 -0
  306. data/assets/js/search/lit/directives/live.min.js +7 -0
  307. data/assets/js/search/lit/directives/ref.min.js +7 -0
  308. data/assets/js/search/lit/directives/repeat.min.js +7 -0
  309. data/assets/js/search/lit/directives/unsafe-html.min.js +7 -0
  310. data/assets/js/search/lit/index.min.js +7 -0
  311. data/assets/js/search/lit-element/lit-element.min.js +12 -0
  312. data/assets/js/search/lit-html/directives/class-map.min.js +22 -0
  313. data/assets/js/search/lit-html/directives/join.min.js +12 -0
  314. data/assets/js/search/lit-html/directives/live.min.js +28 -0
  315. data/assets/js/search/lit-html/directives/ref.min.js +32 -0
  316. data/assets/js/search/lit-html/directives/repeat.min.js +27 -0
  317. data/assets/js/search/lit-html/directives/unsafe-html.min.js +22 -0
  318. data/assets/js/search/lit-html/is-server.min.js +12 -0
  319. data/assets/js/search/lit-html/lit-html.min.js +12 -0
  320. data/assets/js/search/ninja-action.min.js +101 -0
  321. data/assets/js/search/ninja-footer.min.js +62 -0
  322. data/assets/js/search/ninja-header.min.js +78 -0
  323. data/assets/js/search/ninja-keys.min.js +39 -0
  324. data/assets/js/search/reactive-element/decorators/custom-element.min.js +12 -0
  325. data/assets/js/search/reactive-element/decorators/event-options.min.js +12 -0
  326. data/assets/js/search/reactive-element/decorators/property.min.js +22 -0
  327. data/assets/js/search/reactive-element/decorators/query-all.min.js +17 -0
  328. data/assets/js/search/reactive-element/decorators/query-assigned-elements.min.js +17 -0
  329. data/assets/js/search/reactive-element/decorators/query-assigned-nodes.min.js +17 -0
  330. data/assets/js/search/reactive-element/decorators/query-async.min.js +17 -0
  331. data/assets/js/search/reactive-element/decorators/query.min.js +17 -0
  332. data/assets/js/search/reactive-element/decorators/state.min.js +27 -0
  333. data/assets/js/search/reactive-element/reactive-element.min.js +17 -0
  334. data/assets/js/search-setup.js +17 -0
  335. data/assets/js/shortcut-key.js +11 -0
  336. data/assets/js/tabs.min.js +5 -0
  337. data/assets/js/theme.js +314 -0
  338. data/assets/js/tooltips-setup.js +3 -0
  339. data/assets/js/typograms.js +1341 -0
  340. data/assets/js/vanilla-back-to-top.min.js +1 -0
  341. data/assets/js/vega-setup.js +24 -0
  342. data/assets/js/venobox-setup.js +5 -0
  343. data/assets/js/wechat.js +14 -0
  344. data/assets/js/zoom.js +15 -0
  345. data/assets/json/resume.json +98 -0
  346. data/assets/json/table_data.json +128 -0
  347. data/assets/jupyter/blog.ipynb +48 -0
  348. data/assets/pdf/example_pdf.pdf +0 -0
  349. data/assets/plotly/demo.html +72 -0
  350. data/assets/video/pexels-engin-akyurt-6069112-960x540-30fps.mp4 +0 -0
  351. data/assets/webfonts/fa-brands-400.ttf +0 -0
  352. data/assets/webfonts/fa-brands-400.woff2 +0 -0
  353. data/assets/webfonts/fa-regular-400.ttf +0 -0
  354. data/assets/webfonts/fa-regular-400.woff2 +0 -0
  355. data/assets/webfonts/fa-solid-900.ttf +0 -0
  356. data/assets/webfonts/fa-solid-900.woff2 +0 -0
  357. data/assets/webfonts/fa-v4compatibility.ttf +0 -0
  358. data/assets/webfonts/fa-v4compatibility.woff2 +0 -0
  359. data/docs/Gemfile +5 -0
  360. data/docs/_config.yml +83 -0
  361. data/docs/_documentation/en/01-quick-start.md +115 -0
  362. data/docs/_documentation/en/02-tools.md +146 -0
  363. data/docs/_documentation/en/03-usage.md +107 -0
  364. data/docs/_documentation/en/04-jekyll-basics.md +51 -0
  365. data/docs/_documentation/en/05-pages-collections.md +68 -0
  366. data/docs/_documentation/en/06-github-web-editing.md +92 -0
  367. data/docs/_documentation/en/10-profiles.md +125 -0
  368. data/docs/_documentation/en/11-unaltreselfie.md +39 -0
  369. data/docs/_documentation/en/12-unaltreprojecte.md +38 -0
  370. data/docs/_documentation/en/13-unaltremanual.md +237 -0
  371. data/docs/_documentation/en/14-unaltredocs.md +92 -0
  372. data/docs/_documentation/en/15-profile-checklist.md +39 -0
  373. data/docs/_documentation/en/20-syntax.md +353 -0
  374. data/docs/_documentation/en/21-themes.md +103 -0
  375. data/docs/_documentation/en/22-feature-reference.md +56 -0
  376. data/docs/_documentation/en/23-front-matter.md +51 -0
  377. data/docs/_documentation/en/24-data-files.md +28 -0
  378. data/docs/_documentation/en/30-customization.md +448 -0
  379. data/docs/_documentation/en/31-template.md +55 -0
  380. data/docs/_documentation/en/32-development.md +108 -0
  381. data/docs/_documentation/en/33-reusable-workflows.md +136 -0
  382. data/docs/_documentation/en/40-distribution.md +164 -0
  383. data/docs/_documentation/en/41-bibliometrics.md +137 -0
  384. data/docs/_documentation/en/42-docker-image.md +185 -0
  385. data/docs/_documentation/en/50-faq.md +33 -0
  386. data/docs/_pages/ca/index.md +35 -0
  387. data/docs/_pages/en/index.md +35 -0
  388. data/docs/_pages/es/index.md +35 -0
  389. data/docs/agents/action-prompts/00-start-site-session.txt +10 -0
  390. data/docs/agents/action-prompts/05-create-new-web.txt +5 -0
  391. data/docs/agents/action-prompts/10-content-update.txt +9 -0
  392. data/docs/agents/action-prompts/15-edit-default-content.txt +8 -0
  393. data/docs/agents/action-prompts/20-manual-teaching-materials.txt +18 -0
  394. data/docs/agents/action-prompts/22-manual-style-audit.txt +14 -0
  395. data/docs/agents/action-prompts/23-manual-structure-audit.txt +17 -0
  396. data/docs/agents/action-prompts/25-translation-prepublish.txt +8 -0
  397. data/docs/agents/action-prompts/30-project-site-update.txt +7 -0
  398. data/docs/agents/action-prompts/40-documentation-update.txt +7 -0
  399. data/docs/agents/action-prompts/50-bibliography-entry.txt +7 -0
  400. data/docs/agents/action-prompts/60-bibliometrics-refresh.txt +7 -0
  401. data/docs/agents/action-prompts/70-build-and-review.txt +12 -0
  402. data/docs/agents/manual-authoring-components.md +255 -0
  403. data/docs/agents/mcp-contract.md +162 -0
  404. data/docs/agents/quarto-computation-adoption.md +102 -0
  405. data/docs/assets/img/unaltraweb-docs-hero.svg +36 -0
  406. data/lib/unaltraweb/version.rb +8 -0
  407. data/lib/unaltraweb.rb +31 -0
  408. data/requirements.txt +5 -0
  409. data/scripts/biblio/fetch_scimago_csv.sh +126 -0
  410. data/scripts/biblio/metrics_common.py +154 -0
  411. data/scripts/biblio/metrics_merge_meta.py +73 -0
  412. data/scripts/biblio/metrics_update.py +826 -0
  413. data/scripts/computations/python/Dockerfile +37 -0
  414. data/scripts/computations/r/Dockerfile +31 -0
  415. data/scripts/computations/render.py +1267 -0
  416. data/scripts/cv/render_pdf_preview.sh +36 -0
  417. data/scripts/deploy/publish_branch.sh +80 -0
  418. data/scripts/generate_logo_variants.py +47 -0
  419. data/scripts/manual/Dockerfile +31 -0
  420. data/scripts/manual/build_pdf.py +1780 -0
  421. data/scripts/manual/filters/bibliography.lua +164 -0
  422. data/scripts/manual/filters/code-blocks.lua +102 -0
  423. data/scripts/manual/filters/figure-captions.lua +35 -0
  424. data/scripts/manual/publish_release.sh +281 -0
  425. data/scripts/manual/templates/manual.tex +494 -0
  426. data/scripts/manual/verify_release_assets.py +650 -0
  427. data/scripts/test_gem_build.py +128 -0
  428. data/scripts/test_reproducible_jekyll_build.py +191 -0
  429. data/scripts/test_wheel_install.py +282 -0
  430. data/scripts/unaltraweb-docker-mount.sh +36 -0
  431. data/scripts/unaltraweb-mcp-bootstrap.sh +105 -0
  432. data/scripts/unaltraweb-mcp-cleanup.sh +73 -0
  433. data/scripts/unaltraweb-mcp-project-id.sh +34 -0
  434. data/scripts/validate_distribution.py +563 -0
  435. data/scripts/validate_workflows.py +1285 -0
  436. data/scripts/web_captures/Dockerfile +31 -0
  437. data/scripts/web_captures/capture.mjs +157 -0
  438. data/scripts/web_captures/package-lock.json +56 -0
  439. data/scripts/web_captures/package.json +9 -0
  440. data/scripts/web_captures/render.py +867 -0
  441. data/src/unaltraweb_mcp/component-contract.json +153 -0
  442. data/src/unaltraweb_mcp/component-contract.schema.json +87 -0
  443. data/src/unaltraweb_mcp/docker_mount.py +19 -0
  444. metadata +861 -0
@@ -0,0 +1,136 @@
1
+ ---
2
+ title: Use Reusable GitHub Workflows
3
+ description: GitHub Actions workflows provided by the unaltraweb core.
4
+ lang: en
5
+ ref: reusable_workflows
6
+ profiles:
7
+ - unaltredocs
8
+ documentation_profiles:
9
+ - github-publishers
10
+ - contributors
11
+ - core-developers
12
+ section: Publish With GitHub
13
+ weight: 70
14
+ permalink: "/reusable-workflows/"
15
+ nav_title: GitHub Workflows
16
+ ---
17
+ Child sites should keep workflow files thin and call reusable workflows from the core repository.
18
+
19
+ These wrappers should normally be manual-only. Use `workflow_dispatch` so a push or Dependabot pull request does not start a deploy unless someone explicitly asks for it.
20
+
21
+ ## Site deploy
22
+
23
+ {% raw %}
24
+ ```yaml
25
+ jobs:
26
+ validate:
27
+ # Generated callers fail unless reviewed_sha equals the selected main commit.
28
+ # Keep this generated job unchanged.
29
+ deploy:
30
+ uses: dosquartsdedocs/unaltraweb/.github/workflows/site-deploy.yml@<reviewed-commit-sha>
31
+ with:
32
+ reviewed_sha: "${{ inputs.reviewed_sha }}"
33
+ manual-pdf-image: "ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:<reviewed-digest>"
34
+ check-manual-pdf: false
35
+ sync-manual-pdf: true
36
+ vegavisuals-sha: "<reviewed-vegavisuals-commit-sha>"
37
+ ```
38
+ {% endraw %}
39
+
40
+ Pin the reusable workflow to a reviewed commit because it receives Pages and OIDC permissions. The generated caller accepts only `workflow_dispatch`, requires the full locally reviewed SHA, and fails unless the selected ref is `refs/heads/main` at exactly that SHA. The reusable workflow repeats that source check, requires the PDF worker by immutable GHCR digest, rejects configured PDF/cover outputs already tracked by Git, installs Ruby dependencies, rejects stale computations, web captures and manifest-backed Vega visualizations, builds with the `unaltraweb` gem config and deploys to GitHub Pages. The checks are no-ops when their source configuration is absent. Set `check-computations`, `check-web-captures` or `check-visualizations` to `false` only when another freshness gate intentionally owns that source type.
41
+
42
+ A site with `.vegavisuals.yml` must pass `vegavisuals-sha` as the full lowercase 40-character SHA of a reviewed commit. The workflow installs that exact revision from the fixed public repository URL before checking freshness; it does not accept a mutable tag, branch, or caller-supplied URL. Deployment only checks committed visualization outputs; run `make visualization-render` locally rather than rendering in CI.
43
+
44
+ For `unaltremanual`, the `latest` channel is a manual-only deployment from the reviewed `main` branch. PDF output is disabled in a fresh manual scaffold until a maintainer configures it. When enabled, deployment deterministically rebuilds every configured language and places the current PDF and cover into the site artifact before Jekyll publishes it. The default `assets/pdf/manual-<lang>.pdf` and `assets/img/manual-cover-<lang>.png` outputs are generated deployment products and are not committed. Existing tracked copies require a reviewed one-time `git rm --cached`. The resulting website and PDF display `latest`; release checks reject generated `legacy/` or `sandbox/` content.
45
+
46
+ Clean package scaffolds include a manual GitHub Pages wrapper pinned to a reviewed workflow revision. It has no push deployment trigger: a maintainer runs it only after local checks/renders and human review. The optional integration template retains additional local publishing experiments, but generated sites do not publish from local validation targets.
47
+
48
+ The `consumer_integration` object in `src/unaltraweb_mcp/component-contract.json` is the single source for the reviewed core revision, workflow path, attested manual PDF image digest, and Vega renderer revision. The scaffold renders that tuple atomically into `Gemfile`, `Gemfile.lock`, and the packaged caller. The caller passes the existing `reviewed_sha` input through to the provider, so the reviewed `main` source is checked independently at both caller and provider boundaries.
49
+
50
+ This pin-only integration follows the required M -> D -> B order: D was built from M's permanent identity before the caller recorded either value. Repeat that order for future provider updates; never use `@main` or substitute a mutable/version-tagged image for D.
51
+
52
+ ## Stable manual releases
53
+
54
+ `.github/workflows/site-release.yml` is a separate `workflow_call`-only boundary for future `vYYYY.MM` and `vYYYY.MM.N` releases. Its preparation job has only `contents: read`: it checks the reviewed `main` SHA, checks out an immutable core revision, requires digest-pinned manual PDF and MCP site-build images, records the Python runtime from the site-build image, derives `SOURCE_DATE_EPOCH` from the reviewed consumer commit, and runs Jekyll offline inside the same MCP image used for local candidate review. When `.vegavisuals.yml` exists, the job runs the freshness check from the exact reviewed vegavisuals checkout rather than merely recording its SHA. It then requires the rebuilt version-2 `release-manifest.json` SHA-256 to equal the locally reviewed candidate digest supplied by the caller, assembles a deterministic web archive, writes checksums, and uploads a same-run Actions artifact. Only the dependent `publish` job receives `contents: write`. That job requires the `stable-release` GitHub environment and consists only of pinned artifact download, immutable verifier checkout, exact Python setup, and the reviewed publisher. The publisher verifies the asset allowlist, source/runtime identity, site tree fingerprint and PDF hashes, creates a lightweight tag at the reviewed source SHA, and addresses one matching draft by numeric release ID. A retry resets that draft's canonical metadata and assets, downloads them, compares every byte with the prepared candidate, confirms that the remote asset inventory and tag have not changed, and publishes the draft last.
55
+
56
+ Prepare and check the stable candidate locally from the exact clean `main` commit, then obtain the caller input with `sha256sum tmp/manual-release/<selector>/release-manifest.json`. CI is the authoritative offline rebuild; any network-dependent local difference changes the manifest digest and fails before any job has publication authority. Before enabling a stable caller, protect `main` against direct changes, enable immutable releases in repository settings, protect `v*` tags while allowing only the approved release workflow to create them, and configure required reviewers with self-review and bypass disabled for the repository's `stable-release` environment. Restrict that environment to protected `main`. No stable caller is installed by the current scaffold because the reusable workflow must first exist at a reviewed immutable commit. Use two commits:
57
+
58
+ 1. Merge the reusable workflow and every helper it executes; call the resulting permanent commit `A`.
59
+ 2. In a follow-up change, add the consumer caller and pin both its `uses:` and `core_sha` to `A`. Require `reviewed_sha`, `candidate_manifest_sha256`, and the reviewed PDF and MCP site-build image digests as dispatch inputs. Never use `@main`, and do not squash or rebase `A` away.
60
+
61
+ This is deliberate: a workflow cannot truthfully pin itself to the commit being created. Preparing a local candidate or passing the read-only job is evidence, not publication authorization. Do not dispatch a stable release until a stable edition is intentionally approved.
62
+
63
+ A future caller should keep the reviewed core revision static and grant write authority only to the reusable job:
64
+
65
+ {% raw %}
66
+ ```yaml
67
+ on:
68
+ workflow_dispatch:
69
+ inputs:
70
+ selector:
71
+ required: true
72
+ type: string
73
+ reviewed_sha:
74
+ required: true
75
+ type: string
76
+ candidate_manifest_sha256:
77
+ required: true
78
+ type: string
79
+
80
+ permissions:
81
+ contents: read
82
+
83
+ jobs:
84
+ release:
85
+ permissions:
86
+ contents: write
87
+ uses: dosquartsdedocs/unaltraweb/.github/workflows/site-release.yml@<commit-A>
88
+ with:
89
+ selector: "${{ inputs.selector }}"
90
+ reviewed_sha: "${{ inputs.reviewed_sha }}"
91
+ candidate_manifest_sha256: "${{ inputs.candidate_manifest_sha256 }}"
92
+ core_sha: "<commit-A>"
93
+ manual_pdf_image: "ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:<reviewed-digest>"
94
+ site_build_image: "ghcr.io/dosquartsdedocs/unaltraweb-mcp@sha256:<reviewed-digest>"
95
+ ```
96
+ {% endraw %}
97
+
98
+ ## Publication metrics
99
+
100
+ ```yaml
101
+ jobs:
102
+ metrics:
103
+ uses: dosquartsdedocs/unaltraweb/.github/workflows/metrics-update.yml@main
104
+ ```
105
+
106
+ Metrics updates are manual and explicit. Normal site deploys remain static.
107
+
108
+ ## Project computation images
109
+
110
+ Projects that extend a core computation image can publish a separate GHCR package without copying the factory workflow:
111
+
112
+ ```yaml
113
+ name: Publish Python computation image
114
+
115
+ on:
116
+ workflow_dispatch:
117
+
118
+ permissions:
119
+ contents: read
120
+ packages: write
121
+
122
+ jobs:
123
+ image:
124
+ uses: dosquartsdedocs/unaltraweb/.github/workflows/project-compute-image.yml@<reviewed-commit-sha>
125
+ with:
126
+ engine: python
127
+ image: example-compute-python
128
+ dockerfile: Dockerfile.compute-python
129
+ context: .
130
+ base_image: ghcr.io/dosquartsdedocs/unaltraweb-compute-python@sha256:<digest>
131
+ test_command: make test-compute-image
132
+ ```
133
+
134
+ Pin the reusable workflow to a reviewed commit because it receives the caller's package-write token. The provider checkout is bound to the defining job's `workflow_repository` and `workflow_sha`, not caller-controlled workflow identity. Before a login is possible, default-branch candidate publication checks that provider revision with `distribution-check`, while an exact `vX.Y.Z` tag publication uses `distribution-release-check`. The workflow also requires a digest-pinned `base_image`, validates confined build paths and the selected ref, runs the optional project test command, and completes a no-push image build. Only the dependent publication job can publish `main` and `sha-*` under the consumer repository owner or semver/release-tag metadata from a release tag. Published images include SBOM and provenance attestations. Keep engine-specific dependencies and lockfiles in that project; for example, a TIGIT site should publish `tigit-compute-r`, not a TIGIT variant of the core package.
135
+
136
+ After publication, make the package public or authenticate Docker, select its full GHCR digest in `.unaltraweb/computations.yml`, run `manual-compute-render`, and commit the updated generated artifacts and computation lock. Publishing an extension does not select or rerender it automatically.
@@ -0,0 +1,164 @@
1
+ ---
2
+ title: Understand The Distribution Model
3
+ description: Core/template split and update model for unaltraweb.
4
+ lang: en
5
+ ref: distribution_model
6
+ profiles:
7
+ - unaltredocs
8
+ documentation_profiles:
9
+ - core-developers
10
+ section: Core Development
11
+ weight: 620
12
+ permalink: "/distribution/"
13
+ nav_title: Distribution Model
14
+ ---
15
+ `unaltraweb` is the source of truth for reusable code. Template repositories should stay thin and contain only site-specific content, local overrides and small integration files.
16
+
17
+ ## Repository Roles
18
+
19
+ - `unaltraweb`: layouts, includes, Sass, assets, Jekyll plugins, Python and shell tooling, reusable GitHub Actions workflows, documentation, small internal examples and the shared Docker runtime image.
20
+ - `unaltraweb_mcp` package scaffolds: clean profile-specific config, localized home pages, content roots, and native build/serve files used by new sites.
21
+ - `unaltraweb-template`: multi-profile demo assets, local Docker workflow, Dependabot config, workflow wrapper and Playwright integration tests.
22
+ - `docs/` in `unaltraweb`: public reference site for the platform itself.
23
+
24
+ The template is the better place to validate gem consumption, centralized styles and shared logic because it runs as a child site. It is not required to create a site: package scaffolds are the supported clean starting point.
25
+
26
+ ## Component Contract
27
+
28
+ `src/unaltraweb_mcp/component-contract.json` is the canonical versioned bill of materials. Its `consumer_integration` object is the sole source for the reviewed core Git revision, reusable deploy workflow, manual PDF image digest, and Vega renderer revision. Scaffold templates render that tuple atomically into consumer `Gemfile`, `Gemfile.lock`, and deploy workflow files. `component-contract.schema.json` defines schema version 1. Runtime loading and `scripts/validate_distribution.py` validate the complete document against that schema, then enforce semantic parity between versions, release tags, repositories, references, wheel contents, CLI availability, and consumer integration pins.
29
+
30
+ The BOM is an interoperability contract, not a bundle. The wheel contains only its Python control/inspection modules, schema/BOM, and clean package-owned scaffolds. In particular it does not contain Ruby theme assets, Docker image layers, factory Make/scripts/docs, TeX, Chromium, computation environments, `diavisuals`, or `vegavisuals`.
31
+
32
+ For the selected release, the core-owned container references use `0.3.0`; the BOM selects the published `diavisuals v0.3.1` and `vegavisuals v0.3.1` releases. Current checkouts can be used through `suggested_path`, while immutable release references remain the distribution contract. `distribution-check` validates structural integrity for normal CI. `distribution-release-check` blocks coordinated publication while any component is `pending` or `unavailable`; reviewed source authorized to produce the final same-commit candidates is `ready`, while an already-published component is `released`.
33
+
34
+ ## Wheel And Doctor
35
+
36
+ A clean `unaltraweb-mcp` wheel works without a factory checkout for `version`, `new-web`, top-level `doctor`, constrained source management, scaffold synchronization, `site-doctor`, HTML audit, and pure inspection where feasible. Examples include `mcp list-tools`, `starter-templates`, `detect-site`, `site-context`, `profile-check`, content/language/bibliography inventories, and `build-health`.
37
+
38
+ ```bash
39
+ unaltraweb-mcp doctor
40
+ unaltraweb-mcp doctor --project /path/to/site
41
+ unaltraweb-mcp doctor --project /path/to/site --docker
42
+ ```
43
+
44
+ Doctor performs no network requests. It reports limited wheel mode as an informational healthy state, reads `_config.yml`, Gemfile/lock, Make pins, computation settings, capture recipes, PDF enablement, and companion manifests when a project is supplied, and checks only components relevant to those features. `release_ready` is separate from operational `ok`, so any pending or unavailable component release is visible without making package-only inspection unusable. Companion-specific findings retain their stable companion codes; core package and image releases use the generic release codes. `--docker` optionally inspects local Docker and selected image presence; it never pulls or builds. Every finding has stable `code`, `severity`, `expected`, `actual`, and `remediation` fields.
45
+
46
+ Factory-backed MCP serving, site preflight/build, computations, captures, PDF operations, bibliometrics, and prompt loading still require the checkout or the selected MCP image. A wheel invocation fails those commands explicitly and tells the caller to set `UNALTRAWEB_FACTORY_DIR`; it does not pretend the factory assets were bundled.
47
+
48
+ ## User Paths
49
+
50
+ ### GitHub-only editing
51
+
52
+ Users can push a site created by `new_web` and edit small content changes in the GitHub web UI. The generated README requires an assigned issue or accepted file reservation, one task branch, one active editor per file, and a small Draft pull request. Editors never change `main` directly; they stop and ask a maintainer when work overlaps or conflicts.
53
+
54
+ This path is intended for small content edits, bibliography updates, course/manual chapter edits and configuration changes. It does not require Docker, Make or a local development environment. A maintainer checks and renders the branch locally, reviews it, merges it, and only then starts deployment manually.
55
+
56
+ For `unaltremanual`, `latest` is a manual-only deployment from reviewed `main`; a push does not deploy it. The caller requires the exact locally reviewed commit SHA and an immutable manual PDF worker digest. When PDF output is enabled, its default PDF and cover are generated for deployment rather than versioned. The website marker and PDF both identify the selected channel/version. Stable `vYYYY.MM(.N)` editions use explicit immutable releases, bind the rebuilt assets to the locally reviewed candidate manifest, and reject generated private/runtime trees.
57
+
58
+ ### Local editing
59
+
60
+ Users who need larger edits can clone their generated site repository and use its package-scaffolded Docker workflow:
61
+
62
+ ```bash
63
+ make serve
64
+ make build
65
+ make test
66
+ make down
67
+ ```
68
+
69
+ Local editing requires Git, Docker and GNU Make. On Windows, use WSL2 with Docker Desktop and run the same commands inside the WSL Linux shell.
70
+
71
+ Theme development can happen side by side by pointing the template at a local core checkout:
72
+
73
+ ```bash
74
+ make serve LOCAL_CORE=../unaltraweb
75
+ make build LOCAL_CORE=../unaltraweb
76
+ make test LOCAL_CORE=../unaltraweb SITE_PROFILE=unaltreprojecte
77
+ ```
78
+
79
+ ## Demo Strategy
80
+
81
+ - Template demo: realistic content for `unaltreselfie`, `unaltreprojecte`, `unaltremanual` and `unaltredocs`, used to validate the gem consumer path.
82
+ - Core docs: the `unaltraweb` reference site, focused on concepts, profile capabilities, syntax, customization points, tools and links to the template.
83
+ - Avoid duplicating full demo content between the two repositories.
84
+
85
+ ## Core Docs Publishing
86
+
87
+ The core repository deploy workflow is manual. It builds only `docs/` and publishes it with GitHub Pages Actions. The root core Jekyll build excludes `docs/`, so the reference site can use its own root-relative permalinks without colliding with the internal core demo build.
88
+
89
+ Reference deployment, link checks, Docker image publishing and publication metrics run manually from GitHub or locally. Repository CI runs for pushes and pull requests, and CodeQL runs for pull requests, default-branch pushes and a weekly schedule. Neither automatic workflow deploys or publishes.
90
+
91
+ ## Updates
92
+
93
+ Repositories created from a GitHub template are not linked to the template as forks, so template changes are not automatically proposed to users.
94
+
95
+ For that reason:
96
+
97
+ - normal improvements should ship through the `unaltraweb` gem or reusable workflows;
98
+ - site repositories can enable Dependabot for Bundler and GitHub Actions, but deploy workflows should remain manual;
99
+ - breaking changes should be released with migration notes;
100
+ - scaffold changes should be rare; generated sites can explicitly dry-run `scaffold_sync`, which updates only unchanged baseline runtime files (including the pull-request template), creates newly managed missing files, reports conflicts, never deletes paths, stages every output, rechecks adopted and unchanged files around the manifest write, rolls the whole transaction back on failure, and commits its manifest last. Generated README prose is site-owned and is not overwritten by synchronization.
101
+
102
+ ## Docker Runtime
103
+
104
+ The pending `0.3.0` contract names the intended semver runtime target. Before release, a maintainer may manually run the Docker workflow from the final reviewed default-branch commit. Its credential-separated build, test, and promotion jobs publish SHA-only candidates, verify and test their exact signed digests without write authority, and only then assign `main` and `latest` from a non-executing package-write job. Local maintainer images use explicit names such as `unaltraweb:dev`.
105
+
106
+ The same candidate rule applies to workers. The Python and R computation workers are already released and selected by immutable digest; the gem, wheel, runtime, MCP, web-capture worker, and manual PDF worker remain truthfully `pending`. The final reviewed source commit marks only candidate components `ready` before default-branch publication. For runtime, MCP, and manual PDF, `build-candidates` builds each image once under only its SHA tag, builds MCP from the runtime digest, and creates a GitHub-signed build-provenance attestation for each exact digest while retaining BuildKit SBOM and maximum provenance. It never runs those images. `test-candidates` has only read permissions, verifies registry-stored attestations against the exact repository, workflow, and source commit, pulls and checks all revision labels, logs out of GHCR, and then runs every Ruby test, all manual PDF integrations, reproducibility, MCP smoke, and docs against digest references without exposing `GH_TOKEN`. Only its successful digest outputs reach `promote-candidates`, which has package write but executes no candidate and points `sha-*`, `main`, and `latest` to those digests without rebuilding. A failure can leave a reviewable SHA candidate but cannot move broad aliases.
107
+
108
+ The pre-build absence lookup is not an atomic no-clobber guarantee: GHCR exposes separate read and tag-write operations, not compare-and-swap. A package administrator could race the lookup or later retagging. Immediate equality checks and post-promotion verification bound that risk, while the signed, source-bound digest tested by the read-only job remains the evidence to record. An immediately following `release-candidates.json` child commit records immutable image digests and package checksums while changing no other path. Validation requires the parent to belong to the default branch, requires each image digest to use the component's declared GHCR repository, and checks exact package names. Before semver promotion, the tag-only job proves that each source commit's SHA tag still resolves to the recorded digest, verifies its GitHub-signed attestation with `receipt.source_commit` as the source digest, and requires the image revision label to equal that commit. It then uses `docker buildx imagetools create` to add and verify semver aliases without rebuilding, executing, or trusting a mutable source tag. Excluding the receipt from image and package contents avoids an impossible self-digest for the MCP. Publication workflows require the reviewed manual PDF image by full digest; this candidate state does not assert that a remote `v0.3.0` image exists. Separate worker images keep Chromium, TeX, and computation environments out of ordinary site and wheel installs.
109
+
110
+ The image is not the source of layouts or styles. Child sites still get those from the `unaltraweb` gem declared in their `Gemfile`. This keeps updates centralized in two places:
111
+
112
+ - gem updates change reusable site behaviour, layouts, Sass, plugins and scripts;
113
+ - Docker image updates change the local build/runtime environment.
114
+
115
+ Before recommending the local Docker workflow to unauthenticated users, complete this first-publish checklist:
116
+
117
+ - Mark the components `ready` in the final reviewed source commit.
118
+ - Run the image and package-preparation workflows from that exact default-branch commit to publish `sha-<full-commit>` images and prepare the gem/wheel candidates without creating a release tag. For runtime, MCP, and manual PDF, preserve the workflow summary that pairs the source commit with all three signed and read-only-tested digests; `main` and `latest` move only from the dependent promotion job after those tests pass.
119
+ - Add only `release-candidates.json` in the next commit, recording the parent source SHA, immutable image references, package basenames and SHA-256 checksums.
120
+ - Run `make distribution-release-check`, create the exact release tag on the receipt commit, then run the image workflows from the tag to promote the recorded manifests to semver aliases.
121
+ - Open the `ghcr.io/dosquartsdedocs/unaltraweb` package settings in GitHub.
122
+ - Make the package public.
123
+ - Confirm that `docker pull ghcr.io/dosquartsdedocs/unaltraweb:0.3.0` works without `docker login`.
124
+ - Make the `ghcr.io/dosquartsdedocs/unaltraweb-mcp` package public after its first publication.
125
+ - Confirm that `docker pull ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.3.0` works without `docker login`.
126
+
127
+ The receipt uses a full source commit and different evidence by component kind. This abbreviated example shows both forms; the real `components` object must contain exactly every component marked `ready`:
128
+
129
+ ```json
130
+ {
131
+ "schema_version": 1,
132
+ "release": "v0.3.0",
133
+ "source_commit": "0123456789abcdef0123456789abcdef01234567",
134
+ "components": {
135
+ "runtime": {
136
+ "reference": "ghcr.io/dosquartsdedocs/unaltraweb@sha256:<64 lowercase hex characters>"
137
+ },
138
+ "gem": {
139
+ "artifact": "unaltraweb-0.3.0.gem",
140
+ "sha256": "<64 lowercase hex characters>"
141
+ }
142
+ }
143
+ }
144
+ ```
145
+
146
+ This checklist describes future publication verification; changing the contract does not publish, tag, or release any artifact.
147
+
148
+ ## CI And Release Gates
149
+
150
+ Automatic `.github/workflows/ci.yml` uses `distribution-check`. It validates schema/version/reference parity and release-status declarations, but permits a selected component to remain explicitly `pending` or `unavailable`. It also runs Python compile/unit/diff checks, wheel/gem checks, workflow policy, MCP smoke and the docs build. CodeQL is an independent automatic security check for JavaScript/TypeScript, Python and Ruby.
151
+
152
+ `distribution-release-check` is the strict coordinated-release gate. The final reviewed source commit marks authorized candidate components `ready`; already-published components may be `released`, and released containers except MCP must use digest references. Core artifact workflows keep source/package preflights unprivileged and without registry access. Runtime, MCP, and manual PDF use separate signing/package-write build, read-only test, and non-executing package-write promotion jobs. Every SHA-only build gets a GitHub-signed provenance attestation; tests verify its exact digest, signer workflow, and source commit before removing registry credentials and running it; broad aliases receive only successful test-job digest outputs. The receipt-only child commit binds every `ready` component to an immutable image digest or package checksum and binds those candidates to its parent source SHA. An exact semver release tag is rejected unless that complete evidence is valid. Tag jobs reverify SHA-tag equality, signed source provenance, and revision labels before promoting the receipt's manifests rather than rebuilding or executing them, preserving their SBOM and provenance attestations. The MCP candidate consumes the exact runtime digest emitted by the candidate runtime build.
153
+
154
+ The manual `.github/workflows/package-prepare.yml` builds and checks the gem and wheel, writes `SHA256SUMS`, and uploads an immutable workflow artifact whose name includes the source commit SHA. It does not call RubyGems, PyPI or GitHub Releases. Passing CI, preparing candidates, and later passing the strict coordinated-release gate are evidence for a release, not authorization to publish: tagging, starting a credentialed image workflow, uploading language packages and creating a GitHub release remain separate explicit maintainer approvals.
155
+
156
+ ## Verification
157
+
158
+ Core changes should be validated in two layers:
159
+
160
+ - Run `make workflow-check`, `make distribution-check`, `make wheel-check`, and `make gem-check` for workflow publication policy, version/schema parity, selected release metadata, CLI/wheel boundaries, clean wheel installation, and built-gem content. Run `make distribution-release-check` after all final-commit candidates are verified and before creating the coordinated tag. `gem-check` uses local RubyGems or an already-local selected runtime image and never pulls implicitly.
161
+ - Build the core repository to catch internal Jekyll errors.
162
+ - Build or test `../unaltraweb-template` with `LOCAL_CORE=../unaltraweb` to catch consumer-path regressions.
163
+
164
+ Template Playwright tests and screenshot generation are intentionally heavier than a Jekyll build. Run targeted profiles when machine resources are limited.
@@ -0,0 +1,137 @@
1
+ ---
2
+ title: Maintain The Metrics Pipeline
3
+ description: Static bibliometric metrics workflow for unaltraweb sites.
4
+ lang: en
5
+ ref: bibliometrics
6
+ profiles:
7
+ - unaltredocs
8
+ documentation_profiles:
9
+ - contributors
10
+ - core-developers
11
+ section: Core Development
12
+ weight: 630
13
+ permalink: "/bibliometrics/"
14
+ nav_title: Metrics Pipeline
15
+ ---
16
+ This project uses a data-first bibliometrics workflow:
17
+
18
+ - metrics are fetched and written into BibTeX fields (`x_*` + `note`) in a pre-build step,
19
+ - aggregated totals are generated into `_data/metrics.yml`,
20
+ - Jekyll render remains static (no API calls during `jekyll build`).
21
+
22
+ ## Files
23
+
24
+ - `scripts/biblio/metrics_update.py`
25
+ - `scripts/biblio/metrics_merge_meta.py`
26
+ - `scripts/biblio/fetch_scimago_csv.sh`
27
+ - `_data/metrics-overrides.yml`
28
+ - `_data/metrics.yml` (generated summary; useful for metrics summary components)
29
+
30
+ ## Local data cache (not versioned)
31
+
32
+ - `.cache/scimago/scimagojr.csv`
33
+
34
+ Large Scimago datasets are intentionally excluded from git.
35
+
36
+ ## Scimago source
37
+
38
+ `make metrics-scimago-fetch` downloads the public `sjrdata` R dataset and converts it to CSV:
39
+
40
+ - source: `https://raw.githubusercontent.com/ikashnitsky/sjrdata/master/data/sjr_journals.rda`
41
+ - output: full CSV (all available Scimago columns). Required minimum columns: `year,issn,sjr,sjr_best_quartile,categories`
42
+
43
+ You can also pass local files:
44
+
45
+ - `./scripts/biblio/fetch_scimago_csv.sh --input path/to/sjr_journals.rda`
46
+ - `./scripts/biblio/fetch_scimago_csv.sh --input path/to/scimagojr.csv`
47
+
48
+ ## Commands
49
+
50
+ From repository root:
51
+
52
+ ```bash
53
+ make metrics-scimago-fetch
54
+ make metrics-update
55
+ make metrics-update-all
56
+ make metrics-check
57
+ ```
58
+
59
+ Local commands accept extra script arguments:
60
+
61
+ ```bash
62
+ make metrics-update METRICS_ARGS="--strict-external --require-scimago"
63
+ make metrics-check METRICS_ARGS="--require-scimago"
64
+ make metrics-scimago-fetch SCIMAGO_INPUT=path/to/scimagojr.csv
65
+ ```
66
+
67
+ Equivalent direct commands:
68
+
69
+ ```bash
70
+ ./scripts/biblio/fetch_scimago_csv.sh
71
+ python3 scripts/biblio/metrics_update.py
72
+ python3 scripts/biblio/metrics_update.py --offline --dry-run
73
+ ```
74
+
75
+ ## GitHub workflow
76
+
77
+ Publication metrics are not part of automatic CI. Use the manual/reusable `.github/workflows/metrics-update.yml` workflow when you want GitHub to update or check metrics.
78
+
79
+ The workflow keeps generated Scimago files and diagnostics out of pull requests. When PR creation is enabled, PRs include only versionable generated data: BibTeX changes under `_bibliography/` and the aggregate `_data/metrics.yml` summary.
80
+
81
+ Child repositories can add a thin manual wrapper:
82
+
83
+ ```yaml
84
+ name: Update publication metrics
85
+
86
+ on:
87
+ workflow_dispatch:
88
+
89
+ jobs:
90
+ metrics:
91
+ uses: dosquartsdedocs/unaltraweb/.github/workflows/metrics-update.yml@main
92
+ with:
93
+ fetch_scimago: true
94
+ create_pull_request: true
95
+ ```
96
+
97
+ Useful workflow inputs:
98
+
99
+ - `fetch_scimago`: downloads and validates the local Scimago CSV cache before updating metrics.
100
+ - `offline`: skips OpenAlex and Crossref calls.
101
+ - `dry_run`: avoids rewriting BibTeX entries while still writing diagnostics.
102
+ - `strict_external`: fails the workflow if OpenAlex or Crossref requests fail.
103
+ - `require_scimago`: fails when the Scimago CSV is unavailable.
104
+ - `create_pull_request`: opens a PR with generated versionable changes.
105
+
106
+ If `create_pull_request` is `false`, the workflow uploads `_data/metrics.yml` and diagnostics as artifacts but does not persist generated changes.
107
+
108
+ ## Failure modes
109
+
110
+ - Missing Scimago cache: entries are marked with `scimago-missing` unless `--require-scimago` is set.
111
+ - Broken Scimago URL or blocked network: `fetch_scimago` fails with a message suggesting a local `--input` file.
112
+ - OpenAlex/Crossref outage: entries are marked with `api-error`, diagnostics include request errors, and `--strict-external` makes the command fail non-zero.
113
+
114
+ ## Overrides
115
+
116
+ Use `_data/metrics-overrides.yml` to force IDs and values when automatic matching fails.
117
+ Supported examples:
118
+
119
+ - `openalex_id`
120
+ - `crossref_cited_by`
121
+ - `gs_id`, `gs_cited_by`
122
+ - `x_scimago_*`
123
+
124
+ ## Diagnostics
125
+
126
+ The update script produces:
127
+
128
+ - `tmp/metrics-report.json`
129
+ - `tmp/metrics-unmatched.tsv`
130
+
131
+ Use these files to review unmatched DOI/ISSN items and stale Scimago matches.
132
+
133
+ ## Build/deploy note
134
+
135
+ Because metrics are precomputed and saved in repo files, site build does not need runtime access to OpenAlex, Crossref, Scimago, or Google Scholar APIs.
136
+
137
+ If deploying with GitHub Pages and `jekyll-scholar`, keep using a custom GitHub Actions build (not the restricted native Pages build).
@@ -0,0 +1,185 @@
1
+ ---
2
+ title: Use The Docker Image
3
+ description: Runtime image used by local unaltraweb workflows.
4
+ lang: en
5
+ ref: docker_image
6
+ profiles:
7
+ - unaltredocs
8
+ documentation_profiles:
9
+ - local-authors
10
+ - core-developers
11
+ section: Work Locally
12
+ weight: 140
13
+ permalink: "/docker-image/"
14
+ nav_title: Docker Image
15
+ ---
16
+ The pending distribution contract selects this eventual shared image, which is published manually from the core repository and may not exist remotely yet:
17
+
18
+ ```text
19
+ ghcr.io/dosquartsdedocs/unaltraweb:0.3.0
20
+ ```
21
+
22
+ It provides the runtime environment: Ruby, Bundler, Jekyll system dependencies, ImageMagick, Node for ExecJS and Python tooling.
23
+
24
+ The image is not the source of layouts and styles. Those come from the `unaltraweb` gem in the child site's `Gemfile`.
25
+
26
+ The GHCR package is kept because it makes the local Docker workflow cheap and repeatable. Publishing is manual. Its unprivileged `preflight` job performs package and source checks without a registry login or Docker build. A default-branch run then crosses three separate credential boundaries:
27
+
28
+ 1. `build-candidates` has package-write, attestation-write, and OIDC signing authority but never executes a candidate. It checks that the runtime, MCP, and manual PDF `sha-<full-commit>` tags are absent, builds and pushes each image exactly once under only its SHA tag, and builds MCP from the runtime build's exact digest. Each build retains BuildKit SBOM and maximum provenance and is immediately followed by a GitHub-signed SLSA build-provenance attestation for the exact repository and digest, stored with the image in GHCR.
29
+ 2. `test-candidates` has only read permissions. It authenticates to GHCR with its read-scoped token, verifies each exact digest's registry-stored attestation against repository `dosquartsdedocs/unaltraweb`, signer workflow `dosquartsdedocs/unaltraweb/.github/workflows/docker-image.yml`, and the current source commit, then pulls and checks the OCI revision labels. It explicitly logs out and destroys its dedicated Docker credential directory before candidate execution. No `GH_TOKEN` is present while it runs every `test/**/*_test.rb` file from a read-only source mount, all manual PDF integration tests, reproducibility and MCP smoke with the MCP digest, and docs with the runtime digest. Only digests that pass every gate become job outputs.
30
+ 3. `promote-candidates` regains package-write authority but never executes a candidate. It rechecks the signed attestations, SHA tags, and revision labels, then points `sha-<full-commit>`, `main`, and `latest` at the tested digests with `docker buildx imagetools create` and verifies all resulting tag digests. A failed test run therefore cannot advance broad aliases, and no image is rebuilt after testing.
31
+
32
+ GHCR does not provide this workflow with a compare-and-swap tag update. The absence check before the build and the equality checks before and after promotion reduce accidental clobbering, but a package administrator can still race those separate registry operations. The durable evidence is the signed, source-bound digest that the read-only job tested, not a claim that the SHA tag update is atomic.
33
+
34
+ A receipt-only child commit records the immutable candidate digests outside the image contents. On the exact release tag, the package-write `promote-release` job executes no candidate and performs no rebuild. It requires each receipt-derived SHA tag to resolve to the recorded digest, verifies the GitHub-signed provenance with `--source-digest` set to `receipt.source_commit`, checks the revision label against that same commit, and only then creates and verifies version aliases. The hosted runner uses the following verification shape for each digest; an OCI verification requires read authentication to GHCR:
35
+
36
+ ```bash
37
+ gh attestation verify oci://ghcr.io/dosquartsdedocs/unaltraweb@sha256:<digest> \
38
+ --bundle-from-oci \
39
+ --repo dosquartsdedocs/unaltraweb \
40
+ --signer-workflow dosquartsdedocs/unaltraweb/.github/workflows/docker-image.yml \
41
+ --source-digest <source-commit>
42
+ ```
43
+
44
+ During local core development, use the locally built image:
45
+
46
+ ```bash
47
+ docker build -t unaltraweb:dev .
48
+ make docs-serve DOCKER_IMAGE=unaltraweb:dev
49
+ ```
50
+
51
+ After the first GHCR publish, make the package public and confirm unauthenticated pulls work.
52
+
53
+ ## Computation Images
54
+
55
+ Executable manual chapters use separate images from the Jekyll runtime and PDF builder:
56
+
57
+ ```text
58
+ ghcr.io/dosquartsdedocs/unaltraweb-compute-python@sha256:18cb269811bd4005800382da25a480ec2bca7eac8d0501ad1ef36bad1c0f8cd9
59
+ ghcr.io/dosquartsdedocs/unaltraweb-compute-r@sha256:928ffb93f221e09e8b929157dee473b838e061915a2eb67224e4124b85f81837
60
+ ```
61
+
62
+ The Python image provides Quarto, Jupyter, NumPy, pandas, Matplotlib, GeoPandas, and geospatial libraries. The R image builds on `rocker/geospatial`, preserves RStudio Server, and adds Quarto, `knitr`, `rmarkdown`, `renv`, and the computation driver.
63
+
64
+ Prepare the selected images with:
65
+
66
+ ```bash
67
+ make manual-compute-image-python
68
+ make manual-compute-image-r
69
+ make manual-compute-images
70
+ ```
71
+
72
+ An image already available locally is reused. Otherwise the target pulls a selected published image or builds a configured project extension. New `unaltremanual` sites select both release workers in `.unaltraweb/computations.yml`, and `manual_computation_render` performs this preparation automatically for each engine that has discovered sources.
73
+
74
+ The factory owns the `manual-compute-*` Make targets and exposes them to child repositories through the MCP computation tools. Package-created sites keep a small build/serve Makefile instead of copying the computation implementation. Rendering and project image preparation run through the factory because they need the core scripts and Docker contracts.
75
+
76
+ Do not use host `quarto render` for publishable manual computations. Missing Jupyter packages, read-only runtime directories such as `/run/user/...`, and local socket restrictions are host-environment failures; use `manual_computation_render` instead so the selected computation image supplies Quarto/Jupyter and records provenance.
77
+
78
+ ### Select An Image
79
+
80
+ Image resolution uses this precedence:
81
+
82
+ 1. `COMPUTE_PYTHON_IMAGE` or `COMPUTE_R_IMAGE` from Make or the environment.
83
+ 2. `engines.<engine>.environments.<COMPUTE_ENV>` in `computations.yml`.
84
+ 3. A configured `local_image` with a project Dockerfile in the local environment.
85
+ 4. `engines.<engine>.image` in `computations.yml`.
86
+ 5. The corresponding core GHCR image.
87
+
88
+ `COMPUTE_ENV` defaults to `ci` when `CI` is true and to `local` otherwise. Keep environment selection in `computations.yml`:
89
+
90
+ ```yaml
91
+ engines:
92
+ python:
93
+ environments:
94
+ local: my-manual-compute-python:local
95
+ ci: ghcr.io/example/my-manual-compute-python@sha256:<digest>
96
+ ```
97
+
98
+ Use `COMPUTE_PYTHON_IMAGE` or `COMPUTE_R_IMAGE` only as an explicit one-command override. Prefer digest-pinned CI images when the remote image identity must be independently reproducible.
99
+
100
+ ### Extend An Image
101
+
102
+ Keep project-specific packages outside the core. Configure a Dockerfile and version its dependency lock:
103
+
104
+ ```yaml
105
+ engines:
106
+ python:
107
+ dockerfile: Dockerfile.compute-python
108
+ context: .
109
+ base_image: ghcr.io/dosquartsdedocs/unaltraweb-compute-python@sha256:<digest>
110
+ local_image: example-compute-python:local
111
+ lockfiles:
112
+ - requirements-compute.txt
113
+ ```
114
+
115
+ ```dockerfile
116
+ ARG BASE_IMAGE
117
+ FROM ${BASE_IMAGE}
118
+
119
+ COPY requirements-compute.txt /tmp/requirements-compute.txt
120
+ RUN python3 -m pip install --no-cache-dir -r /tmp/requirements-compute.txt
121
+ ```
122
+
123
+ The builder passes `BASE_IMAGE`, defaults the context to the project root, and builds a lowercase, Docker-safe `<project>-compute-<engine>:local` name when `local_image` is omitted. Pin the base image by digest when reproducible project-image builds matter. The Dockerfile and declared lockfiles participate in freshness checks. Extend the base image instead of copying the core renderer.
124
+
125
+ ### Figure-Only Sources
126
+
127
+ Use `unaltraweb_compute.mode: figure` when a Quarto, R, Python, or notebook source owns reusable figures but not a generated manual chapter. Declare every versioned output explicitly:
128
+
129
+ ```yaml
130
+ title: Palette reference
131
+ lang: en
132
+ ref: palette_reference
133
+ unaltraweb_compute:
134
+ engine: python
135
+ mode: figure
136
+ outputs:
137
+ - assets/img/generated/en/palette-reference.svg
138
+ ```
139
+
140
+ The renderer executes the source in the selected computation image, verifies the declared outputs exist, records their signatures in `.unaltraweb/computations.lock.json`, and marks them stale if source code, inputs, Dockerfiles, lockfiles, image identity, or output bytes change.
141
+
142
+ If a local Docker installation cannot reach package repositories through its default bridge, select another build network explicitly rather than hard-coding it in the Dockerfile:
143
+
144
+ ```bash
145
+ make manual-compute-image-r COMPUTE_DOCKER_BUILD_NETWORK=host
146
+ ```
147
+
148
+ ### Offline Execution
149
+
150
+ Source execution uses `--network none`, a read-only container root, dropped Linux capabilities, `no-new-privileges`, process/CPU/memory limits, a temporary `/tmp`, a read-write project mount, and a staging directory under `tmp/manual-computations`. Pulling or building an image can require network access, but the actual render cannot fetch remote data. The project mount means trusted source code can still modify repository files; review the working tree after execution. Prepare images and version local inputs before an offline session.
151
+
152
+ Ordinary web and PDF builds need only committed Markdown and figures. Their freshness check can run without Docker by using the image identity recorded at render time as a provenance trust anchor and validating artifact signatures. It does not resolve a mutable remote tag without network access. A locally available image takes precedence and detects a rebuilt mutable tag; use a digest-pinned image when remote identity must also be immutable.
153
+
154
+ ### RStudio Server
155
+
156
+ Start the selected R image as a loopback-only authoring environment:
157
+
158
+ ```bash
159
+ make manual-compute-rstudio
160
+ make manual-compute-rstudio RSTUDIO_PORT=8788
161
+ ```
162
+
163
+ The target prepares the image, mounts the project at `/home/rstudio/project`, maps the current user and group, and starts Rocker's `/init` with authentication disabled. Keep the `127.0.0.1` bind. RStudio is an authoring aid; publishable results must still come from `manual-compute-render` and pass `manual-compute-check`.
164
+
165
+ ### Publish To GHCR
166
+
167
+ Core maintainers publish both base images with the manual `Compute images` workflow in `.github/workflows/compute-images.yml`. Its strict, no-credentials preflight and no-push build matrix must complete before its package-write matrix can start. Candidate Python and R images carry SBOM/provenance and default-branch `main` plus full-commit `sha-*` channels; release-tag runs promote a recorded immutable digest instead of rebuilding. Consumer defaults use the digest-pinned references selected by the BOM. Packages intended for child sites must allow unauthenticated pulls.
168
+
169
+ Projects can call `.github/workflows/project-compute-image.yml` to publish their own extension package. Use a separate package name such as `example-compute-r`; do not encode project dependencies as variants of `unaltraweb-compute-r`.
170
+
171
+ The current publication workflows build `linux/amd64` images. ARM authors need Docker emulation or a separately published compatible image; image IDs recorded in the computation lock are platform-specific.
172
+
173
+ ## Web Capture Image
174
+
175
+ Selector-based screenshot authoring uses a separate Playwright image rather than adding Chromium to the Jekyll runtime:
176
+
177
+ ```text
178
+ ghcr.io/dosquartsdedocs/unaltraweb-web-capture:0.3.0
179
+ ```
180
+
181
+ The image contains pinned Playwright/Chromium, the capture worker, the Python status controller, and the core visual sources used in fingerprints. `make web-capture-image` builds the explicitly named `unaltraweb-web-capture:dev` maintainer image; set `WEB_CAPTURE_IMAGE` to that name when testing it. The manual `Web capture image` workflow publishes default-branch, commit, and semver/release tags to GHCR.
182
+
183
+ Manual PDF commands similarly consume `ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf:0.3.0` by default. `manual-pdf-image` reuses or pulls that selected image instead of rebuilding it locally. A pending release may therefore fail to pull until it is actually published. Maintainers use `make manual-pdf-image-dev` and then pass `MANUAL_PDF_IMAGE=unaltraweb-manual-pdf:dev` for local PDF runtime changes.
184
+
185
+ Rendering creates an ephemeral Docker `--internal` network shared only by Jekyll and Chromium, keeps browser requests on the preview origin, blocks service workers, popups, and WebSockets, drops Linux capabilities, uses a read-only container root and bounded resources, and writes only the declared PNG/SVG outputs under the mounted project. Ordinary checks run without browser execution or network access.