# AUIS Revival Roadmap

Current as of 2026-07-11. See `porting-changelog.md` for the detailed
history behind each completed item.

---

## Current action plan

### Objective: messages demo a.k.a.amsdemo

- ~~Prerequisite: cui~~ — done 2026-07-07, was a missing RESOLVER_LIB link flag, not sgtty
- ~~gendemo~~ — done 2026-07-07: cwd bug (needs to run from `src/ams/demo/`)
  plus a `cui recon` segfault (modern-flex init-flag polarity bug, new bug
  class, see `porting-assessment.md` §13); both fixed, demo folder populates
  and reconstructs cleanly
- ~~Then find the bugs in the demos~~ — done 2026-07-11. Chased through three
  stacked bugs to find the real one:
  1. Caption display: `tm_year` (years since 1900) printed via `%02d`
     instead of `%02d` of `tm_year % 100` — harmless before 2000, wrong
     ("7-Jul-126") once `tm_year` exceeds 99. Fixed in `bldcapt.c`/`shrkdate.c`.
  2. Message ordering: `recon.c`'s sort-by-time comparator had no tiebreak
     for messages sharing the same one-second-resolution `AMS_DATE`; fixed
     with an `AMS_ID` fallback (kept as a general hardening, checked in
     separately from the caption fix).
  3. **Parser bug in `parsedate()` — FIXED.** Root cause: mkparser/cparser.c 
     fixed-width-table assumption affecting all bison-generated grammars tree-wide. 
     Full analysis: porting-assessment.md §15. Result: `gendemo` populates with 
     correct captions and Part 1…23 ordering.
   - Inter-line spaceing in folders and message header panes is double wide.

### Objective: AMS over IMAP/SMTP (kicked off 2026-07-16)

Teach the AMS clients to use IMAP as a mail store and SMTP as a sender,
Fastmail as the test platform. Plan of record:
`revival/doc/ams-IMAP-project.md`; the MS_* server-client interface it
builds on is documented in `revival/doc/ams-server-client-interface.md`
(converted from `ServerCalls.d` via ez2md). Architecture decision: local
`.MS_MsgDir` store stays as the cache (Thunderbird model), sync agent
mirrors IMAP; AMDS delivery remains excluded.

- ~~Milestone 1: SMTP send~~ — **done 2026-07-17**. `tlscon`/`netrc`/
  `smtpsub` modules in `overhead/mail/lib`, `dropoff()` gated on the
  `smtphost` preference, legacy sendmail pipe as fallback. End-to-end
  acceptance passes (`revival/tools/smtp-send-test`: scripted cui →
  SMTP → Fastmail, real send confirmed). Implementation delegated to a
  Sonnet instance against `revival/doc/claude-history/smtp-send-prompt.md` (three
  stages, two review gates). The acceptance push flushed out and fixed
  three latent legacy bugs: cui NULL address-validation crashes (7
  sites), the fdplumb.h open-rename variadic-ABI corruption (see
  `revival.md`, "Old bugs never found"), and client-side dest-host DNS
  validation (now defaults off when `smtphost` is set;
  `validatedesthosts` preference overrides).
- ~~Milestone 2: IMAP spike~~ — **done 2026-07-17**. Full
  CAPABILITY/LOGIN/LIST/EXAMINE/SEARCH/FETCH sequence (read-only,
  including a real 9.6KB body literal) ran against live Fastmail;
  decision: **hand-roll** the IMAP client (§8 of the plan doc now
  records the reasoning). Key transport finding: tlscon's fixed 4KB
  line buffer + missing resync primitive wedge the connection on
  large single-line responses (`UID SEARCH ALL` on a 3,939-message
  mailbox) — growable buffer + reconnect design is milestone 3's
  first task, and sync will target Fastmail's `ESEARCH`/`CONDSTORE`
  instead of naive SEARCH-ALL. Spike driver:
  `src/overhead/mail/lib/imapspike.c`; `tlscon_ReadBytes` added
  (additive; both SMTP regression suites re-passed).
- Milestone 3a — **done 2026-07-18**: tlscon hardened
  (`tlscon_ReadLineAlloc`, growable line reads — the spike's
  `UID SEARCH ALL` wedge case now survives) and `imap_prot.[ch]`
  landed: the tree's first born-ANSI module (full-prototype header,
  scanf banned in favor of strtoul/strcasecmp), ESEARCH-aware,
  streaming body fetch, reconnect-with-UIDVALIDITY-check contract.
  `revival/tests/imap-protocol-tests` 9/9 live against Fastmail; both
  SMTP suites still green. Spec: `revival/doc/claude-history/imap-protocol-prompt.md`.
