Skip to content
This repository was archived by the owner on Sep 17, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .design-sync/NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ grep -o -- '--color-warning[a-z-]*:' .design-sync/.cache/compiled.css | sort -u
- **`cfg.dtsPropsFor` is hand-maintained and nothing verifies it against the source.** It
is the highest-value thing in the config (see the section above) and the easiest to let
rot — a prop renamed in `src/` leaves the design agent coding against the old name.
- **`__APP_VERSION__` in `ds-entry.tsx` is a hardcoded `"6.3.0"`.** Cosmetic (it only feeds
- **`__APP_VERSION__` in `ds-entry.tsx` is a hardcoded `"6.4.0"`.** Cosmetic (it only feeds
the sidebar footer), but bump it when the app's major/minor moves, or accept the drift.
- **`src/assets/logo_eddi.png` must stay importable.** Moving it back under `public/`
silently reintroduces a broken image in every design using the expanded `Sidebar`.
Expand Down
2 changes: 1 addition & 1 deletion .design-sync/ds-entry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// component untouched. The value is cosmetic chrome; it is a static string and
// will drift from package.json (recorded in NOTES.md's re-sync risks).
(globalThis as unknown as { __APP_VERSION__?: string }).__APP_VERSION__ ??=
"6.3.0";
"6.4.0";

// ── ui/ ────────────────────────────────────────────────────────────────────
export { AccessibleDialog } from "@/components/ui/accessible-dialog";
Expand Down
8 changes: 7 additions & 1 deletion HANDOFF.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# EDDI Manager Project Handoff

## Current Status (v6.3.0, plus the post-6.3.0 EDDI alignment in #197-#203)
## Current Status (v6.4.0, plus the post-6.3.0 EDDI alignment in #197-#203)

### How a linked account is actually consumed (traced end to end, after getting it wrong once)

Expand Down Expand Up @@ -69,6 +69,11 @@ when the agent makes an outbound call; chat attachments are uploads via
enumerate a user's remote content, so a picker would need a new backend surface.

### Completed Phases
- **An approval diff you can read when the proposed body is not JSON** (branch: `fix/approval-diff-invalid-json`), plus the Manager version to **6.4.0**. Reported from a live pause: the operator's `updateLlm` call proposed an LLM config with one closing brace too many (`…60000}}]}`). It parsed on neither side of the approval, so the stored document was pretty-printed and key-sorted while the proposed one stayed a single raw line — every stored line red, one green line, nothing comparable. **6511 passing (411 files)**; each review fix below was mutation-checked (reverting it fails a named test).
- **The broken side is re-indented, never repaired** (`src/lib/reindent-json.ts`). Whitespace outside strings is the only thing it touches, so a stray bracket stays visible as its own line. Text that does not open with `{`/`[` is compared as written. Against a broken side the diff ignores indentation — its nesting is wrong from the first stray closer on, and comparing indentation reported every later line as changed — and prints the parsed side in the broken side's key order (`jsonKeyOrder`), since alphabetical sorting of one side only turned moved keys into changes.
- **What changed, and what did not.** Paired changed lines mark the words that differ (`<ins>`/`<del>`, with a per-pair timeout and a render budget — two long dissimilar lines cost over a second each), and the sticky legend reads "Lines: N added · N removed · N unchanged".
- **Two failure modes, two warnings.** A body broken *inside* the document is rejected by EDDI. A complete document followed by more text is not: Jackson's default reader stops at the end of the first value, and EDDI's `StrictConfigurationParser` only adds `FAIL_ON_UNKNOWN_PROPERTIES`, so the write can succeed with the tail silently dropped. `parseLeadingJson` tells them apart; the approval preview says which, hedges when redaction markers are present, and hides the viewer's own caveat so the warning is not repeated.
- **A trailing brace was a way past the capability scan.** `detectEscalationFlags` skipped any body that failed to parse, so appending `}` to a group create hid `dynamicAgents.allowCreation` while EDDI would still store it. It now scans the leading document.
- **Connections review findings** (branch: `fix/connections-review-findings`): a second review of the connections feature against the backend's current contract and the fixes landing in parallel there. Seven items, one commit each; **6188 passing (388 files)**, +101 tests and 3 files against the 6158 recorded below. The full run on this machine shows **60 failures in 8 files that are not this branch's** — `updates.test.ts`, `update-check-card`, `update-banner`, the operator canaries and page, `use-platform-status`, `use-send-message-409-rollback` — every one a raw `fetch` (external host, `credentials: "omit"` + `signal`, or an SSE stream) that MSW did not intercept here, so the request hit a network that is not there. The same 10 `updates.test.ts` failures reproduce at the base commit `184fde17` in the same worktree; CI, where these pass, is the source of truth for them.
- **`CALLER_SUPPLIED` is the third binding, and the Manager now knows it.** `binding` was derived from the auth type alone, so a caller-supplied document loaded into the editor was saved back as `SERVICE` on the first unrelated edit — with an empty `valueTemplate` the backend refuses on that binding. `bindingFor(authType, requested)` honours a requested binding where the type allows it (STATIC has two legal values; every other type exactly one), `legalBindings` names the pairs, and a loaded document keeps its stored binding. The STATIC form offers the choice as a two-way radio group with the doc's reasoning — authority, not convenience: an agent holding one shared key can reach everything that key can — and, for caller-supplied, replaces the header-value field with the exact `X-EDDI-Connection-Credential: <name> <value>` line the integrator must send. The wizard now builds its document through `toStoredConnection` like the editor, so a template typed before switching the binding is not sent. The badge has a third look; the MSW fixture (`conn6`, gnowbe) carries the shape.
- **The mirror carries the backend's newer write rules**: the name grammar `^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$`, `timeoutMs` in 1..60000 (null is the default), the literal-segment rule on `valueTemplate` (a literal half over 32 characters or with a run of 12+ from the credential alphabet — `Bearer ${vault:k}` passes, `sk-live-abcdef${vault:x}` does not; checked on the literal halves only, so a long vault key *name* never trips it), and `extraAuthParams` value rules (no `${`, ≤ 512 characters, not one long token-alphabet run) plus reserved OAuth names refused stripped of case and separators. The `code_verifier` note above is corrected: the backend fixed its denylist spelling, so normalising both sides is now the same rule. The backend's own 400 still reaches the toast verbatim, and a test pins it.
Expand Down Expand Up @@ -455,6 +460,7 @@ enumerate a user's remote content, so a picker would need a new backend surface.
- 112 Backend tenancy tests passing (`mvn test`)

### Last Commit Focus
- Frontend: the approval diff against a non-JSON body, and 6.4.0 (above). Worth carrying forward: **"not JSON" is two different outcomes on the backend.** Check what EDDI's reader actually does with a malformed body before writing a warning about it — here the obvious sentence ("EDDI will reject this") was wrong for the case that matters most, the one where the write goes through.
- Frontend: the post-6.3.0 EDDI alignment above (#197-#203). Three things worth carrying forward:
- **A passing test hid several of these bugs.** The GDPR counter typo survived because its test asserted the label and not the value; the MSW fixture had been written to match the page rather than the server. When a fixture and a client agree, neither is evidence. Fixtures here now describe what EDDI actually sends, including an export that answers 207.
- **Dead API surface is a defect, not spare capacity.** The first cut of #197 shipped a `headerCount` helper, a `postWithResponse` method and a header accessor with no callers anywhere — the same fault the same set of PRs was fixing in `transferOwnership`. All three were cut before merge; `ApiResponse` carries the status and nothing else. Add the accessor with its consumer, not before it.
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "eddi-manager",
"private": true,
"version": "6.3.0",
"version": "6.4.0",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
Loading
Loading