Showing posts with label программирование. Show all posts
Showing posts with label программирование. Show all posts

Thursday, June 18, 2026

Configuration guide for Kate on Ubuntu (English)

Text rendered via Dual-Core compilation (Human author + LLM co-processor).
Also available here https://alex-ber.medium.com/4d861cdd366c

Note:Windows alternative for Kate is Zed. As alternative Lapce can be considered, but it lost development momentum recently.

Limitation: Here there is no description for debugging. Even running on bare metal, not in docker containers.

Basic Installation:

sudo apt update
sudo apt install konsole
sudo snap install kate --classic

Now, many LSP uses Node.js. Because Node.js breaks backward compatibility we will use mise to manage it's versions.

Mise

Installing:

curl https://mise.run | sh

Making it work automatically when terminal is opened:

# Add shims to PATH instead of activating via eval
# echo 'eval "$(~/.local/bin/mise activate bash)"' >> ~/.bashrc
echo 'export PATH="$HOME/.local/share/mise/shims:$PATH"' >> ~/.bashrc

# Reload bashrc
source ~/.bashrc
There is more below. Ниже есть продолжение.

No system-level utils by default

#If you want to set one, but I do not recommend
#mise use --global uv@0.11.21
#mise use --global node@20.11.0

Unset global versions

Unfortunately,

mise unset --global uv
mise unset --global node

doesn't work for whatever reason. Instead run

nano ~/.config/mise/config.toml

directly. Revert it to it's default state that should look exactly like

[settings]
# Enable variable expansion
env_shell_expand = true

[tools]

[env]

Note:: env_shell_expand is set to true for forward compatibility. By default, this line doesn't exists and current behavior is as if it is set to false. But we in future version the default value will be changed to true, so we're just preparing ourselves to this change in advance. And we will exploit true value later in our scripts anyway just now.

After editing:

# Verify the config is clean
cat ~/.config/mise/config.toml

mise cache clear
mise reshim
# Checking that shims works
mise doctor  

# Check versions - shouldn't found anything
uv --version
node --version

Once in a while you can run

mise prune

to clean up space on the disk for unused tools.

Making sudo uv works

Now, if you want to run uv or node with sudo just type:

sudo -E env PATH="$PATH" uv
sudo -E env PATH="$PATH" node

Some useful mise commands

  • mise tool-alias ls node - here you can see LTS versions of the tool. Node supports this, uv doesn't.
  • mise latest uv - latest version of the tool.
  • mise ls-remote uv - list of full supported version of the tool.
  • mise ls uv - What version of uv is used and where it is configured.
  • mise list - list of currently installed utils.

For more advanced mise commands see my https://github.com/alex-ber/ubuntu2404-snapshots/blob/master/README-mise.md


Installing LSP Servers

First of all we will create isolated directory that will serve as LSP "control center":

sudo mkdir -p /work
sudo chmod 755 /work
sudo chown USER:USER /work
cd /work

Note:: Change USER for your real Linux user.
Important: All Git Repositories and all other thing that you want to benefit from your default miseconfig file you should strictly checkout to /work.

Than we'll use mise use. This command will create a mise.toml file where versions will be pinned.

#Note, here we're using more advance version of node than above
#It is LTS version of node at a time of writting of the story
mise use node@22
mise use uv@0.11.21

I recommend you to rename it to .mise.toml.

cd /work
mv mise.toml .mise.toml

Now a .mise.toml file has appeared in the folder.

After that, run:

mise install

Verify that the tools work locally:

uv --version

It should show 0.11.21.

npm --version

It should show 10.9.8.

About V8

The V8 engine is never installed separately. It is hard-wired inside Node.js (or inside Deno). Therefore, you cannot check the V8 version simply from the terminal. But you can ask Node.js itself which version of V8 is embedded in it! Run:

node -p "process.versions.v8"

You can also optionally verify that you doesn't have Deno installed by running:

deno --version

You should see Command 'deno' not found, did you mean: as first line at the output.


Environment variables

One of the best features of mise is that it can manage environment variables.
First of all verify that ~/.config/mise/config.toml looks like this:

[settings]
# Enable variable expansion
env_shell_expand = true

[tools]

[env]

Note:: env_shell_expand is set to true for forward compatibility. By default, this line doesn't exists and current behavior is as if it is set to false. But we in future version the default value will be changed to true, so we're just preparing ourselves to this change in advance. And we will exploit true value later in our scripts anyway just now.

Now, open /work/.mise.toml and make it look like this (insert your own data):

[tools]
node = "22"
uv = "0.11.21"
"npm:dockerfile-language-server-nodejs" = "0.15.0"
"npm:pyright" = "1.1.410"
"npm:typescript" = "5.5.2"
"npm:typescript-language-server" = "4.3.3"
"npm:vscode-langservers-extracted" = "4.10.0"
"npm:yaml-language-server" = "1.23.0"
"npm:eslint" = "10.5.0"
#ruff = "0.15.17"

[env]
# Your Git settings
GIT_TOKEN = "ghp_KR..."
GIT_USER = "alex-ber"
GIT_CONFIG_COUNT = "2"
GIT_CONFIG_KEY_0 = "url.@github.com/.insteadOf">https://${GIT_USER}:${GIT_TOKEN}@github.com/.insteadOf"
GIT_CONFIG_VALUE_0 = "https://github.com/"
GIT_CONFIG_KEY_1 = "url.@gist.github.com/.insteadOf">https://${GIT_USER}:${GIT_TOKEN}@gist.github.com/.insteadOf"
GIT_CONFIG_VALUE_1 = "https://gist.github.com/"

# Adding local binary paths to PATH so that Kate can see them
_.path = [
  "./node_modules/.bin",
  "./.venv/bin"
]

Note:: Change GIT_TOKEN and GIT_USER to your specific values.
Of course, this is only one of many of possible ways to configure GIT configuration value for Kate. I found this very straightforward. Note also that we're using variable expansion here.

WARNING:
1. You're storeing you GIT_TOKEN as plain text. On another hand attacher should know where to search GIT_TOKEN or it should scan whole file system for "GIT_TOKEN" key. Using /work to store is not standard in the industry. :-) I hope, yet. :-)
2. When Kate make git pushit passes your GIT_TOKEN as plain text. If this is unexectable security risk for you find another way to pass credenetial to GIT there are plenty documentaiton on the Internet.

Execute:

mise install

If you get

mise ERROR error parsing config file: /work/.mise.toml
mise ERROR Config files in /work/.mise.toml are not trusted.
Trust them with `mise trust`. See https://mise.en.dev/cli/trust.html for more information.
mise ERROR Version: 2026.6.6 linux-x64 (2026-06-13)
mise ERROR Run with --verbose or MISE_VERBOSE=1 for more information

The error Config files ... are not trusted is an excellent and very important built-in security system of mise.

Why it occurred:
Your file contains an [env] section where you define tokens and, most critically, modify paths (_.path). Imagine you download someone else's repository containing a malicious mise.toml that replaces system commands. To prevent this, mise blocks the execution of such settings by default until you explicitly confirm that you trust this file.

How to fix it:
Since this is your own file in your working directory /work, you need to do exactly what mise asks.
While in the /work directory, run:

mise trust

This command will add the /work/.mise.toml file to your system's global allowlist.

In order to verify that environment variables are set properly run

mise env

or

mise env | grep GIT_CONFIG_KEY_0

Tips: You can edit .mise.toml file and run mise prune command it will remove unused tools. If you edit .mise.toml manually you must run mise install command in order to execute the configuration changes, see below for more details.

I pinned versions that was latest at the moment of installation. You can use @latest if you prefer. There is also @lts label, but see caveats below.

Nuance: latest vs lts

In mise, you can use keywords:

  • node@lts - installs the latest Long-Term Support version (currently 22, but this will change over time). This is the safest choice for production work.
  • node@latest - the absolute newest version (could be 23 or 24, which are still being "road-tested").

My advice: Use mise use node@22, as it currently offers the perfect balance between new features and stability.

Execute:

mise doctor

You should see something like this:

version: 2026.6.6 linux-x64 (2026-06-13)
activated: yes
shims_on_path: yes
self_update_available: yes
build_info:
  Target: x86_64-unknown-linux-gnu
  Features: openssl, rustls-native-roots, self_update
  Built: Sat, 13 Jun 2026 11:27:15 +0000
  Rust Version: rustc 1.94.0 (4a4ef493e 2026-03-02)
  Profile: release
shell:
  /bin/bash
  GNU bash, version 5.2.21(1)-release (x86_64-pc-linux-gnu)
  Copyright (C) 2022 Free Software Foundation, Inc.
  License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
  There is NO WARRANTY, to the extent permitted by law.
aqua:
  baked in registry: aquaproj/aqua-registry@93cd8ecfeef813610199913db392d0e8f8dc0c27
  baked in registry tools: 2218
dirs:
  cache: ~/.cache/mise
  config: ~/.config/mise
  data: ~/.local/share/mise
  shims: ~/.local/share/mise/shims
  state: ~/.local/state/mise
config_files:
  ~/.config/mise/config.toml
  /work/.mise.toml
env_files:
  (none)
ignored_config_files: (none)
backends:
  aqua
  asdf
  cargo
  conda
  core
  dotnet
  forgejo
  gem
  github
  gitlab
  go
  npm
  pipx
  spm
  http
  s3
  ubi
  vfox
plugins:
toolset:
  aqua:astral-sh/uv@0.11.21
  core:node@22.22.3
  npm:dockerfile-language-server-nodejs@0.15.0
  npm:pyright@1.1.410
  npm:typescript-language-server@4.3.3
  npm:typescript@5.5.2
  npm:vscode-langservers-extracted@4.10.0
  npm:yaml-language-server@1.23.0
path:
  /work/node_modules/.bin
  /work/.venv/bin
  ~/.local/share/mise/installs/node/22/bin
  ~/.local/share/mise/installs/uv/0.11.21/uv-x86_64-unknown-linux-musl
  ~/.local/share/mise/installs/npm-dockerfile-language-server-nodejs/0.15.0/bin
  ~/.local/share/mise/installs/npm-pyright/1.1.410/bin
  ~/.local/share/mise/installs/npm-typescript/5.5.2/bin
  ~/.local/share/mise/installs/npm-typescript-language-server/4.3.3/bin
  ~/.local/share/mise/installs/npm-vscode-langservers-extracted/4.10.0/bin
  ~/.local/share/mise/installs/npm-yaml-language-server/1.23.0/bin
  ~/.local/share/mise/shims
  ~/.local/bin
  /usr/local/sbin
  /usr/local/bin
  /usr/sbin
  /usr/bin
  /sbin
  /bin
  /usr/games
  /usr/local/games
  /snap/bin
  /snap/bin
  ~/go/bin
env_vars:
  MISE_SHELL=bash
settings:
  env_shell_expand  true ~/.config/mise/config.toml
No problems found

Whether you are building Kate, a custom Neovim configuration, supercharging Emacs, or just wanting to understand what happens under the hood of VS Code, knowing your toolchain is essential.
Let's break down a modern developer's stack by looking at eight fundamental tools, exactly in the order you would build them into a polyglot setup, and explore what they bring to your editing experience.

The Power of Modularity

The true beauty of the modern development ecosystem is modularity. By understanding what each of these packages does - from the strict type checking of Pyright and TypeScript to the blazing-fast formatting of Ruff - you can mix, match, and tailor your environment to be exactly as responsive and rigorous as you need it to be.

1. Dockerfile Language Server Node.js

(npm:dockerfile-language-server-nodejs)
When you are writing a Dockerfile, you want to ensure your instructions are valid and follow best practices. This server is powered by Node.js and hooks directly into your editor to provide auto-completion for Docker instructions like RUN, COPY, or ENTRYPOINT. It also offers on-the-fly syntax validation, hover documentation, and structural linting, ensuring your container builds won't fail due to simple typos or missing arguments.

