mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 08:02:28 +00:00
docs(attr-child-clock): add reference findings and the feasibility fact
This commit is contained in:
@@ -89,3 +89,76 @@ Say which category your change is in.
|
||||
does not.
|
||||
4. Propose a mechanism; prefer architecture over a guard. State whether it removes the bug class.
|
||||
5. Mark every claim VERIFIED or UNVERIFIED. Cite file:line.
|
||||
|
||||
---
|
||||
|
||||
# Reference findings
|
||||
|
||||
Five independent implementations were reviewed. Projects are deliberately not named here; describe
|
||||
any conclusion in repo-native terms only. Every mechanism below was read at source and verified.
|
||||
|
||||
## Converged — all five agree
|
||||
|
||||
1. **A child's activity never touches the parent row's lifecycle state, label, or timestamp.**
|
||||
2. **Attribution happens at ingestion (the producer boundary), never as a reader-side filter.**
|
||||
3. **Exactly one writer of a row's status/recency.** None of the five keeps two writers apart with
|
||||
publication filters. They make the second writer *impossible*.
|
||||
4. **Child -> parent rollups do exist** — but they roll up *status* or a *count*, never a label and
|
||||
never a timestamp, and each is explicit and documented.
|
||||
5. **The row label is a stored title derived from the user's own prompt** — never a backward scan
|
||||
for the newest assistant message.
|
||||
|
||||
## Closest architectural match (same platform: Electron, host-service process + renderer sidebar
|
||||
## that nests parent and subagent rows)
|
||||
|
||||
- Subagent hook events are routed to a **separate roster at ingestion, before any store write**.
|
||||
The ingestion comment reads: *"Subagent activity is not the terminal's lifecycle: no chime, no
|
||||
status change, no session id capture."*
|
||||
- The store method recording subagent events is documented *"Never touches the parent binding's
|
||||
lifecycle state."*
|
||||
- The renderer **derives** status on every read inside a `useMemo` and **stores nothing**.
|
||||
- The state-entry stamp is preserved server-side as
|
||||
`prior !== undefined && !sessionChanged ? prior.startedAt : occurredAt`.
|
||||
**There is no done-state special case.** That is the shape of Orca's *main* canonical writer
|
||||
(`server-ingest-structured.ts:65`), not the renderer bridge's.
|
||||
|
||||
## How the references make a second writer impossible
|
||||
|
||||
- One reference's generic update API **structurally omits** the status/recency fields, so the type
|
||||
itself forbids a second writer; a lint rule confines cache writes to owner modules.
|
||||
- One consolidated *"ten independent writers across six slices"* into a single registry writer and
|
||||
recorded the decision as an architecture decision record.
|
||||
- One gates client updates behind a monotonic sequence check and replaces **whole rows**, so a
|
||||
client cannot mutate an individual field.
|
||||
|
||||
## Where the references DIVERGE — do not claim precedent here
|
||||
|
||||
The child clock (defect C) has **no single answer**:
|
||||
- one shows **no timestamp at all** on the desktop row, carrying liveness via status + derived counts;
|
||||
- one shows a **live-ticking elapsed duration** that freezes at completion;
|
||||
- one carries a true **advancing per-child progress field**.
|
||||
|
||||
All three do quarantine the spawn stamp from display. So C has several legitimate answers — choose
|
||||
one with stated reasons; you may not justify it by precedent alone.
|
||||
|
||||
## Material deviation to disclose (repo-native terms, for the eventual PR body)
|
||||
|
||||
> Orca keeps two real writers of one status row apart with publication filters. Every reference
|
||||
> implementation examined removes the possibility of a second writer rather than suppressing its
|
||||
> traffic.
|
||||
|
||||
## Feasibility fact established in Orca
|
||||
|
||||
The producer already has the attribution and discards it:
|
||||
- `src/main/claude/claude-structured-item-translation.ts:57` already parses
|
||||
`parentToolUseId: claudeText(frame.parent_tool_use_id)`.
|
||||
- `src/main/claude/claude-structured-journal-translation.ts:143-144` uses it only for
|
||||
`observeChildActivity(...)`, then drops it; the item is journaled with no producer trace.
|
||||
- The journal schemas carry **no producer field at all** — zero hits for
|
||||
`parentToolUseId|agentId|parentAgentId|producer|subagentId` in
|
||||
`src/shared/agent-session-journal-schemas.ts` and `src/shared/agent-session-journal-types.ts`.
|
||||
- A canonical subagent id already exists next door:
|
||||
`src/main/claude/claude-subagent-roster.ts:121` (`this.ids.canonical(parentToolUseId)`).
|
||||
|
||||
So attributing at the producer means **persisting a value we already compute and throw away three
|
||||
lines later** — not plumbing a new one end to end.
|
||||
|
||||
Reference in New Issue
Block a user