Merge branch 'review/off-queue-dx'
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -14,18 +14,18 @@
|
|||||||
|
|
||||||
**Стало.** Если `HSchool.AppHost.dll` и `HSchool.Server.dll` новее входов (C#, csproj, props,
|
**Стало.** Если `HSchool.AppHost.dll` и `HSchool.Server.dll` новее входов (C#, csproj, props,
|
||||||
`global.json`), скрипт делает `dotnet run --no-build`. Иначе — `dotnet build`, потом `--no-build`.
|
`global.json`), скрипт делает `dotnet run --no-build`. Иначе — `dotnet build`, потом `--no-build`.
|
||||||
`--rebuild` собирает всегда. Конфигурация (`-c` / `--configuration`) выбирает, какие dll сравнивать;
|
`--rebuild` собирает всегда. Конфигурация (`-c` / `--configuration`) выбирает, какие dll сравнивать
|
||||||
по умолчанию Debug, как у `dotnet run`.
|
и с какой конфигурацией звать `dotnet run`; по умолчанию Debug.
|
||||||
|
|
||||||
**Почему.** Инкрементальный MSBuild всё равно оценивает Aspire SDK. `--no-build` это пропускает.
|
**Почему.** Инкрементальный MSBuild всё равно оценивает Aspire SDK. `--no-build` это пропускает.
|
||||||
Клиентский TypeScript и JSONC модов не входы: Vite и каталог читают диск (`ContentRoot`), а не
|
Клиентский TypeScript и JSONC модов не входы: Vite и каталог читают диск (`ContentRoot`), а не
|
||||||
`bin`. Тестовые проекты AppHost не ссылается — их правки запуск не пересобирают.
|
`bin`. Тестовые проекты AppHost не ссылается — их правки запуск не пересобирают.
|
||||||
|
|
||||||
Правила «устарел ли билд» живут в `tools/apphost-uptodate.ps1` (то, что вызывает `run-aspire.ps1`) и в
|
Правила «устарел ли билд» живут в трёх местах: `tools/apphost-uptodate.ps1` (Windows),
|
||||||
`LaunchBuildStamp` (то, что проверяют тесты). Менять надо оба.
|
`needs_build` в `run-aspire.sh` (Ubuntu) и `LaunchBuildStamp` (то, что проверяют тесты).
|
||||||
|
Менять надо все три.
|
||||||
|
|
||||||
### Что не входит
|
### Что не входит
|
||||||
|
|
||||||
Голый `dotnet run --project src/HSchool.AppHost` по-прежнему собирает — так удобнее агентам с
|
Голый `dotnet run --project src/HSchool.AppHost` по-прежнему собирает — так удобнее агентам с
|
||||||
грязным деревом. Linux-обёртки нет: точка входа Windows — `.cmd`. Протокол, HTTP и сейв не
|
грязным деревом. Протокол, HTTP и сейв не трогаем.
|
||||||
трогаем.
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# Проверенные фазы «Вне очереди»
|
# Проверенные фазы «Вне очереди»
|
||||||
|
|
||||||
Портреты 60–62. Соседей по папке (уроки, DX) этот журнал не закрывает.
|
Разделы ниже — отдельные проходы. Чужой раздел не затирать. Уроки 48, 50–53 этот журнал
|
||||||
|
не закрывает.
|
||||||
|
|
||||||
## Портреты. Модели, слои промпта, LoRA и embeddings
|
## Портреты. Модели, слои промпта, LoRA и embeddings
|
||||||
|
|
||||||
@@ -35,3 +36,26 @@ Discovery читает `models.Embedding` (офлайн — пустой спи
|
|||||||
### Открытое
|
### Открытое
|
||||||
|
|
||||||
Хостовый `GetPortraitPrompt_ReturnsBuiltPositiveAndNegative` больше не ищет подстроку `age ` (она есть в `teenage`); проверка `\bage \d+` в этом проходе не гонялась.
|
Хостовый `GetPortraitPrompt_ReturnsBuiltPositiveAndNegative` больше не ищет подстроку `age ` (она есть в `teenage`); проверка `\bage \d+` в этом проходе не гонялась.
|
||||||
|
|
||||||
|
## DX. Пропуск сборки, «Что нового», состояние экрана
|
||||||
|
|
||||||
|
- **Фазы:** 49, 54, 55
|
||||||
|
- **Проверен на:** `d8d0423`, 2026-08-20
|
||||||
|
- **Пути:** `tools/apphost-uptodate.ps1`, `run-aspire.cmd`, `run-aspire.ps1`, `run-aspire.sh`, `tests/HSchool.AppHost.Tests/LaunchBuildStamp.cs`, `tests/HSchool.AppHost.Tests/LaunchBuildStampTests.cs`, `src/HSchool.Server/Changelog/BuildChangelog.cs`, `src/HSchool.Server/Api/ChangelogEndpoints.cs`, `src/HSchool.Server/HSchool.Server.csproj`, `tools/embed-changelog.ps1`, `tools/embed-changelog.sh`, `tests/HSchool.Server.Tests/BuildChangelogTests.cs`, `tests/HSchool.AppHost.Tests/ChangelogApiTests.cs`, `src/HSchool.Client/src/ui/whatsNew.ts`, `src/HSchool.Client/src/ui/whatsNew.test.ts`, `src/HSchool.Client/src/ui/seenRevision.ts`, `src/HSchool.Client/src/ui/viewState.ts`, `src/HSchool.Client/src/ui/viewState.test.ts`, `src/HSchool.Client/src/ui/gameScreen.ts`, `src/HSchool.Client/src/main.ts`, `docs/protocol.md`, `docs/design/off-queue/skip-stale-build.md`, `docs/design/off-queue/whats-new.md`, `docs/design/off-queue/view-state.md`
|
||||||
|
- **Итог:** обещания 49/54/55 совпадают с кодом. Сокет не бампили (v9). Дописаны порядок нескольких коммитов в changelog и восстановление вкладки с меню из `sessionStorage`. `run-aspire` передаёт `-c` в `dotnet run`, не только в штамп. Дизайн 49 догнан до `run-aspire.sh`. `BuildChangelogTests` зелёные (4). Хостовые `ChangelogApiTests` и `LaunchBuildStampTests` в этом проходе не гонялись (штамп не менялся; HTTP не менялся; живой сервер пользователя не трогали).
|
||||||
|
|
||||||
|
### Фаза 49
|
||||||
|
|
||||||
|
`apphost-uptodate.ps1` / `LaunchBuildStamp` / `needs_build` в `.sh` смотрят AppHost+Server dll против `*.cs`/`*.csproj`/`*.props` под `src/` и трёх named props; TS/JSONC и `bin`/`obj`/`node_modules` не входы. Семь тестов штампа на временных папках есть, без `AppHostFixture`. `--rebuild` собирает и затем стартует AppHost.
|
||||||
|
|
||||||
|
### Фаза 54
|
||||||
|
|
||||||
|
SHA и first-parent лог вшиваются при сборке Server, не из рантайма. `GET /api/changelog` за сессией: пусто без `since` / неизвестный / текущий SHA; `Mark phase N` в списке нет, якорем остаётся. Кука `hschool.seen-rev` (год, `Path=/`, `SameSite=Lax`, не HttpOnly). Модалка после `ensureSession` на старте и после logout, не при выходе из школы на меню.
|
||||||
|
|
||||||
|
### Фаза 55
|
||||||
|
|
||||||
|
Query держит школу/режим/вкладки/выбор; `sessionStorage` ключ `h-school.view.{id}` — фильтры людей, соискателей, карточку и управление. Вход/выход — `pushState`, вкладки и фильтры — `replaceState`. Гость с `mode=manage` остаётся в обзоре. F5 с `?school=` шлёт тот же `OpenSchool`.
|
||||||
|
|
||||||
|
### Открытое
|
||||||
|
|
||||||
|
Ничего, что фаза 54 обещала и не сделала. Баги сессии из журнала среза 8 (другое имя при живой куке, Data Protection) сюда не входят — не трогали.
|
||||||
|
|||||||
@@ -35,3 +35,4 @@
|
|||||||
| Срез 10. Этапы B–C — работник, карточка и дамп | `f4f726a` | [10-craft](10-craft/reviewed.md) |
|
| Срез 10. Этапы B–C — работник, карточка и дамп | `f4f726a` | [10-craft](10-craft/reviewed.md) |
|
||||||
| Портреты (вне очереди) 60–61 | `5e23d1f` | [off-queue](off-queue/reviewed.md) |
|
| Портреты (вне очереди) 60–61 | `5e23d1f` | [off-queue](off-queue/reviewed.md) |
|
||||||
| Портреты (вне очереди) 62 | `d093ea3` | [off-queue](off-queue/reviewed.md) |
|
| Портреты (вне очереди) 62 | `d093ea3` | [off-queue](off-queue/reviewed.md) |
|
||||||
|
| Вне очереди. DX 49/54/55 | `d8d0423` | [off-queue](off-queue/reviewed.md) |
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ $run = @(
|
|||||||
'--project', (Join-Path $PSScriptRoot 'src\HSchool.AppHost\HSchool.AppHost.csproj')
|
'--project', (Join-Path $PSScriptRoot 'src\HSchool.AppHost\HSchool.AppHost.csproj')
|
||||||
'--no-build'
|
'--no-build'
|
||||||
'--no-restore'
|
'--no-restore'
|
||||||
|
'-c', $configuration
|
||||||
) + $dotnetArgs
|
) + $dotnetArgs
|
||||||
& dotnet run @run
|
& dotnet run @run
|
||||||
$exitCode = $LASTEXITCODE
|
$exitCode = $LASTEXITCODE
|
||||||
|
|||||||
+1
-1
@@ -131,7 +131,7 @@ fi
|
|||||||
echo
|
echo
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
dotnet run --project src/HSchool.AppHost/HSchool.AppHost.csproj --no-build --no-restore "${dotnet_args[@]}"
|
dotnet run --project src/HSchool.AppHost/HSchool.AppHost.csproj --no-build --no-restore -c "$configuration" "${dotnet_args[@]}"
|
||||||
exit_code=$?
|
exit_code=$?
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { getLocale, setLocale } from '../i18n/locale.ts';
|
|||||||
import { t } from '../i18n/strings.ts';
|
import { t } from '../i18n/strings.ts';
|
||||||
import { GameScreen } from './gameScreen.ts';
|
import { GameScreen } from './gameScreen.ts';
|
||||||
import type { School } from '../net/api.ts';
|
import type { School } from '../net/api.ts';
|
||||||
|
import { patchChrome } from './viewState.ts';
|
||||||
|
|
||||||
vi.mock('../net/api.ts', async (importOriginal) => {
|
vi.mock('../net/api.ts', async (importOriginal) => {
|
||||||
const actual = await importOriginal<typeof import('../net/api.ts')>();
|
const actual = await importOriginal<typeof import('../net/api.ts')>();
|
||||||
@@ -272,6 +273,25 @@ describe('GameScreen view restore', () => {
|
|||||||
expect(screen.element.querySelector('.panel__body--fill')?.hasAttribute('hidden')).toBe(false);
|
expect(screen.element.querySelector('.panel__body--fill')?.hasAttribute('hidden')).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('reopens the last tab from sessionStorage when opening from the menu', () => {
|
||||||
|
history.replaceState(null, '', '/');
|
||||||
|
patchChrome(1, { route: { tab: 'people' } });
|
||||||
|
const screen = new GameScreen({
|
||||||
|
onLeave: () => {},
|
||||||
|
onSetRunning: () => {},
|
||||||
|
onSetSpeed: () => {},
|
||||||
|
onSkip: () => {},
|
||||||
|
});
|
||||||
|
document.body.append(screen.element);
|
||||||
|
screen.show(school());
|
||||||
|
|
||||||
|
const peopleTab = [...screen.element.querySelectorAll('.panel__tab')].find(
|
||||||
|
(button) => button.textContent === t('peopleTitle'),
|
||||||
|
);
|
||||||
|
expect(peopleTab?.classList.contains('panel__tab--active')).toBe(true);
|
||||||
|
expect(location.search).toContain('tab=people');
|
||||||
|
});
|
||||||
|
|
||||||
it('keeps a guest on overview even when the URL asks for manage', () => {
|
it('keeps a guest on overview even when the URL asks for manage', () => {
|
||||||
history.replaceState(null, '', '/?school=3&mode=manage');
|
history.replaceState(null, '', '/?school=3&mode=manage');
|
||||||
const screen = new GameScreen({
|
const screen = new GameScreen({
|
||||||
|
|||||||
@@ -5,13 +5,15 @@ namespace HSchool.Server.Tests;
|
|||||||
public class BuildChangelogTests
|
public class BuildChangelogTests
|
||||||
{
|
{
|
||||||
private const string Head = "cccccccccccccccccccccccccccccccccccccccc";
|
private const string Head = "cccccccccccccccccccccccccccccccccccccccc";
|
||||||
|
private const string Mid = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
|
||||||
private const string Mark = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
|
private const string Mark = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
|
||||||
private const string Merge = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
|
private const string Merge = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
|
||||||
private const string Unknown = "dddddddddddddddddddddddddddddddddddddddd";
|
private const string Unknown = "dddddddddddddddddddddddddddddddddddddddd";
|
||||||
|
|
||||||
private static readonly string Sample = string.Join('\n',
|
private static readonly string Sample = string.Join('\n',
|
||||||
Head,
|
Head,
|
||||||
$"{Head}\u001f2026-01-03T12:00:00Z\u001fAdd changelog window",
|
$"{Head}\u001f2026-01-04T12:00:00Z\u001fAdd changelog window",
|
||||||
|
$"{Mid}\u001f2026-01-03T12:00:00Z\u001fSkip stale AppHost build",
|
||||||
$"{Mark}\u001f2026-01-02T12:00:00Z\u001fMark phase 54 in progress.",
|
$"{Mark}\u001f2026-01-02T12:00:00Z\u001fMark phase 54 in progress.",
|
||||||
$"{Merge}\u001f2026-01-01T12:00:00Z\u001fMerge branch 'phase/53-weather-commute'");
|
$"{Merge}\u001f2026-01-01T12:00:00Z\u001fMerge branch 'phase/53-weather-commute'");
|
||||||
|
|
||||||
@@ -22,9 +24,11 @@ public class BuildChangelogTests
|
|||||||
|
|
||||||
var visible = changelog.VisibleSince(Merge);
|
var visible = changelog.VisibleSince(Merge);
|
||||||
|
|
||||||
var commit = Assert.Single(visible);
|
Assert.Equal(2, visible.Count);
|
||||||
Assert.Equal(Head, commit.Sha);
|
Assert.Equal(Mid, visible[0].Sha);
|
||||||
Assert.Equal("Add changelog window", commit.Subject);
|
Assert.Equal("Skip stale AppHost build", visible[0].Subject);
|
||||||
|
Assert.Equal(Head, visible[1].Sha);
|
||||||
|
Assert.Equal("Add changelog window", visible[1].Subject);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -34,8 +38,9 @@ public class BuildChangelogTests
|
|||||||
|
|
||||||
var visible = changelog.VisibleSince(Mark);
|
var visible = changelog.VisibleSince(Mark);
|
||||||
|
|
||||||
var commit = Assert.Single(visible);
|
Assert.Equal(2, visible.Count);
|
||||||
Assert.Equal("Add changelog window", commit.Subject);
|
Assert.Equal("Skip stale AppHost build", visible[0].Subject);
|
||||||
|
Assert.Equal("Add changelog window", visible[1].Subject);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
Reference in New Issue
Block a user