Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ Simple and complete Marko testing utilities that encourage good testing practice

## Agent feedback

Anything actionable but out of scope for the current task — a suspected bug, cleanup, a perf/size win, tooling friction, or code that was confusing — must be recorded in [`agent-feedback/`](agent-feedback/README.md) before finishing. Don't silently drop it, and don't fix it inside an unrelated diff.
Anything actionable but out of scope for the current task (suspected bug, cleanup, perf or size win, tooling friction, confusing code) must be filed in [`agent-feedback/`](agent-feedback/README.md) before finishing. Never drop it silently. Never fix it inside an unrelated diff.
69 changes: 45 additions & 24 deletions agent-feedback/README.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,60 @@
# Agent Feedback

Actionable observations that were **out of scope for the task that surfaced them**. If something is in scope, fix it instead. Do not expand a task's diff to fix issues recorded here.
Actionable observations that were out of scope for the task that surfaced them. In scope: fix it. Out of scope: file it here. Never expand a task's diff to fix an item recorded here.

## When to add an entry
One item per file in `items/`, named `YYYY-MM-DD-<slug>.md`.

While working on any task, record anything a future contributor should act on:
## When to file

- a suspected bug you couldn't pursue → `bugs.md`
- duplication, dead code, inconsistency, refactor opportunities → `cleanup.md`
- runtime speed or bundle size opportunities → `perf.md`
- friction in builds, tests, tooling, or repo workflows → `dx.md`
- code or docs that were confusing, and what would have clarified them → `unclear.md`
Anything a future contributor should act on:

## Rules
- `bug`: a suspected defect left unpursued
- `cleanup`: duplication, dead code, inconsistency, refactor opportunity
- `perf`: speed, memory, payload or bundle size, build time
- `dx`: friction in builds, tests, tooling, or repo workflows
- `unclear`: code or docs that were confusing, and what would have clarified them

