Skip to content

Read and write every text file as UTF-8 - #88

Open
VelitRicardo wants to merge 8 commits into
wandercom:mainfrom
VelitRicardo:utf8-text-io
Open

VelitRicardo wants to merge 8 commits into
wandercom:mainfrom
VelitRicardo:utf8-text-io

Conversation

@VelitRicardo

@VelitRicardo VelitRicardo commented Oct 20, 2026 •

Copy link
Copy Markdown

Summary

Make Kindex's text files UTF-8 on supported Python versions, including Windows. The original commit adds explicit UTF-8 to 117 text-mode calls. Follow-up changes:

  1. Set UTF-8 on the remaining os.fdopen and NamedTemporaryFile text writers, including inbox and scheduler state. Force LF for the tracked index, merge-driver output, and installed instruction Markdown.
  2. Leave invalid UTF-8 inbox items and scheduler state untouched, and report the path and manual repair action. Report invalid .kin/config encountered during project scanning.
  3. Extend the AST guard to text-mode descriptor, temporary, and compressed-file APIs; test non-ASCII bytes and preservation of legacy cp1252 files.
  4. Document manual conversion of confirmed legacy text files in CHANGELOG.md.
  5. Address Adapt feedback on diagnostics and line endings.
  6. Pin tracked .kin text to UTF-8/LF in .gitattributes and add missing rules when generating those artifacts.

Why

Locale-default text I/O can misread UTF-8 files shared through Git or between machines. The repository's tracked .kin/config already contains non-ASCII UTF-8 text. Explicit UTF-8 also keeps behavior stable across Python versions and UTF-8 mode settings.

Compatibility

ASCII files need no conversion. A previously written cp1252 file containing non-ASCII bytes may need manual repair; the changelog gives a copy-first procedure. Kindex does not guess a legacy encoding or rewrite invalid files automatically. Git tracks selected .kin artifacts, while local graph databases are not recoverable from those snapshots.

Test plan

  • The original AST guard fails on the upstream base with 117 offenders and passes on this branch. It was not present on the upstream base; the earlier test-plan wording claiming it passed there was incorrect.
  • Focused encoding and previously failing reminder tests pass after rebasing onto current main.
  • Full local pytest tests/ -q run on an earlier rebased head: 3,926 passed, 4 skipped, 9 subtests passed. Current head: 106 focused tests passed.
  • CI test check on current head bd8ca04: run 40384633455 passed.
  • Native Windows rerun on the final head. The earlier Windows run combined this PR with Run kindex on Windows #89 and predates these follow-up commits.

@VelitRicardo VelitRicardo mentioned this pull request Oct 20, 2026
2 of 3 tasks

@adaptcom adaptcom Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confidence Score: 4/5

Summary

Makes all kindex text I/O explicit UTF-8 (124 call sites, AST-identical otherwise), forces LF on git-shared outputs, and reports instead of resetting legacy non-UTF-8 files. Low risk on Linux/macOS; full suite green except known sandbox-env failures; native Windows rerun still pending.

Important Files Changed

File Overview
tests/test_text_encoding.py Extended AST guard (fdopen, tempfile, gzip/bz2/lzma, io/codecs) plus non-ASCII and legacy-file tests
src/kindex/daemon.py Inbox read strict UTF-8; undecodable items reported via results, left in place
src/kindex/ingest.py Legacy .kin/config reported via record_degraded and unconditional stderr; index.json LF
src/kindex/scheduling.py State read/write UTF-8; non-UTF-8 state raises ValueError instead of reset
src/kindex/cli.py 21 encodings; LF for merge-driver output and CLAUDE/AGENTS/GEMINI.md; cron prints step errors
src/kindex/setup.py 40 encodings; .gitattributes writer still without newline="\n"
src/kindex/hooks.py Inbox writer now UTF-8
src/kindex/claude_install.py _atomic_json and settings reads UTF-8
src/kindex/project_store.py Registry NamedTemporaryFile writer UTF-8
src/kindex/budget.py Ledger read/write UTF-8
src/kindex/subscription_review.py Receipt writer and reads UTF-8
src/kindex/adapters/code.py ctags/cscope list files UTF-8 (file is pre-existing CRLF)
src/kindex/adapters/git_hooks.py 11 hook read/write calls UTF-8
src/kindex/config.py 7 YAML/degraded-event reads UTF-8
src/kindex/adapters/files.py 2 errors=replace reads UTF-8
src/kindex/adapters/claude_web.py 2 JSON reads UTF-8
src/kindex/supervisor_health.py 2 config.json reads UTF-8
src/kindex/code_map.py Graph JSON read UTF-8
src/kindex/conversations.py load_conversations read UTF-8
src/kindex/dream.py Detached log opened UTF-8
src/kindex/kin_merge.py load_json read UTF-8
src/kindex/reinforce.py Transcript tail read UTF-8
src/kindex/reminders.py Codex rollout read UTF-8
src/kindex/routing.py Session JSONL read UTF-8
src/kindex/secret_mask.py Mask file read UTF-8
CHANGELOG.md Documents manual cp1252-to-UTF-8 copy-first repair procedure