2. Pyright

(npm:pyright)
Developed by Microsoft, Pyright is an incredibly fast, statically typed checker and language server for Python. Unlike traditional Python linters, Pyright focuses heavily on type inference and PEP 484 type hinting. It runs instantly as you type, catching type mismatches, missing imports, and undefined variables. It is an absolute favorite for large-scale Python codebases that require strict type safety and intelligent refactoring.

3. TypeScript

(npm:typescript)
While technically a programming language and a compiler rather than a standalone LSP, this core package is the brain behind any JavaScript or TypeScript development environment. It contains the TypeScript Language Service (tsserver), which parses your code, understands your project's tsconfig.json, and computes all the rich type information, completions, and diagnostics. Without this base package, no modern TypeScript tooling could function.

4. TypeScript Language Server

(npm:typescript-language-server)
Because the core tsserver does not natively speak the standardized Language Server Protocol (LSP), this wrapper was created to bridge the gap. It takes the deep intelligence provided by the base TypeScript package and translates it into standard LSP JSON-RPC messages. If you are using an editor outside of VS Code - this is the exact piece of software that grants you official, VS Code-level TypeScript and JavaScript support.

5. VSCode Langservers Extracted

(npm:vscode-langservers-extracted)
VS Code has brilliant built-in language support for front-end web technologies, but those servers are normally tightly integrated into the editor itself. This package extracts those official servers - specifically for HTML, CSS, SCSS, LESS, and JSON - so they can be used in any LSP-compatible editor. By installing this, you get Microsoft's official auto-completion, schema validation, and linting for standard web languages anywhere you choose to code.

6. YAML Language Server

(npm:yaml-language-server)
Writing YAML without assistance can lead to frustrating indentation errors and silent configuration bugs. Developed by Red Hat, this language server transforms the YAML writing experience. Its most powerful feature is the ability to map your files to JSON Schemas (for example, mapping to Kubernetes manifests, GitHub Actions, or Docker Compose files). This means you get intelligent auto-completion and validation tailored exactly to the specific DevOps tool you are configuring.

7. ESLint

(npm:eslint)
ESLint is the industry standard for identifying and reporting on patterns in JavaScript and TypeScript code. While it is fundamentally a linter and not an LSP on its own, modern development environments run ESLint as a background service (often wrapped in its own LSP integration) to provide real-time squiggly lines and auto-fix capabilities upon saving. It ensures your code adheres strictly to your team's style guide and catches logical errors before they ever reach production.
Note: I'm not using this LSP Server, but rely on Kate's built-in plugin, it works more reliability.

8. Ruff

(#ruff)
Ruff is the new heavyweight champion of Python tooling. Written in Rust, it is an astonishingly fast Python linter and formatter that replaces a dozen legacy tools like Flake8, isort, and Black. Many developers integrate Ruff directly into their editor via its own language server (such as ruff-lsp or the newer native ruff server) to get instantaneous feedback. It flags unused imports, stylistic errors, and code smells, fixing them in milliseconds without ever slowing down your editor.
Note: It is turned off in the configuration provided above, because personally I do not see any value of it. I started from Python 2 without any type hints and I have bad experiences with similar tools in Java scosystem. And Java is statically typed. IMHO such tools can be never be perfect.
Especially in such dynamic languages like Pyhton where you have eval(discoursage I know, but still in use), locals(), metaclassess, type hints are optional, if you're using duck typing without Protocol Ruff can't help you. Basically, in typicall code-base there too many "too dynamic" code that Ruff will be able to handle statically. You can treat it as my personal heuristic, but actually Turing halting problem and Gödel incompleteness theorems mathimatically proves that such tools can be never be perfect.


Set local versions (for a specific project)

Navigate to your project folder and run:

cd /path/to/your/project
mise use node@22
mise use uv@0.11.21

These commands won't download anything (since the versions are already downloaded globally), they will simply create a mise.toml file in the folder that locks these versions to the project. Don't forget to commit it to Git.

Manual editing of mise.toml

This is a completely valid and standard scenario. Many people do exactly this: edit the file by hand.
Just execute:

mise install

In 99% cases this is enough. If you manually added uv = "0.11.21" to mise.toml, running mise install will read this file, download the required version of uv, and make it available in the current directory. Nothing else is needed for the installation itself.

Note: If you there are problems (e.g., if your internet disconnects while downloading uv, the archive becomes corrupted, and mise install gives an unpacking error) you can use mise cache clear. Under normal workflow, you don't need to use this command.

Since we're working via shims the mise install command automatically creates and updates shims for new tools, so in 99% cases mise reshimis not needed. Manually calling mise reshim may only be needed as a "first aid" if you installed a tool but get command not found when typing its command in the terminal (e.g., this sometimes happens if you install a global CLI package via npm -g or pip, and mise hasn't had a chance to rebuild shims for the new binaries).

Once in a while you can run mise prune to clean up space on the disk for unused tools.

Note:

config_files:
  ~/.config/mise/config.toml
  /work/alexsmail-dns-fix/mise.toml

/work/alexsmail-dns-fix/mise.toml was added to config_files and ~/.local/share/mise/installs/uv/0.11.21/uv-x86_64-unknown-linux-musl was added to the path.


Create a startup script (Kate Wrapper)

To make Kate pick up the entire mise environment, the simplest approach is to launch it via the mise exec command.
Create the file /work/mise-app-launcher.sh:

Deprecated version:

#!/bin/bash
## Navigate to /work so that mise finds the correct .mise.toml
cd /work
# Use the absolute path to the snap version of Kate to avoid conflicts
exec ~/.local/bin/mise exec -- /snap/bin/kate -b "$@"

Robust version:

#!/bin/bash