1. **Search the category file first.** If an entry already covers it, don't duplicate; append a corroborating sentence only if you have new information.
2. **Be self-contained.** Include enough detail (paths, symbols, reasoning) that someone can act without re-discovering your analysis. Never reference "my earlier analysis" or conversation context.
3. **Cite by stable symbol, not line number.** Line numbers rot with the next edit; anchor the primary citation to the nearest enclosing stable symbol (exported function, class, variable, or a heading for docs). A line number may appear in the body as a secondary hint.
4. **Append to the end** of the category file.
5. Entries are **removed when resolved** (delete, don't mark done; git history is the archive).
6. **Verify before recording.** A guess is not feedback.
## Rules

## Resolving a "won't fix" item
1. **Verify first.** A guess is not feedback. Every item ends with a check that reproduces the claim.
2. **Dedupe first.** `grep -ril '<path or symbol>' agent-feedback/items`. If a file covers it, edit that file only when you add new information.
3. **Check the code site.** An intent comment there means the behavior is deliberate. Do not file it.
4. **Self-contained.** Paths, symbols, reasoning. Never reference conversation context or "earlier analysis".
5. **Cite by stable symbol**, never line number.
6. **State the defect and the check.** Never describe what works. Never narrate a landed fix.
7. **Direction is preventive for `unclear` and `dx`.** Name what would have stopped the trip: a comment, a doc line, a lint rule, a compile error, a debug-only warning. The goal is that the next agent does not hit it.
8. **Resolve by deleting the file in the same PR as the fix.** A partial fix rewrites the file to what remains.
9. **Won't-fix is a maintainer's call, never an agent's.** Add a comment (two lines max) at the code site stating the behavior and why it is deliberate, then delete the file. The comment is what stops re-filing. Never consult git history to learn whether something was resolved; if it is not in `items/` and not commented at the site, it is unresolved.

When a maintainer has explicitly deemed an item "won't fix" / "not worth it", resolve it by adding a brief inline comment at the code site that captures the decision (so it is not re-filed), then remove the entry. Only on such an explicit call — never on your own initiative.
## Item format

## Entry format
`items/YYYY-MM-DD-<slug>.md`:

```md
## <one-line imperative summary>
---
type: bug | cleanup | perf | dx | unclear
impact: high | med | low
effort: high | med | low
site: <path/to/file.ts> › <nearestStableSymbol>
---

# <one-line imperative title>

`<primary/file/path.ts>` › `<nearestStableSymbol>` | 2026-07-02 | impact:<low|med|high> | effort:<low|med|high>
<2-6 sentences: the problem, why it matters, a concrete direction. Cut evidence a fixer can re-derive from the site.>

<2–6 sentences: the problem, why it matters, and a concrete suggested direction,
ending with the check that re-verifies the claim (a command, input, or
observation). Cut evidence beyond what a fixer needs to act; further detail is
re-derived from the citation. Additional file paths inline as needed.>
Check: <command, input, or observation that reproduces the claim>
```

`impact`: what breaks or is lost if ignored. `effort`: expected size of the fix. Both are the filer's estimate; triage re-judges.

## Repo notes

Single package, pnpm, vitest. Wraps `@testing-library/dom` for Marko templates and supports Marko 3 through 6 through separate branches in `src/index.ts`.

**Reproduce a claim.** Add a fixture under `src/__tests__/fixtures/` and a case in the matching `src/__tests__/*.test.ts`. Server-side rendering is covered by `*.server.test.ts`, browser/DOM by the rest.

**Guard tests.** `pnpm test` (`vitest run`); `pnpm test:update` for snapshots, `pnpm test:watch` while iterating.

**Pre-ship.** `pnpm run build` (rolldown + tsc), `pnpm run @ci:lint`, `pnpm test`. Add a changeset with `pnpm run change`.

**Gotchas.** `devDependencies` pins a Marko 5 line while `peerDependencies` allows `3 - 6`, so the Marko 6 code paths are not exercised by the default install or by CI. Reproducing anything on the Marko 6 branch needs a Marko 6 installed on purpose; say so in the item. A Marko 6 render returns a stream-backed object, so `toString()` throws while a render is pending.
9 changes: 0 additions & 9 deletions agent-feedback/bugs.md

This file was deleted.

3 changes: 0 additions & 3 deletions agent-feedback/cleanup.md

This file was deleted.

3 changes: 0 additions & 3 deletions agent-feedback/dx.md

This file was deleted.

12 changes: 12 additions & 0 deletions agent-feedback/items/2026-07-30-render-awaits-completed-stream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
type: bug
impact: med
effort: med
site: src/index.ts › render
---

# Consume the first render chunk in `render()` instead of awaiting the completed stream

The Marko 6 branch does `String(await (template as any).render(input))`, and that await settles only once marko's `ServerRendered` boundary reaches `FlushStatus.complete`, so a `*.server.test.ts` can never observe an `<await>`/`<try>` placeholder or any intermediate streaming state. The HTML handed to `JSDOM.fragment` is always the fully drained output, and a fixture whose `load()` promise never settles hangs `render()` until vitest's timeout with no diagnostic. `toString()` is not an escape hatch: marko throws "Cannot consume asynchronous render with 'toString'" while the render is still pending. Nothing is needed from marko, since the object returned by `template.render(input)` already exposes `[Symbol.asyncIterator]()`, `pipe()`, and `toReadable()`, and a `for await` over a `<try><await>` fixture yields the `Loading...` placeholder in chunk one. Read the first chunk and stop, either as the default or behind a new flag on `RenderOptions` in `src/shared.ts`, leaving the Marko 3/4/5 callback branch untouched. CI does not cover this path: `devDependencies` pins `marko@^5.39.13` while `peerDependencies` allows `3 - 6`, so reproducing needs a Marko 6 install.

Check: add a `<try><await>` fixture under `src/__tests__/fixtures/` plus a case in `src/__tests__/render.server.test.ts` asserting the placeholder text, then `pnpm test`; the case sees only resolved content, or times out when the promise never settles.
3 changes: 0 additions & 3 deletions agent-feedback/perf.md

This file was deleted.

3 changes: 0 additions & 3 deletions agent-feedback/unclear.md

This file was deleted.