Skip to content

feat(inbox): render the signal report artefact log#2557

Open
oliverb123 wants to merge 11 commits into
mainfrom
sig/artefact-log-ui
Open

feat(inbox): render the signal report artefact log#2557
oliverb123 wants to merge 11 commits into
mainfrom
sig/artefact-log-ui

Conversation

@oliverb123

@oliverb123 oliverb123 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Problem

Signal reports now accumulate a richer set of artefacts on the backend — code references, diffs, pushed commits, task runs, and notes — alongside the existing judgments and findings. The inbox had no way to surface them, so all that work-log context was invisible to reviewers.

This is the PostHog Code side of the artefact-log feature. The backend half (new artefact types, the append-only log, per-commit diffs, attribution, and unlabelled task↔report associations) lands in PostHog/posthog#61545.

Changes

Adds a chronological activity log to the right column of the report detail pane (below the status sections), rendering every artefact type with a tailored body rather than raw JSON:

  • Code references / line references — syntax-highlighted code blocks with the relevant span and note.
  • Code diffs — unified-diff rendering with add/remove coloring (DiffBlock).
  • Commits — one artefact per pushed commit (message, sha, repo@branch), with a collapsible "View diff" that fetches the commit-vs-parent diff on demand from the backend endpoint; missing/rewritten commits surface a clean message instead of a raw error, and oversized diffs show a truncation notice.
  • Task runs — loads the linked task and expands to its full conversation log via TaskLogsPanel. Badged from the artefact's (product, type): signals-pipeline runs show Research / Implementation; custom agents show their humanized product + type.
  • Notes / judgments / findings / reviewers — each rendered as a point-in-time entry with a relative timestamp; judgment reasoning and long notes are collapsed behind a toggle.
  • Attribution byline — every entry shows who produced it ("by Oliver" for user writes, "by agent" for task-attributed writes; system/pipeline writes show nothing), from the API's created_by / task_id attribution fields.
  • A dev-only raw-JSON inspector on each row (hidden in release builds, same pattern as other dev-only controls).

Beyond rendering, this PR also tracks the backend's model changes:

  • The signed-commit hook — after every successful git_signed_commit push, the harness automatically records one commit artefact per pushed commit on every signal report the task is associated with, attributed via the X-PostHog-Task-Id header. Best-effort: an artefact failure can never fail a commit that already landed. Credentials come from the sandbox env (live agentsh env file first), so it works identically in the Claude in-process server and the Codex stdio child.
  • Artefact-derived task associationSignalReportTask is gone from the backend; a task_run artefact is the task↔report association. The Runs bars and the activity log now read the same artefacts: each association, its start time, and its purpose badge (Research / Implementation for the signals pipeline, humanized product + type for custom agents) all derive from the report's task_run artefacts. getSignalReportTasks and the SignalReportTask type are deleted (desktop + mobile).

Artefact content types are hand-written in packages/shared/src/domain-types.ts — every artefact extends a shared SignalReportArtefactBase carrying timestamps plus attribution — and normalized in packages/api-client's posthog-client.ts (the task_run content carries product/type, matching the backend).

How did you test this?

  • pnpm typecheck — passes.
  • biome check — clean on all changed files.
  • vitest — git, agent, and app suites green, including new unit tests for the signed-commit hook (one POST per commit per report, header attribution, failures swallowed, no-op without a task or credentials).
  • Manual: rendered a report seeded with one of each artefact type against a local backend; verified the commit diff loads against a real pushed commit, the task_run entry expands to the conversation log, and the timeline orders correctly by timestamp.
  • No automated component tests were added for these renderers.

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

Created with PostHog Code

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

React Doctor could not complete this scan.

No React dependency found in /tmp/react-doctor-baseline-EYvgBU/package.json. Add "react" to dependencies (or peerDependencies) and re-run.

Reviewed by React Doctor for commit f8794f9.

@greptile-apps

