Skip to content

ResearchMemory.merge overwrites without conflict signal #161

Description

@zoewu90

backend/app/faros/memory/research_memory.py:20-22:

def merge(self, payload: Dict[str, Any]) -> None:
    self._data.update(payload)
    self.state_store.save_memory(self.run_id, self._data)

The orchestrator at backend/app/faros/runtime/orchestrator.py:103 calls memory.merge(result.outputs) after every step. Because dict.update silently overwrites, later capability outputs clobber earlier ones with the same key — for example:

  • idea_refinement produces paperType (via the user's input passed to its inputs dict in idea_refinement.py:24).
  • experiment produces paperType again (line 20 of experiment.py: paper_type = inputs.get("paperType", "algorithm") — but then it's not in outputs).
  • paper_drafting reads paperType from inputs (line 34 of paper_drafting.py).

The keys should be namespaced per capability, especially since the orchestrator at line 73-74 does:

node_inputs = {}
node_inputs.update(memory.data)
node_inputs.update(node.inputs)

…i.e., memory leaks straight into the next node's inputs. This is convenient for "selectedCandidate" (it's the whole point of the workflow), but dangerous for anything that two adjacent capabilities both compute.

Two options

  1. Namespace per node: memory.merge({f"{node.id}.{k}": v for k, v in result.outputs.items()}). Then downstream capabilities have to opt-in by explicitly referencing memory["idea.selectedCandidate"].

  2. Conflict-warn merge: log a warning when merge overwrites a key that another capability set. The first option is structurally cleaner; the second is back-compat and adds an observability signal.

I'd lean toward (2) for the v1.1 release since (1) is a contract change for capabilities and the README's "Stable release baseline" claim covers FAROS metadata.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions