diff --git a/site/assets/css/default.css b/site/assets/css/default.css
index b95be3b..4f6b6f8 100644
--- a/site/assets/css/default.css
+++ b/site/assets/css/default.css
@@ -171,7 +171,7 @@ html, body {
@apply wrap-anywhere;
}
- &:not(:has(> code:only-child)) {
+ &:not(:has(> code:only-child)):not(:has(> img)) {
@apply px-1;
&:not(.font-mono) {
@@ -230,8 +230,8 @@ html, body {
code:not(pre > code) {
@apply border-1 border-dotted px-2 py-0.5 border-black dark:border-white;
- a:hover &:not(:is(h1, h2, h3, h4, h5, h6) *),
- a:active &:not(:is(h1, h2, h3, h4, h5, h6) *) {
+ a:hover &:not(:only-child, :is(h1, h2, h3, h4, h5, h6) *),
+ a:active &:not(:only-child, :is(h1, h2, h3, h4, h5, h6) *) {
@apply border-transparent;
}
}
@@ -252,9 +252,7 @@ html, body {
}
& li::before {
- @apply pr-1;
-
- content: "[" counter(item) "]";
+ content: counter(item) ". ";
}
}
diff --git a/site/assets/images/cpu-dumb.webp b/site/assets/images/cpu-dumb.webp
new file mode 100644
index 0000000..44e37f1
Binary files /dev/null and b/site/assets/images/cpu-dumb.webp differ
diff --git a/site/blog/test.md b/site/blog/2024-01-01-test.md
similarity index 99%
rename from site/blog/test.md
rename to site/blog/2024-01-01-test.md
index 2b9257e..abb6da3 100644
--- a/site/blog/test.md
+++ b/site/blog/2024-01-01-test.md
@@ -1,7 +1,7 @@
---
-date: 2024-01-01
title: Test
description: "Testing"
+
draft: true
---
diff --git a/site/blog/htmnix.md b/site/blog/2024-03-04-htmnix.md
similarity index 99%
rename from site/blog/htmnix.md
rename to site/blog/2024-03-04-htmnix.md
index eb6d0ff..847b0ec 100644
--- a/site/blog/htmnix.md
+++ b/site/blog/2024-03-04-htmnix.md
@@ -2,8 +2,6 @@
title: HTMNIX
description: How the absolutely cursed HTMNIX project works.
-date: 2024-03-04
-
keywords:
- html
- nix
diff --git a/site/blog/cosmic-drift.md b/site/blog/2024-04-02-cosmic-drift.md
similarity index 99%
rename from site/blog/cosmic-drift.md
rename to site/blog/2024-04-02-cosmic-drift.md
index 9f6dab4..862d7cb 100644
--- a/site/blog/cosmic-drift.md
+++ b/site/blog/2024-04-02-cosmic-drift.md
@@ -2,8 +2,6 @@
title: Cosmic Drift
description: Or how I missed the school bus because of a cosmic ray.
-date: 2024-04-02
-
keywords:
- time
- unix-timestamps
diff --git a/site/blog/nix-iceberg.md b/site/blog/2024-04-15-nix-iceberg.md
similarity index 79%
rename from site/blog/nix-iceberg.md
rename to site/blog/2024-04-15-nix-iceberg.md
index 847b205..59218c4 100644
--- a/site/blog/nix-iceberg.md
+++ b/site/blog/2024-04-15-nix-iceberg.md
@@ -2,7 +2,6 @@
title: Explaining the Nix iceberg
description: And revealing how cursed Nix is.
-date: 2024-04-15
draft: true
keywords:
@@ -16,12 +15,10 @@ it a reputation of being arcane and hard to use.
I'll be explaining the contents of the following iceberg chart, which includes
some truly arcane examples of Nix code.
-Some knowledge of Nix is required, you may get confused in the terminology if
-you've never used it.
+Some knowledge of Nix is required, you may get confused with the terminology if
+you've never used Nix.
-
-
-[Here's the original source for this image, on cohost.](https://cohost.org/leftpaddotpy/post/3885451-the-nix-iceberg)
+[](https://cohost.org/leftpaddotpy/post/3885451-the-nix-iceberg)
Let's start:
@@ -54,7 +51,7 @@ So, what are we doing in this snippet?
2. Creating a derivation that runs an echo command, which writes a Nix
expression to the output file.
3. Then we import the output file, forcing the derivation to be realized as we
- accessed the contents of it.
+ just accessed the contents of it.
> Wait, what does _realization_ mean?
@@ -519,14 +516,14 @@ known.
# Tier 3: `assigned nix hacker at employment`
-
+
```sh
#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p python3
```
-
+
_(taken verbatim from `man nix-shell`)_
@@ -565,7 +562,16 @@ print t
## `--accept-flake-config` more like `--pwn-me-mommy`
-TODO
+The
+[`accept-flake-config`](https://nix.dev/manual/nix/2.29/command-ref/conf-file#conf-accept-flake-config)
+Nix configuration variable or `--accept-flake-config` flag in Nix commands
+allows Nix to unconditionally accept flake `nixConfig`'s.
+
+This is dangerous, because this can enable `builtins.importNative` by enabling
+the
+[`allow-unsafe-native-code-during-evaluation`](https://nix.dev/manual/nix/2.29/command-ref/conf-file#conf-allow-unsafe-native-code-during-evaluation)
+option, which then allows Nix expresions to load arbitrary dynamic libraries,
+which can do anything as they are not confined to the Nix evaluation sandbox.
## Zilch
@@ -717,8 +723,7 @@ But if two attribute sets that are compared have the same memory location, Nix
ignores this and does a pointer comparison, totally ignoring all members. This
is a hack.
-[Link to code that does this.](https://github.com/NixOS/nix/blob/aa165301d1ae3b306319a6a834dc1d4e340a7112/src/libexpr/eval.cc#L2525-L2528)
-Here's the snippet:
+[Here's the snippet:](https://github.com/NixOS/nix/blob/aa165301d1ae3b306319a6a834dc1d4e340a7112/src/libexpr/eval.cc#L2525-L2528)
```cpp
bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_view errorCtx)
@@ -739,7 +744,7 @@ want with this information.
As surprising as it sounds, Nix does indeed supports plugins. You can load
plugins using the
-[`plugin-files`](https://nix.dev/manual/nix/2.22/command-ref/conf-file#conf-plugin-files)
+[`plugin-files`](https://nix.dev/manual/nix/2.29/command-ref/conf-file.html#conf-plugin-files)
configuration option.
From the configuration reference:
@@ -771,7 +776,7 @@ Some example plugins are [`nix-doc`](https://github.com/lf-/nix-doc) and
## `/bin/sh` and sandbox impurity
By setting the
-[`sandbox-paths`](https://nix.dev/manual/nix/2.22/command-ref/conf-file#conf-sandbox-paths)
+[`sandbox-paths`](https://nix.dev/manual/nix/2.29/command-ref/conf-file#conf-sandbox-paths)
option to `/bin/sh=/bin/sh`, Nix will bind the `/bin/sh` path in the build
sandbox (left) to the `/bin/sh` path in the host (right). This is of course
impure, but is useful for bootstrapping from absolute scratch without copying
@@ -779,10 +784,11 @@ impure binaries to the Nix store.
## `rec { a = 5; b = a + 1; __overrides.a = 6; }`
-There is a special field named `__overrides` in recursive attrset expressions,
-which simply overrides the parent attribute set with the keys inside it. This is
-different from the update operator (`//`) because that will not override the
-self-references in the recursive attribute set.
+There is a special field named `__overrides` in keyed expressions (attribute
+sets, `let-in`'s and as secret third thing), which simply overrides the parent
+attribute set with the keys inside it. This is different from the update
+operator (`//`) because that will not override the self-references in the
+recursive attribute set.
`rec { a = 5; b = a + 1; __overrides.a = 6; }.b` will evaluate to 7, while
`(rec { a = 5; b = a + 1; } // { a = 6; }).b` will evaluate to 6.
@@ -814,7 +820,58 @@ TODO
## `let a = _: -1; or = 6; in [ a or 9 ]`
-TODO
+The Nix parser is weird.
+
+Normally, `or` is used for attribute path selection defaults:
+
+```nix
+{ foo = 123; }.not-here.not-here-either or 123
+```
+
+That above evaluates to `123`.
+
+But when parsing an expression that is not an attribute-select, `or` is treated
+as an identifier. This means that in the following `let-in`, we are passing `or`
+to `a`.
+
+```nix
+let
+ a = _: -1;
+ or = 6;
+in a or
+```
+
+But there is another piece of weirdness. Function applications that use the
+literal `or` have higher precedence than the spaces when parsing lists, so these
+two codeblocks are not equivalent:
+
+```nix
+let
+ a = _: -1;
+ or = 6;
+in [ a or ]
+```
+
+> This evaluates to `[ -1 ]`
+
+```nix
+let
+ a = _: -1;
+ foo = 6;
+in [ a foo ]
+```
+
+> This evaluates to `[ 6 ]`
+
+However, this behaviour might get removed in the future. But currently, in the
+Nix version that I am using which is `2.28.3`, it prints this warning instead:
+
+```text
+warning: at «string»:4:6: This expression uses `or` as an identifier in a way that will change in a future Nix release.
+Wrap this entire expression in parentheses to preserve its current meaning:
+ (a or)
+Give feedback at https://github.com/NixOS/nix/pull/11121
+```
## eelco's home address is in nixpkgs
@@ -822,16 +879,25 @@ TODO
## `restrict-eval`
-TODO
+[From the Nix manual:](https://nix.dev/manual/nix/2.29/command-ref/conf-file.html?highlight=restrict-eval#conf-restrict-eval)
+
+> If set to true, the Nix evaluator will not allow access to any files outside
+> of `builtins.nixPath`, or to URIs outside of `allowed-uris`.
## nix2
## `__noChroot`
-TODO
+When the
+[`sandbox`](https://nix.dev/manual/nix/2.29/command-ref/conf-file.html?highlight=__nos#conf-sandbox)
+Nix configuration value is set to `relaxed`, fixed-output derivations (FODs)
+that have the `__noChroot` attribute set to `true` will not run in the Nix
+sandbox.
## cloud scale hydra
+TODO
+
## `(_:_) != (_:_)` but `(a:a) == (a:a)`
Evaluating `(_:_) == (_:_)`, we see that it is `false`, which means the two
@@ -855,3 +921,149 @@ TODO
This is the legacy `let` syntax. Equivalent to `let huh = "?"; in huh`.
## Tier 6: `has meowed before`
+
+### `let { body = 1; __overrides.body = 2; }`
+
+This is a combination of [`__override`](#rec-a-5-b-a-1-overridesa-6-) for keyed
+experessions and the [`legacy let syntax`](#let-huh-body-huh-).
+
+### function identity is load bearing on importing nixpkgs
+
+Since
+[attribute sets with function members compare function identities (memory locations)](#let-f-a-a-s-ff-in-f-f-s-s),
+comparing any attribute set that contains a function is load-bearing on the
+function's identity.
+
+The way this affects importing nixpkgs is that nixpkgs internally compares
+stdenvs, which contain functions, to determine whether if we are
+cross-compiling.nixpkgs internally compares stdenvs, which contain functions, to
+determine whether if we are cross-compiling.
+
+Therefore, function identity really **is** load bearing on importing nixpkgs.
+
+### `import `
+
+This looks like we are importing , and getting the `fetchurl.nix` file in
+it.
+
+Let's see if that is true:
+
+```nix
+nix-repl> builtins.readDir
+{
+ ".clang-format" = "regular";
+ ".clang-tidy" = "regular";
+ ".dir-locals.el" = "regular";
+ ".editorconfig" = "regular";
+ ".github" = "directory";
+ ".gitignore" = "regular";
+ ".mergify.yml" = "regular";
+ ".shellcheckrc" = "regular";
+ ".version" = "regular";
+ ".version-determinate" = "regular";
+ "CITATION.cff" = "regular";
+ "CONTRIBUTING.md" = "regular";
+ COPYING = "regular";
+ "HACKING.md" = "symlink";
+ "README.md" = "regular";
+ contrib = "directory";
+ doc = "directory";
+ "docker.nix" = "regular";
+ "flake.lock" = "regular";
+ "flake.nix" = "regular";
+ maintainers = "directory";
+ "meson.build" = "regular";
+ "meson.options" = "regular";
+ misc = "directory";
+ nix-meson-build-support = "directory";
+ packaging = "directory";
+ "precompiled-headers.h" = "regular";
+ scripts = "directory";
+ src = "directory";
+ tests = "directory";
+}
+```
+
+There doesn't seem to be a `fetchurl.nix` file here.
+
+This is because
+[`` actually falls back to `corepkgs`](https://github.com/NixOS/nix/blob/2afc84fddf463b22196aeb70587bc0c9259e330f/src/libexpr/eval.cc#L3117-L3118),
+which is a Nix path
+[defined inside Nix itself.](https://github.com/NixOS/nix/blob/2afc84fddf463b22196aeb70587bc0c9259e330f/src/libexpr/eval.cc#L321)
+
+[Later, the `fetchurl.nix` path is defined in `corepkgs`](https://github.com/NixOS/nix/blob/2afc84fddf463b22196aeb70587bc0c9259e330f/src/libexpr/eval.cc#L363)
+and its contents are set to a
+[generated C++ header.](https://github.com/NixOS/nix/blob/2afc84fddf463b22196aeb70587bc0c9259e330f/src/libexpr/meson.build#L129-L135)
+
+You do not need to be in impure evaluation mode to use `corepkgs`, aka
+``.
+
+### test suite of nix wasn't run
+
+TODO
+
+### fixed-output derivation sandboxing
+
+TODO
+
+### `importNative`
+
+[`builtins.importNative`](https://nix.dev/manual/nix/2.29/command-ref/conf-file.html#conf-allow-unsafe-native-code-during-evaluation)
+allows Nix expressions to import arbitrary dynamic libraries to produce Nix
+expressions.
+
+Of course, this is turned off by default as it is a security risk. You probably
+shouldn't use this.
+
+### `chromium recompressTarball`
+
+TODO
+
+### more than 1 million chars of indents breaks things
+
+The weird Nix parser
+[hard codes `1000000`](https://github.com/NixOS/nix/blob/2afc84fddf463b22196aeb70587bc0c9259e330f/src/libexpr/include/nix/expr/parser-state.hh#L250)
+instead of `SIZE_MAX` when determining the minimum indent to strip in strings
+spanning multiple lines.
+
+So when you have a line with more than a million spaces for the indent, it is
+ignored and not included in the minimum indent calculation.
+
+## Tier 7: `wears animal ears to NixCon`
+
+
+
+```nix
+nix-repl> builtins.fromJSON ''{"uwu\u0000": 1, "uwu": 2}''
+{ uwu = 2; "uwu" = 1; }
+```
+
+
+
+TODO
+
+## `(_: builtins.break _)`
+
+TODO
+
+## multiplayer tic-tac-toe in nix repl
+
+TODO
+
+## `let e="e"; in [001.2e01e.30.4]`
+
+TODO
+
+## `/__corepkgs__/`
+
+[Already explained previously.](#import-nixfetchurlnix)
+
+## `some-expr`
+
+TODO
+
+## `__darwinAllowLocalNetworking`
+
+TODO
+
+## `builtins.derivationStrict`
diff --git a/site/blog/swap-i.md b/site/blog/2024-05-20-swap-i.md
similarity index 99%
rename from site/blog/swap-i.md
rename to site/blog/2024-05-20-swap-i.md
index 4f27fa3..7d3522b 100644
--- a/site/blog/swap-i.md
+++ b/site/blog/2024-05-20-swap-i.md
@@ -2,8 +2,6 @@
title: Swap the `ı` and `i` key on your keyboard for faster modal editing
description: How to swap the ı and i key on your Turkish keyboard on Linux.
-date: 2024-05-20
-
keywords:
- localisation
- modal-editors
diff --git a/site/blog/gitignore.md b/site/blog/2024-09-30-gitignore.md
similarity index 99%
rename from site/blog/gitignore.md
rename to site/blog/2024-09-30-gitignore.md
index 27a507d..65ea639 100644
--- a/site/blog/gitignore.md
+++ b/site/blog/2024-09-30-gitignore.md
@@ -5,8 +5,6 @@ description: And how to roll the rock over the edge.
color: "#A5804C"
thumbnail: /assets/images/sisyphus-ds-store.webp
-date: 2024-09-30
-
keywords:
- vcs
---
diff --git a/site/blog/2025-06-05-why-cores.md b/site/blog/2025-06-05-why-cores.md
new file mode 100644
index 0000000..8ca2bdb
--- /dev/null
+++ b/site/blog/2025-06-05-why-cores.md
@@ -0,0 +1,269 @@
+---
+title: "Why more `/sys/class/hwmon/*/temp*_label` than CPU cores?"
+
+color: "#99CF9F"
+thumbnail: /assets/images/cpu-dumb.webp
+
+keywords:
+- hardware
+---
+
+So, I am currently working on a Linux tool+daemon to replace
+[`auto-cpufreq`](https://github.com/AdnanHodzic/auto-cpufreq) with a more
+efficient, tunable and observable alternative.
+
+And obviously, to tune a CPU well, knowing how hot it is is a requirement.
+
+Then, how do you actually see how hot your CPU is in Linux? Using
+`/sys/class/hwmon` of course.
+
+This path contains hardware monitoring devices. In the laptop I'm testing this
+on, `hwmon4` under this directory corresponds to the CPU.
+
+Let's run a `tree`:
+
+```text
+/sys/class/hwmon/hwmon4 -> ../../devices/platform/coretemp.0/hwmon/hwmon4
+├── device -> ../../../coretemp.0
+│ ├── driver_override
+│ ├── hwmon
+│ ├── modalias
+│ ├── power
+│ ├── subsystem -> ../../../bus/platform
+│ └── uevent
+├── name
+├── power
+│ ├── autosuspend_delay_ms
+│ ├── control
+│ ├── runtime_active_time
+│ ├── runtime_status
+│ └── runtime_suspended_time
+├── subsystem -> ../../../../../class/hwmon [recursive, not followed]
+├── temp10_crit
+├── temp10_crit_alarm
+├── temp10_input
+├── temp10_label
+├── temp10_max
+├── temp14_crit
+├── temp14_crit_alarm
+├── temp14_input
+├── temp14_label
+├── temp14_max
+├── temp18_crit
+├── temp18_crit_alarm
+├── temp18_input
+├── temp18_label
+├── temp18_max
+├── temp1_crit
+├── temp1_crit_alarm
+├── temp1_input
+├── temp1_label
+├── temp1_max
+├── temp22_crit
+├── temp22_crit_alarm
+├── temp22_input
+├── temp22_label
+├── temp22_max
+├── temp26_crit
+├── temp26_crit_alarm
+├── temp26_input
+├── temp26_label
+├── temp26_max
+├── temp2_crit
+├── temp2_crit_alarm
+├── temp2_input
+├── temp2_label
+├── temp2_max
+├── temp30_crit
+├── temp30_crit_alarm
+├── temp30_input
+├── temp30_label
+├── temp30_max
+├── temp34_crit
+├── temp34_crit_alarm
+├── temp34_input
+├── temp34_label
+├── temp34_max
+├── temp35_crit
+├── temp35_crit_alarm
+├── temp35_input
+├── temp35_label
+├── temp35_max
+├── temp36_crit
+├── temp36_crit_alarm
+├── temp36_input
+├── temp36_label
+├── temp36_max
+├── temp37_crit
+├── temp37_crit_alarm
+├── temp37_input
+├── temp37_label
+├── temp37_max
+├── temp38_crit
+├── temp38_crit_alarm
+├── temp38_input
+├── temp38_label
+├── temp38_max
+├── temp39_crit
+├── temp39_crit_alarm
+├── temp39_input
+├── temp39_label
+├── temp39_max
+├── temp40_crit
+├── temp40_crit_alarm
+├── temp40_input
+├── temp40_label
+├── temp40_max
+├── temp41_crit
+├── temp41_crit_alarm
+├── temp41_input
+├── temp41_label
+├── temp41_max
+├── temp42_crit
+├── temp42_crit_alarm
+├── temp42_input
+├── temp42_label
+├── temp42_max
+├── temp43_crit
+├── temp43_crit_alarm
+├── temp43_input
+├── temp43_label
+├── temp43_max
+├── temp44_crit
+├── temp44_crit_alarm
+├── temp44_input
+├── temp44_label
+├── temp44_max
+├── temp45_crit
+├── temp45_crit_alarm
+├── temp45_input
+├── temp45_label
+├── temp45_max
+├── temp46_crit
+├── temp46_crit_alarm
+├── temp46_input
+├── temp46_label
+├── temp46_max
+├── temp47_crit
+├── temp47_crit_alarm
+├── temp47_input
+├── temp47_label
+├── temp47_max
+├── temp48_crit
+├── temp48_crit_alarm
+├── temp48_input
+├── temp48_label
+├── temp48_max
+├── temp49_crit
+├── temp49_crit_alarm
+├── temp49_input
+├── temp49_label
+├── temp49_max
+├── temp6_crit
+├── temp6_crit_alarm
+├── temp6_input
+├── temp6_label
+├── temp6_max
+└── uevent
+```
+
+Let's `cat` all the `_label` files:
+
+```text
+/sys/class/hwmon/hwmon4/temp1_label:
+Package id 0
+/sys/class/hwmon/hwmon4/temp2_label:
+Core 0
+/sys/class/hwmon/hwmon4/temp6_label:
+Core 4
+/sys/class/hwmon/hwmon4/temp10_label:
+Core 8
+/sys/class/hwmon/hwmon4/temp14_label:
+Core 12
+/sys/class/hwmon/hwmon4/temp18_label:
+Core 16
+/sys/class/hwmon/hwmon4/temp22_label:
+Core 20
+/sys/class/hwmon/hwmon4/temp26_label:
+Core 24
+/sys/class/hwmon/hwmon4/temp30_label:
+Core 28
+/sys/class/hwmon/hwmon4/temp34_label:
+Core 32
+/sys/class/hwmon/hwmon4/temp35_label:
+Core 33
+/sys/class/hwmon/hwmon4/temp36_label:
+Core 34
+/sys/class/hwmon/hwmon4/temp37_label:
+Core 35
+/sys/class/hwmon/hwmon4/temp38_label:
+Core 36
+/sys/class/hwmon/hwmon4/temp39_label:
+Core 37
+/sys/class/hwmon/hwmon4/temp40_label:
+Core 38
+/sys/class/hwmon/hwmon4/temp41_label:
+Core 39
+/sys/class/hwmon/hwmon4/temp42_label:
+Core 40
+/sys/class/hwmon/hwmon4/temp43_label:
+Core 41
+/sys/class/hwmon/hwmon4/temp44_label:
+Core 42
+/sys/class/hwmon/hwmon4/temp45_label:
+Core 43
+/sys/class/hwmon/hwmon4/temp46_label:
+Core 44
+/sys/class/hwmon/hwmon4/temp47_label:
+Core 45
+/sys/class/hwmon/hwmon4/temp48_label:
+Core 46
+/sys/class/hwmon/hwmon4/temp49_label:
+Core 47
+```
+
+Notice something? I do:
+
+- `temp1_label` is `Package id 0` - what is that?
+- The core numbers make no sense. This device only has 32 cores, there shouldn't
+ be any gaps within numbers and the numbers shouldn't go that high.
+
+The explanation for the first point is simple, looking at the kernel
+[`coretemp.c`](https://github.com/torvalds/linux/blob/ec7714e4947909190ffb3041a03311a975350fe0/drivers/hwmon/coretemp.c#L348)
+implementation, we can see that it is the temperature of the CPU as a whole:
+
+```c
+static ssize_t show_label(
+ struct device *dev,
+ struct device_attribute *devattr,
+ char *buf
+) {
+ struct platform_data *pdata = dev_get_drvdata(dev);
+ struct temp_data *tdata = container_of(devattr, struct temp_data, sd_attrs[ATTR_LABEL]);
+
+ if (is_pkg_temp_data(tdata))
+ return sprintf(buf, "Package id %u\n", pdata->pkg_id);
+
+ return sprintf(buf, "Core %u\n", tdata->cpu_core_id);
+}
+```
+
+That leaves us the second question. Why do we have CPUs 1, 2, 6, 10, 14, 18, 22,
+26, 30, 34-49, instead of the expected 0-31?
+
+It turns out that CPU It's common for chip manufacturers to disable faulty or
+degraded cores before shipping. Or if a lower tier SKU[^Stock Keeping Unit] is
+selling more, cores of higher tier SKUs are disabled to match expectations.
+
+This process is called `binning`, and it exists to not waste silicon. Since
+silicon manufacturing is not perfect, some CPUs are more faulty, thus slower
+than others. The process determintes how faulty a CPU is and sorts them into
+"bins". This is also why lower tier CPUs who are almost exactly the same as
+higher tier CPUs exist.
+
+The likelyhood of faulty silicon also increases with the smaller the
+architechture size gets (the Apple M4 is 4m, which is crazy), so this method of
+recycling worse chips is becoming much more valuable by the day.
+
+So, in summary the 32 core CPU I was testing this on was most likely just the 64
+core version with a bunch of the cores disabled.
diff --git a/site/blog/_data.ts b/site/blog/_data.ts
index d50cb78..bd76e4f 100644
--- a/site/blog/_data.ts
+++ b/site/blog/_data.ts
@@ -1,4 +1,6 @@
export default {
layout: "text.vto",
type: "article",
+
+ description: null,
};