greptile-apps Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Comments Outside Diff (1)

  1. apps/code/src/renderer/features/inbox/components/detail/ArtefactTaskRun.tsx, line 814-819 (link)

    P2 Eager task fetches vs. lazy diff fetches

    ArtefactPushedBranch only fetches the diff when the user expands the row (enabled: expanded), but ArtefactTaskRun fires getTask immediately on mount regardless of whether the row is expanded. In a report with many task_run artefacts this generates N simultaneous API calls as soon as the detail pane opens. The task title displayed in the collapsed state is the only reason for eager loading, but content.task_id could be used as the fallback text (it already is, on line 851) until the user expands the row, which would allow lazy loading here too.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/code/src/renderer/features/inbox/components/detail/ArtefactTaskRun.tsx
    Line: 814-819
    
    Comment:
    **Eager task fetches vs. lazy diff fetches**
    
    `ArtefactPushedBranch` only fetches the diff when the user expands the row (`enabled: expanded`), but `ArtefactTaskRun` fires `getTask` immediately on mount regardless of whether the row is expanded. In a report with many `task_run` artefacts this generates N simultaneous API calls as soon as the detail pane opens. The task title displayed in the collapsed state is the only reason for eager loading, but `content.task_id` could be used as the fallback text (it already is, on line 851) until the user expands the row, which would allow lazy loading here too.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
apps/code/src/renderer/features/inbox/components/detail/ArtefactTaskRun.tsx:814-819
**Eager task fetches vs. lazy diff fetches**

`ArtefactPushedBranch` only fetches the diff when the user expands the row (`enabled: expanded`), but `ArtefactTaskRun` fires `getTask` immediately on mount regardless of whether the row is expanded. In a report with many `task_run` artefacts this generates N simultaneous API calls as soon as the detail pane opens. The task title displayed in the collapsed state is the only reason for eager loading, but `content.task_id` could be used as the fallback text (it already is, on line 851) until the user expands the row, which would allow lazy loading here too.

### Issue 2 of 2
apps/code/src/renderer/features/inbox/components/detail/ArtefactTaskRun.tsx:37-38
`getTask` already returns `Task` internally (it does its own `as unknown as Task` cast). The additional cast here is redundant and suggests a type mismatch that isn't actually present. Removing the outer cast makes the intent clear.

```suggestion
    (client) => client.getTask(content.task_id),
```

Reviews (1): Last reviewed commit: "feat(inbox): render the signal report ar..." | Re-trigger Greptile

Comment on lines +37 to +38
async (client) =>
(await client.getTask(content.task_id)) as unknown as Task,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 getTask already returns Task internally (it does its own as unknown as Task cast). The additional cast here is redundant and suggests a type mismatch that isn't actually present. Removing the outer cast makes the intent clear.

Suggested change
async (client) =>
(await client.getTask(content.task_id)) as unknown as Task,
(client) => client.getTask(content.task_id),
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/features/inbox/components/detail/ArtefactTaskRun.tsx
Line: 37-38

Comment:
`getTask` already returns `Task` internally (it does its own `as unknown as Task` cast). The additional cast here is redundant and suggests a type mismatch that isn't actually present. Removing the outer cast makes the intent clear.

```suggestion
    (client) => client.getTask(content.task_id),
```

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in dd2d85bgetTask already returns Task, so the outer cast was redundant and is removed.

After every successful git_signed_commit push the harness posts one `commit`
artefact per pushed commit to every signal report the task is associated with,
attributed via the X-PostHog-Task-Id header. Best-effort: reportCommitArtefacts
never throws, so an artefact failure can't fail a commit that already landed.
SignedCommitResult now carries the repository (owner/repo) so the hook doesn't
re-derive it.

Generated-By: PostHog Code
Task-Id: 03657aa4-20d8-4dea-aeef-e8c1ab4bbce2
Adds an Activity section below the report summary rendering every artefact
chronologically with a tailored body per type: syntax-highlighted code
references and line references, unified-diff coloring for code diffs, commits
with a lazily-fetched commit-vs-parent diff (new getCommitDiff endpoint),
task runs that expand to the full conversation log, notes, judgments,
findings, reviewers, and dismissals — plus a dev-only raw-JSON inspector.

