website-xp-phone 2.2.11 → 2.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.
@@ -41,8 +41,8 @@ jobs:
41
41
  - name: Verify lockfile STABLE
42
42
  run: git diff --exit-code package-lock.json
43
43
 
44
- - name: Build site
45
- run: npm run build
44
+ - name: Build site + drift manifest
45
+ run: npm run build:gated
46
46
 
47
47
  - name: Verify drift policy
48
48
  run: |
package/README.md CHANGED
@@ -56,6 +56,26 @@ Build for production:
56
56
  npm run build
57
57
  ```
58
58
 
59
+ `npm run build:local` runs the full pre-push pipeline locally — the same
60
+ checks CI ("Website CI") runs on main: lockfile STABLE, the gated build
61
+ (vite build + checksums + drift report), and the drift-policy gate, plus
62
+ lint/tests/audit. `npm run check:ci` runs just the CI-equivalent subset
63
+ (lockfile + gated build + drift policy) without the content refresh.
64
+
65
+ `npm run build` is the deploy build (Render): vite build only — no
66
+ checksums pass, no content regeneration — so host rebuilds stay cheap.
67
+ `npm run build:gated` is `build` plus the checksums/drift-report pass and
68
+ is what CI and `build:local` run. The drift-policy gate
69
+ (`npm run verify:policy`) is a pure static check of the committed drift
70
+ report, so the Render deploy runs it before installing anything and
71
+ fails fast when the uploaded build doesn't pass.
72
+
73
+ Content snapshots that mirror live services (`src/content/soundcloud.json`)
74
+ are regenerated only by `npm run refresh:soundcloud`, which runs inside
75
+ `build:local` — never by `npm run build`. Deploy-side builds (Render)
76
+ ship the committed snapshot and manifest exactly as `build:local`
77
+ produced them.
78
+
59
79
  Run linting:
60
80
 
61
81
  ```
package/build/env.ts CHANGED
@@ -15,5 +15,8 @@ export const SECURITY_HEADERS = {
15
15
  "X-Content-Type-Options": "nosniff",
16
16
  "X-Frame-Options": "SAMEORIGIN",
17
17
  "Content-Security-Policy": "frame-ancestors 'self'",
18
- "Referrer-Policy": "no-referrer",
18
+ // not "no-referrer": YouTube embeds fail with Error 153 when the player
19
+ // cannot see the embedding origin (cross-origin requests only get the
20
+ // origin under this policy, so it stays privacy-friendly).
21
+ "Referrer-Policy": "strict-origin-when-cross-origin",
19
22
  };
@@ -3,13 +3,43 @@ import path from "node:path";
3
3
  import type { Plugin } from "vite";
4
4
  import { DIST, PUBLIC } from "./env.ts";
5
5
  import { withRouteMeta } from "./meta.ts";
6
- import { loadRoutes, normalizeRoute } from "./routes.ts";
6
+ import { loadRoutes, normalizeRoute, type RouteConfig } from "./routes.ts";
7
7
  import { generateSitemap } from "./sitemap.ts";
8
8
 
9
+ /**
10
+ * dist-relative paths the skeleton generator emits for the given routes:
11
+ * one index.html per route, a `<slug>.html` sibling for static hosts
12
+ * (unless a hand-written `public/<slug>.html` wins over it), plus the
13
+ * root index.html and sitemap.xml.
14
+ *
15
+ * Exported pure so tests can assert the generated set without touching fs.
16
+ */
17
+ export function generatedPathsForRoutes(
18
+ routes: RouteConfig[],
19
+ publicSiblingExists: (slug: string) => boolean,
20
+ ): string[] {
21
+ const generated = new Set<string>(["index.html", "sitemap.xml"]);
22
+ for (const route of routes) {
23
+ const normalized = normalizeRoute(route.path);
24
+ if (normalized === "/") continue; // root index.html, already included
25
+ const slug = normalized.slice(1);
26
+ generated.add(`${slug}/index.html`);
27
+ if (!publicSiblingExists(slug)) {
28
+ generated.add(`${slug}.html`);
29
+ }
30
+ }
31
+ return [...generated].sort();
32
+ }
33
+
9
34
  /**
10
35
  * After the bundle is written, emit one index.html per route (with that
11
36
  * route's title/description meta), a `<slug>.html` sibling for static hosts,
12
37
  * and sitemap.xml. The SPA still hydrates from the same bundle.
38
+ *
39
+ * The emitted `dist/.generated.json` lists every generated path so the
40
+ * checksums drift gate (write-dist-checksums.mjs) can auto-mark
41
+ * webapp-generated artifacts as mutable instead of hand-maintaining page
42
+ * entries: any new route or project page is mutable automatically.
13
43
  */
