19 Commits

Author SHA1 Message Date
Edward Langley ffc7d0aecc Merge gh/main 08ad7b81 into fix/wpxr-empty-record-view
Every write the merged PRs added now names a view, chosen deliberately:

- The keyboard commit names OpenedCell::view, captured when the editor
  opened, as EditTarget does for the mouse (context/code/clients.md).
- RenameRecordCoordinate names no view. Its record must hold cells, so it
  resolves in the store alone: NamedRecord::Stored, as does the rename
  destination records_at_stake adds. named_records replaces cells_named as
  the exhaustive list records_named is read off.
- #252/#265's non_item_refusal moves into Grids::unwritable. The strict view
  lookup (a missing view is RecordGone) and the Grids memo are kept.
- Test fixtures name a view their document has: Default for host() and
  host_on_a_fold(), the records view for the rename pair, and the viewing
  client's own view in browser_round_trip.

Evidence files: both sides kept, every heading of both parents verified
present. Test names: the merge holds every test of both parents.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 12:53:03 -07:00
Edward Langley 88598c6f7e Merge PR #292 (3f98a17c) into the 2026-09-24 integration wave
# Conflicts:
#	context/test-evidence/command.md
#	crates/improvise-command/src/ui/app.rs
#	tests/shipped_documents_load.rs
2026-09-24 02:46:37 -07:00
Edward Langley 1629944eac Merge gh/main into fix/gk51-non-item-record-projection (#292)
Conflicts:
- cmd/core.rs committable_cell_key: took main's form, which asks
  `uneditable` (#277), and gave `uneditable` a declining NonItem arm.
  That keeps this branch's refusal of a commit on a non-item cell.
- resolve.rs reopened_at (auto-merged, non-exhaustive after the merge):
  a declining NonItem arm, the sentence `i` already says.
  The #277 review asked for both arms to decline, never to open.
- tests/shipped_documents_load.rs: kept both, this branch's
  every_record_a_shipped_document_projects_is_writable and main's git()
  helper.
- context/test-evidence/{command,core}.md: both sides appended at EOF; kept
  both, the branch's first.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 23:19:46 -07:00
Edward Langley 12a92a8669 Give run_git's config nulls a witness no -c reaches (improvise-3j70)
GIT_CONFIG_GLOBAL=/dev/null and GIT_CONFIG_NOSYSTEM=1 in run_git were
witnessed by a config excludesFile, which vwjj's -c
core.excludesFile=/dev/null outranks. So dropping either line passed
every test from vwjj onwards.

The hostile child's config, read as both GIT_CONFIG_GLOBAL and
GIT_CONFIG_SYSTEM, now also sets core.sharedRepository = nonsense.
Measured on git 2.55: git init and git add die on it, git ls-files
does not read it (so the walk, which does not null the user's config,
is unaffected), and run_git passes no -c for it. init.defaultObjectFormat
and init.defaultRefFormat were tried first; they only warn.

Dropping either env line is now red. Every other rival in the combined
test is unchanged, and there is still one child per test.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:32:41 -07:00
Edward Langley 5b8bdc19b1 One child per test, carrying every hostile git setting at once (improvise-eahe)
tests/shipped_documents_load.rs re-ran itself in 18 child processes, one
per hostile setting, and each child spawns several gits. So the binary
took 2.1-3.3s against design-principles 7's 2s-per-binary tripwire.

The six per-setting tests (53zz x2, vwjj, pr3i, a0i3 and 2iws/vav0) are
now one test, a_hostile_git_environment_changes_nothing. It has two
children: the gzip shape test and every_shipped_document_loads. Each
carries every setting at once:
- the template dir;
- the global and system config (with trace2 targets);
- XDG_CONFIG_HOME;
- GIT_DIR and GIT_INDEX_FILE;
- the five pathspec and attribute settings;
- the six trace variables.

Afterwards the test asserts the outer index is still empty.

Each setting breaks the walk on its own, so a rival that drops one
defence leaves that setting live, and the child fails. Every rival that
was red against the per-setting tests is red against the combined one.
The rivals that were green before are green now:
- ICASE;
- the trace2 names under the 0 override;
- the GIT_CONFIG_GLOBAL and NOSYSTEM nulls, whose excludes witness vwjj's
  -c override masks. That last pair is filed as improvise-3j70.

Measured on an Apple M4 Max, three workspace runs each: this binary went
from 2.10-3.31s (load 37-39) to 0.57-0.91s (load 30-33). It is now
below the next-largest binary in every run.

The evidence sections keep their reasoning, under prose headings.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:23:40 -07:00
Edward Langley fbfe37802f Pin the GIT_TRACE prefix with all six variables; override config trace2 targets (improvise-2iws review, improvise-vav0)
The review of #276 found that an exact list of the three names the test
set passed it. The child now sets all six variables that write to their
target on git 2.55: GIT_TRACE, _SETUP, _PERFORMANCE, 2, 2_EVENT and
2_PERF. An exact three-name list leaves GIT_TRACE_SETUP behind and
fails.

vav0: a trace2.*Target in user config is not an environment variable,
so removal cannot reach it, and the walk's git does not null the user's
config. untraced_git now also sets GIT_TRACE2, GIT_TRACE2_EVENT and
GIT_TRACE2_PERF to 0, which outranks the config. The child adds a
GIT_CONFIG_GLOBAL whose [trace2] section sends all three targets to
/dev/stdout.

Rivals, each of which fails:
- no strip;
- the exact three names;
- the prefix minus GIT_TRACE, minus _SETUP, or minus _PERFORMANCE;
- no 0 override.

The evidence entry moves from the web_demo_model section to the
shipped_documents_load one.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:16:22 -07:00
Edward Langley ddcdf93a6b The shipped-document walk strips every GIT_TRACE* variable (improvise-2iws)
GIT_TRACE, GIT_TRACE2_EVENT and GIT_TRACE_PERFORMANCE are process-wide,
so --local-env-vars lists none of them. Pointed at /dev/stdout, git
wrote trace lines into the ls-files -z output, and the walk read them
as paths. git() now builds on untraced_git(), which removes every
variable starting with GIT_TRACE: a prefix, because the family is
open-ended. The rev-parse --local-env-vars call goes through it too,
since its stdout is parsed as well.

the_walk_ignores_a_git_trace_sent_to_stdout reruns the gzip shape test
and every_shipped_document_loads in children with all three set to
/dev/stdout. It failed at #269's head. Rivals, each of which fails it:
- no strip;
- the exact name only;
- keep GIT_TRACE_PERFORMANCE;
- keep GIT_TRACE2_EVENT.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:01:54 -07:00
Edward Langley 4cef40c951 Strip pathspec and attribute-source settings from the walk's git (improvise-a0i3)
GIT_LITERAL/GLOB/NOGLOB/ICASE_PATHSPECS and GIT_ATTR_SOURCE are
process-wide, so --local-env-vars names none of them. Remove them in
git() beside the local-vars loop.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 17:30:59 -07:00
Edward Langley da0eb3d7cb improvise-a0i3: red test, the walk under the user's pathspec and attribute settings
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 17:28:43 -07:00
Edward Langley adb6b81416 improvise-gk51: the pivot branch too, a shipped-document enumeration, and the argument
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 17:19:01 -07:00
Edward Langley 322de37053 Init scratch repos with an empty template directory
improvise-pr3i, found reviewing #255. git init copies GIT_TEMPLATE_DIR
into the new .git. That variable is not in --local-env-vars, and it
bypasses config, so a template whose info/exclude holds *.gz still broke
a_gzipped_document_is_walked at git add. scratch_repo now runs
`git init -q --template=`, which copies no template at all, including a
distribution's compiled-in default. Stripping the variable would still
copy that default.

Also: rerun_with_env's callers print the child's stderr as well as its
stdout (told), because the child's panic goes to stderr.

Stacked on #255 (fix/vwjj-default-excludes).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 17:01:33 -07:00
Edward Langley 56ac72a291 Null the default excludes and attributes files for scratch repos
improvise-vwjj, found reviewing #248. GIT_CONFIG_GLOBAL=/dev/null empties
the config files. It does not stop git falling back to
$XDG_CONFIG_HOME/git/ignore (or ~/.config/git/ignore) when
core.excludesFile is unset, and git/attributes has the same kind of
default. So a *.gz line in the user's default ignore file still failed
a_gzipped_document_is_walked.

run_git now passes -c core.excludesFile=/dev/null and
-c core.attributesFile=/dev/null. A -c argument outranks every config
file and every default path.

The new test re-runs the gzip shape test under an XDG_CONFIG_HOME whose
git/ignore holds *.gz, and again with a git/attributes line that breaks
git add. Each half was red on its own.

Stacked on #248 (fix/53zz-scratch-repo-env).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 11:29:01 -07:00
Edward Langley f5cfc7edd3 Isolate shipped_documents_load's scratch repos from the caller's git env
improvise-53zz. The scratch-repo shape tests inherited the caller's git
environment. A hook in a linked worktree exports GIT_DIR (and
GIT_INDEX_FILE), which override -C, so `git -C <scratch> add` staged the
scratch files into the outer checkout's index. The user's global
excludesFile applied too, so a `*.gz` line there broke the gzip test.

One helper, git(root), now removes every name that
`git rev-parse --local-env-vars` prints. run_git also sets
GIT_CONFIG_GLOBAL=/dev/null and GIT_CONFIG_NOSYSTEM=1.

Two new tests re-run a shape test in a child process of this binary with
the variables set. Both were red before the fix. Five rivals are recorded
in context/test-evidence/tui.md.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 11:10:11 -07:00
Edward Langley 6dceaad1c7 every_shipped_document_loads walks the index, not a .gitignore reading (improvise-c0aj) 2026-09-23 08:56:26 -07:00
Edward Langley 4e52d06838 WIP red: four ways of shipping a document the .gitignore walk misses (improvise-c0aj) 2026-09-23 08:54:15 -07:00
Edward Langley 4d2252373e every_shipped_document_loads walks what .gitignore un-ignores, harness/fixtures included (improvise-qlrh)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 08:26:48 -07:00
Edward Langley f7d377b010 refactor(tests): cap the integration tests' comments
grid_frame_agreement.rs is the strongest test in the last wave and its
comments were the record of six injected faults; all of it is now in
context/test-evidence/tui.md, keyed by test name.

THE_MEMBERSHIP_CORRECT_SPANS and its assert_ne! are UNTOUCHED. Its comment
now says what it is — a deliberately wrong constant and a live tripwire —
and points at the derivation rather than carrying it.

shipped_documents_load.rs keeps its two load-bearing claims in the file
(directory walk, full-name match) because both sit directly over the code
that would otherwise be "simplified" back into the bug.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 09:51:38 -07:00
Edward Langley 239f1f0b80 test: the shipped-document walk must not skip a gzipped one
Self-review of improvise-odbc's own guard. The walk filtered on
`Path::extension() == "improv"`, and `extension()` of `demo.improv.gz` is
`gz` — so a gzipped shipped document would have been skipped silently, which
is exactly the "exercised by nothing" hole the test exists to close, put back
one line inside the fix for it.

Matched on the full name instead. Proved both arms: a valid `.improv.gz`
dropped into `examples/` passes, and a truncated one fails. (The truncation
also exercises the `with_context` added two commits ago, from the other side.)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 22:48:12 -07:00
Edward Langley 1c2361b45a fix(persistence): delete bank-info.improv, and pin why it could not be read
improvise-odbc named two readings of the parse failure at
`- JORDAN MARTINEZ` and said to decide by asking whether improvise can
WRITE that line today. It cannot: `item_list`'s `name` is
`pipe_quoted | bare_name`, `bare_name` is `[A-Za-z_][A-Za-z0-9_-]*`, and
`quote_name` mirrors it character for character, so a spaced item name is
emitted `|JORDAN MARTINEZ|`. So the reader and the writer agree and the
round-trip property is not incomplete — the file was stale.

It was stale by hand, not by drift. c48a5cd migrated it to v2025-04-09 by
editing it in place: the `Date` items were pipe-quoted and the `Entity`
ones were not, and every line of its `## Data` section names a category
`Measure` where the file declares `_Measure`. It has not been loadable
since April, and nothing loaded it, so nothing said so. Deleted rather
than regenerated: there is no generator for it — it is hand-written fake
bank data — so "regenerating" would mean inventing a canonical form and
checking in 1200 lines whose only property is that they parse, which the
generator-driven proptests already establish over a far wider input space.

What is kept is the evidence and the gap the incident actually exposed:

- `an_item_name_the_item_line_cannot_carry_round_trips` puts the file's own
  item names through `format_md`/`parse_md` and asserts the spaced ones come
  back quoted and the bare-legal one stays bare.
- `a_bare_item_name_with_a_space_is_rejected` asserts the reader really does
  refuse the unquoted line, with the quoted form parsing as the precondition.
  Without it the first test would be consistent with the reader accepting
  both spellings, which is not what happened.
- `tests/shipped_documents_load.rs` closes "a sample document exercised by
  nothing": it walks the two directories `.gitignore` un-ignores and loads
  every `.improv` in them. A directory walk, not a list of names, because a
  list is a second place to remember. Proved discriminating by dropping the
  offending line into `examples/` and watching it fail.

Unrelated, reported not fixed: `foo.improv` in the repo root has no version
line at all and is equally unloadable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 22:36:12 -07:00