From b033d0b9ec43f7f7037b7b0d53b6a16541b880b4 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Sat, 12 Sep 2026 10:59:39 +0300 Subject: [PATCH] Others are observed, never touched ADR 0026 and the change documents for surveying every working directory of this repository. Two agents worked on this repository at once and the owner could see one. The tool reported the queue of the directory it was pointed at, which was sitting on a branch whose pull request had already merged, so it said there was nothing to do, and nothing on screen named the branch it had read. A working directory is not a remote thing: git worktree shares one object store, so the survey is a local read with no daemon, no network and no registry. Read-only is what the view can do, not how it looks. A foreign change carries no action, and identity is the directory together with the name rather than the name alone, because two directories can hold a change of one name at different content. No git runs against a directory this host does not own. Collisions are not computed for a foreign directory: a subprocess per directory per read, answering a question the viewer cannot act on. Work not worth doing is not made cheap by moving it to the background. A directory carries a label, defaulting to its own directory name and overridable by a file in it. Label and not owner: owner asserts authority this view does not grant, and a-lease-says-who already found that a word which overstates gets believed. It lives in the directory and not only in the lease, because the lease exists only while a mutating run holds one. Where a lease records a git author different from this checkout's, the survey says so in words, with colour agreeing rather than carrying it. The label answers which directory; the git author answers whose commits these would be. Nothing foreign enters the local order and no relation is drawn between directories, for the reason a collision is not an edge in ADR 0025. A change present in two directories is reported, not refused: it arises from ordinary branching, and is inert until a copy is edited. Co-Authored-By: Claude Opus 5 (1M context) --- ...-directories-are-observed-never-touched.md | 160 ++++++++++++++++++ docs/adr/README.md | 1 + .../what-the-others-are-doing/.openspec.yaml | 8 + .../what-the-others-are-doing/design.md | 134 +++++++++++++++ .../what-the-others-are-doing/proposal.md | 69 ++++++++ .../specs/shared-ui/spec.md | 133 +++++++++++++++ .../what-the-others-are-doing/tasks.md | 115 +++++++++++++ 7 files changed, 620 insertions(+) create mode 100644 docs/adr/0026-other-working-directories-are-observed-never-touched.md create mode 100644 openspec/changes/what-the-others-are-doing/.openspec.yaml create mode 100644 openspec/changes/what-the-others-are-doing/design.md create mode 100644 openspec/changes/what-the-others-are-doing/proposal.md create mode 100644 openspec/changes/what-the-others-are-doing/specs/shared-ui/spec.md create mode 100644 openspec/changes/what-the-others-are-doing/tasks.md diff --git a/docs/adr/0026-other-working-directories-are-observed-never-touched.md b/docs/adr/0026-other-working-directories-are-observed-never-touched.md new file mode 100644 index 0000000..f1e9410 --- /dev/null +++ b/docs/adr/0026-other-working-directories-are-observed-never-touched.md @@ -0,0 +1,160 @@ +# 0026: Other Working Directories Are Observed, Never Touched + +Status: Accepted + +Date: 2026-09-12 + +## Context + +ADR-0022 gave a change its own working directory so two changes can run +at once, and ADR-0024 made what can run alongside what derivable rather +than declared. ADR-0025 drew the result as a picture. All three answer +for **one** working directory: the one the host was pointed at. + +On 2026-09-12 two agents were working on this repository at once — one +in the primary checkout, one in `…​.worktrees/proposals` — and the owner +could see only their own. Six proposals existed a directory away and +were invisible from the tool built to show what is in flight. + +Two things went wrong in that session that this ADR exists to stop +happening again, and neither was a bug in any code: + +- The primary checkout was sitting on a branch whose pull request had + already merged, so the tool honestly reported an empty queue. The + owner could not tell "there is nothing to do" from "I am looking at a + stale checkout". Nothing on screen named the branch being read. +- A change that had been archived in one directory was still present, as + a tracked file, in another — inherited from the branch point, put + there by nobody. Harmless while untouched, and a genuine collision the + moment it is edited. Nothing would have reported it. + +A working directory is not a remote thing. `git worktree` shares one +object store and one ref namespace: the sibling's `.git` is a file +naming a subdirectory of the primary's. Everything below is therefore a +local read, with no daemon, no network and no registry. + +## Decision + +**Other working directories are surveyed, and never acted on.** + +The survey reports, per directory: the branch it has checked out, the +changes in its own `openspec/changes`, how far each one's tasks have +got, and — where a mutating run holds it — the lease's holder and git +author. + +Read-only is a property of what the view can do, not of how it looks. +A foreign change carries no action: no opening it in the editor, no +starting a run against it, no ticking anything. Recessed styling +agrees with that fact; it does not create it. + +The rule is specific because the failure is specific. A change's +identity is the pair `(working directory, name)`, not the name. Two +directories can hold a change of one name at different content — that +already happened here — and an action routed by name alone would act on +a different change while looking perfectly correct. + +**No git is run against a directory this host does not own.** + +Enumerating the working directories is one `git worktree list` against +this repository, which this host does own. Everything after that is a +filesystem read: names under `openspec/changes`, each `tasks.md`, each +`.openspec-ui/workspace.lease.json`. + +The collision detection of ADR-0024 is deliberately not computed for a +foreign directory. It costs a git invocation per directory per read, and +it answers a question the viewer cannot act on: a collision between two +changes in somebody else's directory is not theirs to resolve. Work not +worth doing is not made cheap by moving it to the background — the +background changes who waits, not what is spent. + +**A directory is labelled, and the label is not an identity.** + +Each working directory carries a short label. It defaults to the +directory's own name — `proposals` — which is already chosen, already +meaningful, needs no configuration, and is distinct by construction +since git will not put two working directories at one path. It can be +overridden by a file in that directory. + +The label lives in the directory and not only in the lease, because the +lease exists only while a mutating run holds one. An agent editing files +holds no lease, and that is the ordinary state — the survey has to work +then, which is most of the time. + +The word is "label" and not "owner". "Owner" asserts authority, and this +view grants none; the lesson of ADR-0025's neighbour, `a-lease-says-who`, +is that a word which overstates gets believed. The label is +self-declared: attribution, never authentication. + +**The git author is reported, and reported as different when it is.** + +The lease already records the git identity of the directory that took +it. Where that identity differs from this checkout's own, the survey +says so — that is how a second *person* becomes visible, as opposed to a +second directory. + +It is said in a word and agreed with by colour, never carried by colour +alone: this shell is held to WCAG AA, and a reader who cannot separate +two hues must still be able to tell whose run it is. + +The two are different questions and neither stands in for the other. The +label answers "which working directory"; the git author answers "whose +commits would this be". On one person's machine every directory reports +the same author, and that is correct rather than a defect. + +**Nothing foreign enters the local order.** + +Each directory's changes are laid out on their own, by the layout of +ADR-0025, against that directory's own queue. They are never merged into +another directory's columns and no relation is drawn between directories. + +A column means depth in a declared order. Between changes on two +branches the repository declares no order at all, so a line across would +assert a sequence that does not exist — the same reason a collision is +not an edge in ADR-0025, and believed for the same reason: it would look +like every other line in the drawing. + +**A change in two directories at once is reported.** + +Not prevented, and not resolved. It arises from ordinary branching — cut +a working directory from a main that has active changes and every one of +them comes along — so it is a condition to be noticed, not an error to +be refused. + +## Consequences + +The survey works with no configuration: a directory that declares +nothing still reports its name, its branch and its changes. + +The tool can say which branch each reading came from, so an empty queue +is distinguishable from a stale checkout. + +A foreign directory costs filesystem reads and no subprocess. It is read +less often than the local one and only while being looked at, on the +same reasoning ADR-0025 used for the tab itself. + +The survey is a reading, never a subscription. A directory can change +between two of them, and the view says when it last looked. + +## Alternatives considered + +**A central registry or daemon agents report to.** Rejected: the +information is already on this disk, and a registry would add a second +source of truth that can disagree with the filesystem — and be believed, +because it is the one being displayed. + +**Reading git in each foreign directory for a full readiness report.** +Rejected above: a subprocess per directory per read, for collisions the +viewer cannot act on. + +**Merging every directory's changes into one graph.** Rejected: it would +place changes from unrelated branches in shared columns, asserting an +order the repository does not contain. + +**Identifying a directory by its git author.** Rejected: on one person's +machine every directory reports the same author. It answers a different +question, and is kept for that question. + +**Refusing to create a working directory that would duplicate an active +change.** Rejected for now: it would refuse the ordinary case (branching +from a main with work in flight) in order to prevent the rare one +(editing both copies). Reporting it costs nothing and forbids nothing. diff --git a/docs/adr/README.md b/docs/adr/README.md index 4291a17..b2f3183 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -32,5 +32,6 @@ Alternatives / Consequences. | [0023](0023-standalone-shell-visual-direction.md) | The standalone shell commits to an editor-native look | Accepted | | [0024](0024-parallel-readiness-is-derived.md) | Parallel readiness is derived, never declared | Accepted | | [0025](0025-the-pipeline-picture-is-derived-and-drawn-by-hand.md) | The pipeline picture is derived, and drawn without a graph library | Accepted | +| [0026](0026-other-working-directories-are-observed-never-touched.md) | Other working directories are observed, never touched | Accepted | New architecture-impacting changes must add an ADR and reference it from the related OpenSpec change. diff --git a/openspec/changes/what-the-others-are-doing/.openspec.yaml b/openspec/changes/what-the-others-are-doing/.openspec.yaml new file mode 100644 index 0000000..6a1dda3 --- /dev/null +++ b/openspec/changes/what-the-others-are-doing/.openspec.yaml @@ -0,0 +1,8 @@ +schema: spec-driven +created: 2026-09-12 +follows: + - changes-run-side-by-side + - what-can-start-now + - a-lease-says-who +blocked_by: + - a-graph-of-what-is-running diff --git a/openspec/changes/what-the-others-are-doing/design.md b/openspec/changes/what-the-others-are-doing/design.md new file mode 100644 index 0000000..d745ad2 --- /dev/null +++ b/openspec/changes/what-the-others-are-doing/design.md @@ -0,0 +1,134 @@ +# Design + +See `docs/adr/0026-other-working-directories-are-observed-never-touched.md` +for the decisions: a directory is surveyed and never acted on, no git is +run against one this host does not own, a directory carries a label that +is not an identity, and nothing foreign enters the local order. + +## Decision: a survey, not a second readiness report + +`readChangeReadiness` derives facts that cost work: which changes +collide over a capability, which branches have changed the same files, +what can be started alongside what. That is right for the directory a +person is working in, where every answer is actionable. + +For a directory somebody else is working in, none of it is. A collision +between two of their changes is not this viewer's to resolve, and +computing it costs a git invocation per directory on every read. + +So the survey is a different, smaller thing: what a directory *is*, +rather than what could be done about it. Names, tasks, branch, lease. +The two are separate functions and the foreign one is not a degraded +version of the local one — it answers a different question. + +## Decision: what is read, and what is never inferred + +Read: + +- the working directories, from one `git worktree list` against this + repository — the only git this feature runs; +- each directory's branch and head, from the same output; +- the names under its `openspec/changes`, excluding `archive`; +- each change's `tasks.md`, for how many items are closed; +- its `.openspec-ui/workspace.lease.json`, where one exists. + +Never inferred: whether an agent is working, stuck, or idle. A directory +with no lease means no mutating run holds it right now — an agent +editing files holds none. Reporting that as "idle" would be the same +mistake as calling a git author a user: a word the data does not +support, believed because it was displayed. + +## Decision: the label, and why it lives in the directory + +Each directory has a short label, defaulting to the last segment of its +own path. That default is free and already meaningful: somebody chose +`proposals` when they made it, and git guarantees no two working +directories share a path, so labels are distinct by construction. + +It is overridable by `.openspec-ui/worker.json` in that directory — one +field, self-declared. + +It lives in the directory rather than in the lease because the lease +exists only while a mutating run holds one. The ordinary state of a +directory is somebody editing files in it, holding nothing. The survey +has to name it then, which is most of the time. + +## Decision: "label", not "owner" + +"Owner" asserts authority over the thing named, and this view grants +none — it cannot act on a foreign change at all. `a-lease-says-who` +already found that a word which overstates gets believed: the lease says +"git author" and never "user", so that a self-declared string is not +read as an established identity. The same applies here. + +## Decision: the git author answers a different question + +The label says which working directory. The git author says whose +commits a run there would be. Neither substitutes for the other: on one +person's machine every directory reports the same author, and that is a +correct answer, not a failure of the label. + +Where a directory's lease records an author different from this +checkout's own configured identity, the survey says so. That is the +signal that a second *person* — not merely a second directory — is at +work. + +It is said in a word, and colour agrees with the word. Never colour +alone: the shell is held to WCAG AA by a browser suite that runs axe, +and the same rule already governs running-versus-blocked on a pipeline +card. + +## Decision: each directory keeps its own picture + +Each directory's changes are laid out by `layoutChanges` against that +directory's own queue, and drawn as their own picture. + +They are not merged into one graph. A column means depth in a declared +order, and between changes on two branches the repository declares no +order at all — placing them in shared columns would assert one. For the +same reason no relation is drawn between directories: a line across +would be believed, because it would look like every other line. + +## Decision: a duplicate is reported, not refused + +A change can exist in two directories at once. It arises from ordinary +branching — cut a directory from a main that has active changes and all +of them come along — so refusing it would refuse the common case to +prevent the rare one. + +While both copies are untouched it is inert: the archive of one side +merges cleanly against an unmodified other. It becomes a collision the +moment either is edited, which is exactly when somebody wants to know. +So it is surfaced, and nothing is done about it. + +## Non-Goals + +Acting on another directory: opening, running, ticking, releasing its +lease. All of it is refused by construction — there is no control. + +A registry, a daemon, or any reporting protocol between agents. The +information is on this disk already, and a second source of truth would +be free to disagree with the filesystem and be believed. + +Directories of other repositories, or on other machines. `git worktree +list` bounds this to working directories of this repository. + +Merging foreign changes into the local readiness report, which would +make `openspec-ui-cli ready` answer for work its caller cannot start. + +## Risks / Trade-offs + +The survey is a reading, not a subscription: a directory can change +between two of them. It says when it last looked, as the pipeline tab +already does. + +A directory can be on a network path or an unmounted drive, where a read +blocks or fails. One unreadable directory must be reported as unreadable +and must not remove the others from the survey. + +Reading another directory's files means displaying content this host did +not write. It is displayed as text and never executed — the same footing +as repository file contents everywhere else in this tool. + +Many directories make a long page. They are read less often than the +local one and only while being looked at. diff --git a/openspec/changes/what-the-others-are-doing/proposal.md b/openspec/changes/what-the-others-are-doing/proposal.md new file mode 100644 index 0000000..c66ba67 --- /dev/null +++ b/openspec/changes/what-the-others-are-doing/proposal.md @@ -0,0 +1,69 @@ +# What the others are doing + +## Why + +On 2026-09-12 two agents worked on this repository at once — one in the +primary checkout, one in a working directory beside it — and the owner +could see only their own. Six proposals sat one directory away, written +and invisible. + +The tool answered honestly and uselessly. It reported the queue of the +directory it was pointed at, which happened to be sitting on a branch +whose pull request had already merged, so it said there were no active +changes. Nothing on screen named the branch it had read, so "there is +nothing to do" and "you are looking at a stale checkout" looked +identical. + +A second thing went unnoticed in the same session: a change archived in +one directory was still present, as a tracked file, in another. It came +along with the branch point, put there by nobody. Harmless while +untouched, and a real collision the moment either copy is edited. +Nothing reports it today. + +The parts to fix both are already here. `changes-run-side-by-side` gave +each change a working directory; `what-can-start-now` derived what is +running from the lease each one holds; `a-lease-says-who` made the lease +say whose run it is; `a-graph-of-what-is-running` drew the result. Every +one of them stops at the edge of the directory it was given. + +Nothing about that edge is expensive to cross. A working directory is +not a remote thing: `git worktree` shares one object store, and the +sibling's `.git` is a file naming a subdirectory of this one. The survey +is a local read, with no daemon, no network and no registry. + +## What Changes + +- A **survey** of every working directory of this repository: its label, + the branch it has checked out, the changes in its own queue, how far + each one's tasks have got, and who holds it where a run does. +- The pipeline tab shows each directory's changes as their own picture — + this one at full strength, the others recessed beneath it. Nothing + foreign enters the local order, and no relation is drawn between + directories. +- Foreign changes carry **no action at all**. Read-only is what the view + can do, not how it looks. +- Each directory carries a **label**, defaulting to its own directory + name and overridable by a file in it. Self-declared: attribution, + never authentication. +- Where a directory's lease records a **git author different from this + checkout's**, the survey says so — in a word, agreed with by colour, + never carried by colour alone. +- A change present in more than one directory at once is **reported**, + not prevented and not resolved. +- The tab **names the branch each reading came from**, so an empty queue + is not mistaken for a stale checkout. +- **No git is run against a directory this host does not own.** One + `git worktree list` enumerates them; everything after that is a + filesystem read. + +## Impact + +- `packages/core` — a survey module beside `change-readiness`, reading + directories rather than deriving new facts about them. +- `packages/server` — one endpoint carrying the survey. +- `packages/webui` — the foreign bands under the local picture, and the + branch each reading names. +- No new dependency, no background service, no configuration required + for a directory to appear. + +See `docs/adr/0026-other-working-directories-are-observed-never-touched.md`. diff --git a/openspec/changes/what-the-others-are-doing/specs/shared-ui/spec.md b/openspec/changes/what-the-others-are-doing/specs/shared-ui/spec.md new file mode 100644 index 0000000..3e0df9c --- /dev/null +++ b/openspec/changes/what-the-others-are-doing/specs/shared-ui/spec.md @@ -0,0 +1,133 @@ +## ADDED Requirements + +### Requirement: Every working directory of the repository is surveyed + +The tool SHALL report every working directory of the repository it was +opened on, not only the one it was pointed at. + +For each, it SHALL report the branch that directory has checked out, the +changes in that directory's own queue, how far each of those changes has +got, and, where a mutating run holds it, who holds it. + +A directory that cannot be read SHALL be reported as unreadable, and +SHALL NOT remove the others from the survey. + +#### Scenario: A second working directory with changes of its own + +- **WHEN** another working directory holds changes that this one does + not +- **THEN** they are reported, with the branch they are on + +#### Scenario: A directory that cannot be read + +- **WHEN** one working directory cannot be read +- **THEN** it is reported as unreadable and the rest of the survey still + appears + +### Requirement: Another directory's changes cannot be acted on + +A change belonging to another working directory SHALL carry no action: +it SHALL NOT be openable, runnable, or modifiable from here. + +A change SHALL be identified by its working directory together with its +name, never by name alone, so that no action can reach a change of the +same name in a different directory. + +Recessed or otherwise quietened presentation SHALL NOT be the only thing +that makes it unmodifiable. + +#### Scenario: A change belonging to somebody else's directory + +- **WHEN** a change from another working directory is shown +- **THEN** nothing offers to open, run, or change it + +#### Scenario: One name in two directories + +- **WHEN** two working directories each hold a change of the same name +- **THEN** each is shown under its own directory, and neither can be + acted on through the other + +### Requirement: A working directory is labelled, and the label is not an identity + +Each working directory SHALL carry a label. + +Where the directory declares none, its own directory name SHALL be used, +so that a directory that declares nothing is still named. + +The label SHALL be reported as self-declared. Nothing SHALL be permitted +or refused on the strength of it. + +#### Scenario: A directory that declares nothing + +- **WHEN** a working directory carries no declared label +- **THEN** it is named by its directory name + +#### Scenario: A directory that declares a label + +- **WHEN** a working directory declares a label +- **THEN** that label names it + +### Requirement: A run by a different git author is distinguished + +Where a working directory is held by a run whose recorded git author +differs from this checkout's own configured identity, the survey SHALL +say so. + +It SHALL be said in words. Colour MAY agree with those words and SHALL +NOT be the only thing that carries the distinction. + +The label and the git author SHALL be reported as the separate facts +they are; neither SHALL stand in for the other. + +#### Scenario: Another person's run + +- **WHEN** a directory's lease records a git author other than this + checkout's +- **THEN** the survey says so in words + +#### Scenario: Several directories, one person + +- **WHEN** every directory records the same git author +- **THEN** none is distinguished as another person's, and each is still + named by its own label + +### Requirement: A reading names the branch it came from + +The tool SHALL name the branch each reading was taken from. + +An empty queue SHALL therefore be distinguishable from a reading taken +somewhere other than where the reader expected. + +#### Scenario: A checkout with no active changes + +- **WHEN** the directory being read has no active changes +- **THEN** it says so and names the branch it read + +### Requirement: Nothing from another directory enters this one's order + +Changes belonging to another working directory SHALL be laid out against +that directory's own queue, and SHALL NOT be placed in this one's order. + +No relation SHALL be drawn between changes in different working +directories. The repository declares no order between them, and a drawn +relation would assert one. + +#### Scenario: Two directories with unrelated changes + +- **WHEN** two working directories each hold changes +- **THEN** each set is laid out on its own, and nothing is drawn between + them + +### Requirement: A change present in more than one directory is reported + +Where one change exists in more than one working directory, the survey +SHALL report it. + +It SHALL NOT be refused, prevented, or resolved: it arises from ordinary +branching, and becomes a conflict only if a copy is edited. + +#### Scenario: A change inherited by a new working directory + +- **WHEN** a change exists in two working directories at once +- **THEN** the survey reports that it does, and both continue to be + shown diff --git a/openspec/changes/what-the-others-are-doing/tasks.md b/openspec/changes/what-the-others-are-doing/tasks.md new file mode 100644 index 0000000..7ef5dba --- /dev/null +++ b/openspec/changes/what-the-others-are-doing/tasks.md @@ -0,0 +1,115 @@ +Two agents worked on this repository at once and the owner could see one +of them. The tool reported the queue of the directory it was pointed at, +which was sitting on a branch whose pull request had already merged, so +it said there was nothing to do — and nothing on screen named the branch +it had read. + +## 1. The survey + +- [ ] 1.1 `worktree-survey.ts` in core: every working directory of this + repository, each with its path, label, branch, head, changes, and the + lease holder where one exists. +- [ ] 1.2 One `git worktree list` and nothing else. No git is run against + a directory this host does not own — see ADR 0026. Everything after + that is a filesystem read. +- [ ] 1.3 Per directory: the names under `openspec/changes` other than + `archive`, and each one's closed and total task counts. +- [ ] 1.4 The lease is read where present. Absent means no mutating run + holds it — never "idle", which is a claim the data does not make: an + agent editing files holds no lease. +- [ ] 1.5 A directory that cannot be read is reported as unreadable and + does not remove the others. A network path or an unmounted drive is + one directory's problem, not the survey's. +- [ ] 1.6 Collisions are deliberately NOT computed for a foreign + directory: a git invocation per directory per read, answering a + question the viewer cannot act on. +- [ ] 1.7 A change present in more than one directory is reported as + such. Not refused and not resolved — it comes from ordinary branching. + +## 2. The label + +- [ ] 2.1 Defaults to the last segment of the directory's own path. Free, + already meaningful, and distinct by construction: git will not put two + working directories at one path. +- [ ] 2.2 Overridable by `.openspec-ui/worker.json` in that directory, + one field. +- [ ] 2.3 Lives in the directory and not only in the lease. The lease + exists only while a mutating run holds one, and the ordinary state is + somebody editing files, holding nothing. +- [ ] 2.4 Called a label, never an owner. "Owner" asserts authority this + view does not grant, and `a-lease-says-who` already found that a word + which overstates gets believed. Self-declared: attribution, never + authentication. + +## 3. Whose run it is + +- [ ] 3.1 The survey marks a directory whose lease records a git author + different from this checkout's own configured identity. +- [ ] 3.2 Said in words; colour agrees with the words and never carries + the distinction alone. The browser suite runs axe at WCAG AA, and the + same rule already governs running-versus-blocked on a card. +- [ ] 3.3 The label and the git author are reported as separate facts. + On one person's machine every directory reports the same author, which + is a correct answer rather than a failure of the label. + +## 4. Getting it to the shell + +- [ ] 4.1 A server endpoint carrying the survey, in the shape core + returns. +- [ ] 4.2 A webui client, browser-safe: it asks, it does not derive. + `packages/server/src/static.test.ts` is the gate. + +## 5. Showing it + +- [ ] 5.1 The pipeline tab names the branch its reading came from, so an + empty queue is not mistaken for a stale checkout. This is the one item + that would have saved the session that prompted this change. +- [ ] 5.2 Each foreign directory gets its own picture beneath the local + one, laid out by `layoutChanges` against that directory's own queue. +- [ ] 5.3 Recessed, and labelled with its label, its branch, and — where + a run holds it — the holder and git author. +- [ ] 5.4 No relation is drawn between directories. The repository + declares no order between them, and a line would be believed because + it would look like every other line. +- [ ] 5.5 A foreign change carries no action: no opening, no running, no + ticking. Read-only is what the view can do, not how it looks. +- [ ] 5.6 A duplicate change is called out where it appears. +- [ ] 5.7 Foreign directories are read less often than the local one, and + only while the tab is being looked at. + +## 6. Tests + +- [ ] 6.1 Core: two working directories, each with its own changes; both + surveyed with their branches. +- [ ] 6.2 Core: a directory with no lease is reported as held by nobody, + and never as idle. +- [ ] 6.3 Core: an unreadable directory is reported as such and the rest + of the survey survives. +- [ ] 6.4 Core: the label defaults to the directory name and a declared + one overrides it. +- [ ] 6.5 Core: one change in two directories is reported as duplicated. +- [ ] 6.6 Core: no git subprocess is invoked per foreign directory — + asserted against a wrapper that records its calls, because this is a + cost the code could reacquire silently. +- [ ] 6.7 webui: a foreign change offers no action, and a foreign + directory whose author differs says so in words rather than only in + colour. +- [ ] 6.8 webui: no relation is drawn between two directories. +- [ ] 6.9 Browser suite: the tab with a second working directory passes + axe at WCAG AA, and its screenshot under `docs/images/standalone/` is + regenerated. + +## 7. Verification + +- [ ] 7.1 This change validates strictly. `check(validate-change)` +- [ ] 7.2 `npm run verify` unpiped, after the last edit, with everything + staged. Record the run and the per-package test counts. +- [ ] 7.3 The whole browser suite, not a selected spec. +- [ ] 7.4 A pending changeset exists. `check(changeset-present)` +- [ ] 7.5 **Delegated to `claude-cli`**: with a second agent actually + working in a second working directory, open the tab and check that its + label, branch and changes are the ones on disk there, that nothing + offers to act on them, and that a run held there names its git author. + Evidence: both directories, and the tab. The unit tests drive the + survey with directories a test made; only a real second agent shows + that what it writes is what the survey reads.