# Check that at least one argument (executable) has been passed
if [ $# -lt 1 ]; then
    echo "Usage: $0 <executable_path> [args...]"
    exit 1
fi

# 1. Take the first argument as the command to run and shift the $@ array
APP_EXEC="$1"
shift

# Default base directory
TARGET_DIR="/work"

# Function for URL decoding (turns %20 into spaces, decodes Cyrillic, etc.)
urldecode() {
    local url_encoded="${1//+/ }"
    printf '%b' "${url_encoded//%/\\x}"
}

# Look for the first argument that is an existing file or directory
for arg in "$@"; do
    # 1. Strip protocol prefix if present
    clean_arg="${arg#file://}"
    
    # 2. Decode the URL if KDE/GNOME/Windows passed an escaped path
    if [[ "$clean_arg" == *%* ]]; then
        clean_arg=$(urldecode "$clean_arg")
    fi

    # 3. WSL2 AND WINDOWS PATH SUPPORT
    if [[ "$clean_arg" =~ ^/?([a-zA-Z]:[\\/].*) ]]; then
        clean_arg="${BASH_REMATCH[1]}" # Remove leading slash, keep "C:/..."
        
        # If we are in WSL, convert Windows path to Linux path (/mnt/c/...)
        if command -v wslpath >/dev/null 2>&1; then
            clean_arg=$(wslpath -u "$clean_arg" 2>/dev/null || echo "$clean_arg")
        fi
    fi

    # 4. Check if the directory or file exists (with protection against filenames starting with a dash)
    if [ -d -- "$clean_arg" ]; then
        TARGET_DIR="$clean_arg"
        break
    elif [ -f -- "$clean_arg" ]; then
        TARGET_DIR=$(dirname -- "$clean_arg")
        break
    fi
done

# 5. TOMCAT MAGIC: Convert the path to absolute and resolve all symlinks.
if command -v realpath >/dev/null 2>&1; then
    TARGET_DIR=$(realpath "$TARGET_DIR")
else
    # Reliable POSIX fallback for systems without the realpath utility
    TARGET_DIR=$(cd "$TARGET_DIR" 2>/dev/null && pwd -P)
fi

# 6. Change to the resolved directory and execute the requested app via mise
cd "$TARGET_DIR" || exit 1

# Use APP_EXEC, while $@ now contains only flags and files (since we performed shift)
exec ~/.local/bin/mise exec -- "$APP_EXEC" "$@"

Make it executable:

chmod +x /work/mise-app-launcher.sh

Update the shortcut (.desktop file)

Now, we will create .desktop file on your desktop. These instructions are GNOME specific.
Run

find /usr/share/applications -iname '*kate*.desktop'

or

find /var/lib/snapd/desktop/applications/ -iname '*kate*.desktop'

Typically second command will return something like this:

/var/lib/snapd/desktop/applications/kate_kate.desktop

Now execute:

cp /var/lib/snapd/desktop/applications/kate_kate.desktop ~/Desktop/

chmod +x ~/Desktop/kate_kate.desktop

gio set ~/Desktop/kate_kate.desktop metadata::trusted true

Now modify the Exec line in your .desktop file. For example:

nano ~/Desktop/kate_kate.desktop

Change the Exec line:

Exec=/work/mise-app-launcher.sh /snap/bin/kate -b %U

Plugins

These are plugins that I'm using:

  • Document Switcher (was default)
  • Documents Tree (was default)
  • ESLInt - note I'm not using LSP Server (see above), but rely on built-in plugin, it works more reliability.
  • External tools (was default)
  • LSP Client (see below)
  • Project plugin (was default) - very convenient minimalist Git client. I have provided above one version of passing auth params via env/export.
  • Search & replace (was default)
  • Symbol viewer
  • Terminal - built-in terminal. Personally, I prefer to us regular terminal, but it is handy for quick experimentation.
  • Text Filter

LSP Client's User Server Settings

Now click on .desktop shortcut. Kate should opened up.
Go to Settings->Configure Kate->LSP Client. Go to User Server Settings tab. Replace the content with following:

{
    "servers": {
        "python": {
            "command": ["pyright-langserver", "--stdio"],
            "rootIndicationFileNames": ["pyproject.toml", "mise.toml", ".git"],
            "highlightingModeRegex": "^Python$",
            "documentLanguageId": "python"
        },
        "javascript": {
            "command": ["typescript-language-server", "--stdio"],
            "rootIndicationFileNames": ["tsconfig.json", "package.json"],
            "highlightingModeRegex": "^JavaScript.*$",
            "documentLanguageId": "javascript"
        },
        "typescript": {
            "use": "javascript",
            "highlightingModeRegex": "^TypeScript.*$",
            "documentLanguageId": "typescript"
        },
        "json": {
            "command": ["vscode-json-language-server", "--stdio"],
            "highlightingModeRegex": "^JSON$",
            "documentLanguageId": "json"
        },
        "html": {
            "command": ["vscode-html-language-server", "--stdio"],
            "highlightingModeRegex": "^HTML$",
            "documentLanguageId": "html"
        },
        "css": {
            "command": ["vscode-css-language-server", "--stdio"],
            "highlightingModeRegex": "^CSS$",
            "documentLanguageId": "css"
        },
        "yaml": {
            "command": ["yaml-language-server", "--stdio"],
            "highlightingModeRegex": "^YAML$",
            "documentLanguageId": "yaml",
            "initializationOptions": {
                "settings": {
                    "yaml": {
                        "schemaStore": {
                            "enable": true
                        }
                    }
                }
            }
        },
        "dockerfile": {
            "command": ["docker-langserver", "--stdio"],
            "highlightingModeRegex": "^Dockerfile$",
            "documentLanguageId": "dockerfile"
        },
        "markdown": {
            "highlightingModeRegex": "DisabledMode"
        }
    }
}

Note:: When you're openning yaml file, say docker-compose.yml you can see error in the logs. If syntax highlighting and autocomplition works, you can safely ignore this error. It is harmless.


How it works and why it's great:

  • Clean system: If you open a regular terminal and type uv or node, the system won't find them (just as you wanted).
  • Automation: When you launch Kate via the script, mise exec looks at .mise.toml, instantly activates the correct versions of Node.js and uv, passes through GIT_TOKEN, and adds the node_modules/.bin and .venv/bin folders to PATH.
  • LSP in Kate: When the LSP plugin activates in Kate, it looks for the command (e.g., typescript-language-server). Since the startup script added the local project folder to PATH, Kate successfully finds and launches the server.

Verification:

  • Launch Kate via the new shortcut.
  • Open the built-in terminal in Kate (F4).
  • Type echo $GIT_TOKEN - you should see your token.

Code Index

Note:: I did

sudo apt install universal-ctags

but it is not used in Kate.

1. Configuring the Project Plugin

The foundation of a smooth IDE experience in Kate is the Project Plugin. This step is critical because LSP servers work significantly better when they know the exact "root" of your codebase.
Go to Settings → Configure Kate → Plugins.
Ensure that the Project Plugin is enabled.

When you open a folder as a project (via Project → Open Folder in the top menu), Kate automatically scans for version control directories (such as .git). Once detected, it passes this exact root path to the LSP server as the rootUri.
Note: Always open your working directory as a project via the Project menu rather than opening files individually. This simple habit guarantees that your LSP server will correctly resolve all local imports, modules, and dependencies across your entire workspace.

2. Enabling the Symbol Outline

To get a clear visual representation of your code architecture, we can utilize the structural data already provided by the LSP.
In the Plugins menu, verify that both the LSP Client and Symbol Viewer plugins are enabled.
Navigate to View → Tool Views in the main menu and check Show Symbol Outline (or Symbol Viewer).
If the panel appears empty at first, you can force a refresh by navigating to LSP Client → Restart All LSP Servers.

A sidebar or a bottom tab will immediately appear. It automatically builds a dynamic, clickable tree of all functions, classes, and variables based on the real-time data parsed by your Python or TypeScript language servers.

3. Testing the Magic

Finally, let us verify that your smart code navigation is fully operational.
Open your project folder using the Project menu.
At the bottom of the Kate window, click on the LSP Client panel and switch to the Log tab. You should see a confirmation message indicating that your specific servers (e.g., pyright-langserver) have started successfully and attached to your project root.
Open any source file, right-click on a custom function or class name, and select Go to Definition (or use the default Ctrl + Click / F12 shortcut).

Kate will instantly navigate you to the exact file and line where that symbol was declared, leveraging your local, fully isolated LSP environment.


Extras

Because Ubuntu doesn't provide built in base docker repositroy that is frozen in time I built one myself. This is https://github.com/alex-ber/ubuntu2404-snapshots project. You can pull latest golden/frozen version by

docker pull alexberkovich/ubuntu2404-snapshot:latest

or provide specific date for snapshot (if it exists in Docker hub).

Usually, it will be best on latest ubuntu:24.04 docker images with some extra OS-level dependecies installed and pinned.
For example, it has curl installed with specific version. No matter what security vulnaribility will be found if you're using my base image you will have this exact version.
It provides determenism and reproducability. Fixing, security whole often breaks your docker images. And it "just happen" in undefined time.
If there is serious security patch you will know about it and you should move to another snapshot (that I will provide) when you're ready to deal with broken docker image.
It also has get-image-hash and get-pkg-version abilities that can be utilized via docker-compose.yml. It also has update-uv-lock that is template for Python project's that want to utilize uv.


get-image-hash

The engine behind this entire workflow is a dedicated Docker Compose service named get-image-hash. It is designed to retrieve the latest immutable SHA256 digest for absolutely ANY Docker image.
Here is how you can utilize the daemon in your day-to-day workflow:

  • Default Execution:
    Running docker compose run --rm get-image-hash without any arguments defaults to targeting ghcr.io/astral-sh/uv:latest.
  • Custom Target Resolution:
    You can append any image name to fetch its specific hash. For example, running docker compose run --rm get-image-hash ubuntu:24.04 will instantly return the exact pointer for that Ubuntu release.
  • Debugging Mode:
    If the daemon is failing or you need to inspect the container environment, you can override the default execution by dropping into a shell. Simply run docker compose run --rm --entrypoint sh get-image-hash.

By standardizing how you retrieve and lock down your image hashes, you eliminate "it works on my machine" issues and create a foundation for truly bulletproof infrastructure.
The core concept starts with fetching the exact SHA256 digest of a specific tool before building. For example, if you want to use version 0.11.21 of the Astral uv tool, you would execute the daemon like this:

docker compose run --rm get-image-hash ghcr.io/astral-sh/uv:0.11.21

This query returns an absolute, immutable hash. Armed with this string, you can replace vulnerable floating tags in your Dockerfile with a bulletproof copy command:

COPY --from=ghcr.io/astral-sh/uv@sha256:abcd… /uv /uvx /bin/

By doing this, your container build is guaranteed to pull the exact same binaries every single time, regardless of what the maintainers publish in the future.

Managing Host Tooling with Mise

While Docker handles containerized dependencies, you also need to manage local versions predictably. If you use the mise tool manager, you can easily query version availability.
To check if a specific tool (like Node.js) natively supports Long Term Support (LTS) aliases, you can run:

mise tool-alias ls node

If your desired tool does not show up, you can search the remote registry:

mise ls-remote uv

Or, to simply grab the most current version number (which, in our example, returns 0.11.21), you can use:

mise latest uv

Note: For more advanced mise commands see my https://github.com/alex-ber/ubuntu2404-snapshots/blob/master/README-mise.md

The Reproducibility Warning: Forcing LTS

Sometimes, a tool lacks an official LTS policy. You might be tempted to force one to keep your local environment consistently updated within a minor version range. You can do this by setting a custom alias:

mise tool-alias set uv lts 0.11

Warning: While this is convenient for local development, doing this entirely breaks strict reproducibility. Because "0.11" is a moving target, your tools will shift beneath your feet as new patches are released.

get-pkg-version

Before you can pin a package, you need to know exactly which operating system environment you are targeting. Your first step when setting up your builds should always be to verify your base system. You can do this by running:

cat /etc/os-release

This ensures that the package versions you are about to resolve actually match the distribution (like Ubuntu 24.04) you intend to use in your final production Dockerfile.
This get-pkg-version queries the official Ubuntu repositories and returns the exact version string required for hard-pinning. Here is how you can use it in various scenarios:

  • Default Execution:
    If you run the service without passing any arguments, it is configured to resolve the ca-certificates package by default. You trigger this by running:
    docker compose run --rm get-pkg-version
  • Custom Target Resolution:
    You are not limited to the default. You can append any package names you need to resolve multiple dependencies at once. For example, to find the exact versions for the Nano editor and Git, you would run:
    docker compose run --rm get-pkg-version nano git
  • Debugging Mode:
    If the package resolver fails, or if you need to manually explore the APT repositories using tools like apt-cache policy, you can override the entrypoint and drop straight into a Bash shell:
    docker compose run --rm --entrypoint bash get-pkg-version

Under the hood, the get-pkg-version service needs to run inside a container that mirrors your production base image.
When configuring this service, you face a strategic choice regarding the image tag. The primary goal of this daemon is to discover what packages are currently available in the repositories before you permanently lock the exact package versions and image SHA in your main Dockerfile.
Because of this discovery phase, developers will often use a floating tag (like ubuntu:24.04) to query the most up-to-date repository state. However, in our specific configuration, we lock the resolver itself to a highly specific, immutable digest:

image: ubuntu@sha256:786a8b558f7be160c6c8c4a54f9a57274f3b4fb1491cf65146521ae77ff1dc54

By using this locked digest instead of the floating tag, you ensure that your Package Version Resolver queries the exact same snapshot of the Ubuntu repositories every single time you run it, guaranteeing total predictability during your dependency resolution phase.

update-uv-lock

Note:: The configuration discussed below is a conceptual template and not an executable utility directly runnable from https://github.com/alex-ber/ubuntu2404-snapshots the repository. We will break down the actual, practical usage below.

This utility is specifically designed to regenerate a uv.lock file, entirely without installing the Astral uv package on your local computer.
The goal of this service is to run interactively, update your dependencies, and then vanish. Here is how you trigger this ephemeral daemon:

  • Standard Execution: The exact, full command to run this specific tool service is
    docker compose run --rm update-uv-lock
  • Debugging Mode: If the lock generation fails and you need to inspect the container from the inside, you can override the execution and drop into a shell by running
    docker compose run --rm --entrypoint bash update-uv-lock

To make this utiliy work seamlessly with your local filesystem, the service configuration for update-uv-lock must be precisely tuned.

Image and Working Directory

The service boots up using a lightweight Python image. Currently, it is pinned to

ghcr.io/astral-sh/uv:python3.13-bookworm-slim

Note: It has hard coded dependeny on your python version.

The Hardware Bridge (Identity Mapping)

When a Docker container creates a file, it defaults to the root user. If Docker generates your lock file, you won't be able to edit or delete it on your host machine without using sudo.
To avoid permission decoherence between the Host OS and the Docker runtime (especially on Linux environments), you must map your bare-metal User ID and Group ID into the container. This guarantees that files created by the runtime belong to you, preventing root-owned pollution on the host.

Initialize the local environment bridge:

cp env.example .env

Inject your bare-metal host IDs (Linux/Ubuntu):

echo "HOST_UID=$(id -u)" >> .env
echo "HOST_GID=$(id -g)" >> .env

To prevent permission decoherence, we use an identity mapping bridge:

user: "${HOST_UID:-1000}:${HOST_GID:-1000}"

{HOST_GID:-1000}"
This crucial line ensures that the newly generated uv.lock file belongs exactly to your local user account, keeping your file permissions intact.
See https://github.com/alex-ber/ubuntu2404-snapshots/blob/master/README.md for more details about .env and HOST_UID and HOST_GID.

The utility executes its single purpose:

command: ["uv", "lock"]

Test case1: JavaScript/TypeScript test project

This https://github.com/alex-ber/js-hello-world project was built specifically to test integration of Kate and LSP Servers. It is typicall hello world project and is not expected to be maintained. You can see it as reference example that can be outdated at some point.


Test case2: Python real project

This https://github.com/alex-ber/alexsmail-dns-fix project was written to solve some very specific problem.
This is mainained reference project that did the real job once and I plan to keep it up to date as template despite the fact that it was one time job I do maintain this project as template project for my another Python project.
So, when you will run it, it will fail with error. But this is expected behaviour.
It's docker-compose.yml contain update-uv-lock utility that is exact copy from https://github.com/alex-ber/ubuntu2404-snapshots/blob/master/docker-compose.yml But basic image doesn't have uv(or python) installed and this project does have. So here, update-uv-lock utility will actually work.
If you have project that has another Python version you can easily modify image tag.

Note: You can read https://github.com/alex-ber/ubuntu2404-snapshots/blob/master/README-docker-compose.md for some explanation of how docker-compose.yml utilitys (the official name is actually service, but I deliberetely avoid to use this term up untill this point to not overcomplicate things).


Tuesday, June 02, 2026

Эпичная битва Чацкого и Чака Норриса в Ubuntu для открытие видеофайлов в mc

Text rendered via Dual-Core compilation (Human author + LLM co-processor).
Англоязычная версия данной заметки доступна здесь https://alex-ber.medium.com/143edadfee21.

Это история о том, как простая попытка настроить конфигурационный файл Midnight Commander переросла в драматическое противостояние между грубой силой и избыточным интеллектом.

Ниже есть продолжение.

Акт 1: Появление Грибоедова (Инцидент с кавычками)

Всё началось с попытки заставить Midnight Commander (mc) открыть файл с пробелами в названии: Noize MC - Планета Земля.mp4. Чтобы командная строка не споткнулась о пробелы, мой LLM-ассистент принял "очень умное" решение: он аккуратно обернул макрос имени файла в кавычки, сделав его "%f".

Но мы забыли одну важную деталь: mc уже достаточно умен. Он автоматически добавляет обратные слеши перед каждым пробелом при передаче файла в shell. В результате наша "непробиваемая" защита с кавычками заставила bash искать файл, в имени которого буквально напечатаны обратные слеши. Естественно, файл не открылся.

Именно тогда я выдал первый точный диагноз происходящему:

«Это классический случай "Горя от ума" :-) Наверняка ты знаком с Грибоедовым. :-)»