Findings

  • src/kindex/scheduling.py:118 — This ValueError reaches kin setup-cron uncaught via setup.install_launchd -> applied_interval (not in main()'s handled list), so a legacy state file yields a traceback; catch there and print the remedy.
  • src/kindex/ingest.py:623 — Unconditional stderr print fires on every cron/scan while the legacy file remains, and record_degraded already persists it; gate on verbose like the rest of this function.
  • src/kindex/ingest.py:827 — _resolve_kin_recursive now raises, but its only entry points (resolve_kin_chain/load_project_context) have no handler or internal caller; scan_kin_files' except catches config._resolve_kin_chain instead. Catch here or drop.
  • src/kindex/setup.py:1486 — .gitattributes is git-tracked yet written without newline="\n" (also 1512 and the Cursor rule at cli.py:6707); add it for consistency with index.json and CLAUDE.md.
  • src/kindex/daemon.py:570 — With several undecodable inbox items, _step_failed overwrites results["errors"]["inbox"] each time, so only the last path is reported; accumulate the paths.

Reviewed 41d0bd3...8fd3307 · ↻ Re-run review · View in Adapt

Comment thread tests/test_text_encoding.py Outdated
Comment thread src/kindex/scheduling.py
Comment thread src/kindex/ingest.py Outdated
VelitRicardo and others added 5 commits October 20, 2026 14:32
117 read_text/write_text/open calls named no encoding, so on Windows
they used the ANSI code page (cp1252) where Linux and macOS use UTF-8:
an imported transfer file was decoded as cp1252 and its content
corrupted, and files shared through git (.kin/index.json rewritten by
the merge driver, CLAUDE.md/AGENTS.md blocks, vault notes) were written
in an encoding other clones cannot read. Every text-mode call now says
encoding="utf-8", which is what POSIX locales already gave; a test keeps
new ones from leaving it out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@blast-hardcheese

Copy link
Copy Markdown
Collaborator

Adapt follow-up on head 8fd3307: all three inline findings have code fixes, replies, and resolved threads. I corrected the PR test plan: the AST guard fails on the upstream base (as intended), and the earlier combined Windows run does not validate this final head. The rebased local full suite passed (3,926 passed, 4 skipped); GitHub CI is now running after workflow approval.

@blast-hardcheese

Copy link
Copy Markdown
Collaborator

I missed the five findings in Adapt's review summary when I previously checked only its inline threads. Follow-up commit 1119c0e addresses them:

  1. setup-cron: the launchd path now prints the scheduler state's repair message and exits with code 2, without a traceback. A CLI test checks this with a cp1252 state file.
  2. Project scan: invalid UTF-8 is still recorded in the degraded ledger and shown by kin status/kin doctor; stderr output is limited to verbose scans so each cron run does not repeat it. Tests cover both paths.
  3. .kin/config inheritance API: the raised UnicodeError is intentional for direct Python callers; it includes the file and copy-first repair guidance and leaves the bytes intact. A test now makes that contract explicit. There is no CLI caller on this path.
  4. Line endings: .gitattributes install/uninstall writes and installed Cursor rules now request LF explicitly.
  5. Inbox: repeated failures for the same step accumulate in results["errors"]["inbox"], so every undecodable item path remains visible. A two-file test checks this.

Validation on head 1119c0e: 3,929 passed, 4 skipped, 9 subtests passed locally. A native Windows run on this final head remains outstanding.

@blast-hardcheese

blast-hardcheese commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Update on PR #88: commit bd8ca04 simplifies the Git attributes follow-up after feedback. The previous version of this comment described checks that have now been removed.

The branch now only pins UTF-8 bytes and LF endings for tracked .kin text in .gitattributes, and adds those rules when kin index, kin export code-map, kin repo-memory publish, or kin setup-merge creates tracked .kin artifacts. Installation is idempotent. The doctor audit, read/write guards, and the large override test module are gone. A small Git test verifies that a global CP1252 attribute does not change a non-ASCII .kin/config blob when the tracked policy is present.

Focused local tests: 106 passed. Native Windows testing remains unavailable; this change relies on Git attribute behavior and does not detect a higher-precedence local override.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants