Export the backlog to ~/src/todo, not the pre-reorganisation ~/todo
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
file-length / file length <= 250 lines (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
release-apk / release (APK) (push) Waiting to run

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Krzysztof Rudnicki 2026-09-12 17:13:21 +02:00
parent 3fd326516b
commit 753e410fb4
7 changed files with 80 additions and 4 deletions

View File

@ -55,6 +55,18 @@ repos:
# rule that a TODO carries "REMOVE ME AFTER FINISH" and nothing else may.
# Shared gate in ~/src/utils owns the namespaces and the exemption list, so
# one repo's idea of a valid name cannot drift from every other repo's.
# Since the 2026-09-11 reorganisation ~ holds eleven visible entries and
# home-tidy sweeps anything else to inbox/ within the hour. The migration's
# rewriter matched *literal* /home/kuhy/<name> strings, so paths assembled
# at run time survived it -- the todo wrapper exported to a dead ~/todo for
# a day while its MCP read ~/src/todo. This gate matches the shape, so it
# stays correct as repos come and go.
- id: home-path-layout
name: home-relative paths stay inside the ~ layout
entry: bash scripts/check_home_paths.sh
language: system
pass_filenames: true
- id: md-naming
name: markdown naming convention
entry: scripts/check_md_naming.sh

View File

@ -39,10 +39,12 @@ Future<void> main(List<String> args) async {
// Overridable so a verification run cannot point at the real backlog: an
// app that starts with an empty store would export over it.
//
// The default comes from [defaultBacklogPath] so it is unit-covered; this
// file is coverage:ignore-file and the path silently broke once already.
final server = WrapperServer(
webRoot: webRoot,
backlogPath:
_argValue(args, '--backlog-path') ?? p.join(home, 'todo', 'BACKLOG.md'),
backlogPath: _argValue(args, '--backlog-path') ?? defaultBacklogPath(home),
logPath:
_argValue(args, '--log-path') ??
p.join(home, '.local', 'share', 'todo-desktop', 'todo_notes.json'),

View File

@ -16,6 +16,19 @@ part 'wrapper_sync_routes.dart';
/// [kSyncAccountEnvVar] as [kSyncAccountPath].
const kSyncCredentialsPath = '/sync-credentials';
/// The canonical backlog file for [home], i.e. `~/src/todo/BACKLOG.md`.
///
/// Lives here rather than in `bin/todo_desktop.dart` so it is covered: the
/// entry point is `coverage:ignore-file` thin wiring, and this path silently
/// broke once already. The 2026-09-11 `~` reorganisation moved every repo
/// under `~/src`, but the migration's rewriter only matched *literal*
/// `/home/kuhy/todo` strings — a path assembled from segments was invisible
/// to it, so the wrapper went on exporting to the dead `~/todo` while the
/// `todo` MCP read `~/src/todo`. Every backlog read between 2026-09-11 and
/// 2026-09-12 got a stale file.
String defaultBacklogPath(String home) =>
p.join(home, 'src', 'todo', 'BACKLOG.md');
/// Local HTTP server backing the desktop app.
///
/// The desktop app is a Flutter **web** build (Flutter's Linux embedder manages

View File

@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.34+1
version: 1.0.35+1
environment:
sdk: ^3.12.2

4
run.sh
View File

@ -78,7 +78,9 @@ install_flutter_debian() {
return
fi
log "no apt package named 'flutter'; cloning the Flutter SDK instead"
local install_dir="${HOME}/development/flutter"
# ~/sdk is the toolchain bucket since the 2026-09-11 ~ reorganisation;
# anything else at ~ root is swept to inbox/ within the hour.
local install_dir="${HOME}/sdk/flutter"
if [[ ! -d "${install_dir}" ]]; then
sudo apt-get install -y git curl
git clone --depth 1 -b stable https://github.com/flutter/flutter.git "${install_dir}"

34
scripts/check_home_paths.sh Executable file
View File

@ -0,0 +1,34 @@
#!/bin/bash
# ============================================================================
# Fail if code builds a ~/<name> path that ~ is not allowed to contain.
#
# Thin delegate to the shared gate in ~/src/utils, which owns the eleven
# allowed root entries and the exclusion list. Copying that logic here is what
# lets one repo's idea of the layout drift from every other repo's -- so this
# script only locates the shared checker and forwards its arguments.
#
# Why it exists: the 2026-09-11 reorganisation's rewriter matched *literal*
# /home/kuhy/<name> strings, so a path assembled at run time was invisible to
# it. The todo desktop wrapper went on exporting to a dead ~/todo for a day
# while its MCP read ~/src/todo, and every backlog read in between was stale.
#
# Usage:
# scripts/check_home_paths.sh <file> [<file> ...] # pre-commit passes these
# scripts/check_home_paths.sh --all [<root>] # whole tree, default cwd
# ============================================================================
set -euo pipefail
readonly SHARED_GATE="${UTILS_ROOT:-$HOME/src/utils}/scripts/check_home_paths.sh"
main() {
if [[ ! -x "$SHARED_GATE" ]]; then
echo "Error: shared gate not found at $SHARED_GATE" >&2
echo "Clone kuhyx/utils to ~/src/utils, or set UTILS_ROOT." >&2
exit 1
fi
exec "$SHARED_GATE" "$@"
}
main "$@"

View File

@ -131,4 +131,17 @@ void main() {
expect(kind('a.bin'), 'application/octet-stream');
expect(kind('a.unknown'), 'application/octet-stream');
});
// Regression: the 2026-09-11 `~` reorganisation moved every repo under
// `~/src`, and this path — assembled from segments — was invisible to the
// migration's literal-string rewriter. The wrapper exported to the dead
// `~/todo` while the `todo` MCP read `~/src/todo`, so every backlog read
// for a day came back stale. Assert the `src` segment, not just the tail.
test('default backlog path is the canonical ~/src/todo/BACKLOG.md', () {
expect(
defaultBacklogPath('/home/someone'),
'/home/someone/src/todo/BACKLOG.md',
);
expect(p.split(defaultBacklogPath('/h')), contains('src'));
});
}