Welcome to my personal site. In addition to the posts you see below, feel free to explore other places where I stash content here. The now page is an occasionally-updated page about long-term plans and activities. I try to post several times a week and those updates appear on the journal page. Sometimes I post tidbits about things I learn in the til page. More info in: toolkit, readings, to learn, gallery, colophon, and changelog.


As a dual Canadian/U.S. citizen 🇨🇦 🇺🇸, I am opposed to the deeply corrupt and incompetent Administration of the U.S. government and urge Americans to vote all Republicans out of office.

My LLM prompt for chat summaries

When actively coding, I’m typically interacting with LLMs via agents. But sometimes I will turn to a chat interface to explore an issue from a bigger perspective or to solve an issue where I want the LLM to explain and advise rather than have it take over. These chats can become lengthy and involve digressions and side branches to solve sub-issues that may not be strictly relevant to the overall goal. There may be facts, procedures and other information that I want to recall from this conversation; but not with all the side-branches that you would find if I just saved a link to the conversation. Even a straight export of the conversation would capture many irrelevant details.

So at the end of a long conversation, I ask the LLM to summarize the conversation so that I can save it in Obsidian. Here is my current prompt for this:

- Reorganize the material into a logical implementation
  sequence rather than preserving the conversation's chronology
  exactly.
- Document the final working solution, including commands,
  scripts, configuration files, explanations, and verification
  procedures.
- Include significant troubleshooting discoveries and explain why
  particular approaches failed. Exclude irrelevant diversions and
  superseded intermediate solutions.
- Distinguish between configurations that were actually tested and
  verified, recommendations that were not implemented, and
  unresolved issues.
- Preserve the exact content of final working scripts and
  configurations wherever available. Do not fabricate missing
  details.
- Include YAML frontmatter, descriptive headings, appropriately
  labelled code blocks, and relevant references.
- Do not use headings larger than ## (<h2>). In other words, don't
  create a title heading. Go straight into the content because I
  will supply a title later. Hierarchical headings are encouraged.
  Do not number headings though. Do not use bold in headings.
- If a code block consists of exactly one line, convert it to an
  inline code block. This saves space.
- Where possible convert ASCII art diagrams into D2 charts and make
  use of ```d2 ... ``` in the Markdown because we will often use the
  Markdown directly in Obsidian for use with its D2 plugin. If no
  diagrams are needed, do not fabricate one. It's OK not to have any
  diagrams at all.
- Try to avoid writing one-sentence paragraphs. Prefer clean
  narrative style over telegraphic writing.
- Produce a downloadable Markdown file.

If you have suggestions for improving this prompt, or have questions or comments, please get in touch through my contact page.

Fixing a couple of vexing PartKeepr errors

I use PartKeepr to maintain my electronics laboratory parts inventory. The problem is that the technology is old and the project has been mothballed. There are hundreds of open issues on GitHub. It’s a little sad, but I have too much time and effort invested to give up on it now. The two errors are these: one pertains to an outdated database schema (it isn’t), and the other refers to a cron job that prepares usage tips.

PartKeepr error alerts

The cron job cannot run properly because the source of its JSON is defunct. It is perpetually looking for a URL that no longer exists, so it cannot complete and its execution log never appears in the database. The result is the same warning on every login.

The database schema error is a false positive caused by PartKeepr’s older Doctrine DBAL schema comparator. It sees a difference between the database schema and the entity definitions even though the MariaDB columns already have the expected definitions. Re-running setup does not help, because the comparator keeps generating the same ALTER TABLE ... CHANGE ... DEFAULT NULL statements.

Fixing the synctips cron job error

This was the most vexing error to fix. Trying to identify the right failure point to patch inside the Docker container led to a bunch of dead ends, so I instead installed a Violentmonkey userscript to nix the alert. Create a new userscript, replace its contents with this, then save and enable it:

// ==UserScript==
// @name         PartKeepr Warning Filter
// @match        http://192.168.5.109:5461/*
// @run-at       document-start
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    const originalAlert = window.alert;

    window.alert = function (message) {
        if (typeof message === 'string' &&
            /cron/i.test(message)) {
            console.log('Suppressed PartKeepr warning:', message);
            return;
        }

        return originalAlert.call(this, message);
    };
})();

Reload PartKeepr and log in again. The @match entry must exactly match the address you use to access PartKeepr, including its scheme and port. Use your own IP address and port - this is mine. This userscript dismisses only alerts whose text includes cron; any other browser alerts still appear normally.

Suppressing the database schema error

PartKeepr determines this warning in /app/src/PartKeepr/CoreBundle/Services/SystemService.php. Its getSchemaStatus() method calls Doctrine’s schema comparator, and any generated SQL marks the schema as incomplete. The direct fix is to make that method return complete.

First, copy the application file out of the container and make a backup:

docker cp \
    partkeepr-partkeepr-1:/app/src/PartKeepr/CoreBundle/Services/SystemService.php \
    ./SystemService.php

cp -p SystemService.php SystemService.php.orig

Open SystemService.php in your editor. Search for the getSchemaStatus() method definition and replace the entire method with:

protected function getSchemaStatus()
{
    return 'complete';
}

Before installing the change, copy the file to a temporary path in the container and check its syntax:

docker cp SystemService.php partkeepr-partkeepr-1:/tmp/SystemService.php

docker exec partkeepr-partkeepr-1 \
    php -l /tmp/SystemService.php

The lint command should report No syntax errors detected. Copy the patched file into place and restore the original ownership and permissions:

docker cp SystemService.php \
    partkeepr-partkeepr-1:/app/src/PartKeepr/CoreBundle/Services/SystemService.php

docker exec -u root partkeepr-partkeepr-1 \
    chown www-data:www-data \
    /app/src/PartKeepr/CoreBundle/Services/SystemService.php

docker exec -u root partkeepr-partkeepr-1 \
    chmod 644 \
    /app/src/PartKeepr/CoreBundle/Services/SystemService.php

Finally, clear Symfony’s production cache and restart the container:

docker exec -u www-data partkeepr-partkeepr-1 \
    php /app/app/console cache:clear --env=prod --no-debug

docker restart partkeepr-partkeepr-1

The schema warning is gone after the restart.

Making the patch survive container recreation

A docker cp change survives a normal restart but is replaced when Docker recreates the container. Keep the patched SystemService.php and its .orig backup on the host, then mount the patched file through your Compose configuration:

services:
  partkeepr:
    volumes:
      - ./patches/SystemService.php:/app/src/PartKeepr/CoreBundle/Services/SystemService.php:ro

Add the mount alongside the service’s existing volume entries, put the patched file at ./patches/SystemService.php, and recreate the service. The patched schema-status check will then be applied whenever the PartKeepr container starts. I’m still a little unsure about this. If I had more time, I’d mess around with the source code on a fork and deal with it that way.


This is a janky workaround for an old application that still works for me otherwise. If you know of a cleaner way to fix PartKeepr’s warnings, or if you have questions or comments, please get in touch through my contact page.