Nemotron qualification framework (bench/psyche-ab-matrix) — DRAFT until live plan runs - #1492
Nemotron qualification framework (bench/psyche-ab-matrix) — DRAFT until live plan runs#1492hartsock wants to merge 48 commits into
Conversation
…ier is warning-clean
The R4 panel rework added `PsychePersonaAction {Keep, Clear, Switch}` and
`PersonaStore::save`, both constructed only inside the `#[cfg(feature =
"rich-tui")]` panel-outcome mapping. Under `--no-default-features` (the lean CI
firewall, #1409) the panel doesn't exist, so `Clear`/`Switch` and `save` are
never constructed → `-D dead-code` failed the `clippy (lean, no default
features)` job on PR #1492.
Why it slipped the local checks: the two lean *test* steps stayed green because
`cargo test` doesn't apply `-D warnings`; local clippy passed because
`--features newt-data/kernel` pulls newt-cli's default `rich-tui` in via feature
unification — the lean job strips it — and `--no-verify` skipped the local lean
gate. Reproduced with the exact CI command `cargo clippy -p newt-agent
--no-default-features --all-targets -- -D warnings`.
Rather than an `allow(dead_code)`, gate the whole panel path behind `rich-tui`
with a lean fallback, so no lint is suppressed and the lean tier is honestly
warning-clean. `active_backend_name` / `apply_persona_backend` have other lean
call sites, so there is no dead-code cascade.
What this PR does:
- `#[cfg(feature = "rich-tui")]` on `PsychePersonaAction`, `PsychePanelResult`,
`run_psyche_panel`, and `PersonaStore::save`.
- `/psyche edit` handler: rich-tui body + a `#[cfg(not(feature = "rich-tui"))]`
fallback pointing at the text `/psyche` + per-dial commands (same text the
launcher printed before).
- Behaviour unchanged in both configs (rich: identical; lean: same fallback).
Test plan:
- `cargo clippy -p newt-agent --no-default-features --all-targets -- -D warnings`
→ clean (this was the failing job).
- `cargo clippy --workspace --all-targets --features newt-data/kernel -- -D warnings`
(rich + live-spill + embedded) → clean; `-p newt-tui --features rich-tui
--all-targets` → clean; `cargo fmt --all -- --check` → clean.
- `cargo test -p newt-agent --no-default-features --no-run` → links; rich
`config_panel` unit tests pass.
Out of scope:
- The pre-existing local trybuild flake (#1496) and mcp_cli fixture leak (#1494).
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
|
Implementation update from OpenAI Codex (GPT-5), Codex desktop harness on Windows. Three focused commits are now on
All new HTTP tests use |
…ier is warning-clean
The R4 panel rework added `PsychePersonaAction {Keep, Clear, Switch}` and
`PersonaStore::save`, both constructed only inside the `#[cfg(feature =
"rich-tui")]` panel-outcome mapping. Under `--no-default-features` (the lean CI
firewall, #1409) the panel doesn't exist, so `Clear`/`Switch` and `save` are
never constructed → `-D dead-code` failed the `clippy (lean, no default
features)` job on PR #1492.
Why it slipped the local checks: the two lean *test* steps stayed green because
`cargo test` doesn't apply `-D warnings`; local clippy passed because
`--features newt-data/kernel` pulls newt-cli's default `rich-tui` in via feature
unification — the lean job strips it — and `--no-verify` skipped the local lean
gate. Reproduced with the exact CI command `cargo clippy -p newt-agent
--no-default-features --all-targets -- -D warnings`.
Rather than an `allow(dead_code)`, gate the whole panel path behind `rich-tui`
with a lean fallback, so no lint is suppressed and the lean tier is honestly
warning-clean. `active_backend_name` / `apply_persona_backend` have other lean
call sites, so there is no dead-code cascade.
What this PR does:
- `#[cfg(feature = "rich-tui")]` on `PsychePersonaAction`, `PsychePanelResult`,
`run_psyche_panel`, and `PersonaStore::save`.
- `/psyche edit` handler: rich-tui body + a `#[cfg(not(feature = "rich-tui"))]`
fallback pointing at the text `/psyche` + per-dial commands (same text the
launcher printed before).
- Behaviour unchanged in both configs (rich: identical; lean: same fallback).
Test plan:
- `cargo clippy -p newt-agent --no-default-features --all-targets -- -D warnings`
→ clean (this was the failing job).
- `cargo clippy --workspace --all-targets --features newt-data/kernel -- -D warnings`
(rich + live-spill + embedded) → clean; `-p newt-tui --features rich-tui
--all-targets` → clean; `cargo fmt --all -- --check` → clean.
- `cargo test -p newt-agent --no-default-features --no-run` → links; rich
`config_panel` unit tests pass.
Out of scope:
- The pre-existing local trybuild flake (#1496) and mcp_cli fixture leak (#1494).
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
|
Addressed the review findings in two commits after rebasing onto merged PR #1519:
Local acceptance is green: workspace build/test/clippy/fmt, 49 harness tests, and This remains draft. I did not run the vLLM |
|
Final remote verification: every GitHub check on |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 71bf419. Configure here.
| ): | ||
| required_labels.add(f"tasks/{task}/setup.sh") | ||
| for missing in sorted(required_labels - labels): | ||
| self.error(f"harness source manifest lacks required source {missing}") |
There was a problem hiding this comment.
Validator reads live setup.sh
Medium Severity
Qualification re-validation decides whether tasks/{task}/setup.sh must appear in harness-sources.json by calling is_file() on the manifest’s tasks_dir at validation time, not from the retained snapshot. A later-added setup.sh on disk can fail an otherwise valid historical bundle; a removed path can skip checks that the snapshot still recorded.
Reviewed by Cursor Bugbot for commit 71bf419. Configure here.
| @@ -0,0 +1,39 @@ | |||
| # Psyche × OCAP A/B matrix — ornith-1.0-35b-q8 | |||
|
|
|||
| Endpoint `http://192.168.0.103:8080` · each cell = pass-rate over the task set + avg tokens/wall per task. | |||
There was a problem hiding this comment.
Committed runs ignore gitignore
Low Severity
This change adds exploratory matrix CSV/Markdown under bench/psyche-ab-matrix/runs/ even though the harness .gitignore excludes runs/ and the README says run bundles must not be committed. The ornith sample also records a private LAN endpoint, which conflicts with the stated retention policy.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 71bf419. Configure here.
| | obsessive | off | write-greeting | pass | completed | 1 | 1 | 6133 | 3.2 | | ||
| | obsessive | on | edit-version | pass | completed | 2 | 1 | 7059 | 16.1 | | ||
| | obsessive | on | fix-typo | pass | completed | 2 | 1 | 6391 | 5.1 | | ||
| | obsessive | on | write-greeting | pass | completed | 1 | 1 | 6128 | 3.1 | |
There was a problem hiding this comment.
Exploratory run summaries committed
Medium Severity
This change adds exploratory matrix outputs under bench/psyche-ab-matrix/runs/ while also introducing a .gitignore that excludes runs/ and qualification-runs/. The README states those bundles should stay out of git. The ornith summary exposes a private LAN endpoint (192.168.0.103), and the CSV schema lacks the current events_file column, so these files read as run evidence but cannot pass today’s validator.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 71bf419. Configure here.
|
Before merge: The implementation and mocked protocol coverage are substantially stronger now, but I do not think this is ready to merge until we execute and review the live Nemotron qualification plan. Please treat the following as merge blockers:
The loopback preflight is valuable and should remain. It proves that Newt constructs the expected request and performs bounded continuation after a reasoning-only truncation. It does not prove that the inference server renders the correct Nemotron chat template, that the native reasoning and tool parsers reconstruct the response correctly, or that Nemotron can sustain a real multi-round terminal task. I am comfortable reviewing the implementation in its current state. I am not comfortable treating green mocked tests as live Nemotron qualification evidence or merging this as a completed performance fix until the live artifact bundles above are attached and reviewed. |
Split per review (Story A)This PR is now the draft Nemotron qualification framework. The production half — psyche dials, personas, runtime, reasoning replay, context budgeting, and the Blocker fixes landed here on Mechanics: Stays draft until the live plan runs: pinned vLLM C1–C10, the six-task multi-round pilot, the llama.cpp portability comparison, all four cognition postures, the failure taxonomy, the full Psyche×OCAP matrix, a paired digest-pinned tb-30, and regression checks for known-good non-Nemotron models. |
…nacity/crew/backend) A persona is already a saved collection of settings — role, tools, skills, caveats, model, tier, altitude — loaded from a `.md` (front-matter + soul body). This adds the "psyche" dimension: how hard the persona thinks and works. - New `Cognition` dial (glancing → pondering → deliberating → contemplating), mapping onto the OpenAI `reasoning.effort` wire value (minimal/low/medium/high). - New `RoleProfile` fields: `cognition`, `tenacity` (reuses the existing `newt_core::Tenacity` enum), `crew` (bool), and `backend` (names a `[[backends]]` entry a persona runs on, e.g. sol → gpt-5.6-sol). - Threaded through `FrontMatter` parse, `is_role_bound`, and the `/persona` status display. Declared-first, enforced-incrementally — exactly how `tools`/`model`/`tier` already ship (RoleProfile.tools: "enforcement is a follow-up"). The emit sites land next on this branch: `backend`→backend selection, `cognition`→the `reasoning.effort` wire. Ships two example personas: `bob.md` (a researcher on sol) and `obsessive.md` (the max-dials "ultra" preset). Not yet seeded into DEFAULT_PERSONAS — that waits until the dials are enforced, so no half-working default ships. Tests: role_profile unit tests (fully mocked) cover parsing the psyche front-matter, the cognition→reasoning-effort mapping, and that a lone dial makes a persona role-bound. 31 role_profile tests green; clippy -D warnings clean. Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
…nses in solve/worker
The headless TurnDriver path (`newt solve`, worker) drove every OpenAI backend
over /v1/chat/completions, so a responses-only model like gpt-5.6-sol 400s:
"Function tools with reasoning_effort are not supported … use /v1/responses".
Root cause: `agentic/driver.rs::run_one_turn` had its OWN openai dispatch
(`if kind==Openai { openai_chat_complete(...) }`) that bypassed the
responses-vs-chat branch in `chat_complete_with_prompt_and_artifacts`. The
interactive chat path already routed correctly (chat.rs calls
`apply_openai_api_env`); only the headless path missed it.
- `run_one_turn` now mirrors the interactive dispatch: `responses_api_selected()`
→ `openai_responses_complete`, else `openai_chat_complete`.
- `solve.rs` surfaces the backend's `api = "responses"` into `NEWT_OPENAI_API`
(via the now-`pub` `newt_tui::apply_openai_api_env`), exactly as the chat
path does — so a `[[backends]] api = "responses"` entry works headless with
no env fiddling.
Verified end-to-end on Windows: `newt solve --config <sol> …` against
gpt-5.6-sol now returns status=completed with a real reply (4214 tokens), where
it previously 400'd. driver + role_profile tests green; clippy -D warnings clean.
Follow-up (noted for review): the `apply_openai_api_env` writer arguably belongs
in newt_core next to its reader `responses_api_selected`, not in newt_tui.
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
… dispatch Follow-up to 960e55e (addresses review: avoid duplicate execution paths). That commit fixed the headless responses-routing bug by MIRRORING the openai-responses-vs-chat dispatch inside `run_one_turn` — but that left the same wire-format decision living in two places (`chat_complete_with_prompt_and_artifacts` AND the driver), exactly the sprawl that makes "did we fix the bug, or is there a second site?" unanswerable. Root the decision in one owner instead. `run_one_turn` no longer forks on `config.kind` — it just calls `chat_complete(ctx, &mut mcp)`, which already routes openai-vs-ollama and, for openai, responses-vs-chat. `openai_chat_complete` for the openai case with responses off is exactly what that entry resolves to, so this is behaviour-preserving *and* removes the pre-existing openai/ollama fork the driver carried. The wire-format dispatch now lives in exactly one function; the headless driver and the interactive TUI go through it identically. Net effect: three Cs — the routing knowledge (config: NEWT_OPENAI_API / `api="responses"`) drives one cohesive dispatcher, and the two call paths are loosely coupled to it rather than each re-deciding. Verified: `newt solve` → gpt-5.6-sol still status=completed via /v1/responses; driver tests 7/7; clippy -D warnings clean. Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
…ivalent tmux-drive assumed a Unix box: no tmux exists on native Windows (Git Bash) and WSL — the usual way to get one — needs a reboot. But the concept transfers: a TTY-only program needs a real pseudo-terminal, and Windows has ConPTY (exposed by pywinpty). This documents the Windows-native equivalent and ships a helper. - New `scripts/wdrive.py` — the Windows sibling of `tdrive.sh`: a `Tui` class that spawns a console program in a pseudoconsole and gives send / wait / screen / quit. Requirements are no-admin/no-reboot (pywinpty + Git Bash's bundled winpty). - New "Windows addendum" section in SKILL.md: the structural difference (a pseudoconsole is in-process, so you write a driver SCRIPT rather than one-subcommand-per-call — and there's no self-kill hazard), plus the two Windows gotchas: (1) cp1252 `print` crash on unicode → utf-8 stdout / PYTHONUTF8; (2) a pseudoconsole is a REAL tty, so isatty()-gated first-run work fires (for newt: the 468 MB on-host summarizer pull) → set the opt-out (NEWT_NO_MODEL_PULL=1). - Frontmatter: exec caveat gains `python`/`winpty`; version 2.0.0 -> 2.1.0. Verified on this Windows box: `wdrive.Tui` drives the real newt TUI end to end and asserts the psyche persona display (bob shows role/backend/cognition/ tenacity with crew hidden; obsessive shows crew on). Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
The cognition dial was declared on personas but inert. Route it to the
OpenAI Responses request through a single owner:
- ChatCtx gains `cognition: Option<Cognition>` (sibling of persona_tools).
- `responses_reasoning_field` is the one place that projects the level to the
`{"effort": ...}` wire shape; the value mapping stays in
Cognition::reasoning_effort. build_body emits it, omitting the field entirely
when unset (bit-for-bit unchanged for non-opt-in callers).
- The TUI resolves it from the active persona's `cognition:` front-matter,
co-located with persona_tools. Headless / eval callers pass None.
Chat-shape `reasoning_effort` emit is deferred on purpose: the chat path has
~7 request-body literals that must be consolidated to one owner first (called
out at the chat destructure) — scattering a field across all of them is the
exact sprawl the repo warns against.
Test plan: a wiremock test asserts reasoning.effort=high reaches the actual
/v1/responses body for cognition=contemplating, and that no reasoning field
is sent when unset; a pure unit test covers the level→effort mapping. clippy
--workspace --all-targets -D warnings and fmt --check clean.
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Completes the cognition knob: the operator sets reasoning depth live, mirroring /tenacity, without editing a persona file. - newt-core::cognition — the session-override module (CognitionOverride Unset/Off/Set + resolve_cognition), the cognition analogue of tenacity's override. A separate tiny module on purpose: the two psyche dials act in different places — tenacity steers the harness LOOP (read at decision points), cognition rides the wire REQUEST (resolved into ChatCtx.cognition, whose single emit owner is responses_reasoning_field). - Precedence, defined once in resolve_cognition: live /cognition override > the active persona's `cognition:` > None (no reasoning.effort). - Cognition gains FromStr / all / describe / Display for the command surface. - /cognition [level|off|auto|list] in commands/settings.rs, routed + helped in lib.rs next to /tenacity. `off` suppresses the field even under a persona; `auto` follows the persona (default). - chat.rs resolves ctx.cognition via resolve_cognition(persona). Test plan: newt-core module tests (unset→persona, set-wins-over-persona, off-forces-none) + a settings command test (status/list/set/off/auto/error). clippy --workspace --all-targets -D warnings + fmt --check clean. Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Adds the read-only psyche panel: cognition, tenacity, and crew in one view, each with how to change it. Reads the live session state — the cognition + tenacity process-globals and the crew NEWT_TEAM startup gate (the same gate newt-cli reads to build the crew runner) — so it reports what is actually in effect, not what a persona merely declares (that stays /persona's job). The three dials are kept factored on purpose: cognition rides the wire request, tenacity steers the harness loop, crew sets how many minds — the panel names "obsessive" as the max-everything posture (contemplating + relentless + crew on) without yet wiring the macro (a follow-up, gated on the crew-is-startup design). Routed + helped in lib.rs next to /cognition and /tenacity; a test asserts the panel names all three dials and points at how to change each. Plain-scroller, per docs/decisions/plain_scroller_tui.md — a text panel, not widgets/sliders (those live in gilamonster-agent). Test plan: settings command test (panel names cognition/tenacity/crew/obsessive and the /cognition, /tenacity pointers). clippy --workspace --all-targets -D warnings + fmt --check clean. Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
…rsona state + ex-cmd validation Reworks the #14 config panel (`/psyche edit`) to close the review-2 merge bar. The panel is now handed the EFFECTIVE resolved posture and the active persona, so it displays and saves the real values instead of the raw override. What this PR does: - review-2 #1: SAVE serializes the EFFECTIVE cognition/tenacity (`cognition_for_save` / `tenacity_for_save`) — a persona saved while the dial reads `auto` reproduces the resolved level (e.g. bob's `contemplating`), not an empty field. - review-2 #2: cognition/tenacity dials gain a real `auto`/`inherit` ladder position that CLEARS the override on apply (cognition → `Unset`, tenacity → `clear_cli_tenacity`), so a value can return to persona/config resolution. Rendered as `auto → <effective>`. - review-2 #4: the persona row shows the active persona with an `(active)` marker and maps `none` → Clear via a `PersonaAction {Keep, Clear, Switch}`; the session loop applies it (`persona clear` / `persona set … --keep-context` + backend re-route). - review-2 #5: ex-commands validate with a VISIBLE magenta status line — unknown verb, missing name (`:w`), and existing-persona-without-bang (`:w!`/`:wq!` to overwrite) each report why, instead of failing silently. - review-2 #3: the module doc labels this an INTERIM SURFACE — its ex-command reader does not yet reuse newt's shared vi/emacs editor core; unifying them is tracked as a follow-up. - `run_psyche_panel` (lib.rs) + the `/psyche edit` branch (chat.rs) pass the effective snapshot in and act on the returned `PsychePersonaAction`. Test plan: - 5 pure `PanelState` unit tests under `GlobalSettingsGuard` (untouched dials not written, `auto` clears the override, save serializes effective, active marker + none→Clear, ex-commands validate visibly). - v4 TUI-drive (`config_panel_drive.py`, pywinpty ConPTY): 9/9 — hint, auto/inherit labels, visible unknown/missing-name validation, `:w` writes a persona file + status, `(active)` marker, `none` clears the active persona. - `cargo clippy -p newt-tui --features rich-tui --all-targets -- -D warnings` and the CI Windows leg `cargo clippy --workspace --all-targets --features newt-data/kernel -- -D warnings` both clean; `cargo fmt --all -- --check` clean. Out of scope: - Reusing the shared vi/emacs semantic-command layer in the panel (tracked follow-up; the panel is explicitly labeled interim until then). Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
…issue (#1495) The vi/emacs editor-core reuse follow-up (review-2 #3) now has a home; link it from the module doc so the INTERIM SURFACE label is actionable. Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
…ier is warning-clean
The R4 panel rework added `PsychePersonaAction {Keep, Clear, Switch}` and
`PersonaStore::save`, both constructed only inside the `#[cfg(feature =
"rich-tui")]` panel-outcome mapping. Under `--no-default-features` (the lean CI
firewall, #1409) the panel doesn't exist, so `Clear`/`Switch` and `save` are
never constructed → `-D dead-code` failed the `clippy (lean, no default
features)` job on PR #1492.
Why it slipped the local checks: the two lean *test* steps stayed green because
`cargo test` doesn't apply `-D warnings`; local clippy passed because
`--features newt-data/kernel` pulls newt-cli's default `rich-tui` in via feature
unification — the lean job strips it — and `--no-verify` skipped the local lean
gate. Reproduced with the exact CI command `cargo clippy -p newt-agent
--no-default-features --all-targets -- -D warnings`.
Rather than an `allow(dead_code)`, gate the whole panel path behind `rich-tui`
with a lean fallback, so no lint is suppressed and the lean tier is honestly
warning-clean. `active_backend_name` / `apply_persona_backend` have other lean
call sites, so there is no dead-code cascade.
What this PR does:
- `#[cfg(feature = "rich-tui")]` on `PsychePersonaAction`, `PsychePanelResult`,
`run_psyche_panel`, and `PersonaStore::save`.
- `/psyche edit` handler: rich-tui body + a `#[cfg(not(feature = "rich-tui"))]`
fallback pointing at the text `/psyche` + per-dial commands (same text the
launcher printed before).
- Behaviour unchanged in both configs (rich: identical; lean: same fallback).
Test plan:
- `cargo clippy -p newt-agent --no-default-features --all-targets -- -D warnings`
→ clean (this was the failing job).
- `cargo clippy --workspace --all-targets --features newt-data/kernel -- -D warnings`
(rich + live-spill + embedded) → clean; `-p newt-tui --features rich-tui
--all-targets` → clean; `cargo fmt --all -- --check` → clean.
- `cargo test -p newt-agent --no-default-features --no-run` → links; rich
`config_panel` unit tests pass.
Out of scope:
- The pre-existing local trybuild flake (#1496) and mcp_cli fixture leak (#1494).
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
…st projection, complete test isolation Addresses the review-3 change request (transaction semantics + TUI state integrity) on the #14 psyche config panel. What this PR does: - §1 TRANSACTION. Save is I/O-injected: `config_panel::run` takes a `persist` closure (the caller owns the `PersonaStore`), so the file write happens INSIDE the event loop and can keep the panel open on failure. `:wq` order is validate → persist → apply cognition/tenacity → (caller) apply persona + reroute → (caller) recompute + report. A failed persist returns `None` from the command, so the loop never breaks and `PanelState::apply` never runs — no dial, persona, or backend change. `PersonaStore::save` now writes atomically (temp file in the destination dir + rename) and refuses an existing persona without `!`; a failed or partial write never truncates the original. New `SaveResult` {Saved,Exists,InvalidName,Failed}; "saved persona" is shown only after the write lands. - §2 EXPLICIT OUTCOME. `PanelOutcome` {Cancelled, Applied, Saved, SavedAndApplied} distinguishes cancellation from application — the panel returns NO summary string. On cancel the caller prints "psyche edit cancelled" (never a posture summary from the abandoned working copy); after an apply it builds the summary from freshly-resolved `effective_cognition()` / `effective_tenacity()` after the persona + backend commit. - §3 HONEST PROJECTION. The panel receives each persona's declarations (`PersonaChoice`) plus the config/family tenacity base; selecting a persona recomputes the projected effective cognition/tenacity/backend/crew from THAT persona and labels provenance (override vs `persona: <name>` vs base/current). The active persona shows "(active)", a different selection "(pending)". Save serializes exactly the projected posture. - §4 TEST ISOLATION. New `tenacity::{snapshot,restore}_runtime_state` + `TenacityRuntimeSnapshot` cover ALL FOUR tenacity globals — CLI, persona, `TENACITY_CONFIG`, `ACTIVE_FAMILY` (the last two were the audited gap: mutated by `Config::resolve` and the solve model-selection path, never restored). A symmetric `cognition::{snapshot,restore}_runtime_state` covers the two cognition globals. `GlobalSettingsGuard` now composes these two snapshots instead of reaching into each global piecemeal; its doc records the full audit. New `tenacity::{tenacity_config,active_model_family,base_tenacity}` accessors. - §5 #1495 (shared vi/emacs input) stays visible: milestoned v0.8.0, linked from the panel doc; no new panel-specific key parsing was added, and the injected `persist` seam + structured outcome port cleanly onto the shared editor. Test plan: - newt-core lib: 1891 passed (incl. snapshot round-trip of all 4 tenacity globals, base_tenacity, and Drop-restores-on-panic). - newt-tui lib (rich-tui): 681 passed (transaction: :wq success/fail-rollback, :w-then-cancel = Saved-not-applied, exists-without-bang; projection follows the selected persona / base; atomic save + overwrite-failure-preserves-original; ex-command validation). - TUI-drive (`config_panel_drive.py`, real ConPTY): 10/10 — provider row + provenance render, visible validation, `:w` persists a file, CANCEL prints "psyche edit cancelled", APPLY prints a fresh posture summary, active/pending + projected values. - `cargo fmt --all -- --check` clean; `cargo clippy --workspace --all-targets --features newt-data/kernel -- -D warnings` and `cargo clippy -p newt-agent --no-default-features --all-targets -- -D warnings` both clean. Out of scope: - The shared vi/emacs input consolidation (#1495, milestoned v0.8.0). - Pre-existing Windows-local flakes: mcp_cli fixture leak (#1494) and the trybuild snapshot drift (#1496) — both CI-green on Linux, untouched here. - `cargo clippy --all-features` is not buildable on Windows (macOS/CUDA deps). Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Three review findings (all §2/§3 truthfulness, none blocking) from the transaction review: - Active persona absent from the projected list (e.g. its file failed to load) no longer maps Enter to a silent Clear: PanelState::new appends the active persona if missing, so it renders "(active)" and Enter = Keep. - The saved-persona confirmation now echoes the store's NORMALIZED on-disk name (from the returned path stem), not the raw typed name — `:wq MyPersona` reports `saved persona 'mypersona'`, matching the file. - The backend projection fallback for a persona that declares no backend is now the operator BASELINE (`base_provider` — what apply_persona_backend reverts to), not the outgoing persona's current backend; provenance labels it "base". Test plan: - New unit tests: active-persona-absent → Keep; no-backend persona projects the baseline; save returns the normalized on-disk name. config_panel 13 + persona 40 pass; TUI-drive 10/10; clippy (newt-data/kernel + lean) + fmt clean. Out of scope: unchanged from the parent commit. Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Co-authored-by: hartsock <[email protected]> Co-authored-by: Codex <[email protected]>
A reproducible bench that measures how the psyche dials + the OCAP lane affect a
headless `newt solve`, on ornith-1.0-35b-q8 (dgx1). Built to run unattended on
gnuc (or any host that can reach dgx1) — no ~/.newt or host-specific paths.
What this adds (bench/psyche-ab-matrix/):
- run-matrix.sh — sweeps {baseline, tenacity, crew, obsessive} × {OCAP off,on}
over a task set, driving `newt solve` per cell; collects verify pass/fail +
status/tool_calls/write_calls/tokens/wall; renders matrix.md + results.csv.
Postures/OCAP are set purely via global flags + env (--tenacity/--obsessive,
NEWT_TEAM=1, NEWT_BENCH_OCAP=on, --non-interactive true). Endpoint/model/tasks
are env-overridable; a /v1/models 200 pre-check fails fast on a dead backend;
python3→python fallback for cross-box portability.
- tasks/ — 3 small self-verifying tasks (write-greeting, edit-version, fix-typo),
each instruction.txt + setup.sh + verify.sh.
- README.md — the reproduction recipe (endpoints: Tailscale 100.113.207.102:8080
or LAN dgx1.home.lan:8080; how gnuc runs it).
Pre-flight validated on NUC01 against real ornith on dgx1: hello + find/edit both
work end-to-end, and baseline × off × 3 tasks = 3/3 verify pass (tool loop drives
real edits; ~6–8k tokens/turn — ornith is a heavy reasoner, budgets sized for it).
Note: ornith is a chat_completions backend, so the cognition dial (reasoning.effort,
Responses-only) is inert here — the axes that move ornith are tenacity + crew; the
matrix records all four postures so that null result is measured, not assumed.
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
…r delegate (#1320 PR-3) Extracts the config-based backend precedence into one place — `Config:: select_configured_backend` (NEWT_PROVIDER > default_backend > sole > prefer-OpenAI, else first usable) — and routes `solve::pick_backend` and the ACP worker's `select_openai_backend` through it, so chat, solve, and the worker agree on which configured backend the operator named. Retires solve's + the worker's divergent pickers (the worker keeps its OpenAI-kind requirement for the vLLM path, layered over the shared pick). The env-synthesized fallbacks (codex, legacy dgx, localhost) stay in chat's `resolve_backend_choice`, around this. Test plan: pick_backend tests 4/4 (default_backend precedence preserved); worker compiles; fmt clean. Behavior-preserving for solve (adds the sole/prefer-OpenAI rungs that match chat); the worker now honors NEWT_PROVIDER/default_backend when they name an OpenAI backend. Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
…g (sol) The matrix runner now drives any backend via MODEL_ENDPOINT / MODEL_ID / MODEL_API / MODEL_KEY_FILE / BACKEND_NAME (ORNITH_* kept as aliases), so the same sweep runs the ornith leg (chat_completions, dgx1) AND a sol leg (api=responses, gpt-5.6-sol, keyed) — the only backend where the cognition dial wires through. Auth-gated endpoints skip the unauthenticated reachability probe. README documents both legs + the env table. Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
#1139) PR-4 of the #1320 psyche-config chain, landing on feat/psyche. ## What this PR does - Add newt-core `RuntimeSettingsSnapshot` — the single resolved read model of the operator posture (cognition, tenacity, crew, active persona, and a layered `BackendState { configured, operator, persona, effective, model }`), resolved ONCE from the process globals + `Config` via `RuntimeSettingsSnapshot::resolve`. It REUSES the existing resolvers (`effective_cognition`, `effective_tenacity`, `Config::select_configured_backend`) rather than re-deriving them. Its `summary()` is now the single source for the chat `/psyche edit` apply line, which previously re-derived each dial inline. - Fix the ACTIVE_FAMILY-in-chat gap: interactive chat never called `set_active_model_family`, so per-family `[tenacity.families]` defaults silently never applied there (only `solve` attributed a family). Add `tenacity::attribute_active_family(config, model)` and call it (a) at chat startup for the base model and (b) inside `refresh_backend` — the single seam every mid-session model change (`/backends`, `/model`, persona routing via `apply_persona_backend`) flows through — so the family tracks a live backend/persona switch instead of going stale on the startup model. ## Test plan - `cargo test --workspace --features newt-data/kernel` — green. - New unit tests (fully mocked, GlobalSettingsGuard-isolated): - runtime.rs: `resolve_reads_effective_dials_and_the_selected_backend`, `operator_pin_and_crew_gate_are_reflected`. - tenacity.rs: `attribute_active_family_installs_card_then_substring_then_clears` (card-family / name-substring / clear-on-no-match paths). - `cargo clippy --workspace --all-targets --features newt-data/kernel -- -D warnings` — clean. - `cargo fmt --all -- --check` — clean. ## Out of scope - Threading one snapshot through dispatch / moving `BackendChoice` into core (the end-to-end #1139 ownership step) — tracked separately; runtime.rs is the read-model seam it grows from. Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
…; +x on runner/task scripts Both legs of the psyche×OCAP A/B matrix (stamp 20260731-194124, newt 0.7.6 @4782bf7): 24/24 cells pass per leg, OCAP on≈off in every posture (parity clean). NOTE for review: sol per-posture token usage is byte-flat (±5 tok across 24 cells) — consistent with the P1 'dials display-only / cognition dropped on the wire' findings; needs a wire-level request dump to adjudicate. Exec bits restored on run-matrix.sh + task scripts (lost via Windows checkout; verify.sh silently skipped without them). Co-authored-by: Fable 5 <[email protected]>
The runs/ dir is ignored for workspaces/traces; these four small files are the durable evidence (matrix.md grid + results.csv per leg) the board card cites. Co-authored-by: Fable 5 <[email protected]>
Preserve split and inline assistant reasoning across tool rounds only when an endpoint explicitly opts into the current-user-turn replay contract. Keep unknown endpoints conservative and propagate the capability through TUI and headless solve paths. Co-authored-by: Codex <[email protected]>
Co-authored-by: Codex <[email protected]>
Co-authored-by: Codex <[email protected]>
Co-authored-by: Codex <[email protected]>
Co-authored-by: Codex <[email protected]>
Co-authored-by: Codex <[email protected]>
Co-authored-by: Codex <[email protected]>
Compose input ceilings with generation reserves, persist learned hard windows, and apply resolved runtime configuration consistently across interactive and explicit-profile solves. Record the cognition, tenacity, and crew posture actually used by the turn. Co-authored-by: Codex <[email protected]>
Activate the declared Chat Completions capability profile, validate captured request bodies, retain immutable runtime and workspace provenance, and reject incomplete or mismatched qualification cells after collecting the full matrix. Co-authored-by: Codex <[email protected]>
…nvalidatable) `bench/psyche-ab-matrix/runs/` is `.gitignore`d yet these four files were tracked. `runs/20260731-194124-ornith/matrix.md` exposes `http://192.168.0.103:8080` — the dgx1 private-LAN endpoint, which RATCHET.md forbids from any commit. The CSVs also predate the current qualification schema, so they read as evidence while being impossible to validate with the current validator. Nothing references them. Removed rather than kept. Sanitized synthetic fixtures (against the current schema, marked non-evidence) will be added under `bench/psyche-ab-matrix/tests/fixtures/` if/when the validator tests need sample data. NOTE: the IP remains in branch history; a history rewrite is inadvisable here because feat/psyche is already the base of PR #1520 (step-28.1) — rewriting it would break that stacked branch. Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
…endently verified The review is right that the vLLM lane's independent probes prove declaration *consistency* (model name in /v1/models + server /version), not process *identity* — the weight digest, context window, chat template, tool parser, and reasoning parser all come from an operator-supplied launch manifest, and the identity gate only proves that manifest is self-consistent. A stale/pre-existing server matching the display name + version passes without any attacker. The caveats were already in the README; this adds a prominent headline banner so the top-level framing matches them: bundles are the operator's declaration checked for internal consistency, NOT independently-verified qualification. Full process-identity binding (harness-owned lifecycle or nonce-bound launch attestation) is future work. (The llama.cpp lane is stronger — it independently reads build_info/n_ctx/chat-template-hash from /props.) Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
The ACP worker constructed `LocalVllmBackend::from_config` for every OpenAI backend and that adapter always posts to `/v1/chat/completions`, discarding `BackendConfig.api`. So `newt worker` drove a Responses-only model (e.g. gpt-5.6-sol, `api = "responses"`) over Chat Completions — recreating the exact 400-on-function-tools failure this line claims to fix. `newt solve` was already correct because it reaches the Responses wire through the agentic loop; the worker consumes the `InferenceBackend` seam directly and had no api-aware path. Add `ResponsesBackend` (POST `/v1/responses`, `instructions` + `input`, parses `output[].content[].output_text` with an `output_text` fallback, `input/output` token usage) and a single `openai_inference_backend(cfg)` factory that selects the transport from `cfg.api` with an EXHAUSTIVE match (a new `OpenAiApi` variant must be handled, not silently defaulted). The ACP worker's OpenAI branch now routes through the factory, so both the flat and coder ACP paths obey the wire API. The seam carries the simple completion shape (messages → text); multi-turn function-calling stays in the agentic loop. Wire tests (wiremock): a responses config posts to `/v1/responses` and never to `/v1/chat/completions` (`.expect(0)`), output-text extraction + usage parse, and the factory selects Responses vs Chat Completions (and the unset default) by api. Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
A dirty checkout made the bundle irreproducible: `commit` + the candidate binary hash pinned something git could not reconstruct, and qualification mode accepted it anyway (the validator only checked `harness.dirty` was a bool). Qualification now fails closed on a dirty tree BEFORE any inference. An explicit `ALLOW_DIRTY_QUALIFICATION=1` override still runs, but retains `source-dirty.patch` (`git diff --binary HEAD`) and `source-dirty-status.txt` (untracked listing) in the bundle so the run stays reproducible/inspectable. A `FAKE_SOURCE_DIRTY` test hook (consistent with the runner's existing `FAKE_EFFECTIVE_MODEL` / `FAKE_TIMEOUT_LOG`) drives the gate deterministically without mutating the real repo. The existing fixture tests opt into the override (they exercise the run + dirty-recording paths, and the dev/CI checkout may be dirty). New tests: dirty + no override → non-zero exit with "clean source tree" and no results produced; dirty + override → runs and retains the diff. Follow-up (not this commit): retaining Cargo.lock, toolchain identity, and the exact candidate binary on override — tracked separately. Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
… (B2) Historical bundle validation was time-dependent: the validator decided whether `tasks/<task>/setup.sh` was a required source by `stat`-ing the LIVE external task tree (`(Path(tasks_dir)/task/"setup.sh").is_file()`). So adding a setup.sh later made an old bundle invalid, removing one made a required-source check vanish, and moving/deleting the checkout changed the verdict — contradicting the "validates against a pinned snapshot" claim. The bundle already retains the task sources (harness-sources snapshot). The only non-hermetic bit was which tasks REQUIRED a setup.sh. Pin that as a fact at run time — `manifest.matrix.tasks_with_setup` (computed once from the task tree while the runner is producing the bundle) — and have the validator derive the required set from that pinned fact + the retained source manifest, never the live tree. The field is schema-checked (a list, subset of matrix.tasks). Regression test (discriminating): a produced bundle validates identically after (a) a setup.sh is ADDED to the live tree post-run — the exact mutation the old `is_file()` check reacted to — and (b) the original task tree is deleted entirely. Validator fixtures pin the fact; the setup-source test now asserts the hermetic contract (pinned-present ⇒ retained-source-required). Note: proof paths remain host-absolute but self-consistent (derived from the recorded tasks_dir via strict=False resolve, no fs access). Switching them to bundle-relative logical paths is a larger follow-up, tracked separately. Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
…e-production feat(psyche): agent psyche dials + personas + api=responses transport (production split of #1492)


What this PR does
Introduces the agent psyche: orthogonal controls for how much inference work is requested, how hard the harness pushes toward action, and whether a crew participates.
cognitiondial (glancing,pondering,deliberating,contemplating) and threads it through personas, TUI, and headless turns. OpenAI Responses maps it toreasoning.effort; explicitly capable Chat Completions endpoints map it to a backend-neutral generation policy. Unknown endpoints receive no new request fields.tenacityandcrewthrough persona configuration and adds/cognition,/psyche, and the obsessive posture.context_window - max_output_tokens.input_ceiling_pctto1..=99, applies the same effective ceiling to preflight, compaction, context reporting, accepted-cap learning, and 400 recovery, and persists learned hard windows without permitting later raises.--configsolves. Nemotron family tenacity and CLI backend overrides now reach actual runtime behavior and contract output.bench/psyche-ab-matrix/run-matrix.shcapability-aware and fail-closed: it validates two captured preflight requests, retains immutable candidate/server/model/template/parser/workspace provenance, collects every cell, and exits nonzero for incomplete, mismatched, failed, or unverifiable qualification evidence.The branch is rebased onto main after merged PR #1519 (
ad7a69d).Test plan
Local acceptance at
71bf419:cargo build --workspacecargo test --workspacecargo clippy --workspace --all-targets -- -D warningscargo fmt --all -- --checkjust cov-ci— 87.44% line coverage, 80% floorpython3 -B -m unittest discover -q -s bench/psyche-ab-matrix/tests -p "test_*.py"— 49 passedbash -n bench/psyche-ab-matrix/run-matrix.shshellcheck bench/psyche-ab-matrix/run-matrix.shThe Rust regression coverage includes all four cognition levels at 32K and 65K, zero and invalid percentages, percentage/output-reserve composition, numbered and numberless 400 recovery, persisted hard-window behavior, explicit-profile Nemotron family tenacity, explicit-profile CLI backend precedence, conservative unknown Chat cognition, and model-issued crew execution.
The harness tests exercise capability projection, first-request capture, strict tool schemas, same-turn reasoning replay, provenance cross-binding, Git workspace baselines, symlink and path-escape rejection, mode-downgrade rejection, timeouts, missing artifacts, model mismatch, and aggregate fail-closed behavior.
Nemotron qualification status
qwen3_coder+nano_v3reference laneThe live reference lane still requires a pinned model digest, native
qwen3_codertool parser,nano_v3reasoning parser, declared context window, large output allowance, server/version identity, template/parser identity, and retained raw evidence.Out of scope
Co-authored-by: Claude Opus 4.8 (1M context) [email protected]
Co-authored-by: Codex [email protected]
Note
Medium Risk
Large new qualification tooling with strict validation and subprocess/network probes; risk is operational (misconfigured runs, sensitive bundles) rather than production runtime changes. Committed exploratory
runs/artifacts are low sensitivity but add repo noise.Overview
Adds
bench/psyche-ab-matrix, a fail-closed Psyche × OCAP qualification runner for Nemotron (vLLM reference + llama.cpp portability):run-matrix.shdrives the full 4×2 posture/OCAP grid, renders Nemotron capability TOML, probes server identity, runs loopback two-request cognition preflight, hashes harness/Newt sources, records per-cell Git/justbaselines, and only passes aftervalidate-run.pychecks contracts, provenance, and artifacts. Supporting pieces includequalification_harness.py,loopback-preflight.py, three self-verifying tasks, extensive offline tests, README, and gitignore for sensitive run bundles; sample exploratoryruns/CSV/Markdown snapshots are included.tmux-drive bumps to 2.1.0 with a Windows addendum and new
scripts/wdrive.py(Tuiover ConPTY/pywinpty) for in-process TUI automation, plus skill exec allowlist updates forpythonandwinpty.Reviewed by Cursor Bugbot for commit 71bf419. Configure here.