Commit Graph

2 Commits

Author SHA1 Message Date
Levi Neuwirth 2d2d63abfc
docs: mark the git Stage 1 framing approved
The lane in docs/active-work.md already recorded revision 5 as APPROVED
2026-08-09; the framing document itself still opened with "Awaiting
approval". Same fact, two files, opposite answers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
2026-08-09 14:01:03 +02:00
Levi Neuwirth 9567c0e09e
docs: frame git integration Stage 1 (revision 5, approved)
COHERENCE.md section 15 grades contextual affordances "weak" and says
the Git affordance list "has nothing to attach to yet". For a daily
driver this is the largest remaining gap --- not the deepest (sections 7
and 9 are), but the one a user touches every working hour.

Stage 1 is read-only and panel-based: a `*git-status*` listview over
`--porcelain=v2 --branch -z`, and a file-level `*git-diff*` in plain
generated text. THE STAGE LINE FALLS AT THE WIRE, and that is a
scheduling decision as much as a design one: `DecorationKind` is a
closed enum, so gutter markers need new variants and a
PROTOCOL_VERSION bump. Bumps are a strict serialization point --- this
session recorded eight broken assertions from one --- so Stage 1
touching no wire is what lets it run beside other lanes, and Stage 2
must be scheduled alone.

FOUR REVIEW ROUNDS, and the doc records what each one caught, because
the pattern is the useful part:

  - `ProjectKind::Git` means a BARE git repo; a language marker beside
    `.git` wins, so this very repository reports "rust". A `kind ==
    "git"` gate would have failed on the repo it was written in. The
    rule is now: never ask pmacs whether it is a git repo --- run git
    and let it resolve its own worktree.
  - `tests/fixtures/pmacs-magit/` already exists: 1,914 lines, a
    porcelain-v2 parser, 32 tests. Section 15's "no Git integration
    anywhere in the tree" is literally false; the PRODUCT gap is real.
    The tokenizer is deliberately REWRITTEN for `-z` rather than
    ported --- newline-delimited and NUL-delimited v2 are different
    grammars.
  - `listview.open` resets collapse and always seats line 1, so
    selection preservation is the consumer's job, not the primitive's.
    And `d` is not on its key surface; binding it needs an additive
    `keys` table, which makes "no listview modification" false.
  - `Keymap::bind` REFUSES duplicates, and the refresh path re-opens
    the panel --- so a naive `keys` implementation would have failed on
    every successful refresh.

Two git exit states were measured, not assumed. `--no-index` implies
`--exit-code`, so an untracked diff exits 1 ON SUCCESS --- under the
first predicate, every untracked diff would have rendered a failure row
instead of the diff it had just produced. And `git diff HEAD` exits 128
in an unborn repository, which is exactly a fresh `git init` with the
first files staged.

The unborn policy was then enumerated from a real unborn repository
rather than reasoned about, which closed one case by RULING IT OUT: a
`git mv` of a staged-but-uncommitted file emits `1 A.`, never a `2`
record, so rename/copy is unreachable without a HEAD and needs no
policy. `AM` and `AD` are ordinary there and carry both states, so they
render TWO labelled patches --- `--cached` alone loses the worktree
edit, plain `git diff` alone loses the staged base. The split is
unborn-only: with a HEAD, one total is the question this lane asks.

Section 9 impact is recorded as NEGATIVE and not dressed up: spawned
processes do not appear in `*workers*`, so this adds a fifth
unattributable background thing. The process is labelled; a label is
not attribution.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
2026-08-09 13:25:52 +02:00