- Milestone 3b — **done 2026-07-18**: `imapsync`
  (`src/ams/msclients/imapsync/`) mirrors IMAP one-way into a local
  mspath root (`~/.IMAP/fastmail/.MESSAGES/...`) through the store's
  own code via one additive MS entry point
  (`MS_AppendFileToFolderWithId`, caller-supplied id/date). Ids are
  deterministic f(UIDVALIDITY,UID) in base32hex — mixed-case base64
  collided on APFS's case-insensitive filenames (two live pairs hit,
  e.g. `...GvA`/`...Gva`). Flags mapping via `MS_AlterSnapshot`,
  CONDSTORE/HIGHESTMODSEQ refresh skip, `-full-check` expunge marking,
  skip-and-retry on empty body fetches (a live Fastmail
  expunge-during-FETCH race). `revival/tests/imap-sync-tests` 6 cases
  live incl. scripted cui browse; real-mailbox browse in `messages`
  confirmed by hand. Spec: `revival/doc/claude-history/imap-sync-prompt.md`.
  - Latent hazard noted for the wider tree: the store's own
    `ams_genid()` ids are mixed-case base64 too, so every natively
    created message file carries the same (much rarer) case-collision
    risk on case-insensitive filesystems. Not fixed; revisit if a
    native-store collision is ever observed.
  - Close-out regression run surfaced two more real bugs, both fixed
    2026-07-18: (1) `WritePureFile` (`ams/libs/ms/rawdb.c`) unlinked
    its target on *open* failure — under `O_CREAT|O_EXCL` an `EEXIST`
    collision therefore deleted the existing message's body file
    (35-year-old data-loss bug; see revival.md old-bugs); (2) RFC 3501
    `UID n:*` always includes the highest existing uid, so an
    idempotent re-run could re-present the top already-mirrored
    message as a candidate — imapsync now filters candidates at/below
    its watermark and pre-checks the deterministic `+<id>` body file
    before appending (robust even when the store's Message-ID-based
    duplicate check can't catch a re-append).
  - M3c observations from first real browse: mirrored folders need
    Message Folders → Expose All to appear (subscription defaults —
    M3c work item); metamail launch is reported for MIME messages but
    displays nothing (pre-existing platform gap, metamail not
    functional here — HTML mail display now has its own objective,
    see "Objective: HTML mail rendering" below; root cause now
    identified, see that section); first full mirror
    is slow-ish (~3,800 messages;
    per-run incremental cost is near-zero thereafter).
  - **NEW BUG 2026-07-19: messages crashes on exit** —
    `EXC_BAD_ACCESS` in `MS_SetAssociatedTime` (amsn.do), called from
    `captions__MakeCachedUpdates` ← `ams__CommitState` during the
    quit keystroke's `keystate__DoProc`. Faulting address
    `0x16c34214` fits entirely in 32 bits on a platform where heap/
    stack pointers don't — the classic LP64 pointer-truncation
    signature (see porting-assessment §12); crash is at
    `ldr w8, [x21, #0x14]`, i.e. dereferencing a bad struct pointer.
    **ROOT-CAUSED same day** (second capture showed the sign-extended
    twin `0xffffffffb6c34214`, and the user isolated the trigger:
    only after clicking into the mirrored INBOX's captions): LP64
    Variant 1, missing prototype. `FindInDirCache` (defined
    `msdir.c:680`, returns `struct MS_Directory *`) is declared in no
    header; `setasct.c:48` calls it undeclared → implicit-int return
    truncates the pointer to 32 bits, then the cast re-extends
    (bit 31 decides zero- vs sign-extension — both observed
    addresses). The elegant part: the cache-miss sentinel
    `(struct MS_Directory *) -1` survives truncation intact, so the
    `!= -1` guard works and nothing crashes until the directory is
    actually IN the cache (i.e., you visited the folder) and a real
    pointer gets mangled — exactly the observed "clicking into INBOX
    lights the fuse." Long-latent (1991), not a regression; local
    folders were exposed too but the garbage deref only faults when
    the truncated address is unmapped. Fix: one-line
    `extern struct MS_Directory *FindInDirCache();` in setasct.c
    (sole external caller), compile-verified, in tree pending
    runtime confirmation + commit. The build's
    `-Wno-implicit-function-declaration` is why this class is silent
    — standing argument for the M2 prototype sweep.
  - Startup noise logged 2026-07-19, unassessed: `Fontconfig warning:
    using without calling FcInit()` and two `Not a JPEG file` lines
    (libjpeg probing a non-JPEG — source not identified).
  - First real-send observations (2026-07-18, sending from `messages`):
    1. **From-address is `wdc@Mac-mini.lan`** — RESOLVED 2026-07-18.
       `MS_SubmitMessage` (`ams/libs/ms/submsg.c`) deletes any
       user-supplied From and stamps `Me@MyMailDomain`; `MyMailDomain`
       is the cell name = `ThisDomain`, an **AndrewSetup** key
       (`overhead/util/lib/svcconf.c`), falling back to the hostname
       when no AndrewSetup exists — hence the `.lan` From and
       Fastmail's "551 5.7.1 Not authorised" on external relay. Fix
       (no sudo needed): the AndrewSetup search path ends at
       `${ANDREWDIR}/etc/AndrewSetup` (site.h points ANDREWDIR at the
       build tree), so `build/etc/AndrewSetup` containing
       `ThisDomain: fastmail.com` corrects every AMS client at once.
       Verified live: cui send now arrives as
       `From: William Cattey <wdc@fastmail.com>`. Belongs in the
       quickstart doc (M3c deliverable).
    2. **FIXED 2026-07-18: formatted send was default.** 
       Root cause: MS_GetConfigurationParameters LP64 int*/long* mismatch in out-parameters 
       (see porting-assessment.md §12, "By-pointer case"). Plain bodies now auto-strip, 
       formatted bodies offer choice per `mailsendingformat`.
    3. **`<critical:fdplumb>` "File descriptor replaced!" and transient preferences blackout.**
       Gate 1 CLOSED 2026-07-19 by Fable static analysis (see `revival/doc/claude-history/fdplumb-REPORT.md`).
       Key finding: preferences fopen is raw libc (not dbg_fopen), so fdplumb is exonerated 
       for the blackout. Fixes committed: profile.c now retries transient load failures, 
       prints errno, and dbg_dup2/setprof.c crash paths fixed. Remaining: profile.c 
       runtime monitoring of the new errno log (low priority).
    4. **FIXED 2026-07-18: RCPT TO built from a display-form address.**
       dropoff() callers pass full RFC 822 addresses; in particular the
       kept-blind-copy fallback (submsg.c) appends `MyPrettyAddress`
       (`William Cattey <wdc@fastmail.com>`) verbatim to the envelope
       vector when direct insertion of the blind copy fails. smtpsub.c
       then wrapped it in a second bracket pair — `RCPT
       TO:<William Cattey <wdc@fastmail.com>>`. Fastmail answers 250 at
       RCPT time and fails the whole transaction after DATA with
       `501 5.1.3 Bad recipient address syntax`, so *every* recipient is
       reported bad — which is exactly how it presented in the GUI.
       Caught by the user reading an `AMS_SMTP_TRACE=1` transcript.
       Fix: `smtp_addrspec()` in smtpsub.c reduces each tolist entry to
       a bare addr-spec (ParseAddressList, strip comments and display
       phrase, unparse unfolded) at the protocol boundary, healing all
       callers. Reproduced and verified with `smtptest.test` and a
       display-form recipient: 501 before, queued after. Follow-up
       still open: why the blind copy's *direct insertion* fails in
       this setup ("Sending your BCC through the mail after error in
       direct insertion") — with the envelope fixed, keep-blind now
       mails you the copy instead of failing the whole send, but the
       direct-file path should work.
- Milestones 3c–5 (next: 3c, messages-GUI acceptance incl. folder
  visibility): writeback via change journal (4) — **spec written
  2026-07-19: `revival/doc/claude-history/imap-writeback-prompt.md`**
  (now in `claude-history/`, retired 2026-07-23 with M4) (gated,
  Sonnet-executable: per-folder `.MS_Journal` capture at the four MS
  mutation points, replay-then-mirror server-wins ordering,
  drop-and-refetch identity for appends, purge safety valve, all
  destructive tests confined to a dedicated `Revival/WritebackTest`
  mailbox); XOAUTH2 (5).
- **Delegated work queue (written 2026-07-19, for Sonnet-class
  sessions during the budget crunch).** Standing briefing:
  `revival/doc/sonnet-playbook.md` (launch instructions at the top;
  one task per fresh session; STOP-gated; no fossil commits — each
  session ends with a `<task>-session.diff` + `<task>-REPORT.md` in
  the tree root for review). Task prompts, in suggested order of
  attack (safest first):
  1. ~~`strlit-sweep-prompt.md`~~ (now in `claude-history/`) —
     **done 2026-07-23.** Root cause wasn't a file-by-file mutation
     bug after all: `config/darwin/system.mcr` had simply never set
     `-fwritable-strings`, and Apple clang (unlike real gcc since 4.0)
     still implements it — one-line fix plus a full rebuild, verified
     live. A `-Wwrite-strings` scan afterward quantified the scope
     (26,628 literal→`char*` sites, almost all inert boilerplate or
     never-mutated static tables) and a full source cleanup was
     considered and rejected as disproportionate. The three confirmed
     reachable-by-literal call sites got belt-and-suspenders fixes
     anyway. See `porting-assessment.md` issue #1 and
     `claude-history/strlit-REPORT.md`.
  2. ~~`m2-census-prompt.md`~~ (now in `claude-history/m2/`) —
     **done 2026-07-24.** Classified all 67 `int*/long*` and 18
     `char**→char*` instances into 13 shared root shapes and fixed
     three findings: the `char**` cluster's real bug was three
     `CUI_*` methods in `ams.ch` typed `char *` when their `cuilib.c`
     implementations take `char **` (clang's own "remove &" fix-it
     would have broken all 18 correct callers); a live,
     reachable bug via the stretch-goal sweep — `MS_ParseDate`
     writing a class-typed `long *` into a real `int *`
     implementation, hit by `captions__MarkRangeOfMessages`'s
     uninitialized `long` locals; and `fontdesc_StringBoundingBox`'s
     `.ch` signature, the odd one out among its long*-typed siblings.
     All three verified via full rebuild and a human smoke test,
     committed as three separate checkins. The other 45 `int*/long*`
     instances (caller declares `int`, callee wants `long *` —
     stack-overrun direction) are cataloged but not yet fixed. See
     `claude-history/m2/m2-census-REPORT.md`.
  3. `bcc-direct-insertion-prompt.md` — root-cause the blind-copy
     direct-insertion failure (investigation-gated).
  4. ~~`folder-visibility-prompt.md`~~ (now in `claude-history/`) —
     **done 2026-07-22.** Root cause was not subscriptions but a
     site-config global, `AMS_OnlyMail` (defaults to `1` without
     `RUN_AMDS_ENV`), which restricted the default "Expose New" view
     to `$HOME/.MESSAGES` regardless of subscription status. The
     Gate-1 report's own proposal (imapsync auto-subscribe at
     creation) was tested live and falsified before this was found —
     see `revival/doc/claude-history/folder-visibility-REPORT.md`'s
     "Correction" section. Fixed via `AMS_OnlyMail: No` in
     `build/etc/AndrewSetup` (new `revival/tools/write-andrewsetup`
     regenerates it after `make Clean`); mirrored folders now need
     that setting plus Ask/Show-All subscription (not plain Subscribe)
     to appear by default. Documented in `quickstart.md` and
     `mail-quickstart.md`.
  5. ~~`fdplumb-prompt.md`~~ (now in `claude-history/`) — Gate 1 CLOSED 2026-07-19 by a Fable
     session (static analysis; see `revival/doc/claude-history/fdplumb-REPORT.md` and
     M3c item 3 above). Fixes committed. Only the low-priority
     runtime half remains (wait for the new profile warning line to
     fire); do not re-queue as written — the prompt's dbg_fopen
     premise was disproven.
  6. ~~`imap-writeback-prompt.md`~~ (now in `claude-history/`) — milestone 4 writeback. **DONE
     2026-07-23**, all three gates closed and committed (`fb4876a`
     Gate 1 code, `83dc58c`/`6879cdf` Gate 2, `df2a94c`/`164f736` Gate 3
     — see `revival/doc/claude-history/imap-writeback-REPORT.md` for
     the full history and `ams-IMAP-project.md` §7 for the design
     summary). AMS-over-IMAP is feature-complete: capture, suppression,
     flags/purge/append replay, crash-safe resume, all confined to
     `Revival/WritebackTest` in test. One real incident happened and
     was fully resolved mid-arc — a Gate 1 test suite that was safe
     when written became unsafe once Gate 2's replay went live and
     permanently deleted one real ~2009 message from the live account;
     fixed same day, not recoverable, user chose not to pursue further
     recovery. Remaining: a messages-GUI hand test (two-line
     instruction in the Gate 3 report) is wdc's to run, not automated.
  7. ~~`mime-display-prompt.md`~~ (now in `claude-history/`) — **done
     2026-07-21.** MIME body display in `messages`: new `mimepart`
     module (`src/ams/libs/hdrs/mimepart.h` +
     `src/ams/libs/shr/mimepart.c`), wired into `text822.c`:
     multipart/alternative prefers text/plain, html-only mail gets
     the interim tag-strip shim, multipart/mixed lists non-text parts
     as `[attachment: ...]` lines, UTF-8 `text/plain` finally renders
     instead of falling to a dead metamail button. Three gates, all
     closed — see `revival/doc/claude-history/mime-display-REPORT.md`.
     By-hand acceptance against wdc's real mailbox (Gate 3) found and
     fixed two more pre-existing, unrelated bugs that were blocking
     this from working at all: `GetHeader`'s header/body-boundary
     check was CRLF-blind (an entire CRLF-encoded body was being
     swallowed into the "minor headers" display — explains the
     wall-of-headers/tiny-font/undecoded-`=20`/stray-bold symptoms
     wdc first saw, all at once), and `text822.do`'s Imakefile link
     line silently omitted `libmsshr.a` (`-undefined dynamic_lookup`
     masks missing libs at build time; the first real call to a new
     library symbol crashed at runtime — fixed, verified with `nm
     -m`). One follow-on left open: a `multipart/mixed` attachment
     renders as a bare `?` instead of the expected `[attachment:
     ...]` line — root cause not yet found, queued as
     `mime-attachment-icon-prompt.md` (item 8 below).
  8. `mime-attachment-icon-prompt.md` — root-cause the bare-`?`
     attachment-rendering bug above (added 2026-07-21).

### Objective: HTML mail rendering (added 2026-07-19; queued behind milestones 4–5)

Essentially all real-world mail arrives as HTML (usually
multipart/alternative with a text/html part). metamail is not
functional on this platform (launches, displays nothing — see the
M3c observations above, and the root-cause finding below), and even
fixed it would remain an external button-press viewer. For
`messages` to be genuinely useful as a daily reader, text/html
bodies must render **inline** in the message pane via the
htmlview/html inset machinery. Sequencing: start after writeback (4)
and XOAUTH2 (5) close out the store work.

Current state of the pieces:

- htmlview no longer crashes (overlapping-strcpy family, fixed
  2026-07-10) but renders essentially nothing from real-world HTML —
  and that symptom has **never been root-caused**; it may be a few
  gating bugs (DOCTYPE? charset meta? entity handling?) rather than
  wholesale parser obsolescence. See Insets to Repair → htmlview.
- messages' foreign-type display path shells out to metamail
  (`atkams/messages/lib/mailobj.c`); AMS has a header parser
  (`hdrparse`) but no MIME body parser (`ams-IMAP-project.md` §4).
- **metamail root cause identified 2026-07-24** (found during M2
  rollout point 4b's runtime check, `claude-history/
  m2/m2-metamail-REPORT.md`): a plain `text/plain` body run directly
  (`printf ... | metamail`) already crashes with a Bus error before
  any display happens. Under `lldb`, the actual first-hit signal is
  `SIGTTOU` (terminal job-control — a background process group
  attempting a terminal-control `ioctl`), stopped inside
  `ExecuteMailcapEntry`'s `ioctl()` call (`metamail.c`), reached via
  `HandleMessage` → `TryMailcapEntry` → `ExecuteMailcapEntry` — the
  code that forks an external viewer for a mailcap entry and hands it
  terminal control. This is 1980s/90s BSD job-control code
  (companion to the `gtty`/`stty` legacy-syscall macros elsewhere in
  the same file, `sgtty.h`/`sys/ioctl_compat.h`) that doesn't survive
  contact with modern macOS process-group/terminal semantics — a
  different failure category entirely from "displays nothing," and
  unrelated to M2's implicit-declaration fixes (confirmed:
  `ioctl` was already correctly declared before that session touched
  the file, and M2's fixes are additive declarations only, no logic
  changes). Root cause identified, not yet fixed — whoever picks up
  metamail's "separate side quest" (H3 below) should start from this
  finding rather than the mailcap-execution code in general.

**MIME body plumbing moved out of this objective 2026-07-19, done
2026-07-21** — was the `mime-display` task in the delegated work
queue above, spec now retired to
`revival/doc/claude-history/mime-display-prompt.md`, report at
`revival/doc/claude-history/mime-display-REPORT.md`. Delivered: the
quick win (prefer text/plain from multipart/alternative — most mail
now readable with zero htmlview work), CTE decoding, UTF-8→Latin-1
conversion, and an interim tag-strip shim for html-only mail —
confirmed working against a real mailbox message (Gate 3 by-hand
acceptance). What remains here is the real HTML rendering:

1. **H1 — htmlview triage:** build a fixture corpus from real
   Fastmail messages and establish what the ~1994 parser actually
   does with each — root-cause the "renders nothing" symptom before
   designing any rewrite.
2. **H2 — good-enough rendering:** readable text with paragraphs,
   links, emphasis, lists; unknown tags skipped cleanly,
   script/style content dropped, UTF-8 and common entities handled.
   Explicitly NOT: CSS, tables-as-layout fidelity, remote images.
3. **H3 — inline integration:** route text/html parts to an inline
   htmlview inset in the message pane, replacing both the metamail
   button and mime-display's interim tag-strip shim for this type;
   metamail stays the fallback for other foreign types (its macOS
   build remains a separate side quest).

### Objective: Reliable operation

- Let's get all the function prototypes live with ANSI — plan of record
  now at Medium-term → ANSI C conversion (M1–M4)

---

## Little Annoyances to clean up

### Keymap:

- The arrow keys don't work yet
- We don't have a "Meta" key active yet

### make Clean transiently deletes src/atk/adew/Arb:

- adew's `clean::` rule does `$(RM) arb`, which on macOS's
  case-insensitive filesystem deletes the version-controlled `Arb`
  directory entry's file `Arb` (observed 2026-07-10 during the
  batch-11 gate; dependInstall regenerates it and fossil is clean
  again post-gate, so it's self-healing in a full gate but would
  leave the tree dirty after a bare `make Clean`). Pre-existing;
  fix is renaming one of the two or making the rule case-exact.

### messages: X_OpenFont BadValue (observed 2026-07-23, not yet investigated)

- `messages` printed `X error 2-BadValue ... Will ignore operation
  45:0 on resource ID a005b3` (and a005b4, one right after) to the
  terminal during otherwise-normal use (browsing folders after the M4
  hand test). Request code 45 is `X_OpenFont`; the catch-all handler
  (`XErrorsToConsole`, `atk/basics/x/xim.c:696`) logs and ignores any X
  error rather than crashing, so this is non-fatal but real — two font
  loads failed. Plausible candidate for another LP64-class bug (a
  corrupted value reaching the OpenFont request) given this tree's
  track record, and/or related to the known `MK_CONSOLE` font gap —
  not yet distinguished. Not root-caused; needs a dedicated session
  (breakpoint the font-open path, identify which font name/size
  triggered it) before it goes in `porting-assessment.md`.

### ez: horizontal text-block drag locks at position 0 after first drag (observed 2026-07-25, not yet investigated)

- Selecting and dragging a block of text: vertical dragging works
  correctly, but after the first horizontal drag the displayed
  horizontal position reads 0 and stays locked there — further
  horizontal drags have no visible effect (vertical dragging continues
  to work). Found during M2 rollout point 4h's (`contrib/zip/lib`)
  runtime check, unrelated to that session's own declaration-only
  fix — no M2 session has touched any mouse-drag or cursor-position
  code. Not yet root-caused; "locks at exactly 0" is suggestively
  similar in shape to this project's other LP64 sign/width-corruption
  bugs (a coordinate corrupted *to* zero rather than merely wrong),
  but that's a hypothesis, not a finding — needs its own dedicated
  investigation session. See memory `project_text_drag_horizontal_lock`.

### filetype.c DeleteEntry:

- `filetype__DeleteEntry` (atk/basics/common/filetype.c:216,218,
  observed 2026-07-09, logged *before* the basics/common -pi
  rollout — pre-existing, not a regression): passes
  `&defaultMapping.newAttributes` (a `struct attributes **`) to
  `FreeAttributes()`, which walks it as a list node — UB/bogus
  frees if that path ever runs. The enclosing
  `if (strcmp(extension, "*"))` also looks inverted (wipes the
  default mapping when the extension is NOT `"*"`). Compiler flags
  it via -Wincompatible-pointer-types.

---

## Applications to Repair

Applications that currently crash instead of running. All are
pre-existing failures surfaced by first-ever runtime tests during the
M1 rollout — none are `-pi` regressions.

### Overlapping-strcpy crash family — FIXED 2026-07-10, runtime-confirmed

A tree-wide audit (grep for the same-variable idiom `strcpy(x, x+n)`
plus manual read-through of every call site that derives its second
argument from a pointer computed off the first, e.g. via
`index()`/`strchr()`/`rindex()` in the enclosing function) found
**15 overlapping-strcpy call sites across 9 files** — the 3 already
logged here (bush, org, htmlview) plus 6 more never surfaced by a
runtime test. All are the same idiom: an in-place left-shift
(`strcpy(dst, dst+n)` or two differently-named pointers that alias
the same buffer) to delete characters from a string. Apple's
fortified libc's `strcpy` aborts (`EXC_BREAKPOINT` →
`__strcpy_chk` → `__chk_fail_overlap`) whenever src/dst ranges
overlap, even though the classic forward byte-copy this idiom relies
on is safe *precisely for this direction* (dst < src) and has clearly
worked for ~35 years on non-fortified libcs. Fix is mechanical and
semantics-preserving everywhere: `strcpy(dst, src)` → `memmove(dst,
src, strlen(src)+1)` — memmove is defined for overlapping ranges and
produces byte-identical output to what the (unfortified) strcpy
already produced. All 9 files compile clean (zero `error:` lines)
after the fix, checked individually per file, **except** the two
noted as dead-tree below. Full gate (`make Clean && make
dependInstall`) run 2026-07-10: zero real `error:` lines tree-wide
(one hit, the known `-Wdeprecated-non-prototype` false positive);
`bush.do`, `org.do`, `htmlview.do`, `strtbl.do`, `label.do`, and
`gentlex` all reinstalled with fresh timestamps.

- **bush.c:269** (`bush__InitTree`) — root cause confirmed: not the
  originally-guessed `strcpy(p, p+n)` shape. `GivenDirName` is
  `self->given_dir_name`; `bush__Create` calls
  `bush_InitTree(self, GivenDirName)`, so `root_path` and
  `GivenDirName` are the *same pointer* inside `InitTree` — the
  `strcpy(GivenDirName, root_path)` at line 269 is a full self-copy,
  which fortify treats as total overlap. **Runtime-confirmed
  2026-07-10: bush launches** (was: instant crash on every launch).
  New pre-existing bug noticed during this check, NOT related to the
  strcpy fix (bush.c's rendering code was untouched): bush is
  confused about foreground/background colors, and leaf nodes draw
  completely wrong. Needs its own dedicated debugging session —
  logged here so it isn't mistaken for a side effect of this fix.
- **org.c:396** (`Strip()`, called from `Read_Body` at line 192) —
  root cause corrected from what was logged here previously. The
  earlier note named `strcpy(fName, tmpnam(seed))` (org.c:231) as the
  site; re-derivation found that call copies between two independent
  stack buffers (not overlapping) and doesn't match the crash's
  actual call path as convincingly as `Strip()`'s
  `strcpy(string, ptr)` where `ptr = string + (leading whitespace
  count)` — an exact instance of the same aliasing idiom as every
  other confirmed site, sitting directly in `Read_Body`'s control
  flow, and triggered by any node name with leading whitespace
  (routine in org's indented tree format). Fixed at line 396.
  **Runtime-confirmed 2026-07-10: all 3 example `.org` files load
  and work 100%** (was: crash on load). **Separately noted, not
  fixed:** `org.c:231`'s `strcpy(fName, tmpnam(seed))` is still a
  real bug — `seed` is sprintf'd as if it were a naming template,
  but `tmpnam()`'s buffer-argument form just overwrites it, so the
  sprintf'd content is silently discarded. Not an overlap (doesn't
  crash), but wasted work and a misleading read. Left alone pending
  a deliberate decision on temp-file strategy
  (`tempnam()`/`mkstemp()`) — out of scope for a mechanical overlap
  fix.
- **html.c** (`html__ReadSubString`/entity parser) — all 4 sites
  fixed: line 992 (`posStart`/`posEnd+1` alias the same `buf`) and
  the three `strcpy(buf, buf+pos)` sites (now ~1414, 1424, 1462).
  **Runtime-confirmed 2026-07-10: htmlview launches without
  crashing** (was: instant crash on any HTML content). New
  pre-existing issue noticed during this check, NOT related to the
  strcpy fix: no HTML file on hand actually rendered visible text —
  real-world HTML has likely diverged too far from what this ~1994
  parser understands. Separate task, needs its own fixture/triage
  (does it choke on DOCTYPE/charset, on modern tag soup, or
  something else); logged here so it isn't mistaken for a
  regression.
- **atk/supportviews/strtbl.c** (3 sites) and **label.c** (3 sites)
  — identical escape-stripping idiom (`while (t = index(t, '\\'))
  strcpy(t, t+1);` for `\`, `{`, `}`) in `stringtbl__AddString` and
  `label__SetText`. Never hit a coredump — found only by the
  tree-wide grep, and no fixture exists to exercise a label/string-
  table entry containing `\`, `{`, or `}`. **Accepted gate-only**
  (compiles clean, installed, mechanically identical to the 3
  runtime-confirmed sites above) — same precedent as `ptext`/
  `ltext`/`circlepi`/`mit-util` in point-10 batch 11.
- **atk/syntax/tlex/readtlx.c:260** — quote-stripping in the tlex
  grammar reader (`seq` line handling). `atk/syntax/tlex` is a
  build-time code generator (not a runtime app); found only by grep.
  Runtime check: rebuild whatever `.tlx` grammar exercises a quoted
  `seq` argument.
- **contrib/calc/calcv.c:502** — leading-zero digit strip in the
  calculator inset. **Verified 2026-07-11**: `contrib/calc` is now in
  the active build (`MK_CALC`, see "calc inset" under Completed) and
  this fix compiles clean.
- **contrib/mit/fxlib/server/commands.c:230** — same idiom (`.@` realm
  stripping in the MIT `fx` course server). **Still outside the active
  build**: fails to compile for an unrelated reason, a missing
  generated `fxserver_err.h` from a Kerberos code-gen step that's
  never been run in this checkout. Fixed by the same mechanical edit
  for correctness/consistency, but **compile-unverified** — no way to
  build the file right now. Verify whenever `fxlib/server` is ever
  brought into the active tree (same precedent as `wpedita.ch` in
  point-10 batch 11).

### typescript — crashes on launch (PTY failure + missing NULL check)

- First-ever launch of the `typescript` app (2026-07-10, point-10
  batch-6 runtime checks; not a -pi regression: atk/typescript was
  zero-fallout, no `.ch`/`.c` file in the directory was touched).
  Prints `Can't connect subchannel` (from `GetPtyandName` failing —
  suspect PTY allocation doesn't work the way this code expects
  under the current terminal/sandbox), then `EXC_BAD_ACCESS` inside
  `typescript__Create` at the `typescript_SetDataObject(self, ...)`
  call: `self = typescript_New()` came back NULL because
  `InitializeObject` returned FALSE (the pty failure above), and
  `Create` never checks for that before dispatching through `self`.
  Two bugs really — the underlying PTY/subchannel failure (macOS
  PTY compat, not LP64), and the missing NULL check that turns any
  such failure into a crash instead of a clean error return.

---

## Insets to Repair

Insets with known breakage, or not buildable/enabled at all. Each is
its own task; none block M1.

### calc — FULLY WORKING — all rendering bugs fixed, confirmed 2026-07-12

Brought into the active build 2026-07-11 (see Completed → `contrib/calc`
inset). First real interactive exercise (2026-07-11/12) found one real
crash (fixed) and three real Xft rendering bugs, all now fixed. Full
trail, reproduction steps, and what was tried/disproven along the way:
`revival/doc/claude-history/calc-text-rendering-investigation.md`. Summary:

- **Fixed, confirmed:** `calc.c Writer` NULL-pointer crash on every
  document checkpoint (`sprintf`'s `int` return cast to `char *`).
- **Fixed, confirmed via lldb trace:** `xgraphic.c GetXftForeColor` used
  the stale `foregroundpixel` even in `graphic_WHITE` (erase) mode,
  since Xft never consults the core-X GC's color swap — erase-by-redraw
  was drawing in black, not white.
- **Root-caused and fixed 2026-07-12:** the ghost was AA
  erase-by-overdraw residue in `xgraphic_DrawChars`'s Xft path —
  "erasing" a string by redrawing the same glyphs in background color
  only exactly restores pixels where a glyph's alpha is 1; anti-aliased
  edge pixels stay partially gray forever, accumulating with each
  draw/erase cycle. Fixed by filling the glyph's advance-cell rectangle
  with the background color (`XftDrawRect`) instead of redrawing glyph
  shapes, whenever `transferMode == graphic_WHITE`. User-confirmed: no
  more gray residue behind the final answer.
- **Fixed and confirmed 2026-07-12:** a bug surfaced by the ghost fix
  above — during incremental multi-keystroke redraws, the display showed
  only a *suffix* of the correct string (typing `123+4=` showed `1`,
  `2`, `23`, `3+`, `23+4` instead of `1`, `12`, `123`, `123+`, `123+4`),
  and a window focus-loss/regain always corrected it. Root-caused via a
  live `XGetImage` framebuffer readback added to `xgraphic_DrawChars`:
  the server-side drawable consistently had the *correct* pixels even at
  moments the screen showed them missing, proving this wasn't a drawing
  defect but a rootless-XQuartz recomposite lag — Xft/Render-extension
  draws don't reliably reach the visible native window surface without
  an external nudge. Fixed with a self-`XCopyArea` "kick" through the
  core X11 path (known to repaint reliably) after each Xft draw, forcing
  the compositor to pick up the already-correct pixels. This also fixed
  an independently-discovered, broader symptom: text near a calc inset
  staying invisible until unrelated nearby redraw activity revealed it —
  same root cause, not calc-specific. Full writeup:
  `porting-changelog.md`'s 2026-07-12 entry.
- **Intentional design:** the "=" button remains highlighted after being
  pressed, staying highlighted until a different button is pressed — a
  common calculator UI pattern for showing the last-pressed button.
- **Tried and reverted:** a hypothesis that `xgraphic_DrawChars`'s
  alignment math should use the Xft-resolved font's metrics instead of
  the core "dummy" font's metrics (since Xft's fontconfig substitute for
  a custom Andy font could plausibly have different ascent/descent).
  Implemented, tested live, found to make **zero observable difference**
  anywhere (not just calc) — reverted back to original core-only
  metrics, then re-confirmed inert via a side-by-side Frame-animation
  comparison in both states. Not the cause of anything seen this
  session, in either direction.

### zip — builds and loads now; solid-black render bug at `-O`, RESOLVED 2026-07-11

- **Progress 2026-07-11:** `MK_ZIP` defined in `config/site.h`,
  Makefiles regenerated down `contrib/zip/{lib,symbols,samples,utility}`.
  `contrib/zip/lib`'s ~21 `.ch` files were **100% untyped 1990s K&R
  style** (never touched by the M1 rollout since the directory was
  inert) — typing them against real implementations took ~479 compile
  errors down to 0 (Sonnet-delegated mechanical pass + 6 real `.c`-side
  bug fixes: missing K&R param declarations in `zipdf00.c`/`zipdi00.c`/
  `zipve02.c`, a pointer-through-`long`-rock laundering cast in
  `zipedit.c`, a transposed-argument live bug in `zipve00.c`'s
  `DrawString` call, and 13 files' `Build_Object` stub `peer` params
  retyped from `long`/`int` to `zip_type_figure`). All installed and
  indexed (`build/dlib/atk/index`), fonts installed, `zipview` class
  loads — the "not supported" placeholder is gone for good. Full
  details, including a Makefile `install.time`/`$?` staleness gotcha
  that silently skips reinstalling files after a `-k` build error, in
  memory `project_zip_inset_status`.
- **Also fixed 2026-07-11, general core-ATK bug, not zip-specific:**
  `atk/basics/x/xgraphic.c`'s Xft (anti-aliased text) drawing path
  never applied the pane-level GC clip to its `XftDraw` — zoomed-in
  text in any Xft-rendered, clip-relying view could bleed outside its
  own bounds. Fixed with a new `xgraphic_GetClipBoundingRect` helper
  mirroring `xgraphic_LocalSetClippingRect`'s clip computation;
  required relinking `libbasics.a`/`runapp` (statically linked).
  Runtime-confirmed: zip zoom no longer escapes its box.
- **RESOLVED 2026-07-11.** Solid-black rectangle at `-O` (correct at `-O0`). 
  Root cause: classpp typed-dispatch signedness mismatch — `zip.ch` declared 
  `returns char` but implementation is `unsigned char`. Full analysis: 
  porting-assessment.md §16. Fix: one-line `.ch` type correction + classpp regeneration. 
  Tree-wide scan of 566 `.ch` files found no other instances. Confirmed working 
  end-to-end at normal default optimization. Tested against `Cattey.turnin` and 
  `contrib/zip/samples/dragon.zip`.
- **Confirmed 2026-07-11 (found while gating an unrelated `MK_CALC`
  change), RESOLVED 2026-08-01 (M3 Wave 7 batch C2):**
  `contrib/zip/utility/ltapp.c:115,123` —
  `lt_Set_Debug(self->lt, debug)` / `ltv_Set_Debug(self->ltview,
  debug)` pass a `boolean` (int) `debug` through an untyped `Set_Debug`
  class method whose `.ch`-declared parameter is `void *` — same
  untyped-K&R-`.ch` gap as the rest of `contrib/zip/lib` before its
  M1-style typing pass, not a regression from anything touched this
  session. Blocked a full top-to-bottom `make dependInstall` gate
  (`SUBDIRS` order puts `zip` after `calc` in `contrib/Imakefile`).
  Fixed by M3 C2's `.ch`-typing treatment (`Set_Debug( boolean debug
  );` across `lt`/`ltv`/`sched`/`schedv`) — the same treatment
  `contrib/zip/lib` already got. Confirmed gone from both the subtree
  and tree-wide gates; see `claude-history/m3/m3-rollout-runbook.md`'s C2 findings entry.

### zip / calc / raster — insets fail to load when embedded inside a mixed-content document — RESOLVED 2026-07-26 (calc/zip/raster all runtime-confirmed)

- Found during M2 rollout point 4h's (`contrib/zip/lib`) runtime
  check: a standalone zip-only document round-trips correctly
  (save/reload confirmed working), but the same zip inset content
  embedded inside a larger document — surrounded by ordinary text and
  other inset types — fails to render at all, "as if there is no zip
  inset present"; a subsequent save of that document loses the inset
  entirely. `calc` shows the identical symptom in the same test
  document; `annotation`, `eq`, and `table` insets in the same
  document render correctly (`html` renders too, with its own
  already-known incorrect behavior). Test file: wdc's `/tmp/t2.ez`,
  later reproduced minimally with `revival/simple_calc.ez`.
- **Confirmed not a regression from any M2 work** (unchanged from the
  original triage — the M2 diffs to the relevant files were additive-
  only or a single unrelated `#include` line). Pre-existing, original-
  1988-import code, not caused by the ANSI C conversion work — traced
  via `fossil annotate` to the initial-import commit, predating any
  modernization work.
- **Root-caused 2026-07-26, via lldb.** The earlier "resync-on-failed-
  Read" hypothesis (below, for the record) was directly disproven:
  `calc__Read` was breakpointed and confirmed to return `0`
  (`dataobject_NOREADERROR`) cleanly — no resync fires, the read
  genuinely succeeds. The real bug is on the **write** side: `calc`'s
  shared `apt__WriteObject` helper (`atk/apt/apt/apt.c:524`) wrote a
  `long` unique id into its own `\begindata`/`\enddata` tags using
  `%d` instead of `%ld` — on this LP64 platform that silently
  truncates the id to its low 32 bits. The separately-written
  `\view{calcv,id,...}` reference tag (`atk/text/text.c:1332`) computes
  the *same* id correctly with `%ld`. Result: the two tags disagree
  (verified numerically — the view's id and the truncated id are
  bit-identical except for the truncated id missing the top 32 bits),
  so on reload `dictionary_LookUp` (keyed by the correct id from the
  view tag) never finds the object registered under its truncated
  begindata id — a completely silent miss
  (`atk/text/text.c:705-709`, bare `return 0`, no stderr at all,
  which is why nothing printed during the original triage). `zip` has
  an independent instance of the identical mistake in its own
  `zip__Write` (`contrib/zip/lib/zip.c:307,324`) — not shared code
  with `apt.c`, the same K&R idiom copy-pasted into a second file.
  Full writeup: `porting-assessment.md` §20, memory
  `project_lp64_printf_id_truncation` (supersedes memory
  `project_embedded_inset_load_failure`, which has the full
  investigation trail).
- **Fixed and runtime-confirmed 2026-07-26** for both `calc` and `zip`:
  `apt.c` and `zip.c` fixed (`%d`→`%ld`), rebuilt, installed
  (`apt.do`/`zip.do`); wdc confirmed both survive insert → save →
  reload embedded in a mixed document.
- **`raster` has the identical bug, independently found via a tree-
  wide sweep for the same mistake** (`raster__Write`,
  `atk/raster/cmd/raster.c` — its own independent Write function, not
  shared with `apt.c` or `zip.c` either): almost certainly the same
  vanish-on-embed/lost-on-save symptom would reproduce for an embedded
  raster/image inset, but this was never previously reported or
  tested — it was found by code inspection, not a runtime symptom.
  Fixed and rebuilt (`raster.do` installed). **Runtime-confirmed
  2026-07-26**: wdc tested an embedded raster insert → save → reload
  in a mixed document — works correctly.
- The tree-wide sweep also fixed ~30 other files carrying the same
  copy-pasted mistake (most never previously reported broken, since
  nobody had tested embedding those inset types the way this
  investigation tested calc/zip) — see `porting-assessment.md` §20 for
  the full inventory. Notably `eq`'s instance (`eqvcmds.c`) is in its
  Cut/Copy-to-cutbuffer path, not its ordinary save (which was already
  correct) — wdc confirmed eq Cut/Copy still works correctly after the
  fix.

<details>
<summary>Original working hypothesis (2026-07-25, disproven — kept for the record)</summary>

`simpletext__HandleBegindata` (`smpltext.c:901`) already has the
2026-07-05 figure-fix's resync-on-failed-read fallback (falls back
to a raw "unknown" object and prints a warning to stderr if
`dataobject_Read` returns anything other than `dataobject_NOREADERROR`)
— that fallback is what should fire here if `zip`'s/`calc`'s `Read`
fails partway through when called via this embedding path
specifically, as opposed to when either class is the top-level/root
object of its own file. **Directly disproven via lldb 2026-07-26**:
`calc__Read` returns `0` (success) cleanly; the resync path never
fires. The real cause is the write-side `%d`/`%ld` truncation above.

