diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e0e93839..be8584d46 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -168,6 +168,7 @@ jobs: cache: npm cache-dependency-path: ui/package-lock.json - name: Install UI deps + id: ui-deps working-directory: ui run: npm ci - name: First-party LOC and complexity ratchet @@ -176,6 +177,12 @@ jobs: # with the previous tip (github.event.before). Never fall back to # the historical dashboard: that paints merge commits red. BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }} + BASE_BRANCH: ${{ github.event.pull_request.base.ref }} + SOURCE_BRANCH: ${{ github.event.pull_request.head.ref }} + SOURCE_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + BASE_REPOSITORY: ${{ github.event.pull_request.base.repo.full_name }} + SOURCE_REPOSITORY: ${{ github.event.pull_request.head.repo.full_name }} + EVENT_REPOSITORY: ${{ github.event.repository.full_name }} run: | set -euo pipefail if [ -z "${BASE_SHA:-}" ] || [ "${BASE_SHA}" = "0000000000000000000000000000000000000000" ]; then @@ -195,17 +202,24 @@ jobs: uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: code-health-report - path: code-health.md + path: | + code-health.md + code-health-integration.json if-no-files-found: ignore # Split `npm run check` so a hung runner is visible in the failing step # instead of one opaque 6-hour job (GitHub's default timeout). + # Collect all validation results even when the ratchet or an earlier + # check fails. A failed step still fails this job and CI required. - name: UI tests + if: ${{ !cancelled() && steps.ui-deps.outcome == 'success' }} working-directory: ui run: npm test - name: Lint with zero warnings + if: ${{ !cancelled() && steps.ui-deps.outcome == 'success' }} working-directory: ui run: npm run lint -- --max-warnings=0 - name: Type-check, build and bundle budget + if: ${{ !cancelled() && steps.ui-deps.outcome == 'success' }} working-directory: ui run: python ../scripts/build_ui.py && python ../scripts/build_ui.py --check && npm run budget diff --git a/.gitignore b/.gitignore index 91d73a207..8f0e4bae3 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,12 @@ ui/blob-report/ # Private planning notes and local-only development artefacts. /internal/ /comunicaciones/ +# Temporary agent handoffs and unapplied integration instructions. +/H[0-9][0-9]_HANDOFF.md +/INTEGRATION*.patch +/PR_BODY.md +/ui/src/features/diagnostics/INTEGRATION.patch +/code-health-integration.json # Pinokio runtime logs/ diff --git a/H07_HANDOFF.md b/H07_HANDOFF.md deleted file mode 100644 index 9a6e4c569..000000000 --- a/H07_HANDOFF.md +++ /dev/null @@ -1,48 +0,0 @@ -# H07 handoff — reuse vocal analysis across shots - -Branch `grok/agente1-h07-speech-analysis-cache-20260911` from `origin/development`. -Draft PR toward `development`. Do not merge. - -## What shipped - -- Persistent atomic cache (`app/services/speech_analysis_cache.py`) keyed by - audio SHA-256, BS-RoFormer/Rhubarb identity, isolation/analysis parameters - and the 90 s payload window. Same segment, three shots → one isolation and - one Rhubarb run. Different windows stay different keys; they are never - concatenated. -- `isolate_voice` / `analyze_voice` coalesce in-flight work. A failed worker - does not publish a `.wav`/`.json` entry. Pins skip eviction while another - consumer still needs the result. -- UI `decodeVoice` keeps a bounded (8) decoder cache. Simultaneous requests - share one fetch; aborting one caller does not abort or drop the shared - decode. `mixSceneSpeech` still mixes the original soundtrack URL. - -CueTimeline was not edited (H06). 90 s analysis cap unchanged. - -## Mock vs real isolation - -| Circuit | Result | -| --- | --- | -| Isolation worker mocked (`subprocess.run` copies WAV, CPU/offline env still asserted) | **simulated PASS** — three shots, one worker | -| Rhubarb mocked (writes `mouthCues`) + isolation mock | **simulated PASS** — cue times identical, isolation once | -| Missing optional BS-RoFormer files | **simulated PASS** — `reason=optional_model_missing`, no download | -| Failure / `os.replace` error | **simulated PASS** — no partial cache file | -| Concurrent waiters; one abandoned | **simulated PASS** — shared result kept | -| UI decode cache + mix soundtrack | **simulated PASS** — original URL only | -| Installed BS-RoFormer `app/ckpts/roformer/*.ckpt,*.yaml` + `audio_separator` | **PENDING real** — tests never start a download | -| Real Rhubarb binary | **PENDING real** — not required for this PR | - -Do not download vocal-isolation models to “complete” this lane. The worker -stays installed-only, CPU, `HF_HUB_OFFLINE=1`. - -## How to try it - -```bash -PYTHONPATH=app /home/ina/pinokio/api/Maestro-next.git/app/env/bin/python -m pytest \ - tests/test_speech_analysis_cache.py tests/test_vocal_isolation.py tests/test_scene3d_speech.py -q -cd ui && npx tsx --tsconfig tsconfig.app.json --import ./tests/setupI18n.ts \ - --test tests/scene3dSpeechAudioCache.test.ts -``` - -Cache dir: `SPEECH_ANALYSIS_CACHE_DIR` or `cache/speech-analysis/` (gitignored). -Limits: `SPEECH_ANALYSIS_CACHE_MAX_BYTES` (128 MiB), `SPEECH_ANALYSIS_CACHE_MAX_ENTRIES` (64). diff --git a/H17_HANDOFF.md b/H17_HANDOFF.md deleted file mode 100644 index 38ec1f46a..000000000 --- a/H17_HANDOFF.md +++ /dev/null @@ -1,60 +0,0 @@ -# H17 handoff — Wizard/MCP corpus - -Branch `grok/agente1-h17-wizard-corpus-20260911` from `origin/development` `780d3915`. -Draft PR toward `development`. Do not merge. - -## What shipped - -- EN/ES corpus fixture `tests/fixtures/wizard_mcp_corpus.json` (intents, negations, - ambiguous refs, workspace change, retry, compound, unpublished, errors). -- Contract tests: `tests/test_wizard_mcp_corpus.py`, `ui/tests/wizardMcpCorpus.test.ts`. -- Simulated E2E: `ui/e2e/specs/wizard-mcp-corpus.spec.ts` (Playwright harness, no Pinokio restart). -- Guide: `docs/development/WIZARD_MCP_USAGE.md` (usable without reading the code). -- Local evidence (gitignored): `outputs/wizard-mcp-corpus-20260911/`. - -No product runtime files were changed. No foreign lanes edited. - -## Mock vs real - -| Circuit | Result | -| --- | --- | -| FakeNative HTTP + MCP (image/speech/music/sfx/upscale) | **simulated PASS** — admission, replay, two clients, same id | -| Wizard parse/reconcile/format (EN/ES corpus) | **simulated PASS** | -| Playwright simulated API | implemented; run in CI / locally with the UI preview | -| Live `GET /api/v1/generation/commands` on already-running API `:42005` | **read-only real** if that process is up | -| Live MCP `tools/list` | not executed (Bearer token not taken from the shared runtime) | -| Real generation with installed models | **PENDING** | - -Installed on the shared machine (not used): `flux2_klein_4b`, `kugelaudio_0_open`, -`ace_step_v1_5_xl_sft_lm_4b`, others. H17 does **not** enqueue GPU work on the -cinematic/shared Pinokio runtime. - -## Matrix - -See the fixture `matrix` array and `docs/development/WIZARD_MCP_USAGE.md`. -Short form: designed/implemented/simulated for published ops; `generation.video` -designed but **not implemented** (H01); real generate pending. - -## Failures found (not silently fixed) - -1. **H01** `generation.video` is unpublished on this base. Repro: catalog omits it; - MCP `tools/call` name `generation.video` is `isError` and creates zero tasks. -2. **H09** prior Video Editor 589/590 frame finding is recorded, not retested. -3. **agentActions** “Open Studio, prepare a Flux image … and generate it.” - fills the form and does **not** start. Repro `compound-prepare-and-generate-it`. -4. **wizardTurnReport** how-to with an empty action list keeps model prose - (invented “I generated invented.png.”). No task is created. Repro in the - corpus fixture `howto-empty-turn-keeps-model-prose`. Not patched here - (`wizardTurnReport.ts` is read-only for this lane). - -## How to try it - -```bash -PYTHONPATH=app /home/ina/pinokio/api/Maestro-next.git/app/env/bin/python -m pytest tests/test_wizard_mcp_corpus.py -q -cd ui && npx tsx --tsconfig tsconfig.app.json --import ./tests/setupI18n.ts --test tests/wizardMcpCorpus.test.ts -# optional: npx playwright test -c e2e/playwright.config.ts e2e/specs/wizard-mcp-corpus.spec.ts -``` - -As a user: read `docs/development/WIZARD_MCP_USAGE.md`. Refusal must create no -task; an unpublished tool must not promise success; a timeout replay must keep -the same job id on both clients. diff --git a/INTEGRATION.patch b/INTEGRATION.patch deleted file mode 100644 index 4ff79362c..000000000 --- a/INTEGRATION.patch +++ /dev/null @@ -1,30 +0,0 @@ -H14 integration notes (do not rewrite ActivityFooter / useStore / applicationAdapters). - -1) i18n resources one-liner (ui/tests/i18nFoundation.test.tsx freezes NAMESPACES; - this PR keeps catalogs in ui/src/i18n/locales/{en,es}/generationInspector.json - and loads them from features/generation-inspector/copy.ts): - - import generationInspectorEn from './locales/en/generationInspector.json' - import generationInspectorEs from './locales/es/generationInspector.json' - // NAMESPACES += 'generationInspector' - // resources.en.generationInspector = generationInspectorEn - // resources.es.generationInspector = generationInspectorEs - -2) H02 execution detail hook (ui/src/features/activity/executionDetail.tsx GroupActions), - without rewriting ActivityFooter: - - import { inspectFromActivity } from '../generation-inspector' - } { @@ -44,28 +45,28 @@ export function SeriesVoiceFields({

{kitOwnsTts ? t('canon.kitTtsHint') : t('canon.unlinkedTtsHint')}

- onPatchVoice(index, { provider: event.target.value })} /> + onPatchVoice(index, { provider: event.target.value })} /> - onPatchVoice(index, { voiceId: event.target.value })} /> + onPatchVoice(index, { voiceId: event.target.value })} /> - onPatchVoice(index, { language: event.target.value })} /> + onPatchVoice(index, { language: event.target.value })} /> - onPatchVoice(index, { pace: Number(event.target.value) })} /> + onPatchVoice(index, { pace: Number(event.target.value) })} /> - onPatchVoice(index, { pitch: Number(event.target.value) })} /> + onPatchVoice(index, { pitch: Number(event.target.value) })} /> - onPatchVoice(index, { emotionalDefaults: event.target.value })} /> + onPatchVoice(index, { emotionalDefaults: event.target.value })} /> -