Commit Graph

5 Commits

Author SHA1 Message Date
Duncan
b91d17e9e4 fix(desktop): Phase 1 round-5 — make FIELD_OWNERS load-bearing, revert mobile lockfile
Add fieldOwner(field, ctx) exported from agentFormModel.ts. It reads from
FIELD_OWNERS for the base owner and handles two sets of context-dependent
overrides: (1) rows-9-10 dual-owner fields (respondTo, respondToAllowlist,
parallelism) are D-owned in definition-only context and I-owned otherwise;
(2) definition-fallback fields (systemPrompt, model, provider) are D-owned
when a definition is present and I-owned in instance-only context.

Wire fieldOwner into emitAgentFormDiff via isD/isI helpers. Every field
routing decision now consults fieldOwner(field, ctx) rather than hardcoded
hasInst/def===null conditionals — making FIELD_OWNERS the single
authoritative routing source as the JSDoc claims.

Add 8 new tests to agentFormModel.test.mjs: fieldOwner context resolution
for respondTo/parallelism/systemPrompt/model/provider, delegation to
FIELD_OWNERS for static fields, and end-to-end emit routing via fieldOwner.
4568/4568 pass.

Revert mobile/pubspec.lock to origin/main (boundary violation from round-4
commit — lockfile churn is pre-existing local dirt, not in scope).

Clean up stale AgentInstanceEditDialog references in AGENTS.md,
agentConfigOptions.tsx, agentConfigControls.tsx, AgentRunLocationContext.tsx,
AgentCreationPreview.tsx, AgentDefinitionDialog.tsx.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
2026-08-08 18:12:58 -04:00
Duncan
04c4c426e6 fix(desktop): Phase 1 round-4 — close all Paul round-3 gate defects
Wire onDeleteDefinition/onRemoveFromMyAgents/onShare/isIdentityArchived/
linkedInstanceCount through AgentEditDialog to all three callers
(UserProfilePanel, AgentsView, AgentManagementDialogs).

Add onShare to AgentEditMergedDialogProps and render Share action in
the definition admin section. Fix mislabeled comment above Delete button.

Add R6 respondTo regression tests covering definition-only context
seed and emit through coordinator.

Export FIELD_OWNERS constant as load-bearing source-of-truth map
annotating every AgentFormModel field with its FieldOwner.

Delete AgentInstanceEditDialog.tsx and agentInstanceEditPinning.test.mjs
(zero production consumers). Remove definitionReadOnly prop from
AgentDefinitionDialog.tsx.

Update agentDialogRouting.test.mjs: remove AgentInstanceEditDialog import;
replace is-NOT-reachable test with positive assertion that
AgentEditMergedDialog appears in all R1-R7 contexts.

Add two e2e tests: team-linked instance D-fields disabled + team-notice
names the team; linked agent one-Save persists both D and I layers.

4560/4560 desktop tests pass. TypeScript clean. Biome clean.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
2026-08-08 17:30:30 -04:00
Duncan
7ee13d417b fix(desktop): Phase 1 round-3 — close all Thufir pass-2 findings
All six Thufir pass-2 findings resolved:

[CRITICAL-1] Ownership layer
- seedAgentFormModel seeds respondTo/allowlist/parallelism from instance
  when present; emitAgentFormDiff routes them to agentInput, never personaInput
- Separate definitionRuntimeId (D-field) from selectedRuntimeId (I harness pin);
  resolveAgentCommandUpdate contract used for harness-pin submission
- Kill three phantom writes: untouched-linked access, pin→def-runtime rewrite,
  instance parallelism into definition behavior
- Tests: test_untouched_linked_agent_emits_no_diff,
  test_linked_access_edit_emits_only_agentInput_not_personaInput,
  test_untouched_parallelism_on_linked_agent_emits_no_diff

[CRITICAL-2] Artifact 4 field completeness
- startOnAppLaunch: state, seeding, submit wiring + control in EditAgentAdvancedFields
- Name pool and D-env vars added to D-section (behind Advanced toggle)
- Definition admin section: custom delete with blast-radius copy,
  built-in 'Remove from My Agents' (14a), team-managed guard
- Unlinked avatar: read-only with tooltip (row 2 gap)
- Team note names the team: 'Managed by team X'
- Identity-archived flair with data-testid

[CRITICAL-3] Settlement per boundary
- Settle after each of steps 1–3; stop advancing on observed mismatch
- observedStateMatchesAgentInput() now includes agentCommand/harnessOverride/
  agentArgs/acpCommand
- observedPolicyMatches() for per-boundary and final policy settlement
- Tests: test_harness_command_success_but_observed_mismatch_returns_false,
  test_auto_restart_success_but_observed_unchanged_returns_false,
  test_start_on_app_launch_success_and_observed_match_calls_onDone,
  test_definition_write_not_persisted_stops_instance_write

[IMPORTANT-4] R6 respondTo carry
- reviewOverrides now carries respondTo from agent request
- initialValueOverrides.respondTo seeded into form state

[IMPORTANT-5] Behavioral tests + E2E
- E2E: agent-provider-dropdowns, agents.spec, edit-agent.spec,
  inline-custom-harness updated to merged dialog testids/interactions
- Routing test: instance-edit arm and AgentInstanceEditDialog removed