</details>

### ness — bison grammar extension blocker

- `atk/ness/objects/ness.gra` uses a multi-character string token
  extension specific to the Andrew bison fork. Ness scripting is
  unavailable until this is resolved. Options: implement the
  extension in a bison `%skeleton` or rewrite the affected grammar
  rules. `atk/ness/{objects,type}` are inert (not in the default
  build). Related loose end: `celv`'s only callers live in
  `ness/objects`, and `nevent.c` was edited in point-10 batch 1 —
  compile-unverified until ness builds.

### htmlview — crashed reading any HTML file (ReadSubString overlapping strcpy) — FIXED 2026-07-10, runtime-confirmed

- First-ever real engagement of htmlview (2026-07-10, point-10
  batch-11 runtime checks; needs a `~/.ezinit` to map `.html` at
  all, per the help instructions — without it ez reads HTML as
  plain text, which is why this never surfaced before). See
  "Overlapping-strcpy crash family" under Applications to Repair for
  the fix (all 4 sites in `html.c` now use `memmove`, compiles clean,
  installed via the full gate). Runtime-confirmed 2026-07-10:
  htmlview launches without crashing (was: instant crash). A
  `.ezinit` in the home directory does NOT affect regular non-HTML
  ez startup (verified). New follow-on, separate from this fix: no
  HTML fixture on hand actually rendered visible text — likely
  real-world HTML has diverged too far from this ~1994 parser (see
  the html.c bullet under "Overlapping-strcpy crash family" above).
  **2026-07-19: this follow-on is now milestone H1 of "Objective:
  HTML mail rendering" (Current action plan)** — triage/root-cause
  happens there, driven by a real-mail fixture corpus.

### layout — excess whitespace — RESOLVED (transient, not reproduced 2026-07-24)

- **Observed 2026-07-10** during point-10 batch-5 runtime checks: the
  complex layout inset near the end of `Sherman.Alloc` appeared to
  render with excess whitespace margin around its contents. Presumed
  pre-existing, not a regression — zero files in atk/layout were
  touched in that batch. **No longer reproduces** (confirmed 2026-07-24).
  Likely a transient rendering artifact that cleared as other Xft/display
  work was completed, or a session-state issue. No explicit fix needed.

### figure — menu commands ignored until inset regains input focus — RESOLVED (LP64 #3 fix, 2026-07-04)

- **Observed 2026-07-09** in `95Summer.ez`: figure inset menus posted
  but menu commands were ignored until the inset regained input focus.
  **Fixed 2026-07-04** as part of the LP64 bug #3 audit: `figv.c`'s
  `ChangeZoomProc` was passing bare `-1` literal through untyped dispatch
  for zoom direction; on arm64, this zero-extended to `0xFFFFFFFF`,
  corrupting the menu command dispatch. Fixed with `(long)-1` cast
  (`figv.c:129-130`). **No longer reproduces** (confirmed 2026-07-24).

### figure — `figotext` label rendering garbled — RESOLVED 2026-07-24

- Figure-inset text labels (`figotext` objects — box labels,
  captions) rendered corrupted/garbled instead of the real string,
  observed in `PAPERS/conf/1993/Inglett` and
  `NEWSLETTERS/EZ/95Summer.ez`. Found during M2 rollout point 3a's
  runtime check; confirmed pre-existing and unrelated to that batch's
  fix via a controlled revert test (`claude-history/m2/m2-batch3a-REPORT.md`
  §11). **Root cause found and fixed same day**: `atk/basics/common/
  fontdesc.c`'s `fontdesc__StringBoundingBox` computed its string
  width via `fontdesc_StringSize(font, graphic, string, (long *) &w,
  (long *) &junk)`, but `w`/`junk` were declared plain `int` (4 bytes);
  the real implementation (`xfontdesc__StringSize`, `atk/basics/x/
  xfontd.c`) writes through both out-params as genuine `long *`
  (8 bytes), so every call overflowed 4 bytes past each stack slot —
  a live memory-corruption bug on every label recompute. Confirmed via
  `fossil artifact` against the original 2026-06-24 trunk import: the
  cast is verbatim 1990s CMU source, not something this port
  introduced — on the 32-bit hosts this code was written for, `int`
  and `long` were the same width, so the cast was a no-op; LP64 is
  what turns it into a real overflow. It evaded the M2 census's own
  compiler-warning-based audit specifically because the explicit cast
  suppresses `-Wincompatible-pointer-types`; see `porting-assessment.md`
  §12's "New sub-variant (2026-07-24)" for the full writeup and a
  tree-wide census of this masking pattern (21 hits, only this one
  real). Fixed by widening `w`/`junk` to `long` and dropping the now-
  unneeded casts. Rebuilt (`atk/basics/common`, `libbasics.a` relink,
  `runapp` relink) and confirmed live: `95Summer.ez` renders
  correctly; `Inglett` renders correctly except for the two items
  below (both pre-existing, both narrower in scope than this fix).

### figure — italic text: non-monotonic sizing, distinct from the fix above (found 2026-07-24, open)