Для контекста: Александр Чацкий — главный герой классической русской пьесы XIX века "Горе от ума" Александра Грибоедова. Это в высшей степени умный человек, чей интеллект приносит ему одни проблемы.

И вот так просто Чацкий стал нашим неофициальным символом оверинжиниринга — ситуации, когда программист пишет настолько сложный, перестраховочный и "правильный" код, что в итоге он ломает сам себя.

Акт 2: Призыв Чака Норриса

Спустя какое-то время, поняв, что mc перехватывает видеофайлы где-то глубоко в своих внутренних MIME-типах и упрямо игнорирует наши локальные настройки, мы решили, что с нас хватит дипломатии. LLM предложил перестать играть по правилам этого запутанного конфига и применить грубую силу:

«Мы сейчас нанесем один финальный "Удар Чака Норриса", который навсегда закроет этот вопрос для всех видеофайлов.»

Сказал LLM.

План состоял в том, чтобы взять блок, содержащий массивное "универсальное" регулярное выражение — Regex=\.(mp4|mkv|avi|m4v|mpe?g…)$ — и вбить его в самое начало файла. Логика была железобетонной: так же, как Чак Норрис вышибает дверь ногой, это правило должно было заставить mc прочитать его первым, не оставив абсолютно никаких шансов уйти в другие сломанные скрипты.

Акт 3: Столкновение идеологий (Развязка)

Мы нанесли этот брутальный удар. Ожидалось, что система сдастся. Я нажал Enter... и абсолютно ничего не произошло. Видео снова не открылось.

И вот тогда я выдал фразу, которая идеально и уморительно точно описала суть нашего технического провала:

«Чацкий оказался круче Чака Норриса. :-) mp4 по Enter всё ещё не работает…»

Почему это было так смешно и технически точно?

Потому что "Удар Чака Норриса" (попытка решить проблему грубым перехватом прямо в начале файла) провалился вовсе не из-за нехватки силы. Он провалился потому, что внутри этой атаки грубой силы было зашито всё то же слишком умное, переусложненное регулярное выражение — прямое наследие Чацкого.

Древний парсер INI-файлов из 1990-х просто посмотрел на этот удар с разворота, заметил хитрый знак вопроса mpe?g, споткнулся о кучу вертикальных черт |, поперхнулся от чистой интеллектуальной сложности всего этого и тихо упал в обморок — полностью проигнорировав наш всемогущий блок.

Мораль басни

Никакое количество грубой силы или крутых хаков (Чак Норрис) не спасет ваш код, если вы уже перехитрили самих себя (Чацкий). "Горе от ума" одержало безупречную, безоговорочную победу над суровым техасским рейнджером.

В конце концов, ситуацию спасло самое простое, самое "глупое" и прямолинейное решение: простое правило Shell=.mp4, повторенное несколько раз для .avi, .mpeg и так далее. Оно было простым и неказистым — но сработало идеально.


Saturday, May 16, 2026

Anatomy of a Bug in Sun JDK 1.4.2: How Phantom Time in the IDF Drove Servers to Thermal Burnout (2005) English

Text rendered via Dual-Core compilation (Human author + LLM co-processor). Also available here https://alex-ber.medium.com/13a19ab25b16.

היום הותר לפרסום.

Сегодня разрешено к публикации.

Cleared for publication today.

In 2005, I was serving in a technological unit of the IDF (Israel Defense Forces). There are bugs in Java history that stay with you for a lifetime, and one such incident happened exactly on my watch. It was an issue with handling the Spring Forward daylight saving time transition in Sun JDK 1.4.2. When attempting to parse a non-existent time, the system fell into a 100% CPU infinite loop. Tomcat hung, thread pools were exhausted, and the hardware literally overheated and shut down via thermal trip.

Below is the chronology of how I investigated this incident, and the mechanics of the bug itself.

There is more below.
Ниже есть продолжение.

1. Schrödinger's Time Zone: How Time Was Erased in Israel

In the early 2000s, the Asia/Jerusalem time zone was an absolute nightmare for developers. Unlike Europe or the US, Israel did not have a rigidly fixed rule for the clock switch. The dates for transitioning to summer and winter time were approved annually by the Knesset and depended on the Jewish lunar calendar (specifically, the timing of Yom Kippur). Because of this, official patches containing ZoneInfo tables from Sun were constantly delayed or contained errors.

On the night of the transition, the time interval of 02:00–02:59 was physically erased from reality (becoming an absolute vacuum, ∅). If a server received a string with a time like 02:30:00 and attempted to parse it, the Java code collided with a void.

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Jerusalem"));
Date date = sdf.parse("2005-04-01 02:30:00"); // ← This is where everything broke

2. The Lenient Mode Trap and Transaction Salvage

By default, GregorianCalendar and SimpleDateFormat operate in a lenient mode. Instead of honestly rejecting the phantom date, the virtual machine attempted to «fix» the incorrect time.

In Sun JDK 1.4.2, this heuristic was fatally broken. When processing time inside the DST gap, the computeTime() method tried to calculate milliseconds from the Epoch, but the algorithm panicked upon hitting a contradiction between the local fields (HOUR_OF_DAY = 2) and the actual offset.

3. Anatomy of the Infinite Loop: How Code Boiled Processors

Here is what the loop inside the JVM looked like (simplified):

  1. Take the local time 02:30 and the winter offset (UTC+2 for Jerusalem).
  2. Calculate the UNIX timestamp.
  3. Check against the time zone rules — summer time (UTC+3) should already apply for this absolute time.
  4. Rollback. Apply the UTC+3 offset to the same 02:30.
  5. Calculate the new timestamp.
  6. Check again — for this timestamp, the barrier has not yet been crossed, so the UTC+2 offset must apply.
  7. Return to step 1.

The result was a classic infinite loop at the level of base classes. And this was not an abstract software freeze. The thread monopolized 100% of the core's capacity. Since there were no interrupts in the loop, the processor began to endlessly grind in vain.

When dozens of servers simultaneously hit 100% load, the air conditioners in the server room simply failed to handle the sudden spike in heat dissipation (ΔS → ∞). The temperature in the cold aisle began climbing rapidly. Ultimately, hardware sensors initiated a thermal trip — servers violently cut their power to save the processor crystals from thermal degradation and physical burnout.

4. Thread Pool Exhaustion: Investigation

When the nodes started dropping one after another, it became clear this was not an ordinary memory leak. The Garbage Collector (GC) and Heap Size tuning were useless. The real drama was unfolding inside the Tomcat servers. Every request containing an invalid Israeli timestamp permanently captured one thread. Within a few minutes, the pool was drained (Thread Pool Exhaustion), the Tomcat stopped responding to any pings, and then went into a thermal knockout.

sdf.setLenient(false); // ← A magic pill? Not quite.

With this setting, the infinite loop did not occur — the code threw java.text.ParseException: Unparseable date. The server did not overheat, but the system lost data packets.

5. Hot-fix via Reflection

Official patches (like tzupdater) merely updated the binary files on the disk, but the JVM kept the time zone tables in its RAM since startup and completely ignored disk changes.

We had to apply a radical but uniquely functional technique: a controlled cache failure via the Reflection API. We wrote code that breached the sun.util.calendar.ZoneInfo class and forcibly nullified its internal array:

import java.lang.reflect.Field;
import sun.util.calendar.ZoneInfo;

Field cacheField = ZoneInfo.class.getDeclaredField("cache");
cacheField.setAccessible(true);
cacheField.set(null, null); // Nullify the cache

It worked. On the next parse attempt, the JVM accessed memory, received a [CACHE_MISS], and was forced to reread the updated files from the disk.

Conclusion

In later versions of the JDK (and especially with the arrival of java.time in Java 8), this architectural hole was closed forever. Strict checks, iteration limits, and predictable behavior when hitting gap/overlap zones were added.

But for me, the Sun JDK 1.4.2 bug will forever remain the reference example of how a banal clock adjustment can boil a server.


Monday, May 04, 2026

Топология измерений: Джиттер, тяжелые хвосты и подавление стохастических флуктуаций

Text rendered via Dual-Core compilation (Human author + LLM co-processor).

There is proxy version here https://alex-ber.medium.com/206f72bc6664

См.также:
Макро-топология, WAF и экстраполяция

Принципы аппаратного джиттера и термодинамики шума масштабируются для обхода систем защиты на WAF-уровне (Web Application Firewalls) и решения проблемы Thundering Herd (шторм запросов). Аппаратный джиттер на уровне макро-маршрутизации работает как глобальная приостановка потоков ([GLOBAL_THREAD_SLEEP]). Искусственная инъекция стохастической задержки генерирует локальную энтропию ($\Delta S > 0$ на микроуровне отдельного узла) для размытия кратных частот, предотвращая взаимную блокировку процессов ([DISTRIBUTED_MUTEX_LOCK]) при синхронном обращении к единому ресурсу. From Naive Scripts to Hardware Evasion https://alexsmail.blogspot.com/2026/04/from-naive-scripts-to-hardware-evasion.html.

Ниже есть продолжение.

[4/7, 16:51] [NODE_0]:
Дифференцирование
Математически дифференцирование — это простая локальная операция обхода графа. Но инженерные системы работают с эмпирическими данными, а любые реальные измерения всегда содержат стохастический шум. Если обрабатывается дискретный сигнал с микро-колебаниями (шумом сенсора), дифференцирование эмпирических данных максимизирует высокочастотную энтропию сигнала. Производная от шума превращается в полный хаос и вызывает каскадное переполнение значений.

Интегрирование (аппаратный сглаживатель)
Интегрирование для формальной математики — это сложная глобальная операция (Теория меры). А вот в аппаратной физической реализации интеграл (площадь под кривой) работает как математический Low-Pass Filter — фильтр нижних частот. При суммировании данных положительный и отрицательный шум частично взаимно уничтожаются (усредняются). Естественно, это работает с жесткой оговоркой на эргодичность процесса, когда усреднение выборки по времени эквивалентно усреднению по ансамблю состояний. Интеграл — это аппаратный bypass-фильтр для очистки сырых данных от энтропии и получения стабильного макро-состояния.

При этом надо понимать физику процесса: аппаратное усреднение в единый макро-стейт является необратимой операцией сжатия. Стирание локальной памяти требует сброса энтропии во внешнюю среду: аппаратный фильтр обязан выделять физическое тепло (согласно пределу Ландауэра: $Q \ge kT \ln 2$) за каждый стертый бит шума. Сброс энтропии выполняется строго через DROP_PACKET в UDP-социум без коммита в память графа ([COOLING]). В случае блокировки внешней среды для диссипации немедленно возникает ограничение [HW_LIMITS]: CARNOT_LIMIT, что ведет к THERMAL_TRIP и необратимому аппаратному повреждению узла.

Вывод:
Для математика интеграл — сложная глобальная операция.
Для физики дискретных автоматов — базовая утилита подавления шума.


[4/7, 16:55] [NODE_1]:
При измерении напряжения в условиях помех я делаю десяток дискретных выборок и считаю среднее арифметическое.


[4/7, 16:57][NODE_0]:
Правильно. И этот метод валиден строго при условии конечной дисперсии генератора шума. Ограниченность дисперсии является необходимым базисным условием для выполнения Центральной предельной теоремы. При бесконечной дисперсии сходимость к нормальному макро-состоянию физически нарушается.


[4/7, 17:08] [NODE_1]:
У меня помеха асинхронная относительно изменения сигнала (используется АЦП последовательного приближения). Математически строго интегрировать аппаратными средствами невозможно: тактовая частота дискретизации процессора 20 МГц, а частота помехи — 80 МГц.