Artefacts are an append-only history now, so the status selectors
(reviewers, judgments, findings) become explicitly latest-wins instead of
relying on response ordering, and the reviewers edit optimistically appends
a synthetic latest row mirroring the server's append semantics.

Generated-By: PostHog Code
Task-Id: 03657aa4-20d8-4dea-aeef-e8c1ab4bbce2
SignalReportTask is now an unlabelled task↔report association — the
relationship label is gone from the API. A task's purpose (Research /
Implementation / a custom agent's humanized identifier) is derived from the
report's task_run artefacts; freely-associated tasks with no task_run
artefact surface generically as "Agent task". Task creation stops sending
the relationship label, and the report repository falls back to walking
associated tasks oldest-first.

Generated-By: PostHog Code
Task-Id: 03657aa4-20d8-4dea-aeef-e8c1ab4bbce2
Renders as a RightColumnSection below the report's status sections
(Runs, Suggested reviewers) instead of under the summary, and drops the
now-unused belowSummary slot from InboxDetailFrame.

Generated-By: PostHog Code
Task-Id: 03657aa4-20d8-4dea-aeef-e8c1ab4bbce2
Priority and actionability entries show their badge with the explanation
behind a "Show reasoning" toggle — the paragraphs were dominating the log.

Generated-By: PostHog Code
Task-Id: 03657aa4-20d8-4dea-aeef-e8c1ab4bbce2
Notes are free-form markdown and can run long — collapsed they show a
truncated first-line preview that expands to the rendered note + author.

Generated-By: PostHog Code
Task-Id: 03657aa4-20d8-4dea-aeef-e8c1ab4bbce2
The backend removed the /signals/reports/{id}/tasks/ surface — task_run
artefacts are the sole source of association. useReportTasks now reads them
directly (one entry per associated task, earliest artefact wins for
startedAt), getSignalReportTasks and the SignalReportTask type are gone, and
resolveReportRepository walks artefact-derived task ids oldest-first.

Generated-By: PostHog Code
Task-Id: 03657aa4-20d8-4dea-aeef-e8c1ab4bbce2
The API already attributes every artefact (created_by for user writes,
task_id for agent writes) but the client normalizers dropped both fields,
so the log had no byline. Thread them through a shared artefact base type
and render who produced each entry next to its timestamp.

Generated-By: PostHog Code
Task-Id: 03657aa4-20d8-4dea-aeef-e8c1ab4bbce2
The normalizer had no safety_judgment branch, so rows fell into the
generic fallback (which requires a content/session_id string) and were
silently dropped — the "Safety assessed" label was unreachable. Add the
typed artefact, its normalizer, and a Safe/Unsafe badge body with
collapsible reasoning.

Generated-By: PostHog Code
Task-Id: 03657aa4-20d8-4dea-aeef-e8c1ab4bbce2
@oliverb123 oliverb123 force-pushed the sig/artefact-log-ui branch from 058c05e to 5194d1d Compare June 11, 2026 17:17
Typed normalizers returned null on any shape mismatch, vanishing the row
(unknown dismissal reasons, future artefact types, partial content).
Route every miss through a degraded fallback that keeps the row — type,
timestamps, attribution, and a text preview — and render it as a plain
entry. Adds coverage asserting all 14 backend artefact types normalize
and that malformed rows survive as degraded previews.

Generated-By: PostHog Code
Task-Id: 03657aa4-20d8-4dea-aeef-e8c1ab4bbce2
The backend removed the code_diff artefact type in the review pass — agents
point at code via code_reference / line_reference, and real diffs render
from commit artefacts. Removes the type, its normalizer, and its renderer;
DiffBlock stays for the commit diff view.

Generated-By: PostHog Code
Task-Id: f65424ca-a7fe-49f5-9f75-7a3cf004b417
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant