CLAUDE.md@apps/macos · git:20261004.efaf638 · 2026-10-04 · sha256 b77903c5fcebdc83

CLAUDE.md@apps/macos git:20261004.efaf638A

Immutable. This exact content never changes and is served at /api/v1/blob/b77903c5fcebdc83.

# CLAUDE.md

Working notes for AI agents in this repo (the macOS desktop Scout app).

## Fixtures must be anonymized — this repo and its two siblings are public

Scout runs against a real person's vault, so anything lifted from it into a
fixture or an inline test string **must be scrubbed before it lands**. All three
Scout repos — this one, `scout-iOS-app`, and `scout-plugin` — are public.

- **No real identifiers.** Strip company/product names, real coworker names, real
  Linear IDs, GitHub repos, and Slack workspaces/channels. Use the shared
  stand-ins so fixtures stay internally consistent:
  - People: `Alex` / `Priya` / `Sam`; comment/proposal author `alex` / `Alex`.
  - Linear: `PROJ-1234` (use neutral team prefixes like `OPS-`, `DESK-`, `TEAM-`
    when you need variety) — never the real team prefixes (`AI-`, `KAI-`, `ST-`, …).
  - GitHub: `example-org/<repo>`.
  - Slack: `acme-co.slack.com/archives/C0123456789/p1700000000000000`.
  - Vendors/products: a generic noun ("the demo", "the tracing job"), not the brand.
- **Anonymize content, not structure.** Keep the load-bearing *shapes* the parser
  is tested on — `[#TAG]` short-prefixes, `**bold**`, `_(italic)_`,
  `[[wikilinks]]`, ` — ` separators, `` `code` ``. Only swap the words around them.
  A `[#TAG]`'s **shape** is load-bearing; its **letters are not**. Each corpus tag
  is chosen to exercise one grammar property, so a replacement must preserve that
  property — the `_note` on each case says which:
  - `IOTA` — 4 chars, contains I and O, i.e. *not* Crockford base32 (which omits
    I/L/O/U). A replacement must also contain one of those letters.
  - `XI7391` — 6 chars, contains I; longer than the old 4-char limit.
  - `NTX` — 3 chars, no bold, no separator.
  - `7391K` — digit-led with a trailing letter, so it is not a bare GitHub ref.

  The tags themselves are invented and must stay that way. **Verify a new tag
  against the vault before using it** (see below) — the previous set (`MIRO`,
  `AI3026`, `RSM`, `5864M`) was documented here as synthetic but was not: each
  appeared in dozens to hundreds of real vault files, and `AI3026` was a real
  Linear id under the real `AI-` prefix. Replaced in #111.
- **Check a literal against the vault before trusting it.** Count *files*, and
  exclude `~/Scout/.claude/` — those are session transcripts holding copies of
  this repo's own test source, so they inflate every literal, invented ones
  included. Real identifiers land in the tens-to-hundreds once excluded;
  invented ones land at zero.

  ```bash
  grep -rIow -F -f candidates.txt ~/Scout | sort -u \
    | grep -v '/Scout/\.claude/' | awk -F: '{print $NF}' | sort | uniq -c | sort -rn
  ```

  Two traps: compare priority-shaped tokens against their siblings (`P3` scored
  224 files where `P1`/`P2` scored ~50, so it was a codename, not a priority);
  and a prefix collision is not a leak (`CC-N` here is this repo's own Control
  Center bug numbering from `docs/control-center-bugs.md`, even though `CC-` is
  also a real Linear team prefix).
- **Preserve legitimate attribution** — these are NOT leaks, leave them: the
  `pyproject`/`marketplace.json` owner, `LICENSE`, and the project's own
  `github.com/<org>/…` URLs.

### `parser-corpus.json` is ONE byte-identical file living in three repos

`ScoutTests/Fixtures/parser-corpus.json` is byte-identical to the **canonical**
copy in `scout-plugin` and the copy in `scout-iOS-app`, and is checksum-guarded on
both the Swift and Python sides — so you cannot edit just one copy. On any change
(anonymizing counts):

1. Edit the corpus; keep every `expected` field consistent with the parser rules
   (`ParserContractTests` is the judge).
2. Copy it byte-for-byte into the sibling checkouts:
   - `../scout-plugin/engine/tests/fixtures/contract/parser-corpus.json` (canonical)
   - `ScoutMobileTests/Fixtures/parser-corpus.json` in `Raven-Scout/scout-iOS-app`,
     which is usually **not** checked out alongside this repo — clone it when you
     need to touch the corpus. It has no checksum guard of its own, so nothing
     fails locally if you forget it; the copy just silently drifts.
3. Update BOTH checksum guards to the new `shasum -a 256` of the file:
   - `canonicalSHA256` in `ScoutTests/ActionItems/ParserContractTests.swift`
   - `EXPECTED_SHA256` in `../scout-plugin/engine/tests/unit/test_parser_corpus_checksum.py`
4. Verify all three: this repo's `ParserContractTests` (on `platform=macOS`),
   scout-iOS `ParserContractTests`, and plugin
   `pytest tests/unit/test_parser_contract.py tests/unit/test_parser_corpus_checksum.py`.
   scout-iOS-app builds via **XcodeGen**, so `xcodegen generate` has to run before
   its tests will build at all — if that tool is not installed, say so rather than
   reporting the corpus as fully verified.
5. Open all three PRs and **merge them together.** The two checksum guards fail on
   either side the moment one lands alone.