14
44
  export function routeSkeletonsPlugin(): Plugin {
15
45
  return {
@@ -21,6 +51,8 @@ export function routeSkeletonsPlugin(): Plugin {
21
51
 
22
52
  const indexHtml = fs.readFileSync(indexPath, "utf-8");
23
53
  const routes = loadRoutes();
54
+ const publicSiblingExists = (slug: string) =>
55
+ fs.existsSync(path.join(PUBLIC, `${slug}.html`));
24
56
 
25
57
  for (const route of routes) {
26
58
  const normalized = normalizeRoute(route.path);
@@ -36,7 +68,7 @@ export function routeSkeletonsPlugin(): Plugin {
36
68
  fs.writeFileSync(path.join(DIST, slug, "index.html"), html, "utf-8");
37
69
 
38
70
  // a hand-written public/<slug>.html wins over the generated sibling
39
- if (!fs.existsSync(path.join(PUBLIC, `${slug}.html`))) {
71
+ if (!publicSiblingExists(slug)) {
40
72
  fs.writeFileSync(path.join(DIST, `${slug}.html`), html, "utf-8");
41
73
  }
42
74
  }
@@ -46,6 +78,16 @@ export function routeSkeletonsPlugin(): Plugin {
46
78
  generateSitemap(routes),
47
79
  "utf-8",
48
80
  );
81
+
82
+ fs.writeFileSync(
83
+ path.join(DIST, ".generated.json"),
84
+ `${JSON.stringify(
85
+ { generated: generatedPathsForRoutes(routes, publicSiblingExists) },
86
+ null,
87
+ 2,
88
+ )}\n`,
89
+ "utf-8",
90
+ );
49
91
  },
50
92
  };
51
93
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "website-xp-phone",
3
- "version": "2.2.11",
3
+ "version": "2.3.0",
4
4
  "license": "GPL v2",
5
5
  "author": "Kirill <kine> Nevzorov <akinevz@outlook.com>",
6
6
  "type": "module",
@@ -13,9 +13,11 @@
13
13
  "scripts": {
14
14
  "dev": "vite",
15
15
  "refresh:content": "node ./scripts/refresh-content.mjs",
16
+ "refresh:soundcloud": "node ./scripts/refresh-soundcloud.mjs",
16
17
  "render": "echo 'https://render.com/'",
17
- "build": "vite build && npm run checksums && npm run render",
18
- "build:local": "npm run refresh:content && npm run check:all && npm run build && npm run dev && git add -A && git commit",
18
+ "build": "vite build && npm run render",
19
+ "build:gated": "npm run build && npm run checksums",
20
+ "build:local": "npm run refresh:content && npm run refresh:soundcloud && npm run check:lockfile && npm run check:all && npm run build:gated && npm run verify:policy && git add -A && git commit && npm run dev",
19
21
  "build:ready": "git add -A && npm run push",
20
22
  "push": "git push origin main",
21
23
  "preview": "vite preview --host 127.0.0.1 --port 8086",
@@ -26,14 +28,14 @@
26
28
  "check:audit": "npm audit --audit-level=low",
27
29
  "check:security": "npm run lint && npm run test",
28
30
  "check:all": "npm run check:security && npm run check:audit",
31
+ "check:lockfile": "git diff --exit-code package-lock.json",
32
+ "check:ci": "npm run check:lockfile && npm run build:gated && npm run verify:policy",
29
33
  "checksums": "node ./scripts/write-dist-checksums.mjs",
30
34
  "verify:policy": "node ./scripts/verify-policy.mjs",
31
35
  "postinstall": "node ./scripts/ensure-xpcss.mjs"
32
36
  },
33
37
  "dependencies": {
34
- "eslint-plugin-react-refresh": "^0.5.7",
35
38
  "lightdni-jssas-toggle": "1.1.1",
36
- "postcss": "^8.5.24",
37
39
  "react": "^19.2.8",
38
40
  "react-dom": "^19.3.1",
39
41
  "react-markdown": "^10.1.0",
@@ -42,6 +44,7 @@
42
44
  "rehype-raw": "^7.0.0",
43
45
  "rehype-sanitize": "^6.0.0",
44
46
  "typescript-eslint": "^8.71.2",
47
+ "unist-util-visit": "^5.1.0",
45
48
  "vite": "^8.3.1"
46
49
  },
47
50
  "overrides": {
@@ -0,0 +1,8 @@
1
+ # Herbstluftwm automation!
2
+
3
+ The video shows the window manager reacting to live commands while
4
+ the agent narrates what it is doing.
5
+
6
+ Please watch:
7
+
8
+ <https://youtu.be/n_L-E8K_gcg>
@@ -1,5 +1,5 @@
1
- 7662b14af8fcf871b057630b6e7089645c0ff728aac31d8647d9caf510165f0b 404.html
2
- 7662b14af8fcf871b057630b6e7089645c0ff728aac31d8647d9caf510165f0b 404/index.html
1
+ 619ab617a4f44753f7094eb5e7d28d067a014efb404f8ab8036b5f39104791d7 404.html
2
+ 619ab617a4f44753f7094eb5e7d28d067a014efb404f8ab8036b5f39104791d7 404/index.html
3
3
  7da83c3d559cadd8e46256230136893e2ce6fe70f03a41ef2d81181d744eadda 5.html
4
4
  3b3034521c33c8fd32ae15b18e1758f4155160cf65241c2c282b407881d1f554 BAHNSCHRIFT.TTF
5
5
  d70465bbbb7a22764551a2c9fde0cc7c617618fbb41da07661b71a3598e0a25a Beep.ogg
@@ -10,9 +10,9 @@ acec8ef1b8db9f0526e7ed043c807e77784ded2cace20cee0ee66327ff129db6 Layered Networ
10
10
  f2090319a17b8426af1826047aa9fe316923998c3d8db162b70fdfbb7d73ed09 Smoll.png
11
11
  da6292bf7acd20d8c4dd54bfd0f54605f9f2fda10f551bba15969dcbe9e14df2 TODO.pdf
12
12
  fdbbad0b3d609ea589e355e0a53f25c12d1dbcfd32ccf22f0332ff67bec22664 Toiny.png
13
- 126fbba2a5a2a217d13ccc40b82f6f63fcc0c312143c189027ab9155b4f05670 addons.html
13
+ 8d4ff11c42945a1c376ac3138026357111a5c2196497bc96867cbedd0c8d9f08 addons.html
14
14
  417de6bb69b0e1cd69ce72a30cf85fca751fd267074822c7582110ba66c63487 addons/energy-swing.txt
15
- 126fbba2a5a2a217d13ccc40b82f6f63fcc0c312143c189027ab9155b4f05670 addons/index.html
15
+ 8d4ff11c42945a1c376ac3138026357111a5c2196497bc96867cbedd0c8d9f08 addons/index.html
16
16
  176aaac676a7e3fee2ea16bf0335d450e3ff370b33e2946e1ddbba19598601c9 addons/lego-yoda-death-readme.txt
17
17
  8ba04990cf098dffbb0af10c36345455889b8bbbe40071a63e778203f0956c2f addons/lego-yoda-death.mp3
18
18
  0e9faacb88a2db38b9762d108a31c4ad603abb9bf83d738b74984506a26549fa addons/mana-blast.txt
@@ -30,25 +30,24 @@ c53afc7432e19212cdc0c22c3bbfd87e2dbde6b76dd6eee560b5ddda2a1db7b8 addons/rueg-wa
30
30
  98dea05b5d5a429c6f49e92d8e4501735f96615e5e2525093ab951a7eaf45192 addons/rueg-wa-rueg.txt
31
31
  0fab27c7181385b8817de8a6ed3a547b044956af021043240d102dc8a83508bd addons/rueg-wa-shaman.txt
32
32
  0a11450902acc459dacd274070c894590339e4134ca99e210169bf201dfe3462 addons/rueg-wa-warrior.txt
33
- f4b9f4400d79673bfd2c6b4a0036983a2637b5ab9d0a15408e59864b47f7be58 addons/sidetip-0.1.19.zip
34
33
  6ce859ccf2408b5b733815e79b9446ffa8e2879d5081ede5fb9bba076ebd0b8b addons/spirit-smash.txt
35
34
  93f4825028c263e69ca4560f45ff54415fccad38c10e37ea1eefef3ab0ff3f29 assets/PerfectDOSVGA437Win-BZfDqYRn.woff2
36
35
  c71295b97f51c2f199b8f1a0ef3cc55fbe5dec6f78daee9098b4dbfe942931a8 assets/PerfectDOSVGA437Win-C4lD4zTj.woff
37
- 67ec487aadc8a9729753d325c569a505d17de8330fa88d76179594ae382e30b7 assets/index-Ctb24RtL.css
38
- 7240d24e560cd1ad1c96cd5d393acdff426ed7f600c99622aecf459b5733eff7 assets/index-z86-hiKg.js
39
- f245acfe10a0b729b5f697d0829fa43627c9d4cb772b98d5e53c6dda89bab4d3 assets/markdown-DKJpDlSZ.js
36
+ 58e0bf98992807691c5c4ff0be7cbd7156b80ca3bcfde2c210a5c848a042fe7b assets/index-8bBd-nO8.css
37
+ 3c421c13f79b17f111ac86048078523dcab8494c0e3140d74b7c2e7bb95d1b17 assets/index-D3lgn0aS.js
38
+ ac6beb6bc514d67eddb79a725d4cc7fa3055fd7709006eb0da6432dd2431ef67 assets/markdown-CuorB-jH.js
40
39
  0c69b2d91191bce88ce4ec0ad81b26f3dd106ea62eff080b30ce550f75438a6c assets/ms_sans_serif-C3pax6mQ.woff
41
40
  917afdc85e0876f9086d34392ece168b5590c97e458e6e827dee47ce56684154 assets/ms_sans_serif-Du8rjN1q.woff2
42
41
  ba32e68de906bdfc02295fe5a456a714b285772ef7b9cc8f8eae953efa72c90b assets/ms_sans_serif_bold-B8yxhAcs.woff
43
42
  277904449a3f546fb27617b68d303118f1a37e5c5e934ff25e71c68dbb26618d assets/ms_sans_serif_bold-D5dpRRHG.woff2
44
- 3f3c6d28d3b9909f32098480f2be47690daf23303c3ca63afeac1bb1b4d5fd94 assets/react-core-9sdj916r.js
43
+ 6fda42a2101ef12dba2781b5e016a505cfb3c4f5c14b13ba2e06d4d146cafa11 assets/react-core-C0IanMcB.js
45
44
  580ad8c58061a4dde99bde0a56905e382f0568516ee2f5b84dbfb52085709021 assets/rolldown-runtime-hePW80VL.js
46
- ab199bfa971b6ced175a78d6d6fa2e863f48386f7add17f26d2ea252f18b0bf6 assets/toastify-BuPt3Adk.js
47
45
  0154e6d3c50c1cfaa9b6d828b9da52b2f7a728a7e276dc2e4a751524b22ea9c0 assets/toastify-DVtug25g.css
46
+ c94165c680c279315913687161b17baa9526e7e457baefb619b750b9c3e4aba2 assets/toastify-P1CTFsTp.js
48
47
  3aa0443bd8f40482e458b937f34acbe25cf98ba8d1da2643268f639cf645bd0f assets/vendor-BOqpxYmv.js
49
48
  37eeb63788be9805d5ff1494d7e737c810d0ca98094ce2f3899b04534767618f avatar.jpg
50
49
  465b5adb81e7c1ee040e1a9842d947aea2a9df4f5d153908438745d373e8f22c avatar.png
51
- a28add7a690c99f325fa1d0a028a17f0f8e94ea5fae081f90b4fc3925740e721 blog.html
50
+ cc88189ebf1d67eff03f338758e66c3f2eee47fd69d92dfdcc500c33d2c2ecea blog.html
52
51
  57bc1a174b8e4b77b417c9f0f8841a17f40e8de9398e5c6901f997be0c1829dc blog/1st.md
53
52
  59996c7883d75c6d9d2a3f8bebdd894df7f13d234ad8fbd488152c7354b05d3c blog/2nd.md
54
53
  169fab54f1fb8596d3648dcc2c07fdc87012dca4048018d724dece997fa3033c blog/3rd.md
@@ -57,23 +56,24 @@ c798889828d3da966f7946d9c8a5814c4e3409d1d14dd5eaa4652b387cde0345 blog/5th.md
57
56
  f9d3862eb88c58f2f788758cb0c9e7a5f1bd1989c4b4b9c9c5fa8a9430e19140 blog/7.md
58
57
  237dc169931f8712f58fe1ad3a2ee626636b8e653e40f00a9d53ddd76cd3e1a6 blog/P5kKjYA.png
59
58
  380fc0b2043ea9fdc006d99578a6e2e3bc85b0bdfaec53e0c2378fb431e068d8 blog/exhausted.txt
60
- a28add7a690c99f325fa1d0a028a17f0f8e94ea5fae081f90b4fc3925740e721 blog/index.html
59
+ cc88189ebf1d67eff03f338758e66c3f2eee47fd69d92dfdcc500c33d2c2ecea blog/index.html
61
60
  9b356b02e46d302dfcd1b54f10b7e584743e2852fe4f3cd2e76189d4ce60f519 blog/pizza.gif
62
61
  9eca0cb1b767713681adbc57609216265f60638acd35f1cf44e7b155f8607ffb blog/random/branch.md
63
62
  2df79aa533ce44abafdca53fc6d47461ee9a7badf1ca930387de8bc5f7b534df blog/random/cpus.md
64
63
  10dd61b40abca4875b3722a7d11001de958822615bbd5e38fa0c2dd337409fc1 blog/random/gdiff.md
65
64
  8cfd0278521371d555607643b6d4a7b6a261077e24fbac2b232ba7474d069e87 blog/random/google.md
65
+ 4b5cafe337191479506cbc157b60ff80ae7b033256c1654117b7a82c81b4caaf blog/random/hlwm.md
66
66
  d327f052d31ca0ed0154ccba9670eb139338e955f0eb6912b036cb3d4795edf6 blog/references/NA2000_03.pdf
67
67
  006bc1b90067fcb72301755e5444664018ccfef3211a2a08c784bce23532842b blog/relevant.jpg
68
68
  1864ee7f96e2e53bc99bac537fc469004de22665f07a72abfc1535ce6d7bbc04 blog/wsl.1.md
69
69
  7450b1ef49558a9476245635ba282913a3af31c1b1e5d72053dab225d7f04b6a blog/рунисч-глоссарий.md
70
- 6ccf146d06807140207450f38ed85fc43bd0f223d3cef1003e446aa05967af4f configs.html
71
- 6ccf146d06807140207450f38ed85fc43bd0f223d3cef1003e446aa05967af4f configs/index.html
72
- 53d1fadefc98716c66c834c8a0f1d26e2f13f2fc29022e86f1373c76916b8339 contact.html
73
- 53d1fadefc98716c66c834c8a0f1d26e2f13f2fc29022e86f1373c76916b8339 contact/index.html
70
+ 6d10e0ba7c9ce13c7780cfce5b196d85640c43c135855f794b692af03b409245 configs.html
71
+ 6d10e0ba7c9ce13c7780cfce5b196d85640c43c135855f794b692af03b409245 configs/index.html
72
+ 3f2dbd827ab71d98251c53f697a437cc4daa53837c8b8d3dea97a7b17ce210df contact.html
73
+ 3f2dbd827ab71d98251c53f697a437cc4daa53837c8b8d3dea97a7b17ce210df contact/index.html
74
74
  812708d9776e7907534bda54e61169a56ee928923b53445691889d71ef213583 crunchy_kick.ogg
75
- cd505b046f1e1b59e145b9bfd44062b1e7cea68b288bffde4c5e0c617e27ce1d development.html
76
- cd505b046f1e1b59e145b9bfd44062b1e7cea68b288bffde4c5e0c617e27ce1d development/index.html
75
+ 39a0e261212af12f9bf6b1c4cfc0a5ff60371a406cf0846d3da6c14bc29e0b2f development.html
76
+ 39a0e261212af12f9bf6b1c4cfc0a5ff60371a406cf0846d3da6c14bc29e0b2f development/index.html
77
77
  bb79532b74f54410660a90d90e8db3dfa447e083d2411133ad9fddc9ded7c949 dist.7z
78
78
  9d78649ba6229bf35d63f277a95d3fc5e18ac11b948003244b4f6b8007b3b19f documents/Creating Good Code.mp4
79
79
  b952d24cf701bc4e7a7d21e1ae85c611824e80579a89836c0cb49b193446ccfe documents/Creating Good Code.mp4:Zone.Identifier
@@ -81,15 +81,15 @@ b952d24cf701bc4e7a7d21e1ae85c611824e80579a89836c0cb49b193446ccfe documents/Crea
81
81
  b952d24cf701bc4e7a7d21e1ae85c611824e80579a89836c0cb49b193446ccfe documents/Creating Good Code.pptx:Zone.Identifier
82
82
  5bad29e7ee0d18caaf16d6f123ca637e643677869b8f73e8c2ce40199a10f4a4 documents/formal/resume.pdf
83
83
  a1be4705c20f54806a754e8b7abefc907960f0905a7399bda5a6366c30c88764 documents/resume.pdf
84
- f3452b501cda04d56fb6f63fe9ee26a56bbf43e5e8399f380548bf96883d7318 doftiles.html
85
- f3452b501cda04d56fb6f63fe9ee26a56bbf43e5e8399f380548bf96883d7318 doftiles/index.html
84
+ 3d192848dad082cd1896e0133021ff2ea1d669fd2ced6a1944678e1a315672da doftiles.html
85
+ 3d192848dad082cd1896e0133021ff2ea1d669fd2ced6a1944678e1a315672da doftiles/index.html
86
86
  1250236bbf53b016f4403560cc9a404a032ffc64a754ff8aa22d9f9ce9fe5c55 favicon.ico
87
- 76ac91468bb2be2c63b649c27b2dc8fcad8663ac04916c6d9feee639fa0ff297 frontend.html
88
- 76ac91468bb2be2c63b649c27b2dc8fcad8663ac04916c6d9feee639fa0ff297 frontend/index.html
89
- 95b61896b5e8c437fbe80693902908a8a03cba9035b7c183c0db1d109e4610b7 graphbrowser.html
90
- 95b61896b5e8c437fbe80693902908a8a03cba9035b7c183c0db1d109e4610b7 graphbrowser/index.html
91
- d22b92c62c85f0126aa5a01c8e7c8c9d3e2ac7c4cd65b0a314f597aa7a061d6a herbstutil.html
92
- d22b92c62c85f0126aa5a01c8e7c8c9d3e2ac7c4cd65b0a314f597aa7a061d6a herbstutil/index.html
87
+ af2a50e25432e3d983f9a0ea7865ab45d0b7717bb06402f4f4387d39f8d0f84d frontend.html
88
+ af2a50e25432e3d983f9a0ea7865ab45d0b7717bb06402f4f4387d39f8d0f84d frontend/index.html
89
+ 0a36d524c0398d43db8a0ad72f3b605206cb87087d707fd8bbf213880b95f9ff graphbrowser.html
90
+ 0a36d524c0398d43db8a0ad72f3b605206cb87087d707fd8bbf213880b95f9ff graphbrowser/index.html
91
+ 4128ac4e7fe0d29c8e6ca47d3b5c7a3bd2bb0edef0a6cd4e9985ada4f5650702 herbstutil.html
92
+ 4128ac4e7fe0d29c8e6ca47d3b5c7a3bd2bb0edef0a6cd4e9985ada4f5650702 herbstutil/index.html
93
93
  89c6bb229c6e782bbd724c870ea05361fd56252b6003f42a62783d0dc8122b2d images/Ateric1.png
94
94
  286938df69955764f2a75a6bc0617315336e588cc5db5422a3a360e4845a2667 images/Ateric2.png
95
95
  8db9767f41cd14cb080a46fd254e8c0493ef32dbdeda2a57b2a5a4062a4a4dee images/Screenshot 2026-07-23 074101.png
@@ -109,49 +109,49 @@ bf87b6222b106d2ff310312bbe120033011233124d686ca01ca695565715e6ff images/kogg1.p
109
109
  6435136d03b1dca6176ea40012b49a9ea73a9536c926b972189a962cd1b90bb9 images/kogg2.png
110
110
  b3e19635a8088227b05bdb37e4ebf6d3e85c871b32249087bcf85e0108a43492 images/rueg1.png
111
111
  ed9b21eea7cdec55954f9af6d00bc61608d027cf4e1bc6182090ad051913e224 images/rueg2.png
112
- bfcb7a2711bbea82997eff84df3d95281170a174c03995ba1b33c24aa221e20f index.html
113
- ae11306e9b2ecacdc2d84b21983d60bec5abc2cd08df13367e260a46140082fd lightdni-jssas-toggle.html
114
- ae11306e9b2ecacdc2d84b21983d60bec5abc2cd08df13367e260a46140082fd lightdni-jssas-toggle/index.html
112
+ 960932bfbb0ff2b7ab13fc19f4c44a1d2458814d1c829a42ede2dfb8e2c87a56 index.html
113
+ 5d7f4fd6fffbf5b2ff8a88fbb5148e5e8161954c056d2dc300cac0f48ecb4cd6 lightdni-jssas-toggle.html
114
+ 5d7f4fd6fffbf5b2ff8a88fbb5148e5e8161954c056d2dc300cac0f48ecb4cd6 lightdni-jssas-toggle/index.html
115
115
  929d1233a6e6a2d7580219d2ec78752fc4b1540fe181031efe9557dee099c314 loading.css
116
116
  825c84d88cba6ff7fdaa324946c134ab3161007d0a63a3c5906ff381c49b2f7e lol.jpg
117
117
  2a1670273af4da1a966e557b6fbdce11c4e50e4488ddcfda465613871b52906b medium.png
118
- 0b1fa6c4f8bb38ea05ad9344fba4cc1b35b0026a58d076ca79d5b30ce18fff77 music.html
119
- 0b1fa6c4f8bb38ea05ad9344fba4cc1b35b0026a58d076ca79d5b30ce18fff77 music/index.html
120
- 01b214d29d69b29bf692b2eec5c4ce22dd5e3821b1c5c055211895aa5794158b pagerts.html
121
- 01b214d29d69b29bf692b2eec5c4ce22dd5e3821b1c5c055211895aa5794158b pagerts/index.html
122
- 65582b94bf1163b6dba16821541decc32de21702fb4f7a6f3b7cfd0a978d0921 projects.html
123
- bdc3d3af85b3d8ee911ad5494fbba38bad430ced39bafea1bfdc55f34158684e projects/development.html
124
- bdc3d3af85b3d8ee911ad5494fbba38bad430ced39bafea1bfdc55f34158684e projects/development/index.html
125
- bc4a581cc7112faa69897c4997948230a6bd83709afbd600a0782c0a06e805e6 projects/doftiles.html
126
- bc4a581cc7112faa69897c4997948230a6bd83709afbd600a0782c0a06e805e6 projects/doftiles/index.html
127
- 3f8a3b87852029d6e385450683675c7ffa403f95b4cfdd00c48fd6e7845d079d projects/frontend.html
128
- 3f8a3b87852029d6e385450683675c7ffa403f95b4cfdd00c48fd6e7845d079d projects/frontend/index.html
129
- 6511326cb73e65deeab431869c72131f7f59a7ae4e4cc0001ab95fd8c8bd27ee projects/graphbrowser.html
130
- 6511326cb73e65deeab431869c72131f7f59a7ae4e4cc0001ab95fd8c8bd27ee projects/graphbrowser/index.html
131
- b93fef40de659726300968832e6fa9abfa8d988743541f8195f0806fc4bb9c86 projects/herbstutil.html
132
- b93fef40de659726300968832e6fa9abfa8d988743541f8195f0806fc4bb9c86 projects/herbstutil/index.html
133
- 65582b94bf1163b6dba16821541decc32de21702fb4f7a6f3b7cfd0a978d0921 projects/index.html
134
- c722325e5455d0454a006fe8ea1e55688970aa668d6a7560133e69d05ab63796 projects/lightdni-jssas-toggle.html
135
- c722325e5455d0454a006fe8ea1e55688970aa668d6a7560133e69d05ab63796 projects/lightdni-jssas-toggle/index.html
136
- 33260f113b262f2bb880967513029a06e56c70543868cd869e28818269b62021 projects/pagerts.html
137
- 33260f113b262f2bb880967513029a06e56c70543868cd869e28818269b62021 projects/pagerts/index.html
138
- 78899ad4eb4221ab2c40c694d28d88b86c7f42ba70fa341741b4477fe7c86f4e projects/rarebert.html
139
- 78899ad4eb4221ab2c40c694d28d88b86c7f42ba70fa341741b4477fe7c86f4e projects/rarebert/index.html
140
- cf4ca218774fdc53f889b39c3dfdb9d9738e89756764f94773966aea4990b1be projects/webuser.html
141
- cf4ca218774fdc53f889b39c3dfdb9d9738e89756764f94773966aea4990b1be projects/webuser/index.html
142
- 06d33a9d87552f75086504e00aa4162ecd822f9e4d8cf0feadf023f8603e777f rarebert.html
143
- 06d33a9d87552f75086504e00aa4162ecd822f9e4d8cf0feadf023f8603e777f rarebert/index.html
118
+ 2d7b9a6b1e974e96dce2e6fc654d76f929d3f2b6581356fa2437074d44c3d461 music.html
119
+ 2d7b9a6b1e974e96dce2e6fc654d76f929d3f2b6581356fa2437074d44c3d461 music/index.html
120
+ 49eda91dc720c383dcdb1a906d8abbe6690afefbcd03808eebbd16635deeea28 pagerts.html
121
+ 49eda91dc720c383dcdb1a906d8abbe6690afefbcd03808eebbd16635deeea28 pagerts/index.html
122
+ d8845a1ff2d68ab27d83a8f85318496a69151d2f12593e1e8a225f97783008e0 projects.html
123
+ c8dc54c86b2ffc21ba2bbaa1a16675efd8261f36ffc02343b787efbefd9b4b36 projects/development.html
124
+ c8dc54c86b2ffc21ba2bbaa1a16675efd8261f36ffc02343b787efbefd9b4b36 projects/development/index.html
125
+ eb3e3b79699937979b58db9b39fee7622f1d5d80e37fcf938f0b859e742519a4 projects/doftiles.html
126
+ eb3e3b79699937979b58db9b39fee7622f1d5d80e37fcf938f0b859e742519a4 projects/doftiles/index.html
127
+ 6d2dc8cc0f7c01063e07eaea5f7eab95a478394258d2a13dfbc4135bcde5575b projects/frontend.html
128
+ 6d2dc8cc0f7c01063e07eaea5f7eab95a478394258d2a13dfbc4135bcde5575b projects/frontend/index.html
129
+ 0207adb46488deafd54cc9d03461301c9911876dc15029d77733e334f1954cb4 projects/graphbrowser.html
130
+ 0207adb46488deafd54cc9d03461301c9911876dc15029d77733e334f1954cb4 projects/graphbrowser/index.html
131
+ 077be061cc7c60e9dac044f7eef28e38e7c86d4f819d881c38abec183275b36e projects/herbstutil.html
132
+ 077be061cc7c60e9dac044f7eef28e38e7c86d4f819d881c38abec183275b36e projects/herbstutil/index.html
133
+ d8845a1ff2d68ab27d83a8f85318496a69151d2f12593e1e8a225f97783008e0 projects/index.html
134
+ ad7bcb48b4bbd2b701d37f09dd6a22a09ddb80ef22dd1fe42407615c92ac04d3 projects/lightdni-jssas-toggle.html
135
+ ad7bcb48b4bbd2b701d37f09dd6a22a09ddb80ef22dd1fe42407615c92ac04d3 projects/lightdni-jssas-toggle/index.html
136
+ 3cc577edf4e57b0efbf7e61d9e6f7263349b6bd9bde2f4c04676b5a5574ffb53 projects/pagerts.html
137
+ 3cc577edf4e57b0efbf7e61d9e6f7263349b6bd9bde2f4c04676b5a5574ffb53 projects/pagerts/index.html
138
+ bfd570f132e3267cfe5d841c1920c9b6efdb2684a2b76e4d5122d0128b0ddbc0 projects/rarebert.html
139
+ bfd570f132e3267cfe5d841c1920c9b6efdb2684a2b76e4d5122d0128b0ddbc0 projects/rarebert/index.html
140
+ 123d46f358665d9fea64d28ce22f196eac273666b7d6f92ecf76a955c2460a2a projects/webuser.html
141
+ 123d46f358665d9fea64d28ce22f196eac273666b7d6f92ecf76a955c2460a2a projects/webuser/index.html
142
+ 90e3784c8674ecebe775715fc724725097c5cc75189babdb3a8e57ad3d2bc945 rarebert.html
143
+ 90e3784c8674ecebe775715fc724725097c5cc75189babdb3a8e57ad3d2bc945 rarebert/index.html
144
144
  a08e74f98aea8781ea9711986758a690a3ee10d14d1d799a10411862477cfbda resume.html
145
- e98c002cc7e8daa9c372f931db27ecfde61b32b1ba267572ea9533d29e0a1615 resume/index.html
145
+ e94ff30ead17d66687ec91b092b33a68bc2bb19a32e623fa90b9d62a38643d20 resume/index.html
146
146
  9e335bff121283bade7005bff78316104846ea5e99e7e2f594fac9fddf39c455 robots.txt
147
- 5f7d9a20d2099fd22b2ba80cdb3d6d751f67bd3c3edd2978980307ff50f149e4 sitemap.html
148
- ceebe239b132b89ac99d679595c6fc7a2bbf7186023e5b8ea34143f2c8efdb40 sitemap.xml
149
- 5f7d9a20d2099fd22b2ba80cdb3d6d751f67bd3c3edd2978980307ff50f149e4 sitemap/index.html
147
+ 7636b13dfcca6672fdc3e34073f67e9458ecf30c95ae42c725108a49ccd6f3a0 sitemap.html
148
+ 5103abe4d34be71d8247e9bbb713a052d8301b1c61ff09013b0914ac4d89a1cb sitemap.xml
149
+ 7636b13dfcca6672fdc3e34073f67e9458ecf30c95ae42c725108a49ccd6f3a0 sitemap/index.html
150
150
  fc6ff550d5c7fbd55537560ef0d5470bc68f74b2f41b6386d78b149e897b033c spinner.svg
151
151
  873d500bd694a9e637f93d79238270dbb00016e38fa87fe05a87fb76fe464543 stories/1.md
152
152
  e58ca0ef8466ec1d0b0a0e71c4c1f1b620a8d30285df4a8d9e1b243654f0cd6e tada.wav
153
- 4a8f9ce2b89b3e40b243d8c4d078be097097e0ed036c782cd72cb3c5448e54d0 webuser.html
154
- 4a8f9ce2b89b3e40b243d8c4d078be097097e0ed036c782cd72cb3c5448e54d0 webuser/index.html
155
- c714f057b4a99503d890e929a396bc3bb3f66b60dda796c8216188f5efa92498 wow.html
156
- c714f057b4a99503d890e929a396bc3bb3f66b60dda796c8216188f5efa92498 wow/index.html
153
+ 89db00464dd25c283b9745dfaf3d4b7a03fa9811cd849ddd47522649a7ceaa8d webuser.html
154
+ 89db00464dd25c283b9745dfaf3d4b7a03fa9811cd849ddd47522649a7ceaa8d webuser/index.html
155
+ 1c5581d03ea6cdff7669f3595298cba08dbf7af70149df34e274ef5ac15552d1 wow.html
156
+ 1c5581d03ea6cdff7669f3595298cba08dbf7af70149df34e274ef5ac15552d1 wow/index.html
157
157
  da5cb674a690cb58ae78f63c2162ed18ee5daf7576d05c57930f000e9df48194 yooh.mp3
@@ -1,39 +1,26 @@
1
1
  {
2
2
  "baselineUrl": "https://akinevz.com/checksums.txt",
3
- "generatedAt": "2026-10-23T21:21:29.982Z",
3
+ "generatedAt": "2026-10-24T11:56:28.486Z",
4
4
  "mutablePaths": [
5
- "index.html",
5
+ "blog/",
6
+ "stories/",
7
+ "dist.7z",
8
+ "documents/drift-report.json",
9
+ "checksums.txt",
10
+ "assets/*.js",
11
+ "assets/*.css"
12
+ ],
13
+ "generatedPaths": [
6
14
  "404.html",
7
15
  "404/index.html",
8
16
  "addons.html",
9
17
  "addons/index.html",
10
18
  "blog.html",
11
19
  "blog/index.html",
12
- "contact.html",
13
- "contact/index.html",
14
- "music.html",
15
- "music/index.html",
16
- "resume/index.html",
17
- "sitemap.xml",
18
- "sitemap.html",
19
- "sitemap/index.html",
20
- "wow.html",
21
- "wow/index.html",
22
- "pagerts.html",
23
- "pagerts/index.html",
24
- "projects.html",
25
- "projects/index.html",
26
- "blog/",
27
- "stories/",
28
- "checksums.txt",
29
- "assets/*.js"
30
- ],
31
- "violationCount": 0,
32
- "violations": [],
33
- "rehashOnlyCount": 36,
34
- "rehashOnly": [
35
20
  "configs.html",
36
21
  "configs/index.html",
22
+ "contact.html",
23
+ "contact/index.html",
37
24
  "development.html",
38
25
  "development/index.html",
39
26
  "doftiles.html",
@@ -44,8 +31,14 @@
44
31
  "graphbrowser/index.html",
45
32
  "herbstutil.html",
46
33
  "herbstutil/index.html",
34
+ "index.html",
47
35
  "lightdni-jssas-toggle.html",
48
36
  "lightdni-jssas-toggle/index.html",
37
+ "music.html",
38
+ "music/index.html",
39
+ "pagerts.html",
40
+ "pagerts/index.html",
41
+ "projects.html",
49
42
  "projects/development.html",
50
43
  "projects/development/index.html",
51
44
  "projects/doftiles.html",
@@ -56,6 +49,7 @@
56
49
  "projects/graphbrowser/index.html",
57
50
  "projects/herbstutil.html",
58
51
  "projects/herbstutil/index.html",
52
+ "projects/index.html",
59
53
  "projects/lightdni-jssas-toggle.html",
60
54
  "projects/lightdni-jssas-toggle/index.html",
61
55
  "projects/pagerts.html",
@@ -66,9 +60,19 @@
66
60
  "projects/webuser/index.html",
67
61
  "rarebert.html",
68
62
  "rarebert/index.html",
63
+ "resume/index.html",
64
+ "sitemap.html",
65
+ "sitemap.xml",
66
+ "sitemap/index.html",
69
67
  "webuser.html",
70
- "webuser/index.html"
68
+ "webuser/index.html",
69
+ "wow.html",
70
+ "wow/index.html"
71
71
  ],
72
+ "violationCount": 0,
73
+ "violations": [],
74
+ "rehashOnlyCount": 0,
75
+ "rehashOnly": [],
72
76
  "liveMatchCount": 0,
73
77
  "liveMatched": []
74
78
  }
package/render.yaml CHANGED
@@ -5,7 +5,17 @@ services:
5
5
  envVars:
6
6
  - key: NODE_VERSION
7
7
  value: 22.22.1
8
- buildCommand: git submodule update --init --recursive && npm install && npm --prefix xp.css install --no-audit --no-fund && npm --prefix xp.css run build && npm run build
8
+ # Deploy builds are deliberately cheap and side-effect-free:
9
+ # - no content regeneration — committed snapshots (soundcloud.json et
10
+ # al.) ship exactly as build:local produced and committed them;
11
+ # - no checksums/drift pipeline — the committed manifest + drift
12
+ # report (public/, copied into dist/ by vite) are served as-is; the
13
+ # live-baseline pipeline re-runs where it belongs (CI, build:local).
14
+ # The static gate below fails the deploy before ANY install/build
15
+ # compute when the uploaded build's drift report is missing, corrupt,
16
+ # or reports unresolved violations (verify-policy.mjs needs no
17
+ # node_modules — node builtins only).
18
+ buildCommand: git submodule update --init --recursive && npm run verify:policy && npm install && npm --prefix xp.css install --no-audit --no-fund && npm --prefix xp.css run build && npm run build
9
19
  staticPublishPath: ./dist
10
20
  routes:
11
21
  - type: redirect
@@ -13,6 +13,13 @@
13
13
  * stable entry is a silent drift regression — the unsafe failure
14
14
  * mode for a drift detector.
15
15
  *
16
+ * Pages generated by the webapp are NOT listed here: the build itself
17
+ * declares them in `dist/.generated.json` (emitted by
18
+ * routeSkeletonsPlugin — one entry per generated page, including future
19
+ * routes and project pages), and write-dist-checksums.mjs auto-marks
20
+ * every listed path as mutable. Only copied/refresh-varying artifacts
21
+ * (content subtrees, LFS blobs, self-generated sidecars) are listed.
22
+ *
16
23
  * `checksums.txt` itself is excluded from the manifest (see
17
24
  * write-dist-checksums.mjs), so it does not need to appear here. It is
18
25
  * listed for documentation completeness and to guard against it ever
@@ -21,28 +28,6 @@
21
28
  * Paths are relative to `dist/` and use forward slashes.
22
29
  */
23
30
  export const MUTABLE_PATHS = Object.freeze([
24
- "index.html",
25
- "404.html",
26
- "404/index.html",
27
- "addons.html",
28
- "addons/index.html",
29
- "blog.html",
30
- "blog/index.html",
31
- "contact.html",
32
- "contact/index.html",
33
- "music.html",
34
- "music/index.html",
35
- "resume/index.html",
36
- "sitemap.xml",
37
- "sitemap.html",
38
- "sitemap/index.html",
39
- "wow.html",
40
- "wow/index.html",
41
- // new pages - allowed as NEW until baseline is updated
42
- "pagerts.html",
43
- "pagerts/index.html",
44
- "projects.html",
45
- "projects/index.html",
46
31
  // Blog post content: posts (.md), attachments, and embedded documents
47
32
  // are authored content. Publishing a new post or editing an existing
48
33
  // one is a legitimate content change, never STABLE-invariant drift,
@@ -50,8 +35,21 @@ export const MUTABLE_PATHS = Object.freeze([
50
35
  // documents embedded into posts via blog.json.
51
36
  "blog/",
52
37
  "stories/",
38
+ // Git-LFS artifact: CI checkouts that do not smudge LFS see the pointer
39
+ // bytes, so its digest depends on the checkout environment — and the
40
+ // archive itself legitimately changes. Never a STABLE invariant.
41
+ "dist.7z",
42
+ // Self-referential sidecar: write-dist-checksums.mjs rewrites it on
43
+ // every build (generatedAt, violation counts), so it changes each run.
44
+ "documents/drift-report.json",
53
45
  "checksums.txt",
46
+ // Vite-emitted bundles: content-hashed names, and chunk hashing/module
47
+ // ordering can legitimately vary between rebuilds of identical inputs
48
+ // ("rebuild noise"). Covers every chunk vite emits under assets/
49
+ // (index-*.css, toastify-*.css, *.js). Hand-copied public/ files land
50
+ // at the dist ROOT, never in assets/, so they stay STABLE.
54
51
  "assets/*.js",
52
+ "assets/*.css",
55
53
  ]);
56
54
 
57
55
  export const MUTABLE_PATH_SET = Object.freeze(new Set(MUTABLE_PATHS));