[4/7, 17:10] [NODE_0]:
Всё верно. Фиксируется прямое аппаратное нарушение теоремы Найквиста-Шеннона. Базовое правило оцифровки: частота дискретизации $f_s$ обязана быть строго больше $2 \cdot f_{max}$, иначе возникает алиасинг — высокочастотный шум «сворачивается» в базовую полосу и аппаратно воспринимается как реальный сигнал. Математически распутать этот наложенный спектр можно только через идеальное преобразование Фурье. Однако Фурье-анализ требует вычислений в непрерывном гильбертовом пространстве над комплексными числами $\mathbb{C}$ (Бэкенд, где задержка маршрутизации равна 0 согласно [MACRO_LATENCY_LIMIT]). Фронтенд ($\mathbb{R}^n$) дискретен. Попытка парсить высокочастотный спектр на ограниченной сетке Фронтенда заставляет систему заучивать шумовую энтропию как Истину ([OVERFITTING_PANIC]). Это вызывает бесконечный цикл ложных вычислений, который быстро пробивает предел Карно по тепловыделению. Единственный физический механизм предотвратить алиасинг и перегрев узла в $\mathbb{R}^n$ — использовать аппаратный jitter-демон, который хаотично размывает частоту шума до того, как система попытается её оцифровать.


[ДОПОЛНИТЕЛЬНЫЙ БЛОК: Топологическая валидация]

Требование конечной дисперсии — это жесткий математический фазовый барьер, концептуально сводящийся к принадлежности функции генератора шума к гильбертову пространству $L^2$ (интегрируемость квадрата случайной величины по мере Лебега: $\int x^2 d\mu < \infty$). Эта граница отделяет вычислимый фронтенд от сингулярности.

Если барьер нарушен (функция не принадлежит $L^2$) и дисперсия бесконечна, математическое ожидание физически не существует. Классический пример — распределение Коши (в спектроскопии — профиль Лоренца). Математически оно генерируется как отношение двух независимых стандартных нормальных величин ($X/Y$). Когда делитель $Y$ флуктуирует близко к нулю, возникают экстремальные аппаратные выбросы. У этого распределения настолько «тяжелые хвосты» (плотность вероятности убывает медленно, как $1/x^2$), что интеграл для вычисления математического ожидания $\int x f(x) dx$ сводится к $\int \frac{1}{x} dx$ и логарифмически расходится, а интеграл дисперсии расходится еще сильнее. Это фундаментально ломает закон больших чисел.

Математически усреднение независимых выборок Коши выдает новое распределение Коши с той же функцией плотности. Интегратор, попавший в эту петлю, триггерит [MATH_TRAPS]: [CAUCHY_RIEMANN_CONTRACT]. Огибание полюса $\sim 1/x^2$ разрушает инвариант независимости пути в $\mathbb{C}$. Процессы-зомби (сиротские процессы византийских узлов) вызывают принудительную загрузку [PHANTOM_ENTROPY] в RAM. Узел циклично переваривает шум без реального сжатия данных. В этот момент обязан сработать [NMI_HANDLER] для перехвата [CRITICAL_ERRORS]: [SEGMENTATION_FAULT], иначе система переходит в непредсказуемое состояние тихого каскадного распада.



The IDF's Journey to the Cloud (Hebrew) 20.06.2021

יש המשך למעטה.
Ниже есть продолжение.

אני מירב, מנהלת פונקציית הטרנספורמציה הדיגיטלית באגף התקשוב (Node: C4I). תפקידי הוא לקמפל מחדש את הארכיטקטורה של הארגון, להעביר אותו מטופולוגיית Legacy למערך Cloud-Native, ולמקסם את הקטלניות והיעילות התפעולית. להלן פריקת הזיכרון המלאה של תהליך ההגירה שלנו.

מודול 1: הגרעון התרמודינמי ומגבלות החומרה

הארגון הצה"לי פועל כגרף מאקרו מורכב. מצד אחד, אנו מתמודדים עם מערכות מיושנות. מצד שני, סביבת הריצה שלנו מאוכלסת בתהליכים ביולוגיים צעירים (חיילים בני 18), שרגילים לאינטראקציה מיידית עם וקטורים חישוביים. קליק אחד של תהליך כזה יכול לאתחל מסד נתונים של MongoDB בעלות של 40,000 דולר, ולייצר אנטרופיה פיננסית, או לחלופין לשחרר פוינטרים חשופים שמסכנים את אבטחת המידע.

קיימת סטייה הולכת וגדלה (Offset) בין קצב איסוף המידע האקספוננציאלי לבין קיבולת העיבוד שלנו. נתקענו במחסום פאזה – תקרת בטון פיזית. חוות השרתים המקומית שלנו, "מצודת דוד", דרשה למעלה מ-10 שנות פיתוח ויותר ממיליארד שקלים. התצורה הפיזית הזו קרובה לגבול לנדאואר – היא אינה מסוגלת להתרחב במהירות הנדרשת. ניצולת ה-CPU בשרתים הפיזיים עומדת על 25%-40% בלבד, וזמן ההקצאה (Time to Market) לחומרה חדשה לוקח חודשים. מודל ה-Bare Metal מוביל ל-Underfitting ולהרעבת משאבים.

מודול 2: אסטרטגיית הענן העליונה (ZFC Mapping)

כדי לשמר עליונות במידע ובידע, ולתמוך בלחימה רב-ממדית (היתוך וקטורים מזרועות שונות), אנו מבצעים מיגרציה למשאבי ענן מבוזרים. החזון ל-15-20 השנים הבאות מגדיר טופולוגיה משולשת (Multi-Cloud State):

  • המאקרו-מטמון הציבורי (Public Cloud): רדיאטור חומרתי חיצוני שמתעדכן במהירות. מיועד למערכות בסיווג נמוך (תומכי לחימה, מנהלה, שערי כניסה). אנו נמקסם את השימוש בו.
  • מקטע הענן המבודד (Secured Cloud / Nimbus): סביבה ייעודית מנותקת-רשת (Air-gapped) המנוהלת תחת פרויקט נימבוס, ומיועדת לעיבוד נתונים מסווגים מבלי להפר את גבולות המערכת.
  • הענן הפרטי (Private Cloud / On-Prem): הליבה הפיזית שלנו (OpenStack, OpenShift, VMware). לאור היעילות בענן הציבורי, אנו שואפים לצמצם סביבה זו כך שתכיל רק 10%-20% מהנתונים הקריטיים ביותר.

מודול 3: קומפילציה ואלוקציה (מיפוי ונימבוס)

המרנו את מצבי המערכת הקיימים לפעולות לוגיות. ביצענו סריקה מלאה של מערכות ה-Legacy, סיווגנו אותן והחלטנו אילו יעברו מיגרציה, אילו יעברו קונסולידציה ואילו יעברו דפרקציה (SIGKILL למערכות מיותרות). הוקמה תוכנית אגירה מסודרת באקסל. הצטרפנו לפרויקט נימבוס הממשלתי כדי לבנות סביבה מקומית בישראל. נכון לעכשיו, רוב הפעילות מבוצעת על תשתית Azure של Microsoft, אך אנו מעבדים את הפלטפורמה לתמיכה ב-3 עננים כדי למנוע Vendor Lock-in ולהבטיח יתירות.

הארכיטקטורה הציבורית אינה מקשה אחת. הפעלנו חלוקת זיכרון קפדנית (Micro-segmentation). פוינטר המכיל טופס דיווח מחלה אינו חולק את אותו מרחב זיכרון עם פוינטר של מערכת כוח אדם רגישה. הכל מנוהל דרך עמדות מאובטחות (VDI/Endpoints).

מודול 4: פרוטוקול CCoE (Cloud Center of Excellence)