- While confirming the fix above against `Inglett`, two remaining,
  narrower problems surfaced, both isolated to **italic** text
  (`fontstyle:2`) specifically — every plain/bold `figotext` in the
  document now renders correctly:
  1. A modest (~3-5%) width overflow on the two italic runs in the
     document (`andy`-16pt "The quick brown" lead-in and the
     `andysans`-10pt-italic "The quick brown..." label), enough to
     visibly overlap adjacent content but not a dramatic mismatch —
     likely just the ordinary cost of substituting `times`/`helvetica`
     for the (uninstalled at these sizes) `andy`/`andysans` font
     family, not a code bug. Quantified via a standalone core-vs-Xft
     width comparison tool; see below.
  2. **Real, unexplained bug**: hand-testing in the figure toolset
     (Figure → Toolset → ungroup → select text → font-size picker)
     found that italic text size scaling is **not monotonic** —
     10pt italic renders bigger than 12pt, and bigger than 20pt.
     Plain and bold text both scale monotonically as expected; only
     italic is affected. Root cause not yet found: the toolset's
     size-selection code (`fontselv.c`'s `SetSizeProc`/`InsertSize`)
     was checked and is not the cause (each menu entry resolves via
     a stable string-table handle, not by position); a faithful
     simulation of the core font-resolution engine
     (`xfontdesc_LoadXFont`'s `ClosestFonts`/`XExplodeFontName`
     fallback chain, `atk/basics/x/xfontd.c`) for one italic pair
     (10pt vs 12pt) came out monotonic and correct, so the inversion
     is not yet localized. Needs its own investigation session —
     not chased further here at wdc's request. Diagnostic tools used
     for both items above (not checked in, scratch-only):
     `fontwidth_test.c` (core `XTextWidth` vs Xft `XftTextExtents8`
     for the same resolved font) and `fontpick_test.c` (ports
     `GetNthDash`/`XExplodeFontName`/`ClosestFonts` verbatim to show
     which installed bitmap a given nominal size/style resolves to).

### eq — integral symbol missing (suspect font pipeline, not eq)

- Integral symbol missing in eq insets (observed 2026-07-08 in
  `Sherman.Alloc`, pre-existing — not a -pi regression). Suspects:
  symba PCF generation, or the `xset fp+` font-path setup. Other
  symbol glyphs render fine.

### raster — convertraster RF read-back hang

- `convertraster intype=RF` hangs reading back the `.ras` file the
  same binary just wrote (observed 2026-07-09, logged *before* the
  atk/raster/lib -pi rollout — pre-existing, not a regression).
  Writer output also looks LP64-suspicious: header fields appear
  8 bytes wide. **Lead found 2026-07-12** (M2 point 0 triage, see
  Medium-term → ANSI C conversion): `oldRF__WriteImage`
  (`oldrf.c:221`) passes a `long buf[]` to `pixelimage_GetRow`,
  whose real signature wants `short *dest` — a 4x size mismatch,
  `-Wincompatible-pointer-types` flags it directly. Not yet traced
  through `GetRow`'s bit-packing far enough to confirm/fix; likely
  root cause or a major contributor. Other codecs fine:
  raster identity rewrite, PostScript, MacPaint, Xbitmap write and
  Xbitmap→raster round-trip (byte-identical to identity output) all
  pass; baseline captured in `~/src/AUIS/test-baselines/raster-pi/`.
  The raster inset itself is proven working; this is the converter
  CLI only.

### ~~clock — face never draws~~ — working again, likely font/session state, not code (2026-07-12)

- Clock inset was observed instantiating with its face/hands never
  rendering (2026-07-12, in `build/testing.ez`). Manually bisected
  across the entire M1 rollout plus all recent zip/calc/Xft work — 9
  checkpoints from `6338ade7de` (2026-07-07, before M1 point 1) through
  HEAD, each a full from-scratch `make Clean && make World` rebuild —
  blank at every single one, including the oldest. No commit in that
  range explains it, so it was logged as a confirmed pre-existing,
  not-yet-root-caused bug.
- **Reopened same day:** inserting a brand-new clock inset via ez's
  `<ESC><TAB>clock` ("insert inset by name") command rendered
  correctly, in the same session, same build. The old inset (parsed
  from serialized datastream text in the test file) and the new one
  (created fresh through ez's own inset-creation code path) are not
  the same code path, and only the old one was ever observed broken.
- **Concrete mechanism found:** `clockview__InitializeObject`
  (`contrib/time/clockv.c:288-289`) does
  `if (!(self->cursor = cursor_Create(self))) return(FALSE);` followed
  by `cursor_SetStandard(self->cursor, Cursor_Gunsight)`.
  `xcursor__SetStandard` (`atk/basics/x/xcursor.c:97-107`) hardcodes
  `fontdesc_Create("icon", 0, 12)` (font family `icon12`) to build the
  cursor's fill pattern. If that font resolution fails for any reason,
  `cursor_Create` returns null, `InitializeObject` returns `FALSE`
  immediately, and the clockview never finishes initializing —
  matching the observed symptom exactly (nothing draws at all, not
  just labels: hands are drawn later in `Redraw`, which never runs on
  an object that failed to initialize).
- **Not fully closed:** `icon12` itself was already confirmed present
  in `fonts.dir` and resolvable via `xlsfonts` before any of the
  2026-07-12 `con10`/`con12` console-font work (see "`MK_CONSOLE` being
  off..." below), so this isn't the same root cause as that issue.
  Current best explanation is a transient X-server font-cache/session
  state problem specific to whatever `ez` process the old, broken
  clock instance lived in — not a permanent gap and not a code defect
  — but this hasn't been isolated further (e.g. by testing whether the
  *old* serialized datastream clock also now renders correctly in a
  fresh `ez` launch, which would confirm it's session-state and not
  something specific to the by-name insertion path).

### image — JPEG/GIF import renders as a solid black box, TIFF import renders as a solid white box; raster renders correctly (found 2026-07-26, open)

- Found during M3 batch O2's (`overhead/image/jpeg`, `overhead/image/
  tiff`) runtime check: inserting an Image inset in `ez` and importing
  a `.jpg`/`.jpeg` or `.gif` file renders a solid black box; importing
  a `.tif`/`.tiff` file renders a solid white box. Importing an ATK
  native raster (`.ras`) file renders correctly. This is the general
  `image`/`igraphic` inset family (`atk/image`, `atk/basics/common`),
  not specific to any one format's decoder — GIF and raster both go
  through code untouched by O2 and show the same
  broken/working split as JPEG and TIFF respectively, so the pattern
  cuts across the O2 diff rather than following it.
- **Confirmed NOT a regression from M3 O2**: bisected live (2026-07-26)
  by stashing the batch's entire diff, rebuilding `libjpeg.a`/
  `libtiff.a` and relinking `jpeg.do`/`tif.do` from pristine,
  unmodified K&R source, and re-testing the identical JPEG/TIFF files
  — same black-box/white-box symptom on the pristine build. This inset
  family had never been exercised before in this revival (first-ever
  runtime test, same situation M1/M2 kept finding elsewhere in the
  tree); the bug is pre-existing, not introduced by the ANSI
  conversion. O2's own diff is gate-green (gated twice, deterministic)
  and unrelated to this finding — committed alongside this entry.
- **Working hypothesis, not yet investigated**: wdc's own suspicion,
  based on the black-vs-white split cutting cleanly across which
  format renders solid black (JPEG, GIF) vs. solid white (TIFF) vs.
  correctly (raster) — "something funky going on with drawables," and
  possibly the same class of bug as the zip inset's solid-black
  render bug (`porting-assessment.md` §16, a classpp typed-dispatch
  signedness mismatch between a `.ch`'s declared `returns char`/`short`
  and the real implementation's signedness — RESOLVED 2026-07-11, see
  "zip" above). Not confirmed; needs its own dedicated debug session
  before being written up as root-caused. `nm -g` consumer detail and
  exact runtime-check commands are in
  `claude-history/m3-o2-imagecodecs-REPORT.md`.
- **Re-tested 2026-07-26 after M3 batch B1** (`atk/basics/common`,
  which owns `gif.c`/`image.c`, unlike O2's jpeg/tiff codec libraries):
  importing a *different* GIF file (`foo.gif`) now renders a solid
  **white** box, not black; re-importing the same JPEG test file
  (`testorig.jpg`) still renders solid black, unchanged. **Not
  attributed to B1**: `gif.c`'s B1 diff was reviewed function-by-function
  and is pure K&R→ANSI signature syntax with zero semantic change (no
  type, body, or logic differences); `jpeg.c` wasn't touched by B1 at
  all (it's O2's file, a different directory) and shows no symptom
  change either, consistent. A separate, concurrent session also
  landed 11 commits touching `image.c`/`image.ch` (an LP64 `%d`→`%ld`
  datastream-write fix, `image__SendBeginData`/`SendEndData`) between
  B1's start and this re-test; confirmed via `fossil diff` that this
  fix is about the *save/write* datastream path only, not the
  `gif__Load` import/decode path, and gif's own file has no overlap
  with that commit set at all. Most likely explanation: the new test
  file simply exercises the still-unconfirmed underlying bug
  differently (consistent with "something funky going on with
  drawables" depending on file-specific state) rather than a code
  change on either side — but this is inference, not a confirmed root
  cause, same as the entry above. Still needs its own dedicated debug
  session.

---

## Questions

- How do I get a right click with my magic pad?
- How do I get drag scroll working without having to click and drag the elevator?

---

## Major milestones

- **2026-07-17**: **First SMTP mail sent by AMS** — AMS/IMAP-project
  milestone 1 complete: scripted cui composes and submits through the
  real `dropoff()` path over TLS to Fastmail, authenticated,
  end-to-end. Roughly 35 years after AMDS last moved a message by
  copying files through a distributed filesystem, the Andrew Message
  System speaks a mail protocol the rest of the world still speaks.

- **2026-07-10**: **M1 complete** — classpp emits fully typed dispatch
  casts by default across the whole active tree (11 rollout points,
  ~50 directories, ~35 years of `.ch` signature drift found and
  fixed; five live LP64/caller bugs caught by the typed casts along
  the way: suite unsigned rocks, htmlview DisplayString transposition,
  clockv NewString, lexan ParseNumber int*/long*, noteview/stroffetv
  ICONSTYLE string literal). The compiler now type-checks every
  method call site tree-wide. Next: M2 prototype sweep.

- **2026-07-05**: `messages` application running with local mail store —
  "mail (Private BB; 0 new of 0)" confirmed in the folder panel. All three
  prerequisite streams closed simultaneously: AMS local backend alive,
  atkams/ interface working, ATK insets (lset, value, pushbutton/link)
  sufficient for the messages UI to render.

---

## Completed

- `ez2md` converter (`revival/tools/ez2md`): converts `.ez` files to
  Markdown; handles styles, footnotes, page breaks, nested insets, and
  raster images (decoded to inline PNG); tested against 51 archive
  documents
- Full build: 278 `.do` files, 0 errors, `make dependInstall` exit 0
- `ez` launches, renders documents, scrollbar/menus/keyboard input all work
- `help` application: multiple frames, topic navigation working
- Dialog boxes: visible, correctly positioned, text readable
- Raster insets: rendering correctly
- Table insets: cell text visible (LP64 `update.c` fix)
- Eq insets: complex equations render correctly
- Fad insets: fully working (LP64 fix + Xft XOR ghost fix + 30ms timing floor)
- Fnote insets: marker glyph centered correctly (Xft metrics fix, 2026-07-04); **proven working** — footnote marker and popup text display correctly in `Cattey.Writing`
- `help` app: fully functional — Programs list panel scroll fixed (LP64 fix, 2026-07-04); regression tests below
- Bp (page break) insets: **proven working** — visible as page-break rule in `Cattey.Writing`
- Srctext insets: **proven working** — indentation and syntax coloring render correctly (LP64 audit)
- Figure insets: **proven working** — `95Summer.ez`'s figure renders correctly end to end (see Chronological log 2026-07-04). Two independent bugs stacked on top of each other: (1) parser-desync — official CMU `patch.633` (figattr tolerates unknown attributes from later format versions) plus new `smpltext.c` hardening (failed inset reads fall back to a raw `unknown` object instead of corrupting the rest of the parse); (2) LP64 — `figure__Read`'s `$origin` line was parsed with `sscanf(buf, "$origin %d %d", &val1, &val2)` into `long val1, val2`, the same %d-into-long pattern as the other LP64 audits, leaving stack garbage in the upper 32 bits of `originx`. That corrupted `originx` flows straight into `figview`'s `panx` (`SetDataObject` does `panx = originx`), pushing the entire figure's rendering ~4 billion pixels off-screen — content was being drawn, just nowhere near the visible clip region. Confirmed live via `lldb`: found `originx == 0x100000000` in the running `figview`'s memory. Fixed both `figure__Read` and the analogous `figure__ReadPartial`.
- `Sherman.Alloc` integration test: text, eq, fad, cel/arbiter spreadsheet
  all render; zip unsupported (expected). Calc is a separate contrib
  inset, not part of this document — see `contrib/calc` under Completed.
- Xft phase 1: body text rendering via client-side Xft (anti-aliased)
- Andy symbol fonts (`symba*.pcf`) built and installed in `build/X11fonts/`
- `overhead/malloc/malloc.ci` `addarena` arena-size pointer-arithmetic bug fixed (`patches/contrib/malloc.ci.auis6.3.diff`, 2026-07-04) — source-correctness only, see Historical patches audit below for why it has no runtime effect here
- `messages` application: **running** (2026-07-05) — local mail store (`Private BB`) visible in folder panel; three-pane layout, menus, and help text all rendering; AMS local backend + atkams/ interface + ATK insets all working
- `chart` application: launched and runtime-verified interactively (2026-07-10, point-10 batch 5) — startup, chart creation, format switching, palette labels; exercises the `SetChartAttribute`/`SetItemAttribute` rewrite
- `htmlview` DisplayString transposition fixed (2026-07-09) — three `message_DisplayString` calls had priority/string transposed since the 1990s; those HTML-editing status messages display for the first time
- `mkparser`/`cparser.c` fixed-width table bug (2026-07-11) — the shared parser engine used by all five AUIS grammars (`prsdate`, `eliy`, `eqparse`, `num`, `parsey`) assumed every bison table was a `short`; modern bison narrows some to 1 byte per grammar, corrupting every lookup into a narrowed table. Root-caused via `amsdemo`'s caption dates/ordering; fixed generically in the shared engine, not per-grammar. See `porting-assessment.md` §15 — a close cousin of the LP64 bug family (§12): different mechanism (generator-chosen storage width vs. ABI sign/zero-extension), same shape (1990s code assumed a fixed width; a modernized tool in the chain silently chose otherwise decades later).
- `contrib/calc` inset — brought into the active build 2026-07-11:
  `#define MK_CALC` in `config/site.h`, Makefiles regenerated down
  `contrib/calc` (`make Makefiles` from `contrib/`). Unlike `zip`,
  `calc.ch`/`calcv.ch` were already fully ANSI-typed (not 1990s K&R) —
  no classpp typing pass needed. `calcv.c` had 11 K&R functions
  forward-referenced (called before their `static` definition) via a
  stale non-`static` forward declaration, which clang now rejects as a
  linkage conflict (`static declaration ... follows non-static
  declaration`); fixed by replacing the one non-static forward decl
  with proper `static` ANSI prototypes for all 11 internal helpers.
  Also fixed: three `graphic_BLACK` (0xFF int constant) arguments
  passed directly to `void *` `Tile` parameters in `Fill_Area`,
  needing the same `(struct graphic *)` cast already used at
  `chart/charthst.c:238` for the identical idiom; and 5 sites
  (`calc.c:155`, `calcv.c:526,548,557,558`) using `sscanf(...,"%F",
  &x)` where `x` is `double` — `%F`/`%f` only fill 4 bytes, silently
  leaving the upper 4 bytes of each `double` as stack garbage, the
  same wrong-width-scanf shape as the documented LP64 Variant 4 class
  (just float/double instead of int/long) — fixed to `%lf`. The
  already-present `calcv.c:502` overlapping-strcpy fix (see
  Overlapping-strcpy crash family above) compiles clean now that the
  directory builds. `calc.do`/`calcv.do` build warning-clean of errors
  and install (`make install` in `contrib/calc`); full top-level
  `make dependInstall` gate confirms `contrib/calc` itself builds
  clean, though the gate doesn't reach past `contrib/zip/utility`
  (pre-existing, unrelated break — see Insets to Repair → zip).
  **Fully working** — runtime rendering confirmed 2026-07-12; all
  identified bugs fixed (see Insets to Repair → calc for details).

**LP64 bug classes identified and swept:**
- Variant 1: Missing prototypes / pointer return truncation (23 sites)
- Variant 2: >8-arg untyped dispatch stack spill (classpp fix)
- Variant 3: `int` constant zero-extended through untyped dispatch
  (`observable_OBJECTDESTROYED`, `value_OBJECTDESTROYED`,
  `class_VERSIONNOTKNOWN`)
- Variant 4: `%d` with `long *` in scanf family (full tree audit done; one straggler found later and fixed — `figure.c`'s `$origin` parsing, see Completed and Chronological log 2026-07-04)
- Variant 5: `long`/`int` mismatch in display positioning through untyped
  dispatch (lpair, panel, dialog, table, fad, srctext, eq, metax, toez,
  typescript margins; style__ReadAttr operand; figure_NULLREF sentinel; full audit committed)

**Related but not itself LP64 (2026-07-22):** a K&R-style empty-parens
extern declaration of a *new* variadic function crashes on arm64 —
the ABI passes variadic args on the stack and fixed args in registers,
so an under-declared call site emits the wrong calling convention
regardless of word width; symptom is a crash inside `vsnprintf`/
`vfprintf`, not a truncated value. Found building the IMAP writeback
change journal (`MSJournal_Record`, `ams/libs/ms/msjournal.c`); fixed
with a full `...`-prototyped extern at every call site. Same root
pathology as the LP64 family (K&R declarations under-specifying type
info for a modern ABI) but a different mechanism — grouped here for
visibility, not counted as Variant 6. Full writeup:
`porting-assessment.md` §18; also in `sonnet-playbook.md`'s bug-class
list (item 6) since that's what delegated sessions read first.

**Variant 3 follow-up audit (2026-07-04) — bare `-1` literals at call sites,
not just `#define`d sentinels:**

Found via `help`'s list-panel scroll bug: `textv.c:455`,
`self->frameDot = text_CreateMark((struct text *) dataObject, -1, 0)`.
`text_CreateMark` dispatches through the untyped `(struct mark *(*)())`
class-method macro, so the bare `int` literal `-1` isn't sign-extended to
the `long pos` field on LP64 — `frameDot->pos` ends up as garbage (observed:
`4294967295`, `4294967335`, `8589934591` in lldb — all the "low 32 bits look
like -1, upper 32 bits are register garbage" signature). `DoUpdate`'s
`mark_GetPos(self->frameDot) != -1` check then spuriously fires on every
first redraw. **Fixed**: `(long)-1` cast at the call site.

This is the same root mechanism as Variant 3 (`observable_OBJECTDESTROYED`
etc.) but the `-1` is a bare call-site literal rather than a named
`#define`d sentinel, so grepping for the constant's name doesn't find it —
it only shows up by grepping call sites directly. A full sweep (see
methodology below) turned up **6 more confirmed instances**, all fixed with
the same `(long)-1` cast, all compile-clean and rebuilt/reinstalled:

- `src/atk/text/content.c:649`, `src/atk/textaux/contentv.c:134,186` —
  `content_Enumerate`/`content_Denumerate`'s `opos`/`pos` (`long`) is
  checked `< 0` as an "enumerate everything" sentinel in
  `src/atk/text/content.c` (`content__Enumerate`/`content__Denumerate`);
  the corrupted value would read as a huge positive number instead,
  silently skipping the enumerate-all path.
- `src/atk/figure/figv.c:129-130` — `ChangeZoomProc`'s `rock` (`long`) is
  checked `rock<0`/`rock>0` to decide zoom in vs. zoom out; the "Zoom Out"
  menu item and `Esc-z` keybinding both passed a bare `-1` through
  `menulist_AddToML`/`keymap_BindToKey` (both untyped dispatch). If
  corrupted, **Zoom Out would zoom in instead**.
- `src/atk/raster/cmd/rasterv.c:1634-1635` — `ModifyCommand`'s `rock`
  (`long`) is checked `rock == -1` (exact equality) for "invert
  selection"; the "Negative" menu item and `Esc-n` keybinding both passed
  a bare `-1` through the same two untyped-dispatch macros. If corrupted,
  **Negative would silently do nothing** (falls through all the `==`
  branches).

**Audit methodology** (repeatable for future sweeps):
```sh
# class-dispatch-style calls (lower_Upper(...)) with a bare -1 argument
grep -rEn '\b[a-z][a-zA-Z0-9]*_[A-Z][a-zA-Z0-9]*\([^;()]*(,|\() *-1 *(,|\))[^;]*\)' \
  src/ --include=*.c | grep -v "(long)-1\|(long) -1\|== *-1\|!= *-1"
```
This narrowed ~925 raw `-1`-near-parens hits down to 22 candidates. Each
candidate needs manual triage: (1) find the macro's dispatch — untyped
`(TYPE (*)())` cast is the risky pattern, a plain field-assignment macro
(e.g. `mark_SetPos`, `rectangle_SetRectSize`) or a normal prototyped C
function is safe; (2) find the receiver and check whether it actually
*consumes* the value in a way sensitive to its exact bit pattern (a sign
check `< 0`/`== -1`, or arithmetic) vs. ignoring the parameter entirely
(several `view_FullUpdate(...,-1,-1)` width/height args in `figv.c` and
`rastvaux*.c` are ignored by both `figview__FullUpdate` and
`rasterview__FullUpdate`, which recompute geometry from the view instead —
confirmed harmless despite passing through the same untyped mechanism).

**Deferred / not yet triaged** (lower priority, left as future audit
targets, not confirmed either way):
- `src/atk/basics/common/rect.c` / `figv.c:905` — `rectangle_InsetRect`
  is a plain function but its header prototype
  (`rect.h:73: void rectangle_InsetRect(/*LHS, DeltaX, DeltaY*/);`) has no
  parameter types, so call sites don't widen `-1` to the real `long
  DeltaX, DeltaY`. Unlike the confirmed bugs above, the receiver does
  arithmetic (`+=`/`-=`) rather than a sign check, so a corrupted value
  would grossly mis-size a rectangle rather than silently no-op. (Not the
  cause of the `95Summer.ez` "messy screen" case — that turned out to be
  a figure-attribute version mismatch, see Completed; this remains an
  untriaged latent risk.)
- `environ_GetProfileInt(...,-1)` (messages/atkams, several sites) and
  `cwp_Search(...,-1,...)` (ams/delivery) — likely safe (looks like a
  plain `int`-returning function, not virtual dispatch) but unverified;
  deprioritized since `messages`/AMS revival is long-term, not part of
  the active inset sweep.
- `tlex_RecentPosition(...,-1 or -2,...)` (ness) — moot until the `ness`
  bison grammar extension blocker is resolved; the code doesn't run yet.

---

## Historical patches audit (`patches/`) — complete, 2026-07-04

CMU's official 6.3.x point-release patches plus community/site contrib
patches from the 1990s live in `patches/official/` and `patches/contrib/`
(the same set is duplicated verbatim under `andrew-6.4/patches/`,
`trunk/patches/`, and the top-level `AUIS/patches/` — they're identical,
no need to check more than one copy). This was triggered by finding that
CMU had already patched the exact figure-attribute-version bug hit while
fixing `95Summer.ez` (see Completed, above) — worth checking here *before*
deep-diving into a new bug, since CMU or a site admin may have already
found and fixed it decades ago. Every file every patch touches was
diffed against current source (not just the patch descriptions) to
determine actual relevance.

**Applied:**
- `official/patch.633` — "make figure accept figures created with later
  versions, including C++ 7.2+." Makes `figattr__Read` tolerate unknown
  attribute names instead of returning `dataobject_BADFORMAT`. Applied
  2026-07-04 as part of the `95Summer.ez` figure fix (see Completed).
- `contrib/malloc.ci.auis6.3.diff` — `overhead/malloc/malloc.ci`
  `addarena`: `A.arenaend - A.arenastart` is `struct freehdr *`
  subtraction, which the C standard defines in units of
  `sizeof(struct freehdr)`, not bytes — undercounts the arena-growth
  heuristic by ~20-24x. Fixed by casting both to `char *` before
  subtracting. **No observable runtime effect**: `ANDREW_MALLOC_ENV` is
  `#undef`'d in `config/site.h` and there is no `malloc.o`/`libmalloc.a`
  anywhere in `build/` — this codebase runs on system `malloc` via libc,
  Andrew's custom allocator is dead code here. Fixed anyway for source
  correctness (submitted originally by the current user, `wdc@mit.edu`,
  in 1995) in case `ANDREW_MALLOC_ENV` is ever revisited. `malloc.ci` is
  `#include`d into `malloc.c`/`pmalloc.c`, which currently fail to
  compile for unrelated pre-existing reasons (`AbortFullMessage`
  static/non-static prototype conflict) — out of scope, this directory
  isn't part of the active build either way.

**Investigated, found already fixed in our 6.3.1 baseline** (no action
needed — but worth knowing these bug patterns were already closed before
this project started, so don't waste time rediscovering them):
- `official/patch.631`, `atk/figure/figospli.c` hunk — guards
  `ctemp[last+1].t4 /= ctemp[last+1].t2` division (spline math for
  polyline figures) with `if (last >= 0)` to avoid an uninitialized-value
  divide on degenerate (too-few-point) curves. Already present at both
  call sites (lines ~148, ~210).
- `official/patch.631`, `atk/textobjects/unknown.c` (the exact file our
  new `smpltext.c` hardening depends on) — all 3 hunks already applied:
  `self->odata==NULL` typo (comparison instead of assignment, would have
  left a dangling pointer after `text_Destroy`) is correctly `=`; `static
  int tungetc` is correctly `static void`; `unknown__Read` already
  `return`s `ret` at the end.
- `official/patch.631`, `atk/support/hash.c` hunk — use-after-free fix
  (`return egg->value` after `free(egg)`) already applied; value is
  copied to a local before the free.
- `official/patch.631`, `atk/text/tabs.c` hunk — `PrevTab >= 0` bounds
  check already extended to `PrevTab >= 0 && PrevTab < self->number`.

**Not applicable:**
- `official/patch.631`, `atk/basics/common/im.c` hunk — `#ifdef
  hpux`-only, doesn't affect Darwin.
- `official/patch.632` — AMS `parseadd.c` fix, `official/patch.634` —
  AMS/`eatmail` coredump fix. Both out of scope; AMS/Messages revival is
  long-term (see Medium-term below), not part of the active inset sweep.
- `contrib/symlink.patch` — makes a shared-lib install symlink relative
  instead of absolute in `overhead/class/lib/Imakefile`. Confirmed dead
  code path for us: it's inside `#else /* LIBDL_ENV */`, and Darwin's
  config never defines `LIBDL_ENV` — we build a static `libclass.a`, not
  the shared `libclass.so` this patch targets.
- All SGI/NetBSD/Solaris/HP-UX/RS6000 platform ports (`SGI-port.6.3.3.*`,
  `NetBSD*.README`/`.diffs`, `Solaris*.diffs`/`.README`,
  `patch.631-hp-only`, `dvi2disp.patch`, `mit.patch`) — assembler flags,
  `stty`/`gtty` variants, `mode_t` sizing for Irix, `sys_errlist` typing,
  etc. for platforms unrelated to macOS/arm64.

---

## Subsystem dependency lattice

Indentation shows inheritance / dependency. `[PROVEN]` means confirmed
working through runtime testing. Unlabelled leaves are untested.

```
overhead/class  [PROVEN — loader, everything depends on this]

atk/basics  [PROVEN — view, graphic, scroll, lpair, panel, sbuttonv, xgraphic, xfontd, xim]

dataobject [PROVEN]          view [PROVEN]
    |                            |
    +-- bp / bpv  [PROVEN]       +-- scroll / sbuttonv  [PROVEN]
    +-- raster    [PROVEN]       +-- lpair              [PROVEN]
    +-- text ---- textview  [PROVEN]
    |        +-- fnote         [PROVEN — Cattey.Writing: footnote marker + popup]
    |        +-- textref / texttag  [PROVEN — ex14/ex14.doc cross-ref page numbers]
    |        +-- rofftext             (extends text)
    |        +-- srctext      [PROVEN — indentation + syntax coloring confirmed]
    |
    +-- eq -- eqview  [PROVEN — complex equation rendered from ia-archive/dec.91]
    +-- table         [PROVEN — cell text visible after LP64 fix]
    +-- fad -- fadview  [PROVEN]
    +-- pushbutton -- pushbuttonview
    |        +-- link -- linkview     (hyplink)
    +-- lookz -- lookzview
    +-- value -- valueview
    |        +-- sliderv
    |        |      +-- bargraphV
    |        +-- buttonV
    |               +-- controlV, enterintV, enterstrV, fourwayV
    |        +-- stringV -- clklistV
    +-- apt -- aptv
    |        +-- org -- orgv          (outliner)
    |        +-- chart                (charts)
    +-- cel                           (ADEW spreadsheet cell; needs value+text)
    |        +-- arbiter              (ADEW application builder)
    +-- lset                          (scrollable list view)
    +-- figure -- figview             [PROVEN — 95Summer.ez renders correctly]
               +-- figobj hierarchy
                      (figorect, figoplin, figoell, figogrp, figotext...)

application [PROVEN via ez, help]
    +-- ez          [PROVEN]
    +-- help        [PROVEN — multiple frames, topic nav, frame size correct]
    +-- fad         [PROVEN]
    +-- typescript / pipescript       (terminal emulator)
    +-- bush                          (shell)
    +-- org (orga)                    (outliner as standalone app)
    +-- chart (chartapp)
    +-- launchapp

contrib
    +-- writestamp [PROVEN]
    +-- calc [builds and installs clean, 2026-07-11 — runtime untested]
```

Note: `help` does not use `lset` — confirmed by source audit. `lset` is
unproven and requires its own test.

---

## Inset testing sequence

Ordered by dependency depth; each step proves a layer the next relies on.
`[PROVEN]` items are already confirmed; start from the first unconfirmed entry.

| # | Inset / App | Test document | What it proves | Search string |
|---|-------------|--------------|----------------|---------------|
| 1 | **fnote** | **[PROVEN]** `PAPERS/atk/Cattey.Writing` | inline text-in-text insets | look for superscript footnote markers in body text; click to expand |
| 2 | **textref / texttag** | **[PROVEN]** `src/atk/examples/ex14/ex14.doc` + `ex15/ex15.doc` | cross-ref insets; page-number references that update dynamically | in ex14: search "Program Listing for Example 14 at the end of this section on p." — the number after "p." is a live textref pointing to the texttag at the listing |
| 3 | **eq** | `ia-archive/dec.91` | **[PROVEN]** equation editor; text marks confirmed | look for rendered equations with fractions and subscripts |
| 4 | **table** | `ia-archive/aug.90` | **[PROVEN]** cell text visible | spreadsheet cells with numbers and formulas |
| 5 | value (slider/button) | `ia-archive/sep.90` or `ia-archive/jan.90` | value views; valueview dispatch chain | slider or button widgets embedded in text |
| 6 | lset | `ia-archive/nov.91` or `ia-archive/jan.90` | scrollable list widget | scrollable selection list inset |
| 7 | pushbutton / link | `PAPERS/conf/1995/widgets.ez` | hyplink chain: pushbutton→link→linkview | clickable button insets |
| 8 | **fad** | `src/atk/adew/Title.doc` | **[PROVEN]** LP64 fix complete | animated/fading text title inset |
| 9 | org | `src/atk/org/example1.org` | outliner; proves apt→aptv base | outline nodes with expand/collapse |
| 10 | rofftext | `bin/rofftext -d <manpage>` | roff formatter on top of text | formatted man page output |
| 11 | chart | `build/doc/atk/classes.org` or synthesize | proves apt branch independently of org | bar or line chart inset |
| 12 | **cel / adew** | `src/atk/adew/vallist` | **[PROVEN via Sherman.Alloc]** ADEW stack: value+text+cel+arbiter renders | spreadsheet cells with live calculation |
| 13 | typescript | `bin/typescript -d` | terminal emulator; **crashes "Can't connect subchannel"** — likely macOS PTY compat issue, not LP64 | terminal window inset |
| 14 | bush | `bin/bush -d` | shell application | interactive shell |
| 15 | **figure** | `NEWSLETTERS/EZ/95Summer.ez` | **[PROVEN]** two stacked bugs fixed: parser desync (patch.633 + smpltext.c) and LP64 `$origin` scanf corruption (figure.c); renders correctly end to end | drawing/diagram insets in newsletter |
| 16 | **Sherman.Alloc** | `PAPERS/atk/Sherman.Alloc` | **[PROVEN]** text+eq+fad+cel/arbiter all render; zip unsupported (expected) | multi-inset compound document |
| 18 | **calc** | Esc-Tab, type `calc`, Enter in any `ez` doc (see `contrib/calc/calc.help`) | **[PROVEN]** fully working 2026-07-12; rendering bugs fixed (AA erase, recomposite lag), all tests pass | calculator button-grid inset |
| 17 | **Cattey.Writing** | `PAPERS/atk/Cattey.Writing` | **[PROVEN]** writestamp, fnote, raster, |

**No good test document exists for:** `lookz`, `launchapp`, `prefed`
— these need synthetic test files or targeted app launches.
`srctext` is now [PROVEN].

**Known non-starters:** `ness` (bison extension blocker, still inert)
— detailed under **Insets to Repair**. `zip` now builds and loads
(see Insets to Repair → zip) though `zip/utility` is still broken.
`clock`/`timeoday` (contrib, lower priority, still inert). `calc` now
builds (see row 18 above; row kept lower-priority pending runtime test).

---

## Heisenbugs (intermittent, not currently reproducible)

### Display mess

**Observed:** On rare occasions, text will draw into the menu area. 
But I can't reproduce it reliably.

### ^V scroll hang on fresh window (spoon host)
**Observed:** on host `spoon`, repeatedly: opening `help` or `ez` and
pressing `^V` to scroll the default window caused the process to die
(confirmed dead in debugger) while the X window persisted until XQuartz
was restarted. `help` would still believe a server process was available.
Triggered even on the default help window with no special document.
Stopped reproducing spontaneously once debugging attempts began.

**Not reproduced on:** Mac-mini. Not triggered by VS Code terminal (was
running from native Terminal.app).

**Possible cause (superseded, see below):** the checkpoint timer UAF
(`observable_OBJECTDESTROYED` zero-extension bug, fixed 2026-06-30) was a
plausible match — scrolling a fresh window can trigger a checkpoint, and
the UAF produced a crash rather than a hang.

### Xlib display-lock self-deadlock — **deferred** (reproduced 2026-07-04, root cause identified)

Reproduced by accident during the figure-inset LP64 audit: scrolling in
both `ez` (viewing `NEWSLETTERS/EZ/95Summer.ez`) and, independently, a
`help` window hung the same session. **Not a crash this time** — attaching
lldb to the stuck `help` process (no relaunch, no interrupt needed — it
was already wedged) showed:

```
frame #0: libsystem_kernel.dylib`__psynch_mutexwait
frame #1: libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_wait
frame #2: libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_slow
frame #3: libX11.6.dylib`_XLockDisplay
frame #4: libX11.6.dylib`XkbGetUpdatedMap
frame #5: libX11.6.dylib`XkbKeysymToModifiers
frame #6: libX11.6.dylib`XRefreshKeyboardMapping
frame #7: runapp`HandleWindowEvent
frame #8: runapp`xim__HandleFiles
frame #9: runapp`im__Interact
frame #10: runapp`im__KeyboardProcessor
frame #11: runapp`application__Run
frame #12: helpa.do`helpapp__Run
frame #13: runapp`main
```

Only **one thread exists** in the process, and it's blocked forever trying
to acquire Xlib's own display-connection mutex (`_XLockDisplay`) — a
self-deadlock, not a cross-thread one. `HandleWindowEvent` is responding
to an X `MappingNotify` (keyboard mapping changed) by calling
`XRefreshKeyboardMapping`, which tries to lock the display — but something
earlier in the *same* call chain already holds that lock (almost
certainly Xlib's own event-dispatch machinery calling back into
`xim__HandleFiles`/`HandleWindowEvent` while still holding it internally),
and the lock isn't held recursively. This matches the "intermittent,
input-related, seems tied to fresh windows" character of the original
report far better than the checkpoint-timer theory, and is **not** fixed
by any patch committed so far — this is a live, distinct bug.

**Trigger appears to be keyboard-mapping churn** (`MappingNotify`), not
scrolling logic itself — consistent with why `^V` specifically was the
original trigger (a modifier-involving key combo) and why it's
intermittent (depends on X server-side keymap-change timing, not app
state).

**Not yet investigated:** which AUIS/Xlib call site re-enters
`_XLockDisplay` while already holding it; whether this is triggerable
deliberately (vs. needing to wait for an incidental `MappingNotify`);
whether it's an AUIS-side bug (calling into Xlib from inside a callback
that already holds the lock) or an XQuartz/libX11 packaging issue specific
to this environment. Needs a dedicated debugging session — see
`revival/doc/runtime-debugging-guide.md` for the general lldb debugging
process/cookbook developed for this project.

---

## Regression test checklists

### help application
Run: `DISPLAY=:0; build/bin/runapp helpa -d`

1. **Startup**: window opens showing "A Guided Tour of Andrew" in the main panel
2. **Overviews pane**: right panel top section shows entries (Andrew Tour, Multimedia, Mail, Programming); text is readable
3. **Programs pane**: right panel bottom section shows programs list starting from the **top** of the list (first entry visible, scrollbar at top) — regression for LP64 frameDot bug
4. **Overviews link**: click "Andrew Tour" in Overviews → main panel changes to that document
5. **Programs link**: click any entry in Programs → main panel changes to that help topic
6. **In-text links**: click a cross-reference link in the main panel text → navigates to linked topic
7. **Expand/Shrink Programs pane**: use Panels menu → "Expand Programs" / "Shrink Programs" → pane resizes correctly
8. **Show History**: use Panels menu → "Show History" → history pane appears listing previously visited topics
9. **History links**: click an entry in the History pane → main panel navigates to that topic

### ez application (menus)
Run: `DISPLAY=:0; build/bin/ez build/testing.ez`

**Before testing, check `~/.ezinit`.** If it exists, it must start
with `include /Users/wdc/src/AUIS/andrew-6.4/build/lib/global.ezinit`
or every global menu/keybinding — including "Media" — silently
disappears. This is original 1988 `atk/basics/common/init.c` cascade
design (`addmenu`/`addkey` docstring at line 76), not a bug: `app.c`
loads `~/.ezinit` first, and if it loads successfully, **returns
immediately** without ever reaching `global.ezinit` (where the
`addmenu` lines for Media live — see `atk/ez/ezinit`). A personal
init file replaces the global one unless it explicitly `include`s it.
This looks exactly like a code regression in menu construction and
cost a full manual bisection (`6338ade7de` through HEAD, 9 checkpoints,
each a clean from-scratch rebuild, all showing Media present) before
being traced to a stray one-line `~/.ezinit` (added earlier for
htmlview testing, forgotten about) on 2026-07-12.

1. **Media menu present**: textview "Insert"-area menu bar has a
   "Media" submenu (Equation, Header/Footer, PostScript, Raster,
   Spreadsheet, Animation, Hyperlink, Layout, Ness, Note, Writestamp,
   By name...)
2. **Clock inset**: insert fresh via `<ESC><TAB>clock` and confirm it
   renders — see Insets to Repair → clock (unrelated to the Media
   issue above; a *parsed* clock from serialized datastream text has
   been seen failing to render even when a freshly-inserted one works,
   root cause not fully isolated)

---

## Active (instances running)

- **Xft phase 2: menu rendering** — deprioritized; menus are working
  acceptably with the current rendering path

---

## Near-term

### ~~LP64 positioning sweep~~ — complete
All five LP64 variant classes identified, swept, and committed. `Sherman.Alloc`
and `95Summer.ez` used as integration tests; both render correctly.

### ~~Messages application prerequisites~~ — **DONE (2026-07-05)**

Goal: get `messages` running with a local mail store. Three streams of work:

**Stream 1 — remaining ATK inset prerequisites (unproven):**
These insets appear in the messages UI and/or in rendered mail:
- `lset` (scrollable list) — mail folder/message list display; test with `ia-archive/nov.91` or `jan.90`
- `value` / `valueview` (slider, button) — UI controls; test with `ia-archive/sep.90` or `jan.90`
- `pushbutton` / `link` / `linkview` — hyplink navigation; test with `PAPERS/conf/1995/widgets.ez`

**Stream 2 — AMS local mail store: found, 2026-07-04.** The build already
separates the message store/UI from the AMDS delivery daemon via independent
Imake flags:

| Flag | Gates | Needed for local-store `messages`? |
|---|---|---|
| `AMS_ENV` | whether `ams/`/`atkams/` build at all (`Imakefile:37-39`), plus `overhead/mail` (`libmail.a`, `libcparser.a`) | **yes** — currently `#undef`'d in `config/site.h`, overriding `allsys.h`'s default of 1 |
| `AMS_DELIVERY_ENV` | `ams/delivery/` (sendmail/vicemail/queuem/trymail) and `ams/utils/` (nntp/muserver/purge/reauth/undigest) — the actual AMDS transport | no — leave off |
| `SNAP_ENV` | networked "remote message server" variant (`ams/ms`, `libcuis.a`) vs. the local `nosnap` path (`libcuin.a`) | no — leave off, local path is the default |
| `WHITEPAGES_ENV` | `overhead/wpi`/`wputil`; auto-forced only by `AFS_ENV` or `AMS_DELIVERY_ENV` | no — stays off since neither of those is on |

With only `AMS_ENV` on, `atkams/messages/lib`'s Imakefile builds `amsn.do`
against `NLIBS` (`libcui.a`, `libcuin.a`, `libmssrv.a`, `libeli.a`,
`librxp.a`) — the local, non-networked message store — and never touches
delivery or white-pages code.

The local-mailbox backend the user remembers is real and already in the
source: `ams/libs/ms/newmail.c`'s `ProcessNewMail(..., PROCESSNEW_MBOX, ...)`
imports from a plain mailbox file returned by `GetPersonalMailbox()` in
`ams/libs/ms/findmbox.c` — a standard Unix mbox (`~/mailbox`, or the
`mailboxdir` profile override), with no AFS/AMDS/white-pages involved. This
is almost certainly the exact seam the user's fetchmail fork fed into at
MIT Athena. `AFS_ENV`/`WHITEPAGES_ENV` references in `ams/libs/ms/mswp.c`,
`init.c`, and `atkams/messages/lib/{ams,stubs}.c` are all `#ifdef`-optional
(`mswp.c:980` even has an explicit `#ifndef WHITEPAGES_ENV` fallback path),
confirming this is a first-class supported configuration, not a hack.

**Next action:** ~~flip `#undef AMS_ENV` → `#define AMS_ENV 1` in
`config/site.h`~~ — **done, 2026-07-05.** `AMS_ENV`/`CONTRIB_ENV` are on in
`config/site.h`. All newly-exposed subtrees (`atkams/messages/lib`,
`overhead/mail`, `overhead/eli`, `ams/libs/cui`, `ams/libs/ms`,
`contrib/srctext`/`eatmail`/`time`) fixed and verified compiling/linking
clean per-directory. User's first full top-level `make dependInstall`
(no `-k`) surfaced exactly 2 more link-time errors (`nns`'s `getla()`
needing `getloadavg()` instead of dead `/dev/kmem`+`nlist()`, and a
missing `${RESOLVER_LIB}` on `nns`'s link line) — both fixed same-day,
full details in `porting-changelog.md`'s 2026-07-05 entry. `ams/msclients/vui`
and `contrib/tm` — curses terminal clients on the removed BSD `sgtty` API —
remain conditionalized out of the build (`MK_VUI`/`MK_TM`) rather than fixed;
not needed for the GUI `messages` path. Rationale in `porting-assessment.md`
§7a. `ams/msclients/cui` was originally grouped with them but didn't actually
share that dependency — see the 2026-07-07 fix below.

First runtime test of `messages` (2026-07-05) segfaulted: `EXC_BAD_ACCESS`
in `_platform_strlen` via `mailconf.c`'s `CkAMSCellConfig` (`AndrewDir`/
`LocalDir` called with no prototype in scope — same LP64 #1 pattern fixed
at 23 sites on 2026-06-30, recurring because `overhead/mail` was never
built/audited before `AMS_ENV` went on). Fixed `mailconf.c` plus a sweep
of 5 more active files with the same bare-call pattern (`ams/libs/ms/init.c`,
`hdlnew.c`; `atkams/messages/lib/stubs.c`; `overhead/mail/metamail/metamail/{metamail,mailto}.c`;
`overhead/eli/lib/prims1.c`); all rebuilt clean. Full details in
`porting-changelog.md`. Separately, `contrib/bdffont` turned out to be
unbuildable (missing `bdfparse.act`, no generator, no fossil history) and
was conditionalized out (`MK_BDFFONT`); see `porting-assessment.md` §7b.
**✓ MILESTONE (2026-07-05):** `messages` is running. "mail (Private BB; 0 new
of 0)" confirmed in the folder panel. Three-pane layout, menu bar, and help
text all rendering correctly.

**Follow-up (2026-07-05): same-tip rebuild on host `spoon` segfaulted immediately.**
Real `SIGSEGV` (confirmed via `lldb`, not a codesigning/kernel-kill artifact),
in `CUI_GetHeaders`'s header-scanning loop. Two `long`/`int` mismatches in
`CUI_GetHeaders`'s `startbyte`/`nbytes`/`status` params, both invisible at
compile time (no prototype in scope at the mismatched boundaries) — same
LP64 Variant 5 family as `lpair__Init`/`style__SetNewIndentation`, but this
time crossing a plain unprototyped C call, not just the `void (*)()` vtable
macros. `ms/libs/ms/headers.c`'s `MS_HeadersSince` (`int`/`int *`) was the
outlier; `cuilib.c`'s `CUI_GetHeaders` and the dormant SNAP variant
(`cuisnap.c`) already agreed on `long`/`long *`. Fixed end-to-end
(`headers.c`, `ams.ch`/`amsn.ch`/`amss.ch`, `ams.c`/`amsn.c`/`amss.c`,
`capaux.c`, `foldaux.c`, dormant `ams/ms/ms.c`); rebuilt clean. Full detail
in `porting-assessment.md` §12 and `porting-changelog.md`. **Next up:**
retest on `spoon`.

**Stream 3 — atkams/ interface audit: resolved by the Stream 2 survey.**
`ams/Imakefile` and `atkams/messages/lib/Imakefile` show the boundary is
exactly the Imake flags above — `messages` links against the local
`libmssrv.a`/`libcuin.a` regardless of whether AMDS is present. No IMAP
adapter is needed for the local-store path; that fallback remains available
later if the mbox approach hits a wall.

**Contrib objects:** `CONTRIB_ENV` on brings in `calc demos gestures wpedit
time eatmail mit srctext` (see `contrib/Imakefile`); `tm` and `bdffont`
deferred (§ above). Still TBD whether any of these besides `srctext`
(already a proven inset, see Completed) matter for the messages path
specifically.

### gendemo — done; demo folder populates and reconstructs cleanly

**✓ (2026-07-07)** `cui` builds/links/installs — the blocker was a missing
`${RESOLVER_LIB}` link flag on its Imakefile (same bug class as `nns`'s
2026-07-05 fix), not the BSD `sgtty` API as originally assumed. `cui` doesn't
use curses at all, and its one sgtty reference was already dead code
(`POSIX_ENV` is unconditionally on for darwin). Full detail in
`porting-changelog.md`'s 2026-07-07 entry.

**✓ (2026-07-07)** `gendemo` itself has two independent bugs, both fixed:

1. It reads its 23 demo posts (`d1`/`d1.heads` ... `d23`/`d23.heads`)
   relative to the current directory, not `$ANDREWDIR` — those files live
   only in `src/ams/demo/` and are never installed. Must `cd src/ams/demo`
   before invoking it (`ANDREWDIR` is only used to find `cui`/`arpadate`).
2. With cwd fixed, `cui`'s final `recon` step segfaulted on the very first
   address caption it tried to build. Root cause: a **new bug class** — flex
   regenerates `overhead/mail/lib/parsel.c` at build time (no fossil
   history), and modern flex inverted the meaning of an internal init flag
   that a hand-written `pareset_lexer()` was poking directly instead of
   using flex's real public API. Fixed (`yyrestart(yyin)`); swept the whole
   tree and found/fixed one sibling instance (`overhead/eli/lib/elil.flex`,
   the ELI/FLAMES filter-language lexer — pre-emptive, no confirmed crash
   yet). Full writeup in `porting-assessment.md` §13, session detail in
   `porting-changelog.md`'s 2026-07-07 entry. Verified: `recon` completes
   ("Reconstructed folder ~/.MESSAGES/amsdemo with twenty-three entries")
   repeatably, no crash.

**Next up — two threads:**

1. ~~New, unrelated intermittent crash found while re-verifying `recon`~~ —
   **root-caused and fixed 2026-07-11.** The `memmove` heap overrun and
   unkillable-`UE`-state hang (escalated 2026-07-09) were both symptoms of
   the same bug: `mkparser`/`cparser.c` — the shared, hand-written parser
   engine used by *every* AUIS grammar, not just `prsdate` — assumes every
   LALR table is a `short`, but modern bison narrows several tables to
   1-byte types when a grammar's value range allows it. Reading a 1-byte
   array through a `(short *)` cast merges pairs of entries into garbage,
   which manifested as `parsedateheader()` failing on *every* input (not
   just certain years), sometimes cleanly (fast syntax error), sometimes by
   a runaway state-machine loop that grew the parser stack without bound
   (the `memmove` overrun) badly enough to occasionally take unbounded time
   (the `UE` hang). Full root-cause writeup: `porting-assessment.md` §15.
   Since the crash is gone, `gendemo`'s auto-invocation from
   `src/ams/demo/Imakefile`'s `install.time::` target (disabled 2026-07-09,
   `#if 0`/`#endif`) can likely be re-enabled — not done as part of this
   fix; left as a follow-up decision since it changes `dependInstall`'s
   default behavior.
2. Once `recon` is fully stable, verify `messages` can actually browse and
   read the populated `amsdemo` folder end-to-end (captions, dates, bodies).
   **Partially done 2026-07-11:** captions and Part 1…23 ordering verified
   correct interactively. Body content for each message not separately
   re-verified this session.

### IMAP / AMS backend investigation (week of 2026-07-14)

With `messages` running against the local mbox backend, investigate whether
an IMAP adapter behind `atkams/` is viable for connecting to a live mail
server. The `atkams/`–`ams/` boundary is already audited (see Stream 3 above);
this is the next architectural step toward real-world mail use.

### printf/fprintf %d/%ld audit
2,597 printf-family hits with `long` values and `%d` format specifiers
logged during the scanf audit. These produce wrong output for large values
but do not corrupt memory. Address as a batch; not blocking messages work.

### Xft phase 2 (deferred)
Menu text rendering via Xft. Menus are currently acceptable without it.
Only remaining X core font path dependency is Andy symbol and cursor fonts.

### Update quickstart.md
Remove resolved known-issues entries as each fix lands.

### Not current focus
- `typescript`, `bush`, `org` crashes — details consolidated under
  **Applications to Repair**; defer until after messages + M1 close
- `chart` — runtime-verified 2026-07-10 (see Completed); `launchapp`
  — inert (`MK_BASIC_UTILS` off), defer

---

## Medium-term

### ANSI C conversion (M1–M4) — plan of record, assessed 2026-07-08

Absorbs the former "Prototype sweep" and "Classpp typed dispatch" entries
here plus the long-term "ANSI C modernization" entry into one ordered
plan. Analysis — June mass-conversion postmortem, keystone finding, tool
verdicts, delegation guardrails — in `porting-assessment.md` §14.

Keystone: `.ch` files already carry full ANSI method signatures; classpp
parses and discards them. Emitting them (M1) type-checks every method
call site and definition tree-wide *before* any mass file editing starts
— the compiler becomes the auditor instead of grep.

- **M1 — classpp emits types.** Typed prototypes in `.eh` (today:
  `long text__Read();`) and typed casts in all `.ih` dispatch macros
  (extends the 2026-06-30 ≥9-arg fix to every method). Kills LP64
  Variants 2/3/5 structurally and catches signature drift (the
  `CUI_GetHeaders` class of bug) at compile time. The machinery
  already exists in classpp (`usePrototypesImport`/`Export`, `-p`,
  `-D` signature/`.desc` files, `$(CLASSFLAGS)` hook in andrew.rls —
  see porting-assessment §14 "M1 mechanics"); the code change is just
  splitting `-p` into `-pi`/`-pe` and dropping the `>= 8` gates behind
  `-pi`, defaults untouched. The real work is the per-directory
  rollout — see "M1 rollout points" below.
- **M2 point 0 — `-Wincompatible-pointer-types` triage (census
  2026-07-12, extended and partly fixed 2026-07-23/24).** A cheap,
  high-signal precursor to the M2 sweep proper: 483 warnings
  tree-wide, a fixed enumerable
  list, not requiring `-Wno-implicit-function-declaration` to come
  off anywhere. This is M1's bug signature (real/pointer size
  mismatches) surfacing in plain C calls that never went through a
  Class dispatch macro, so M1's typed casts had no chance to catch
  them. Grouping the log
  (`grep -B1 "Wincompatible-pointer-types\]" dependInstall.log`) by
  message pattern splits cleanly into benign-idiom noise and a few
  real-bug clusters:
  - **Benign, already covered by the M1 runbook's ruling — leave
    alone:** ~150+ instances of a subclass pointer passed where the
    cast names the defining superclass (prefix-layout subtyping,
    expected tree-wide); ~55 instances of `struct X * → char *`
    across many struct types (`egg`, `style`, `chartapp`, ...) plus
    the `int () → char *` cluster (55, mostly `roffcmds.c`/
    `rofftext.c`) — both are the pre-ANSI idiom of `char *` used as
    a generic pointer (this codebase's `void *` substitute, e.g.
    `hash.c`'s table API and roff command-handler tables). Cosmetic;
    M3/M4 territory if ever cleaned up, not a bug hunt.
  - **`fselect.c:65`(`overhead/util/lib`) — confirmed real, low
    urgency.** `int *` passed where libc's `select()` now wants
    `fd_set *`: 1988-era 4.2BSD int-bitmask `select()` calling
    convention, never updated when the platform moved to POSIX
    `fd_set`. Currently survives by coincidence, not correctness —
    Darwin's `fd_set` word size is 32 bits and the code clamps its
    fd count to `<= 32`, so the region `select()` actually
    touches stays inside the 4 bytes of the `int` it was given.
    Fragile, not an active corruption. Only live caller: `cui`
    (`ams/msclients/cui/unixmach.c`). Fix: real `fd_set` +
    `FD_SET`/`FD_ISSET`, own commit.
  - **`oldrf.c:221` (`atk/raster/lib`) — strong new lead on the
    already-logged raster RF bug, not yet root-caused.**
    `oldRF__WriteImage` declares `long buf[BUFBITS>>5]` and passes
    it straight to `pixelimage_GetRow`, whose real (Class-typed)
    signature is `GetRow(long x, long y, long length, short *dest)`
    — a `long`/`short` size mismatch (4x) landing directly in the
    read/write path. This lines up with the existing Insets to
    Repair → raster entry ("header fields appear 8 bytes wide";
    `convertraster intype=RF` read-back hang) closely enough that
    it's very likely the root cause or a major contributor — not
    yet traced through `GetRow`'s bit-packing logic far enough to
    hand over a fix. Same cluster (`long*`/`short*` mismatches,
    11 instances) also touches `raster.c`, `rasterio.c`, `paint.c`,
    `xwdio.c`, `suite.c` — worth surveying together once the
    `oldrf.c` root cause is nailed down, in case it's one shared
    bug pattern rather of five separate ones.
  - **`int */long*` cluster, 67 instances — CENSUS AND FIXES COMPLETE
    2026-07-24.** Full classification in
    `claude-history/m2/m2-census-REPORT.md`: 13 shared root shapes
    across two directions, all now fixed. 22 instances (one callee,
    `fontdesc_StringBoundingBox`) were caller-has-`long`-but-`.ch`-
    still-`int *`, the odd one out among its `StringSize`/`TextSize`
    siblings — fixed by widening to match (commit `0a6cf595ef`). The
    stretch-goal sweep (functions with *no* warning because the
    mismatch crosses a K&R untyped call boundary, same shape as
    `MS_GetConfigurationParameters` earlier in this doc) additionally
    found and fixed a live, reachable bug: `MS_ParseDate` writing a
    class-typed `long *` into a real `int *` implementation, hit by
    `captions__MarkRangeOfMessages`'s **uninitialized** `long`
    locals — worse than the usual zero-init-masked half-fill (commit
    `f4a9d6909b`). The remaining 45 instances (9 shapes) — the
    caller-declares-`int`-but-callee-wants-`long *` stack-overrun
    direction — were fixed 2026-07-24 by widening each caller's local
    to `long` after checking every secondary use for width
    assumptions (commit `d8af32c158`; also fixed 4 pre-existing
    `%d`-vs-`long` format-string mismatches found along the way).
    This rollout **caused a live regression, found and fixed the same
    session**: widening three `atkams/messages/lib` callers exposed a
    dormant 35-year-old `.ch`/real-implementation width drift (LP64
    variant #6 — `MS_GetDirInfo`/`MS_GetNewMessageCount`/
    `MS_GetSubscriptionEntry`/`MS_NameChangedMapFile` are `long *` in
    `ams.ch` but `int *` in their real `ams/libs/ms` implementations),
    producing a garbled subscription-status message in `messages`.
    Corrected by narrowing `.ch`/wrappers back to `int *` and
    reverting those three callers to `int` (commit `0f45da237d`); see
    `porting-assessment.md` §19 for the full writeup and the general
    rule it establishes — **before widening any Group-A-shaped caller,
    check the real K&R implementation's declared width directly, not
    just the `.ch`**, since `.ch` itself can be the stale side.
  - **`char ** → char *; remove &` cluster, 18 instances — FIXED
    2026-07-24.** Census found all 18 collapse to one root cause:
    three `CUI_*` methods (`CUI_DisambiguateDir`,
    `CUI_RewriteHeaderLine`, `CUI_RewriteHeaderLineInternal`) are
    typed `char *` in `ams.ch` when their real `cuilib.c`
    implementations take `char **` — every one of the 18 callers was
    already correct; clang's own "remove &" fix-it would have broken
    all of them. Fixed by widening the three `.ch` signatures
    (commit `c496c2a9ea`).

  **Status:** M2 point 0 is done except `oldrf.c` and `fselect.c`,
  which remain open (already scoped, independent of the sweeps above;
  one is tied to a known open bug — see Insets to Repair → raster).
  Neither blocks starting the M2 sweep proper.

- **M2 — Prototype sweep — COMPLETE 2026-07-25.**
  `-Werror=implicit-function-declaration` subtree-by-subtree
  (`src/config/darwin/system.mcr` COMPILERFLAGS); fixed by adding
  `#include`s or `extern` declarations at call sites. Closed Variant 1
  permanently — it had cost debugging time on every subtree activation
  before this. Real total: 3,888 fallout instances fixed across 29
  directories, well past the original census (2,353 instances/396
  files, 2026-07-24) once every directory's malloc-family blind spot
  was counted. Procedure, census, fallout taxonomy, and ordering:
  `claude-history/m2/m2-rollout-runbook.md` (shared session rhythm: `rollout-procedure.md`).
  Rollout points:
  1. [x] Pilot — `atk/eq` (done 2026-07-24; 10/10 census instances
     fixed — 8 missing `<string.h>`, 2 `eqview_Format` cross-file
     forward reference with no declaring header, fixed with an
     untyped K&R forward decl matching the tree's one existing
     precedent for it. Gate green, tree-wide and subtree-local both
     clean — first data point (not yet a ruling) that M2 fallout
     stays directory-local, unlike M1's cross-directory blast radius.
     Found one procedure gap, folded into the runbook: directories
     with bison/lex-generated sources need `make depend` before the
     subtree-local `install`, or the generated header's absence masks
     real warnings behind a fatal error.)
  2. [x] Small/leaf directory batch — `atk/frame`, `atk/adew`,
     `atk/value`, `atk/lookz`, `atk/help/src`, `atk/extensions`,
     `overhead/cmenu`, `overhead/fonts/cmd` (done 2026-07-24; 70/70
     census instances fixed across 24 files, all three taxonomy
     categories exercised — see `claude-history/m2/m2-batch2-REPORT.md`. Resolved the
     runbook's open `FoldedEQ` question: real function, not a typo.
     Found a third "missing in-tree/project header" sub-case: a
     header exists but is stale/incomplete, and the flagged
     directory already had its own local-extern habit for the gap
     (`overhead/cmenu`'s `cmdraw.h`, `atk/help/src`'s `index.h`) —
     matched that existing convention rather than editing the
     outside header. Second data point for "subtree-local gate is
     sufficient" — this time including a statically-linked,
     tree-wide-consumed directory (`overhead/cmenu`) — zero fallout
     beyond the flagged directories either time. Gate green,
     8-directory runtime check user-verified (`ez`, `help`,
     `fdbbdf`), no regressions.)
  3. Mid-size directories, batched (see runbook's proposed ordering):
     - [x] Batch A — `atk/basics/x`, `atk/basics/common`,
       `atk/figure`, `atk/syntax/tlex`, `atk/raster/cmd` (done
       2026-07-24; 137/137 census instances fixed across 34 files, no
       new taxonomy category — see `claude-history/m2/m2-batch3a-REPORT.md`. Third data
       point settling "subtree-local gate is sufficient," this time
       including the statically-linked X11/core-class directories and
       M1's former largest-blast-radius directory (`atk/basics/
       common`) — zero cross-directory fallout either time. Found and
       worked around (without editing) a real pre-existing bug in
       `overhead/cmenu/cmenu.h` (`_STDC_`/`__STDC__` typo). Runtime
       check surfaced a real `atk/figure` text-rendering bug —
       confirmed via controlled revert/rebuild/fresh-restart test to
       be pre-existing and unrelated to this fix; see Insets to Repair
       → figure.)
     - [x] Batch B — `overhead/eli/lib`, `ams/libs/cui`,
       `ams/msclients/nns`, `overhead/mail/metamail/richmail`,
       `overhead/index` (done 2026-07-24; 528 instances fixed across
       34 files — far past the runbook's stale "1–42 each" estimate
       for this bucket (`ams/libs/cui` alone was 350) — see
       `claude-history/m2/m2-batch3b-REPORT.md`. Fourth data point settling "subtree-
       local gate is sufficient," this time including `ams/libs/cui`
       (linked into `messages`'s `amsn.do`) at the largest volume yet
       — zero cross-directory fallout. Two new taxonomy sub-shapes
       found: a wrapper-family header (`fdplumb.h`) that only declares
       part of its family, recurring with no local precedent across 3
       directories; consumer-supplied callback interfaces with no
       declaring header anywhere (`ReportError` et al., `richmail`'s
       `controloutput`/`controlputc`). Resolved the open `overhead/
       index`/`index.h` question from rollout point 2: now that
       `overhead/index` is the flagged directory, extending `index.h`
       directly was correct (no competing local-extern habit).
       `overhead/eli/lib` found to have zero live runtime consumers in
       this build (`ams/ms`/`SNAP_ENV` disabled, `rdemo` unreferenced)
       — structural, not a testing gap. `ams/msclients/nns`'s
       pre-existing SSLLIB link failure confirmed unrelated. Runtime
       check user-verified (`messages`, `cuin`, `help`, `richtext`/
       `richtoatk`), no regressions.)
  4. [x] Large, dedicated-session territory (~70–140 instances each;
     gate schedule ruled 2026-07-24, see `claude-history/m2/m2-rollout-runbook.md`'s
     "Gate scope" section — subtree-local gate always required,
     tree-wide gate only where marked below):
     - [x] `overhead/util/lib` — subtree-local gate only (done
       2026-07-24; 74/74 instances fixed across 29 files — first
       bucket-4 directory where the real count matched the stale
       estimate exactly — see `claude-history/m2/m2-utillib-REPORT.md`. Confirms rather
       than undermines the gate-scope ruling: statically linked into
       both `runapp` and `amsn.do`, same shape as the four directories
       that already proved subtree-local sufficiency. Found a real
       methodology blind spot: `malloc`/`realloc`/`free` are clang
       builtins, so an undeclared call to one doesn't trigger the M2
       diagnostic at all — invisible to the `-k` census (caught via a
       `svcconf.c` near-miss before it became a bug; folded into
       `rollout-procedure.md`). First live test of the new
       command-style guidance: zero permission prompts across ~90 tool
       calls, strongly positive. Runtime check user-verified (`ez`,
       `messages`, test email sent), no regressions.)
     - [x] `overhead/mail/metamail/metamail` — subtree-local gate only
       (done 2026-07-24; 338/338 instances fixed across 7 files — far
       past the stale estimate of 70, mostly `metamail.c`/`mailto.c`'s
       own large same-file forward-reference populations — see
       `claude-history/m2/m2-metamail-REPORT.md`. Structurally strongest gate-scope data
       point yet: this directory builds only `ProgramTarget`s, no
       library at all, so cross-directory fallout is structurally
       impossible, not just empirically absent. Runtime check found
       metamail crashes (SIGTTOU in `ExecuteMailcapEntry`'s `ioctl`
       call) and `mailto`/`splitmail` fail on a missing
       `/usr/lib/sendmail` — both confirmed pre-existing and unrelated
       to this fix (metamail's non-functionality on this platform was
       already documented before this session; root cause now
       identified, see "Objective: HTML mail rendering"). `mmencode`
       round-tripped correctly. User-verified, proceeding to commit.)
     - [x] `atk/text` — subtree-local gate only (done 2026-07-24;
       50 census-visible instances matched the stale estimate exactly
       — but that match was misleading: a directory-wide sweep for
       the malloc-family blind spot (see below) found 106 more
       call sites across 18 files, invisible to the M2 census
       entirely, real total 156 across 23 files — see
       `claude-history/m2/m2-text-REPORT.md`. Cleanest gate-scope data point yet: every
       function touched confirmed statically linked directly into
       `runapp` via `nm -g`. Found a class family (`textv.do`/
       `text.do`'s 8 files) with three independently-invented,
       non-overlapping local-extern conventions — matched whichever
       precedent existed per file. User-verified (`ez` editing/
       read-only/save-restore/insert-file/style-editor, `Sherman.Alloc`
       render, `indexpro` CLI), no regressions; `indexpro.c`'s
       pre-existing `gets()` call triggers a macOS runtime deprecation
       warning, unrelated to this fix, logged as a minor pre-existing
       finding, not fixed here.)
     - [x] `atk/rofftext` — subtree-local gate only (done 2026-07-24;
       54 census-visible instances (vs. stale estimate 47) plus 50
       more from the mandatory malloc-blind-spot sweep, real total 104
       across 9 files — see `claude-history/m2/m2-rofftext-REPORT.md`. New taxonomy
       wrinkle: one same-file forward reference fixed by adding
       `#include <roffcmds.h>` (the file that defines the whole
       `*_cmd` family had never included its own already-complete
       header) rather than a hand-written extern. Structurally the
       cleanest gate-scope case yet: no `LibraryTarget` at all, only
       dynamically-loaded `.do` targets, confirmed via `nm -g` to have
       zero symbols in `runapp`. User-verified via `help` (roff
       rendering correct) and the standalone `rofftext` converter
       (well-formed `.ez` datastream output, brace-matched throughout
       — a good correctness signal for the `BeginStyle`/`EndStyle`/
       `CloseStyle` style-stack fixes specifically), no regressions.)
     - [x] `atk/table` — subtree-local gate only (done 2026-07-24;
       154 census-visible instances (vs. stale estimate 113) plus 32
       more from the mandatory malloc-blind-spot sweep, real total 186
       across 9 of 10 files (`print.c` needed zero fixes) — see
       `claude-history/m2/m2-table-REPORT.md`. Two new findings: (1) malloc-sweep
       methodology gap — `table.c`'s own `myrealloc()` wrapper false-
       positives under a naive substring `grep`; sweep pattern is now
       word-boundary-anchored and space-tolerant in
       `rollout-procedure.md`; (2) new taxonomy sub-case — a
       class-internal double-underscore method's declaration exists in
       `spread.eh` but only outside an `AUXMODULE` guard, structurally
       unreachable from the one `AUXMODULE`-consumer file (`update.c`)
       that calls it via a macro that (unusually) dispatches directly
       rather than through the routine table; fixed with a commented
       local extern. Structurally the same `DynamicMultiObject`-only
       shape as `atk/rofftext` (no `LibraryTarget`), confirmed zero
       symbols in `runapp`. User-verified (menu-inserted spreadsheet,
       formula evaluation incl. a deliberate malformed-formula error
       case, save/reload round-trip, direct `table` binary launch,
       `.table` file-type auto-load), no regressions; bare `table`
       binary with no file opens a plain-text `ez` buffer with no
       table-insert path — matches `ez`'s own bare-launch default,
       not investigated further as a possible bug.)
     - [x] `overhead/mail/lib` — subtree-local gate only (done
       2026-07-25; 112 census-visible instances (matched the stale
       estimate exactly) plus 12 more from the malloc-blind-spot
       sweep, real total 124 across 22 of 33 files — see
       `claude-history/m2/m2-mail-lib-REPORT.md`. Widest-fan-out directory examined yet
       (`libmail.a`, ~25 consumer directories); extra `nm -g`
       verification against 3 structurally distinct real consumers
       (`amsn.do`, `cuin`, `overhead/mail/cmd`'s standalone tools)
       found zero symbol leakage, confirming subtree-local gate holds
       even at this scale. No new taxonomy category; malloc-sweep
       findings cleanly split into three shapes (invisible blind spot;
       stale wrong-typed extern that only became a hard conflict once
       `<stdlib.h>` was added; dead/unused stale externs). Caught and
       fixed its own self-inflicted `*/`-in-comment syntax error
       immediately. User-verified (`arpadate` standalone check, `cuin`
       startup, fresh `messages` process folder-list load), no
       regressions.)
     - [x] `atkams/messages/lib` — tree-wide gate required (the
       `messages` app's actual backend) (done 2026-07-25; 212
       census-visible instances (vs. stale estimate 140) plus 124 more
       from the malloc-blind-spot sweep, real total 336 across 18 of
       23 files — see `claude-history/m2/m2-messageslib-REPORT.md`. Both gates required
       and both clean: subtree-local twice for determinism, plus the
       full tree-wide `make Clean && make dependInstall`
       (233,099-line log, same 4 pre-existing baseline errors every
       prior session has documented, zero new ones, confirmed none
       fall within this directory's own build span). `SNAP_ENV`
       confirmed disabled empirically; `amss.c`/`amss.do` never enter
       the build graph. Concrete LP64 finding: 6 functions (`CUI_
       DisambiguateDir`, `CUI_GetHeaders`, `CUI_Initialize`,
       `MS_GetDirInfo`, `MS_MatchFolderName`, `MS_UnlinkFile`) are
       `long`-returning at their real definitions while ~65 sibling
       functions in the same two families default to `int` — sourced
       from two independent places before declaring. No new taxonomy
       category; explicitly ruled out a recurrence of `atk/table`'s
       `AUXMODULE` sub-case. User-verified (fresh `messages` process
       with a real IMAP-backed folder list, opening a message,
       composing/sending, folder tree, scrolling, options panel), no
       regressions.)
     - [x] `contrib/zip/lib` — tree-wide gate required (tree's
       highest-defect-density directory) (done 2026-07-25; 145
       census-visible instances (vs. stale estimate 141) plus 111
       more from the malloc-blind-spot sweep, real total 256 across 24
       of 41 files — see `claude-history/m2/m2-ziplib-REPORT.md`. Both gates clean,
       including the second subtree-local determinism pass at the
       directory's normal unmodified `-O` level to confirm no new
       anomaly near the known pre-existing `-O`-only rendering bug
       (none found). `AUXMODULE` sub-case explicitly ruled out
       (structurally, zero files define it). Third concrete LP64
       finding (`zip_Enparse_Stream`/`zip_Deparse_Stream`, both
       `long`-returning). User-verified with two new, real,
       pre-existing (confirmed unrelated to M2 via direct diff
       inspection) findings logged for dedicated investigation: zip/
       calc insets failing to load when embedded in a mixed-content
       document (see "Insets to Repair" below), and `ez` horizontal
       text-block drag locking at position 0 after the first drag
       (see "Little Annoyances" above). **Bucket 4 complete** — next
       is the fixed tree-wide checkpoint before `ams/libs/ms`.)
     - [x] Fixed checkpoint after the last bucket-4 directory: tree-wide
       gate required regardless of which directory precedes it. Done
       2026-07-25, run directly by the orchestrator (pure verification,
       no fix work): `make Clean && make dependInstall`, exactly the
       same 4 pre-existing baseline errors every M2 gate has
       documented, zero new ones anywhere in the tree. **Bucket 4
       fully closed.**
  5. [x] `ams/libs/ms` (its own dedicated session; briefed on the
     fdplumb history first via `claude-history/fdplumb-REPORT.md`).
     Done 2026-07-25; 1567 census-visible instances (vs. stale
     estimate 892) plus 2 more from the malloc-blind-spot sweep, real
     total 1569 across 102 files — by far the largest single directory
     in the whole sweep (114 `.c` files, ~38% of the original
     tree-wide census) — see `claude-history/m2/m2-amsms-REPORT.md`.
     Both gates required and both clean: subtree-local twice for
     determinism, plus the full tree-wide gate (238,642-line log, same
     4 pre-existing baseline errors every M2 gate has documented, zero
     new ones, this directory's own build span independently confirmed
     clean) — this gate doubles as **M2's own completion gate**.
     Strongly confirmed the runbook's "a handful of functions
     dominate" prediction (top 10 functions = 45.6% of the total, all
     5 of the runbook's own named examples in the actual top 6); the
     `fdplumb.h` partial-wrapper-family gap alone accounted for 300
     instances, the largest such population found in the sweep.
     Two more concrete LP64 mixed-width findings (`conv64tolong`,
     `KRHash`, both `unsigned long`) plus three genuine near-misses
     where a naive first-match grep would have picked the wrong
     same-named function from an unrelated directory — all correctly
     resolved by checking real definitions and call-site usage.
     Self-caught and fixed a bulk-insertion bug (new declarations
     briefly landing inside a dead `#ifdef AFS_ENV` block; caught by
     the next rebuild, fixed with nesting-depth-aware insertion,
     re-derived all affected files fresh). Notable open finding: the
     malloc-family blind spot's invisibility itself stopped holding
     partway through this session (`malloc`/`free`/`realloc` became
     census-visible, independently reproduced on this machine) — most
     likely a toolchain update mid-project; doesn't affect correctness
     anywhere since the sweep was always run unconditionally regardless
     of census visibility. User-verified (`messages` folder list and
     message open, `cuin`, a test send, `imapsync`, folder
     subscribe/unsubscribe), no regressions.

- **M3 — Definition conversion.** `ansify` (`revival/tools/ansify`,
  built and validated 2026-07-08 — see porting-assessment §14):
  static-fix tools → class methods/classprocs by signature-DB lookup
  (`ansify --build-db`, 565 classes) → file-local helpers from their
  own K&R declarations, strict parser (cproto rejected: can't read
  macOS SDK headers) → per-file compile gate with auto-restore.
  Per-subtree step: add `-pe` to the directory's `CLASSFLAGS` (its
  `.eh` must be prototyped in the same step — narrow param types like
  `char` conflict with typeless `.eh` decls otherwise; proven on
  `eq__WriteFILE`), force regen, `ansify --dir`, clean build, triage
  DRIFT reports, commit. One subtree per commit, dependency order:
  overhead → atk/basics+support → atk/text → insets → apps →
  atkams/ams → contrib. Ratchet each completed subtree from `-Wno-*`
  to
  `-Werror=implicit-int,strict-prototypes,int-conversion,incompatible-function-pointer-types`.
  Procedure, gate-scope reasoning (stronger locality guarantee than M2
  had — `.eh` is never installed tree-wide, same-directory quoted
  include only), ordering rationale, and batching plan:
  `claude-history/m3/m3-rollout-runbook.md`. **M3 complete 2026-08-01**
  — 15 sessions, all 91 active directories converted; retired to
  `claude-history/m3/` (prompts, reports, `m3-batches.md`, the runbook
  itself) now that the milestone is closed.
- **M4 — Global strictness.** Tree-wide `-Werror` on
  `implicit-int,int-conversion,incompatible-function-pointer-types,implicit-function-declaration`;
  `-Wformat` then catches any remaining scanf `%d`/`%ld` (Variant 4)
  automatically. **`strict-prototypes` dropped from the set (Phase 0
  finding, 2026-08-01, pending confirmation)** — unlike the other three,
  it doesn't isolate real bugs here: ~6,024 tree-wide matches, almost
  all the deliberate C89 "unspecified arguments" idiom M2/M3 used
  correctly and on purpose, not leftover K&R. Keep `-std=gnu89` until
  conversion completes; consider c99 after. Writable-strings stays
  deferred. **Phase 0 (audit) and Phase 1 (global flip + census) both
  complete 2026-08-01.** Real census: 1,778 errors across 83 of 91
  directories (`implicit-int` 1,079, `incompatible-function-pointer-types`
  515, `implicit-function-declaration` 183, `int-conversion` 0 clean) —
  far past the "small residual" the plan hoped for, so this milestone
  does need a real directory batch map after all: `m4-batches.md`, 24
  batches across the same 7 dependency-order waves M3 used, built from
  the real per-directory counts. Also found and fixed a real prerequisite
  blocker along the way: classpp itself (`overhead/class/pp/class.c` and
  `overhead/class/lib/class.c`) failed to compile under the new flags,
  cascading into every `-pe`/`-pi` consumer — fixed (missing `stdlib.h`,
  two missing forward declarations, two missing return types), verified,
  not yet committed. Task breakdown, verified starting state, the
  `strict-prototypes` finding, and the classpp fix in full:
  `m4-rollout-runbook.md`. Phase 3 (fixing the real fallout) not yet
  started.

Scale: ~13,700 K&R definitions across ~1,301 of 1,544 `.c` files; ~5,100
are class methods converted by `.ch` lookup, not inference. M2/M3 runs
are delegable (Sonnet-class) under the §14 guardrails; M1 and
`.ch`-vs-`.c` signature disagreements stay top-level.

#### M1 rollout points (Import half: `CLASSFLAGS = -pi` per directory)

Rollout state lives only in committed Imakefiles; classpp defaults
never change until step 10. Per-step rhythm: set `CLASSFLAGS` → force
regen (delete the directory's generated `.ih`/`.eh` or touch its
`.ch`s) → `make Clean; make dependInstall` → fix consumer fallout →
runtime spot-check → commit. Clean build passing is the definition of
done. Ordering is by external-consumer count (survey 2026-07-08,
porting-assessment §14), not directory nesting: pilots on
zero-consumer leaves, then the core, largest last.

1. [x] classpp: `-pi`/`-pe` split, `>= 8` gates dropped under `-pi`
       (done 2026-07-08; verified byte-identical default output,
       binary installed)
2. [x] Pilot A — `atk/eq` (done 2026-07-08; clean-build gate green,
       eq inset visually verified in `Sherman.Alloc`. Findings — see
       porting-assessment §14 "Pilot A findings": macro-parameter
       capture bug class, fixed structurally in classpp; DoScript
       stray-`*` DRIFT in `eq.ch`, a ~35-year-old typo caught by the
       first typed rebuild; two process wrinkles for the runbook)
3. [x] Pilot B — `atk/figure` (done 2026-07-09; clean-build gate
       green, figure inset visually verified in `95Summer.ez` —
       behavior unchanged; new pre-existing menu-focus bug logged
       under Little Annoyances. Findings — see
       porting-assessment §14 "Pilot B findings": typeless `.ch`
       declarations (`MoveHandle`), rock-idiom `long`→`void *`, and
       a six-file `Build(action, v)` vs runtime `(v, action)`
       transposition — the `.ch` was wrong for ~35 years; all fixes
       interface-side only)
4. [x] First cross-directory step — `atk/raster/lib` (done 2026-07-09;
       ZERO fallout — the seven codec `.ch`s were accurate; consumers
       `raster/cmd` + `raster/convert` rebuilt clean against typed
       `.ih`; gate green. First before/after test protocol:
       `convertraster` battery byte-identical to pre-rollout baseline
       (`~/src/AUIS/test-baselines/raster-pi/`, incl. Xbitmap
       round-trip == identity invariant); user visually verified
       92Sep.ez raster inset and face.raster negate/flip-lr/flip-ud
       before and after. Pre-existing RF read hang logged under
       Little Annoyances pre-flip)
5. [x] `atk/frame` (5 classes, 95 external; done 2026-07-09; gate
       green, frame chrome (windows, menus, scrollbars) visually
       verified. Findings — see porting-assessment §14: `Enumerate`'s
       `long functionData` rock retyped to `void *`; six call sites
       across five files (`framecmd.c` x4, `atk/textaux/contentv.c`,
       `atk/extensions/{compile,tags,deskey}.c`) carried a redundant
       `(long)` cast on the pointer they passed — a one-caller-in-five
       omission (`framecmd.c:768`, bare pointer, no cast) is what
       first exposed the pattern as a live disagreement, which in
       turn prompted a runbook revision pre-authorizing deletion of
       these casts as part of the rock-idiom interface fix, since
       they launder a pointer through `long` rather than mean
       anything. First rollout point with import fallout in
       directories other than the flagged one, confirming the
       blast-radius-asymmetry prediction in §14)
6. [x] `atk/supportviews` (17 classes, 178 external; done
       2026-07-09; gate green, `help` app scrollbars/panel
       expand-shrink/matte chrome and `ez` visually verified. One
       fallout: `sbutton.ch Enumerate`'s `long rock` retyped to
       `void *` — same rock-idiom pattern as `atk/frame`/`atk/figure`,
       all three tree-wide callers already passed bare pointers, no
       `(long)` casts to delete)
7. [x] `atk/text` (21 classes, 321 external; done 2026-07-09; gate
       green, `help` regression checklist and `ez` (`Cattey.Writing`
       fnote, `ex14.doc` textref) visually verified. Two rock-idiom
       fallouts, same pattern as points 5/6: `pcompch.ch`
       `ATKToASCII`/`ASCIIToATK` and `text.ch` `EnumerateEnvironments`
       `long rock` retyped to `void *`; `EnumerateEnvironments` again
       showed the bare-vs-laundered-cast split (one caller in
       `atk/lookz/lookzv.c` passed the pointer bare, five callers in
       `atk/text` laundered via `(long)` — all five casts deleted per
       the point-5 pre-authorized exception). No new fallout pattern)
8. [x] `atk/support` (19 classes, 450 external; done 2026-07-09; gate
       green, `help` app, `ia-archive/jan.90`'s `lset`/`buttonV`
       widget (first proof of both, previously unproven insets), and
       a `File > Save All` buffer command all visually verified. Two
       rock-idiom fallouts: `buffer.ch` `Enumerate`/`EnumerateViews`
       — same pattern as points 5-7 (8 of 9 callers laundered a
       pointer via `(long)`, one bare-pointer omission at
       `framecmd.c:552` exposed it). `list.ch` `Enumerate` — a
       genuine hard stop, escalated mid-session: rock declared
       `char *` but two callers (`dired.c` `FindPosProc`, `buttonv.c`
       `findkey`) pass real `long` integers compared numerically,
       disagreeing with ~40 pointer-passing callers elsewhere.
       Resolved as a new **dual-use rock** pattern (ruling added to
       the runbook's rock-idiom bullet): retype to `void *`; the
       integer call sites get an explicit `(void *)` cast
       (`dired.c:348`, `buttonv.c:489`, plus a third found while
       sweeping, `prefs.c:513` in `atk/prefed`, which isn't part of
       the default build — `MK_PREFS`/`MK_AUX_UTILS` are off — so
       harmless but unverified locally); pointer call sites drop
       their now-redundant casts; callbacks (`FindPosProc`,
       `findkey`) untouched, since they're invoked through typeless
       `procedure` pointers outside `-pi` checking. Also: the gate
       surfaced an unrelated pre-existing hang — see `gendemo` below
       — worked around, not a rollout fallout.)
9. [x] `atk/basics/common` (41 classes, 2,351 external; done
       2026-07-09; gate green after four cycles, `help`/`ez` runtime
       battery visually verified. The directory's own `.ch`s had ZERO
       local fallout; all fallout was consumer-side rock collisions.
       16 rocks retyped `void *` across 10 `.ch`s (menulist
       AddToML/Chain*/Unchain/GetChained, im HandleMenu/
       AddZombieHandler/EnqueueEvent/SetInteractionEvent/
       SetDeleteWindowCallback, keystate SetOverride, init Load,
       view PostResource, namespace/proctable Enumerate, message
       AskForStringCompleted); `keymap_BindToKey` stays `long` under
       the new integer-majority ruling. ~100 call-site cast edits in
       ~50 consumer files, driven by static censuses, not the gate
       log (censuses + mechanical edits delegated to cheaper-model
       agents — see §14 "Point 9 findings" and the runbook's new
       methodology notes). Real bugs caught: clockv.c NewString
       missing prototype (LP64 pointer truncation), suite.c laundered
       out-params, htmlview.c DisplayString arg transposition (fixed
       as separate commit per ruling), filetype.c DeleteEntry
       attributes** misuse (logged, untouched))
10. [x] Breadth: remaining atk (`value`, `adew`, `apt`, `basics/wm`,
       `basics/x`, `hyplink`, `syntax/parse`, ...), then `atkams`/
       `ams`, `contrib` (`zip/lib` first), `examples` — delegable
       batches (one session + one gate per batch, ruled 2026-07-09;
       exhaustive batch list + per-session prompts:
       revival/doc/claude-history/m1-point10-batches.md)
       - Batch 1 (2026-07-09): `atk/value`, `atk/adew`,
         `atk/apt/{apt,suite,tree}`, `atk/controllers` (inert — not
         in default build). Two live-LP64-bug classes fixed (suite
         unsigned rocks feeding every handler callback; LinkTree
         missing param decl), the suite+treev attribute-pair
         convention expanded at 95 dispatch sites across 12 files,
         and two long-dormant caller bugs caught (bushv title-as-code
         no-op; chartv `*X`-for-`&X` CaptureString corruption) — see
         porting-assessment §14 "Point 10 batch 1 findings" and the
         runbook's new unsigned-rock and variadic-by-macro bullets.
       - Batch 2 (2026-07-10): `atk/basics/x`, `atk/basics/wm`
         (inert — `WM_ENV` off). ZERO fallout: census clean (no pair
         macros, no rocks, overrides match the point-9-typed
         defining classes), gate green first pass, full ez + help
         regression verified. Imakefile-only, like raster/lib.
         Census note: classpp shares comma types like C
         (`GrayPattern(short a, b)` casts as `(short, short)`) —
         verified empirically, not drift. [Correction, batch 3:
         classpp does NOT comma-share — override macros take the
         defining class's typed decl, which is what GrayPattern
         showed; see batch 3 findings.]
       - Batch 3 (2026-07-10): `atkams/messages/lib` alone. Gate
         green first pass, all fallout local (19 errors, one ring);
         messages runtime fixture verified. Seven `.ch` drift fixes
         (cvEng typeless, DisplayNewBody bare params, PostMenus
         by-value struct, AlterSubscriptionStatus 35-year arg
         transposition, ReadFromFile file-private `Boolean`,
         SetCUIRock rock→`void *` + one pre-authorized `(char *)`
         cast at ams.c:120). New pattern for the runbook: an
         unknown type token in a `.ch` (`proc`, a file-private
         typedef) emits an implicit-`int` cast param under gnu89 —
         a typed cast that lies, truncating function pointers on
         LP64; fixed `proc`→`procedure` in ams/amsn/amss.ch and
         cross-directory in `orgv.ch` (fldtreev inherits it;
         classpp reads the INSTALLED parent `.ch`, so the fix
         needed `make install` in atk/org). See porting-assessment
         §14 "Point 10 batch 3 findings".
       - Batch 4 (2026-07-10): `atk/image`, `atk/hyplink`,
         `atk/console/lib` + `atk/console/cmd` (both inert —
         `MK_CONSOLE`/`MK_BASIC_UTILS` off, no generated Makefile, no
         `console` binary), `atk/raster/cmd`. Gate green first pass.
         Two known-taxonomy fallout fixes, no new patterns: `image`'s
         `sliderv.ch SetCallback` rock (`long`→`void *`, sole caller
         `cmapv.c` passes a bare pointer); `hyplink`'s `pshbttn.ch
         ParseRGB` signature drift (`unsigned char rgb_vect` declared
         by value, impl + all four callers use it as an array,
         matching the already-correct `GetFGColor`/`GetBGColor`
         siblings). `raster/cmd`'s own four `.ch`s were zero-fallout
         (fully typed already). `convertraster` battery run for
         due-diligence but doesn't actually verify `raster/cmd` —
         `convrast.c` only includes `raster/lib` headers, never
         `raster/cmd`'s; byte-identical regardless. Runtime: hyplink
         verified via `PAPERS/conf/1995/widgets.ez`
         (pushbutton→link→linkview), raster/cmd verified via
         `NEWSLETTERS/EZ/92Sep.ez`'s raster inset; `image` accepted
         gate-only (no known fixture for its picture-format codecs,
         zero-caller local fix only).
       - Batch 5 (2026-07-10): `atk/chart`, `atk/org`, `atk/bush`,
         `atk/fad`, `atk/layout`, `atk/table`. Gate green first pass
         (all fallout caught and fixed during chart's local
         `make -k install`, before the tree-wide gate ran). chart
         carried the suite-identical variadic-by-macro attribute
         family across two classes (`chart.ch` Chart/Item Attribute,
         `chartv.ch` Chart/ChangeChart Attribute) — true arity
         declared, ~45 dispatch call sites mechanically rewritten
         (all local to atk/chart, zero external consumers), pair
         macros fenced for `*_Specification`-table-only use, per the
         ruling already in hand. `chartobj.ch` also had a ~35-year
         signature-drift typo (`SetDataObject(struct char *)` →
         `struct chart *`) and four typeless declarations
         (`WhichItem`, `SetChartOptions`, `HitChart`, `ObserveChart`);
         `HitChart`'s typeless override repeated across five
         subclasses (chartcsn, charthst, chartmap, chartpie,
         chartstk). Two dual-use-attribute-value call sites
         (`chartobj.c`, `chartpie.c`, `PrintString` argument) were
         missing the `(char *)` cast their siblings already had —
         found only once the tree-wide gate walked past the local
         rebuild's stopping point. `org.ch NodeName(node)` was fully
         typeless (zero callers tree-wide, so zero fallout risk);
         typed from the impl. `bush`, `fad`, `layout`, `table` were
         all zero-fallout — census clean, gate green, no `.ch`/`.c`
         edits needed. No new patterns for porting-assessment §14.
         Runtime: chart verified interactively (create/format/label a
         chart); fad+table verified via `Sherman.Alloc`. Two
         pre-existing bugs surfaced by first-ever runtime tests, not
         regressions (both logged under Little Annoyances): org
         crashes loading a file (`Read_Body`'s `tmpnam`/`strcpy`
         misuse, same overlapping-strcpy-under-fortify class as
         bush's already-logged InitTree crash); Sherman.Alloc's
         complex layout inset renders with excess whitespace margin
         (zero atk/layout files touched this batch, so presumed
         pre-existing). bush's pre-existing startup crash confirmed
         unchanged.
       - Batch 6 (2026-07-10): `atk/textobjects`, `atk/textaux`,
         `atk/rofftext`, `atk/srctext`, `atk/typescript`, `atk/lookz`.
         Gate green first pass. No attribute-pair macros anywhere in
         this batch. Three genuine drift fixes, no new patterns:
         `rofftext/rofftxta.ch` had two typeless declarations
         (`ParseArgs(argc,argv)`, `InitializeObject(self)`) typed to
         match every sibling app's `ParseArgs(int argc, char **argv)`
         and the impl's `struct rofftextapp *self`; `srctext/hlptext.ch`
         and `srctext/rawtextv.ch` each had a signature-drift
         `InitializeObject`/`FinalizeObject` typed to the WRONG
         sibling struct (`struct srctext *`/`struct srctextview *`
         instead of their own class), caught immediately by the
         local rebuild since both are cast-incompatible pointer
         types. `textobjects/dired.ch`'s `EnumerateAll`/
         `EnumerateMarked` rock retyped `long`→`void *` (all three
         tree-wide callers in `diredv.c` already pass pointers, same
         rock-idiom precedent as frame/figure/supportviews).
         `textobjects/chlist.ch`'s `AddItemAtIndex` had a ~35-year
         transposed-parameter signature drift (`.ch` declared
         `(str, index, ...)`, impl and its sole caller use
         `(index, str, ...)`) — fixed to match. `srctext.ch`'s
         `Lookup` classprocedure was missing the `**`/`[]` on its
         hash-table parameter (declared `Dict hashTable` by value;
         impl and all 8 tree-wide callers use `Dict *hashTable[]`,
         and its two sibling classprocs `BuildTable`/`HashInsert`
         already had it right) — an isolated typo, not a pattern.
         `textaux`, `typescript` were zero-fallout. Runtime: lookz
         verified via `PAPERS/atk/Hansen.Algebra`; textaux's
         `contentv` (Table of Contents) verified via
         `PAPERS/atk/Cattey.Writing` (Hansen.Algebra has no section
         headings, so ToC has nothing to discover — Cattey.Writing is
         the fixture to reuse); help app confirmed no regression
         (textobjects' only live consumer, `panel`). srctext and
         textobjects' `dired`/`chlist`/`unknown` accepted gate-only —
         no srctext/ctext document exists anywhere in ia-archive,
         PAPERS, or NEWSLETTERS, and `dired`/`chlist`/`unknown` have
         no live consumer in the default build (chlist's only callers
         are contrib/wpedit and contrib/bdffont, neither built; dired
         and unknown have zero call sites anywhere, presumably
         reflective/by-name loading for unknown). typescript crashes
         on launch (new pre-existing bug, logged under Little
         Annoyances): `typescript__Create` doesn't check `typescript_New()`
         for NULL before calling `SetDataObject` on it, and `New()`
         returns NULL because `InitializeObject` fails at
         `GetPtyandName` ("Can't connect subchannel") — zero
         atk/typescript files were touched this batch (fully
         zero-fallout), so this cannot be caused by the diff.
       - Batch 7 (2026-07-10, live subset only): pre-flag census found
         8 of the planned 12 directories (`ezprint`, `preview`, `toez`,
         `datacat`, `launchapp`, `createinset/null`, `music`, `prefed`)
         are currently inert — `MK_BASIC_UTILS`/`MK_AUTHORING`/
         `MK_AUX_UTILS` are all off in `allsys.h` and no per-app
         override (`MK_EZPRINT`, `MK_PREVIEW`, etc.) is defined, so none
         are in `atk/Imakefile`'s `SUBDIRS` and none have a generated
         Makefile; deferred to a future batch (user decision: split
         rather than flip the macros on). The `ez2ascii`/`ez2ps`
         binaries already in `build/bin` are leftovers from
         `contrib/mit/util` (batch 11, gated by `CONTRIB_ENV`, also
         off) plus a csh wrapper — not built from `atk/ezprint` at all,
         so the planned CLI byte-diff battery had no live target and
         was skipped along with the rest of the deferred 8.
         [Correction, 2026-07-10 active-tree census: `CONTRIB_ENV`
         is ON in `config/site.h` (since 2026-07-05) and
         `contrib/mit/util` IS in the default build — the gate log
         shows `building (dependInstall)` descents into it, and
         `ez2ascii`/`ez2ps` are rebuilt live by every gate, not
         leftovers. The "not built from atk/ezprint" half of the
         finding stands; the "CONTRIB_ENV off" half was a
         mis-census — see the Active tree section below for the
         reliable liveness check.] Ran the
         full runbook on the 4 live directories instead: `atk/ez`,
         `atk/utils`, `atk/help/src`, `atk/extensions` (all
         unconditionally in `BASICS`). Gate green first pass. Six
         genuine drift fixes caught by census before any build, no new
         patterns: `utils/dialog.ch` and `utils/dialogv.ch` each had
         `InitializeObject`/`FinalizeObject` typed to the wrong
         sibling struct (`struct sbutton *self` instead of their own
         class) — same pattern as batch 6's hlptext/rawtextv;
         `help/src/hlptextv.ch` had the identical wrong-sibling-struct
         drift (`struct srctextview *self` instead of
         `struct hlptextview *self`) — a different file from batch 6's
         srctext/hlptext.ch, just a confusingly similar name.
         `help/src/help.ch` and `help/src/helpdb.ch` each declared
         `InitializeClass(struct help(db) *self)` with a bogus extra
         `self` param the implementation doesn't take (impls take only
         `classID`, matching the universal zero-param
         `InitializeClass()` convention every other class uses).
         `extensions/ezdiff.ch` had the opposite arity drift:
         `FinalizeObject()` was missing its `self` param entirely
         (impl is `ezdiff__FinalizeObject(classID, self)`).
         `utils/dialogv.ch`'s `PostInput` `choicerock` was a rock-idiom
         retype (`long`→`void *`; its one tree-wide caller,
         `frame.c:1746`, already passes a bare pointer). Traced how
         `InitializeObject`/`FinalizeObject`/`InitializeClass` arity
         actually matters under `-pi` despite the user-facing
         convenience macros having zero external callers tree-wide:
         classpp's auto-generated `Destroy`/`Finalize` wrapper code
         (baked into the `.eh`) calls the raw `classname__FinalizeObject`
         function by the fixed `(classID, self)` convention regardless
         of what the `.ch` declares, so a `.ch` arity mismatch becomes a
         real prototype conflict once `-pi` is on — not dormant.
         Confirmed `struct thisobject *self` (used pervasively for
         `InitializeObject`/`FinalizeObject`/`ObservedChanged` self
         params across dozens of files, including several already
         flagged in batch 1) is a real, working classpp idiom that
         resolves to `void *` even under `-pi` — not a bug, left alone
         everywhere it appears (`strinput.ch` included). Runtime:
         `ez` launch confirmed (including an Extensions-menu command);
         a Quit-with-unsaved-changes confirmation dialog exercised the
         `dialog.ch`/`dialogv.ch` fix and the `PostInput` rock retype
         directly; `help` launch confirmed, including a
         `hlptextview`-rendered topic with working hyperlinks. All
         three user-verified, no regressions. Checkins: bug fixes
         105b96414a, rollout 165e3862b6.
       - Batch 9 (2026-07-10, live subset only, batch 8 skipped ahead
         of per user request): pre-flag census found 21 of the 22
         planned directories inert — all 19 `atk/examples/ex*` dirs
         (`MK_EXAMPLES` off in `allsys.h`, no per-app override) and
         both `rdemo` dirs (`rdemo` isn't referenced anywhere in
         `src/Imakefile`'s `SUBDIRS` at all — a standalone package
         with its own `config.csh`/`config.h` generation, never part
         of `make dependInstall`). Only `overhead/class/testing` is
         live. Same user ruling as batch 7: split, flag/verify the
         live dir now, defer the rest as Batch 9b. Both `.ch` files
         (testobj.ch, testobj2.ch) were already clean — no
         `InitializeObject`/`FinalizeObject`, no pair macros, no
         typeless params — zero fixes needed, pure flag-and-gate.
         Gate green first pass; confirmed real typed casts in the
         local `.ih` files directly (this directory has no
         `InstallClassFiles`, so nothing copies to `build/include`).
         Runtime check skipped by user choice: the only artifact,
         `testmain`, is a class-loader self-test ending in
         `while(1);`, not part of the normal install path — matches
         the batch's own "gate is the whole verification" guidance.
         Checkin: rollout-only, no bug-fix commit needed.
       - Batch 8 (2026-07-10, live subset — first Sonnet-delegated
         batch): `atk/syntax/{parse,tlex,sym}`; ness dropped (inert,
         bison blocker). Gate green first pass. Six known-taxonomy
         drift fixes (wrong-sibling structs, int/long index params,
         unsigned name params, FindAll rock to impl's `long *`,
         Create's error handler to `void (*)()`) — details in
         claude-history/m1-point10-batches.md. One hard stop escalated and ruled:
         `lexan.c ParseNumber` passed a `long *` where
         `TransEscape` takes `int *` — live LP64 bug, fixed with an
         `int` temporary as its own commit. Runtime: ctext syntax
         coloring/indent user-verified on a scratch `.c` in ez.
         Checkins: d3386126d5 (.ch), 7ad519b869 (lexan.c),
         6b1564ec89 (rollout).
       - Batch 11 (2026-07-10, live subset — Sonnet-delegated):
         `contrib/{mit/annot, mit/util, srctext/html, srctext/ptext,
         srctext/ltext, time, wpedit, demos/circlepi}`. Gate green,
         ez2ascii battery byte-identical before/after (new baseline
         `~/src/AUIS/test-baselines/ez2-pi/`; ez2ps excluded — it
         execs inert ezprint + eqn/ditroff). Six .ch drift fixes
         (typeless SetDesired/DecidedSize/RecommendSize; wrong-struct
         FinalizeObject ×2 incl. wpedita.ch borrowing AMS `struct
         folders *`; AddImage missing `*`; ReindentLine `struct
         mark *`→`long pos` matching sibling ptext.ch) + one
         pre-authorized dual-use rock cast (html.c). One hard stop
         escalated and ruled: noteview.c/stroffetv.c defined
         ICONSTYLE/TITLESTYLE as the STRING LITERAL
         `"fontdesc_Plain"` — a ~35-year copy/paste bug truncating a
         pointer into every note/troff inset's font-style `int`;
         fixed to the bare symbol + the missing `<fontdesc.ih>`
         includes, own commit. Census correction: wpedit is inert
         one level deeper than the gate log shows — descent happens
         but its Imakefile body is entirely
         `#ifdef AMS_DELIVERY_ENV`-gated (flag committed inside the
         guards, compile-unverified; runbook liveness rule refined:
         descent ≠ compilation). ptext/time/circlepi/mit-util
         zero-fallout, typed casts verified in all 27 installed
         `.ih`s. Runtime: note inset (exercises the ICONSTYLE fix
         path) and clock inset user-verified; htmlview surfaced a
         NEW PRE-EXISTING crash (ReadSubString overlapping strcpy,
         logged under Insets to Repair — crash precedes the batch's
         only html.c edit in execution order, so mechanically not a
         regression); ptext/ltext/circlepi/mit-util gate-only by
         user sign-off. Checkins: 7eaec122fd (live-bug fix),
         f46de124ed (rollout).
       - **Point 10 is COMPLETE (2026-07-10):** every live `.ch`
         directory in the active tree now builds under `-pi`. Only
         point 11 remains for M1.
11. [x] Default flip (done 2026-07-10): classpp emits typed import
       casts (`-pi` behavior) by default (`class.c`
       `usePrototypesImportAll = TRUE`; `-pi` accepted as a no-op);
       all 50 per-directory `-pi` flags deleted. Hybrid execution:
       classpp edit + unit proof top-level (flagless regeneration of
       testobj.ch byte-identical to flag-era output), mechanical
       remainder Sonnet-delegated. Gate green. **Decisive proof: all
       341 installed `.ih`/`.eh` headers byte-identical to the
       pre-flip baseline** (`~/src/AUIS/test-baselines/
       point11-headers/before/`) — the default is bit-for-bit
       equivalent to the flags it replaces. ez/help/messages
       regression battery user-verified. Checkins: ff35ac3904
       (classpp flip), 4f6c344e44 (flag deletions).
       **M1 IS COMPLETE.**
12. [ ] Export (`-pe`) is *not* sequenced here — it rides with each
       subtree's M3 conversion, since its blast radius is only the
       implementing directory

Steps 2–4 are top-level work (learning the fix patterns); 5–10 are
increasingly delegable once the patterns are documented.

#### Active tree — census 2026-07-10

M1's scope is the **active tree**: directories the default build
actually descends into. Liveness ground truth is the gate log —
`grep '^building (dependInstall)' dependInstall.log` — NOT Makefile
presence: stale Makefiles from before subtrees were conditionalized
out survive in `atkbook`, `tm`, `bdffont`, and `prefed`, and a
mis-census around exactly this fooled the batch-7 session into
recording `CONTRIB_ENV` as off (it is on, and contrib builds — see
the correction in batch 7 above).

Census result: **108 directories contain `.ch` files.** 46 are live
(35 flagged + the 11-directory gap above); 62 are inert (4 carry
courtesy flags: `basics/wm`, `console/lib`, `console/cmd`,
`controllers`). The inert 62 break down by gate:

- Off in `allsys.h`: `MK_EXAMPLES` (ex1–ex19); `MK_BASIC_UTILS`/
  `MK_AUTHORING`/`MK_AUX_UTILS` (ezprint, preview, toez, datacat,
  launchapp, createinset/null, music, prefed); `WM_ENV`
  (basics/wm); `MK_CONSOLE` (console/lib, console/cmd)
- Off in `contrib/Imakefile`: `MK_ZIP` (zip/lib, zip/utility —
  see Insets to Repair), `MK_CALC`, `MK_CHAMP`, `MK_GESTURES`
  (gtext), `MK_TM`, `MK_BDFFONT`; `alink` is SunOS-only; `atkbook`
  (18 dirs), `mit/neos`, `pobbconf`, `snap2` aren't in `SUBDIRS`
  at all
- Never wired into `src/Imakefile`: `rdemo/{hide,rdemosh}`

**Consequence of point 11:** once the classpp default flips, inert
directories need no Imakefile flag ever — any inert subtree enabled
later gets typed casts automatically, and the runbook's census/fix
work simply happens at enable time as part of turning it on.
Batches 7b, 9b, 10, and 11's inert remainder are therefore obsolete
as flagging exercises; each survives only as a "run the runbook
census when enabling" note attached to its gate. **M1 ends at point
11 with typed dispatch across the whole active tree.** Full ANSI C —
prototypes everywhere (M2), K&R definition conversion (M3), global
`-Werror` (M4) — continues from that foundation.

### ~~Integration test: `Sherman.Alloc`~~ — proven
All insets in `Sherman.Alloc` render correctly (fad, cel, arbiter, eq, table);
zip unsupported as expected. Multi-inset compound documents confirmed working.

### ~~zip inset~~ — root-caused, moved
Moved to **Insets to Repair → zip**: it isn't broken, it was never
built (`MK_ZIP` never defined anywhere). Repair path documented there.

### ~~ness.gra bison extension~~ — moved
Moved to **Insets to Repair → ness** (same content).

### Andy font path automation
`xset fp+ build/X11fonts && xset fp rehash` is currently a manual step
required each XQuartz session. Automate via a wrapper script or by
installing the PCF files into XQuartz's default font path
(`/opt/X11/share/fonts/`).

### ~~fad view "wrong icon" bug~~ — root-caused, not a regression (2026-07-12)
Suspected `fad` (animation) drawing bug — `ams/demo/d10`'s diagram
showed a literal "M" instead of an icon for its "Client Program" node.
Traced to `con10` (a console-app icon font the diagram happens to
reference) never being built, because `MK_CONSOLE` gates out all of
`atk/console` including `console/fonts` — not a `fad` defect at all.
Full root cause and permanent-fix options: `porting-assessment.md` →
"`MK_CONSOLE` being off silently breaks `con10`/`con12`...". Fixed and
confirmed 2026-07-12: once `con10` resolves, the animation renders and
plays correctly. Codified as `revival/tools/install-console-fonts`
(builds only `console/fonts`, never touches the rest of `console`) —
re-run it any time a full clean rebuild wipes `build/X11fonts/`; not a
true upstream fix (that needs `console/fonts` carved out of the
`MK_CONSOLE` gate, or `MK_CONSOLE` itself enabled), but no longer a
manual multi-step recipe either.

### ~~Frame size reporting in help~~ — fixed

---

## Long-term / architectural

### ANSI C modernization (full K&R conversion)

**Elevated to medium-term** — see Medium-term → ANSI C conversion
(M1–M4). The `modernize` tool is no longer the starting point; see
`porting-assessment.md` §14 tool verdicts.

### Messages application

**Elevated to near-term focus** — see Near-term section for the active
work plan. Moved here for architectural notes only.

`messages` is the AUIS mail/bulletin-board client. Full AMS revival is
off the table — the AFS/shared-filesystem delivery model is a dead end.
See Near-term → Messages prerequisites for the two viable backend paths
(local store vs. IMAP adapter).

---

## Stretch goals

### Pie menus
AUIS's menu architecture is well-suited to Don Hopkins' pie menu design.
The menu system is clean and the attachment points are known. A
collaborative implementation project once the core system is stable.

### Additional applications
`bush` (shell), `typescript` (terminal emulator), `org` (outliner),
`chart`, `layout` -- each is a symlink to `runapp` and built; exercise
and fix as interest warrants after core insets are stable.

### ez2md improvements
`ez2md` (`revival/tools/ez2md`) converts `.ez` documents to Markdown; text,
page breaks, footnotes, and raster images are fully handled, but table, eq,
figure, fad, image, and link objects currently render as placeholder
comments (orphaned from an earlier, pre-C-revival phase of this project;
folded in here from a since-retired `revival/ROADMAP.md`). Two
follow-ons, not started:

- **Table rendering** — parse the ATK table/spreadsheet format into
  Markdown tables.
- **Batch conversion of archive documents** — convert the FAQ, README,
  newsletters, and papers to Markdown for easier browsing (perhaps into
  `revival/converted/`, alongside the originals).

Raster insets are decoded from their run-length-encoded 1bpp bitmap format
and re-encoded as inline `data:image/png;base64,...` images (2026-07-16) —
see `revival/tools/ez2md`'s `decode_raster`/`encode_png_1bit`. Version-1
rasters and the `refer`/`share`/`file` keyword variants (rare in archived
documents) still fall back to a placeholder comment. Chosen deliberately
over sidecar `.png` files since `ez2md` is meant to be used as a stdin/stdout
filter with no natural output directory to write sidecar files into; the
tradeoff is that at least one browser Markdown-viewer extension with a
restrictive CSP won't load `data:` image URIs; VS Code's built-in preview
renders them correctly.