[IMPORTANT-6] Model metadata + dead code
- FieldOwner gains 'create-only' variant
- Dead instance-edit arm removed from AgentDialog.tsx
- Dead AgentInstanceEditDialog import removed from AgentDialog.tsx
- Dead editPersonaDialogState() and its tests removed
- Dead submitUpdate() removed from useAgentManagement.ts
- Dead JSDoc in AgentDialog.tsx updated

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
2026-08-08 16:39:14 -04:00
Duncan
12b517dfcd fix(agents): wire observed-state settlement, team D-field read-only, coordinator tests
Address all pass-1 CHANGES_REQUIRED findings from Thufir's review:

CRITICAL-1+2: AgentEditDialog now delegates instance contexts entirely to
AgentInstanceEditDialog (all I/L fields, correct testid). Definition-only
contexts use AgentDefinitionDialog + Artifact 3 coordinator. Removed the
type-cast hack (onUpdated?.(undefined as unknown as ManagedAgent)); the
definition-only path correctly does not call onUpdated.

IMPORTANT-3: AgentDefinitionDialog gains definitionReadOnly prop — when set,
all D-fields render disabled and a 'Managed by team' notice is shown; canSubmit
is gated; coordinator also guards against a misconfigured bypass. isDefinitionReadOnly
in agentFormModel.ts checks sourceTeam at the diff layer too.

IMPORTANT-4: Coordinator now settles from observed state on BOTH success and
error paths (not just error). The old 'no firstError → success' branch is gone;
the result is derived entirely from re-fetched observed store comparison.
Absent entity after refetch = not persisted. Per-policy failure tracking:
each policy tracked individually; unattempted policies also reported failed.

IMPORTANT-5: Publish success toast uses personaSaveNotice (not generic 'saved').
Publication status tracked through updatePersonaAndPublish return value.

Tests added:
- agentFormModel.test.mjs: 3 new tests covering team D-field unemittability
  (test_team_definition_emits_no_personaInput_even_when_fields_differ,
   test_team_definition_with_instance_emits_no_personaInput_but_allows_instance_diff,
   plus the env-clobber variants already present)
- agentSaveCoordinator.test.mjs (new file): 11 tests covering write ordering,
  local-save/publish failure, observed-state mismatch, and partial policy failure

Full desktop test suite: 4553/4553 passing. TypeScript clean. Biome clean.
File-size gate: AgentDefinitionDialog.tsx 1041 lines (limit 1041).

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
2026-08-08 12:52:12 -04:00
Duncan
f1e18d924e feat(desktop): merge agent edit surface — Phase 1 route collapse (R1–R7)
Per the Phase 0 spec (Thufir CLEAR 9/9/9), collapse all seven edit routes
onto a single AgentEditDialog that owns the merged agent edit surface.
The create path (Phase 2), vocabulary renames (Phase 3), and Instances
section rename (S5) are explicitly out of scope.

New modules:
- agentFormModel.ts: canonical AgentFormModel type, AgentEditContext
  discriminated union, seedAgentFormModel(), emitAgentFormDiff(). Row 1
  (pooled-name materialization drop) and row 8 (env wholesale-replace drop)
  are structural: unemittable by construction.
- agentSaveCoordinator.ts: Artifact 3 coordinator (runAgentSaveCoordinator):
  validate -> definition write -> instance write -> policy setters ->
  settlement from observed re-fetched state, not from command result.
  Partial-failure toast names exactly what persisted and what did not.
- AgentEditDialog.tsx: merged dialog wrapping AgentDefinitionDialog for
  D-fields. Supports all three AgentEditContext kinds: instance-with-definition,
  instance-only, definition-only. Preserves the "saved while stopped" toast.

Route collapses:
- R1: UserProfilePanel.handleEditAgent no longer prefers the definition dialog
  when a linked persona exists; always opens AgentEditDialog.
- R2: requestOpenEditAgent event handler opens AgentEditDialog.
- R3: handleEditPersona opens AgentEditDialog (definition-section focus).
- R4: onEditLinkedPersona back-door deleted; avatar lives on the merged surface.
- R5: usePersonaActions.openEdit sets personaToEdit (AgentPersona) instead of
  personaDialogState(editPersonaDialogState). AgentsView renders AgentEditDialog
  for definition-only context.
- R6: AgentManagementDialogs routes update action to AgentEditDialog.
  assertAgentCanActFromOrigin guard preserved verbatim via onValidate prop.
  Agent-requested field changes pre-filled for user review via initialValueOverrides.
  Unresolvable updates toast the editError and dismiss.
- R7: UserProfilePersonaDialogs host now only fires for R8 (duplicate/create
  seed); no edit routes remain through personaDialogState.
- R8 (duplicate) and R9 (start-on-launch quick toggle) kept unchanged.

Regression tests (agentFormModel.test.mjs):
- test_pooled_name_instance_name_not_materialized_when_name_pool_exists
- test_pooled_name_instance_name_not_materialized_even_when_names_differ
- test_no_name_pool_explicit_instance_name_change_emits_agentInput
- test_env_clobber_dropped_when_user_edits_unrelated_d_field
- test_env_clobber_dropped_even_when_definition_env_differs_from_instance_env

AC1 grep verified: definition-edit and instance-edit appear only in AgentDialog
component definitions and comments; editPersonaDialogState appears only in
AgentEditDialog's own internal seeding; duplicatePersonaDialogState appears only
in R8 (duplicate) paths.

Full desktop test suite: 4540/4540 passing.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
2026-08-08 11:56:22 -04:00