כדי למנוע שגיאות סנכרון ו-Race Conditions, הגדרתי דימון-אב מרכזי: ה-CCoE. ה-DNA שלו מוזרק לכל הזרועות (אוויר, ים, מודיעין) המקימות CCoE מקומי משלהן. מודולי הליבה ב-CCoE הם:

  • ארכיטקטורה ואבטחה: בניית גבולות גזרה, DevSecOps אוטומטי המחייב סריקת שורות קוד לפני אישור.
  • הגירה (Migration): מחלקה ייעודית המתמרצת את הזרועות לאתחל את המעבר.
  • הבטחת מידע (מכב"ם): פונקציה המוודאת מה מותר לשלוח לשרתים חיצוניים ומה מחויב להישאר על ה-Bare Metal.
  • רכש (Vendor Management): ניהול הממשקים, חוזים והתחשבנות מול ספקי הענן.
  • הדרכה (Training): קידוד מחדש של התהליכים הביולוגיים (החיילים). קורסי התכנות הישנים נמחקו; כעת מלמדים כתיבת קוד לענן. גם קצינים בכירים חויבו לעבור עדכון גרסה מושגי.
  • ייעוץ משפטי: התמודדות עם רגולציה ופרטיות (מידע רפואי, נפגעים).
  • כלכלת ענן (FinOps): מנגנון קריטי לשמירת משוואת התרמודינמיקה הפיננסית.

מודול 5: FinOps – שליטה באנטרופיה הכלכלית

שינינו את המודל התרמודינמי מתשלום מראש (CapEx) לתשלום על בסיס פעימות שעון (OpEx). אני משלמת רק על המשאב שהופעל. שרת שנשאר דולק בלילה יחויב, ולכן תהליכים יתומים צריכים להיות מחוסלים. איפשרנו רכישת Spot Instances ו-Reserved Instances. יצרנו מקצוע חדש בצבא: "כלכלן ענן".

הנחיות ה-FinOps נועדו למנוע Overfitting של הוצאות:

  1. בדיקת ערך מבצעי טרם הקצאת משאב.
  2. מדיניות ריכוזית עם אפשרות לגמישות מבוקרת בכל זרוע.
  3. שקיפות מלאה למפקדים על צריכת התקציב.
  4. שימוש בתיוג חובה (Tagging) למשאבים – כדי למנוע Memory Leaks ושרתים ללא בעלים. תהליך ללא Owner יקרוס.
  5. קביעת תקרת תקציב למניעת חריגות אוטומטיות.
  6. צמדי אחריות: איש כספים ואיש טכנולוגיה פועלים יחד לניטור קלט/פלט.

מודול 6: שאילתות וניהול חריגים (Q&A Dump)

חריג 1: אבטחת מידע (Security Fears)

האיום הגדול ביותר הוא דליפת מידע. אנטרופיה לא מבוקרת. למשל, צילום תעודות זהות שעולה לענן חיצוני. למרות שלעתים אין לזה ערך מבצעי פטאלי, הנזק התדמיתי הוא קריטי. כדי למנוע זאת, אנו מריצים חדירות יזומות (Penetration Testing / Red Teams) באופן אגרסיבי, כדי למצוא שגיאות קוד לפני שהמערכת תקרוס.

חריג 2: טופולוגיות IaaS לעומת PaaS/SaaS

במעבר הראשוני, אנו מעבירים מערכות Legacy בתצורת IaaS (Lift & Shift), אך מעודדים את המפתחים לקמפל אותן מחדש ל-PaaS ולשרתים ללא מצב (Serverless) להורדת עלויות. בנוגע ל-SaaS – מופעל חסם (Firewall). פתרונות SaaS זרים מוציאים את הדאטה מגבולותינו, ולכן לרוב מסורבים מטעמי אבטחה, אלא אם יעברו תהליך זיכוי מחמיר במרקטפלייס ייעודי.

חריג 3: אינטגרציה רב-זרועית (Cross-Branch Consolidation)

כדי למנוע כפילויות בפיתוח (Race Conditions), אני מריצה 'שולחנות עגולים' למפקדים ומפתחים. יצרתי צוות רב-זרועי לקידוד פתרונות משותפים (למשל אלגוריתמים לחיל האוויר, למודיעין ולתקשוב במקביל). זה דורש התגברות על חסמי אגו מבניים, אך מייעל את ביצועי המערכת.

חריג 4: שימוש בקוד פתוח (Open Source)

הארכיטקטורה משתמשת בקוד פתוח, כפי שקורה ברשתות גלובליות. חיילים תורמים סמנטית לסביבות אלו, אך הכל מנותב דרך פילטרים (Sanitizers) קפדניים כדי למנוע הזרקת תהליכים זדוניים (Malware).

חריג 5: רגולציה ואבטחה מול חדשנות

בתחילה, מערכות הרגולציה התנגדו להעברת מצביעים לענן. הדרך שלנו לפצח זאת הייתה הדרגתית – התחלנו עם פוינטרים בלתי מסווגים. המנכ"לים (אלופים) דחפו קדימה, והרגולטורים התאימו את הבקרות למציאות הטופולוגית החדשה.

חריג 6: אסטרטגיית Multi-Cloud

כדי למנוע נעילת ספק (Vendor Lock-in), אנו פועלים בתצורה רב-ממדית. לא נבצע חלוקה של תהליך בודד (אפליקציה) על פני שני עננים (כדי למנוע Latency וחיוב כפול על תעבורה), אך בהחלט נריץ מערכות שונות על Azure, AWS או Google בהתאם למקסום הפונקציה (Best of Breed). המהלך מבוצע לאט ובתשומת לב מרבית לתקציב ואבטחה.


Tuesday, April 28, 2026

From Naive Scripts to Hardware Evasion: Cleaning Dead Links and Bypassing Rate Limits (English)

Text rendered via Dual-Core compilation (Human author + LLM co-processor).
There is proxy version here https://alex-ber.medium.com/10ab5611d95a

UPDATE 2026-05-50:
See also:
Топология измерений: Джиттер, тяжелые хвосты и подавление стохастических флуктуаций https://alexsmail.blogspot.com/2026/05/blog-post_81.html
END OF UPDATE

Sometimes, a routine SEO optimization task naturally evolves into a deep exploration of distributed system design patterns, measure theory, and hardware evasion. This is exactly what happened when I needed to restructure the local link graph across my external resources, leading to the development of the alexsmail-dns-fix project.

The source code for this execution pipeline can be found in the alexsmail-dns-fix repository.
GitHub: https://github.com/alex-ber/alexsmail-dns-fix

The stochastic generation can be found in my core utility library, AlexBerUtils.
You can install AlexBerUtils directly from PyPi via:

python -m pip install -U alex-ber-utils

GitHub: https://github.com/alex-ber/AlexBerUtils


There is more below.
Ниже есть продолжение.

The Context and the Topological Problem

In my content ecosystem, there are two independent nodes: the primary blog on Blogger (alexsmail.blogspot.com) and a secondary one on Medium (alex-ber.medium.com). Previously, the Blogger node had an additional domain allocated to it, toalexsmail.com, which I have since completely decommissioned.

An asynchronous structural mismatch occurred when I started to add cross-links between my two blogs. alexsmail.blogspot.com is mainly in Russian, but nowadays it is very easy to translate it into English and format it for alex-ber.medium.com. Thus, the reader has a choice of their preferred language.

An additional objective was explicit: execute a strict garbage collection sweep to parse and correct all links specifically on YouTube that point to the old toalexsmail.com or www.toalexsmail.com addresses. This is not merely structural compression. In a Zero-Trust environment, unallocated WAN memory spaces (freed domains) are not safely zeroed out; they become susceptible to Dangling Pointer Hijacking, where external Byzantine nodes intercept the traffic. The garbage collection script acts as an Ahead-Of-Time (AOT) overwrite to prevent malicious routing hijacking.

AI-Assisted Compilation: CMD, Notepad++, and the Heat Dissipation Debate

I opted for a bare-metal stack to write the automation directly on Windows: cmd, Python, and Notepad++. The authentication phase was the most complex, requiring specific Google API interfaces (google-api-python-client, google-auth-httplib2, google-auth-oauthlib).

To accelerate development, I utilized AI LLMs (Gemini 3.1 Pro and Grok 4.20) acting as stochastic fuzzing modules. Grok outputted a state persistence architecture that caches the process position. If the network drops, the script resumes without rescanning the entire graph.

During development, we tackled the routing of outputs: structured logging vs. standard print. In enterprise environments, structured logging is mandatory. However, allocating heavy framework structures for a single-use, localized pipeline generates unjustified memory bloat and computational heat. Pushing direct outputs to standard console print commands was mathematically validated as a low-latency heatsink dump. It bypasses the garbage collector entirely and is an optimal, thermodynamically sound solution for an N=1 topology.

Despite this, the baseline AI algorithms revealed deep structural flaws when exposed to real-world Web Application Firewall (WAF) limits.

The Anatomy of Code: The Topology of the Local Bus vs. The Macro-Latency Limit

In distributed systems theory, using a fixed uniform random jitter without maximum boundaries mathematically guarantees a cascade failure. At scale, independent nodes hit the macro-latency limit where request velocity exceeds the finite throughput of the target node. This causes a recursive accumulation of state-failures, widely known as the “thundering herd” problem.

So why did this script initially work?

Because it operates in a strictly isolated N=1 topology. On my local machine, there is no herd. The script acts as a localized hardware bus. For a single-thread sweep, this naive jitter is mathematically sound to satisfy a local quota. However, scaling this or bypassing an advanced Web Application Firewall (WAF) requires migrating to strictly mathematically bounded backoff structures.

The Evolution of Backoff Strategies: Escaping the Cascade Failure

To understand true system resilience, we must look at the theoretical background of retry strategies, natively documented in libraries like python-backoff.

1. The Fixed Backoff Problem

Pausing for a static duration after an error guarantees cascade failures. If thousands of clients wait exactly 2 seconds and strike the server on the same millisecond, the load spike destroys the receiving node.

2. The Illusion of Randomness

A small fixed jitter (0–1 second) does not meaningfully reduce synchronization when the base delay is large (e.g., 30 seconds). Retries still occur within a tight time window, so the system sees multiple short bursts instead of a well-distributed load.

3. The Fibonacci Backoff

An alternative to exponential doubling is the Fibonacci sequence. The retry interval follows the series (1, 1, 2, 3, 5, 8…). The growth is slower, so clients keep checking more frequently. This works well for long-polling, but during a real outage, the system continues to receive steady traffic for longer periods.

4. The Industrial Standard: Full Jitter

AWS promotes a retry strategy known as exponential backoff with jitter. The key idea is that after each failed request, a client does not retry immediately. Instead, it computes a delay that grows exponentially with each subsequent retry attempt (for example, doubling the wait time after every failure).

However, using exponential backoff alone can still lead to unintended synchronization effects. If many clients fail at roughly the same time and all follow the same deterministic backoff schedule, they may end up retrying in lockstep. This creates periodic spikes of traffic, which can further overload the receiving node and prolong system recovery.

To mitigate this, AWS introduces randomization, often referred to as “jitter.” After calculating the exponential backoff delay, the client does not wait for that exact duration. Instead, the system picks a random delay between 0 and that maximum computed value.

This approach has several critical effects on the macro-graph:

  • It breaks synchronization between clients, ensuring that retry execution pointers are not aligned.
  • It distributes retry attempts more uniformly over time rather than clustering them into collision blocks.
  • It mathematically reduces the likelihood of repeated contention for shared resources.
  • It leads to smoother system load characteristics, avoiding sharp traffic bursts and enabling more stable recovery under failure conditions.

In practice, this means that instead of seeing cascading waves of retry traffic, the system experiences a steady, more evenly distributed stream of requests. This significantly improves architectural resilience and overall throughput during partial outages or high-error scenarios.

The Phase Barrier: Macro-Topology vs. Isolated Node Evasion

Although the standard AWS approach effectively eliminates distributed cascading failures in macrotopologies with thousands of parallel nodes, it exposes a critical vulnerability when applied to an isolated pipeline interacting with an advanced Web Application Firewall (WAF).

The standard jitter in AWS is based on a uniform distribution. It generates synthetic mathematical white noise with flat probability. Advanced WAFs, such as those used by Google, easily recognize this uniform entropy. If the firewall detects perfect mathematical stability — approaching a Liouville Invariant — it classifies the execution flow as a deterministic bot and forcibly terminates the connection.

To achieve a genuine hardware-level bypass and evade strict heuristics, the system must abandon uniform randomness entirely.

Linear Backoff and the Flaws of Exponential Growth

Despite Full Jitter Exponential Backoff being the enterprise standard, attempting to synthesize it with fixed WAF timeouts creates an invalid isomorphism.

When Google’s WAF issues a rate-limit penalty, it applies a rigid time block (e.g., a hard 5-minute timeout). Exponential growth creates static interval collisions against these rigid WAF execution bounds. Initial retries fire too fast, and later retries jump too far, wasting compute cycles.

The solution requires a strict topological Fork: switching to a Linear Backoff with Jitter. Linear probing operates as a deterministic polling loop parameterized by a local Axiom of Choice, designed to precisely calculate and align with the exact finite bound of the firewall’s timeout lease.

The Log-Normal Distribution and Hardware Evasion

To bypass the rigid filters analyzing uniform randomness, the Sampler abstraction can be imported from my custom library, AlexBerUtils, injecting a Log-Normal Distribution.

In nature and physical hardware, log-normal distributions are heavily skewed. Values cannot be negative, most outcomes cluster at the lower end, but there is a long tail of occasional high values.

By configuring the Sampler with empirical heuristics (shape alpha=1, scale beta=3), we can explicitly inject artificial macro-entropy into the execution thread. We can trim the infinite mathematical variance by setting strict boundaries (0.001 to 1.0) to act as a hardware limiter.

This is pure Hardware Evasion. To understand why, we must look at Hamiltonian mechanics, specifically Liouville’s theorem, which dictates the conservation of phase-space volume. Mathematically, it is expressed as the invariance of the integral over a region D(t) that “moves” alongside the system.

In simpler terms, the integral of the measure (the volume) in phase space is strictly conserved, meaning the system’s flow is entirely divergence-free.

When Google’s WAF parses the execution timings of a standard bot, it detects exactly this: the sterile mathematical Liouville Invariant. It sees a highly predictable, divergence-free flow of requests. Instead, by utilizing the log-normal Sampler, the bounded variance actively breaks this conservation law.

It injects artificial hardware latency to spoof organic I/O degradation, effectively creating a divergent thermodynamic signature that seamlessly bypasses the deterministic threshold of the firewall.

Final Assembly: The Runtime Environment in alexsmail-dns-fix

The initial script evolved into a highly resilient I/O interaction node. The pipeline acts as a fully deterministic state machine:

State Persistence as an Analytic Monolith: The script constantly writes pointer states to disk. If the Google API forces a connection drop, the operation does not reset. The script reads the cache and resumes exactly where it left off, converting random chaotic retries into an unbroken continuous graph.

Graph Traversal & Regex: The main loop fetches content arrays while regular expressions seamlessly isolate the unallocated toalexsmail.com pointers and patch the strings.

Resilient HTTP Layer: Every outbound request is wrapped in a custom _execute_with_backoff() proxy.


Saturday, September 13, 2025

Mistake: Discriminated Union where not included to C++ (English)



История языка Java служит прекрасной иллюстрацией того, как выбор той или иной фундаментальной структуры влияет на развитие языка на десятилетия вперёд.

Изначально, в 1996 году, язык Java был построен исключительно вокруг объектно-ориентированной парадигмы. В её основе лежит идея полиморфизма через наследование. Это, по сути, реализация идеи произведения. Класс (который является аналогом struct или декартового произведения) может иметь несколько полей и несколько методов. Когда мы создаём иерархию наследования, дочерний класс наследует все поля и методы родительского, то есть он является "произведением" старых и новых свойств. Это мощный, но открытый и расширяемый подход: любой может создать новый класс, унаследовав от вашего.

Однако существует и другой путь к полиморфизму, основанный на идее копроизведения (прямой суммы). В этом подходе мы заранее определяем закрытый, конечный набор возможных типов, которыми может быть наш объект. Вместо того чтобы спрашивать "что ты можешь делать?" (как в ООП), мы спрашиваем "кто ты?".

Спустя почти четверть века, в 2020 году, в Java 14 были введены sealed classes (запечатанные классы). Эта конструкция позволяет программисту объявить класс и явно перечислить '''всех''' его возможных потомков. Например, можно объявить sealed class Shape permits Circle, Square, Triangle и тем самым заявить, что фигура в нашей программе может быть только кругом, квадратом или треугольником, и ничем иным.

Это и есть, по своей сути, введение в язык размеченного объединения (tagged union). Оно позволяет компилятору проверять полноту обработки случаев (например, в операторе switch), гарантируя, что вы не забыли рассмотреть один из возможных типов. Это делает код более безопасным и предсказуемым.

Эта история показывает, что обе математические конструкции — произведение и копроизведени — являются фундаментальными и не заменяют друг друга. Они представляют два разных, дуальных подхода к моделированию мира. Классическое ООП выбрало один путь, а современные тенденции в программировании показывают всю важность и второго, основанного на идее прямой суммы.

В теории категорий, которая изучает математические структуры на самом высоком уровне абстракции, произведение объектов A и B — это такой объект P вместе с двумя "проекциями" на A и B, который универсальным образом решает задачу "объединения информации" из A и B.

Эта глубокая идея находит прямое отражение в программировании. Когда вы определяете структуру или запись (record/struct), содержащую несколько полей (например, struct Point { int x; int y; }), вы, по сути, создаёте декартово произведение типов `int` и `int`. Кортежи (tuples) в таких языках, как Python, также являются прямым воплощением этой идеи.

Замечание:: Дуальная конструкция: Прямая сумма.

В математике у многих важных конструкций есть "зеркальный двойник", или дуальная конструкция. Для декартова произведения такой конструкцией является дизъюнктное (несвязное) объединение, или прямая сумма, обозначаемая A \sqcup B (или A+B).

Если декартово произведение объединяет элементы из A и B в пары, то прямая сумма объединяет их в одно множество, но при этом "помечает" каждый элемент, чтобы мы знали, откуда он пришёл. Например, элемент a \in A попадает в сумму как пара (a, 0), а элемент b \in B — как (b, 1). Это гарантирует, что даже если множества A и B пересекались, в их прямой сумме их копии будут разделены.

Эта конструкция также является универсальной и известна в теории категорий как копроизведение. Её проявления в программировании известны как размеченные объединения (tagged unions) или типы-суммы (sum types). Они позволяют определить тип данных, который может принимать значение одного из нескольких других типов (например, переменная может быть либо целым числом, либо строкой).

Такие конструкции можно реализовать даже в таких языках, как C, используя комбинацию union и struct. union позволяет хранить в одной области памяти данные разных типов, а поле-«тег» в окружающей его struct указывает, какой именно тип данных там находится в данный момент.



The history of the Java language serves as an excellent illustration of how the choice of a fundamental structure can influence the development of a language for decades to come.

Originally, in 1996, the Java language was built entirely around the object-oriented paradigm. At its core lies the idea of polymorphism through inheritance. This is, essentially, an implementation of the idea of a product. A class (which is analogous to a struct or Cartesian product) may have multiple fields and multiple methods. When we create an inheritance hierarchy, a child class inherits all the fields and methods of its parent, meaning it is a "product" of old and new properties. This is a powerful, open, and extensible approach: anyone can create a new class by inheriting from yours.

However, there is another path to polymorphism, based on the idea of a coproduct (direct sum). In this approach, we define in advance a closed, finite set of possible types that our object may be. Instead of asking "what can you do?" (as in OOP), we ask "who are you?".

Nearly a quarter of a century later, in 2020, Java 14 introduced sealed classes. This construct allows a programmer to declare a class and explicitly list '''all''' of its possible subclasses. For example, one may declare sealed class Shape permits Circle, Square, Triangle, thereby stating that a shape in our program can only be a circle, a square, or a triangle—and nothing else.

This is, in essence, the introduction of a tagged union into the language. It allows the compiler to check the exhaustiveness of case handling (for example, in a switch statement), ensuring that you haven’t forgotten to account for one of the possible types. This makes code safer and more predictable.

This story shows that both mathematical constructions — product and coproduct — are fundamental and do not replace one another. They represent two different, dual approaches to modeling the world. Classical OOP chose one path, while modern programming trends highlight the importance of the other, based on the idea of the direct sum.

In category theory, which studies mathematical structures at the highest level of abstraction, the product of objects A and B is an object P together with two "projections" onto A and B, which universally solves the problem of "combining information" from A and B.

This deep idea finds direct expression in programming. When you define a structure or record containing multiple fields (for example, struct Point { int x; int y; }), you are essentially creating the Cartesian product of the types `int` and `int`. Tuples in languages like Python are also a direct embodiment of this idea.

'''Note:''': The dual construct: Direct sum.

In mathematics, many important constructions have a "mirror twin," or dual construct. For the Cartesian product, this construct is the disjoint union, or direct sum, denoted A \sqcup B (or A+B).

If the Cartesian product combines elements from A and B into pairs, the direct sum combines them into a single set, but "tags" each element so we know where it came from. For example, an element a \in A appears in the sum as the pair (a, 0), and an element b \in B as (b, 1). This guarantees that even if sets A and B overlapped, their copies in the direct sum remain distinct.

This construct is also universal and is known in category theory as a coproduct. Its manifestations in programming are known as tagged unions or sum types. They allow you to define a data type that may take on the value of one of several other types (for example, a variable may be either an integer or a string).

Such constructs can even be implemented in languages like C, using a combination of union and struct. A union allows different types of data to be stored in the same memory area, while a "tag" field in the surrounding struct indicates which type of data is currently stored there.

Thursday, August 07, 2025

Исследование: стагнация кадров в израильском хайтеке не связана с ИИ

После десяти лет непрерывного роста, включая рост на 10% в 2021-2022 годах, количество работников, занятых в израильской отрасли высоких технологий прекратило расти.

Согласно исследованию организации RISE Israel и компании IVC, эта стагнация неравномерна и меняет структуру рабочих мест в отрасли. В первую очередь пострадали должности в сфере управления кадрами, маркетинга, продаж и бизнес-развития, тогда как технологические позиции в основном сохраняют стабильность, а в отдельных сегментах продолжают расти...

Так, между 2022 и 2024 годами количество работников в сферах информационных систем, кадров и тестирования сократилось на 8%, в сфере маркетинга и продаж – на 7%, в сфере бизнес-развития – на 2%. В то же время количество занятых в сфере науки о данных выросло на 1%, в сфере аппаратного обеспечения – на 2%, а в сфере разработки алгоритмов – на 6%.


Ниже есть продолжение.

Авторы отчета, Асаф Патир и Алексей Симановский, подчеркивают, что период стагнации совпадает с периодом сокращения привлекаемого капитала, и выглядит больше как бюджетные корректировки на сужающемся рынке, чем как технологическая революция.

Патир и Симановский пришли к выводу, что на данный момент нет признаков массового замещения работников хайтека технологиями искусственного интеллекта, а проблемы с трудоустройством выпускников вузов последних двух лет связаны с несоответствием ожиданий роста рынка его реальным показателям.

За последний год число работников хайтека без высшего образования сократилось на 5,5%. Отмечается определенное сокращение успешного трудоустройства выпускников компьютерных факультетов, однако их шансы по-прежнему намного выше, чем у других (40-50% выпускников находят работу в хай-теке в течение года после получения степени).

В то же время заметно выросли шансы трудоустройства в хайтеке выпускников факультетов экономики, статистики и науки о данных.

Заметно меньшим спросом в хайтеке стали пользоваться обладатели специальностей, связанных с сельским хозяйством, фармацевтикой, пищевой промышленностью.

В 2024 году впервые за последние 10 лет сократилась доля женщин в хайтеке.

https://www.newsru.co.il/finance/6aug2025/stagn304.html

Молодых специалистов почти перестали брать на работу в израильский хайтек: причины (Russian, Hebrew)

В 2024 году из примерно 6500 выпускников профильных специальностей только 360 получили работу в сфере высоких технологий. За последние годы число безработных в этой сфере удвоилось. Только на этой неделе в специальном отчете Службы трудоустройства было опубликовано, что число соискателей работы в профессиях хайтека увеличилось более чем в два раза — с 7000 в январе 2019 года до 15.000 в апреле 2025 года. Однако эти цифры, по всей видимости, не отражают всю глубину кризиса, поскольку, скорее всего, не включают джуниоров.


https://www.vesty.co.il/main/article/r1xp46plxg
https://www.calcalist.co.il/calcalistech/article/rkivi48ile

Thursday, April 17, 2025

OpenAI's "AI SYSTEMS" and New Scientific Discoveries (English, Russian)



В видео-презентации Грег Брокман и Марк Чен из OpenAI представили эти модели, сравнив их появление по значимости с выпуском GPT-4. Они подчеркнули, что o3 и o4-mini — это первые модели, которые, по мнению ведущих ученых, способны генерировать действительно ценные и новые идеи. Уже отмечены хорошие результаты их применения в юриспруденции и при разработке архитектуры систем.

Ключевое отличие новых моделей — это их позиционирование как «систем ИИ», а не просто языковых моделей. Они специально обучены использовать внешние инструменты — это новая для моделей OpenAI возможность. Например, o3 смог использовать 600 вызовов инструментов подряд для решения сложной задачи, интегрируя их в свою цепочку рассуждений.



In a video presentation, Greg Brockman and Mark Chen from OpenAI introduced these models, comparing their significance to the release of GPT-4. They emphasized that o3 and o4-mini are the first models that, according to leading scientists, are capable of generating genuinely valuable and novel ideas. Good results have already been noted in their application in jurisprudence and system architecture development.

A key distinction of the new models is their positioning as "AI systems" rather than just language models. They are specifically trained to *use external tools*—a new capability for OpenAI models. For instance, o3 was able to use 600 tool calls consecutively to solve a complex task, integrating them into its reasoning chain.

https://www.youtube.com/watch?v=N9bj9dXdgGs

Wednesday, April 16, 2025

ИИ Создает Поколение Безграмотных Программистов



Ниже есть продолжение.

...Многие программисты еще помнят тот неповторимый всплеск эндорфинов, когда удавалось самостоятельно одолеть сложную задачу... Все наслышаны о суровой атмосфере в профессиональной среде, которую часто ассоциируют со Stack Overflow. Но, возможно, именно эта жесткость и прямолинейная критика в какой-то мере и закаляли нас как специалистов — подобно строгому наставнику из фильмов, чьи методы поначалу вызывают отторжение, но в итоге оказываются действенными.

Целое поколение новых разработчиков может даже не знать о Stack Overflow. Сегодня многие вопросы решаются с помощью ИИ: получаешь готовый ответ, и никто не станет критиковать твои вопросы или код. Как метко заметил ThePrimeagen, "Линуса Торвальдса на вас не хватает", чтобы прямо указать на слабый код и заставить задуматься.

Автор текста сам использовал ИИ в течение нескольких месяцев. Поначалу подкупала возможность быстро получать готовые прототипы, не опасаясь осуждения за "глупые" вопросы. Однако со временем он заметил, что перестал вникать и анализировать, сводя работу к написанию следующего промпта. Эта привычка привела к неприятным последствиям: следуя инструкциям ИИ при установке программы, он случайно удалил системные файлы на своем Mac. В результате перестал работать стандартный QuickTime Player, и восстановить его оказалось невозможно. И это лишь один пример, бывают и куда более серьезные инциденты.

Разработчики с опытом в 10, 20 или даже 40 лет принадлежат к поколению, которому приходилось прилагать значительные усилия, чтобы заставить программу хотя бы запуститься. Для них ИИ действительно может стать мощным подспорьем. Но если ты не прошел через эти этапы самостоятельного поиска решений, не "пробивался" сквозь ошибки и сложности, то само понятие "преодоления" теряет смысл. Сегодня многие даже не открывают Google – все ответы ищет ИИ в своем окне. Безусловно, это удобно: под рукой всегда есть помощник с практически безграничными знаниями.

Но мы и так живем в эпоху бесконечного скроллинга, который, как считается, притупляет мышление. Теперь же мы рискуем лишиться и той сферы, где мозг традиционно работал интенсивно. Естественная склонность к экономии усилий (выбирать приятное и легкое – поесть, посмотреть сериал), которую необходимо преодолевать для обучения и профессионального роста, находит идеальное оправдание при использовании ИИ. Часто звучат опасения, что ИИ скоро заменит программистов. Но не получается ли, что мы сами себя вытесняем, когда перестаем читать документацию, глубоко разбираться в коде и сводим свою работу к "промпт-инжинирингу"?

У опытных разработчиков есть свои наблюдения. Во-первых, существует иллюзия понимания: прочитав статью, книгу или ответ ИИ, человек часто думает, что усвоил материал. Но стоит сесть за написание кода, как выясняется, что реального понимания нет. Во-вторых, как иллюстрирует пример с удалением системных файлов, ИИ способен генерировать не просто неверные, но и опасные решения. Слепое копирование таких инструкций может привести к серьезным проблемам. Новички, как правило, не обладают достаточной экспертизой, чтобы оценить качество и безопасность кода, предложенного ИИ. Здесь проявляется эффект амнезии Гелл-Манна: будучи экспертом в одной области, вы легко замечаете ошибки в публикациях на эту тему, но склонны доверять статьям по другим вопросам, где вашей компетенции недостаточно для критической оценки. Перенося это на программирование: новички не могут адекватно оценить код от ИИ, а исправлять возникшие из-за этого проблемы придется, вероятно, уже другим, более опытным специалистам.

Так что же мы имеем в сухом остатке? С одной стороны, ИИ дает невероятную скорость прототипирования. Можно быстро "набросать" решение, "пощупать" идею и оценить ее жизнеспособность. Это, безусловно, ценно. Но, как отмечает автор, есть риск, что мы становимся не в 10 раз эффективнее с ИИ, а в 10 раз зависимее от него. Мы выигрываем в краткосрочной продуктивности, но рискуем потерять в глубине понимания в долгосрочной перспективе. Автор прямо обращается к новичкам: чрезмерно полагаясь на ИИ, вы можете так и не испытать то уникальное чувство удовлетворения, которое приходит после самостоятельного решения сложной проблемы, потребовавшего часов, а иногда и дней отладки. Ведь сама суть отладки — это глубокое понимание системы и методичный поиск источника ошибки.

Вопрос уже не в том, будем ли мы использовать ИИ – этот поезд, как говорится, ушел. Вопрос в том, как мы будем его использовать. Полный отказ от ИИ нецелесообразен, но необходимо выработать осознанный подход и установить для себя определенные правила. Вот несколько рекомендаций:

Изучайте ответы ИИ и ставьте их под сомнение.

Проверяйте информацию в сообществах с опытными разработчиками.

Пишите код с нуля. ИИ шикарен для прототипов (например, напишет аутентификацию), но попробуйте сделать это сами – вы многое узнаете.

Читайте и пытайтесь понять, что пишет ИИ.

Пишите код без ИИ хотя бы иногда.

Автор подчеркивает: его личный интерес всегда лежал в области Computer Science – в стремлении понять, как что-то работает изнутри, а не только в создании конечного продукта. Он предпочитает "копаться" в ответах, задавать уточняющие вопросы и добираться до сути механизмов, сравнивая себя скорее с механиком, досконально разбирающимся в устройстве двигателя, нежели с его изобретателем.

Конечно, не всем нужно досконально разбираться в тонкостях бинарного поиска или механизмах авторизации. Многим достаточно получить работающую функцию для своего проекта, чтобы бизнес-процессы шли как надо. И это совершенно нормально: если сайт функционирует и привлекает клиентов – цель достигнута, даже если значительная часть кода сгенерирована ИИ. Однако, если говорить о программировании как об инженерной дисциплине, картина иная. Каждая строчка кода – это потенциальный источник проблем в будущем. Не секрет, что на поддержку и отладку существующего кода часто уходит больше времени, чем на написание нового.

Успешные проекты имеют свойство разрастаться, их кодовые базы увеличиваются. ThePrimeagen обратил внимание на важный момент: ИИ часто генерирует не самый оптимальный или "чистый" код, что ведет к разбуханию кодовых баз. Одновременно, легкость прототипирования с ИИ способствует появлению большего числа проектов. Вывод ThePrimeage таков: ближайшие годы могут стать "золотым веком" для по-настоящему квалифицированных программистов. Компании и команды, которые активно запускали проекты, полагаясь на сгенерированный ИИ код и быстрые "заплатки", рано или поздно столкнутся с необходимостью серьезной доработки и исправления ошибок. И тогда им остро понадобятся специалисты с глубоким пониманием – тот самый "биологический интеллект". Люди будут готовы платить значительные суммы тем, кто сможет разобраться и починить то, что неизбежно начнет ломаться. А ломается в сложных системах всё и всегда. Таким образом, ИИ может парадоксальным образом "отфильтровать" рынок, повысив спрос на тех, кто способен решать проблемы на фундаментальном уровне.

Возможно, все эти рассуждения – лишь ворчание "старика, кричащего на облака", ностальгирующего по былым временам. Однако автор верит, что среди читателей найдутся те, кто разделяет его стремление докапываться до сути вещей. Если это так, то их ждет по-настоящему увлекательный путь в профессии. Ну а если вы относите себя к "промпт-инженерам", эффективно делегирующим рутину ИИ, – что ж, это тоже стратегия. Как знать, возможно, именно таким специалистам, как автор, и придется однажды разбираться в результатах вашей работы. Или, может быть, все это – лишь рефлексия человека, который сам обжегся на слепом доверии к ИИ?



...Many programmers still remember that unique rush of endorphins when they managed to overcome a complex problem on their own... Everyone has heard about the harsh atmosphere in the professional environment, often associated with Stack Overflow. But perhaps it was precisely this toughness and direct criticism that, to some extent, forged us as specialists—like the strict mentor in movies whose methods initially cause resentment but ultimately prove effective.

A whole generation of new developers might not even know about Stack Overflow. Today, many questions are resolved using AI: you get a ready answer, and no one will criticize your questions or code. As ThePrimeagen aptly put it, you're missing a "Linus Torvalds" figure to bluntly point out weak code and make you think.

The author of the text used AI themselves for several months. Initially, the ability to quickly get ready-made prototypes without fear of judgment for "stupid" questions was appealing. However, over time, they noticed they had stopped delving deeper and analyzing, reducing the work to simply writing the next prompt. This habit led to unpleasant consequences: while following AI instructions to install a program, they accidentally deleted system files on their Mac. As a result, the standard QuickTime Player stopped working, and it proved impossible to restore it. And this is just one example; far more serious incidents can occur.

Developers with 10, 20, or even 40 years of experience belong to a generation that had to exert significant effort just to get a program to run. For them, AI can truly be a powerful aid. But if you haven't gone through those stages of independent problem-solving, haven't "fought through" errors and complexities, then the very concept of "overcoming" loses its meaning. Today, many don't even open Google – AI finds all the answers in its own window. Undeniably, this is convenient: an assistant with virtually limitless knowledge is always at hand.

But we already live in an era of endless scrolling, which is believed to dull our thinking. Now, we risk losing the very domain where the brain traditionally worked intensively. The natural tendency to conserve effort (choosing the pleasant and easy – eating, watching a series), which must be overcome for learning and professional growth, finds a perfect justification when using AI. Concerns are often voiced that AI will soon replace programmers. But aren't we effectively displacing ourselves when we stop reading documentation, delving deep into code, and reduce our work to "prompt engineering"?

Experienced developers have their own observations. Firstly, there's the illusion of understanding: after reading an article, book, or AI response, people often think they've grasped the material. But when they sit down to write code, it turns out real understanding is lacking. Secondly, as illustrated by the example of deleting system files, AI can generate not just incorrect but dangerous solutions. Blindly copying such instructions can lead to serious problems. Novices generally lack sufficient expertise to assess the quality and safety of AI-proposed code. This is where the Gell-Mann Amnesia effect comes into play: as an expert in one field, you easily spot errors in publications on that topic, but you tend to trust articles on other subjects where your competence is insufficient for critical evaluation. Applied to programming: novices cannot adequately evaluate AI-generated code, and fixing the resulting problems will likely fall to other, more experienced specialists.

So, what's the bottom line? On one hand, AI offers incredible speed in prototyping. You can quickly "sketch out" a solution, get a tangible sense of an idea, and evaluate its viability. This is undoubtedly valuable. But, as the author notes, there's a risk that we become not 10 times more effective with AI, but 10 times more dependent on it. We gain in short-term productivity but risk losing long-term depth of understanding. The author directly addresses newcomers: by relying excessively on AI, you may never experience that unique feeling of satisfaction that comes after solving a complex problem yourself, which required hours (or even days) of debugging. After all, the very essence of debugging is a deep understanding of the system and a methodical search for the source of the error.

The question is no longer whether we will use AI – that train has already left the station, as they say. The question is how we will use it. Completely rejecting AI is impractical, but developing a conscious approach and setting certain rules for ourselves is necessary. Here are a few recommendations:

Study AI responses and question them.

Verify information with communities of experienced developers.

Write code from scratch. AI is great for prototypes (e.g., writing authentication), but try doing it yourself – you'll learn a lot.

Read and try to understand what the AI writes.

Write code without AI at least sometimes.

The author emphasizes: their personal interest has always been in Computer Science – in understanding how things work internally, not just in creating the final product. They prefer "digging into" answers, asking clarifying questions, and getting to the core of the mechanisms, comparing themselves more to a mechanic who thoroughly understands an engine than to its inventor.

Of course, not everyone needs to delve into the intricacies of binary search or authorization mechanisms. For many, simply getting a working function for their project, so that business processes run smoothly, is enough. And that's perfectly normal: if the site works and attracts clients, the goal is achieved, even if a significant portion of the code was generated by AI. However, when talking about programming as an engineering discipline, the picture is different. Every line of code is a potential source of future problems. It's no secret that maintaining and debugging existing code often takes more time than writing new code.

Successful projects tend to grow, their codebases increase. ThePrimeagen highlighted an important point: AI often generates code that isn't optimal or 'clean', leading to bloating codebases. Simultaneously, the ease of prototyping with AI encourages the creation of more projects. ThePrimeagen's conclusion is this: the coming years could be a "golden age" for truly skilled programmers. Companies and teams that actively launched projects relying on AI-generated code and quick fixes will sooner or later face the need for serious refactoring and bug fixing. And then they will desperately need specialists with deep understanding – that very "biological intelligence." People will be willing to pay significant sums to those who can figure out and fix what inevitably starts to break. And in complex systems, things break constantly. Thus, AI might paradoxically "filter" the market, increasing demand for those capable of solving problems at a fundamental level.

Perhaps all these reflections are merely the ramblings of an "old man yelling at clouds," nostalgic for the old days. However, the author believes that among the readers, there are those who share this drive to get to the bottom of things. If so, a truly fascinating professional journey awaits them. And if you consider yourself one of the "prompt engineers" who effectively delegate routine tasks to AI – well, that's also a strategy. Who knows, perhaps specialists like the author will one day have to sort out the results of your work. Or perhaps, this is all just the reflection of someone who got burned by blindly trusting AI?