Skip to content

chat: one reader for a report's first prose line so every surface skips a leading fence (#931) - #1807

Open
ursasi wants to merge 3 commits into
Agent-Field:devfrom
ursasi:fence-aware-outcome-reader
Open

ursasi wants to merge 3 commits into
Agent-Field:devfrom
ursasi:fence-aware-outcome-reader

Conversation

@ursasi

@ursasi ursasi commented Oct 11, 2026

Copy link
Copy Markdown

Closes #931.

The bug

A task whose report opens with a code fence (a diff, a command's output, a JSON block) landed with a correct card — #889 taught the card to skip the fence — but the /tasks table, the home panels and the task record still drew three backticks, because the card was not the only path that quotes a report's first line.

Two readers were the cause:

  • the surface skipped the fence through firstProseLine (internal/tui3), while
  • the engine wrote TaskIndexEntry.Outcome through taskOutcome (internal/session), which read the literal first line with firstLine.

mdFenceOpen, the fence detector firstProseLine leaned on, is private to internal/tui3, and taskOutcome lives in internal/session, so neither could reach the other. Copying the loop into internal/session was explicitly the wrong fix — two opinions about what a fence is drift.

The fix — one reader, not two

A new leaf package internal/reportline holds both the fence-marker detection (Fence) and the first-prose-line reading (FirstProse), and both the surface and the engine import it:

  • internal/session taskOutcome → reportline.FirstProse
  • internal/tui3 taskFirstSentence, switcherFirstLine → reportline.FirstProse
  • internal/tui3 firstProseLine → thin wrapper over reportline.FirstProse
  • internal/tui3 mdFenceOpen → thin wrapper over reportline.Fence, so the renderer and the readers share one fence opinion

No user-facing wording changes: rows that quoted a sentence still do, and rows with nothing to quote still render nothing (not empty quotes).

Tests

  • internal/reportline — a table pinning the rule (leading fence, language word, tilde fence, blank lines, fence-only report, empty report) and a table pinning Fence.
  • A structural law (go/ast) asserting every path that quotes a report's first line — taskOutcome, taskFirstSentence, switcherFirstLine, landedCard — routes through the one reader, so a future addition cannot silently use firstLine and put the fence back.
  • internal/session TestTaskOutcomeSkipsAFence — the deterministic repro from the issue.
  • The existing tui3 done-card fence tests still pass against the delegating firstProseLine.

Manual

internal/manual/chat/reading-a-task-page.md, under "The card quotes three backticks instead of a sentence", now applies to every surface that quotes a report, not only the card.

First-time fork PR — CI needs maintainer approval to run. Verified locally: go build ./..., go vet, the new/affected tests above, and the manual corpus test all green.

@CLAassistant

CLAassistant commented Oct 11, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Copy link
Copy Markdown
Member

Hey, thanks for the PR. Could you sign the CLA when you get a chance so we can review it?

ursasi pushed a commit to ursasi/CodeAF that referenced this pull request Oct 11, 2026
@ursasi
ursasi force-pushed the fence-aware-outcome-reader branch from e07b5e5 to c7e11de Compare October 11, 2026 14:14
ursasi added a commit to ursasi/CodeAF that referenced this pull request Oct 11, 2026
…ps a leading fence (Agent-Field#931)

A report that opens with a code fence used to draw three backticks on the
tasks table, the home panels and the task record, while the landed card
(fixed in Agent-Field#889) already quoted the sentence. The cause was two readers: the
surface skipped the fence through firstProseLine, but the engine wrote
TaskIndexEntry.Outcome through taskOutcome, which read the literal first line.

Lift the fence-marker detection and the first-prose-line reading into one
leaf package, internal/reportline, that both the surface and the engine
import. taskOutcome, taskFirstSentence, switcherFirstLine and the renderer's
mdFenceOpen all route through it; firstProseLine becomes a thin wrapper. A
structural law pins that every path quoting a report's first line goes
through the one reader, so a future hand cannot reach for firstLine and put
the fence back.
@ursasi
ursasi force-pushed the fence-aware-outcome-reader branch from c7e11de to 580545f Compare October 11, 2026 14:17
…gent-Field#1807)

firstProseLine is now a one-line delegate to reportline.FirstProse, so the
Agent-Field#889 table in tui3 re-tested the same logic the reportline table already
pins; keep the two card tests that prove the surface is wired to the reader.
Fold the law's bodyCallsSanctionedReader and bodyCallsFirstProse into one
bodyCallsAny(names...).
@ursasi

ursasi commented Oct 11, 2026

Copy link
Copy Markdown
Author

@CLAassistant

Signed! Looking forward to contributing to CodeAF.

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.

chat: the tasks table, the home panels and the task record still quote a report's literal first line, so a fenced report draws three backticks

3 participants